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.
Files changed (39) hide show
  1. package/dist/commands/chat.js +1 -1
  2. package/dist/commands/chat.js.map +1 -1
  3. package/dist/commands/dev.d.ts.map +1 -1
  4. package/dist/commands/dev.js +31 -60
  5. package/dist/commands/dev.js.map +1 -1
  6. package/dist/commands/student.d.ts +3 -0
  7. package/dist/commands/student.d.ts.map +1 -0
  8. package/dist/commands/student.js +26 -0
  9. package/dist/commands/student.js.map +1 -0
  10. package/dist/commands/study.d.ts.map +1 -1
  11. package/dist/commands/study.js +31 -61
  12. package/dist/commands/study.js.map +1 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +2 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/utils/agent-orchestrator.d.ts +4 -0
  17. package/dist/utils/agent-orchestrator.d.ts.map +1 -1
  18. package/dist/utils/agent-orchestrator.js +12 -0
  19. package/dist/utils/agent-orchestrator.js.map +1 -1
  20. package/dist/utils/command-executor.d.ts.map +1 -1
  21. package/dist/utils/command-executor.js +17 -6
  22. package/dist/utils/command-executor.js.map +1 -1
  23. package/dist/utils/patcher.d.ts.map +1 -1
  24. package/dist/utils/patcher.js +10 -2
  25. package/dist/utils/patcher.js.map +1 -1
  26. package/dist/utils/tui.d.ts +12 -0
  27. package/dist/utils/tui.d.ts.map +1 -1
  28. package/dist/utils/tui.js +46 -11
  29. package/dist/utils/tui.js.map +1 -1
  30. package/package.json +1 -1
  31. package/src/commands/chat.ts +1 -1
  32. package/src/commands/dev.ts +30 -64
  33. package/src/commands/student.ts +21 -0
  34. package/src/commands/study.ts +30 -65
  35. package/src/index.ts +2 -0
  36. package/src/utils/agent-orchestrator.ts +13 -0
  37. package/src/utils/command-executor.ts +18 -6
  38. package/src/utils/patcher.ts +12 -2
  39. package/src/utils/tui.ts +51 -11
@@ -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, matexcodexlite, matexelite, matexspirit)', configManager.getDefaultModel())
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
- TUI.drawWelcomeBanner('Welcome to the MATEX AI research preview!');
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
- process.stdout.write(chalk.gray('\n [⚡] Building technical block...\n'));
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
- process.stdout.write(chalk.cyan(`\n [📂] Creating file: ${technicalPath}...\n`));
277
+ TUI.drawStreamingStart('NEW FILE', technicalPath);
273
278
  } else if (patchStartMatch) {
274
279
  technicalType = 'patch';
275
- process.stdout.write(chalk.yellow('\n [📂] Applying surgical patch...\n'));
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
- // Handle the display
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() === 'ajay vai') {
360
- process.stdout.write(`\n${chalk.magenta.bold(`[${currentAgent}]:`)} ${chalk.white(agentBuffer.trim())}\n`);
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.drawGlowingContainer('Final technical content', 'text', technicalBuffer.trim());
375
+ TUI.drawStreamingEnd();
372
376
  }
373
- process.stdout.write('\n');
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
- // ✅ IMMEDIATE FILE AND PATCH APPROVAL
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
+ });
@@ -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, matexcodexlite, matexelite, matexspirit)', configManager.getDefaultModel())
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
- TUI.drawWelcomeBanner('Welcome to the MATEX AI research preview!');
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
- process.stdout.write(chalk.gray('\n [⚡] Building technical block...\n'));
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
- process.stdout.write(chalk.cyan(`\n [📂] Creating file: ${technicalPath}...\n`));
259
+ TUI.drawStreamingStart('NEW FILE', technicalPath);
255
260
  } else if (patchStartMatch) {
256
261
  technicalType = 'patch';
257
- process.stdout.write(chalk.yellow('\n [📂] Applying surgical patch...\n'));
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
- // Handle the display
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() === 'ajay vai') {
342
- process.stdout.write(`\n${chalk.magenta.bold(`[${currentAgent}]:`)} ${chalk.white(agentBuffer.trim())}\n`);
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.drawGlowingContainer('Final technical content', 'text', technicalBuffer.trim());
357
+ TUI.drawStreamingEnd();
354
358
  }
355
- process.stdout.write('\n');
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
- // ✅ IMMEDIATE FILE AND PATCH APPROVAL
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]*?)```/g;
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
- commands.push({
40
- language,
41
- code,
42
- dangerous: isDangerousCommand(code)
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
 
@@ -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/g;
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>/g;
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 = Math.min(process.stdout.columns || 80, 90);
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 = Math.min(process.stdout.columns || 80, 76);
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 = Math.min(process.stdout.columns || 80, 85);
291
+ const width = 76;
252
292
  const innerWidth = width - 10;
253
293
 
254
- // Holographic Header
255
- console.log('\n' + color(` ◢${''.repeat(width - 4)}◣`));
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(' ') + chalk.bgHex('#1a1a1a').white.bold(header) + color(''.repeat(hPad)) + color(' '));
259
- console.log(color(' ') + glowColor('─'.repeat(width - 6)) + 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(' ') + chalk.white(currentLine.padEnd(innerWidth)) + 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(' ') + chalk.white(currentLine.padEnd(innerWidth)) + color(' '));
312
+ if (currentLine) console.log(color(' ') + chalk.white(currentLine.padEnd(innerWidth)) + color(' '));
273
313
 
274
- console.log(color(` ◥${''.repeat(width - 4)}◤\n`));
314
+ console.log(color(` └${''.repeat(width - 4)}┘\n`));
275
315
  }
276
316
 
277
317
  /**