@stan-chen/simple-cli 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -271
- package/dist/anyllm.py +62 -0
- package/dist/builtins.d.ts +726 -0
- package/dist/builtins.js +481 -0
- package/dist/cli.d.ts +0 -4
- package/dist/cli.js +37 -279
- package/dist/engine.d.ts +33 -0
- package/dist/engine.js +138 -0
- package/dist/learnings.d.ts +15 -0
- package/dist/learnings.js +54 -0
- package/dist/llm.d.ts +18 -0
- package/dist/llm.js +66 -0
- package/dist/mcp.d.ts +132 -0
- package/dist/mcp.js +43 -0
- package/dist/skills.d.ts +5 -16
- package/dist/skills.js +91 -253
- package/dist/tui.d.ts +1 -0
- package/dist/tui.js +10 -0
- package/package.json +88 -78
- package/dist/commands/add.d.ts +0 -9
- package/dist/commands/add.js +0 -50
- package/dist/commands/git/commit.d.ts +0 -12
- package/dist/commands/git/commit.js +0 -97
- package/dist/commands/git/status.d.ts +0 -6
- package/dist/commands/git/status.js +0 -42
- package/dist/commands/index.d.ts +0 -16
- package/dist/commands/index.js +0 -376
- package/dist/commands/mcp/status.d.ts +0 -6
- package/dist/commands/mcp/status.js +0 -31
- package/dist/commands/swarm.d.ts +0 -36
- package/dist/commands/swarm.js +0 -236
- package/dist/commands.d.ts +0 -32
- package/dist/commands.js +0 -427
- package/dist/context.d.ts +0 -116
- package/dist/context.js +0 -327
- package/dist/index.d.ts +0 -6
- package/dist/index.js +0 -109
- package/dist/lib/agent.d.ts +0 -98
- package/dist/lib/agent.js +0 -281
- package/dist/lib/editor.d.ts +0 -74
- package/dist/lib/editor.js +0 -441
- package/dist/lib/git.d.ts +0 -164
- package/dist/lib/git.js +0 -351
- package/dist/lib/ui.d.ts +0 -159
- package/dist/lib/ui.js +0 -252
- package/dist/mcp/client.d.ts +0 -22
- package/dist/mcp/client.js +0 -81
- package/dist/mcp/manager.d.ts +0 -186
- package/dist/mcp/manager.js +0 -446
- package/dist/prompts/provider.d.ts +0 -22
- package/dist/prompts/provider.js +0 -78
- package/dist/providers/index.d.ts +0 -15
- package/dist/providers/index.js +0 -82
- package/dist/providers/multi.d.ts +0 -11
- package/dist/providers/multi.js +0 -28
- package/dist/registry.d.ts +0 -24
- package/dist/registry.js +0 -379
- package/dist/repoMap.d.ts +0 -5
- package/dist/repoMap.js +0 -79
- package/dist/router.d.ts +0 -41
- package/dist/router.js +0 -108
- package/dist/swarm/coordinator.d.ts +0 -86
- package/dist/swarm/coordinator.js +0 -257
- package/dist/swarm/index.d.ts +0 -28
- package/dist/swarm/index.js +0 -29
- package/dist/swarm/task.d.ts +0 -104
- package/dist/swarm/task.js +0 -221
- package/dist/swarm/types.d.ts +0 -132
- package/dist/swarm/types.js +0 -37
- package/dist/swarm/worker.d.ts +0 -107
- package/dist/swarm/worker.js +0 -299
- package/dist/tools/analyzeFile.d.ts +0 -16
- package/dist/tools/analyzeFile.js +0 -43
- package/dist/tools/git.d.ts +0 -40
- package/dist/tools/git.js +0 -236
- package/dist/tools/glob.d.ts +0 -34
- package/dist/tools/glob.js +0 -165
- package/dist/tools/grep.d.ts +0 -53
- package/dist/tools/grep.js +0 -296
- package/dist/tools/linter.d.ts +0 -35
- package/dist/tools/linter.js +0 -349
- package/dist/tools/listDir.d.ts +0 -29
- package/dist/tools/listDir.js +0 -50
- package/dist/tools/memory.d.ts +0 -34
- package/dist/tools/memory.js +0 -215
- package/dist/tools/readFiles.d.ts +0 -25
- package/dist/tools/readFiles.js +0 -31
- package/dist/tools/reloadTools.d.ts +0 -11
- package/dist/tools/reloadTools.js +0 -22
- package/dist/tools/runCommand.d.ts +0 -32
- package/dist/tools/runCommand.js +0 -79
- package/dist/tools/scraper.d.ts +0 -31
- package/dist/tools/scraper.js +0 -211
- package/dist/tools/writeFiles.d.ts +0 -63
- package/dist/tools/writeFiles.js +0 -87
- package/dist/ui/server.d.ts +0 -5
- package/dist/ui/server.js +0 -74
- package/dist/watcher.d.ts +0 -35
- package/dist/watcher.js +0 -164
- /package/{docs/assets → assets}/logo.jpeg +0 -0
package/dist/mcp/manager.js
DELETED
|
@@ -1,446 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP Client Manager - Manages multiple MCP server connections
|
|
3
|
-
* Supports Composio, custom MCP servers, and dynamic tool discovery
|
|
4
|
-
* Based on GeminiCLI's mcp-client.ts patterns
|
|
5
|
-
*/
|
|
6
|
-
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
7
|
-
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
8
|
-
import { z } from 'zod';
|
|
9
|
-
import { existsSync, readFileSync } from 'fs';
|
|
10
|
-
import { join } from 'path';
|
|
11
|
-
// MCP Server Configuration Schema
|
|
12
|
-
export const MCPServerConfigSchema = z.object({
|
|
13
|
-
name: z.string(),
|
|
14
|
-
command: z.string().optional(),
|
|
15
|
-
args: z.array(z.string()).optional(),
|
|
16
|
-
env: z.record(z.string()).optional(),
|
|
17
|
-
url: z.string().optional(),
|
|
18
|
-
type: z.enum(['stdio', 'sse', 'http']).optional(),
|
|
19
|
-
timeout: z.number().optional(),
|
|
20
|
-
trust: z.enum(['full', 'partial', 'none']).optional(),
|
|
21
|
-
enabled: z.boolean().optional().default(true),
|
|
22
|
-
});
|
|
23
|
-
// Server Status
|
|
24
|
-
export var MCPServerStatus;
|
|
25
|
-
(function (MCPServerStatus) {
|
|
26
|
-
MCPServerStatus["DISCONNECTED"] = "disconnected";
|
|
27
|
-
MCPServerStatus["CONNECTING"] = "connecting";
|
|
28
|
-
MCPServerStatus["CONNECTED"] = "connected";
|
|
29
|
-
MCPServerStatus["ERROR"] = "error";
|
|
30
|
-
})(MCPServerStatus || (MCPServerStatus = {}));
|
|
31
|
-
/**
|
|
32
|
-
* MCP Client Manager
|
|
33
|
-
* Manages connections to multiple MCP servers and aggregates their tools
|
|
34
|
-
*/
|
|
35
|
-
export class MCPManager {
|
|
36
|
-
servers = new Map();
|
|
37
|
-
onStatusChange;
|
|
38
|
-
constructor(options) {
|
|
39
|
-
this.onStatusChange = options?.onStatusChange;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Load MCP configuration from all available sources
|
|
43
|
-
*/
|
|
44
|
-
async loadConfig(configPath) {
|
|
45
|
-
const allConfigs = [];
|
|
46
|
-
const sources = [
|
|
47
|
-
{ path: configPath, type: 'file' },
|
|
48
|
-
{ path: join(process.cwd(), 'mcp.json'), type: 'file' },
|
|
49
|
-
{ path: join(process.cwd(), '.mcp.json'), type: 'file' },
|
|
50
|
-
{ path: join(process.cwd(), 'mcp'), type: 'dir' },
|
|
51
|
-
{ path: join(process.env.HOME || '', '.config', 'simplecli', 'mcp.json'), type: 'file' },
|
|
52
|
-
{ path: join(process.env.APPDATA || '', 'simplecli', 'mcp.json'), type: 'file' },
|
|
53
|
-
].filter(s => s.path && existsSync(s.path));
|
|
54
|
-
for (const source of sources) {
|
|
55
|
-
try {
|
|
56
|
-
if (source.type === 'file') {
|
|
57
|
-
const content = readFileSync(source.path, 'utf-8');
|
|
58
|
-
allConfigs.push(...this.parseConfigContent(content));
|
|
59
|
-
}
|
|
60
|
-
else if (source.type === 'dir') {
|
|
61
|
-
// Scan directory for .json files
|
|
62
|
-
const { readdir } = await import('fs/promises');
|
|
63
|
-
const files = await readdir(source.path);
|
|
64
|
-
for (const file of files) {
|
|
65
|
-
if (file.endsWith('.json')) {
|
|
66
|
-
const content = readFileSync(join(source.path, file), 'utf-8');
|
|
67
|
-
allConfigs.push(...this.parseConfigContent(content));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
catch (e) {
|
|
73
|
-
if (process.env.DEBUG)
|
|
74
|
-
console.error(`Failed to load MCP source ${source.path}:`, e);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
// De-duplicate by name, preferring earlier (local) configs
|
|
78
|
-
const unique = new Map();
|
|
79
|
-
for (const config of allConfigs) {
|
|
80
|
-
if (!unique.has(config.name)) {
|
|
81
|
-
unique.set(config.name, config);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return Array.from(unique.values()).filter(s => s.enabled !== false);
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Parse MCP config content which can be in multiple formats
|
|
88
|
-
*/
|
|
89
|
-
parseConfigContent(content) {
|
|
90
|
-
try {
|
|
91
|
-
const config = JSON.parse(content);
|
|
92
|
-
// Handle { servers: [...] } format
|
|
93
|
-
if (Array.isArray(config.servers)) {
|
|
94
|
-
return config.servers;
|
|
95
|
-
}
|
|
96
|
-
// Handle { mcpServers: { name: config } } format (Claude-style)
|
|
97
|
-
if (config.mcpServers) {
|
|
98
|
-
return Object.entries(config.mcpServers).map(([name, cfg]) => ({
|
|
99
|
-
name,
|
|
100
|
-
...cfg
|
|
101
|
-
}));
|
|
102
|
-
}
|
|
103
|
-
// Handle single server config
|
|
104
|
-
if (config.name && (config.command || config.url)) {
|
|
105
|
-
return [config];
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
catch (e) {
|
|
109
|
-
if (process.env.DEBUG)
|
|
110
|
-
console.error('Failed to parse MCP content:', e);
|
|
111
|
-
}
|
|
112
|
-
return [];
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Connect to an MCP server
|
|
116
|
-
*/
|
|
117
|
-
async connect(config) {
|
|
118
|
-
const serverName = config.name;
|
|
119
|
-
if (this.servers.has(serverName)) {
|
|
120
|
-
await this.disconnect(serverName);
|
|
121
|
-
}
|
|
122
|
-
const state = {
|
|
123
|
-
client: null,
|
|
124
|
-
transport: null,
|
|
125
|
-
status: MCPServerStatus.CONNECTING,
|
|
126
|
-
config,
|
|
127
|
-
tools: [],
|
|
128
|
-
resources: [],
|
|
129
|
-
prompts: [],
|
|
130
|
-
};
|
|
131
|
-
this.servers.set(serverName, state);
|
|
132
|
-
this.updateStatus(serverName, MCPServerStatus.CONNECTING);
|
|
133
|
-
try {
|
|
134
|
-
const client = new Client({ name: 'simplecli', version: '0.2.1' }, { capabilities: {} });
|
|
135
|
-
let transport;
|
|
136
|
-
if (config.command) {
|
|
137
|
-
// Stdio transport
|
|
138
|
-
transport = new StdioClientTransport({
|
|
139
|
-
command: config.command,
|
|
140
|
-
args: config.args || [],
|
|
141
|
-
env: { ...process.env, ...(config.env || {}) },
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
else if (config.url) {
|
|
145
|
-
// For URL-based transports, we'd need additional SDK imports
|
|
146
|
-
// For now, throw an error suggesting stdio
|
|
147
|
-
throw new Error('URL-based MCP transports require additional configuration. Use stdio transport with command.');
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
throw new Error(`Invalid MCP server config for ${serverName}: missing command or url`);
|
|
151
|
-
}
|
|
152
|
-
// Connect with a 5-second timeout
|
|
153
|
-
await Promise.race([
|
|
154
|
-
client.connect(transport),
|
|
155
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('Connection timeout')), 5000))
|
|
156
|
-
]);
|
|
157
|
-
state.client = client;
|
|
158
|
-
state.transport = transport;
|
|
159
|
-
state.status = MCPServerStatus.CONNECTED;
|
|
160
|
-
// Discover tools, resources, and prompts
|
|
161
|
-
await this.discover(serverName);
|
|
162
|
-
this.updateStatus(serverName, MCPServerStatus.CONNECTED);
|
|
163
|
-
console.log(`✓ Connected to MCP server: ${serverName}`);
|
|
164
|
-
}
|
|
165
|
-
catch (error) {
|
|
166
|
-
state.status = MCPServerStatus.ERROR;
|
|
167
|
-
state.error = error instanceof Error ? error.message : String(error);
|
|
168
|
-
this.updateStatus(serverName, MCPServerStatus.ERROR);
|
|
169
|
-
console.error(`✗ Failed to connect to MCP server ${serverName}:`, state.error);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Connect to all configured servers
|
|
174
|
-
*/
|
|
175
|
-
async connectAll(configs) {
|
|
176
|
-
const serverConfigs = configs || await this.loadConfig();
|
|
177
|
-
await Promise.all(serverConfigs.map(config => this.connect(config).catch(e => {
|
|
178
|
-
console.error(`Failed to connect to ${config.name}:`, e);
|
|
179
|
-
})));
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Disconnect from an MCP server
|
|
183
|
-
*/
|
|
184
|
-
async disconnect(serverName) {
|
|
185
|
-
const state = this.servers.get(serverName);
|
|
186
|
-
if (!state)
|
|
187
|
-
return;
|
|
188
|
-
try {
|
|
189
|
-
if (state.transport) {
|
|
190
|
-
await state.transport.close();
|
|
191
|
-
}
|
|
192
|
-
if (state.client) {
|
|
193
|
-
await state.client.close();
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
catch (e) {
|
|
197
|
-
// Ignore close errors
|
|
198
|
-
}
|
|
199
|
-
this.servers.delete(serverName);
|
|
200
|
-
this.updateStatus(serverName, MCPServerStatus.DISCONNECTED);
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Disconnect from all servers
|
|
204
|
-
*/
|
|
205
|
-
async disconnectAll() {
|
|
206
|
-
await Promise.all(Array.from(this.servers.keys()).map(name => this.disconnect(name)));
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Discover tools, resources, and prompts from a server
|
|
210
|
-
*/
|
|
211
|
-
async discover(serverName) {
|
|
212
|
-
const state = this.servers.get(serverName);
|
|
213
|
-
if (!state?.client)
|
|
214
|
-
return;
|
|
215
|
-
const client = state.client;
|
|
216
|
-
// Discover tools
|
|
217
|
-
try {
|
|
218
|
-
const toolsResult = await client.listTools();
|
|
219
|
-
state.tools = toolsResult.tools.map(tool => ({
|
|
220
|
-
name: tool.name,
|
|
221
|
-
description: tool.description || '',
|
|
222
|
-
serverName,
|
|
223
|
-
inputSchema: tool.inputSchema || {},
|
|
224
|
-
execute: async (args) => {
|
|
225
|
-
const result = await client.callTool({ name: tool.name, arguments: args });
|
|
226
|
-
return result;
|
|
227
|
-
},
|
|
228
|
-
}));
|
|
229
|
-
}
|
|
230
|
-
catch {
|
|
231
|
-
// Server may not support tools
|
|
232
|
-
}
|
|
233
|
-
// Discover resources
|
|
234
|
-
try {
|
|
235
|
-
const resourcesResult = await client.listResources();
|
|
236
|
-
state.resources = resourcesResult.resources.map(resource => ({
|
|
237
|
-
uri: resource.uri,
|
|
238
|
-
name: resource.name,
|
|
239
|
-
description: resource.description,
|
|
240
|
-
mimeType: resource.mimeType,
|
|
241
|
-
serverName,
|
|
242
|
-
}));
|
|
243
|
-
}
|
|
244
|
-
catch {
|
|
245
|
-
// Server may not support resources
|
|
246
|
-
}
|
|
247
|
-
// Discover prompts
|
|
248
|
-
try {
|
|
249
|
-
const promptsResult = await client.listPrompts();
|
|
250
|
-
state.prompts = promptsResult.prompts.map(prompt => ({
|
|
251
|
-
name: prompt.name,
|
|
252
|
-
description: prompt.description,
|
|
253
|
-
serverName,
|
|
254
|
-
arguments: prompt.arguments,
|
|
255
|
-
invoke: async (params) => {
|
|
256
|
-
const stringParams = {};
|
|
257
|
-
for (const [k, v] of Object.entries(params)) {
|
|
258
|
-
stringParams[k] = String(v);
|
|
259
|
-
}
|
|
260
|
-
const result = await client.getPrompt({ name: prompt.name, arguments: stringParams });
|
|
261
|
-
return {
|
|
262
|
-
messages: result.messages.map(m => ({
|
|
263
|
-
role: m.role,
|
|
264
|
-
content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
|
|
265
|
-
})),
|
|
266
|
-
};
|
|
267
|
-
},
|
|
268
|
-
}));
|
|
269
|
-
}
|
|
270
|
-
catch {
|
|
271
|
-
// Server may not support prompts
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Get all discovered tools from all connected servers
|
|
276
|
-
*/
|
|
277
|
-
getAllTools() {
|
|
278
|
-
const tools = [];
|
|
279
|
-
for (const state of this.servers.values()) {
|
|
280
|
-
if (state.status === MCPServerStatus.CONNECTED) {
|
|
281
|
-
tools.push(...state.tools);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
return tools;
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Get all discovered resources from all connected servers
|
|
288
|
-
*/
|
|
289
|
-
getAllResources() {
|
|
290
|
-
const resources = [];
|
|
291
|
-
for (const state of this.servers.values()) {
|
|
292
|
-
if (state.status === MCPServerStatus.CONNECTED) {
|
|
293
|
-
resources.push(...state.resources);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
return resources;
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* Get all discovered prompts from all connected servers
|
|
300
|
-
*/
|
|
301
|
-
getAllPrompts() {
|
|
302
|
-
const prompts = [];
|
|
303
|
-
for (const state of this.servers.values()) {
|
|
304
|
-
if (state.status === MCPServerStatus.CONNECTED) {
|
|
305
|
-
prompts.push(...state.prompts);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
return prompts;
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Get a specific tool by name
|
|
312
|
-
*/
|
|
313
|
-
getTool(name) {
|
|
314
|
-
return this.getAllTools().find(t => t.name === name);
|
|
315
|
-
}
|
|
316
|
-
/**
|
|
317
|
-
* Execute an MCP tool
|
|
318
|
-
*/
|
|
319
|
-
async executeTool(name, args) {
|
|
320
|
-
const tool = this.getTool(name);
|
|
321
|
-
if (!tool) {
|
|
322
|
-
throw new Error(`MCP tool not found: ${name}`);
|
|
323
|
-
}
|
|
324
|
-
return tool.execute(args);
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* Read an MCP resource
|
|
328
|
-
*/
|
|
329
|
-
async readResource(uri) {
|
|
330
|
-
// Find which server has this resource
|
|
331
|
-
for (const state of this.servers.values()) {
|
|
332
|
-
if (state.status !== MCPServerStatus.CONNECTED || !state.client)
|
|
333
|
-
continue;
|
|
334
|
-
const resource = state.resources.find(r => r.uri === uri);
|
|
335
|
-
if (resource) {
|
|
336
|
-
const result = await state.client.readResource({ uri });
|
|
337
|
-
return result;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
throw new Error(`Resource not found: ${uri}`);
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Invoke an MCP prompt
|
|
344
|
-
*/
|
|
345
|
-
async invokePrompt(name, params) {
|
|
346
|
-
const prompt = this.getAllPrompts().find(p => p.name === name);
|
|
347
|
-
if (!prompt) {
|
|
348
|
-
throw new Error(`MCP prompt not found: ${name}`);
|
|
349
|
-
}
|
|
350
|
-
return prompt.invoke(params);
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* Get server status
|
|
354
|
-
*/
|
|
355
|
-
getServerStatus(serverName) {
|
|
356
|
-
return this.servers.get(serverName)?.status || MCPServerStatus.DISCONNECTED;
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* Get all server statuses
|
|
360
|
-
*/
|
|
361
|
-
getAllServerStatuses() {
|
|
362
|
-
const statuses = new Map();
|
|
363
|
-
for (const [name, state] of this.servers) {
|
|
364
|
-
statuses.set(name, state.status);
|
|
365
|
-
}
|
|
366
|
-
return statuses;
|
|
367
|
-
}
|
|
368
|
-
updateStatus(serverName, status) {
|
|
369
|
-
this.onStatusChange?.(serverName, status);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* Create Composio MCP configuration
|
|
374
|
-
* Composio provides pre-built integrations for 250+ tools
|
|
375
|
-
*/
|
|
376
|
-
export function createComposioConfig(apiKey) {
|
|
377
|
-
return {
|
|
378
|
-
name: 'composio',
|
|
379
|
-
command: 'npx',
|
|
380
|
-
args: ['-y', 'composio-core', 'mcp'],
|
|
381
|
-
env: apiKey ? { COMPOSIO_API_KEY: apiKey } : {},
|
|
382
|
-
trust: 'full',
|
|
383
|
-
enabled: true,
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
/**
|
|
387
|
-
* Create filesystem MCP configuration
|
|
388
|
-
*/
|
|
389
|
-
export function createFilesystemConfig(allowedPaths) {
|
|
390
|
-
return {
|
|
391
|
-
name: 'filesystem',
|
|
392
|
-
command: 'npx',
|
|
393
|
-
args: ['-y', '@modelcontextprotocol/server-filesystem', ...allowedPaths],
|
|
394
|
-
trust: 'full',
|
|
395
|
-
enabled: true,
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Create GitHub MCP configuration
|
|
400
|
-
*/
|
|
401
|
-
export function createGitHubConfig(token) {
|
|
402
|
-
return {
|
|
403
|
-
name: 'github',
|
|
404
|
-
command: 'npx',
|
|
405
|
-
args: ['-y', '@modelcontextprotocol/server-github'],
|
|
406
|
-
env: token ? { GITHUB_PERSONAL_ACCESS_TOKEN: token } : {},
|
|
407
|
-
trust: 'full',
|
|
408
|
-
enabled: true,
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* Create memory/context MCP configuration
|
|
413
|
-
*/
|
|
414
|
-
export function createMemoryConfig() {
|
|
415
|
-
return {
|
|
416
|
-
name: 'memory',
|
|
417
|
-
command: 'npx',
|
|
418
|
-
args: ['-y', '@modelcontextprotocol/server-memory'],
|
|
419
|
-
trust: 'full',
|
|
420
|
-
enabled: true,
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* Create Brave Search MCP configuration
|
|
425
|
-
*/
|
|
426
|
-
export function createBraveSearchConfig(apiKey) {
|
|
427
|
-
return {
|
|
428
|
-
name: 'brave-search',
|
|
429
|
-
command: 'npx',
|
|
430
|
-
args: ['-y', '@modelcontextprotocol/server-brave-search'],
|
|
431
|
-
env: apiKey ? { BRAVE_API_KEY: apiKey } : {},
|
|
432
|
-
trust: 'full',
|
|
433
|
-
enabled: true,
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
// Singleton instance
|
|
437
|
-
let mcpManager = null;
|
|
438
|
-
/**
|
|
439
|
-
* Get or create the global MCP manager instance
|
|
440
|
-
*/
|
|
441
|
-
export function getMCPManager() {
|
|
442
|
-
if (!mcpManager) {
|
|
443
|
-
mcpManager = new MCPManager();
|
|
444
|
-
}
|
|
445
|
-
return mcpManager;
|
|
446
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prompt Provider - Manages composition of system prompts
|
|
3
|
-
* Supports built-in defaults, project-specific overrides, and modular personas.
|
|
4
|
-
*/
|
|
5
|
-
export interface PromptOptions {
|
|
6
|
-
cwd: string;
|
|
7
|
-
skillPrompt?: string;
|
|
8
|
-
}
|
|
9
|
-
export declare class PromptProvider {
|
|
10
|
-
/**
|
|
11
|
-
* Builds the full system prompt by composing multiple layers:
|
|
12
|
-
* 1. Built-in system instructions (src/prompts/defaults)
|
|
13
|
-
* 2. Global user overrides (~/.simple/prompts)
|
|
14
|
-
* 3. Project-specific prompts (.simple/prompts)
|
|
15
|
-
* 4. Current skill instructions
|
|
16
|
-
* 5. Local project rules (AGENT.md)
|
|
17
|
-
*/
|
|
18
|
-
getSystemPrompt(options: PromptOptions): Promise<string>;
|
|
19
|
-
private loadFromDirectory;
|
|
20
|
-
private loadProjectRules;
|
|
21
|
-
}
|
|
22
|
-
export declare function getPromptProvider(): PromptProvider;
|
package/dist/prompts/provider.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prompt Provider - Manages composition of system prompts
|
|
3
|
-
* Supports built-in defaults, project-specific overrides, and modular personas.
|
|
4
|
-
*/
|
|
5
|
-
import { readFileSync, existsSync, readdirSync } from 'fs';
|
|
6
|
-
import { join, dirname } from 'path';
|
|
7
|
-
import { fileURLToPath } from 'url';
|
|
8
|
-
import { homedir } from 'os';
|
|
9
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
-
const __dirname = dirname(__filename);
|
|
11
|
-
export class PromptProvider {
|
|
12
|
-
/**
|
|
13
|
-
* Builds the full system prompt by composing multiple layers:
|
|
14
|
-
* 1. Built-in system instructions (src/prompts/defaults)
|
|
15
|
-
* 2. Global user overrides (~/.simple/prompts)
|
|
16
|
-
* 3. Project-specific prompts (.simple/prompts)
|
|
17
|
-
* 4. Current skill instructions
|
|
18
|
-
* 5. Local project rules (AGENT.md)
|
|
19
|
-
*/
|
|
20
|
-
async getSystemPrompt(options) {
|
|
21
|
-
const parts = [];
|
|
22
|
-
// 1. Built-in defaults (Hardcoded in the package)
|
|
23
|
-
const builtInDir = join(__dirname, 'defaults');
|
|
24
|
-
if (existsSync(builtInDir)) {
|
|
25
|
-
parts.push(...this.loadFromDirectory(builtInDir));
|
|
26
|
-
}
|
|
27
|
-
// 2. Global user rules (~/.simple/AGENT.md)
|
|
28
|
-
const globalRulesPath = join(homedir(), '.simple', 'AGENT.md');
|
|
29
|
-
if (existsSync(globalRulesPath)) {
|
|
30
|
-
parts.push('\n## Global Rules\n' + readFileSync(globalRulesPath, 'utf-8'));
|
|
31
|
-
}
|
|
32
|
-
// 3. Project rules (AGENT.md)
|
|
33
|
-
const rules = this.loadProjectRules(options.cwd);
|
|
34
|
-
if (rules) {
|
|
35
|
-
parts.push('\n## Project Rules\n' + rules);
|
|
36
|
-
}
|
|
37
|
-
// 4. Skill-specific prompt (Dynamic based on @skill)
|
|
38
|
-
if (options.skillPrompt) {
|
|
39
|
-
parts.push('\n## Skill Context: ' + options.skillPrompt);
|
|
40
|
-
}
|
|
41
|
-
return parts.join('\n\n').trim();
|
|
42
|
-
}
|
|
43
|
-
loadFromDirectory(dir) {
|
|
44
|
-
try {
|
|
45
|
-
return readdirSync(dir)
|
|
46
|
-
.filter(f => f.endsWith('.md') || f.endsWith('.mdc'))
|
|
47
|
-
.sort() // Ensure deterministic order
|
|
48
|
-
.map(f => readFileSync(join(dir, f), 'utf-8'));
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
return [];
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
loadProjectRules(cwd) {
|
|
55
|
-
const commonPaths = [
|
|
56
|
-
'.simple/AGENT.md',
|
|
57
|
-
'.agent/AGENT.md',
|
|
58
|
-
'AGENT.md',
|
|
59
|
-
'.agent.md',
|
|
60
|
-
'.cursorrules',
|
|
61
|
-
'.aider/agent.md'
|
|
62
|
-
];
|
|
63
|
-
for (const p of commonPaths) {
|
|
64
|
-
const fullPath = join(cwd, p);
|
|
65
|
-
if (existsSync(fullPath)) {
|
|
66
|
-
return readFileSync(fullPath, 'utf-8');
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
let provider = null;
|
|
73
|
-
export function getPromptProvider() {
|
|
74
|
-
if (!provider) {
|
|
75
|
-
provider = new PromptProvider();
|
|
76
|
-
}
|
|
77
|
-
return provider;
|
|
78
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider Bridge: Unified LLM interface via OpenAI SDK
|
|
3
|
-
* Supports OpenAI, DeepSeek, Groq, and other OpenAI-compatible endpoints.
|
|
4
|
-
*/
|
|
5
|
-
export interface Message {
|
|
6
|
-
role: string;
|
|
7
|
-
content: string;
|
|
8
|
-
}
|
|
9
|
-
export interface Provider {
|
|
10
|
-
name: string;
|
|
11
|
-
model: string;
|
|
12
|
-
generateResponse: (systemPrompt: string, messages: Message[]) => Promise<string>;
|
|
13
|
-
}
|
|
14
|
-
export declare const createProviderForModel: (model: string) => Provider;
|
|
15
|
-
export declare const createProvider: () => Provider;
|
package/dist/providers/index.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider Bridge: Unified LLM interface via OpenAI SDK
|
|
3
|
-
* Supports OpenAI, DeepSeek, Groq, and other OpenAI-compatible endpoints.
|
|
4
|
-
*/
|
|
5
|
-
import OpenAI from 'openai';
|
|
6
|
-
const getProviderConfig = () => {
|
|
7
|
-
// 1. OpenAI (Default)
|
|
8
|
-
if (process.env.OPENAI_API_KEY) {
|
|
9
|
-
return {
|
|
10
|
-
apiKey: process.env.OPENAI_API_KEY,
|
|
11
|
-
model: process.env.OPENAI_MODEL || 'gpt-5-mini'
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
// 2. DeepSeek
|
|
15
|
-
if (process.env.DEEPSEEK_API_KEY) {
|
|
16
|
-
return {
|
|
17
|
-
apiKey: process.env.DEEPSEEK_API_KEY,
|
|
18
|
-
baseURL: 'https://api.deepseek.com/v1',
|
|
19
|
-
model: process.env.DEEPSEEK_MODEL || 'deepseek-chat'
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
// 3. Groq
|
|
23
|
-
if (process.env.GROQ_API_KEY) {
|
|
24
|
-
return {
|
|
25
|
-
apiKey: process.env.GROQ_API_KEY,
|
|
26
|
-
baseURL: 'https://api.groq.com/openai/v1',
|
|
27
|
-
model: process.env.GROQ_MODEL || 'llama3-70b-8192'
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
// 4. Mistral
|
|
31
|
-
if (process.env.MISTRAL_API_KEY) {
|
|
32
|
-
return {
|
|
33
|
-
apiKey: process.env.MISTRAL_API_KEY,
|
|
34
|
-
baseURL: 'https://api.mistral.ai/v1',
|
|
35
|
-
model: process.env.MISTRAL_MODEL || 'mistral-large-latest'
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
throw new Error('No supported API key found (OPENAI_API_KEY, DEEPSEEK_API_KEY, GROQ_API_KEY, MISTRAL_API_KEY)');
|
|
39
|
-
};
|
|
40
|
-
export const createProviderForModel = (model) => {
|
|
41
|
-
// Quick heuristic to determine provider for specific model overrides
|
|
42
|
-
// logic can be improved, but this assumes the environment variables set the *default* linkage
|
|
43
|
-
// If a specific model is requested (e.g. for MoE), we try to route it.
|
|
44
|
-
let config = getProviderConfig();
|
|
45
|
-
// Override config if model implies a different provider?
|
|
46
|
-
// For the sake of "Simple-CLI", we assume the default connected provider serves the requested model
|
|
47
|
-
// or we just use OpenAI SDK's flexibility.
|
|
48
|
-
if (model.includes('gpt'))
|
|
49
|
-
config = { ...config, apiKey: process.env.OPENAI_API_KEY, baseURL: undefined };
|
|
50
|
-
else if (model.includes('deepseek'))
|
|
51
|
-
config = { ...config, apiKey: process.env.DEEPSEEK_API_KEY, baseURL: 'https://api.deepseek.com/v1' };
|
|
52
|
-
if (!config.apiKey)
|
|
53
|
-
throw new Error(`Cannot route for model ${model} - missing API key`);
|
|
54
|
-
const client = new OpenAI({
|
|
55
|
-
apiKey: config.apiKey,
|
|
56
|
-
baseURL: config.baseURL
|
|
57
|
-
});
|
|
58
|
-
return {
|
|
59
|
-
name: 'openai-compatible',
|
|
60
|
-
model,
|
|
61
|
-
generateResponse: async (systemPrompt, messages) => {
|
|
62
|
-
try {
|
|
63
|
-
const response = await client.chat.completions.create({
|
|
64
|
-
model: model,
|
|
65
|
-
messages: [
|
|
66
|
-
{ role: 'system', content: systemPrompt },
|
|
67
|
-
...messages.map(m => ({ role: m.role, content: m.content }))
|
|
68
|
-
]
|
|
69
|
-
});
|
|
70
|
-
return response.choices[0]?.message?.content || '';
|
|
71
|
-
}
|
|
72
|
-
catch (e) {
|
|
73
|
-
return `Error calling LLM: ${e instanceof Error ? e.message : e}`; // Fail gracefully
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
};
|
|
78
|
-
export const createProvider = () => {
|
|
79
|
-
const config = getProviderConfig();
|
|
80
|
-
console.log(`🤖 Using model: ${config.model}`);
|
|
81
|
-
return createProviderForModel(config.model);
|
|
82
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Multi-Provider: Manages multiple LLM models for MoE routing via LiteLLM
|
|
3
|
-
* Each tier can use a different model from any provider
|
|
4
|
-
*/
|
|
5
|
-
import { type Provider, type Message } from './index.js';
|
|
6
|
-
import type { Tier, TierConfig } from '../router.js';
|
|
7
|
-
export interface MultiProvider {
|
|
8
|
-
getProvider: (tier: Tier) => Provider;
|
|
9
|
-
generateWithTier: (tier: Tier, systemPrompt: string, messages: Message[]) => Promise<string>;
|
|
10
|
-
}
|
|
11
|
-
export declare const createMultiProvider: (tierConfigs: Map<Tier, TierConfig>) => MultiProvider;
|
package/dist/providers/multi.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Multi-Provider: Manages multiple LLM models for MoE routing via LiteLLM
|
|
3
|
-
* Each tier can use a different model from any provider
|
|
4
|
-
*/
|
|
5
|
-
import { createProviderForModel } from './index.js';
|
|
6
|
-
// Create multi-provider system using LiteLLM
|
|
7
|
-
export const createMultiProvider = (tierConfigs) => {
|
|
8
|
-
const providerCache = new Map();
|
|
9
|
-
const getProvider = (tier) => {
|
|
10
|
-
const cached = providerCache.get(tier);
|
|
11
|
-
if (cached)
|
|
12
|
-
return cached;
|
|
13
|
-
const config = tierConfigs.get(tier);
|
|
14
|
-
if (!config) {
|
|
15
|
-
throw new Error(`No configuration for tier ${tier}`);
|
|
16
|
-
}
|
|
17
|
-
const provider = createProviderForModel(config.model);
|
|
18
|
-
providerCache.set(tier, provider);
|
|
19
|
-
return provider;
|
|
20
|
-
};
|
|
21
|
-
return {
|
|
22
|
-
getProvider,
|
|
23
|
-
generateWithTier: async (tier, systemPrompt, messages) => {
|
|
24
|
-
const provider = getProvider(tier);
|
|
25
|
-
return provider.generateResponse(systemPrompt, messages);
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
};
|