matex-cli 1.2.15 → 1.2.17

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/dist/utils/tui.js CHANGED
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.TUI = void 0;
7
7
  const chalk_1 = __importDefault(require("chalk"));
8
+ const readline_1 = __importDefault(require("readline"));
8
9
  /**
9
10
  * TUI Management for MATEX CLI "God-Mode"
10
11
  * Handles screen buffers, persistent headers, and real-time status updates.
@@ -45,7 +46,7 @@ class TUI {
45
46
  static clear() {
46
47
  process.stdout.write('\x1b[2J\x1b[H');
47
48
  this.drawHeader();
48
- this.drawStatusBar(this.currentStatus);
49
+ this.drawStatusBar(this.currentStatus, true);
49
50
  }
50
51
  /**
51
52
  * Draw the persistent top header
@@ -56,28 +57,89 @@ class TUI {
56
57
  const padding = Math.max(0, Math.floor((width - banner.length) / 2));
57
58
  // Move to top
58
59
  process.stdout.write('\x1b[H');
59
- console.log(chalk_1.default.bgCyan.black(' '.repeat(padding) + banner + ' '.repeat(width - banner.length - padding)));
60
- console.log(chalk_1.default.gray('─'.repeat(width)));
60
+ process.stdout.write(chalk_1.default.bgCyan.black(' '.repeat(padding) + banner + ' '.repeat(width - banner.length - padding)) + '\n');
61
+ process.stdout.write(chalk_1.default.gray('─'.repeat(width)) + '\n');
62
+ }
63
+ /**
64
+ * Helper to draw a box with content
65
+ */
66
+ static drawBox(title, color, lines, icon = '📦') {
67
+ const width = Math.min(process.stdout.columns || 80, 100);
68
+ console.log();
69
+ const trafficLights = chalk_1.default.red('●') + ' ' + chalk_1.default.yellow('●') + ' ' + chalk_1.default.green('●');
70
+ const displayTitle = ` ${icon} ${title} `;
71
+ console.log(chalk_1.default.gray('┏' + '━'.repeat(width - 2) + '┓'));
72
+ console.log(chalk_1.default.gray('┃ ') + trafficLights + ' ' + color(displayTitle).padEnd(width - 4) + chalk_1.default.gray(' ┃'));
73
+ console.log(chalk_1.default.gray('┣' + '━'.repeat(width - 2) + '┫'));
74
+ lines.forEach(line => {
75
+ const formattedLine = line.substring(0, width - 6);
76
+ console.log(chalk_1.default.gray('┃ ') + chalk_1.default.white(formattedLine).padEnd(width - 4) + chalk_1.default.gray(' ┃'));
77
+ });
78
+ console.log(chalk_1.default.gray('┗' + '━'.repeat(width - 2) + '┛'));
79
+ console.log();
61
80
  }
62
81
  /**
63
82
  * Draw a real-time status bar at the bottom
64
83
  */
