lumina-code-agent 1.6.6 → 1.6.7

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 +84 -140
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // @ts-nocheck
3
3
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
4
4
  import { homedir } from 'os';
5
- import { join, dirname, resolve } from 'path';
5
+ import { join, dirname, resolve, extname } from 'path';
6
6
  import { createInterface } from 'readline';
7
7
  const CONFIG_DIR = join(homedir(), '.lumina');
8
8
  const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
@@ -34,6 +34,38 @@ async function onboarding() {
34
34
  saveConfig({ openrouterKey: apiKey.trim(), userName: name.trim() || 'User' });
35
35
  console.log(' ✓ Ready!\n');
36
36
  }
37
+ // ── Extract files from complete model output ────────────────────────
38
+ function extractFiles(text) {
39
+ const files = [];
40
+ // Match FILENAME: path\n...content...END FILE
41
+ const fileRegex = /FILENAME:\s*([^\n]+)\n([\s\S]*?)END FILE/g;
42
+ let match;
43
+ while ((match = fileRegex.exec(text)) !== null) {
44
+ const rawPath = match[1].trim();
45
+ const content = match[2].trim();
46
+ // Skip if it's a directory path (no extension or ends with /)
47
+ if (!rawPath || rawPath.endsWith('/') || !extname(rawPath))
48
+ continue;
49
+ // Skip if path contains invalid chars
50
+ if (rawPath.includes('<') || rawPath.includes('>') || rawPath.includes('"'))
51
+ continue;
52
+ files.push({ path: rawPath, content });
53
+ }
54
+ // Also match ```filename ... ``` code blocks
55
+ const blockRegex = /```([\w./\-_]+)\n([\s\S]*?)```/g;
56
+ while ((match = blockRegex.exec(text)) !== null) {
57
+ const rawPath = match[1].trim();
58
+ const content = match[2].trim();
59
+ if (!rawPath || rawPath.endsWith('/') || !extname(rawPath))
60
+ continue;
61
+ // Skip common non-file patterns
62
+ if (rawPath.startsWith('http') || rawPath.includes('node_modules'))
63
+ continue;
64
+ files.push({ path: rawPath, content });
65
+ }
66
+ return files;
67
+ }
68
+ // ── Chat Loop ───────────────────────────────────────────────────────
37
69
  async function chat(config) {
38
70
  console.log(' Type what you want to build. I\'ll handle the rest.');
39
71
  console.log(' Commands: /help /clear /files /exit\n');
@@ -65,10 +97,9 @@ async function chat(config) {
65
97
  console.log(' /help /clear /files /exit\n');
66
98
  continue;
67
99
  }
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.
100
+ const systemPrompt = `You are LUMINA CODE. You create COMPLETE production-grade websites.
70
101
 
71
- OUTPUT THIS EXACT FORMAT — NO EXCEPTIONS:
102
+ MANDATORY OUTPUT FORMAT — You MUST use this for EVERY file:
72
103
 
73
104
  FILENAME: index.html
74
105
  <!DOCTYPE html>
@@ -76,36 +107,34 @@ FILENAME: index.html
76
107
  <head>
77
108
  <meta charset="UTF-8">
78
109
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
79
- <title>Page</title>
80
- <style>
81
- /* ALL CSS here */
82
- </style>
110
+ <title>Title</title>
111
+ <link rel="stylesheet" href="style.css">
83
112
  </head>
84
113
  <body>
85
- <!-- ALL HTML here -->
86
- <script>
87
- // ALL JavaScript here
88
- </script>
114
+ <!-- Complete HTML -->
115
+ <script src="script.js"></script>
89
116
  </body>
90
117
  </html>
91
118
  END FILE
92
119
 
93
120
  FILENAME: style.css
94
- /* ALL CSS */
121
+ /* Complete CSS */
95
122
  END FILE
96
123
 
97
124
  FILENAME: script.js
98
- // ALL JavaScript
125
+ // Complete JavaScript
99
126
  END FILE
100
127
 
101
- RULES:
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
128
+ CRITICAL RULES:
129
+ 1. ALWAYS start with FILENAME: index.html
130
+ 2. Output COMPLETE files — every line, no truncation
131
+ 3. Do NOT describe what you will do — JUST DO IT
132
+ 4. Do NOT output any text before FILENAME:
133
+ 5. Do NOT use markdown code blocks — ONLY FILENAME: ... END FILE
134
+ 6. Create ALL files needed for a complete working project
135
+ 7. Use Three.js from CDN: https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js
136
+ 8. Use modern CSS (grid, flexbox, custom properties)
137
+ 9. No placeholders, no TODOs, no lorem ipsum
109
138
 
110
139
  Working directory: ${process.cwd()}`;
111
140
  console.log(' ⏳ Generating...\n');
@@ -126,7 +155,7 @@ Working directory: ${process.cwd()}`;
126
155
  { role: 'system', content: systemPrompt },
127
156
  { role: 'user', content: trimmed },
128
157
  ],
129
- stream: true,
158
+ stream: false,
130
159
  max_tokens: 16000,
131
160
  temperature: 0.1,
132
161
  }),
@@ -137,126 +166,41 @@ Working directory: ${process.cwd()}`;
137
166
  const err = await res.text().catch(() => '');
138
167
  throw new Error(`API error ${res.status}: ${err.slice(0, 200)}`);
139
168
  }
