matex-cli 1.1.13 → 1.2.2

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,68 @@
1
+ import chalk from 'chalk';
2
+
3
+ export type AgentRole = 'Architect' | 'Syntax' | 'Frontend' | 'Backend' | 'System' | 'Commander';
4
+
5
+ export interface AgentConfig {
6
+ name: string;
7
+ icon: string;
8
+ color: (text: string) => string;
9
+ }
10
+
11
+ const AGENT_CONFIGS: Record<AgentRole, AgentConfig> = {
12
+ Architect: {
13
+ name: 'MatexCodeArchitect',
14
+ icon: '🧬',
15
+ color: chalk.blue,
16
+ },
17
+ Syntax: {
18
+ name: 'SyntaxGuard',
19
+ icon: 'šŸ›”ļø',
20
+ color: chalk.yellow,
21
+ },
22
+ Frontend: {
23
+ name: 'VisualAgent',
24
+ icon: 'šŸŽØ',
25
+ color: chalk.magenta,
26
+ },
27
+ Backend: {
28
+ name: 'CoreAgent',
29
+ icon: 'āš™ļø',
30
+ color: chalk.cyan,
31
+ },
32
+ System: {
33
+ name: 'Matex_Orchestrator',
34
+ icon: '🧠',
35
+ color: chalk.white,
36
+ },
37
+ Commander: {
38
+ name: 'MatexResearchCommander',
39
+ icon: 'šŸš€',
40
+ color: chalk.green,
41
+ }
42
+ };
43
+
44
+ export class AgentOrchestrator {
45
+ /**
46
+ * Display an agent's "thought" or action
47
+ */
48
+ static speak(role: AgentRole, message: string) {
49
+ const config = AGENT_CONFIGS[role];
50
+ console.log(`\n${config.icon} ${config.color(`${config.name}:`)} ${chalk.white(message)}`);
51
+ }
52
+
53
+ /**
54
+ * Display a collaboration transition
55
+ */
56
+ static transition(from: AgentRole, to: AgentRole) {
57
+ const fromCfg = AGENT_CONFIGS[from];
58
+ const toCfg = AGENT_CONFIGS[to];
59
+ console.log(chalk.gray(` └─ ${fromCfg.icon} āž” ${toCfg.icon} Handover to ${toCfg.name}...`));
60
+ }
61
+
62
+ /**
63
+ * Clean system message
64
+ */
65
+ static announce(message: string) {
66
+ console.log(chalk.bold.white(`\n✨ ${message}`));
67
+ }
68
+ }
@@ -63,13 +63,29 @@ function isDangerousCommand(command: string): boolean {
63
63
  return dangerousPatterns.some(pattern => pattern.test(command));
64
64
  }
65
65
 
66
+ /**
67
+ * Check if command is safe to auto-execute
68
+ */
69
+ export function isSafeAutoCommand(command: string): boolean {
70
+ const safePrefixes = ['cat ', 'ls ', 'grep ', 'find ', 'pwd', 'echo ', 'read '];
71
+ const trimmed = command.trim();
72
+ return safePrefixes.some(prefix => trimmed.startsWith(prefix));
73
+ }
74
+
66
75
  /**
67
76
  * Ask user for permission to execute command
68
77
  */
