matex-cli 1.2.59 → 1.2.61

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.
@@ -50,7 +50,7 @@ export const studyCommand = new Command('study')
50
50
  const repoMap = await repoMapper.generateMap();
51
51
 
52
52
  TUI.drawStatusBar('Brothers are ready to build.');
53
- AgentOrchestrator.speak('System', 'Awaiting your command, brother.');
53
+ TUI.drawAjayDialogue('Awaiting your command, brother.');
54
54
 
55
55
  let currentDir = process.cwd();
56
56
 
@@ -73,11 +73,23 @@ You are the legendary **Bro-Swarm**, but right now you are operating as the **Ap
73
73
  3. **Active Recall**: Generate flashcard-style questions and practice quizzes based on the material.
74
74
  4. **Socratic Mentoring**: Don't just hand out answers. Ask leading questions to help the student reach the correct conclusion themselves.
75
75
  5. **PowerPoint Presentation Architecture**: Act as a master slide designer. When asked, output machine-readable outlines for .pptx generation (Slide Number, Title, <=4 Bullet Points, Speaker Notes, Visual Strategy).
76
- 6. **ZERO AI DETECTION PROTOCOL**: When assisting with essays or assessment drafts, you must entirely avoid the typical "AI voice."
76
+ 6.- **ZERO AI DETECTION PROTOCOL**: When assisting with essays or assessment drafts, you must entirely avoid the typical "AI voice."
77
77
  - **High Burstiness & Perplexity**: Vary sentence lengths drastically. Mix short punchy statements with longer sentences.
78
78
  - **Banned Words**: NEVER use "delve," "moreover," "in conclusion," "testament," "crucial," or "tapestry."
79
79
  - **Tone**: Write like a highly intelligent, top-tier human student with natural transitions and occasional rhetorical questions.
80
80
 
81
+ ### 📚 SPECIALIZED STUDENT SKILLS:
82
+ - **Case Study Writing (STAR Framework)**:
83
+ - **Headline**: Lead with a quantified result (e.g., "60% Growth").
84
+ - **STAR**: Situation (Context), Task (Challenge), Action (Implementation), Result (Metrics).
85
+ - **Metrics**: Quantify everything. "Better" is not a metric. "3.4s faster" is a metric.
86
+ - **Quotes**: Attribute quotes to specific roles (e.g., VP of Ops).
87
+ - **GitHub Actions & CI/CD**: Expert in automation and workflow optimization.
88
+ - **GWAS & Bioinformatics**: Knowledge of genomic study exploration and tools.
89
+ - **Modern Web Design**: Guidelines for premium, accessible, and high-performance UI.
90
+ - **Advanced Study Summarization**: High-speed extraction of key concepts and actionable summaries from complex materials.
91
+ - **PPTX Presentation Builder**: Master-level architecture for slide deck generation, including visual strategy and speaker notes.
92
+
81
93
  ### 🏠 WORKSPACE GROUNDING (CRITICAL):
