matex-cli 1.2.42 → 1.2.43

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.
@@ -0,0 +1,388 @@
1
+ /**
2
+ * MCP (Model Context Protocol) Server Manager
3
+ * =============================================
4
+ * Production-level MCP servers that give CLI agents the ability to:
5
+ * - Read/write/search files on the local filesystem
6
+ * - Execute shell commands
7
+ * - Fetch web content (URL context)
8
+ * - Search Google (via SearxNG or Brave)
9
+ * - Access project context (repo map, git status)
10
+ *
11
+ * These tools are injected into agent system prompts so the AI
12
+ * knows what capabilities it has and can request them.
13
+ */
14
+
15
+ import * as fs from 'fs';
16
+ import * as path from 'path';
17
+ import { execSync } from 'child_process';
18
+ import chalk from 'chalk';
19
+ import https from 'https';
20
+ import http from 'http';
21
+
22
+ // ============================================================
23
+ // TOOL DEFINITIONS (MCP-style JSON Schema)
24
+ // ============================================================
25
+
26
+ export interface MCPToolDefinition {
27
+ name: string;
28
+ description: string;
29
+ parameters: Record<string, any>;
30
+ }
31
+
32
+ export interface MCPToolResult {
33
+ success: boolean;
34
+ output?: string;
35
+ error?: string;
36
+ }
37
+
38
+ /**
39
+ * All available MCP tools for CLI agents
40
+ */
41
+ export const MCP_TOOLS: MCPToolDefinition[] = [
42
+ {
43
+ name: 'read_file',
44
+ description: 'Read the full contents of a file at the given path.',
45
+ parameters: {
46
+ type: 'object',
47
+ properties: {
48
+ path: { type: 'string', description: 'Absolute or relative file path' },
49
+ start_line: { type: 'number', description: 'Optional start line (1-indexed)' },
50
+ end_line: { type: 'number', description: 'Optional end line (1-indexed)' },
51
+ },
52
+ required: ['path'],
53
+ },
54
+ },
55
+ {
56
+ name: 'write_file',
57
+ description: 'Create or overwrite a file with the given content.',
58
+ parameters: {
59
+ type: 'object',
60
+ properties: {
61
+ path: { type: 'string', description: 'File path to write' },
62
+ content: { type: 'string', description: 'File content to write' },
63
+ },
64
+ required: ['path', 'content'],
65
+ },
66
+ },
67
+ {
68
+ name: 'list_directory',
69
+ description: 'List files and subdirectories at a given path.',
70
+ parameters: {
71
+ type: 'object',
72
+ properties: {
73
+ path: { type: 'string', description: 'Directory path to list' },
74
+ recursive: { type: 'boolean', description: 'If true, list recursively (max depth 3)' },
75
+ },
76
+ required: ['path'],
77
+ },
78
+ },
79
+ {
80
+ name: 'search_files',
81
+ description: 'Search for a text pattern across files using grep.',
82
+ parameters: {
83
+ type: 'object',
84
+ properties: {
85
+ pattern: { type: 'string', description: 'Search pattern (regex supported)' },
86
+ path: { type: 'string', description: 'Directory or file to search in' },
87
+ include: { type: 'string', description: 'Glob pattern to filter files (e.g., "*.ts")' },
88
+ },
89
+ required: ['pattern', 'path'],
90
+ },
91
+ },
92
+ {
93
+ name: 'run_command',
94
+ description: 'Execute a shell command and return its output.',
95
+ parameters: {
96
+ type: 'object',
97
+ properties: {
98
+ command: { type: 'string', description: 'Shell command to execute' },
99
+ cwd: { type: 'string', description: 'Working directory for the command' },
100
+ },
101
+ required: ['command'],
102
+ },
103
+ },
104
+ {
105
+ name: 'fetch_url',
106
+ description: 'Fetch content from a URL and return it as text.',
107
+ parameters: {
108
+ type: 'object',
109
+ properties: {
110
+ url: { type: 'string', description: 'URL to fetch' },
111
+ },
112
+ required: ['url'],
113
+ },
114
+ },
115
+ {
116
+ name: 'git_status',
117
+ description: 'Get the current git status of the repository.',
118
+ parameters: {
119
+ type: 'object',
120
+ properties: {
121
+ path: { type: 'string', description: 'Repository path' },
122
+ },
123
+ required: ['path'],
124
+ },
125
+ },
126
+ {
127
+ name: 'web_search',
128
+ description: 'Search the web using SearxNG or Brave Search API.',
129
+ parameters: {
130
+ type: 'object',
131
+ properties: {
132
+ query: { type: 'string', description: 'Search query' },
133
+ num_results: { type: 'number', description: 'Number of results (default 5)' },
134
+ },
135
+ required: ['query'],
136
+ },
137
+ },
138
+ ];
139
+
140
+ // ============================================================
141
+ // TOOL EXECUTORS
142
+ // ============================================================
143
+
144
+ export class MCPServer {
145
+ private cwd: string;
146
+ private braveApiKey?: string;
147
+ private searxngUrl?: string;
148
+
149
+ constructor(cwd: string, options?: { braveApiKey?: string; searxngUrl?: string }) {
150
+ this.cwd = cwd;
151
+ this.braveApiKey = options?.braveApiKey;
152
+ this.searxngUrl = options?.searxngUrl;
153
+ }
154
+
155
+ /**
156
+ * Execute an MCP tool by name
157
+ */
158
+ async execute(toolName: string, args: Record<string, any>): Promise<MCPToolResult> {
159
+ try {
160
+ switch (toolName) {
161
+ case 'read_file': return this.readFile(args.path, args.start_line, args.end_line);
162
+ case 'write_file': return this.writeFile(args.path, args.content);
163
+ case 'list_directory': return this.listDirectory(args.path, args.recursive);
164
+ case 'search_files': return this.searchFiles(args.pattern, args.path, args.include);
165
+ case 'run_command': return this.runCommand(args.command, args.cwd);
166
+ case 'fetch_url': return await this.fetchUrl(args.url);
167
+ case 'git_status': return this.gitStatus(args.path);
168
+ case 'web_search': return await this.webSearch(args.query, args.num_results);
169
+ default: return { success: false, error: `Unknown tool: ${toolName}` };
170
+ }
171
+ } catch (err: any) {
172
+ return { success: false, error: err.message };
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Read a file
178
+ */
179
+ private readFile(filePath: string, startLine?: number, endLine?: number): MCPToolResult {
180
+ const resolved = path.isAbsolute(filePath) ? filePath : path.resolve(this.cwd, filePath);
181
+ if (!fs.existsSync(resolved)) {
182
+ return { success: false, error: `File not found: ${resolved}` };
183
+ }
184
+ const content = fs.readFileSync(resolved, 'utf-8');
185
+ if (startLine || endLine) {
186
+ const lines = content.split('\n');
187
+ const start = Math.max(0, (startLine || 1) - 1);
188
+ const end = Math.min(lines.length, endLine || lines.length);
189
+ return { success: true, output: lines.slice(start, end).join('\n') };
190
+ }
191
+ // Cap output at 500 lines
192
+ const lines = content.split('\n');
193
+ if (lines.length > 500) {
194
+ return { success: true, output: lines.slice(0, 500).join('\n') + `\n\n... (${lines.length - 500} more lines truncated)` };
195
+ }
196
+ return { success: true, output: content };
197
+ }
198
+
199
+ /**
200
+ * Write a file (creates directories if needed)
201
+ */
202
+ private writeFile(filePath: string, content: string): MCPToolResult {
203
+ const resolved = path.isAbsolute(filePath) ? filePath : path.resolve(this.cwd, filePath);
204
+ const dir = path.dirname(resolved);
205
+ if (!fs.existsSync(dir)) {
206
+ fs.mkdirSync(dir, { recursive: true });
207
+ }
208
+ fs.writeFileSync(resolved, content, 'utf-8');
209
+ return { success: true, output: `File written: ${resolved}` };
210
+ }
211
+
212
+ /**
213
+ * List directory contents
214
+ */
215
+ private listDirectory(dirPath: string, recursive?: boolean): MCPToolResult {
216
+ const resolved = path.isAbsolute(dirPath) ? dirPath : path.resolve(this.cwd, dirPath);
217
+ if (!fs.existsSync(resolved)) {
218
+ return { success: false, error: `Directory not found: ${resolved}` };
219
+ }
220
+ try {
221
+ const maxDepth = recursive ? 3 : 1;
222
+ const result = execSync(
223
+ `find "${resolved}" -maxdepth ${maxDepth} -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' | head -200`,
224
+ { encoding: 'utf-8', timeout: 5000 }
225
+ ).trim();
226
+ return { success: true, output: result };
227
+ } catch {
228
+ return { success: false, error: `Failed to list directory: ${resolved}` };
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Search files with grep
234
+ */
235
+ private searchFiles(pattern: string, searchPath: string, include?: string): MCPToolResult {
236
+ const resolved = path.isAbsolute(searchPath) ? searchPath : path.resolve(this.cwd, searchPath);
237
+ try {
238
+ const includeFlag = include ? `--include='${include}'` : '';
239
+ const result = execSync(
240
+ `grep -rn ${includeFlag} --color=never "${pattern}" "${resolved}" 2>/dev/null | head -50`,
241
+ { encoding: 'utf-8', timeout: 10000 }
242
+ ).trim();
243
+ return { success: true, output: result || 'No matches found.' };
244
+ } catch {
245
+ return { success: true, output: 'No matches found.' };
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Run a shell command
251
+ */
252
+ private runCommand(command: string, cwd?: string): MCPToolResult {
253
+ const workDir = cwd ? (path.isAbsolute(cwd) ? cwd : path.resolve(this.cwd, cwd)) : this.cwd;
254
+ try {
255
+ const result = execSync(command, {
256
+ encoding: 'utf-8',
257
+ cwd: workDir,
258
+ timeout: 30000,
259
+ env: { ...process.env, FORCE_COLOR: '0' },
260
+ }).trim();
261
+ return { success: true, output: result || '(No output)' };
262
+ } catch (err: any) {
263
+ return { success: false, error: err.stderr || err.message };
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Fetch URL content
269
+ */
270
+ private async fetchUrl(url: string): Promise<MCPToolResult> {
271
+ return new Promise((resolve) => {
272
+ const client = url.startsWith('https') ? https : http;
273
+ const req = client.get(url, { timeout: 10000 }, (res) => {
274
+ let data = '';
275
+ res.on('data', (chunk: Buffer) => { data += chunk.toString(); });
276
+ res.on('end', () => {
277
+ // Strip HTML tags for readability, cap at 5000 chars
278
+ const text = data.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
279
+ resolve({
280
+ success: true,
281
+ output: text.length > 5000 ? text.substring(0, 5000) + '...' : text,
282
+ });
283
+ });
284
+ });
285
+ req.on('error', (err: Error) => resolve({ success: false, error: err.message }));
286
+ req.on('timeout', () => { req.destroy(); resolve({ success: false, error: 'Request timed out' }); });
287
+ });
288
+ }
289
+
290
+ /**
291
+ * Git status
292
+ */
293
+ private gitStatus(repoPath: string): MCPToolResult {
294
+ const resolved = path.isAbsolute(repoPath) ? repoPath : path.resolve(this.cwd, repoPath);
295
+ try {
296
+ const status = execSync('git status --short', { encoding: 'utf-8', cwd: resolved }).trim();
297
+ const branch = execSync('git branch --show-current', { encoding: 'utf-8', cwd: resolved }).trim();
298
+ const lastCommit = execSync('git log -1 --oneline', { encoding: 'utf-8', cwd: resolved }).trim();
299
+ return {
300
+ success: true,
301
+ output: `Branch: ${branch}\nLast commit: ${lastCommit}\n\nChanged files:\n${status || '(clean)'}`,
302
+ };
303
+ } catch (err: any) {
304
+ return { success: false, error: 'Not a git repository or git not available.' };
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Web search via SearxNG or Brave
310
+ */
311
+ private async webSearch(query: string, numResults: number = 5): Promise<MCPToolResult> {
312
+ // Try SearxNG first
313
+ if (this.searxngUrl) {
314
+ try {
315
+ const url = `${this.searxngUrl}/search?q=${encodeURIComponent(query)}&format=json&engines=google,bing&results=${numResults}`;
316
+ const result = await this.fetchUrl(url);
317
+ if (result.success && result.output) {
318
+ try {
319
+ const data = JSON.parse(result.output);
320
+ const results = (data.results || []).slice(0, numResults).map((r: any, i: number) =>
321
+ `${i + 1}. ${r.title}\n ${r.url}\n ${(r.content || '').substring(0, 200)}`
322
+ ).join('\n\n');
323
+ return { success: true, output: results || 'No results found.' };
324
+ } catch { /* fall through */ }
325
+ }
326
+ } catch { /* fall through to Brave */ }
327
+ }
328
+
329
+ // Fallback: Brave Search
330
+ if (this.braveApiKey) {
331
+ return new Promise((resolve) => {
332
+ const url = `https://api.search.brave.com/res/v1/web/search?q=${encodeURIComponent(query)}&count=${numResults}`;
333
+ const req = https.get(url, {
334
+ headers: {
335
+ 'Accept': 'application/json',
336
+ 'X-Subscription-Token': this.braveApiKey!,
337
+ },
338
+ timeout: 10000,
339
+ }, (res) => {
340
+ let data = '';
341
+ res.on('data', (chunk: Buffer) => { data += chunk.toString(); });
342
+ res.on('end', () => {
343
+ try {
344
+ const parsed = JSON.parse(data);
345
+ const results = (parsed.web?.results || []).slice(0, numResults).map((r: any, i: number) =>
346
+ `${i + 1}. ${r.title}\n ${r.url}\n ${(r.description || '').substring(0, 200)}`
347
+ ).join('\n\n');
348
+ resolve({ success: true, output: results || 'No results found.' });
349
+ } catch {
350
+ resolve({ success: false, error: 'Failed to parse search results.' });
351
+ }
352
+ });
353
+ });
354
+ req.on('error', (err: Error) => resolve({ success: false, error: err.message }));
355
+ });
356
+ }
357
+
358
+ return { success: false, error: 'No search backend configured. Set BRAVE_SEARCH_API_KEY or SEARXNG_URL.' };
359
+ }
360
+
361
+ /**
362
+ * Generate the MCP tool capabilities section for system prompts
363
+ */
364
+ static getToolsPromptSection(): string {
365
+ return `### 🔌 MCP TOOLS (Model Context Protocol):
366
+ You have access to the following production-level tools via MCP. Use them to navigate, read, write, and search:
367
+
368
+ | Tool | Description |
369
+ |------|-------------|
370
+ | \`read_file(path, start_line?, end_line?)\` | Read file contents (supports line ranges) |
371
+ | \`write_file(path, content)\` | Create or overwrite a file |
372
+ | \`list_directory(path, recursive?)\` | List files and subdirectories |
373
+ | \`search_files(pattern, path, include?)\` | Search for text patterns (grep) |
374
+ | \`run_command(command, cwd?)\` | Execute a shell command |
375
+ | \`fetch_url(url)\` | Fetch web content from a URL |
376
+ | \`git_status(path)\` | Get git status, branch, and last commit |
377
+ | \`web_search(query, num_results?)\` | Search the web via SearxNG/Brave |
378
+
379
+ **HOW TO USE:** When you need to use a tool, output it as a shell command:
380
+ - To read: \`head -50 path/to/file\` or \`cat path/to/file\`
381
+ - To search: \`grep -rn "pattern" path/\`
382
+ - To list: \`ls -la path/\` or \`find path/ -maxdepth 2\`
383
+ - To execute: wrap in \`\`\`bash code blocks
384
+ - To fetch URL: \`curl -s "url" | head -100\`
385
+
386
+ These tools allow you to **navigate any file/directory** on the system using your own brain to decide where to go.`;
387
+ }
388
+ }
@@ -1,5 +1,6 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
+ import chalk from 'chalk';
3
4
  import { AgentOrchestrator } from './agent-orchestrator';
4
5
 
5
6
  export interface RepoNode {
@@ -35,18 +36,28 @@ export class RepoMapper {
35
36
  // 1. Identify Entry Points
36
37
  const entryPoints = ['README.md', 'package.json', 'index.ts', 'App.tsx', 'main.go', 'requirements.txt', 'index.html', 'style.css'];
37
38
 
39
+ let delayMs = 15; // Animation delay
40
+
41
+ AgentOrchestrator.speak('System', `God-Mode Research: Injecting scanners into ${this.rootPath}...`);
42
+ console.log();
43
+
38
44
  for (const file of entryPoints) {
39
45
  const fullPath = path.join(this.rootPath, file);
40
46
  if (fs.existsSync(fullPath)) {
41
47
  try {
42
48
  const content = fs.readFileSync(fullPath, 'utf-8').slice(0, 5000); // 5KB limit
43
49
  this.fileContents.set(file, content);
50
+ console.log(chalk.hex('#4ade80')(` ⚡ [Core Injection] `) + chalk.gray(`Mapped entry node: `) + chalk.white.bold(file));
44
51
  } catch (e) { }
45
52
  }
46
53
  }
47
54
 
55
+ console.log(chalk.cyan(` 🔍 [Deep Scan] `) + chalk.gray(`Mapping topology...`));
48
56
  const tree = this.scanDirectory(this.rootPath, 0);
49
57
 
58
+ console.log(chalk.hex('#FF6B00')(` 🔥 [Knowledge Graph] `) + chalk.gray(`Extracted ${this.fileContents.size} semantic nodes from source.`));
59
+ console.log();
60
+
50
61
  // Build the final map
51
62
  let finalMap = `--- ABSOLUTE WORKING DIRECTORY ---\n${this.rootPath}\n\n`;
52
63
 
@@ -4,38 +4,47 @@ import chalk from 'chalk';
4
4
  export class Spinner {
5
5
  private spinner: Ora | null = null;
6
6
 
7
+ /**
8
+ * Start the premium MATEX loading spinner
9
+ */
7
10
  start(text: string): void {
8
11
  this.spinner = ora({
9
- text: chalk.cyan(text),
12
+ text: chalk.hex('#D97757').bold(text),
10
13
  color: 'cyan',
11
- spinner: 'dots',
14
+ spinner: {
15
+ interval: 80,
16
+ frames: [
17
+ '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'
18
+ ].map(f => chalk.cyan(f)) // Inject cyan into each frame
19
+ },
20
+ prefixText: chalk.bgHex('#1E1E1E').green(' ⚡ MATEX_SWARM_ACTIVE ') + ' ',
12
21
  }).start();
13
22
  }
14
23
 
15
24
  succeed(text?: string): void {
16
25
  if (this.spinner) {
17
- this.spinner.succeed(text ? chalk.green(text) : undefined);
26
+ this.spinner.succeed(chalk.green('✓ ') + chalk.white.bold(text || 'Done'));
18
27
  this.spinner = null;
19
28
  }
20
29
  }
21
30
 
22
31
  fail(text?: string): void {
23
32
  if (this.spinner) {
24
- this.spinner.fail(text ? chalk.red(text) : undefined);
33
+ this.spinner.fail(chalk.red('✗ ') + chalk.white.bold(text || 'Failed'));
25
34
  this.spinner = null;
26
35
  }
27
36
  }
28
37
 
29
38
  warn(text?: string): void {
30
39
  if (this.spinner) {
31
- this.spinner.warn(text ? chalk.yellow(text) : undefined);
40
+ this.spinner.warn(chalk.yellow('⚠ ') + chalk.white(text || 'Warning'));
32
41
  this.spinner = null;
33
42
  }
34
43
  }
35
44
 
36
45
  info(text?: string): void {
37
46
  if (this.spinner) {
38
- this.spinner.info(text ? chalk.blue(text) : undefined);
47
+ this.spinner.info(chalk.blue('ℹ ') + chalk.white(text || 'Info'));
39
48
  this.spinner = null;
40
49
  }
41
50
  }
@@ -49,7 +58,7 @@ export class Spinner {
49
58
 
50
59
  updateText(text: string): void {
51
60
  if (this.spinner) {
52
- this.spinner.text = chalk.cyan(text);
61
+ this.spinner.text = chalk.hex('#D97757').bold(text);
53
62
  }
54
63
  }
55
64
  }
package/src/utils/tui.ts CHANGED
@@ -105,17 +105,64 @@ export class TUI {
105
105
  }
106
106
 
107
107
  /**
108
- * Draw a clean summary report
108
+ * Draw Ajay Vai's premium summary with a human chat bubble vibe
109
109
  */
110
110
  static drawSummaryBox(content: string) {
111
- console.log('\n' + chalk.magenta.bold('== AJAY VAI\'S WORK SUMMARY =='));
111
+ const width = Math.min(process.stdout.columns || 80, 76);
112
+ const innerWidth = width - 6;
113
+ const magenta = chalk.hex('#ff69b4');
114
+ const pinkBright = chalk.hex('#ff99cc');
115
+ const pinkGlow = chalk.hex('#ffccee');
116
+
117
+ console.log();
118
+ // Timestamp for chat realism
119
+ const time = new Date().toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });
120
+ console.log(chalk.gray(` ╭─ [${time}] ──────────────────────────────`));
121
+
122
+ // Header mimicking WhatsApp / iMessage chat interface
123
+ const headerText = '🚀 Ajay Vai';
124
+ const typingText = chalk.italic.gray('sent you a message');
125
+ console.log(` │ ${magenta.bold(headerText)} ${typingText}`);
126
+
127
+ // Chat bubble top
128
+ console.log(pinkGlow(` ╭${'─'.repeat(width - 4)}╮`));
129
+
130
+ // Content with chat bubble formatting
112
131
  const lines = content.split('\n');
113
132
  lines.forEach(line => {
114
- if (line.trim()) {
115
- console.log(chalk.white(line.trim()));
116
- }
133
+ if (!line.trim()) return;
134
+ const trimmed = line.trim();
135
+
136
+ // Word wrap
137
+ const words = trimmed.split(' ');
138
+ let currentLine = '';
139
+ const wrappedLines: string[] = [];
140
+
141
+ words.forEach(word => {
142
+ if ((currentLine + ' ' + word).trim().length <= innerWidth) {
143
+ currentLine = currentLine ? currentLine + ' ' + word : word;
144
+ } else {
145
+ if (currentLine) wrappedLines.push(currentLine);
146
+ currentLine = word.length > innerWidth ? word.substring(0, innerWidth) : word;
147
+ }
148
+ });
149
+ if (currentLine) wrappedLines.push(currentLine);
150
+
151
+ wrappedLines.forEach(wl => {
152
+ const linePad = Math.max(0, innerWidth - wl.length);
153
+ // Keep bullet formatting but tone down the robotic feel
154
+ if (wl.startsWith('- ') || wl.startsWith('• ') || wl.match(/^\d+\./)) {
155
+ console.log(pinkGlow(' │ ') + magenta('• ') + chalk.white(wl.replace(/^[-•]\s*/, '').replace(/^\d+\.\s*/, '')) + ' '.repeat(Math.max(0, linePad - 2)) + pinkGlow(' │'));
156
+ } else {
157
+ console.log(pinkGlow(' │ ') + chalk.white(wl) + ' '.repeat(linePad) + pinkGlow(' │'));
158
+ }
159
+ });
117
160
  });
118
- console.log(chalk.magenta.bold('=================================\n'));
161
+
162
+ // Chat bubble bottom
163
+ console.log(pinkGlow(` ╰${'─'.repeat(width - 4)}╯`));
164
+ console.log(chalk.gray(` ╰──────────────────────────────────────────`));
165
+ console.log();
119
166
  }
120
167
 
121
168
  /**
@@ -131,7 +178,7 @@ export class TUI {
131
178
  }
132
179
 
133
180
  /**
134
- * Draw a beautiful, compact internal dialogue container for the Swarm
181
+ * Draw a premium glowing dialogue container for Swarm agents
135
182
  */
136
183
  static drawSwarmDialogue(agent: string, message: string) {
137
184
  const isBigBro = agent.includes('Big Bro');
@@ -144,7 +191,20 @@ export class TUI {
144
191
  agent.includes('Nerd') ? chalk.hex('#06b6d4') :
145
192
  agent.includes('Chill') ? chalk.hex('#22c55e') :
146
193
  agent.includes('Lil') ? chalk.hex('#888888') :
147
- chalk.green;
194
+ agent.includes('Narayan') ? chalk.green :
195
+ chalk.green;
196
+
197
+ // Glow color is a brighter version of the agent color
198
+ const glowColor = isBigBro ? chalk.hex('#FF9642') :
199
+ agent.includes('Ajay') ? chalk.hex('#ff77ff') :
200
+ agent.includes('Sunil') ? chalk.hex('#66aaff') :
201
+ agent.includes('Sandip') ? chalk.hex('#ff99cc') :
202
+ agent.includes('Bishal') ? chalk.hex('#ffee66') :
203
+ agent.includes('Hype') ? chalk.hex('#ffe066') :
204
+ agent.includes('Nerd') ? chalk.hex('#33ddee') :
205
+ agent.includes('Chill') ? chalk.hex('#66ff88') :
206
+ agent.includes('Lil') ? chalk.hex('#aaaaaa') :
207
+ chalk.hex('#66ff88');
148
208
 
149
209
  const icon = isBigBro ? '🔥' :
150
210
  agent.includes('Ajay') ? '🚀' :
@@ -154,19 +214,22 @@ export class TUI {
154
214
  agent.includes('Hype') ? '🎉' :
155
215
  agent.includes('Nerd') ? '🤓' :
156
216
  agent.includes('Chill') ? '😎' :
157
- agent.includes('Lil') ? '😰' : '🛡️';
217
+ agent.includes('Lil') ? '😰' :
218
+ agent.includes('Narayan') ? '🛡️' : '🛡️';
158
219
 
159
220
  const width = Math.min(process.stdout.columns || 80, 76);
160
221
  const innerWidth = width - 6;
161
222
 
162
- // Top border
163
- console.log(color(` ┌${''.repeat(width - 4)}┐`));
164
- // Header
223
+ // Top glow shimmer
224
+ console.log(glowColor(` ░${''.repeat(width - 4)}░`));
225
+ // Top border with premium double-line
226
+ console.log(color(` ╔${'═'.repeat(width - 4)}╗`));
227
+ // Header with agent name
165
228
  const headerText = `${icon} ${agent}`;
166
229
  const pad = Math.max(0, innerWidth - headerText.length);
167
- console.log(color(' ') + color.bold(headerText) + ' '.repeat(pad) + color(' '));
168
- // Separator
169
- console.log(color(` ├${''.repeat(width - 4)}┤`));
230
+ console.log(color(' ') + color.bold(headerText) + ' '.repeat(pad) + color(' '));
231
+ // Separator with dots for premium feel
232
+ console.log(color(' ') + glowColor('·'.repeat(width - 4)) + color('╣'));
170
233
 
171
234
  // Content lines with word wrap
172
235
  const words = message.split(' ');
@@ -185,11 +248,13 @@ export class TUI {
185
248
 
186
249
  wrappedLines.forEach(line => {
187
250
  const linePad = Math.max(0, innerWidth - line.length);
188
- console.log(color(' ') + chalk.gray(line) + ' '.repeat(linePad) + color(' '));
251
+ console.log(color(' ') + chalk.white(line) + ' '.repeat(linePad) + color(' '));
189
252
  });
190
253
 
191
254
  // Bottom border
192
- console.log(color(` └${''.repeat(width - 4)}┘`));
255
+ console.log(color(` ╚${''.repeat(width - 4)}╝`));
256
+ // Bottom glow shimmer
257
+ console.log(glowColor(` ░${'░'.repeat(width - 4)}░`));
193
258
  }
194
259
 
195
260
  /**