140
- // Stream and parse files in real-time
141
- const reader = res.body.getReader();
142
- const decoder = new TextDecoder();
143
- let buffer = '';
144
- let currentFile = null;
145
- let currentContent = '';
146
- let inFile = false;
147
- let fileCount = 0;
148
- let outputBuffer = '';
149
- while (true) {
150
- const { done, value } = await reader.read();
151
- if (done)
152
- break;
153
- buffer += decoder.decode(value, { stream: true });
154
- const lines = buffer.split('\n');
155
- buffer = lines.pop();
156
- for (const line of lines) {
157
- if (!line.startsWith('data: '))
158
- continue;
159
- const data = line.slice(6).trim();
160
- if (data === '[DONE]')
161
- continue;
162
- let delta = '';
163
- try {
164
- const parsed = JSON.parse(data);
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;
199
- }
200
- else {
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)`);
224
- }
225
- catch (e) {
226
- console.log(` ✗ Error: ${currentFile}: ${e.message}`);
227
- }
228
- currentFile = null;
229
- currentContent = null;
230
- inFile = false;
231
- }
232
- }
233
- else {
234
- currentFile += char;
235
- }
236
- }
237
- }
238
- }
169
+ const data = await res.json();
170
+ const content = data.choices?.[0]?.message?.content || '';
171
+ if (!content) {
172
+ console.log(' ⚠ No response from model.\n');
173
+ continue;
174
+ }
175
+ // Show the raw output for debugging
176
+ console.log(' 📝 Model output preview:');
177
+ console.log(' ' + content.slice(0, 200).replace(/\n/g, '\n '));
178
+ console.log('');
179
+ // Extract and create files
180
+ const files = extractFiles(content);
181
+ if (files.length === 0) {
182
+ console.log(' ⚠ No files detected in output. The model may not have used FILENAME: format.');
183
+ console.log(' Here is the full output:\n');
184
+ console.log(content);
185
+ console.log('');
186
+ continue;
239
187
  }
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
- }
253
- catch (e) {
254
- console.log(` ✗ Error: ${currentFile}: ${e.message}`);
255
- }
188
+ console.log(` 📁 Creating ${files.length} file(s)...\n`);
189
+ for (const file of files) {
190
+ try {
191
+ const filePath = join(process.cwd(), file.path);
192
+ const dir = dirname(resolve(filePath));
193
+ if (!existsSync(dir))
194
+ mkdirSync(dir, { recursive: true });
195
+ writeFileSync(filePath, file.content, 'utf-8');
196
+ createdFiles.add(file.path);
197
+ console.log(` ✓ ${file.path} (${file.content.length} chars)`);
198
+ }
199
+ catch (e) {
200
+ console.log(` ✗ ${file.path}: ${e.message}`);
256
201
  }
257
202
  }
258
- console.log(`\n 📊 Created ${fileCount} file(s) | Total: ${createdFiles.size}`);
259
- console.log('');
203
+ console.log(`\n 📊 Total files: ${createdFiles.size}\n`);
260
204
  }
261
205
  catch (e) {
262
206
  console.log(` ⚠ Error: ${e.message}\n`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lumina-code-agent",
3
- "version": "1.6.6",
3
+ "version": "1.6.7",
4
4
  "description": "Lumina Code - AI coding agent",
5
5
  "license": "MIT",
6
6
  "type": "module",