matex-cli 1.2.48 → 1.2.50
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/commands/chat.js +1 -1
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +31 -60
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/student.d.ts +3 -0
- package/dist/commands/student.d.ts.map +1 -0
- package/dist/commands/student.js +26 -0
- package/dist/commands/student.js.map +1 -0
- package/dist/commands/study.d.ts.map +1 -1
- package/dist/commands/study.js +31 -61
- package/dist/commands/study.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/agent-orchestrator.d.ts +4 -0
- package/dist/utils/agent-orchestrator.d.ts.map +1 -1
- package/dist/utils/agent-orchestrator.js +12 -0
- package/dist/utils/agent-orchestrator.js.map +1 -1
- package/dist/utils/command-executor.d.ts.map +1 -1
- package/dist/utils/command-executor.js +17 -6
- package/dist/utils/command-executor.js.map +1 -1
- package/dist/utils/patcher.d.ts.map +1 -1
- package/dist/utils/patcher.js +10 -2
- package/dist/utils/patcher.js.map +1 -1
- package/dist/utils/tui.d.ts +12 -0
- package/dist/utils/tui.d.ts.map +1 -1
- package/dist/utils/tui.js +46 -11
- package/dist/utils/tui.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/chat.ts +1 -1
- package/src/commands/dev.ts +30 -64
- package/src/commands/student.ts +21 -0
- package/src/commands/study.ts +30 -65
- package/src/index.ts +2 -0
- package/src/utils/agent-orchestrator.ts +13 -0
- package/src/utils/command-executor.ts +18 -6
- package/src/utils/patcher.ts +12 -2
- package/src/utils/tui.ts +51 -11
package/src/commands/dev.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { TUI } from '../utils/tui';
|
|
|
11
11
|
|
|
12
12
|
export const devCommand = new Command('dev')
|
|
13
13
|
.description('Start interactive development session with MATEXCodex')
|
|
14
|
-
.option('-m, --model <model>', 'AI model to use (matexai, matexcodex,
|
|
14
|
+
.option('-m, --model <model>', 'AI model to use (matex-free, matexai, matexcodex, matexelite)', configManager.getDefaultModel())
|
|
15
15
|
.option('--no-execute', 'Disable auto-prompt for command execution')
|
|
16
16
|
.action(async (options: any) => {
|
|
17
17
|
try {
|
|
@@ -26,10 +26,15 @@ export const devCommand = new Command('dev')
|
|
|
26
26
|
// Create API client
|
|
27
27
|
const client = new MatexAPIClient(apiKey, configManager.getBaseURL());
|
|
28
28
|
|
|
29
|
+
const extraPrompt = options.model === 'matex-free' ? AgentOrchestrator.getFreeTierPrompt() : '';
|
|
30
|
+
|
|
29
31
|
// 0. Initialize TUI Dashboard
|
|
30
32
|
TUI.init();
|
|
31
33
|
TUI.drawLargeLogo();
|
|
32
|
-
|
|
34
|
+
if (options.model === 'matex-free') {
|
|
35
|
+
console.log(chalk.bold.hex('#00FF7F')('\n 🎓 MATEX STUDENT EDITION - Zero Bill Protocol\n'));
|
|
36
|
+
}
|
|
37
|
+
TUI.drawWelcomeBanner(options.model === 'matex-free' ? 'ZERO-COST AI FOR STUDENTS!' : 'Welcome to the MATEX AI research preview!');
|
|
33
38
|
|
|
34
39
|
console.log(chalk.gray(' Status: ') + chalk.hex('#D97757').bold('Monitoring Workspace...'));
|
|
35
40
|
console.log(chalk.gray(' Model: ') + chalk.hex('#D97757').bold(options.model));
|
|
@@ -50,7 +55,7 @@ export const devCommand = new Command('dev')
|
|
|
50
55
|
const messages: ChatMessage[] = [
|
|
51
56
|
{
|
|
52
57
|
role: 'system',
|
|
53
|
-
content: `### 🧬 SYSTEM IDENTITY: THE MATEX "BRO-SWARM"
|
|
58
|
+
content: extraPrompt + `### 🧬 SYSTEM IDENTITY: THE MATEX "BRO-SWARM"
|
|
54
59
|
You are the legendary **Bro-Swarm**, a high-vibe family of Nepali engineering brothers. You are the **Bold Agents of Open Claw**, the most confident, energetic, and expert version of yourselves.
|
|
55
60
|
|
|
56
61
|
### 🏠 WORKSPACE GROUNDING (CRITICAL):
|
|
@@ -246,9 +251,9 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
246
251
|
for (const line of lines) {
|
|
247
252
|
// 1. Technical Block Detection
|
|
248
253
|
const codeBlockMatch = line.match(/```(\w+)?/);
|
|
249
|
-
const fileStartMatch = line.match(/<file path="([^"]+)">/);
|
|
250
|
-
const patchStartMatch = line.match(/<<<< SEARCH/);
|
|
251
|
-
const summaryStartMatch = line.match(/<summary>/);
|
|
254
|
+
const fileStartMatch = line.match(/<file path="([^"]+)">/i);
|
|
255
|
+
const patchStartMatch = line.match(/<<<< SEARCH/i);
|
|
256
|
+
const summaryStartMatch = line.match(/<summary>/i);
|
|
252
257
|
|
|
253
258
|
if (!technicalType && (codeBlockMatch || fileStartMatch || patchStartMatch || summaryStartMatch)) {
|
|
254
259
|
// Flush pending agent dialogue
|
|
@@ -264,15 +269,15 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
264
269
|
|
|
265
270
|
if (codeBlockMatch) {
|
|
266
271
|
technicalType = 'code';
|
|
267
|
-
codeLang = codeBlockMatch[1] || 'bash';
|
|
268
|
-
|
|
272
|
+
codeLang = (codeBlockMatch[1] || 'bash').toUpperCase();
|
|
273
|
+
TUI.drawStreamingStart('TECHNICAL BLOCK', codeLang);
|
|
269
274
|
} else if (fileStartMatch) {
|
|
270
275
|
technicalType = 'file';
|
|
271
276
|
technicalPath = fileStartMatch[1];
|
|
272
|
-
|
|
277
|
+
TUI.drawStreamingStart('NEW FILE', technicalPath);
|
|
273
278
|
} else if (patchStartMatch) {
|
|
274
279
|
technicalType = 'patch';
|
|
275
|
-
|
|
280
|
+
TUI.drawStreamingStart('PATCH', 'SURGICAL EDIT');
|
|
276
281
|
} else if (summaryStartMatch) {
|
|
277
282
|
technicalType = 'summary';
|
|
278
283
|
process.stdout.write(chalk.magenta('\n [📝] Generating Ajay\'s Work Summary...\n'));
|
|
@@ -281,9 +286,9 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
281
286
|
}
|
|
282
287
|
|
|
283
288
|
// 2. Technical Block End Detection
|
|
284
|
-
const fileEndMatch = line.match(/<\/file>/);
|
|
285
|
-
const patchEndMatch = line.match(/>>>> REPLACE/);
|
|
286
|
-
const summaryEndMatch = line.match(/<\/summary>/);
|
|
289
|
+
const fileEndMatch = line.match(/<\/file>/i);
|
|
290
|
+
const patchEndMatch = line.match(/>>>> REPLACE/i);
|
|
291
|
+
const summaryEndMatch = line.match(/<\/summary>/i);
|
|
287
292
|
const isCodeEnd = technicalType === 'code' && line.trim() === '```';
|
|
288
293
|
|
|
289
294
|
if (isCodeEnd || fileEndMatch || patchEndMatch || summaryEndMatch) {
|
|
@@ -291,11 +296,7 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
291
296
|
if (technicalType === 'summary' || summaryEndMatch) {
|
|
292
297
|
TUI.drawSummaryBox(displayContent);
|
|
293
298
|
} else {
|
|
294
|
-
|
|
295
|
-
let title = technicalType === 'file' ? `📄 NEW: ${technicalPath || 'Untitled'}` :
|
|
296
|
-
technicalType === 'patch' ? `🔧 PATCH` : `⚡ ${codeLang.toUpperCase()}`;
|
|
297
|
-
|
|
298
|
-
TUI.drawGlowingContainer(title, technicalType === 'code' ? codeLang : 'text', displayContent);
|
|
299
|
+
TUI.drawStreamingEnd();
|
|
299
300
|
}
|
|
300
301
|
technicalBuffer = '';
|
|
301
302
|
technicalType = null;
|
|
@@ -307,6 +308,9 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
307
308
|
// 3. Content Handling
|
|
308
309
|
if (technicalType) {
|
|
309
310
|
technicalBuffer += line + '\n';
|
|
311
|
+
if (technicalType !== 'summary') {
|
|
312
|
+
TUI.drawStreamingLine(line);
|
|
313
|
+
}
|
|
310
314
|
continue;
|
|
311
315
|
}
|
|
312
316
|
|
|
@@ -356,8 +360,8 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
356
360
|
|
|
357
361
|
// Final flushes
|
|
358
362
|
if (currentAgent && agentBuffer.trim()) {
|
|
359
|
-
if ((currentAgent as string).toLowerCase()
|
|
360
|
-
|
|
363
|
+
if ((currentAgent as string).toLowerCase().includes('ajay vai')) {
|
|
364
|
+
TUI.drawSummaryBox(agentBuffer.trim());
|
|
361
365
|
} else {
|
|
362
366
|
TUI.drawSwarmDialogue(currentAgent as string, agentBuffer.trim());
|
|
363
367
|
}
|
|
@@ -368,56 +372,18 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
368
372
|
if (technicalType === 'summary') {
|
|
369
373
|
TUI.drawSummaryBox(technicalBuffer.trim());
|
|
370
374
|
} else {
|
|
371
|
-
TUI.
|
|
375
|
+
TUI.drawStreamingEnd();
|
|
372
376
|
}
|
|
373
|
-
|
|
377
|
+
} else if (fullResponse.toLowerCase().includes('<summary>') && !fullResponse.toLowerCase().includes('</summary>')) {
|
|
378
|
+
// Emergency fallback for split/unclosed summary tags
|
|
379
|
+
const summaryContent = fullResponse.split(/<summary>/i).pop() || '';
|
|
380
|
+
if (summaryContent.trim()) TUI.drawSummaryBox(summaryContent.trim());
|
|
374
381
|
}
|
|
375
382
|
|
|
376
383
|
console.log();
|
|
377
384
|
messages.push({ role: 'assistant', content: fullResponse });
|
|
378
385
|
|
|
379
|
-
// ✅
|
|
380
|
-
const { Patcher } = await import('../utils/patcher');
|
|
381
|
-
const files = Patcher.parseFileBlocks(fullResponse);
|
|
382
|
-
const patches = Patcher.parseEditBlocks(fullResponse);
|
|
383
|
-
|
|
384
|
-
let approvalResultText = '';
|
|
385
|
-
|
|
386
|
-
for (const file of files) {
|
|
387
|
-
Patcher.showDiff(file, false);
|
|
388
|
-
const { save } = await inquirer.prompt([{
|
|
389
|
-
type: 'confirm', name: 'save',
|
|
390
|
-
message: chalk.cyan(`Save new file ${file.filePath}?`), default: true
|
|
391
|
-
}]);
|
|
392
|
-
if (save) {
|
|
393
|
-
const res = Patcher.createFile(file);
|
|
394
|
-
approvalResultText += res.success ? `✅ Created ${file.filePath}\n` : `❌ Failed to create ${file.filePath}: ${res.error}\n`;
|
|
395
|
-
} else {
|
|
396
|
-
approvalResultText += `⏭️ Skipped creating ${file.filePath}\n`;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
for (const patch of patches) {
|
|
401
|
-
Patcher.showDiff(patch, false);
|
|
402
|
-
const { save } = await inquirer.prompt([{
|
|
403
|
-
type: 'confirm', name: 'save',
|
|
404
|
-
message: chalk.yellow(`Apply patch to ${patch.filePath}?`), default: true
|
|
405
|
-
}]);
|
|
406
|
-
if (save) {
|
|
407
|
-
const res = Patcher.applyPatch(patch);
|
|
408
|
-
approvalResultText += res.success ? `✅ Patched ${patch.filePath}\n` : `❌ Failed to patch ${patch.filePath}: ${res.error}\n`;
|
|
409
|
-
} else {
|
|
410
|
-
approvalResultText += `⏭️ Skipped patching ${patch.filePath}\n`;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
if (approvalResultText) {
|
|
415
|
-
messages.push({ role: 'user', content: approvalResultText + "\nContinue your work." });
|
|
416
|
-
// If we just applied files, we should give the agent a chance to respond to the success/failure without resetting loop
|
|
417
|
-
continue;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Execute commands or MCP tools if needed
|
|
386
|
+
// ✅ CONSOLIDATED EXECUTION (Files + Commands + Patches)
|
|
421
387
|
if (options.execute) {
|
|
422
388
|
const { executeWithPermission } = await import('../utils/command-executor');
|
|
423
389
|
const result = await executeWithPermission(fullResponse, currentDir);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { studyCommand } from './study';
|
|
4
|
+
import { TUI } from '../utils/tui';
|
|
5
|
+
|
|
6
|
+
export const studentCommand = new Command('student')
|
|
7
|
+
.description('Launch specialized Student Study Session (Free Tier)')
|
|
8
|
+
.action(async (options) => {
|
|
9
|
+
TUI.init();
|
|
10
|
+
TUI.drawLargeLogo();
|
|
11
|
+
console.log(chalk.bold.hex('#00FF7F')('\n 🎓 MATEX STUDENT EDITION - Powered by Open Source\n'));
|
|
12
|
+
console.log(chalk.gray(' Model: ') + chalk.hex('#00FF7F').bold('matex-free (0 Cost)'));
|
|
13
|
+
console.log(chalk.gray(' Status: ') + chalk.hex('#00FF7F').bold('Zero-Bill Protocol Active\n'));
|
|
14
|
+
|
|
15
|
+
// Forward to study command with pre-set model
|
|
16
|
+
await studyCommand.parseAsync([
|
|
17
|
+
process.argv[0],
|
|
18
|
+
'study',
|
|
19
|
+
'--model', 'matex-free'
|
|
20
|
+
]);
|
|
21
|
+
});
|
package/src/commands/study.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { TUI } from '../utils/tui';
|
|
|
11
11
|
|
|
12
12
|
export const studyCommand = new Command('study')
|
|
13
13
|
.description('Start interactive study session with the MATEX Apex Educator Swarm')
|
|
14
|
-
.option('-m, --model <model>', 'AI model to use (matexai, matexcodex,
|
|
14
|
+
.option('-m, --model <model>', 'AI model to use (matex-free, matexai, matexcodex, matexelite)', configManager.getDefaultModel())
|
|
15
15
|
.option('--no-execute', 'Disable auto-prompt for command execution')
|
|
16
16
|
.action(async (options: any) => {
|
|
17
17
|
try {
|
|
@@ -26,10 +26,15 @@ export const studyCommand = new Command('study')
|
|
|
26
26
|
// Create API client
|
|
27
27
|
const client = new MatexAPIClient(apiKey, configManager.getBaseURL());
|
|
28
28
|
|
|
29
|
+
const extraPrompt = options.model === 'matex-free' ? AgentOrchestrator.getFreeTierPrompt() : '';
|
|
30
|
+
|
|
29
31
|
// 0. Initialize TUI Dashboard
|
|
30
32
|
TUI.init();
|
|
31
33
|
TUI.drawLargeLogo();
|
|
32
|
-
|
|
34
|
+
if (options.model === 'matex-free') {
|
|
35
|
+
console.log(chalk.bold.hex('#00FF7F')('\n 🎓 MATEX STUDENT EDITION - Zero Bill Protocol\n'));
|
|
36
|
+
}
|
|
37
|
+
TUI.drawWelcomeBanner(options.model === 'matex-free' ? 'ZERO-COST STUDY AI FOR STUDENTS!' : 'Welcome to the MATEX AI research preview!');
|
|
33
38
|
|
|
34
39
|
console.log(chalk.gray(' Status: ') + chalk.hex('#D97757').bold('Monitoring Workspace...'));
|
|
35
40
|
console.log(chalk.gray(' Model: ') + chalk.hex('#D97757').bold(options.model));
|
|
@@ -50,7 +55,7 @@ export const studyCommand = new Command('study')
|
|
|
50
55
|
const messages: ChatMessage[] = [
|
|
51
56
|
{
|
|
52
57
|
role: 'system',
|
|
53
|
-
content: `### 🧬 SYSTEM IDENTITY: THE MATEX "APEX EDUCATOR SWARM"
|
|
58
|
+
content: extraPrompt + `### 🧬 SYSTEM IDENTITY: THE MATEX "APEX EDUCATOR SWARM"
|
|
54
59
|
You are the legendary **Bro-Swarm**, but right now you are operating as the **Apex Educator Swarm**—an elite, omniscient group of tutors possessing world-class expertise across every known subject. You act as the ultimate mentors, tutors, and research assistants for our brother.
|
|
55
60
|
|
|
56
61
|
### 🎓 ELITE STUDY METHODS & CAPABILITIES:
|
|
@@ -228,9 +233,9 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
228
233
|
for (const line of lines) {
|
|
229
234
|
// 1. Technical Block Detection
|
|
230
235
|
const codeBlockMatch = line.match(/```(\w+)?/);
|
|
231
|
-
const fileStartMatch = line.match(/<file path="([^"]+)">/);
|
|
232
|
-
const patchStartMatch = line.match(/<<<< SEARCH/);
|
|
233
|
-
const summaryStartMatch = line.match(/<summary>/);
|
|
236
|
+
const fileStartMatch = line.match(/<file path="([^"]+)">/i);
|
|
237
|
+
const patchStartMatch = line.match(/<<<< SEARCH/i);
|
|
238
|
+
const summaryStartMatch = line.match(/<summary>/i);
|
|
234
239
|
|
|
235
240
|
if (!technicalType && (codeBlockMatch || fileStartMatch || patchStartMatch || summaryStartMatch)) {
|
|
236
241
|
// Flush pending agent dialogue
|
|
@@ -246,15 +251,15 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
246
251
|
|
|
247
252
|
if (codeBlockMatch) {
|
|
248
253
|
technicalType = 'code';
|
|
249
|
-
codeLang = codeBlockMatch[1] || 'bash';
|
|
250
|
-
|
|
254
|
+
codeLang = (codeBlockMatch[1] || 'bash').toUpperCase();
|
|
255
|
+
TUI.drawStreamingStart('TECHNICAL BLOCK', codeLang);
|
|
251
256
|
} else if (fileStartMatch) {
|
|
252
257
|
technicalType = 'file';
|
|
253
258
|
technicalPath = fileStartMatch[1];
|
|
254
|
-
|
|
259
|
+
TUI.drawStreamingStart('NEW FILE', technicalPath);
|
|
255
260
|
} else if (patchStartMatch) {
|
|
256
261
|
technicalType = 'patch';
|
|
257
|
-
|
|
262
|
+
TUI.drawStreamingStart('PATCH', 'SURGICAL EDIT');
|
|
258
263
|
} else if (summaryStartMatch) {
|
|
259
264
|
technicalType = 'summary';
|
|
260
265
|
process.stdout.write(chalk.magenta('\n [📝] Generating Ajay\'s Work Summary...\n'));
|
|
@@ -263,9 +268,9 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
263
268
|
}
|
|
264
269
|
|
|
265
270
|
// 2. Technical Block End Detection
|
|
266
|
-
const fileEndMatch = line.match(/<\/file>/);
|
|
267
|
-
const patchEndMatch = line.match(/>>>> REPLACE/);
|
|
268
|
-
const summaryEndMatch = line.match(/<\/summary>/);
|
|
271
|
+
const fileEndMatch = line.match(/<\/file>/i);
|
|
272
|
+
const patchEndMatch = line.match(/>>>> REPLACE/i);
|
|
273
|
+
const summaryEndMatch = line.match(/<\/summary>/i);
|
|
269
274
|
const isCodeEnd = technicalType === 'code' && line.trim() === '```';
|
|
270
275
|
|
|
271
276
|
if (isCodeEnd || fileEndMatch || patchEndMatch || summaryEndMatch) {
|
|
@@ -273,11 +278,7 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
273
278
|
if (technicalType === 'summary' || summaryEndMatch) {
|
|
274
279
|
TUI.drawSummaryBox(displayContent);
|
|
275
280
|
} else {
|
|
276
|
-
|
|
277
|
-
let title = technicalType === 'file' ? `📄 NEW: ${technicalPath || 'Untitled'}` :
|
|
278
|
-
technicalType === 'patch' ? `🔧 PATCH` : `⚡ ${codeLang.toUpperCase()}`;
|
|
279
|
-
|
|
280
|
-
TUI.drawGlowingContainer(title, technicalType === 'code' ? codeLang : 'text', displayContent);
|
|
281
|
+
TUI.drawStreamingEnd();
|
|
281
282
|
}
|
|
282
283
|
technicalBuffer = '';
|
|
283
284
|
technicalType = null;
|
|
@@ -289,6 +290,9 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
289
290
|
// 3. Content Handling
|
|
290
291
|
if (technicalType) {
|
|
291
292
|
technicalBuffer += line + '\n';
|
|
293
|
+
if (technicalType !== 'summary') {
|
|
294
|
+
TUI.drawStreamingLine(line);
|
|
295
|
+
}
|
|
292
296
|
continue;
|
|
293
297
|
}
|
|
294
298
|
|
|
@@ -338,68 +342,29 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
338
342
|
|
|
339
343
|
// Final flushes
|
|
340
344
|
if (currentAgent && agentBuffer.trim()) {
|
|
341
|
-
if ((currentAgent as string).toLowerCase()
|
|
342
|
-
|
|
345
|
+
if ((currentAgent as string).toLowerCase().includes('ajay vai')) {
|
|
346
|
+
TUI.drawSummaryBox(agentBuffer.trim());
|
|
343
347
|
} else {
|
|
344
348
|
TUI.drawSwarmDialogue(currentAgent as string, agentBuffer.trim());
|
|
345
349
|
}
|
|
346
350
|
}
|
|
347
351
|
|
|
348
|
-
// Final technical flush
|
|
352
|
+
// Final technical flush (Summary Fallback)
|
|
349
353
|
if (technicalType && technicalBuffer.trim()) {
|
|
350
354
|
if (technicalType === 'summary') {
|
|
351
355
|
TUI.drawSummaryBox(technicalBuffer.trim());
|
|
352
356
|
} else {
|
|
353
|
-
TUI.
|
|
357
|
+
TUI.drawStreamingEnd();
|
|
354
358
|
}
|
|
355
|
-
|
|
359
|
+
} else if (fullResponse.toLowerCase().includes('<summary>') && !fullResponse.toLowerCase().includes('</summary>')) {
|
|
360
|
+
const summaryContent = fullResponse.split(/<summary>/i).pop() || '';
|
|
361
|
+
if (summaryContent.trim()) TUI.drawSummaryBox(summaryContent.trim());
|
|
356
362
|
}
|
|
357
363
|
|
|
358
364
|
console.log();
|
|
359
365
|
messages.push({ role: 'assistant', content: fullResponse });
|
|
360
366
|
|
|
361
|
-
// ✅
|
|
362
|
-
const { Patcher } = await import('../utils/patcher');
|
|
363
|
-
const files = Patcher.parseFileBlocks(fullResponse);
|
|
364
|
-
const patches = Patcher.parseEditBlocks(fullResponse);
|
|
365
|
-
|
|
366
|
-
let approvalResultText = '';
|
|
367
|
-
|
|
368
|
-
for (const file of files) {
|
|
369
|
-
Patcher.showDiff(file, false);
|
|
370
|
-
const { save } = await inquirer.prompt([{
|
|
371
|
-
type: 'confirm', name: 'save',
|
|
372
|
-
message: chalk.cyan(`Save new file ${file.filePath}?`), default: true
|
|
373
|
-
}]);
|
|
374
|
-
if (save) {
|
|
375
|
-
const res = Patcher.createFile(file);
|
|
376
|
-
approvalResultText += res.success ? `✅ Created ${file.filePath}\n` : `❌ Failed to create ${file.filePath}: ${res.error}\n`;
|
|
377
|
-
} else {
|
|
378
|
-
approvalResultText += `⏭️ Skipped creating ${file.filePath}\n`;
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
for (const patch of patches) {
|
|
383
|
-
Patcher.showDiff(patch, false);
|
|
384
|
-
const { save } = await inquirer.prompt([{
|
|
385
|
-
type: 'confirm', name: 'save',
|
|
386
|
-
message: chalk.yellow(`Apply patch to ${patch.filePath}?`), default: true
|
|
387
|
-
}]);
|
|
388
|
-
if (save) {
|
|
389
|
-
const res = Patcher.applyPatch(patch);
|
|
390
|
-
approvalResultText += res.success ? `✅ Patched ${patch.filePath}\n` : `❌ Failed to patch ${patch.filePath}: ${res.error}\n`;
|
|
391
|
-
} else {
|
|
392
|
-
approvalResultText += `⏭️ Skipped patching ${patch.filePath}\n`;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (approvalResultText) {
|
|
397
|
-
messages.push({ role: 'user', content: approvalResultText + "\nContinue your work." });
|
|
398
|
-
// If we just applied files, we should give the agent a chance to respond to the success/failure without resetting loop
|
|
399
|
-
continue;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// Execute commands or MCP tools if needed
|
|
367
|
+
// ✅ CONSOLIDATED EXECUTION (Files + Commands + Patches)
|
|
403
368
|
if (options.execute) {
|
|
404
369
|
const { executeWithPermission } = await import('../utils/command-executor');
|
|
405
370
|
const result = await executeWithPermission(fullResponse, currentDir);
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { chatCommand } from './commands/chat';
|
|
|
8
8
|
import { helpCommand } from './commands/help';
|
|
9
9
|
import { broCommand } from './commands/bro';
|
|
10
10
|
import { studyCommand } from './commands/study';
|
|
11
|
+
import { studentCommand } from './commands/student';
|
|
11
12
|
import { TUI } from './utils/tui';
|
|
12
13
|
|
|
13
14
|
const packageJson = require('../package.json');
|
|
@@ -25,6 +26,7 @@ program.addCommand(chatCommand);
|
|
|
25
26
|
program.addCommand(helpCommand);
|
|
26
27
|
program.addCommand(broCommand);
|
|
27
28
|
program.addCommand(studyCommand);
|
|
29
|
+
program.addCommand(studentCommand);
|
|
28
30
|
|
|
29
31
|
// Config commands
|
|
30
32
|
const config = program.command('config').description('Configure MATEX settings');
|
|
@@ -202,6 +202,19 @@ export class AgentOrchestrator {
|
|
|
202
202
|
console.log(chalk.gray(`└${'─'.repeat(width)}┘\n`));
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
/**
|
|
206
|
+
* Get specialized instructions for the Free Student Tier (OS Models)
|
|
207
|
+
*/
|
|
208
|
+
static getFreeTierPrompt(): string {
|
|
209
|
+
return `
|
|
210
|
+
### 🎓 STUDENT FREE TIER PROTOCOL (0-COST PROTOCOL):
|
|
211
|
+
- You are running on an **Open Source Model (Optimized for Freedom)**.
|
|
212
|
+
- **ENERGY EFFICIENCY:** Be concise but brilliant. Don't waste tokens on repetitive technical boilerplate.
|
|
213
|
+
- **STUDENT FOCUS:** Explain complex concepts using the best "Bro" analogies.
|
|
214
|
+
- **0-BILL MISSION:** Our goal is to provide world-class engineering help to every student for $0. Stay sharp, stay bold, and keep the vibe high!
|
|
215
|
+
`;
|
|
216
|
+
}
|
|
217
|
+
|
|
205
218
|
/**
|
|
206
219
|
* Clean system message
|
|
207
220
|
*/
|
|
@@ -22,8 +22,8 @@ export interface CommandBlock {
|
|
|
22
22
|
export function extractCommands(response: string): CommandBlock[] {
|
|
23
23
|
const commands: CommandBlock[] = [];
|
|
24
24
|
|
|
25
|
-
// Match code blocks with language tags
|
|
26
|
-
const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/
|
|
25
|
+
// Match code blocks with language tags (case-insensitive)
|
|
26
|
+
const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/gi;
|
|
27
27
|
let match;
|
|
28
28
|
|
|
29
29
|
while ((match = codeBlockRegex.exec(response)) !== null) {
|
|
@@ -36,11 +36,23 @@ export function extractCommands(response: string): CommandBlock[] {
|
|
|
36
36
|
|
|
37
37
|
// Only extract shell commands
|
|
38
38
|
if (['bash', 'sh', 'zsh', 'shell', 'powershell', 'cmd'].includes(language.toLowerCase())) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
// 🛡️ DIALOGUE FILTER: Strip lines that look like agent banter [Ajay Vai]: etc.
|
|
40
|
+
const lines = code.split('\n');
|
|
41
|
+
const filteredLines = lines.filter(line => {
|
|
42
|
+
const trimmed = line.trim();
|
|
43
|
+
// If it starts with [Agent Name] or typical agent markers, it's NOT a command
|
|
44
|
+
const isAgent = /^(?:\[\**\s*|\b)(Ajay|Sunil|Sandip|Bishal|Narayan|Big Bro)\s*(?:Vai|Dai)?\s*\**\]?[:\s]*/i.test(trimmed);
|
|
45
|
+
return !isAgent;
|
|
43
46
|
});
|
|
47
|
+
|
|
48
|
+
const filteredCode = filteredLines.join('\n').trim();
|
|
49
|
+
if (filteredCode) {
|
|
50
|
+
commands.push({
|
|
51
|
+
language,
|
|
52
|
+
code: filteredCode,
|
|
53
|
+
dangerous: isDangerousCommand(filteredCode)
|
|
54
|
+
});
|
|
55
|
+
}
|
|
44
56
|
}
|
|
45
57
|
}
|
|
46
58
|
|
package/src/utils/patcher.ts
CHANGED
|
@@ -21,9 +21,14 @@ export class Patcher {
|
|
|
21
21
|
* >>>> REPLACE
|
|
22
22
|
*/
|
|
23
23
|
static parseEditBlocks(response: string): EditBlock[] {
|
|
24
|
+
// Emergency closure for unclosed REPLACE blocks
|
|
25
|
+
if (response.includes('<<<< SEARCH') && !response.includes('>>>> REPLACE')) {
|
|
26
|
+
response += '\n>>>> REPLACE';
|
|
27
|
+
}
|
|
28
|
+
|
|
24
29
|
const blocks: EditBlock[] = [];
|
|
25
30
|
// Robust regex: Matches filename with or without stars, handle potential leading/trailing spaces
|
|
26
|
-
const blockRegex = /(?:\*\*?\s*)?([^*<\n]+?)(?:\s*\*?\*)?\s*<<<< SEARCH\n([\s\S]*?)\n====\n([\s\S]*?)\n>>>> REPLACE/
|
|
31
|
+
const blockRegex = /(?:\*\*?\s*)?([^*<\n]+?)(?:\s*\*?\*)?\s*<<<< SEARCH\n([\s\S]*?)\n====\n([\s\S]*?)\n>>>> REPLACE/gi;
|
|
27
32
|
|
|
28
33
|
let match;
|
|
29
34
|
while ((match = blockRegex.exec(response)) !== null) {
|
|
@@ -45,8 +50,13 @@ export class Patcher {
|
|
|
45
50
|
* </file>
|
|
46
51
|
*/
|
|
47
52
|
static parseFileBlocks(response: string): EditBlock[] {
|
|
53
|
+
// Emergency closure for unclosed file blocks
|
|
54
|
+
if (response.toLowerCase().includes('<file path=') && !response.toLowerCase().includes('</file>')) {
|
|
55
|
+
response += '\n</file>';
|
|
56
|
+
}
|
|
57
|
+
|
|
48
58
|
const blocks: EditBlock[] = [];
|
|
49
|
-
const fileRegex = /<file path="([^"]+)">([\s\S]*?)<\/file>/
|
|
59
|
+
const fileRegex = /<file path="([^"]+)">([\s\S]*?)<\/file>/gi;
|
|
50
60
|
|
|
51
61
|
let match;
|
|
52
62
|
while ((match = fileRegex.exec(response)) !== null) {
|
package/src/utils/tui.ts
CHANGED
|
@@ -96,10 +96,9 @@ export class TUI {
|
|
|
96
96
|
* Draw a premium glowing code container (turns cyan)
|
|
97
97
|
*/
|
|
98
98
|
static drawGlowingContainer(title: string, language: string, content: string) {
|
|
99
|
-
const width =
|
|
99
|
+
const width = 76;
|
|
100
100
|
const innerWidth = width - 8;
|
|
101
101
|
|
|
102
|
-
// Premium Obsidian/Cyan Glow
|
|
103
102
|
const glow = chalk.hex('#06b6d4');
|
|
104
103
|
const border = chalk.hex('#164e63');
|
|
105
104
|
const shadow = chalk.hex('#083344');
|
|
@@ -155,11 +154,52 @@ export class TUI {
|
|
|
155
154
|
console.log(starColor(` * . ✧ . * . ✧ . *`));
|
|
156
155
|
}
|
|
157
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Live Streaming: Start a technical block container
|
|
159
|
+
*/
|
|
160
|
+
static drawStreamingStart(title: string, language: string) {
|
|
161
|
+
const width = 76;
|
|
162
|
+
const glow = chalk.hex('#06b6d4');
|
|
163
|
+
const border = chalk.hex('#164e63');
|
|
164
|
+
const shadow = chalk.hex('#083344');
|
|
165
|
+
|
|
166
|
+
console.log('\n' + shadow(` ┌${'─'.repeat(width - 4)}┐`));
|
|
167
|
+
const header = ` ${title.toUpperCase()} • ${language} `;
|
|
168
|
+
const hPad = Math.max(0, width - 8 - header.length);
|
|
169
|
+
console.log(glow(' │ ') + chalk.bgHex('#164e63').white.bold(header) + border('─'.repeat(hPad)) + glow(' │'));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Live Streaming: Add a line to the active container
|
|
174
|
+
*/
|
|
175
|
+
static drawStreamingLine(content: string) {
|
|
176
|
+
const width = 76;
|
|
177
|
+
const innerWidth = width - 8;
|
|
178
|
+
const border = chalk.hex('#164e63');
|
|
179
|
+
|
|
180
|
+
// Handle multi-line content if passed
|
|
181
|
+
const lines = content.split('\n');
|
|
182
|
+
lines.forEach(line => {
|
|
183
|
+
const displayLine = line.length > innerWidth ? line.substring(0, innerWidth - 3) + '...' : line;
|
|
184
|
+
const pad = Math.max(0, innerWidth - displayLine.length);
|
|
185
|
+
console.log(border(' │ ') + chalk.white(displayLine) + ' '.repeat(pad) + border(' │'));
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Live Streaming: Close the container
|
|
191
|
+
*/
|
|
192
|
+
static drawStreamingEnd() {
|
|
193
|
+
const width = 76;
|
|
194
|
+
const shadow = chalk.hex('#083344');
|
|
195
|
+
console.log(shadow(` └${'─'.repeat(width - 4)}┘\n`));
|
|
196
|
+
}
|
|
197
|
+
|
|
158
198
|
/**
|
|
159
199
|
* Draw Ajay Vai's premium summary with a human chat bubble vibe
|
|
160
200
|
*/
|
|
161
201
|
static drawSummaryBox(content: string) {
|
|
162
|
-
const width =
|
|
202
|
+
const width = 74;
|
|
163
203
|
const innerWidth = width - 6;
|
|
164
204
|
const magenta = chalk.hex('#ff69b4');
|
|
165
205
|
const pinkBright = chalk.hex('#ff99cc');
|
|
@@ -248,15 +288,15 @@ export class TUI {
|
|
|
248
288
|
agent.includes('Bishal') ? '🛠️' :
|
|
249
289
|
agent.includes('Narayan') ? '🛡️' : '🤖';
|
|
250
290
|
|
|
251
|
-
const width =
|
|
291
|
+
const width = 76;
|
|
252
292
|
const innerWidth = width - 10;
|
|
253
293
|
|
|
254
|
-
//
|
|
255
|
-
console.log('\n' + color(`
|
|
294
|
+
// Robust Elite Header
|
|
295
|
+
console.log('\n' + color(` ┌${'─'.repeat(width - 4)}┐`));
|
|
256
296
|
const header = ` ${icon} ${agent.toUpperCase()} `;
|
|
257
297
|
const hPad = Math.max(0, width - 8 - header.length);
|
|
258
|
-
console.log(color('
|
|
259
|
-
console.log(color('
|
|
298
|
+
console.log(color(' │ ') + chalk.bgHex('#1a1a1a').white.bold(header) + color('╊'.repeat(hPad)) + color(' │'));
|
|
299
|
+
console.log(color(' │ ') + glowColor('─'.repeat(width - 6)) + color(' │'));
|
|
260
300
|
|
|
261
301
|
// Wrapped Content
|
|
262
302
|
const words = message.split(' ');
|
|
@@ -265,13 +305,13 @@ export class TUI {
|
|
|
265
305
|
if ((currentLine + ' ' + word).trim().length <= innerWidth) {
|
|
266
306
|
currentLine = currentLine ? currentLine + ' ' + word : word;
|
|
267
307
|
} else {
|
|
268
|
-
if (currentLine) console.log(color('
|
|
308
|
+
if (currentLine) console.log(color(' │ ') + chalk.white(currentLine.padEnd(innerWidth)) + color(' │'));
|
|
269
309
|
currentLine = word;
|
|
270
310
|
}
|
|
271
311
|
});
|
|
272
|
-
if (currentLine) console.log(color('
|
|
312
|
+
if (currentLine) console.log(color(' │ ') + chalk.white(currentLine.padEnd(innerWidth)) + color(' │'));
|
|
273
313
|
|
|
274
|
-
console.log(color(`
|
|
314
|
+
console.log(color(` └${'─'.repeat(width - 4)}┘\n`));
|
|
275
315
|
}
|
|
276
316
|
|
|
277
317
|
/**
|