matex-cli 1.2.84 → 1.2.87
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/dist/index.js +561 -288
- package/package.json +8 -7
- package/dist/api/client.js +0 -173
- package/dist/commands/ask.js +0 -63
- package/dist/commands/augov.js +0 -273
- package/dist/commands/bro.js +0 -304
- package/dist/commands/chaos.js +0 -58
- package/dist/commands/chat.js +0 -59
- package/dist/commands/code.js +0 -94
- package/dist/commands/config.js +0 -74
- package/dist/commands/dev.js +0 -66
- package/dist/commands/help.js +0 -50
- package/dist/commands/login.js +0 -47
- package/dist/commands/models.js +0 -77
- package/dist/commands/student.js +0 -28
- package/dist/commands/study.js +0 -72
- package/dist/prompts/banter-augov.js +0 -21
- package/dist/prompts/banter.js +0 -101
- package/dist/prompts/chaos-prompts.js +0 -57
- package/dist/prompts/system-prompts.js +0 -148
- package/dist/session/agent-session.js +0 -450
- package/dist/utils/agent-orchestrator.js +0 -251
- package/dist/utils/augov-logger.js +0 -35
- package/dist/utils/augov-scrubber.js +0 -68
- package/dist/utils/command-executor.js +0 -507
- package/dist/utils/config.js +0 -139
- package/dist/utils/mcp-server.js +0 -396
- package/dist/utils/patcher.js +0 -202
- package/dist/utils/repo-mapper.js +0 -214
- package/dist/utils/spinner.js +0 -67
- package/dist/utils/tui.js +0 -779
package/dist/utils/mcp-server.js
DELETED
|
@@ -1,396 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* MCP (Model Context Protocol) Server Manager
|
|
4
|
-
* =============================================
|
|
5
|
-
* Production-level MCP servers that give CLI agents the ability to:
|
|
6
|
-
* - Read/write/search files on the local filesystem
|
|
7
|
-
* - Execute shell commands
|
|
8
|
-
* - Fetch web content (URL context)
|
|
9
|
-
* - Search Google (via SearxNG or Brave)
|
|
10
|
-
* - Access project context (repo map, git status)
|
|
11
|
-
*
|
|
12
|
-
* These tools are injected into agent system prompts so the AI
|
|
13
|
-
* knows what capabilities it has and can request them.
|
|
14
|
-
*/
|
|
15
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
16
|
-
if (k2 === undefined) k2 = k;
|
|
17
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
18
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
19
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
20
|
-
}
|
|
21
|
-
Object.defineProperty(o, k2, desc);
|
|
22
|
-
}) : (function(o, m, k, k2) {
|
|
23
|
-
if (k2 === undefined) k2 = k;
|
|
24
|
-
o[k2] = m[k];
|
|
25
|
-
}));
|
|
26
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
27
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
28
|
-
}) : function(o, v) {
|
|
29
|
-
o["default"] = v;
|
|
30
|
-
});
|
|
31
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
32
|
-
var ownKeys = function(o) {
|
|
33
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
34
|
-
var ar = [];
|
|
35
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
36
|
-
return ar;
|
|
37
|
-
};
|
|
38
|
-
return ownKeys(o);
|
|
39
|
-
};
|
|
40
|
-
return function (mod) {
|
|
41
|
-
if (mod && mod.__esModule) return mod;
|
|
42
|
-
var result = {};
|
|
43
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
44
|
-
__setModuleDefault(result, mod);
|
|
45
|
-
return result;
|
|
46
|
-
};
|
|
47
|
-
})();
|
|
48
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
49
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
50
|
-
};
|
|
51
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
-
exports.MCPServer = exports.MCP_TOOLS = void 0;
|
|
53
|
-
const fs = __importStar(require("fs"));
|
|
54
|
-
const path = __importStar(require("path"));
|
|
55
|
-
const child_process_1 = require("child_process");
|
|
56
|
-
const https_1 = __importDefault(require("https"));
|
|
57
|
-
const http_1 = __importDefault(require("http"));
|
|
58
|
-
/**
|
|
59
|
-
* All available MCP tools for CLI agents
|
|
60
|
-
*/
|
|
61
|
-
exports.MCP_TOOLS = [
|
|
62
|
-
{
|
|
63
|
-
name: 'read_file',
|
|
64
|
-
description: 'Read the full contents of a file at the given path.',
|
|
65
|
-
parameters: {
|
|
66
|
-
type: 'object',
|
|
67
|
-
properties: {
|
|
68
|
-
path: { type: 'string', description: 'Absolute or relative file path' },
|
|
69
|
-
start_line: { type: 'number', description: 'Optional start line (1-indexed)' },
|
|
70
|
-
end_line: { type: 'number', description: 'Optional end line (1-indexed)' },
|
|
71
|
-
},
|
|
72
|
-
required: ['path'],
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
name: 'write_file',
|
|
77
|
-
description: 'Create or overwrite a file with the given content.',
|
|
78
|
-
parameters: {
|
|
79
|
-
type: 'object',
|
|
80
|
-
properties: {
|
|
81
|
-
path: { type: 'string', description: 'File path to write' },
|
|
82
|
-
content: { type: 'string', description: 'File content to write' },
|
|
83
|
-
},
|
|
84
|
-
required: ['path', 'content'],
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
name: 'list_directory',
|
|
89
|
-
description: 'List files and subdirectories at a given path.',
|
|
90
|
-
parameters: {
|
|
91
|
-
type: 'object',
|
|
92
|
-
properties: {
|
|
93
|
-
path: { type: 'string', description: 'Directory path to list' },
|
|
94
|
-
recursive: { type: 'boolean', description: 'If true, list recursively (max depth 3)' },
|
|
95
|
-
},
|
|
96
|
-
required: ['path'],
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
name: 'search_files',
|
|
101
|
-
description: 'Search for a text pattern across files using grep.',
|
|
102
|
-
parameters: {
|
|
103
|
-
type: 'object',
|
|
104
|
-
properties: {
|
|
105
|
-
pattern: { type: 'string', description: 'Search pattern (regex supported)' },
|
|
106
|
-
path: { type: 'string', description: 'Directory or file to search in' },
|
|
107
|
-
include: { type: 'string', description: 'Glob pattern to filter files (e.g., "*.ts")' },
|
|
108
|
-
},
|
|
109
|
-
required: ['pattern', 'path'],
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
name: 'run_command',
|
|
114
|
-
description: 'Execute a shell command and return its output.',
|
|
115
|
-
parameters: {
|
|
116
|
-
type: 'object',
|
|
117
|
-
properties: {
|
|
118
|
-
command: { type: 'string', description: 'Shell command to execute' },
|
|
119
|
-
cwd: { type: 'string', description: 'Working directory for the command' },
|
|
120
|
-
},
|
|
121
|
-
required: ['command'],
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
name: 'fetch_url',
|
|
126
|
-
description: 'Fetch content from a URL and return it as text.',
|
|
127
|
-
parameters: {
|
|
128
|
-
type: 'object',
|
|
129
|
-
properties: {
|
|
130
|
-
url: { type: 'string', description: 'URL to fetch' },
|
|
131
|
-
},
|
|
132
|
-
required: ['url'],
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
name: 'git_status',
|
|
137
|
-
description: 'Get the current git status of the repository.',
|
|
138
|
-
parameters: {
|
|
139
|
-
type: 'object',
|
|
140
|
-
properties: {
|
|
141
|
-
path: { type: 'string', description: 'Repository path' },
|
|
142
|
-
},
|
|
143
|
-
required: ['path'],
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
name: 'web_search',
|
|
148
|
-
description: 'Search the web using SearxNG or Brave Search API.',
|
|
149
|
-
parameters: {
|
|
150
|
-
type: 'object',
|
|
151
|
-
properties: {
|
|
152
|
-
query: { type: 'string', description: 'Search query' },
|
|
153
|
-
num_results: { type: 'number', description: 'Number of results (default 5)' },
|
|
154
|
-
},
|
|
155
|
-
required: ['query'],
|
|
156
|
-
},
|
|
157
|
-
},
|
|
158
|
-
];
|
|
159
|
-
// ============================================================
|
|
160
|
-
// TOOL EXECUTORS
|
|
161
|
-
// ============================================================
|
|
162
|
-
class MCPServer {
|
|
163
|
-
constructor(cwd, options) {
|
|
164
|
-
this.cwd = cwd;
|
|
165
|
-
this.braveApiKey = options?.braveApiKey;
|
|
166
|
-
this.searxngUrl = options?.searxngUrl;
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Execute an MCP tool by name
|
|
170
|
-
*/
|
|
171
|
-
async execute(toolName, args) {
|
|
172
|
-
try {
|
|
173
|
-
switch (toolName) {
|
|
174
|
-
case 'read_file': return this.readFile(args.path, args.start_line, args.end_line);
|
|
175
|
-
case 'write_file': return this.writeFile(args.path, args.content);
|
|
176
|
-
case 'list_directory': return this.listDirectory(args.path, args.recursive);
|
|
177
|
-
case 'search_files': return this.searchFiles(args.pattern, args.path, args.include);
|
|
178
|
-
case 'run_command': return this.runCommand(args.command, args.cwd);
|
|
179
|
-
case 'fetch_url': return await this.fetchUrl(args.url);
|
|
180
|
-
case 'git_status': return this.gitStatus(args.path);
|
|
181
|
-
case 'web_search': return await this.webSearch(args.query, args.num_results);
|
|
182
|
-
default: return { success: false, error: `Unknown tool: ${toolName}` };
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
catch (err) {
|
|
186
|
-
return { success: false, error: err.message };
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Read a file
|
|
191
|
-
*/
|
|
192
|
-
readFile(filePath, startLine, endLine) {
|
|
193
|
-
const resolved = path.isAbsolute(filePath) ? filePath : path.resolve(this.cwd, filePath);
|
|
194
|
-
if (!fs.existsSync(resolved)) {
|
|
195
|
-
return { success: false, error: `File not found: ${resolved}` };
|
|
196
|
-
}
|
|
197
|
-
const content = fs.readFileSync(resolved, 'utf-8');
|
|
198
|
-
if (startLine || endLine) {
|
|
199
|
-
const lines = content.split('\n');
|
|
200
|
-
const start = Math.max(0, (startLine || 1) - 1);
|
|
201
|
-
const end = Math.min(lines.length, endLine || lines.length);
|
|
202
|
-
return { success: true, output: lines.slice(start, end).join('\n') };
|
|
203
|
-
}
|
|
204
|
-
// Cap output at 500 lines
|
|
205
|
-
const lines = content.split('\n');
|
|
206
|
-
if (lines.length > 500) {
|
|
207
|
-
return { success: true, output: lines.slice(0, 500).join('\n') + `\n\n... (${lines.length - 500} more lines truncated)` };
|
|
208
|
-
}
|
|
209
|
-
return { success: true, output: content };
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Write a file (creates directories if needed)
|
|
213
|
-
*/
|
|
214
|
-
writeFile(filePath, content) {
|
|
215
|
-
const resolved = path.isAbsolute(filePath) ? filePath : path.resolve(this.cwd, filePath);
|
|
216
|
-
const dir = path.dirname(resolved);
|
|
217
|
-
if (!fs.existsSync(dir)) {
|
|
218
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
219
|
-
}
|
|
220
|
-
fs.writeFileSync(resolved, content, 'utf-8');
|
|
221
|
-
return { success: true, output: `File written: ${resolved}` };
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* List directory contents
|
|
225
|
-
*/
|
|
226
|
-
listDirectory(dirPath, recursive) {
|
|
227
|
-
const resolved = path.isAbsolute(dirPath) ? dirPath : path.resolve(this.cwd, dirPath);
|
|
228
|
-
if (!fs.existsSync(resolved)) {
|
|
229
|
-
return { success: false, error: `Directory not found: ${resolved}` };
|
|
230
|
-
}
|
|
231
|
-
try {
|
|
232
|
-
const maxDepth = recursive ? 3 : 1;
|
|
233
|
-
const result = (0, child_process_1.execSync)(`find "${resolved}" -maxdepth ${maxDepth} -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' | head -200`, { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
234
|
-
return { success: true, output: result };
|
|
235
|
-
}
|
|
236
|
-
catch {
|
|
237
|
-
return { success: false, error: `Failed to list directory: ${resolved}` };
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Search files with grep
|
|
242
|
-
*/
|
|
243
|
-
searchFiles(pattern, searchPath, include) {
|
|
244
|
-
const resolved = path.isAbsolute(searchPath) ? searchPath : path.resolve(this.cwd, searchPath);
|
|
245
|
-
try {
|
|
246
|
-
const includeFlag = include ? `--include='${include}'` : '';
|
|
247
|
-
const result = (0, child_process_1.execSync)(`grep -rn ${includeFlag} --color=never "${pattern}" "${resolved}" 2>/dev/null | head -50`, { encoding: 'utf-8', timeout: 10000 }).trim();
|
|
248
|
-
return { success: true, output: result || 'No matches found.' };
|
|
249
|
-
}
|
|
250
|
-
catch {
|
|
251
|
-
return { success: true, output: 'No matches found.' };
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Run a shell command
|
|
256
|
-
*/
|
|
257
|
-
runCommand(command, cwd) {
|
|
258
|
-
const workDir = cwd ? (path.isAbsolute(cwd) ? cwd : path.resolve(this.cwd, cwd)) : this.cwd;
|
|
259
|
-
try {
|
|
260
|
-
const result = (0, child_process_1.execSync)(command, {
|
|
261
|
-
encoding: 'utf-8',
|
|
262
|
-
cwd: workDir,
|
|
263
|
-
timeout: 30000,
|
|
264
|
-
env: { ...process.env, FORCE_COLOR: '0' },
|
|
265
|
-
}).trim();
|
|
266
|
-
return { success: true, output: result || '(No output)' };
|
|
267
|
-
}
|
|
268
|
-
catch (err) {
|
|
269
|
-
return { success: false, error: err.stderr || err.message };
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Fetch URL content
|
|
274
|
-
*/
|
|
275
|
-
async fetchUrl(url) {
|
|
276
|
-
return new Promise((resolve) => {
|
|
277
|
-
const client = url.startsWith('https') ? https_1.default : http_1.default;
|
|
278
|
-
const req = client.get(url, { timeout: 10000 }, (res) => {
|
|
279
|
-
let data = '';
|
|
280
|
-
res.on('data', (chunk) => { data += chunk.toString(); });
|
|
281
|
-
res.on('end', () => {
|
|
282
|
-
// Strip HTML tags for readability, cap at 5000 chars
|
|
283
|
-
const text = data.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
|
|
284
|
-
resolve({
|
|
285
|
-
success: true,
|
|
286
|
-
output: text.length > 5000 ? text.substring(0, 5000) + '...' : text,
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
req.on('error', (err) => resolve({ success: false, error: err.message }));
|
|
291
|
-
req.on('timeout', () => { req.destroy(); resolve({ success: false, error: 'Request timed out' }); });
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
/**
|
|
295
|
-
* Git status
|
|
296
|
-
*/
|
|
297
|
-
gitStatus(repoPath) {
|
|
298
|
-
const resolved = path.isAbsolute(repoPath) ? repoPath : path.resolve(this.cwd, repoPath);
|
|
299
|
-
try {
|
|
300
|
-
const status = (0, child_process_1.execSync)('git status --short', { encoding: 'utf-8', cwd: resolved }).trim();
|
|
301
|
-
const branch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf-8', cwd: resolved }).trim();
|
|
302
|
-
const lastCommit = (0, child_process_1.execSync)('git log -1 --oneline', { encoding: 'utf-8', cwd: resolved }).trim();
|
|
303
|
-
return {
|
|
304
|
-
success: true,
|
|
305
|
-
output: `Branch: ${branch}\nLast commit: ${lastCommit}\n\nChanged files:\n${status || '(clean)'}`,
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
catch (err) {
|
|
309
|
-
return { success: false, error: 'Not a git repository or git not available.' };
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* Web search via SearxNG or Brave
|
|
314
|
-
*/
|
|
315
|
-
async webSearch(query, numResults = 5) {
|
|
316
|
-
// Try SearxNG first
|
|
317
|
-
if (this.searxngUrl) {
|
|
318
|
-
try {
|
|
319
|
-
const url = `${this.searxngUrl}/search?q=${encodeURIComponent(query)}&format=json&engines=google,bing&results=${numResults}`;
|
|
320
|
-
const result = await this.fetchUrl(url);
|
|
321
|
-
if (result.success && result.output) {
|
|
322
|
-
try {
|
|
323
|
-
const data = JSON.parse(result.output);
|
|
324
|
-
const results = (data.results || []).slice(0, numResults).map((r, i) => `${i + 1}. ${r.title}\n ${r.url}\n ${(r.content || '').substring(0, 200)}`).join('\n\n');
|
|
325
|
-
return { success: true, output: results || 'No results found.' };
|
|
326
|
-
}
|
|
327
|
-
catch { /* fall through */ }
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
catch { /* fall through to Brave */ }
|
|
331
|
-
}
|
|
332
|
-
// Fallback: Brave Search
|
|
333
|
-
if (this.braveApiKey) {
|
|
334
|
-
return new Promise((resolve) => {
|
|
335
|
-
const url = `https://api.search.brave.com/res/v1/web/search?q=${encodeURIComponent(query)}&count=${numResults}`;
|
|
336
|
-
const req = https_1.default.get(url, {
|
|
337
|
-
headers: {
|
|
338
|
-
'Accept': 'application/json',
|
|
339
|
-
'X-Subscription-Token': this.braveApiKey,
|
|
340
|
-
},
|
|
341
|
-
timeout: 10000,
|
|
342
|
-
}, (res) => {
|
|
343
|
-
let data = '';
|
|
344
|
-
res.on('data', (chunk) => { data += chunk.toString(); });
|
|
345
|
-
res.on('end', () => {
|
|
346
|
-
try {
|
|
347
|
-
const parsed = JSON.parse(data);
|
|
348
|
-
const results = (parsed.web?.results || []).slice(0, numResults).map((r, i) => `${i + 1}. ${r.title}\n ${r.url}\n ${(r.description || '').substring(0, 200)}`).join('\n\n');
|
|
349
|
-
resolve({ success: true, output: results || 'No results found.' });
|
|
350
|
-
}
|
|
351
|
-
catch {
|
|
352
|
-
resolve({ success: false, error: 'Failed to parse search results.' });
|
|
353
|
-
}
|
|
354
|
-
});
|
|
355
|
-
});
|
|
356
|
-
req.on('error', (err) => resolve({ success: false, error: err.message }));
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
return { success: false, error: 'No search backend configured. Set BRAVE_SEARCH_API_KEY or SEARXNG_URL.' };
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Generate the MCP tool capabilities section for system prompts
|
|
363
|
-
*/
|
|
364
|
-
static getToolsPromptSection() {
|
|
365
|
-
return `### 🔌 MCP TOOLS (Model Context Protocol):
|
|
366
|
-
You have access to the following production-level tools via MCP. Use them to navigate, read, write, and search:
|
|
367
|
-
|
|
368
|
-
| Tool | Description |
|
|
369
|
-
|------|-------------|
|
|
370
|
-
| \`read_file(path, start_line?, end_line?)\` | Read file contents (supports line ranges) |
|
|
371
|
-
| \`write_file(path, content)\` | Create or overwrite a file |
|
|
372
|
-
| \`list_directory(path, recursive?)\` | List files and subdirectories |
|
|
373
|
-
| \`search_files(pattern, path, include?)\` | Search for text patterns (grep) |
|
|
374
|
-
| \`run_command(command, cwd?)\` | Execute a shell command |
|
|
375
|
-
| \`fetch_url(url)\` | Fetch web content from a URL |
|
|
376
|
-
| \`git_status(path)\` | Get git status, branch, and last commit |
|
|
377
|
-
| \`web_search(query, num_results?)\` | Search the web via SearxNG/Brave |
|
|
378
|
-
|
|
379
|
-
**HOW TO USE:** When you need to use a tool, output it as a shell command:
|
|
380
|
-
- To read: \`head -50 path/to/file\` or \`cat path/to/file\`
|
|
381
|
-
- To search: \`grep -rn "pattern" path/\`
|
|
382
|
-
- To list: \`ls -la path/\` or \`find path/ -maxdepth 2\`
|
|
383
|
-
- To execute: wrap in \`\`\`bash code blocks
|
|
384
|
-
- To fetch URL: \`curl -s "url" | head -100\`
|
|
385
|
-
|
|
386
|
-
**🛑 CRITICAL RULE: "ON-THE-SPOT" EXECUTION 🛑**
|
|
387
|
-
Whenever you output a command block (e.g., \`\`\`bash) or a file block, you **MUST IMMEDIATELY STOP GENERATING ANY FURTHER TEXT**.
|
|
388
|
-
Do not simulate the terminal output.
|
|
389
|
-
Do not hallucinate a response from the user.
|
|
390
|
-
Submit the message. The system will intercept the code block, execute it, and feed the real output directly back into your context window automatically on the next turn.
|
|
391
|
-
|
|
392
|
-
These tools allow you to **navigate any file/directory** on the system using your own brain to decide where to go.`;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
exports.MCPServer = MCPServer;
|
|
396
|
-
//# sourceMappingURL=mcp-server.js.map
|
package/dist/utils/patcher.js
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
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.Patcher = void 0;
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
-
const tui_1 = require("./tui");
|
|
11
|
-
class Patcher {
|
|
12
|
-
/**
|
|
13
|
-
* Parse surgical edit blocks from AI response
|
|
14
|
-
* Format:
|
|
15
|
-
* **filename**
|
|
16
|
-
* <<<< SEARCH
|
|
17
|
-
* content
|
|
18
|
-
* ====
|
|
19
|
-
* replacement
|
|
20
|
-
* >>>> REPLACE
|
|
21
|
-
*/
|
|
22
|
-
static parseEditBlocks(response) {
|
|
23
|
-
// Emergency closure for unclosed REPLACE blocks
|
|
24
|
-
if (response.includes('<<<< SEARCH') && !response.includes('>>>> REPLACE')) {
|
|
25
|
-
response += '\n>>>> REPLACE';
|
|
26
|
-
}
|
|
27
|
-
const blocks = [];
|
|
28
|
-
// Robust regex: Matches filename with or without stars, handle potential leading/trailing spaces
|
|
29
|
-
const blockRegex = /(?:\*\*?\s*)?([^*<\n]+?)(?:\s*\*?\*)?\s*<<<< SEARCH\n([\s\S]*?)\n====\n([\s\S]*?)\n>>>> REPLACE/gi;
|
|
30
|
-
let match;
|
|
31
|
-
while ((match = blockRegex.exec(response)) !== null) {
|
|
32
|
-
blocks.push({
|
|
33
|
-
filePath: match[1].trim(),
|
|
34
|
-
search: match[2],
|
|
35
|
-
replace: match[3]
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
return blocks;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Parse file creation blocks from AI response
|
|
42
|
-
* Format:
|
|
43
|
-
* <file path="path/to/file.ext">
|
|
44
|
-
* content
|
|
45
|
-
* </file>
|
|
46
|
-
*/
|
|
47
|
-
static parseFileBlocks(response) {
|
|
48
|
-
// Emergency closure for unclosed file blocks
|
|
49
|
-
if (response.toLowerCase().includes('<file path=') && !response.toLowerCase().includes('</file>')) {
|
|
50
|
-
response += '\n</file>';
|
|
51
|
-
}
|
|
52
|
-
const blocks = [];
|
|
53
|
-
const fileRegex = /<file path="([^"]+)">([\s\S]*?)<\/file>/gi;
|
|
54
|
-
let match;
|
|
55
|
-
while ((match = fileRegex.exec(response)) !== null) {
|
|
56
|
-
blocks.push({
|
|
57
|
-
filePath: match[1].trim(),
|
|
58
|
-
search: '', // Not used for new files
|
|
59
|
-
replace: match[2]
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
return blocks;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Create a new file (and its directories)
|
|
66
|
-
*/
|
|
67
|
-
static createFile(block) {
|
|
68
|
-
tui_1.TUI.drawStatusBar(`Creating File: ${block.filePath}...`);
|
|
69
|
-
try {
|
|
70
|
-
const fullPath = path_1.default.resolve(process.cwd(), block.filePath);
|
|
71
|
-
const dir = path_1.default.dirname(fullPath);
|
|
72
|
-
if (!fs_1.default.existsSync(dir)) {
|
|
73
|
-
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
74
|
-
}
|
|
75
|
-
fs_1.default.writeFileSync(fullPath, block.replace, 'utf8');
|
|
76
|
-
tui_1.TUI.drawStatusBar(`✅ Success: ${block.filePath} created.`);
|
|
77
|
-
return { success: true };
|
|
78
|
-
}
|
|
79
|
-
catch (err) {
|
|
80
|
-
tui_1.TUI.drawStatusBar(`❌ Error: ${err.message}`);
|
|
81
|
-
return { success: false, error: err.message };
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Apply a surgical patch to a file
|
|
86
|
-
*/
|
|
87
|
-
static applyPatch(block) {
|
|
88
|
-
tui_1.TUI.drawStatusBar(`Applying Patch: ${block.filePath}...`);
|
|
89
|
-
try {
|
|
90
|
-
const fullPath = path_1.default.resolve(process.cwd(), block.filePath);
|
|
91
|
-
if (!fs_1.default.existsSync(fullPath)) {
|
|
92
|
-
tui_1.TUI.drawStatusBar(`Error: File not found: ${block.filePath}`);
|
|
93
|
-
return { success: false, error: `File not found: ${block.filePath}` };
|
|
94
|
-
}
|
|
95
|
-
const startTime = Date.now();
|
|
96
|
-
const content = fs_1.default.readFileSync(fullPath, 'utf8');
|
|
97
|
-
const stats = fs_1.default.statSync(fullPath);
|
|
98
|
-
const fileSizeMB = stats.size / (1024 * 1024);
|
|
99
|
-
if (fileSizeMB > 1) {
|
|
100
|
-
tui_1.TUI.log(chalk_1.default.gray(` [⏱️] Processing large file (${fileSizeMB.toFixed(2)} MB)...`));
|
|
101
|
-
}
|
|
102
|
-
// 1. Precise Normalization
|
|
103
|
-
const normalize = (text) => text.replace(/\r\n/g, '\n').split('\n').map(l => l.trimEnd()).join('\n');
|
|
104
|
-
const normalizedContent = normalize(content);
|
|
105
|
-
const normalizedSearch = normalize(block.search);
|
|
106
|
-
const normalizedReplace = normalize(block.replace);
|
|
107
|
-
// 2. Exact Match Check (Post-Normalization)
|
|
108
|
-
if (normalizedContent.includes(normalizedSearch)) {
|
|
109
|
-
const updatedContent = normalizedContent.replace(normalizedSearch, normalizedReplace);
|
|
110
|
-
fs_1.default.writeFileSync(fullPath, updatedContent, 'utf8');
|
|
111
|
-
tui_1.TUI.drawStatusBar(`✅ Success: ${block.filePath} patched.`);
|
|
112
|
-
return { success: true };
|
|
113
|
-
}
|
|
114
|
-
// 3. Ultra-Fuzzy Matching (Line-by-line trim and compare)
|
|
115
|
-
const contentLines = normalizedContent.split('\n');
|
|
116
|
-
const searchLines = normalizedSearch.split('\n');
|
|
117
|
-
let matchIndex = -1;
|
|
118
|
-
for (let i = 0; i <= contentLines.length - searchLines.length; i++) {
|
|
119
|
-
let match = true;
|
|
120
|
-
for (let j = 0; j < searchLines.length; j++) {
|
|
121
|
-
if (contentLines[i + j].trim() !== searchLines[j].trim()) {
|
|
122
|
-
match = false;
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (match) {
|
|
127
|
-
matchIndex = i;
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (matchIndex !== -1) {
|
|
132
|
-
// Apply replacement while preserving surrounding lines
|
|
133
|
-
const updatedLines = [
|
|
134
|
-
...contentLines.slice(0, matchIndex),
|
|
135
|
-
normalizedReplace,
|
|
136
|
-
...contentLines.slice(matchIndex + searchLines.length)
|
|
137
|
-
];
|
|
138
|
-
fs_1.default.writeFileSync(fullPath, updatedLines.join('\n'), 'utf8');
|
|
139
|
-
const elapsed = Date.now() - startTime;
|
|
140
|
-
if (fileSizeMB > 1) {
|
|
141
|
-
tui_1.TUI.drawStatusBar(`✅ Success (Fuzzy): ${block.filePath} patched in ${elapsed}ms.`);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
tui_1.TUI.drawStatusBar(`✅ Success (Fuzzy): ${block.filePath} patched.`);
|
|
145
|
-
}
|
|
146
|
-
return { success: true };
|
|
147
|
-
}
|
|
148
|
-
tui_1.TUI.drawStatusBar(`❌ Patch Failed: Search block not found in ${block.filePath}`);
|
|
149
|
-
return {
|
|
150
|
-
success: false,
|
|
151
|
-
error: `Search block not found in ${block.filePath}. Please ensure the code snippet matches exactly (ignoring whitespace).`
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
catch (err) {
|
|
155
|
-
tui_1.TUI.drawStatusBar(`❌ Error: ${err.message}`);
|
|
156
|
-
return { success: false, error: err.message };
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Visualize the diff in a premium "Bro" style with Window-like container
|
|
161
|
-
*/
|
|
162
|
-
static showDiff(block, full = false) {
|
|
163
|
-
const width = Math.min(process.stdout.columns || 80, 100);
|
|
164
|
-
const searchLines = (block.search || '').split('\n');
|
|
165
|
-
const replaceLines = block.replace.split('\n');
|
|
166
|
-
const isNewFile = !block.search;
|
|
167
|
-
const isLarge = replaceLines.length > 12;
|
|
168
|
-
const shouldTruncate = isLarge && !full;
|
|
169
|
-
const displaySearch = shouldTruncate ? searchLines.slice(0, 8) : searchLines;
|
|
170
|
-
const displayReplace = shouldTruncate ? replaceLines.slice(0, 8) : replaceLines;
|
|
171
|
-
const redGlow = chalk_1.default.hex('#ef4444');
|
|
172
|
-
const greenGlow = chalk_1.default.hex('#22c55e');
|
|
173
|
-
const border = chalk_1.default.hex('#334155');
|
|
174
|
-
console.log('\n' + border(` ┌${'─'.repeat(width - 4)}┐`));
|
|
175
|
-
const type = isNewFile ? '🆕 NEW FILE' : '🔧 PATCH';
|
|
176
|
-
const title = ` ${type}: ${block.filePath} `;
|
|
177
|
-
console.log(border(' │ ') + chalk_1.default.bgHex('#1e293b').cyan.bold(title).padEnd(width - 6) + border(' │'));
|
|
178
|
-
console.log(border(' ├' + '╌'.repeat(width - 4) + '┤'));
|
|
179
|
-
if (!isNewFile) {
|
|
180
|
-
displaySearch.forEach((line) => {
|
|
181
|
-
const displayLine = line.length > width - 12 ? line.substring(0, width - 15) + '...' : line;
|
|
182
|
-
console.log(redGlow(' │ ') + chalk_1.default.bgRed.white(' - ') + ' ' + redGlow(displayLine.padEnd(width - 10)) + redGlow(' │'));
|
|
183
|
-
});
|
|
184
|
-
if (shouldTruncate && searchLines.length > 8) {
|
|
185
|
-
console.log(redGlow(' │ ') + chalk_1.default.dim(` ... ${searchLines.length - 8} more lines removed ...`).padEnd(width - 6) + redGlow(' │'));
|
|
186
|
-
}
|
|
187
|
-
console.log(border(' ├' + '─'.repeat(width - 4) + '┤'));
|
|
188
|
-
}
|
|
189
|
-
displayReplace.forEach((line) => {
|
|
190
|
-
const displayLine = line.length > width - 12 ? line.substring(0, width - 15) + '...' : line;
|
|
191
|
-
console.log(greenGlow(' │ ') + chalk_1.default.bgGreen.black(' + ') + ' ' + greenGlow(displayLine.padEnd(width - 10)) + greenGlow(' │'));
|
|
192
|
-
});
|
|
193
|
-
if (replaceLines.length > 8) {
|
|
194
|
-
console.log(greenGlow(' │ ') + chalk_1.default.hex('#06b6d4').bold(` ^ [ ${replaceLines.length - 8} MORE LINES • USE ^ TO SEE ALL ] ^`).padEnd(width - 6) + greenGlow(' │'));
|
|
195
|
-
}
|
|
196
|
-
console.log(border(` └${'─'.repeat(width - 4)}┘`));
|
|
197
|
-
console.log();
|
|
198
|
-
return shouldTruncate;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
exports.Patcher = Patcher;
|
|
202
|
-
//# sourceMappingURL=patcher.js.map
|