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/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +76 -60
- package/dist/commands/dev.js.map +1 -1
- package/dist/utils/command-executor.d.ts.map +1 -1
- package/dist/utils/command-executor.js +37 -6
- package/dist/utils/command-executor.js.map +1 -1
- package/dist/utils/patcher.d.ts +15 -0
- package/dist/utils/patcher.d.ts.map +1 -1
- package/dist/utils/patcher.js +63 -22
- package/dist/utils/patcher.js.map +1 -1
- package/dist/utils/tui.d.ts +17 -1
- package/dist/utils/tui.d.ts.map +1 -1
- package/dist/utils/tui.js +73 -12
- package/dist/utils/tui.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/dev.ts +78 -58
- package/src/utils/command-executor.ts +43 -6
- package/src/utils/patcher.ts +70 -24
- package/src/utils/tui.ts +78 -13
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
|
-
|
|
60
|
-
|
|
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
|
|
74
|
-
process.stdout
|
|
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
|
|
77
|
-
process.stdout.write(chalk_1.default.bgWhite.black(
|
|
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
|
-
//
|
|
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
|
}
|
package/dist/utils/tui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.js","sourceRoot":"","sources":["../../src/utils/tui.ts"],"names":[],"mappings":";;;;;;AAAA,kDAA0B;
|
|
1
|
+
{"version":3,"file":"tui.js","sourceRoot":"","sources":["../../src/utils/tui.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/commands/dev.ts
CHANGED
|
@@ -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
|
-
### 💬
|
|
62
|
-
- **CHAT
|
|
63
|
-
- **
|
|
64
|
-
- **NEPALI FLAVOR:** Use
|
|
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
|
-
###
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
141
|
-
temperature: 0.3,
|
|
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;
|
|
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
|
-
|
|
156
|
-
|
|
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
|
-
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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.
|
|
196
|
+
// 3. Content Handling
|
|
189
197
|
if (inCodeBlock) {
|
|
190
|
-
|
|
191
|
-
|
|
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
|
|
202
|
-
if (
|
|
203
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
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
|
|
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(`
|
|
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
|
|
package/src/utils/patcher.ts
CHANGED
|
@@ -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')
|
|
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
|
|
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
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
121
|
-
|
|
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
|
-
|
|
125
|
-
|
|
169
|
+
// Separator between search and replace
|
|
170
|
+
console.log(chalk.gray('┣' + '╍'.repeat(width - 2) + '┫'));
|
|
171
|
+
}
|
|
126
172
|
|
|
127
|
-
//
|
|
128
|
-
displayReplace.forEach((line
|
|
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
|
-
//
|
|
184
|
+
// 4. Footer
|
|
139
185
|
console.log(chalk.gray('┗' + '━'.repeat(width - 2) + '┛'));
|
|
140
186
|
|
|
141
187
|
if (shouldTruncate) {
|