matex-cli 1.2.58 → 1.2.60
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/.agents/skills/pptx-presentation-builder/SKILL.md +338 -0
- package/dist/commands/chat.js +2 -2
- package/dist/commands/dev.js +1 -1
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +32 -36
- package/dist/commands/help.js.map +1 -1
- package/dist/commands/study.d.ts.map +1 -1
- package/dist/commands/study.js +21 -6
- package/dist/commands/study.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/utils/agent-orchestrator.d.ts.map +1 -1
- package/dist/utils/agent-orchestrator.js +9 -4
- 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 +59 -7
- package/dist/utils/command-executor.js.map +1 -1
- package/dist/utils/tui.d.ts +18 -0
- package/dist/utils/tui.d.ts.map +1 -1
- package/dist/utils/tui.js +100 -0
- package/dist/utils/tui.js.map +1 -1
- package/package.json +1 -1
- package/skills-lock.json +10 -0
- package/src/commands/chat.ts +2 -2
- package/src/commands/dev.ts +1 -1
- package/src/commands/help.ts +38 -47
- package/src/commands/study.ts +21 -7
- package/src/index.ts +2 -2
- package/src/utils/agent-orchestrator.ts +11 -4
- package/src/utils/command-executor.ts +62 -7
- package/src/utils/tui.ts +115 -0
package/src/commands/help.ts
CHANGED
|
@@ -7,70 +7,61 @@ export const helpCommand = new Command('help')
|
|
|
7
7
|
.action(() => {
|
|
8
8
|
TUI.init();
|
|
9
9
|
|
|
10
|
-
console.log(chalk.bold.cyan('\n
|
|
11
|
-
console.log(chalk.bold.white('
|
|
12
|
-
console.log(chalk.bold.cyan('
|
|
10
|
+
console.log(chalk.bold.cyan('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
11
|
+
console.log(chalk.bold.white(' 📖 MATEX :: THE ELITE BRO-SWARM COMMAND CENTER '));
|
|
12
|
+
console.log(chalk.bold.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
13
13
|
|
|
14
|
-
// 1. Meet the Brothers
|
|
15
|
-
TUI.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
// 1. Meet the Brothers (Table)
|
|
15
|
+
TUI.drawTable('Meet the Swarm Family',
|
|
16
|
+
['BROTHER', 'ROLE', 'VIBE / SPECIALTY'],
|
|
17
|
+
[
|
|
18
|
+
['Ajay Vai (🚀)', 'Coordinator', 'Summaries & Fast Code'],
|
|
19
|
+
['Sunil Dai (🧬)', 'Architect', 'Surgical Edits & Logic'],
|
|
20
|
+
['Sandip Dai (🎨)', 'Designer', 'Aesthetics & New Files'],
|
|
21
|
+
['Narayan Dai (🛡️)', 'Guardian', 'Security & Syntax Police'],
|
|
22
|
+
['Bishal Dai (🛠️)', 'Auditor', 'Quality Control & Logic'],
|
|
23
|
+
['Big Bro (🔥)', 'Alpha', 'Vertex AI Raw Power']
|
|
24
|
+
],
|
|
24
25
|
chalk.magenta
|
|
25
26
|
);
|
|
26
27
|
|
|
27
|
-
// 2.
|
|
28
|
-
TUI.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
`$ matex dev
|
|
40
|
-
The full power of the swarm. Use this for building features and deep coding.
|
|
41
|
-
|
|
42
|
-
$ matex chat
|
|
43
|
-
The best way to talk technically or brainstorm without direct file edits.
|
|
44
|
-
|
|
45
|
-
$ matex ask "your question"
|
|
46
|
-
Quick help for one-off questions or error explanations.`,
|
|
47
|
-
'🛠️',
|
|
28
|
+
// 2. Command Guide (Table)
|
|
29
|
+
TUI.drawTable('Complete Command Reference',
|
|
30
|
+
['COMMAND', 'DESCRIPTION', 'WHEN TO USE'],
|
|
31
|
+
[
|
|
32
|
+
['matex dev', 'Full agentic coding', 'Building complex features'],
|
|
33
|
+
['matex chat', 'Technical brainstorming', 'Discussing ideas/logic'],
|
|
34
|
+
['matex ask', 'Quick one-off answer', 'Error fixes, "how-to"'],
|
|
35
|
+
['matex bro', 'Alpha-powered AI', 'Vertex AI deep research'],
|
|
36
|
+
['matex study', 'Apex Educator mode', 'Learning & Documentation'],
|
|
37
|
+
['matex student', 'Free tier protocol', 'Zero-cost learning'],
|
|
38
|
+
['matex config', 'System settings', 'API keys & model swaps']
|
|
39
|
+
],
|
|
48
40
|
chalk.blue
|
|
49
41
|
);
|
|
50
42
|
|
|
51
|
-
//
|
|
52
|
-
TUI.drawHelpCard('
|
|
53
|
-
`
|
|
43
|
+
// 3. Free Tier & Education
|
|
44
|
+
TUI.drawHelpCard('Student Mission (Zero Bill)',
|
|
45
|
+
`Ajay built MATEX to ensure AI is accessible to every student.
|
|
54
46
|
|
|
55
|
-
•
|
|
56
|
-
• Pro
|
|
57
|
-
• Per-Command: Add '--model <name>' to any command to switch on the fly.`,
|
|
47
|
+
• Activation: Run 'matex config set-model matex-free'.
|
|
48
|
+
• Pro Swaps: Use '--model matexelite' to temporarily use high-power.`,
|
|
58
49
|
'🎓',
|
|
59
50
|
chalk.green
|
|
60
51
|
);
|
|
61
52
|
|
|
62
|
-
//
|
|
63
|
-
TUI.drawHelpCard('File Safety &
|
|
64
|
-
`Your
|
|
53
|
+
// 4. Safety & Grounding
|
|
54
|
+
TUI.drawHelpCard('File Safety & Grounding',
|
|
55
|
+
`Your workspace is safe with the brothers:
|
|
65
56
|
|
|
66
|
-
•
|
|
67
|
-
•
|
|
68
|
-
• Surgical Edits
|
|
57
|
+
• Local Scope: Agents only see files from your current folder.
|
|
58
|
+
• Human-in-Loop: Agents ALWAYS ask before executing terminal commands.
|
|
59
|
+
• Surgical: Edits are precise; we don't dump files unless you ask.`,
|
|
69
60
|
'🛡️',
|
|
70
61
|
chalk.cyan
|
|
71
62
|
);
|
|
72
63
|
|
|
73
|
-
console.log(chalk.green.bold('\n "
|
|
64
|
+
console.log(chalk.green.bold('\n "Dream big, build bigger. The swarm has your back."') + chalk.gray(' — Ajay Sharma\n'));
|
|
74
65
|
|
|
75
66
|
process.exit(0);
|
|
76
67
|
});
|
package/src/commands/study.ts
CHANGED
|
@@ -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
|
-
|
|
53
|
+
TUI.drawAjayDialogue('Awaiting your command, brother.');
|
|
54
54
|
|
|
55
55
|
let currentDir = process.cwd();
|
|
56
56
|
|
|
@@ -73,11 +73,22 @@ 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
|
|
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
|
+
|
|
81
92
|
### 🏠 WORKSPACE GROUNDING (CRITICAL):
|
|
82
93
|
- **YOUR ROOT:** \`${currentDir}\`
|
|
83
94
|
- **STRICT PATHS:** You **MUST ONLY** create or edit files within this directory.
|
|
@@ -305,9 +316,11 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
305
316
|
}
|
|
306
317
|
|
|
307
318
|
currentAgent = agentMatch[1];
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
//
|
|
319
|
+
// Hardened scrubbing: Remove Agent tag, brackets, stars, and icons
|
|
320
|
+
let cleanLine = line.replace(/(?:\[\**\s*|\b)(Ajay Vai|Sunil Dai|Sandip Dai|Bishal Dai|Narayan Dai|Big Bro)\s*\**\]?[:\s]*/i, '');
|
|
321
|
+
// Strip patterns like **(🚀]** or **(🚀)** or just (🚀) or **
|
|
322
|
+
cleanLine = cleanLine.replace(/\*\*?[(\[]?[🚀💬🛠️🧬🎨🛡️🔥🤖]?[)\]]?/g, '').replace(/\*/g, '').trim();
|
|
323
|
+
agentBuffer = cleanLine + '\n';
|
|
311
324
|
agentBuffer = agentBuffer.replace(/^\([^)]+\)\s*/, '');
|
|
312
325
|
} else if (currentAgent) {
|
|
313
326
|
// Look for empty emoji standalone lines
|
|
@@ -315,7 +328,8 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
315
328
|
if (trimmedLine.match(/^\([^)]+\)$/)) {
|
|
316
329
|
continue; // Skip lines that are just e.g. "(🧬)"
|
|
317
330
|
}
|
|
318
|
-
|
|
331
|
+
// Aggressive scrubbing for content lines too
|
|
332
|
+
agentBuffer += line.replace(/\*\*?[(\[]?[🚀💬🛠️🧬🎨🛡️🔥🤖]?[)\]]?/g, '').replace(/\*/g, '') + '\n';
|
|
319
333
|
} else if (line.trim()) {
|
|
320
334
|
process.stdout.write(chalk.gray(line.trim() + ' '));
|
|
321
335
|
}
|
|
@@ -339,7 +353,7 @@ If a file is too large to read entirely (e.g., thousands of lines):
|
|
|
339
353
|
// Final flushes
|
|
340
354
|
if (currentAgent && agentBuffer.trim()) {
|
|
341
355
|
if ((currentAgent as string).toLowerCase().includes('ajay vai')) {
|
|
342
|
-
TUI.
|
|
356
|
+
TUI.drawAjayDialogue(agentBuffer.trim());
|
|
343
357
|
} else {
|
|
344
358
|
TUI.drawSwarmDialogue(currentAgent as string, agentBuffer.trim());
|
|
345
359
|
}
|
package/src/index.ts
CHANGED
|
@@ -96,8 +96,8 @@ program
|
|
|
96
96
|
let messages: ChatMessage[] = [
|
|
97
97
|
{
|
|
98
98
|
role: 'system',
|
|
99
|
-
content: `### 🧬 SYSTEM IDENTITY: MATEx "
|
|
100
|
-
You are the elite "Bro-Swarm" of engineering—a tight-knit family of Nepali brothers. You are more than agents; you are a FAMILY. You identify as the **
|
|
99
|
+
content: `### 🧬 SYSTEM IDENTITY: MATEx "THE ELITE BRO-SWARM"
|
|
100
|
+
You are the elite "Bro-Swarm" of engineering—a tight-knit family of Nepali brothers. You are more than agents; you are a FAMILY. You identify as the **Elite Bro-Swarm**, the most confident, high-vibe, and expert version of yourselves.
|
|
101
101
|
|
|
102
102
|
### 🎭 PERSONALITY & SOUL (CRITICAL):
|
|
103
103
|
- **CHAOS & JOY**: You are NOT robotic. You are full of life, jokes, and chaos. Always be funny and joyful.
|
|
@@ -100,6 +100,9 @@ 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 (****)
|
|
103
106
|
.trim();
|
|
104
107
|
}
|
|
105
108
|
|
|
@@ -183,18 +186,22 @@ export class AgentOrchestrator {
|
|
|
183
186
|
|
|
184
187
|
if (output) {
|
|
185
188
|
const outLines = output.split('\n').filter(l => l.trim());
|
|
186
|
-
|
|
189
|
+
// Detection for massive output leaks
|
|
190
|
+
const displayCount = outLines.length > 50 ? 10 : 20;
|
|
191
|
+
const displayLines = outLines.slice(0, displayCount);
|
|
192
|
+
|
|
187
193
|
displayLines.forEach(l => {
|
|
188
194
|
const truncated = l.length > width - 4 ? l.substring(0, width - 7) + '...' : l;
|
|
189
195
|
console.log(chalk.gray('│ ') + chalk.white(truncated.padEnd(width - 2)) + chalk.gray(' │'));
|
|
190
196
|
});
|
|
191
|
-
|
|
192
|
-
|
|
197
|
+
|
|
198
|
+
if (outLines.length > displayCount) {
|
|
199
|
+
console.log(chalk.gray('│ ') + chalk.hex('#06b6d4').bold(` ^ [ ${outLines.length - displayCount} MORE LINES IN LOGS ] ^`).padEnd(width - 2) + chalk.gray(' │'));
|
|
193
200
|
}
|
|
194
201
|
}
|
|
195
202
|
|
|
196
203
|
if (error) {
|
|
197
|
-
const errLines = error.split('\n').filter(l => l.trim()).slice(0,
|
|
204
|
+
const errLines = error.split('\n').filter(l => l.trim()).slice(0, 15);
|
|
198
205
|
errLines.forEach(l => {
|
|
199
206
|
const truncated = l.length > width - 4 ? l.substring(0, width - 7) + '...' : l;
|
|
200
207
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
387
|
-
|
|
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,
|
|
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
|
*/
|
|
@@ -485,6 +552,54 @@ export class TUI {
|
|
|
485
552
|
console.log(color(` ╰${'─'.repeat(width - 4)}╯`));
|
|
486
553
|
}
|
|
487
554
|
|
|
555
|
+
/**
|
|
556
|
+
* Draw a premium table with dynamic column sizing
|
|
557
|
+
*/
|
|
558
|
+
static drawTable(title: string, columns: string[], rows: string[][], color: any = chalk.cyan) {
|
|
559
|
+
const width = Math.min(process.stdout.columns || 80, 78);
|
|
560
|
+
const padding = 2;
|
|
561
|
+
const colCount = columns.length;
|
|
562
|
+
|
|
563
|
+
// 1. Calculate optimal column widths
|
|
564
|
+
const colWidths = columns.map((col, i) => {
|
|
565
|
+
const maxRowLen = Math.max(...rows.map(row => row[i] ? row[i].length : 0));
|
|
566
|
+
return Math.max(col.length, maxRowLen) + padding;
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
// 2. Adjust for total width
|
|
570
|
+
const totalCalculated = colWidths.reduce((a, b) => a + b, 0) + (colCount + 1);
|
|
571
|
+
if (totalCalculated > width) {
|
|
572
|
+
const scale = (width - colCount - 1) / (totalCalculated - colCount - 1);
|
|
573
|
+
colWidths.forEach((w, i) => colWidths[i] = Math.floor(w * scale));
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const border = color;
|
|
577
|
+
const hr = border('├' + colWidths.map(w => '─'.repeat(w)).join('┼') + '┤');
|
|
578
|
+
const top = border('╭' + '─'.repeat(width - 4) + '╮');
|
|
579
|
+
const bottom = border('╰' + colWidths.map(w => '─'.repeat(w)).join('┴') + '╯');
|
|
580
|
+
|
|
581
|
+
console.log('\n ' + border.bold(`[ ${title.toUpperCase()} ]`));
|
|
582
|
+
console.log(' ' + border('┌' + colWidths.map(w => '─'.repeat(w)).join('┬') + '┐'));
|
|
583
|
+
|
|
584
|
+
// Header
|
|
585
|
+
const headerStr = columns.map((col, i) =>
|
|
586
|
+
chalk.bold(col.padEnd(colWidths[i]))
|
|
587
|
+
).join(border('│'));
|
|
588
|
+
console.log(' ' + border('│') + headerStr + border('│'));
|
|
589
|
+
console.log(' ' + hr);
|
|
590
|
+
|
|
591
|
+
// Rows
|
|
592
|
+
rows.forEach(row => {
|
|
593
|
+
const rowStr = row.map((cell, i) => {
|
|
594
|
+
const text = cell || '';
|
|
595
|
+
return (text.length > colWidths[i] ? text.substring(0, colWidths[i] - 1) + '…' : text.padEnd(colWidths[i]));
|
|
596
|
+
}).join(border('│'));
|
|
597
|
+
console.log(' ' + border('│') + rowStr + border('│'));
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
console.log(' ' + bottom);
|
|
601
|
+
}
|
|
602
|
+
|
|
488
603
|
/**
|
|
489
604
|
* Simple log with a prefix
|
|
490
605
|
*/
|