@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,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"timestamp": 1769881926630,
|
|
3
|
+
"name": "session-1769881926630",
|
|
4
|
+
"history": [
|
|
5
|
+
{
|
|
6
|
+
"role": "user",
|
|
7
|
+
"content": "Repository Structure:\n├── .claude/\n│ └── settings.local.json\n├── .mentis/\n│ ├── commands/\n│ │ └── ls.md\n│ ├── sessions/\n│ │ ├── 1769189035730.json\n│ │ ├── 1769189569160.json\n│ │ ├── 1769767538672.json\n│ │ ├── 1769767785155.json\n│ │ ├── 1769768745802.json\n│ │ ├── 1769769600884.json\n│ │ ├── 1769770030160.json\n│ │ ├── 1769770606004.json\n│ │ └── 1769771084515.json\n│ └── session.json\n├── docs/\n│ └── SKILLS.md\n├── examples/\n│ └── skills/\n│ ├── code-reviewer/\n│ │ └── SKILL.md\n│ ├── commit-helper/\n│ │ └── SKILL.md\n│ └── pdf-processing/\n│ └── SKILL.md\n├── scripts/\n│ ├── test_config_update.ts\n│ ├── test_features.ts\n│ ├── test_glm.ts\n│ └── test_models.ts\n├── src/\n│ ├── checkpoint/\n│ │ └── CheckpointManager.ts\n│ ├── commands/\n│ │ ├── __tests__/\n│ │ │ └── CommandManager.test.ts\n│ │ ├── Command.ts\n│ │ ├── CommandCreator.ts\n│ │ ├── CommandManager.ts\n│ │ └── SlashCommandTool.ts\n│ ├── config/\n│ │ └── ConfigManager.ts\n│ ├── context/\n│ │ ├── ContextManager.ts\n│ │ └── RepoMapper.ts\n│ ├── llm/\n│ │ ├── ModelInterface.ts\n│ │ └── OpenAIClient.ts\n│ ├── mcp/\n│ │ ├── JsonRpcClient.ts\n│ │ └── McpClient.ts\n│ ├── repl/\n│ │ ├── PersistentShell.ts\n│ │ └── ReplManager.ts\n│ ├── skills/\n│ │ ├── __tests__/\n│ │ │ └── SkillsManager.test.ts\n│ │ ├── LoadSkillTool.ts\n│ │ ├── Skill.ts\n│ │ ├── SkillCreator.ts\n│ │ └── SkillsManager.ts\n│ ├── tools/\n│ │ ├── FileTools.ts\n│ │ ├── GitTools.ts\n│ │ ├── PersistentShellTool.ts\n│ │ ├── SearchTools.ts\n│ │ ├── Tool.ts\n│ │ └── WebSearchTool.ts\n│ ├── ui/\n│ │ ├── InputBox.ts\n│ │ └── UIManager.ts\n│ ├── utils/\n│ │ ├── __mocks__/\n│ │ │ └── chalk.ts\n│ │ ├── __tests__/\n│ │ │ └── ContextVisualizer.test.ts\n│ │ ├── ContextVisualizer.ts\n│ │ ├── ConversationCompacter.ts\n│ │ ├── ProjectInitializer.ts\n│ │ └── UpdateManager.ts\n│ ├── debug_google.ts\n│ ├── debug_lite_headers.ts\n│ ├── debug_lite.ts\n│ ├── debug_search.ts\n│ └── index.ts\n├── .gitignore\n├── ARCHITECTURE.md\n├── CONTRIBUTING.md\n├── debug_fs.js\n├── google_dump.html\n├── lite_dump.html\n├── lite_headers_dump.html\n├── package-lock.json\n├── package.json\n├── README.md\n├── screenshot_1765779883482_9b30.png\n└── tsconfig.json\n\n\n\n\nUser Question: Available Custom Commands:\n/ls [directory]: List all files in current directory\n\nhi do you have mcp capability\n[SYSTEM: You are in BUILD mode. Focus on implementing working code that solves the user request efficiently.]"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"role": "assistant",
|
|
11
|
+
"content": "\nYes, I do have MCP (Model Context Protocol) capability! Looking at the repository structure, I can see there's a dedicated MCP implementation in the `src/mcp/` directory with:\n\n- `JsonRpcClient.ts` - Handles JSON-RPC communication\n- `McpClient.ts` - Main MCP client implementation\n\nThe MCP system allows for integrating external tools and services through a standardized protocol. Let me check what MCP functionality is currently available:\n",
|
|
12
|
+
"tool_calls": [
|
|
13
|
+
{
|
|
14
|
+
"function": {
|
|
15
|
+
"arguments": "{\"filePath\":\"src/mcp/McpClient.ts\"}",
|
|
16
|
+
"name": "read_file"
|
|
17
|
+
},
|
|
18
|
+
"id": "call_-7937540705308331019",
|
|
19
|
+
"index": 0,
|
|
20
|
+
"type": "function"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"role": "tool",
|
|
26
|
+
"tool_call_id": "call_-7937540705308331019",
|
|
27
|
+
"name": "read_file",
|
|
28
|
+
"content": "import { JsonRpcClient } from './JsonRpcClient';\r\nimport { Tool } from '../tools/Tool';\r\n\r\nexport class McpClient {\r\n private rpc: JsonRpcClient;\r\n public serverName: string = 'unknown';\r\n\r\n constructor(command: string, args: string[]) {\r\n this.rpc = new JsonRpcClient(command, args);\r\n }\r\n\r\n async initialize() {\r\n const result = await this.rpc.sendRequest('initialize', {\r\n protocolVersion: '2024-11-05',\r\n capabilities: {},\r\n clientInfo: {\r\n name: 'mentis-cli',\r\n version: '1.0.0',\r\n },\r\n });\r\n\r\n this.serverName = result.serverInfo.name;\r\n\r\n // Notify initialized\r\n this.rpc.sendNotification('notifications/initialized');\r\n return result;\r\n }\r\n\r\n async listTools(): Promise<Tool[]> {\r\n const result = await this.rpc.sendRequest('tools/list');\r\n const mcpTools = result.tools || [];\r\n\r\n return mcpTools.map((t: any) => new McpToolAdapter(this, t));\r\n }\r\n\r\n async callTool(name: string, args: any): Promise<any> {\r\n return this.rpc.sendRequest('tools/call', {\r\n name,\r\n arguments: args,\r\n });\r\n }\r\n\r\n disconnect() {\r\n this.rpc.disconnect();\r\n }\r\n}\r\n\r\nclass McpToolAdapter implements Tool {\r\n private client: McpClient;\r\n public name: string;\r\n public description: string;\r\n public parameters: any;\r\n\r\n constructor(client: McpClient, toolDef: any) {\r\n this.client = client;\r\n this.name = toolDef.name;\r\n this.description = toolDef.description || '';\r\n this.parameters = toolDef.inputSchema || {};\r\n }\r\n\r\n async execute(args: any): Promise<string> {\r\n const result = await this.client.callTool(this.name, args);\r\n // MCP returns { content: [ { type: 'text', text: '...' } ], isError: boolean }\r\n if (result.isError) {\r\n throw new Error('MCP Tool Error');\r\n }\r\n\r\n // Extract text content\r\n if (result.content && Array.isArray(result.content)) {\r\n return result.content.map((c: any) => c.text).join('\\n');\r\n }\r\n\r\n return JSON.stringify(result);\r\n }\r\n}\r\n"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"role": "assistant",
|
|
32
|
+
"content": "\n",
|
|
33
|
+
"tool_calls": [
|
|
34
|
+
{
|
|
35
|
+
"function": {
|
|
36
|
+
"arguments": "{\"filePath\":\"src/mcp/JsonRpcClient.ts\"}",
|
|
37
|
+
"name": "read_file"
|
|
38
|
+
},
|
|
39
|
+
"id": "call_-7937555136399364450",
|
|
40
|
+
"index": 0,
|
|
41
|
+
"type": "function"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"role": "tool",
|
|
47
|
+
"tool_call_id": "call_-7937555136399364450",
|
|
48
|
+
"name": "read_file",
|
|
49
|
+
"content": "import { spawn, ChildProcess } from 'child_process';\r\nimport * as readline from 'readline';\r\n\r\nexport interface JsonRpcRequest {\r\n jsonrpc: '2.0';\r\n method: string;\r\n params?: any;\r\n id?: number | string;\r\n}\r\n\r\nexport interface JsonRpcResponse {\r\n jsonrpc: '2.0';\r\n id: number | string | null;\r\n result?: any;\r\n error?: {\r\n code: number;\r\n message: string;\r\n data?: any;\r\n };\r\n}\r\n\r\nexport class JsonRpcClient {\r\n private process: ChildProcess;\r\n private sequence = 0;\r\n private pendingRequests = new Map<number | string, { resolve: Function; reject: Function }>();\r\n\r\n constructor(command: string, args: string[]) {\r\n this.process = spawn(command, args, {\r\n stdio: ['pipe', 'pipe', 'inherit'], // stdin, stdout, stderr\r\n });\r\n\r\n if (!this.process.stdout) {\r\n throw new Error('Failed to open stdout for MCP process');\r\n }\r\n\r\n const rl = readline.createInterface({ input: this.process.stdout });\r\n rl.on('line', (line) => this.handleMessage(line));\r\n\r\n this.process.on('error', (err) => console.error('MCP Process Error:', err));\r\n this.process.on('exit', (code) => console.log('MCP Process Exited:', code));\r\n }\r\n\r\n private handleMessage(line: string) {\r\n try {\r\n if (!line.trim()) return;\r\n const message = JSON.parse(line);\r\n\r\n // Handle Response\r\n if (message.id !== undefined && (message.result !== undefined || message.error !== undefined)) {\r\n const handler = this.pendingRequests.get(message.id);\r\n if (handler) {\r\n this.pendingRequests.delete(message.id);\r\n if (message.error) {\r\n handler.reject(new Error(message.error.message));\r\n } else {\r\n handler.resolve(message.result);\r\n }\r\n }\r\n } else {\r\n // Handle Notification or Request from server (not implemented deep yet)\r\n // console.log('Received notification from MCP:', message);\r\n }\r\n } catch (e) {\r\n console.error('Failed to parse MCP message:', line, e);\r\n }\r\n }\r\n\r\n public async sendRequest(method: string, params?: any): Promise<any> {\r\n const id = this.sequence++;\r\n const request: JsonRpcRequest = {\r\n jsonrpc: '2.0',\r\n method,\r\n params,\r\n id,\r\n };\r\n\r\n return new Promise((resolve, reject) => {\r\n this.pendingRequests.set(id, { resolve, reject });\r\n try {\r\n if (!this.process.stdin) throw new Error('Stdin not available');\r\n const data = JSON.stringify(request) + '\\n';\r\n this.process.stdin.write(data);\r\n } catch (e) {\r\n this.pendingRequests.delete(id);\r\n reject(e);\r\n }\r\n });\r\n }\r\n\r\n public sendNotification(method: string, params?: any) {\r\n if (!this.process.stdin) return;\r\n const notification: JsonRpcRequest = {\r\n jsonrpc: '2.0',\r\n method,\r\n params,\r\n };\r\n this.process.stdin.write(JSON.stringify(notification) + '\\n');\r\n }\r\n\r\n public disconnect() {\r\n this.process.kill();\r\n }\r\n}\r\n"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"role": "assistant",
|
|
53
|
+
"content": "\nYes, I have MCP (Model Context Protocol) capability! The system includes a full MCP implementation with:\n\n**MCP Components:**\n- `McpClient.ts` - Main client for communicating with MCP servers\n- `JsonRpcClient.ts` - JSON-RPC communication handler\n- Support for dynamic tool loading from MCP servers\n\n**Key Features:**\n1. **Server Initialization** - Connects to MCP servers using command-line processes\n2. **Tool Discovery** - Automatically lists available tools from connected servers\n3. **Tool Execution** - Calls MCP tools with arguments and returns results\n4. **Error Handling** - Proper error handling and process management\n\n**How it works:**\n- Spawns external MCP server processes\n- Uses JSON-RPC 2.0 protocol for communication\n- Adapts MCP tools to the internal Tool interface\n- Supports text content extraction from tool responses\n\nThe MCP system allows integrating external tools and services seamlessly into the Mentis CLI, extending functionality beyond the built-in tools.\n\nWould you like me to show you how to use it or help you set up an MCP server connection?"
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"files": []
|
|
57
|
+
}
|
package/README.md
CHANGED
|
@@ -53,6 +53,23 @@ Type `/model` inside the CLI to launch the interactive configuration wizard:
|
|
|
53
53
|
|
|
54
54
|
*Credentials are stored securely in `~/.mentisrc`.*
|
|
55
55
|
|
|
56
|
+
### Web Search (Optional)
|
|
57
|
+
|
|
58
|
+
Mentis includes web search capabilities for documentation and error solving. To enable it:
|
|
59
|
+
|
|
60
|
+
1. **Get a free Tavily API key** at https://tavily.com
|
|
61
|
+
2. Add to your `.env` file in your project directory:
|
|
62
|
+
```
|
|
63
|
+
TAVILY_API_KEY=your_key_here
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Alternatively, you can use **Exa** via MCP:
|
|
67
|
+
```bash
|
|
68
|
+
export EXA_API_KEY=your_key_here
|
|
69
|
+
mentis
|
|
70
|
+
/mcp connect "Exa Search"
|
|
71
|
+
```
|
|
72
|
+
|
|
56
73
|
## 📖 Usage
|
|
57
74
|
|
|
58
75
|
### Modes
|
|
@@ -49,5 +49,97 @@ class CheckpointManager {
|
|
|
49
49
|
const filePath = path_1.default.join(this.checkpointDir, `${name}.json`);
|
|
50
50
|
return fs_extra_1.default.existsSync(filePath);
|
|
51
51
|
}
|
|
52
|
+
// ─── Per-Directory Local Session Methods ───────────────────────────────
|
|
53
|
+
getLocalSessionsDir(cwd) {
|
|
54
|
+
return path_1.default.join(cwd, '.mentis', 'sessions');
|
|
55
|
+
}
|
|
56
|
+
saveLocalSession(cwd, history, files) {
|
|
57
|
+
const timestamp = Date.now();
|
|
58
|
+
const checkpoint = {
|
|
59
|
+
timestamp,
|
|
60
|
+
name: `session-${timestamp}`,
|
|
61
|
+
history,
|
|
62
|
+
files
|
|
63
|
+
};
|
|
64
|
+
const sessionsDir = this.getLocalSessionsDir(cwd);
|
|
65
|
+
fs_extra_1.default.ensureDirSync(sessionsDir);
|
|
66
|
+
const filePath = path_1.default.join(sessionsDir, `${timestamp}.json`);
|
|
67
|
+
fs_extra_1.default.writeJsonSync(filePath, checkpoint, { spaces: 2 });
|
|
68
|
+
return filePath;
|
|
69
|
+
}
|
|
70
|
+
loadLocalSession(cwd, sessionId) {
|
|
71
|
+
const sessionsDir = this.getLocalSessionsDir(cwd);
|
|
72
|
+
if (!fs_extra_1.default.existsSync(sessionsDir))
|
|
73
|
+
return null;
|
|
74
|
+
let filePath;
|
|
75
|
+
if (sessionId) {
|
|
76
|
+
filePath = path_1.default.join(sessionsDir, `${sessionId}.json`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Load most recent
|
|
80
|
+
const sessions = this.listLocalSessions(cwd);
|
|
81
|
+
if (sessions.length === 0)
|
|
82
|
+
return null;
|
|
83
|
+
filePath = path_1.default.join(sessionsDir, `${sessions[0].id}.json`);
|
|
84
|
+
}
|
|
85
|
+
if (fs_extra_1.default.existsSync(filePath)) {
|
|
86
|
+
return fs_extra_1.default.readJsonSync(filePath);
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
listLocalSessions(cwd) {
|
|
91
|
+
const sessionsDir = this.getLocalSessionsDir(cwd);
|
|
92
|
+
if (!fs_extra_1.default.existsSync(sessionsDir))
|
|
93
|
+
return [];
|
|
94
|
+
const files = fs_extra_1.default.readdirSync(sessionsDir);
|
|
95
|
+
return files
|
|
96
|
+
.filter(f => f.endsWith('.json'))
|
|
97
|
+
.map(f => {
|
|
98
|
+
const filePath = path_1.default.join(sessionsDir, f);
|
|
99
|
+
try {
|
|
100
|
+
const data = fs_extra_1.default.readJsonSync(filePath);
|
|
101
|
+
// Extract meaningful preview from LAST user message (to show current state)
|
|
102
|
+
const lastUserMsg = [...(data.history || [])].reverse().find(m => m.role === 'user');
|
|
103
|
+
let preview = 'No preview';
|
|
104
|
+
if (lastUserMsg?.content) {
|
|
105
|
+
let clean = lastUserMsg.content;
|
|
106
|
+
// 1. Remove Repository Structure (explicitly)
|
|
107
|
+
clean = clean.replace(/Repository Structure:[\s\S]*?(?=\n\n|$)/g, '');
|
|
108
|
+
// 2. Remove "User Question:" label (if context insertion logic used it)
|
|
109
|
+
clean = clean.replace(/User Question:\s*/g, '');
|
|
110
|
+
// 3. Remove "Available Custom Commands" block
|
|
111
|
+
clean = clean.replace(/Available Custom Commands:[\s\S]*?(?=\n\n|$)/g, '');
|
|
112
|
+
// 4. Remove "Available Skills" block (if present)
|
|
113
|
+
clean = clean.replace(/Available Skills \([\s\S]*?(?=\n\n|$)/g, '');
|
|
114
|
+
clean = clean.replace(/Available Skills:[\s\S]*?(?=\n\n|$)/g, '');
|
|
115
|
+
// 5. Remove [SYSTEM: ...] instructions at the end
|
|
116
|
+
clean = clean.replace(/\n\[SYSTEM:[\s\S]*?\]$/g, '');
|
|
117
|
+
// 6. Clean up code blocks references/markdown if they were just context
|
|
118
|
+
const text = clean.trim();
|
|
119
|
+
if (text) {
|
|
120
|
+
// Take the first 50 chars of what's left
|
|
121
|
+
preview = text.substring(0, 50).replace(/\n/g, ' ');
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
preview = 'New Session';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
id: f.replace('.json', ''),
|
|
129
|
+
timestamp: data.timestamp,
|
|
130
|
+
messageCount: data.history?.length || 0,
|
|
131
|
+
preview: preview.length >= 50 ? preview + '...' : preview
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
.filter((s) => s !== null)
|
|
139
|
+
.sort((a, b) => b.timestamp - a.timestamp); // Most recent first
|
|
140
|
+
}
|
|
141
|
+
localSessionExists(cwd) {
|
|
142
|
+
return this.listLocalSessions(cwd).length > 0;
|
|
143
|
+
}
|
|
52
144
|
}
|
|
53
145
|
exports.CheckpointManager = CheckpointManager;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const child_process_1 = require("child_process");
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const query = "expo go latest sdk";
|
|
39
|
+
const url = `https://www.google.com/search?q=${encodeURIComponent(query)}&hl=en`;
|
|
40
|
+
console.log(`Fetching Google: ${url}`);
|
|
41
|
+
try {
|
|
42
|
+
// Mimic standard browser
|
|
43
|
+
const userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
44
|
+
const cmd = `curl -s -L -A "${userAgent}" "${url}"`;
|
|
45
|
+
const html = (0, child_process_1.execSync)(cmd, { encoding: 'utf-8' });
|
|
46
|
+
fs.writeFileSync('google_dump.html', html);
|
|
47
|
+
console.log('Dumped HTML to google_dump.html. Length:', html.length);
|
|
48
|
+
if (html.includes('Captcha') || html.includes('unusual traffic')) {
|
|
49
|
+
console.log('BLOCKED by Google Captcha');
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.log('Seems OK? Checking for result markers...');
|
|
53
|
+
// Google uses complex class names, but often "h3" is title
|
|
54
|
+
if (html.includes('<h3')) {
|
|
55
|
+
console.log('Found h3 tags (likely titles).');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
console.error('Error:', e.message);
|
|
61
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const child_process_1 = require("child_process");
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const query = "expo go latest sdk";
|
|
39
|
+
const url = `https://lite.duckduckgo.com/lite/?q=${encodeURIComponent(query)}`;
|
|
40
|
+
console.log(`Fetching Lite DDG: ${url}`);
|
|
41
|
+
try {
|
|
42
|
+
const cmd = `curl -s -L -A "Mozilla/5.0" "${url}"`;
|
|
43
|
+
const html = (0, child_process_1.execSync)(cmd, { encoding: 'utf-8' });
|
|
44
|
+
fs.writeFileSync('lite_dump.html', html);
|
|
45
|
+
console.log('Dumped HTML to lite_dump.html');
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
console.error('Error:', e.message);
|
|
49
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const child_process_1 = require("child_process");
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const query = "expo go latest sdk";
|
|
39
|
+
const url = `https://lite.duckduckgo.com/lite/?q=${encodeURIComponent(query)}`;
|
|
40
|
+
console.log(`Testing Lite Headers: ${url}`);
|
|
41
|
+
try {
|
|
42
|
+
const cmd = `curl -s -L -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" -H "Referer: https://duckduckgo.com/" -H "Accept-Language: en-US,en;q=0.9" "${url}"`;
|
|
43
|
+
const html = (0, child_process_1.execSync)(cmd, { encoding: 'utf-8' });
|
|
44
|
+
fs.writeFileSync('lite_headers_dump.html', html);
|
|
45
|
+
if (html.includes('anomaly-modal')) {
|
|
46
|
+
console.log('STILL BLOCKED by Captcha');
|
|
47
|
+
}
|
|
48
|
+
else if (html.includes('result-link')) {
|
|
49
|
+
console.log('SUCCESS! Found result links.');
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.log('Unknown response. Check dump.');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
console.error('Error:', e.message);
|
|
57
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const child_process_1 = require("child_process");
|
|
4
|
+
const query = "test";
|
|
5
|
+
const url = `https://lite.duckduckgo.com/lite/?q=${encodeURIComponent(query)}`;
|
|
6
|
+
console.log(`Testing Lite DDG: ${url}`);
|
|
7
|
+
try {
|
|
8
|
+
const cmd = `curl -s -L -A "Mozilla/5.0" "${url}"`;
|
|
9
|
+
const html = (0, child_process_1.execSync)(cmd, { encoding: 'utf-8' });
|
|
10
|
+
console.log('HTML Length:', html.length);
|
|
11
|
+
console.log('Snippet (first 2000 chars):');
|
|
12
|
+
console.log(html.substring(0, 2000));
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
console.error('Error:', e.message);
|
|
16
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -94,6 +94,16 @@ async function main() {
|
|
|
94
94
|
const repl = new ReplManager_1.ReplManager(options);
|
|
95
95
|
await repl.start();
|
|
96
96
|
}
|
|
97
|
+
// Global error handlers to prevent silent crashes
|
|
98
|
+
process.on('uncaughtException', (error) => {
|
|
99
|
+
console.error('Uncaught Exception:', error.message);
|
|
100
|
+
console.error(error.stack);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
});
|
|
103
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
104
|
+
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
});
|
|
97
107
|
// Start the application
|
|
98
108
|
main().catch((error) => {
|
|
99
109
|
console.error('Fatal error:', error);
|
|
@@ -40,6 +40,7 @@ class JsonRpcClient {
|
|
|
40
40
|
constructor(command, args) {
|
|
41
41
|
this.sequence = 0;
|
|
42
42
|
this.pendingRequests = new Map();
|
|
43
|
+
this.REQUEST_TIMEOUT = 30000; // 30 seconds timeout
|
|
43
44
|
this.process = (0, child_process_1.spawn)(command, args, {
|
|
44
45
|
stdio: ['pipe', 'pipe', 'inherit'], // stdin, stdout, stderr
|
|
45
46
|
});
|
|
@@ -61,6 +62,10 @@ class JsonRpcClient {
|
|
|
61
62
|
const handler = this.pendingRequests.get(message.id);
|
|
62
63
|
if (handler) {
|
|
63
64
|
this.pendingRequests.delete(message.id);
|
|
65
|
+
// Clear timeout if present
|
|
66
|
+
if (handler.timeout) {
|
|
67
|
+
clearTimeout(handler.timeout);
|
|
68
|
+
}
|
|
64
69
|
if (message.error) {
|
|
65
70
|
handler.reject(new Error(message.error.message));
|
|
66
71
|
}
|
|
@@ -88,6 +93,16 @@ class JsonRpcClient {
|
|
|
88
93
|
};
|
|
89
94
|
return new Promise((resolve, reject) => {
|
|
90
95
|
this.pendingRequests.set(id, { resolve, reject });
|
|
96
|
+
// Set timeout to prevent indefinite hangs
|
|
97
|
+
const timeout = setTimeout(() => {
|
|
98
|
+
this.pendingRequests.delete(id);
|
|
99
|
+
reject(new Error(`MCP request timeout after ${this.REQUEST_TIMEOUT}ms`));
|
|
100
|
+
}, this.REQUEST_TIMEOUT);
|
|
101
|
+
// Store timeout with the request for cleanup
|
|
102
|
+
const handler = this.pendingRequests.get(id);
|
|
103
|
+
if (handler) {
|
|
104
|
+
handler.timeout = timeout;
|
|
105
|
+
}
|
|
91
106
|
try {
|
|
92
107
|
if (!this.process.stdin)
|
|
93
108
|
throw new Error('Stdin not available');
|
|
@@ -96,6 +111,7 @@ class JsonRpcClient {
|
|
|
96
111
|
}
|
|
97
112
|
catch (e) {
|
|
98
113
|
this.pendingRequests.delete(id);
|
|
114
|
+
clearTimeout(timeout);
|
|
99
115
|
reject(e);
|
|
100
116
|
}
|
|
101
117
|
});
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.McpConfigManager = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const os_1 = require("os");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
class McpConfigManager {
|
|
8
|
+
constructor() {
|
|
9
|
+
// Config path: ~/.mentis/mcp.json
|
|
10
|
+
this.configPath = (0, path_1.join)((0, os_1.homedir)(), '.mentis', 'mcp.json');
|
|
11
|
+
this.config = this.loadConfig();
|
|
12
|
+
}
|
|
13
|
+
loadConfig() {
|
|
14
|
+
if ((0, fs_1.existsSync)(this.configPath)) {
|
|
15
|
+
try {
|
|
16
|
+
const content = (0, fs_1.readFileSync)(this.configPath, 'utf-8');
|
|
17
|
+
return JSON.parse(content);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.warn('Failed to load MCP config, using defaults:', error);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// Default configuration with popular MCP servers
|
|
24
|
+
return this.getDefaultConfig();
|
|
25
|
+
}
|
|
26
|
+
getDefaultConfig() {
|
|
27
|
+
return {
|
|
28
|
+
servers: [
|
|
29
|
+
{
|
|
30
|
+
name: 'Exa Search',
|
|
31
|
+
command: 'npx',
|
|
32
|
+
args: ['-y', '@exa-labs/mcp-server-exa'],
|
|
33
|
+
description: 'Web search via Exa API (requires EXA_API_KEY)',
|
|
34
|
+
autoConnect: false,
|
|
35
|
+
env: {
|
|
36
|
+
EXA_API_KEY: process.env.EXA_API_KEY || ''
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'Memory',
|
|
41
|
+
command: 'npx',
|
|
42
|
+
args: ['-y', '@modelcontextprotocol/server-memory'],
|
|
43
|
+
description: 'Persistent memory storage for conversations',
|
|
44
|
+
autoConnect: false
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'Filesystem',
|
|
48
|
+
command: 'npx',
|
|
49
|
+
args: ['-y', '@modelcontextprotocol/server-filesystem', process.cwd()],
|
|
50
|
+
description: 'Enhanced filesystem operations',
|
|
51
|
+
autoConnect: false
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'GitHub',
|
|
55
|
+
command: 'npx',
|
|
56
|
+
args: ['-y', '@modelcontextprotocol/server-github'],
|
|
57
|
+
description: 'GitHub repository management and operations',
|
|
58
|
+
autoConnect: false,
|
|
59
|
+
env: {
|
|
60
|
+
GITHUB_PERSONAL_ACCESS_TOKEN: process.env.GITHUB_PERSONAL_ACCESS_TOKEN || ''
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'Puppeteer',
|
|
65
|
+
command: 'npx',
|
|
66
|
+
args: ['-y', '@modelcontextprotocol/server-puppeteer'],
|
|
67
|
+
description: 'Web browser automation and scraping',
|
|
68
|
+
autoConnect: false
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'Brave Search',
|
|
72
|
+
command: 'npx',
|
|
73
|
+
args: ['-y', '@modelcontextprotocol/server-brave-search'],
|
|
74
|
+
description: 'Web search via Brave Search API',
|
|
75
|
+
autoConnect: false,
|
|
76
|
+
env: {
|
|
77
|
+
BRAVE_API_KEY: process.env.BRAVE_API_KEY || ''
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'Slack',
|
|
82
|
+
command: 'npx',
|
|
83
|
+
args: ['-y', '@modelcontextprotocol/server-slack'],
|
|
84
|
+
description: 'Slack workspace integration',
|
|
85
|
+
autoConnect: false,
|
|
86
|
+
env: {
|
|
87
|
+
SLACK_BOT_TOKEN: process.env.SLACK_BOT_TOKEN || ''
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
getConfig() {
|
|
94
|
+
return this.config;
|
|
95
|
+
}
|
|
96
|
+
saveConfig() {
|
|
97
|
+
try {
|
|
98
|
+
const dir = (0, path_1.join)((0, os_1.homedir)(), '.mentis');
|
|
99
|
+
if (!(0, fs_1.existsSync)(dir)) {
|
|
100
|
+
require('fs').mkdirSync(dir, { recursive: true });
|
|
101
|
+
}
|
|
102
|
+
(0, fs_1.writeFileSync)(this.configPath, JSON.stringify(this.config, null, 2));
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
console.error('Failed to save MCP config:', error);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
addServer(server) {
|
|
109
|
+
// Remove existing server with same name
|
|
110
|
+
this.config.servers = this.config.servers.filter(s => s.name !== server.name);
|
|
111
|
+
this.config.servers.push(server);
|
|
112
|
+
this.saveConfig();
|
|
113
|
+
}
|
|
114
|
+
removeServer(name) {
|
|
115
|
+
this.config.servers = this.config.servers.filter(s => s.name !== name);
|
|
116
|
+
this.saveConfig();
|
|
117
|
+
}
|
|
118
|
+
getServer(name) {
|
|
119
|
+
return this.config.servers.find(s => s.name === name);
|
|
120
|
+
}
|
|
121
|
+
getAutoConnectServers() {
|
|
122
|
+
return this.config.servers.filter(s => s.autoConnect === true);
|
|
123
|
+
}
|
|
124
|
+
updateServer(name, updates) {
|
|
125
|
+
const server = this.config.servers.find(s => s.name === name);
|
|
126
|
+
if (server) {
|
|
127
|
+
Object.assign(server, updates);
|
|
128
|
+
this.saveConfig();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.McpConfigManager = McpConfigManager;
|