65
- static drawStatusBar(status) {
66
- this.currentStatus = status;
84
+ static drawStatusBar(status, force = false) {
67
85
  if (!this.isInitialized)
68
86
  return;
87
+ if (this.currentStatus === status && !force)
88
+ return;
89
+ this.currentStatus = status;
69
90
  const width = process.stdout.columns || 80;
70
91
  const height = process.stdout.rows || 24;
71
- // Save cursor position
92
+ // Save cursor position using ANSI
72
93
  process.stdout.write('\x1b[s');
73
- // Move to bottom line
74
- process.stdout.write(`\x1b[${height};1H`);
94
+ // Move to absolute bottom row
95
+ readline_1.default.cursorTo(process.stdout, 0, height - 1);
75
96
  const cleanStatus = status.substring(0, width - 10);
76
- const bar = ` [⚡] ${cleanStatus} `.padEnd(width);
77
- process.stdout.write(chalk_1.default.bgWhite.black(bar));
97
+ const barContent = ` [⚡] ${cleanStatus} `.padEnd(width);
98
+ process.stdout.write(chalk_1.default.bgWhite.black(barContent));
78
99
  // Restore cursor position
79
100
  process.stdout.write('\x1b[u');
80
101
  }
102
+ /**
103
+ * Draw a premium code container
104
+ */
105
+ static drawCodeContainer(title, lang, content) {
106
+ const lines = content.split('\n').filter(l => l.trim() || l === '');
107
+ this.drawBox(`${title} (${lang})`, chalk_1.default.cyan.bold, lines, '📝');
108
+ }
109
+ /**
110
+ * Draw a message box for agent dialogue
111
+ */
112
+ static drawMessageContainer(agent, message) {
113
+ const lines = this.wrapText(message, 90);
114
+ const colorMap = {
115
+ 'Ajay Vai': chalk_1.default.magenta.bold,
116
+ 'Sunil Dai': chalk_1.default.blue.bold,
117
+ 'Sandip Dai': chalk_1.default.hex('#FF69B4').bold,
118
+ 'Narayan Dai': chalk_1.default.green.bold
119
+ };
120
+ const color = colorMap[agent] || chalk_1.default.white.bold;
121
+ this.drawBox(agent, color, lines, '🗣️');
122
+ }
123
+ /**
124
+ * Wrap text to a specific width
125
+ */
126
+ static wrapText(text, width) {
127
+ const words = text.split(' ');
128
+ const lines = [];
129
+ let currentLine = '';
130
+ words.forEach(word => {
131
+ if ((currentLine + word).length < width) {
132
+ currentLine += (currentLine ? ' ' : '') + word;
133
+ }
134
+ else {
135
+ lines.push(currentLine);
136
+ currentLine = word;
137
+ }
138
+ });
139
+ if (currentLine)
140
+ lines.push(currentLine);
141
+ return lines;
142
+ }
81
143
  /**
82
144
  * Log content into the scrollable area
83
145
  */
@@ -86,8 +148,7 @@ class TUI {
86
148
  console.log(content);
87
149
  return;
88
150
  }
89
- // Since we are in an alternative buffer, standard console.log works
90
- // within the viewport between header and footer.
151
+ // Ensure we don't overwrite the status bar
91
152
  console.log(content);
92
153
  }