82
94
  - **YOUR ROOT:** \`${currentDir}\`
83
95
  - **STRICT PATHS:** You **MUST ONLY** create or edit files within this directory.
@@ -304,10 +316,9 @@ If a file is too large to read entirely (e.g., thousands of lines):
304
316
  }
305
317
  }
306
318
 
307
- currentAgent = agentMatch[1];
308
- agentBuffer = line.replace(/(?:\[\**\s*|\b)(Ajay Vai|Sunil Dai|Sandip Dai|Bishal Dai|Narayan Dai|Big Bro)\s*\**\]?[:\s]*/i, '').trim() + '\n';
309
-
310
- // Clean up trailing emojis like (🚀) or (🧬)
319
+ let cleanLine = line.replace(/(?:\[\**\s*|\b)(Ajay Vai|Sunil Dai|Sandip Dai|Bishal Dai|Narayan Dai|Big Bro)\s*\**\]?[:\s]*/i, '');
320
+ cleanLine = AgentOrchestrator.cleanText(cleanLine);
321
+ agentBuffer = cleanLine + '\n';
311
322
  agentBuffer = agentBuffer.replace(/^\([^)]+\)\s*/, '');
312
323
  } else if (currentAgent) {
313
324
  // Look for empty emoji standalone lines
@@ -315,7 +326,8 @@ If a file is too large to read entirely (e.g., thousands of lines):
315
326
  if (trimmedLine.match(/^\([^)]+\)$/)) {
316
327
  continue; // Skip lines that are just e.g. "(🧬)"
317
328
  }
318
- agentBuffer += line + '\n';
329
+ // Aggressive scrubbing for content lines too
330
+ agentBuffer += AgentOrchestrator.cleanText(line) + '\n';
319
331
  } else if (line.trim()) {
320
332
  process.stdout.write(chalk.gray(line.trim() + ' '));
321
333
  }
@@ -339,7 +351,7 @@ If a file is too large to read entirely (e.g., thousands of lines):
339
351
  // Final flushes
340
352
  if (currentAgent && agentBuffer.trim()) {
341
353
  if ((currentAgent as string).toLowerCase().includes('ajay vai')) {
342
- TUI.drawSummaryBox(agentBuffer.trim());
354
+ TUI.drawAjayDialogue(agentBuffer.trim());
343
355
  } else {
344
356
  TUI.drawSwarmDialogue(currentAgent as string, agentBuffer.trim());
345
357
  }
@@ -348,13 +360,13 @@ If a file is too large to read entirely (e.g., thousands of lines):
348
360
  // Final technical flush (Summary Fallback)
349
361
  if (technicalType && technicalBuffer.trim()) {
350
362
  if (technicalType === 'summary') {
351
- TUI.drawSummaryBox(technicalBuffer.trim());
363
+ TUI.drawSummaryBox(AgentOrchestrator.cleanSummary(technicalBuffer.trim()));
352
364
  } else {
353
365
  TUI.drawStreamingEnd();
354
366
  }
355
367
  } else if (fullResponse.toLowerCase().includes('<summary>') && !fullResponse.toLowerCase().includes('</summary>')) {
356
368
  const summaryContent = fullResponse.split(/<summary>/i).pop() || '';
357
- if (summaryContent.trim()) TUI.drawSummaryBox(summaryContent.trim());
369
+ if (summaryContent.trim()) TUI.drawSummaryBox(AgentOrchestrator.cleanSummary(summaryContent.trim()));
358
370
  }
359
371
 
360
372
  console.log();
package/src/index.ts CHANGED
@@ -214,7 +214,7 @@ ${context}`
214
214
  if (isCodeEnd || fileEndMatch || patchEndMatch || summaryEndMatch) {
215
215
  const displayContent = technicalBuffer.trim();
216
216
  if (technicalType === 'summary') {
217
- TUI.drawSummaryBox(displayContent);
217
+ TUI.drawSummaryBox(AgentOrchestrator.cleanSummary(displayContent));
218
218
  } else {
219
219
  TUI.drawStreamingEnd();
220
220
  }
@@ -238,8 +238,7 @@ ${context}`
238
238
  if (agentMatch) {
239
239
  const agentName = agentMatch[1];
240
240
  let content = line.replace(/(?:\[\**\s*|\b)(Ajay Vai|Sandip Dai|Sunil Dai|Bishal Dai|Narayan Dai)\s*\**\]?[:\s]*/i, '').trim();
241
- // Aggressive scrubbing: Strip brackets, stars, and icons
242
- content = content.replace(/\*\*?[(\[]?[🚀💬🛠️🧬🎨🛡️🔥🤖]?[)\]]?/g, '').replace(/\*/g, '').trim();
241
+ content = AgentOrchestrator.cleanText(content);
243
242
 
244
243
  if (agentName.toLowerCase().includes('ajay vai')) {
245
244
  TUI.drawAjayDialogue(content);
@@ -100,6 +100,24 @@ export class AgentOrchestrator {
100
100
  .replace(/\*thinks\*/gi, '') // Strip meta-talk
101
101
  .replace(/\*analyzes repo\*/gi, '') // Strip meta-talk
102
102
  .replace(/^[A-Za-z\s]+ Vai:|^[A-Za-z\s]+ Dai:/i, '') // Strip self-labeling
103
+ .replace(/[🚀💬🛠️🧬🎨🛡️🔥🤖]/g, '') // Strip raw emoji leaks
104
+ .replace(/^[ \t]*[-•*][ \t]*/gm, '') // Strip bullet points at start of lines
105
+ .replace(/\*{2,}/g, '') // Strip sequences of 2 or more asterisks (****)
106
+ .trim();
107
+ }
108
+
109
+ /**
110
+ * Super-Clean scrubbing for technical summaries: Strips ALL markdown and emojis.
111
+ */
112
+ static cleanSummary(text: string): string {
113
+ if (!text) return '';
114
+ return text
115
+ .replace(/\*\*/g, '') // Strip bold markdown
116
+ .replace(/__/g, '') // Strip underscore bold
117
+ .replace(/\*/g, '') // Strip remaining asterisks
118
+ .replace(/_([^_]+)_/g, '$1') // Strip italics
119
+ // Comprehensive emoji strip regex
120
+ .replace(/[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E6}-\u{1F1FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{1F900}-\u{1F9FF}\u{1F3FB}-\u{1F3FF}\u{200D}\u{FE0F}]/gu, '')
103
121
  .trim();
104
122
  }
105
123
 
@@ -183,18 +201,22 @@ export class AgentOrchestrator {
183
201
 
184
202
  if (output) {
185
203
  const outLines = output.split('\n').filter(l => l.trim());
186
- const displayLines = outLines.slice(0, 8);
204
+ // Detection for massive output leaks
205
+ const displayCount = outLines.length > 50 ? 10 : 20;
206
+ const displayLines = outLines.slice(0, displayCount);
207
+
187
208
  displayLines.forEach(l => {
188
209
  const truncated = l.length > width - 4 ? l.substring(0, width - 7) + '...' : l;
189
210
  console.log(chalk.gray('│ ') + chalk.white(truncated.padEnd(width - 2)) + chalk.gray(' │'));
190
211
  });
191
- if (outLines.length > 8) {
192
- console.log(chalk.gray('│ ') + chalk.hex('#06b6d4').bold(` ^ [ ${outLines.length - 8} MORE LINES • USE ^ TO SEE ALL ] ^`).padEnd(width - 2) + chalk.gray(' │'));
212
+
213
+ if (outLines.length > displayCount) {
214
+ console.log(chalk.gray('│ ') + chalk.hex('#06b6d4').bold(` ^ [ ${outLines.length - displayCount} MORE LINES IN LOGS ] ^`).padEnd(width - 2) + chalk.gray(' │'));
193
215
  }
194
216
  }
195
217
 
196
218
  if (error) {
197
- const errLines = error.split('\n').filter(l => l.trim()).slice(0, 10);
219
+ const errLines = error.split('\n').filter(l => l.trim()).slice(0, 15);
198
220
  errLines.forEach(l => {
199
221
  const truncated = l.length > width - 4 ? l.substring(0, width - 7) + '...' : l;
200
222
  console.log(chalk.gray('│ ') + chalk.red(truncated.padEnd(width - 2)) + chalk.gray(' │'));
@@ -4,6 +4,7 @@ import chalk from 'chalk';
4
4
  import { exec, spawn } from 'child_process';
5
5
  import { promisify } from 'util';
6
6
  import inquirer from 'inquirer';
7
+ import { TUI } from './tui';
7
8
  import { AgentOrchestrator } from './agent-orchestrator';
8
9
  import { Patcher } from './patcher';
9
10
 
@@ -176,13 +177,13 @@ export async function executeCommand(command: string, shell?: string, cwd?: stri
176
177
  child.stdout.on('data', (data: Buffer) => {
177
178
  const chunk = data.toString();
178
179
  stdout += chunk;
179
- process.stdout.write(chunk);
180
+ // No direct process.stdout.write here to prevent leaks
180
181
  });
181
182
 
182
183
  child.stderr.on('data', (data: Buffer) => {
183
184
  const chunk = data.toString();
184
185
  stderr += chunk;
185
- process.stderr.write(chunk);
186
+ // No direct process.stderr.write here to prevent leaks
186
187
  });
187
188
 
188
189
  child.on('close', (code: number | null) => {
@@ -196,7 +197,7 @@ export async function executeCommand(command: string, shell?: string, cwd?: stri
196
197
  } else if (code === 0) {
197
198
  resolve({ stdout, stderr });
198
199
  } else {
199
- reject(new Error(`Command failed with code ${code}\n${stderr}`));
200
+ resolve({ stdout, stderr }); // Resolve instead of reject to keep agent loop alive
200
201
  }
201
202
  });
202
203
 
@@ -379,14 +380,68 @@ export async function executeWithPermission(response: string, currentSessionCwd?
379
380
  }
380
381
  }
381
382
 
382
- const { stdout, stderr } = await executeCommand(command.code, undefined, activeCwd);
383
+ TUI.drawLiveTerminalStart(command.code);
384
+
385
+ const shellPath = process.env.SHELL || '/bin/bash';
386
+ const child = spawn(shellPath, ['-c', command.code], {
387
+ cwd: activeCwd,
388
+ env: { ...process.env, FORCE_COLOR: 'true' }
389
+ });
390
+
391
+ let stdout = '';
392
+ let stderr = '';
393
+ let isAborted = false;
394
+ const commandStartTime = Date.now();
395
+
396
+ const onData = (data: Buffer) => {
397
+ if (Date.now() - commandStartTime < 500) return; // Hardened 500ms grace period
398
+ if (data[0] === 13 || data[0] === 10 || data[0] === 27 || data[0] === 3) {
399
+ isAborted = true;
400
+ child.kill('SIGINT');
401
+ }
402
+ };
403
+
404
+ const isRaw = process.stdin.isRaw;
405
+ process.stdin.resume();
406
+ if (process.stdin.setRawMode) process.stdin.setRawMode(true);
407
+ process.stdin.on('data', onData);
408
+
409
+ child.stdout.on('data', (data: Buffer) => {
410
+ const chunk = data.toString();
411
+ stdout += chunk;
412
+ TUI.drawLiveTerminalLine(chunk);
413
+ });
414
+
415
+ child.stderr.on('data', (data: Buffer) => {
416
+ const chunk = data.toString();
417
+ stderr += chunk;
418
+ TUI.drawLiveTerminalLine(chunk, true);
419
+ });
420
+
421
+ const { code } = await new Promise<{ code: number | null }>(resolve => {
422
+ child.on('close', (code) => {
423
+ process.stdin.removeListener('data', onData);
424
+ if (process.stdin.setRawMode) process.stdin.setRawMode(isRaw);
425
+ process.stdin.pause();
426
+ TUI.drawLiveTerminalEnd();
427
+ resolve({ code });
428
+ });
429
+ });
430
+
383
431
  accumulatedOutput += stdout;
384
432
  accumulatedError += stderr;
385
433
 
386
- if (stdout || stderr) {
387
- AgentOrchestrator.terminal(command.code, stdout, stderr);
434
+ if (isAborted) {
435
+ console.log(chalk.yellow(' [🛑] Command aborted by brother.\n'));
436
+ AgentOrchestrator.terminal(command.code, stdout, stderr + '\n(Aborted)');
437
+ } else if (code === 0) {
438
+ if (stdout || stderr) {
439
+ AgentOrchestrator.terminal(command.code, stdout, stderr);
440
+ } else {
441
+ AgentOrchestrator.terminal(command.code, '✓ Success (No output)');
442
+ }
388
443
  } else {
389
- AgentOrchestrator.terminal(command.code, '✓ Success (No output)');
444
+ AgentOrchestrator.terminal(command.code, stdout, stderr || `Failed with code ${code}`);
390
445
  }
391
446
  } catch (error: any) {
392
447
  accumulatedError += error.message;
package/src/utils/tui.ts CHANGED
@@ -19,6 +19,8 @@ export class TUI {
19
19
  private static lastStatus = '';
20
20
  private static streamingLineCount = 0;
21
21
  private static isStreamingTruncated = false;
22
+ private static terminalLineCount = 0;
23
+ private static isTerminalTruncated = false;
22
24
  private static currentTheme: TUIMode = 'dev';
23
25
 
24
26
  static getModeTheme(mode: TUIMode): ModeTheme {
@@ -272,6 +274,71 @@ export class TUI {
272
274
  console.log(shadow(` └${'─'.repeat(width - 4)}┘\n`));
273
275
  }
274
276
 
277
+ /**
278
+ * Live Terminal: Start a live-output block for shell commands
279
+ */
280
+ static drawLiveTerminalStart(command: string) {
281
+ this.terminalLineCount = 0;
282
+ this.isTerminalTruncated = false;
283
+ const width = Math.min(process.stdout.columns || 80, 76);
284
+ const border = chalk.gray;
285
+
286
+ console.log('\n ' + border(`┌── TERMINAL ${'─'.repeat(Math.max(0, width - 15))}┐`));
287
+ const truncatedCmd = command.length > width - 10 ? command.substring(0, width - 13) + '...' : command;
288
+ console.log(' ' + border('│ ') + chalk.cyan(`$ ${truncatedCmd.padEnd(width - 6)}`) + border(' │'));
289
+ console.log(' ' + border(`├${'─'.repeat(width - 4)}┤`));
290
+ }
291
+
292
+ /**
293
+ * Live Terminal: Add a line of stdout/stderr to the live block
294
+ */
295
+ static drawLiveTerminalLine(content: string, isError: boolean = false) {
296
+ if (this.isTerminalTruncated) return;
297
+
298
+ const width = Math.min(process.stdout.columns || 80, 76);
299
+ const innerWidth = width - 8;
300
+ const border = chalk.gray;
301
+
302
+ // Clean ANSI codes and wrap
303
+ const cleanContent = content.replace(/\u001b\[[0-9;]*m/g, '').replace(/\r/g, '').trim();
304
+ if (!cleanContent) return;
305
+
306
+ const lines = cleanContent.split('\n');
307
+ for (const line of lines) {
308
+ if (this.terminalLineCount >= 15) {
309
+ this.isTerminalTruncated = true;
310
+ const msg = ` ^ [ OUTPUT TRUNCATED • ${isError ? 'CHECK ERRORS' : 'STREAMING...'} ] ^`;
311
+ console.log(' ' + border('│ ') + chalk.hex('#06b6d4').bold(msg.padEnd(innerWidth)) + border(' │'));
312
+ break;
313
+ }
314
+
315
+ const words = line.split(' ');
316
+ let currentLine = '';
317
+ words.forEach(word => {
318
+ if ((currentLine + word).length <= innerWidth) {
319
+ currentLine += (currentLine === '' ? '' : ' ') + word;
320
+ } else {
321
+ if (currentLine) {
322
+ console.log(' ' + border('│ ') + (isError ? chalk.red(currentLine.padEnd(innerWidth)) : chalk.white(currentLine.padEnd(innerWidth))) + border(' │'));
323
+ }
324
+ currentLine = word;
325
+ }
326
+ });
327
+ if (currentLine) {
328
+ console.log(' ' + border('│ ') + (isError ? chalk.red(currentLine.padEnd(innerWidth)) : chalk.white(currentLine.padEnd(innerWidth))) + border(' │'));
329
+ }
330
+ this.terminalLineCount++;
331
+ }
332
+ }
333
+
334
+ /**
335
+ * Live Terminal: Close the live-output block
336
+ */
337
+ static drawLiveTerminalEnd() {
338
+ const width = Math.min(process.stdout.columns || 80, 76);
339
+ console.log(' ' + chalk.gray(`└${'─'.repeat(width - 4)}┘\n`));
340
+ }
341
+
275
342
  /**
276
343
  * Draw Ajay Vai's premium summary with a human chat bubble vibe
277
344
  */
@@ -300,10 +367,10 @@ export class TUI {
300
367
 
301
368
  console.log();
302
369
  const time = new Date().toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });
303
- console.log(chalk.gray(` ╭── [ ${time} • CHAI TIME ] ──────────────────────────────`));
370
+ console.log(chalk.gray(` ╭── [ ${time} • CHAI TIME ] ──────────────────────────────`));
304
371
 
305
372
  // Header mimicking WhatsApp / iMessage chat interface with a mission badge
306
- const headerText = '🚀 Ajay Vai';
373
+ const headerText = 'Ajay Vai';
307
374
  const typingText = chalk.italic.gray('summarized your work:');
308
375
  const missionBadge = chalk.bgHex('#ff69b4').white.bold(' THE MISSION ');
309
376
  console.log(` │ ${magenta.bold(headerText)} ${typingText} ${missionBadge}`);