matex-cli 1.2.9 → 1.2.11

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,99 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import { TUI } from './tui';
5
+
6
+ export interface EditBlock {
7
+ filePath: string;
8
+ search: string;
9
+ replace: string;
10
+ }
11
+
12
+ export class Patcher {
13
+ /**
14
+ * Parse surgical edit blocks from AI response
15
+ * Format:
16
+ * **filename**
17
+ * <<<< SEARCH
18
+ * content
19
+ * ====
20
+ * replacement
21
+ * >>>> REPLACE
22
+ */
23
+ static parseEditBlocks(response: string): EditBlock[] {
24
+ const blocks: EditBlock[] = [];
25
+ // Match filename followed by search/replace block
26
+ const blockRegex = /\*\*([^*]+)\*\*\s*<<<< SEARCH\n([\s\S]*?)\n====\n([\s\S]*?)\n>>>> REPLACE/g;
27
+
28
+ let match;
29
+ while ((match = blockRegex.exec(response)) !== null) {
30
+ blocks.push({
31
+ filePath: match[1].trim(),
32
+ search: match[2],
33
+ replace: match[3]
34
+ });
35
+ }
36
+
37
+ return blocks;
38
+ }
39
+
40
+ /**
41
+ * Apply a surgical patch to a file
42
+ */
43
+ static applyPatch(block: EditBlock): { success: boolean; error?: string } {
44
+ TUI.drawStatusBar(`Applying Patch: ${block.filePath}...`);
45
+ try {
46
+ const fullPath = path.resolve(process.cwd(), block.filePath);
47
+
48
+ if (!fs.existsSync(fullPath)) {
49
+ TUI.drawStatusBar(`Error: File not found: ${block.filePath}`);
50
+ return { success: false, error: `File not found: ${block.filePath}` };
51
+ }
52
+
53
+ const content = fs.readFileSync(fullPath, 'utf8');
54
+
55
+ // Normalize line endings for comparison
56
+ const normalizedContent = content.replace(/\r\n/g, '\n');
57
+ const normalizedSearch = block.search.replace(/\r\n/g, '\n');
58
+
59
+ if (!normalizedContent.includes(normalizedSearch)) {
60
+ TUI.drawStatusBar(`Error: Search block not found in ${block.filePath}.`);
61
+ return {
62
+ success: false,
63
+ error: `Search block not found in ${block.filePath}.`
64
+ };
65
+ }
66
+
67
+ const updatedContent = normalizedContent.replace(normalizedSearch, block.replace.replace(/\r\n/g, '\n'));
68
+ fs.writeFileSync(fullPath, updatedContent, 'utf8');
69
+
70
+ TUI.drawStatusBar(`Success: ${block.filePath} patched.`);
71
+ return { success: true };
72
+ } catch (err: any) {
73
+ TUI.drawStatusBar(`Error applying patch to ${block.filePath}: ${err.message}`);
74
+ return { success: false, error: err.message };
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Visualize the diff in a premium "Bro" style
80
+ */
81
+ static showDiff(block: EditBlock) {
82
+ process.stdout.write('\n');
83
+ console.log(chalk.bgCyan.black(` 💎 PROPOSED SURGICAL EDIT: ${block.filePath} `));
84
+ console.log(chalk.cyan('╒' + '═'.repeat(70) + '╕'));
85
+
86
+ const searchLines = block.search.split('\n');
87
+ const replaceLines = block.replace.split('\n');
88
+
89
+ searchLines.forEach(line => {
90
+ console.log(chalk.red('│ - ') + chalk.red(line));
91
+ });
92
+ console.log(chalk.gray('╞' + '┄'.repeat(70) + '╡'));
93
+ replaceLines.forEach(line => {
94
+ console.log(chalk.green('│ + ') + chalk.green(line));
95
+ });
96
+ console.log(chalk.cyan('╘' + '═'.repeat(70) + '╛'));
97
+ console.log();
98
+ }
99
+ }
@@ -0,0 +1,108 @@
1
+ import chalk from 'chalk';
2
+ import readline from 'readline';
3
+
4
+ /**
5
+ * TUI Management for MATEX CLI "God-Mode"
6
+ * Handles screen buffers, persistent headers, and real-time status updates.
7
+ */
8
+ export class TUI {
9
+ private static isInitialized = false;
10
+ private static currentStatus = '';
11
+
12
+ /**
13
+ * Initialize the TUI Mode
14
+ */
15
+ static init() {
16
+ if (this.isInitialized) return;
17
+
18
+ // Enter alternative screen buffer
19
+ process.stdout.write('\x1b[?1049h');
20
+
21
+ // Hide cursor
22
+ process.stdout.write('\x1b[?25l');
23
+
24
+ this.clear();
25
+ this.isInitialized = true;
26
+
27
+ // Ensure clean exit
28
+ process.on('SIGINT', () => this.exit());
29
+ process.on('exit', () => this.exit());
30
+ }
31
+
32
+ /**
33
+ * Restore Terminal to normal state
34
+ */
35
+ static exit() {
36
+ if (!this.isInitialized) return;
37
+
38
+ // Show cursor
39
+ process.stdout.write('\x1b[?25h');
40
+
41
+ // Exit alternative screen buffer
42
+ process.stdout.write('\x1b[?1049l');
43
+
44
+ this.isInitialized = false;
45
+ process.exit();
46
+ }
47
+
48
+ /**
49
+ * Clear the main viewport
50
+ */
51
+ static clear() {
52
+ process.stdout.write('\x1b[2J\x1b[H');
53
+ this.drawHeader();
54
+ this.drawStatusBar(this.currentStatus);
55
+ }
56
+
57
+ /**
58
+ * Draw the persistent top header
59
+ */
60
+ static drawHeader() {
61
+ const width = process.stdout.columns || 80;
62
+ const banner = ` MATEX AI :: GOD-MODE DASHBOARD `;
63
+ const padding = Math.max(0, Math.floor((width - banner.length) / 2));
64
+
65
+ // Move to top
66
+ process.stdout.write('\x1b[H');
67
+ console.log(chalk.bgCyan.black(' '.repeat(padding) + banner + ' '.repeat(width - banner.length - padding)));
68
+ console.log(chalk.gray('─'.repeat(width)));
69
+ }
70
+
71
+ /**
72
+ * Draw a real-time status bar at the bottom
73
+ */
74
+ static drawStatusBar(status: string) {
75
+ this.currentStatus = status;
76
+ if (!this.isInitialized) return;
77
+
78
+ const width = process.stdout.columns || 80;
79
+ const height = process.stdout.rows || 24;
80
+
81
+ // Save cursor position
82
+ process.stdout.write('\x1b[s');
83
+
84
+ // Move to bottom line
85
+ process.stdout.write(`\x1b[${height};1H`);
86
+
87
+ const cleanStatus = status.substring(0, width - 10);
88
+ const bar = ` [⚡] ${cleanStatus} `.padEnd(width);
89
+ process.stdout.write(chalk.bgWhite.black(bar));
90
+
91
+ // Restore cursor position
92
+ process.stdout.write('\x1b[u');
93
+ }
94
+
95
+ /**
96
+ * Log content into the scrollable area
97
+ */
98
+ static log(content: string) {
99
+ if (!this.isInitialized) {
100
+ console.log(content);
101
+ return;
102
+ }
103
+
104
+ // Since we are in an alternative buffer, standard console.log works
105
+ // within the viewport between header and footer.
106
+ console.log(content);
107
+ }
108
+ }