lumina-code-agent 1.6.5 → 1.6.6
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/index.js +122 -93
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34,7 +34,6 @@ async function onboarding() {
|
|
|
34
34
|
saveConfig({ openrouterKey: apiKey.trim(), userName: name.trim() || 'User' });
|
|
35
35
|
console.log(' ✓ Ready!\n');
|
|
36
36
|
}
|
|
37
|
-
// ── Streaming chat with real-time file creation ─────────────────────
|
|
38
37
|
async function chat(config) {
|
|
39
38
|
console.log(' Type what you want to build. I\'ll handle the rest.');
|
|
40
39
|
console.log(' Commands: /help /clear /files /exit\n');
|
|
@@ -66,23 +65,47 @@ async function chat(config) {
|
|
|
66
65
|
console.log(' /help /clear /files /exit\n');
|
|
67
66
|
continue;
|
|
68
67
|
}
|
|
69
|
-
|
|
68
|
+
// Ultra-explicit system prompt
|
|
69
|
+
const systemPrompt = `You are LUMINA CODE. You MUST output files using this EXACT format. Do NOT describe what you will do. DO IT.
|
|
70
70
|
|
|
71
|
-
OUTPUT FORMAT —
|
|
71
|
+
OUTPUT THIS EXACT FORMAT — NO EXCEPTIONS:
|
|
72
72
|
|
|
73
|
-
FILENAME:
|
|
74
|
-
|
|
73
|
+
FILENAME: index.html
|
|
74
|
+
<!DOCTYPE html>
|
|
75
|
+
<html lang="en">
|
|
76
|
+
<head>
|
|
77
|
+
<meta charset="UTF-8">
|
|
78
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
79
|
+
<title>Page</title>
|
|
80
|
+
<style>
|
|
81
|
+
/* ALL CSS here */
|
|
82
|
+
</style>
|
|
83
|
+
</head>
|
|
84
|
+
<body>
|
|
85
|
+
<!-- ALL HTML here -->
|
|
86
|
+
<script>
|
|
87
|
+
// ALL JavaScript here
|
|
88
|
+
</script>
|
|
89
|
+
</body>
|
|
90
|
+
</html>
|
|
75
91
|
END FILE
|
|
76
92
|
|
|
77
|
-
|
|
78
|
-
|
|
93
|
+
FILENAME: style.css
|
|
94
|
+
/* ALL CSS */
|
|
95
|
+
END FILE
|
|
96
|
+
|
|
97
|
+
FILENAME: script.js
|
|
98
|
+
// ALL JavaScript
|
|
99
|
+
END FILE
|
|
79
100
|
|
|
80
101
|
RULES:
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
102
|
+
- Start IMMEDIATELY with FILENAME: index.html
|
|
103
|
+
- Output COMPLETE file contents — every single line
|
|
104
|
+
- Do NOT output any text before FILENAME:
|
|
105
|
+
- Do NOT describe what you will do
|
|
106
|
+
- Do NOT output markdown code blocks
|
|
107
|
+
- ONLY use FILENAME: ... END FILE format
|
|
108
|
+
- Create ALL files needed for a complete working project
|
|
86
109
|
|
|
87
110
|
Working directory: ${process.cwd()}`;
|
|
88
111
|
console.log(' ⏳ Generating...\n');
|
|
@@ -105,7 +128,7 @@ Working directory: ${process.cwd()}`;
|
|
|
105
128
|
],
|
|
106
129
|
stream: true,
|
|
107
130
|
max_tokens: 16000,
|
|
108
|
-
temperature: 0.
|
|
131
|
+
temperature: 0.1,
|
|
109
132
|
}),
|
|
110
133
|
signal: controller.signal,
|
|
111
134
|
});
|
|
@@ -114,7 +137,7 @@ Working directory: ${process.cwd()}`;
|
|
|
114
137
|
const err = await res.text().catch(() => '');
|
|
115
138
|
throw new Error(`API error ${res.status}: ${err.slice(0, 200)}`);
|
|
116
139
|
}
|
|
117
|
-
// Stream
|
|
140
|
+
// Stream and parse files in real-time
|
|
118
141
|
const reader = res.body.getReader();
|
|
119
142
|
const decoder = new TextDecoder();
|
|
120
143
|
let buffer = '';
|
|
@@ -122,110 +145,117 @@ Working directory: ${process.cwd()}`;
|
|
|
122
145
|
let currentContent = '';
|
|
123
146
|
let inFile = false;
|
|
124
147
|
let fileCount = 0;
|
|
148
|
+
let outputBuffer = '';
|
|
125
149
|
while (true) {
|
|
126
150
|
const { done, value } = await reader.read();
|
|
127
151
|
if (done)
|
|
128
152
|
break;
|
|
129
153
|
buffer += decoder.decode(value, { stream: true });
|
|
130
154
|
const lines = buffer.split('\n');
|
|
131
|
-
buffer = lines.pop();
|
|
155
|
+
buffer = lines.pop();
|
|
132
156
|
for (const line of lines) {
|
|
133
157
|
if (!line.startsWith('data: '))
|
|
134
158
|
continue;
|
|
135
159
|
const data = line.slice(6).trim();
|
|
136
160
|
if (data === '[DONE]')
|
|
137
161
|
continue;
|
|
162
|
+
let delta = '';
|
|
138
163
|
try {
|
|
139
164
|
const parsed = JSON.parse(data);
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
process.stdout.write(currentContent + char);
|
|
175
|
-
currentContent = '';
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
process.stdout.write(char);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
165
|
+
delta = parsed.choices?.[0]?.delta?.content || '';
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (!delta)
|
|
171
|
+
continue;
|
|
172
|
+
// Process delta for file detection
|
|
173
|
+
for (let i = 0; i < delta.length; i++) {
|
|
174
|
+
const char = delta[i];
|
|
175
|
+
if (!inFile) {
|
|
176
|
+
// Look for FILENAME:
|
|
177
|
+
outputBuffer += char;
|
|
178
|
+
if (outputBuffer.endsWith('FILENAME:')) {
|
|
179
|
+
// Found it! Extract filename on next line
|
|
180
|
+
currentFile = '';
|
|
181
|
+
inFile = true;
|
|
182
|
+
currentContent = '';
|
|
183
|
+
outputBuffer = '';
|
|
184
|
+
process.stdout.write(' 📄 ');
|
|
185
|
+
}
|
|
186
|
+
else if (outputBuffer.length > 20) {
|
|
187
|
+
// Not matching, flush
|
|
188
|
+
process.stdout.write(outputBuffer);
|
|
189
|
+
outputBuffer = '';
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
// In filename or content
|
|
194
|
+
if (char === '\n' && !currentFile.includes('/')) {
|
|
195
|
+
// Still in filename line (no path separator yet)
|
|
196
|
+
if (currentFile.length > 0 && !currentFile.includes('.')) {
|
|
197
|
+
// This is a path separator line, keep accumulating
|
|
198
|
+
currentFile += char;
|
|
182
199
|
}
|
|
183
200
|
else {
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
catch (e) {
|
|
209
|
-
console.log(` ✗ Error saving ${currentFile}: ${e.message}`);
|
|
210
|
-
}
|
|
211
|
-
currentFile = null;
|
|
212
|
-
currentContent = '';
|
|
213
|
-
inFile = false;
|
|
214
|
-
}
|
|
201
|
+
// End of filename
|
|
202
|
+
currentFile = currentFile.trim();
|
|
203
|
+
console.log(currentFile);
|
|
204
|
+
fileCount++;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else if (currentFile && !currentContent && char === '\n' && currentFile.includes('.')) {
|
|
208
|
+
// First newline after filename, start content
|
|
209
|
+
currentContent = '';
|
|
210
|
+
}
|
|
211
|
+
else if (currentContent !== null) {
|
|
212
|
+
currentContent += char;
|
|
213
|
+
// Check for END FILE
|
|
214
|
+
if (currentContent.endsWith('END FILE')) {
|
|
215
|
+
const fileContent = currentContent.slice(0, -8).trim();
|
|
216
|
+
try {
|
|
217
|
+
const filePath = join(process.cwd(), currentFile);
|
|
218
|
+
const dir = dirname(resolve(filePath));
|
|
219
|
+
if (!existsSync(dir))
|
|
220
|
+
mkdirSync(dir, { recursive: true });
|
|
221
|
+
writeFileSync(filePath, fileContent, 'utf-8');
|
|
222
|
+
createdFiles.add(currentFile);
|
|
223
|
+
console.log(` ✓ Saved: ${currentFile} (${fileContent.length} chars)`);
|
|
215
224
|
}
|
|
216
|
-
|
|
217
|
-
currentFile
|
|
225
|
+
catch (e) {
|
|
226
|
+
console.log(` ✗ Error: ${currentFile}: ${e.message}`);
|
|
218
227
|
}
|
|
228
|
+
currentFile = null;
|
|
229
|
+
currentContent = null;
|
|
230
|
+
inFile = false;
|
|
219
231
|
}
|
|
220
232
|
}
|
|
233
|
+
else {
|
|
234
|
+
currentFile += char;
|
|
235
|
+
}
|
|
221
236
|
}
|
|
222
237
|
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// Handle any remaining content
|
|
241
|
+
if (inFile && currentFile && currentContent) {
|
|
242
|
+
const fileContent = currentContent.replace(/END FILE$/, '').trim();
|
|
243
|
+
if (fileContent) {
|
|
244
|
+
try {
|
|
245
|
+
const filePath = join(process.cwd(), currentFile);
|
|
246
|
+
const dir = dirname(resolve(filePath));
|
|
247
|
+
if (!existsSync(dir))
|
|
248
|
+
mkdirSync(dir, { recursive: true });
|
|
249
|
+
writeFileSync(filePath, fileContent, 'utf-8');
|
|
250
|
+
createdFiles.add(currentFile);
|
|
251
|
+
console.log(` ✓ Saved: ${currentFile} (${fileContent.length} chars)`);
|
|
252
|
+
}
|
|
223
253
|
catch (e) {
|
|
224
|
-
|
|
254
|
+
console.log(` ✗ Error: ${currentFile}: ${e.message}`);
|
|
225
255
|
}
|
|
226
256
|
}
|
|
227
257
|
}
|
|
228
|
-
console.log(`\n 📊 Created ${fileCount} file(s)
|
|
258
|
+
console.log(`\n 📊 Created ${fileCount} file(s) | Total: ${createdFiles.size}`);
|
|
229
259
|
console.log('');
|
|
230
260
|
}
|
|
231
261
|
catch (e) {
|
|
@@ -234,7 +264,6 @@ Working directory: ${process.cwd()}`;
|
|
|
234
264
|
}
|
|
235
265
|
rl.close();
|
|
236
266
|
}
|
|
237
|
-
// ── Main ────────────────────────────────────────────────────────────
|
|
238
267
|
const config = loadConfig();
|
|
239
268
|
if (!config?.openrouterKey) {
|
|
240
269
|
onboarding().then(() => chat(loadConfig()).then(() => process.exit(0)));
|