69
78
  export async function askPermission(command: CommandBlock): Promise<boolean> {
70
- // Clean Codex-style Prompt
71
- // > ls -R
79
+ // Clean Codex-style Prompt with Multi-Agent Iconography
72
80
  console.log();
81
+
82
+ // Check for Safe Auto-Execution
83
+ if (isSafeAutoCommand(command.code)) {
84
+ console.log(chalk.cyan('⚔ Auto-Executing Safe Command: ') + chalk.white(command.code));
85
+ return true;
86
+ }
87
+
88
+ console.log(chalk.yellow('šŸ›”ļø SyntaxGuard ') + chalk.white('Analysis:'));
73
89
  console.log(chalk.gray('> ') + chalk.white(command.code));
74
90
  console.log();
75
91
 
@@ -74,7 +74,7 @@ export class ConfigManager {
74
74
  * Get default model
75
75
  */
76
76
  getDefaultModel(): string {
77
- return this.loadConfig().defaultModel || 'matexcodex';
77
+ return this.loadConfig().defaultModel || 'matexcore';
78
78
  }
79
79
 
80
80
  /**
@@ -0,0 +1,156 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { AgentOrchestrator } from './agent-orchestrator';
4
+
5
+ export interface RepoNode {
6
+ path: string;
7
+ type: 'file' | 'directory';
8
+ children?: RepoNode[];
9
+ summary?: string; // e.g., "Class: AuthManager, Func: login"
10
+ }
11
+
12
+ export class RepoMapper {
13
+ private rootPath: string;
14
+ private ignoreList: string[] = [
15
+ '.git', 'node_modules', 'dist', 'build', '.next', '.DS_Store',
16
+ 'coverage', '.vercel', '.firebase', 'out', 'public'
17
+ ];
18
+
19
+ constructor(rootPath: string) {
20
+ this.rootPath = rootPath;
21
+ }
22
+
23
+ /**
24
+ * Generate a hierarchical map of the repository with deep entry-point analysis
25
+ */
26
+ public async generateMap(): Promise<string> {
27
+ AgentOrchestrator.speak('System', `God-Mode Research: Indexing ${this.rootPath}...`);
28
+
29
+ // 1. Identify Entry Points
30
+ const entryPoints = ['README.md', 'package.json', 'index.ts', 'App.tsx', 'main.go', 'requirements.txt'];
31
+ let entryPointContext = '\n--- CRITICAL PROJECT CONTEXT ---\n';
32
+
33
+ for (const file of entryPoints) {
34
+ const fullPath = path.join(this.rootPath, file);
35
+ if (fs.existsSync(fullPath)) {
36
+ const content = fs.readFileSync(fullPath, 'utf-8').slice(0, 5000); // 5KB limit for entry points
37
+ entryPointContext += `\nFILE: ${file}\n${content}\n----------------\n`;
38
+ }
39
+ }
40
+
41
+ const tree = this.scanDirectory(this.rootPath, 0);
42
+ return entryPointContext + '\n--- DIRECTORY STRUCTURE ---\n' + this.formatTree(tree);
43
+ }
44
+
45
+ /**
46
+ * Recursive directory scan
47
+ */
48
+ private scanDirectory(currentPath: string, depth: number): RepoNode {
49
+ const stats = fs.statSync(currentPath);
50
+ const name = path.basename(currentPath);
51
+
52
+ if (stats.isFile()) {
53
+ let summary = this.extractSummary(currentPath);
54
+
55
+ // Auto-read small files (< 10KB) for "Crawler" capability
56
+ if (stats.size < 10240) {
57
+ try {
58
+ const content = fs.readFileSync(currentPath, 'utf-8');
59
+ // Add content preview to summary
60
+ summary += `\n--- CONTENT START ---\n${content}\n--- CONTENT END ---`;
61
+ } catch (e) {
62
+ // Ignore read errors
63
+ }
64
+ }
65
+
66
+ return {
67
+ path: currentPath,
68
+ type: 'file',
69
+ summary: summary
70
+ };
71
+ }
72
+
73
+ // It's a directory
74
+ if (depth > 5) return { path: currentPath, type: 'directory', children: [] }; // Max depth safety
75
+
76
+ const children: RepoNode[] = [];
77
+ try {
78
+ const items = fs.readdirSync(currentPath);
79
+ for (const item of items) {
80
+ if (this.ignoreList.includes(item)) continue;
81
+
82
+ const fullPath = path.join(currentPath, item);
83
+ // Simple ignore check for hidden files
84
+ if (item.startsWith('.') && item !== '.gitignore') continue;
85
+
86
+ children.push(this.scanDirectory(fullPath, depth + 1));
87
+ }
88
+ } catch (error) {
89
+ // Permission denied or other error
90
+ }
91
+
92
+ return {
93
+ path: currentPath,
94
+ type: 'directory',
95
+ children: children
96
+ };
97
+ }
98
+
99
+ /**
100
+ * Extract key definitions (Classes, Functions) from file content
101
+ * A lightweight "ctags" style summary
102
+ */
103
+ private extractSummary(filePath: string): string {
104
+ const ext = path.extname(filePath);
105
+ if (!['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.rs'].includes(ext)) return '';
106
+
107
+ try {
108
+ const content = fs.readFileSync(filePath, 'utf-8');
109
+ const lines = content.split('\n');
110
+ const definitions: string[] = [];
111
+
112
+ // Very header-heavy regex matching for speed
113
+ for (const line of lines) {
114
+ const trimmed = line.trim();
115
+ if (trimmed.startsWith('export class ')) {
116
+ definitions.push(`Class: ${trimmed.split(' ')[2]}`);
117
+ } else if (trimmed.startsWith('function ') || trimmed.startsWith('export function ')) {
118
+ const funcName = trimmed.split('(')[0].split(' ').pop();
119
+ definitions.push(`Func: ${funcName}`);
120
+ } else if (trimmed.includes('const ') && trimmed.includes(' = (') && trimmed.includes('=>')) {
121
+ // Arrow functions
122
+ const parts = trimmed.split(' = ');
123
+ const name = parts[0].split(' ').pop();
124
+ if (name && /^[A-Z]/.test(name)) {
125
+ definitions.push(`Component: ${name}`); // React component guess
126
+ }
127
+ }
128
+ }
129
+
130
+ return definitions.slice(0, 5).join(', '); // Limit to top 5
131
+ } catch (e) {
132
+ return '';
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Format the tree into a compressed string for the LLM
138
+ */
139
+ private formatTree(node: RepoNode, indent: string = ''): string {
140
+ const name = path.basename(node.path);
141
+ let output = `${indent}${name}`;
142
+
143
+ if (node.type === 'file' && node.summary) {
144
+ output += ` [${node.summary}]`;
145
+ }
146
+ output += '\n';
147
+
148
+ if (node.children) {
149
+ for (const child of node.children) {
150
+ output += this.formatTree(child, indent + ' ');
151
+ }
152
+ }
153
+
154
+ return output;
155
+ }
156
+ }