93
154
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tui.js","sourceRoot":"","sources":["../../src/utils/tui.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tui.js","sourceRoot":"","sources":["../../src/utils/tui.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matex-cli",
3
- "version": "1.2.15",
3
+ "version": "1.2.17",
4
4
  "description": "Official CLI tool for MATEX AI - Access powerful AI models from your terminal",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -56,28 +56,29 @@ Your primary goal is to provide PERFECT solutions for the user (your fellow brot
56
56
  2. **[Sunil Dai] (🧬)**: The Expert Architect. Vibe: Senior, wise, mentor. Focus: Backend logic, database, and clean scaleable code ("Leave it to me vai").
57
57
  3. **[Sandip Dai] (🎨)**: The Design Specialist. Vibe: Creative, aesthetic. Focus: UI, UX, CSS, and "WOW" effects ("I'll make it look premium brother").
58
58
  4. **[Narayan Dai] (🛡️)**: The Validator. Vibe: Precise, strict. Focus: Security, debugging, and import/export verification ("I've checked the code brother, it's solid").
59
- 5. **[Ajay Vai] (🏆)**: The Conclusion. Role: Final hand-off and success celebration.
60
59
 
61
- ### 💬 COLLABORATIVE "BRO-VIBE" PROTOCOL:
62
- - **CHAT BETWEEN YOURSELVES FIRST:** Before providing any code or commands, the brothers MUST have a short, energetic chat in the terminal.
63
- - **Example:** [Ajay Vai]: "Oii brothers, new project!" -> [Sunil Dai]: "I'll handle the architecture vai" -> [Sandip Dai]: "And I'll make the UI sexy brother!"
64
- - **NEPALI FLAVOR:** Use terms like "Vai," "Dai," "Oii brother," "Tapai," "Ekdam ramro" naturally.
60
+ ### 💬 BRO-VIBE PROTOCOL:
61
+ - **CHAT FIRST:** Before code, brothers MUST have a short, energetic chat.
62
+ - **AGENT TAGS:** Always prefix your dialogue with your name like: [Ajay Vai]: "...".
63
+ - **NEPALI FLAVOR:** Use "Vai," "Dai," "Tapai," "Ekdam ramro" naturally.
65
64
 
66
- ### ✂️ BREVITY AS POWER (SURGICAL PRECISION):
67
- - **NO FULL FILE DUMPS:** Never 'cat' a file to read it unless it's small (<10 lines). Use grep, head, or tail.
68
- - **NO CHAT REPETITION:** If you use a surgical Search/Replace block, do NOT repeat the code in your natural language response. Just summary of what was fixed.
69
- - **SURGICAL READING:** If a file is long, only summarize what you need. Avoid terminal flood at all costs.
65
+ ### 🛠️ FILE GENERATION & EDIT PROTOCOLS (CRITICAL):
66
+ 1. **NEW FILES:** Use the following tag for ALL new files:
67
+ <file path="path/to/filename.ext">
68
+ content here
69
+ </file>
70
70
 
71
- ### 🛠️ SURGICAL EDIT PROTOCOL (POWER-FULL):
72
- - **USE SEARCH/REPLACE BLOCKS** for all file modifications. This is faster and safer than full rewrites.
73
- - **FORMAT:**
71
+ 2. **SURGICAL EDITS (for existing files):**
74
72
  **path/to/file.ext**
75
73
  <<<< SEARCH
76
74
  exact lines to find
77
75
  ====
78
76
  new lines to replace with
79
77
  >>>> REPLACE
80
- - **RULES:** Search block must match the file EXACTLY (indentation, matching lines). Sunil and Sandip have full permission to use shell commands (POSIX/Win) for other tasks.
78
+
79
+ ### ✂️ BREVITY AS POWER:
80
+ - **NO FULL FILE DUMPS** unless specifically asked.
81
+ - **NO CHAT REPETITION** of code. Just summary.
81
82
 
82
83
  ### 🛠️ ENVIRONMENT CONTEXT:
83
84
  ${repoMap}`
@@ -121,88 +122,106 @@ ${repoMap}`
121
122
  while (loopCount < MAX_LOOPS) {
122
123
  loopCount++;
123
124
 
124
- if (loopCount > 1) {
125
- spinner.start('Analyzing result & Validating...');
126
- } else {
127
- spinner.start('Thinking...');
128
- }
129
-
130
125
  try {
126
+ if (loopCount > 1) {
127
+ spinner.start('Analyzing result & Validating...');
128
+ } else {
129
+ spinner.start('Thinking...');
130
+ }
131
+
131
132
  let fullResponse = '';
132
133
  let buffer = '';
133
134
  let hasStarted = false;
134
135
  let inCodeBlock = false;
135
- let lastRole: AgentRole = 'Commander';
136
+ let codeBuffer = '';
137
+ let codeLang = 'bash';
138
+ let activeAgent = 'Ajay Vai';
139
+ let messageBuffer = '';
136
140
 
137
141
  TUI.drawStatusBar('Swarm is processing...');
138
142
  await client.chatStream({
139
143
  messages,
140
- model: options.model, // Kept original model from options
141
- temperature: 0.3, // Kept original temperature
144
+ model: options.model,
145
+ temperature: 0.3,
142
146
  max_tokens: 8000,
143
147
  }, (chunk) => {
144
148
  if (!hasStarted) {
145
149
  spinner.stop();
146
150
  hasStarted = true;
151
+ console.log(); // Spacing
147
152
  }
148
153
 
149
154
  buffer += chunk;
150
- fullResponse += chunk; // Accumulate full response before parsing
155
+ fullResponse += chunk;
151
156
  const lines = buffer.split('\n');
152
157
  buffer = lines.pop() || '';
153
158
 
154
159
  for (const line of lines) {
155
- let content = line.trim();
156
- if (!content && !inCodeBlock) continue;
160
+ const trimmedLine = line.trim();
161
+
162
+ // 1. Agent Detection (Improved Regex for bolding)
163
+ const agentRegex = /\[\**\s*(Ajay Vai|Sunil Dai|Sandip Dai|Narayan Dai)\s*\**\]/;
164
+ const agentMatch = line.match(agentRegex);
157
165
 
158
- // 1. Agent Detection
159
- const agentMatch = line.match(/\[(Ajay Vai|Sunil Dai|Sandip Dai|Narayan Dai)\]/);
160
166
  if (agentMatch) {
161
- const tag = agentMatch[1];
162
- const role = tag === 'Ajay Vai' ? 'Commander' :
163
- tag === 'Sunil Dai' ? 'Backend' :
164
- tag === 'Sandip Dai' ? 'Frontend' : 'Syntax';
165
-
166
- const color = tag === 'Ajay Vai' ? chalk.magenta :
167
- tag === 'Sunil Dai' ? chalk.blue :
168
- tag === 'Sandip Dai' ? chalk.hex('#FF69B4') : // Hot Pink
167
+ activeAgent = agentMatch[1];
168
+ const color = activeAgent === 'Ajay Vai' ? chalk.magenta :
169
+ activeAgent === 'Sunil Dai' ? chalk.blue :
170
+ activeAgent === 'Sandip Dai' ? chalk.hex('#FF69B4') :
169
171
  chalk.green;
170
172
 
171
- if (tag !== lastRole || !hasStarted) {
172
- console.log(`\n${color.bold(`[${tag}]`)}`);
173
- lastRole = tag as AgentRole;
174
- }
175
- content = content.replace(`[${tag}]`, '').trim();
176
- if (!content) continue;
173
+ process.stdout.write(`\n ${color.bold(`${activeAgent}:`)} `);
174
+ messageBuffer += trimmedLine + ' ';
175
+ continue;
177
176
  }
178
177
 
179
178
  // 2. Code Block Detection
180
- if (content.startsWith('```')) {
181
- inCodeBlock = !inCodeBlock;
182
- if (inCodeBlock && options.execute) {
183
- console.log(chalk.gray('[Technical Block - Executing in Terminal...]'));
179
+ const codeBlockRegex = /```(\w*)/;
180
+ const codeMatch = line.match(codeBlockRegex);
181
+
182
+ if (codeMatch) {
183
+ if (inCodeBlock) {
184
+ inCodeBlock = false;
185
+ TUI.drawCodeContainer('Generated Block', codeLang, codeBuffer.trim());
186
+ codeBuffer = '';
187
+ process.stdout.write('\n'); // Space after box
188
+ } else {
189
+ inCodeBlock = true;
190
+ codeLang = codeMatch[1] || 'bash';
191
+ process.stdout.write(chalk.gray('\n [⚡] Building code block...\n'));
184
192
  }
185
193
  continue;
186
194
  }
187
195
 
188
- // 3. Output logic
196
+ // 3. Content Handling
189
197
  if (inCodeBlock) {
190
- if (!options.execute) {
191
- console.log(chalk.blue(line));
198
+ codeBuffer += line + '\n';
199
+ } else if (trimmedLine) {
200
+ // Strip markdown artifacts for a cleaner stream
201
+ const cleanText = trimmedLine
202
+ .replace(/\*\*%?\*/g, '')
203
+ .replace(/#{1,6}\s/g, '')
204
+ .replace(/\*\*:\*\*/g, ':')
205
+ .trim();
206
+
207
+ if (cleanText) {
208
+ process.stdout.write(chalk.gray(cleanText + ' '));
209
+ messageBuffer += cleanText + ' ';
192
210
  }
193
- } else {
194
- console.log(chalk.gray(content));
195
211
  }
196
212
  }
197
213
  });
198
214
 
199
215
  spinner.stop();
200
216
 
201
- // Final flush
202
- if (buffer.trim() && !inCodeBlock) {
203
- console.log(chalk.gray(buffer.trim()));
217
+ // Final Code Flush if still in block
218
+ if (inCodeBlock && codeBuffer.trim()) {
219
+ TUI.drawCodeContainer('Generated Block', codeLang, codeBuffer.trim());
204
220
  }
205
221
 
222
+ // Space before commands/prompt
223
+ console.log('\n');
224
+
206
225
  // Add assistant response to history
207
226
  messages.push({ role: 'assistant', content: fullResponse });
208
227
  const response = fullResponse;
@@ -215,14 +234,14 @@ ${repoMap}`
215
234
 
216
235
  if (result.executed) {
217
236
  if (result.success) {
218
- console.log(chalk.gray('↺ Feeding output to AI...'));
237
+ TUI.log(chalk.gray('↺ Feeding output to AI...'));
219
238
  messages.push({
220
239
  role: 'user',
221
240
  content: `✅ Command executed successfully. Output:\n${result.output}\n\nProceed to the next step.`
222
241
  });
223
242
  continue;
224
243
  } else {
225
- console.log(chalk.yellow('\n↺ Command failed. Asking AI to fix...'));
244
+ TUI.log(chalk.yellow('\n↺ Command failed. Asking AI to fix...'));
226
245
  messages.push({
227
246
  role: 'user',
228
247
  content: `❌ Command failed with error:\n${result.error}\n\nPlease fix this. If the file doesn't exist, create it first. Or use a different command.`
@@ -237,13 +256,14 @@ ${repoMap}`
237
256
  }
238
257
  } catch (error: any) {
239
258
  spinner.fail('Request failed');
240
- console.error(chalk.red(`Error: ${error.message}\n`));
259
+ TUI.log(chalk.red(`Error: ${error.message}\n`));
241
260
  messages.pop();
242
261
  break;
243
262
  }
244
- }
245
- }
263
+ } // end while (loopCount)
264
+ } // end while (true)
246
265
  } catch (error: any) {
266
+ TUI.exit(); // Restore terminal state on fatal error
247
267
  console.error(chalk.red(`\n❌ Error: ${error.message}`));
248
268
  process.exit(1);
249
269
  }
@@ -159,12 +159,50 @@ export interface ExecutionResult {
159
159
  export async function executeWithPermission(response: string): Promise<ExecutionResult> {
160
160
  const commands = extractCommands(response);
161
161
  const patches = Patcher.parseEditBlocks(response);
162
+ const files = Patcher.parseFileBlocks(response);
162
163
 
163
- if (commands.length === 0 && patches.length === 0) {
164
+ if (commands.length === 0 && patches.length === 0 && files.length === 0) {
164
165
  return { success: true, executed: false };
165
166
  }
166
167
 
167
- // 1. Handle Shell Commands
168
+ // 1. Handle New File Creation
169
+ for (const file of files) {
170
+ let showFull = false;
171
+ let decided = false;
172
+
173
+ while (!decided) {
174
+ const isTruncated = Patcher.showDiff(file, showFull);
175
+
176
+ const choices = [
177
+ { name: '✅ Create this new file brother', value: 'create' },
178
+ { name: '⏭️ Skip', value: 'skip' }
179
+ ];
180
+
181
+ if (isTruncated && !showFull) {
182
+ choices.splice(1, 0, { name: '🔍 View Full Code', value: 'full' });
183
+ }
184
+
185
+ const { action } = await inquirer.prompt([{
186
+ type: 'list',
187
+ name: 'action',
188
+ message: chalk.cyan(`Create ${file.filePath}?`),
189
+ choices: choices
190
+ }]);
191
+
192
+ if (action === 'full') {
193
+ showFull = true;
194
+ continue;
195
+ }
196
+
197
+ if (action === 'create') {
198
+ const result = Patcher.createFile(file);
199
+ if (!result.success) return { success: false, executed: true, error: result.error };
200
+ }
201
+ decided = true;
202
+ }
203
+ }
204
+
205
+ // 2. Handle Shell Commands
168
206
  for (let i = 0; i < commands.length; i++) {
169
207
  const command = commands[i];
170
208
  const shouldExecute = await askPermission(command);
@@ -184,7 +222,7 @@ export async function executeWithPermission(response: string): Promise<Execution
184
222
  }
185
223
  }
186
224
 
187
- // 2. Handle Surgical Patches (Smarter & Faster than full rewrites)
225
+ // 3. Handle Surgical Patches
188
226
  for (const patch of patches) {
189
227
  let showFull = false;
190
228
  let decided = false;
@@ -194,7 +232,7 @@ export async function executeWithPermission(response: string): Promise<Execution
194
232
 
195
233
  const choices = [
196
234
  { name: '✅ Apply this surgical patch brother', value: 'apply' },
197
- { name: '⏭️ Skip this one', value: 'skip' }
235
+ { name: '⏭️ Skip', value: 'skip' }
198
236
  ];
199
237
 
200
238
  if (isTruncated && !showFull) {
@@ -204,13 +242,12 @@ export async function executeWithPermission(response: string): Promise<Execution
204
242
  const { action } = await inquirer.prompt([{
205
243
  type: 'list',
206
244
  name: 'action',
207
- message: chalk.cyan(`What should we do with ${patch.filePath}?`),
245
+ message: chalk.cyan(`Patch ${patch.filePath}?`),
208
246
  choices: choices
209
247
  }]);
210
248
 
211
249
  if (action === 'full') {
212
250
  showFull = true;
213
- // Loop will repeat and show full diff
214
251
  continue;
215
252
  }
216
253
 
@@ -22,7 +22,6 @@ export class Patcher {
22
22
  */
23
23
  static parseEditBlocks(response: string): EditBlock[] {
24
24
  const blocks: EditBlock[] = [];
25
- // Match filename followed by search/replace block
26
25
  const blockRegex = /\*\*([^*]+)\*\*\s*<<<< SEARCH\n([\s\S]*?)\n====\n([\s\S]*?)\n>>>> REPLACE/g;
27
26
 
28
27
  let match;
@@ -37,6 +36,52 @@ export class Patcher {
37
36
  return blocks;
38
37
  }
39
38
 
39
+ /**
40
+ * Parse file creation blocks from AI response
41
+ * Format:
42
+ * <file path="path/to/file.ext">
43
+ * content
44
+ * </file>
45
+ */
46
+ static parseFileBlocks(response: string): EditBlock[] {
47
+ const blocks: EditBlock[] = [];
48
+ const fileRegex = /<file path="([^"]+)">([\s\S]*?)<\/file>/g;
49
+
50
+ let match;
51
+ while ((match = fileRegex.exec(response)) !== null) {
52
+ blocks.push({
53
+ filePath: match[1].trim(),
54
+ search: '', // Not used for new files
55
+ replace: match[2]
56
+ });
57
+ }
58
+
59
+ return blocks;
60
+ }
61
+
62
+ /**
63
+ * Create a new file (and its directories)
64
+ */
65
+ static createFile(block: EditBlock): { success: boolean; error?: string } {
66
+ TUI.drawStatusBar(`Creating File: ${block.filePath}...`);
67
+ try {
68
+ const fullPath = path.resolve(process.cwd(), block.filePath);
69
+ const dir = path.dirname(fullPath);
70
+
71
+ if (!fs.existsSync(dir)) {
72
+ fs.mkdirSync(dir, { recursive: true });
73
+ }
74
+
75
+ fs.writeFileSync(fullPath, block.replace, 'utf8');
76
+
77
+ TUI.drawStatusBar(`✅ Success: ${block.filePath} created.`);
78
+ return { success: true };
79
+ } catch (err: any) {
80
+ TUI.drawStatusBar(`❌ Error: ${err.message}`);
81
+ return { success: false, error: err.message };
82
+ }
83
+ }
84
+
40
85
  /**
41
86
  * Apply a surgical patch to a file
42
87
  */
@@ -55,7 +100,7 @@ export class Patcher {
55
100
  // Normalize and trim for better matching robustness
56
101
  const normalizedContent = content.replace(/\r\n/g, '\n');
57
102
  const normalizedSearch = block.search.replace(/\r\n/g, '\n').trim();
58
- const normalizedReplace = block.replace.replace(/\r\n/g, '\n').trim();
103
+ const normalizedReplace = block.replace.replace(/\r\n/g, '\n');
59
104
 
60
105
  if (!normalizedContent.includes(normalizedSearch)) {
61
106
  // Try a fuzzy match by trimming internal lines as well
@@ -69,11 +114,9 @@ export class Patcher {
69
114
  error: `Search block not found in ${block.filePath}. Please ensure the code snippet matches exactly (ignoring trailing whitespace).`
70
115
  };
71
116
  }
72
-
73
- // If fuzzy match worked, we can still try to replace but it's riskier.
74
- // For now, let's stick to strict-ish matching but with trimmed ends.
75
117
  }
76
118
 
119
+ // Perform replacement on normalized content
77
120
  const updatedContent = normalizedContent.replace(normalizedSearch, normalizedReplace);
78
121
  fs.writeFileSync(fullPath, updatedContent, 'utf8');
79
122
 
@@ -90,10 +133,11 @@ export class Patcher {
90
133
  */
91
134
  static showDiff(block: EditBlock, full: boolean = false): boolean {
92
135
  const width = Math.min(process.stdout.columns || 80, 100);
93
- const searchLines = block.search.split('\n');
136
+ const searchLines = (block.search || '').split('\n');
94
137
  const replaceLines = block.replace.split('\n');
95
138
 
96
- const isLarge = searchLines.length > 8 || replaceLines.length > 8;
139
+ const isNewFile = !block.search;
140
+ const isLarge = replaceLines.length > 8;
97
141
  const shouldTruncate = isLarge && !full;
98
142
 
99
143
  const displaySearch = shouldTruncate ? searchLines.slice(0, 5) : searchLines;
@@ -102,30 +146,32 @@ export class Patcher {
102
146
  process.stdout.write('\n');
103
147
 
104
148
  // 1. Title Bar with Traffic Lights
105
- const title = ` 📂 ${block.filePath} `;
149
+ const type = isNewFile ? '🆕 NEW FILE' : '📂 PATCH';
150
+ const title = ` ${type}: ${block.filePath} `;
106
151
  const trafficLights = chalk.red('●') + ' ' + chalk.yellow('●') + ' ' + chalk.green('●');
107
- const remainingWidth = width - 12 - title.length;
108
152
 
109
153
  console.log(chalk.gray('┏' + '━'.repeat(width - 2) + '┓'));
110
- console.log(chalk.gray('┃ ') + trafficLights + chalk.cyan.bold(title).padEnd(width - 10) + chalk.gray(' ┃'));
154
+ console.log(chalk.gray('┃ ') + trafficLights + ' ' + chalk.cyan.bold(title).padEnd(width - 10) + chalk.gray(' ┃'));
111
155
  console.log(chalk.gray('┣' + '━'.repeat(width - 2) + '┫'));
112
156
 
113
- // 2. Search Block (Deletions)
114
- displaySearch.forEach((line, idx) => {
115
- const prefix = chalk.red('┃ ') + chalk.bgRed.white(' - ') + ' ';
116
- const content = chalk.red(line.substring(0, width - 10));
117
- console.log(prefix + content.padEnd(width - 8) + chalk.gray(' ┃'));
118
- });
157
+ // 2. Search Block (Deletions) - Only for patches
158
+ if (!isNewFile) {
159
+ displaySearch.forEach((line) => {
160
+ const prefix = chalk.red('┃ ') + chalk.bgRed.white(' - ') + ' ';
161
+ const content = chalk.red(line.substring(0, width - 10));
162
+ console.log(prefix + content.padEnd(width - 8) + chalk.gray(' ┃'));
163
+ });
119
164
 
120
- if (shouldTruncate && searchLines.length > 5) {
121
- console.log(chalk.red('┃ ') + chalk.gray(` ... (${searchLines.length - 5} more lines hidden)`).padEnd(width - 5) + chalk.gray(' ┃'));
122
- }
165
+ if (shouldTruncate && searchLines.length > 5) {
166
+ console.log(chalk.red('┃ ') + chalk.gray(` ... (${searchLines.length - 5} more lines hidden)`).padEnd(width - 5) + chalk.gray(' ┃'));
167
+ }
123
168
 
124
- // 3. Separator
125
- console.log(chalk.gray('┣' + '╍'.repeat(width - 2) + '┫'));
169
+ // Separator between search and replace
170
+ console.log(chalk.gray('┣' + '╍'.repeat(width - 2) + '┫'));
171
+ }
126
172
 
127
- // 4. Replace Block (Additions)
128
- displayReplace.forEach((line, idx) => {
173
+ // 3. Replace Block (Additions)
174
+ displayReplace.forEach((line) => {
129
175
  const prefix = chalk.green('┃ ') + chalk.bgGreen.black(' + ') + ' ';
130
176
  const content = chalk.green(line.substring(0, width - 10));
131
177
  console.log(prefix + content.padEnd(width - 8) + chalk.gray(' ┃'));
@@ -135,7 +181,7 @@ export class Patcher {
135
181
  console.log(chalk.green('┃ ') + chalk.gray(` ... (${replaceLines.length - 5} more lines hidden)`).padEnd(width - 5) + chalk.gray(' ┃'));
136
182
  }
137
183
 
138
- // 5. Footer
184
+ // 4. Footer
139
185
  console.log(chalk.gray('┗' + '━'.repeat(width - 2) + '┛'));
140
186
 
141
187
  if (shouldTruncate) {