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.
Files changed (2) hide show
  1. package/dist/index.js +122 -93
  2. 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
- const systemPrompt = `You are LUMINA CODE. Create COMPLETE production-grade websites.
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 — Use this exact format for every file:
71
+ OUTPUT THIS EXACT FORMAT — NO EXCEPTIONS:
72
72
 
73
- FILENAME: path/to/file.ext
74
- [COMPLETE file content — every line, no truncation]
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
- For commands:
78
- COMMAND: npm install something
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
- - Output COMPLETE files every single line
82
- - Use Three.js for 3D, CSS animations for motion
83
- - No placeholders, no TODOs, no lorem ipsum
84
- - Beautiful, cinematic, production-quality
85
- - Create ALL files needed for a working project
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.2,
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 the response and create files in real-time
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(); // Keep incomplete line
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
- const delta = parsed.choices?.[0]?.delta?.content;
141
- if (!delta)
142
- continue;
143
- // Process the delta character by character for file detection
144
- for (const char of delta) {
145
- if (!inFile) {
146
- // Check for FILENAME: pattern
147
- if (currentFile === null) {
148
- // Accumulate to check for FILENAME:
149
- if (!currentContent) {
150
- if (char === 'F')
151
- currentContent = 'F';
152
- else if (currentContent === 'F' && char === 'I')
153
- currentContent = 'FI';
154
- else if (currentContent === 'FI' && char === 'L')
155
- currentContent = 'FIL';
156
- else if (currentContent === 'FIL' && char === 'E')
157
- currentContent = 'FILE';
158
- else if (currentContent === 'FILE' && char === 'N')
159
- currentContent = 'FILEN';
160
- else if (currentContent === 'FILEN' && char === 'A')
161
- currentContent = 'FILENA';
162
- else if (currentContent === 'FILENA' && char === 'M')
163
- currentContent = 'FILENAM';
164
- else if (currentContent === 'FILENAM' && char === 'E')
165
- currentContent = 'FILENAME';
166
- else if (currentContent === 'FILENAME' && char === ':') {
167
- currentFile = '';
168
- currentContent = '';
169
- process.stdout.write(' 📄 Creating: ');
170
- }
171
- else {
172
- // Not a FILENAME: pattern, just output
173
- if (currentContent) {
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
- // We're inside a filename or file content
185
- if (char === '\n' && !inFile) {
186
- // End of filename line
187
- const filename = currentFile.trim();
188
- currentFile = filename;
189
- inFile = true;
190
- currentContent = '';
191
- console.log(` ✓ ${filename}`);
192
- fileCount++;
193
- }
194
- else if (inFile) {
195
- currentContent += char;
196
- // Check for END FILE
197
- if (currentContent.endsWith('END FILE')) {
198
- const fileContent = currentContent.slice(0, -8).trim();
199
- try {
200
- const filePath = join(process.cwd(), currentFile);
201
- const dir = dirname(resolve(filePath));
202
- if (!existsSync(dir))
203
- mkdirSync(dir, { recursive: true });
204
- writeFileSync(filePath, fileContent, 'utf-8');
205
- createdFiles.add(currentFile);
206
- console.log(` ✓ Saved: ${currentFile} (${fileContent.length} chars)`);
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
- else {
217
- currentFile += char;
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
- // Skip malformed JSON chunks
254
+ console.log(` ✗ Error: ${currentFile}: ${e.message}`);
225
255
  }
226
256
  }
227
257
  }
228
- console.log(`\n 📊 Created ${fileCount} file(s) total: ${createdFiles.size}`);
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)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lumina-code-agent",
3
- "version": "1.6.5",
3
+ "version": "1.6.6",
4
4
  "description": "Lumina Code - AI coding agent",
5
5
  "license": "MIT",
6
6
  "type": "module",