@indiccoder/mentis-cli 1.1.4 → 1.1.5
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/.claude/settings.local.json +8 -0
- package/.mentis/session.json +15 -0
- package/.mentis/sessions/1769189035730.json +23 -0
- package/.mentis/sessions/1769189569160.json +23 -0
- package/.mentis/sessions/1769767538672.json +23 -0
- package/.mentis/sessions/1769767785155.json +23 -0
- package/.mentis/sessions/1769768745802.json +23 -0
- package/.mentis/sessions/1769769600884.json +31 -0
- package/.mentis/sessions/1769770030160.json +31 -0
- package/.mentis/sessions/1769770606004.json +78 -0
- package/.mentis/sessions/1769771084515.json +141 -0
- package/.mentis/sessions/1769881926630.json +57 -0
- package/README.md +17 -0
- package/dist/checkpoint/CheckpointManager.js +92 -0
- package/dist/debug_google.js +61 -0
- package/dist/debug_lite.js +49 -0
- package/dist/debug_lite_headers.js +57 -0
- package/dist/debug_search.js +16 -0
- package/dist/index.js +10 -0
- package/dist/mcp/JsonRpcClient.js +16 -0
- package/dist/mcp/McpConfig.js +132 -0
- package/dist/mcp/McpManager.js +189 -0
- package/dist/repl/PersistentShell.js +20 -1
- package/dist/repl/ReplManager.js +410 -138
- package/dist/tools/AskQuestionTool.js +172 -0
- package/dist/tools/EditFileTool.js +141 -0
- package/dist/tools/FileTools.js +7 -1
- package/dist/tools/PlanModeTool.js +53 -0
- package/dist/tools/WebSearchTool.js +190 -27
- package/dist/ui/DiffViewer.js +110 -0
- package/dist/ui/InputBox.js +16 -2
- package/dist/ui/MultiFileSelector.js +123 -0
- package/dist/ui/PlanModeUI.js +105 -0
- package/dist/ui/ToolExecutor.js +154 -0
- package/dist/ui/UIManager.js +12 -2
- package/docs/MCP_INTEGRATION.md +290 -0
- package/google_dump.html +18 -0
- package/lite_dump.html +176 -0
- package/lite_headers_dump.html +176 -0
- package/package.json +16 -5
- package/scripts/test_exa_mcp.ts +90 -0
- package/src/checkpoint/CheckpointManager.ts +102 -0
- package/src/debug_google.ts +30 -0
- package/src/debug_lite.ts +18 -0
- package/src/debug_lite_headers.ts +25 -0
- package/src/debug_search.ts +18 -0
- package/src/index.ts +12 -0
- package/src/mcp/JsonRpcClient.ts +19 -0
- package/src/mcp/McpConfig.ts +153 -0
- package/src/mcp/McpManager.ts +224 -0
- package/src/repl/PersistentShell.ts +24 -1
- package/src/repl/ReplManager.ts +1521 -1204
- package/src/tools/AskQuestionTool.ts +197 -0
- package/src/tools/EditFileTool.ts +172 -0
- package/src/tools/FileTools.ts +3 -0
- package/src/tools/PlanModeTool.ts +50 -0
- package/src/tools/WebSearchTool.ts +235 -63
- package/src/ui/DiffViewer.ts +117 -0
- package/src/ui/InputBox.ts +17 -2
- package/src/ui/MultiFileSelector.ts +135 -0
- package/src/ui/PlanModeUI.ts +121 -0
- package/src/ui/ToolExecutor.ts +182 -0
- package/src/ui/UIManager.ts +15 -2
- package/console.log(tick) +0 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.McpManager = void 0;
|
|
7
|
+
const McpClient_1 = require("./McpClient");
|
|
8
|
+
const McpConfig_1 = require("./McpConfig");
|
|
9
|
+
const ora_1 = __importDefault(require("ora"));
|
|
10
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
+
class McpManager {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.connections = new Map();
|
|
14
|
+
this.configManager = new McpConfig_1.McpConfigManager();
|
|
15
|
+
}
|
|
16
|
+
getConfig() {
|
|
17
|
+
return this.configManager;
|
|
18
|
+
}
|
|
19
|
+
async connectToServer(serverName) {
|
|
20
|
+
const config = this.configManager.getServer(serverName);
|
|
21
|
+
if (!config) {
|
|
22
|
+
console.error(chalk_1.default.red(`MCP server "${serverName}" not found in configuration`));
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
// Check if already connected
|
|
26
|
+
if (this.connections.has(serverName)) {
|
|
27
|
+
console.log(chalk_1.default.yellow(`Already connected to ${serverName}`));
|
|
28
|
+
return this.connections.get(serverName);
|
|
29
|
+
}
|
|
30
|
+
const spinner = (0, ora_1.default)(`Connecting to MCP server: ${serverName}...`).start();
|
|
31
|
+
try {
|
|
32
|
+
// Set environment variables if specified
|
|
33
|
+
if (config.env) {
|
|
34
|
+
for (const [key, value] of Object.entries(config.env)) {
|
|
35
|
+
if (value) {
|
|
36
|
+
process.env[key] = value;
|
|
37
|
+
}
|
|
38
|
+
else if (!process.env[key]) {
|
|
39
|
+
spinner.warn(chalk_1.default.yellow(`Environment variable ${key} is required for ${serverName}`));
|
|
40
|
+
console.log(chalk_1.default.dim(`Set it with: export ${key}=your_key`));
|
|
41
|
+
console.log(chalk_1.default.dim(`Or add it to your MCP configuration`));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const client = new McpClient_1.McpClient(config.command, config.args);
|
|
46
|
+
await client.initialize();
|
|
47
|
+
const tools = await client.listTools();
|
|
48
|
+
const connection = {
|
|
49
|
+
client,
|
|
50
|
+
config,
|
|
51
|
+
tools,
|
|
52
|
+
connectedAt: new Date()
|
|
53
|
+
};
|
|
54
|
+
this.connections.set(serverName, connection);
|
|
55
|
+
spinner.succeed(chalk_1.default.green(`Connected to ${client.serverName}!`));
|
|
56
|
+
if (tools.length > 0) {
|
|
57
|
+
console.log(chalk_1.default.green(`Added ${tools.length} tools:`));
|
|
58
|
+
tools.forEach(t => {
|
|
59
|
+
const description = t.description.length > 60
|
|
60
|
+
? t.description.substring(0, 60) + '...'
|
|
61
|
+
: t.description;
|
|
62
|
+
console.log(chalk_1.default.dim(` - ${chalk_1.default.cyan(t.name)}: ${description}`));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
console.log(chalk_1.default.yellow('No tools available from this server'));
|
|
67
|
+
}
|
|
68
|
+
return connection;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
spinner.fail(chalk_1.default.red(`Failed to connect to ${serverName}: ${error.message}`));
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async disconnectFromServer(serverName) {
|
|
76
|
+
const connection = this.connections.get(serverName);
|
|
77
|
+
if (!connection) {
|
|
78
|
+
console.log(chalk_1.default.yellow(`Not connected to ${serverName}`));
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
connection.client.disconnect();
|
|
83
|
+
this.connections.delete(serverName);
|
|
84
|
+
console.log(chalk_1.default.green(`Disconnected from ${serverName}`));
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
console.error(chalk_1.default.red(`Error disconnecting from ${serverName}: ${error.message}`));
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
disconnectAll() {
|
|
93
|
+
const serverNames = Array.from(this.connections.keys());
|
|
94
|
+
for (const name of serverNames) {
|
|
95
|
+
this.disconnectFromServer(name);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
getConnections() {
|
|
99
|
+
return Array.from(this.connections.values());
|
|
100
|
+
}
|
|
101
|
+
getConnection(name) {
|
|
102
|
+
return this.connections.get(name);
|
|
103
|
+
}
|
|
104
|
+
getAllTools() {
|
|
105
|
+
const allTools = [];
|
|
106
|
+
for (const connection of this.connections.values()) {
|
|
107
|
+
allTools.push(...connection.tools);
|
|
108
|
+
}
|
|
109
|
+
return allTools;
|
|
110
|
+
}
|
|
111
|
+
getServerNames() {
|
|
112
|
+
return Array.from(this.connections.keys());
|
|
113
|
+
}
|
|
114
|
+
getAvailableServers() {
|
|
115
|
+
return this.configManager.getConfig().servers;
|
|
116
|
+
}
|
|
117
|
+
async autoConnect() {
|
|
118
|
+
const autoConnectServers = this.configManager.getAutoConnectServers();
|
|
119
|
+
if (autoConnectServers.length === 0) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
console.log(chalk_1.default.blue(`\nAuto-connecting to ${autoConnectServers.length} MCP servers...`));
|
|
123
|
+
for (const config of autoConnectServers) {
|
|
124
|
+
await this.connectToServer(config.name);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async listServers() {
|
|
128
|
+
const availableServers = this.configManager.getConfig().servers;
|
|
129
|
+
const connectedServers = this.getServerNames();
|
|
130
|
+
if (availableServers.length === 0) {
|
|
131
|
+
console.log(chalk_1.default.yellow('No MCP servers configured.'));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
console.log(chalk_1.default.cyan('\nMCP Servers:\n'));
|
|
135
|
+
for (const server of availableServers) {
|
|
136
|
+
const isConnected = connectedServers.includes(server.name);
|
|
137
|
+
const status = isConnected ? chalk_1.default.green('● Connected') : chalk_1.default.gray('○ Disconnected');
|
|
138
|
+
const auto = server.autoConnect ? chalk_1.default.dim('[auto]') : '';
|
|
139
|
+
console.log(`${status} ${chalk_1.default.bold(server.name)} ${auto}`);
|
|
140
|
+
if (server.description) {
|
|
141
|
+
console.log(chalk_1.default.dim(` ${server.description}`));
|
|
142
|
+
}
|
|
143
|
+
if (isConnected) {
|
|
144
|
+
const connection = this.getConnection(server.name);
|
|
145
|
+
if (connection && connection.tools.length > 0) {
|
|
146
|
+
console.log(chalk_1.default.dim(` Tools: ${connection.tools.map(t => t.name).join(', ')}`));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
console.log('');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async addServer(name, command, args, description) {
|
|
153
|
+
const serverConfig = {
|
|
154
|
+
name,
|
|
155
|
+
command,
|
|
156
|
+
args,
|
|
157
|
+
description,
|
|
158
|
+
autoConnect: false
|
|
159
|
+
};
|
|
160
|
+
this.configManager.addServer(serverConfig);
|
|
161
|
+
console.log(chalk_1.default.green(`Added MCP server "${name}" to configuration`));
|
|
162
|
+
}
|
|
163
|
+
async removeServer(name) {
|
|
164
|
+
// Disconnect if connected
|
|
165
|
+
if (this.connections.has(name)) {
|
|
166
|
+
await this.disconnectFromServer(name);
|
|
167
|
+
}
|
|
168
|
+
this.configManager.removeServer(name);
|
|
169
|
+
console.log(chalk_1.default.green(`Removed MCP server "${name}" from configuration`));
|
|
170
|
+
}
|
|
171
|
+
async testConnection(serverName) {
|
|
172
|
+
const connection = this.getConnection(serverName);
|
|
173
|
+
if (!connection) {
|
|
174
|
+
console.log(chalk_1.default.red(`Not connected to ${serverName}`));
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
// Try to list tools as a test
|
|
179
|
+
await connection.client.listTools();
|
|
180
|
+
console.log(chalk_1.default.green(`${serverName} connection is healthy`));
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
console.log(chalk_1.default.red(`${serverName} connection test failed: ${error.message}`));
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
exports.McpManager = McpManager;
|
|
@@ -13,6 +13,7 @@ class PersistentShell {
|
|
|
13
13
|
this.delimiter = 'MENTIS_SHELL_DELIMITER';
|
|
14
14
|
this.resolveCallback = null;
|
|
15
15
|
this.rejectCallback = null;
|
|
16
|
+
this.COMMAND_TIMEOUT = 120000; // 2 minutes timeout for shell commands
|
|
16
17
|
// Lazy init: Do not spawn here.
|
|
17
18
|
}
|
|
18
19
|
initialize() {
|
|
@@ -60,7 +61,25 @@ class PersistentShell {
|
|
|
60
61
|
this.resolveCallback = resolve;
|
|
61
62
|
this.rejectCallback = reject;
|
|
62
63
|
this.buffer = '';
|
|
63
|
-
|
|
64
|
+
// Set timeout to prevent indefinite hangs
|
|
65
|
+
const timeout = setTimeout(() => {
|
|
66
|
+
this.resolveCallback = null;
|
|
67
|
+
this.rejectCallback = null;
|
|
68
|
+
reject(new Error(`Shell command timeout after ${this.COMMAND_TIMEOUT}ms`));
|
|
69
|
+
}, this.COMMAND_TIMEOUT);
|
|
70
|
+
// Store timeout for cleanup
|
|
71
|
+
const originalResolve = resolve;
|
|
72
|
+
const wrappedResolve = (output) => {
|
|
73
|
+
clearTimeout(timeout);
|
|
74
|
+
originalResolve(output);
|
|
75
|
+
};
|
|
76
|
+
this.resolveCallback = wrappedResolve;
|
|
77
|
+
let cleanCommand = command.replace(/\n/g, '; ');
|
|
78
|
+
// Fix: PowerShell alias 'curl' -> 'Invoke-WebRequest' causes issues for linux-style curl commands.
|
|
79
|
+
// Force usage of 'curl.exe' if on Windows.
|
|
80
|
+
if (os_1.default.platform() === 'win32') {
|
|
81
|
+
cleanCommand = cleanCommand.replace(/(^|[\s|;&])curl(\s|$)/g, '$1curl.exe$2');
|
|
82
|
+
}
|
|
64
83
|
const fullCommand = `${cleanCommand}; echo "${this.delimiter}"\n`;
|
|
65
84
|
this.process?.stdin.write(fullCommand);
|
|
66
85
|
});
|