lumina-code-agent 1.6.6 → 1.6.8
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 +67 -134
- 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,21 @@ async function onboarding() {
|
|
|
34
34
|
saveConfig({ openrouterKey: apiKey.trim(), userName: name.trim() || 'User' });
|
|
35
35
|
console.log(' ✓ Ready!\n');
|
|
36
36
|
}
|
|
37
|
+
function extractFiles(text) {
|
|
38
|
+
const files = [];
|
|
39
|
+
const fileRegex = /FILENAME:\s*([^\n]+)\n([\s\S]*?)END FILE/g;
|
|
40
|
+
let match;
|
|
41
|
+
while ((match = fileRegex.exec(text)) !== null) {
|
|
42
|
+
const rawPath = match[1].trim();
|
|
43
|
+
const content = match[2].trim();
|
|
44
|
+
if (!rawPath || rawPath.endsWith('/') || !extname(rawPath))
|
|
45
|
+
continue;
|
|
46
|
+
if (rawPath.includes('<') || rawPath.includes('>') || rawPath.includes('"'))
|
|
47
|
+
continue;
|
|
48
|
+
files.push({ path: rawPath, content });
|
|
49
|
+
}
|
|
50
|
+
return files;
|
|
51
|
+
}
|
|
37
52
|
async function chat(config) {
|
|
38
53
|
console.log(' Type what you want to build. I\'ll handle the rest.');
|
|
39
54
|
console.log(' Commands: /help /clear /files /exit\n');
|
|
@@ -65,10 +80,9 @@ async function chat(config) {
|
|
|
65
80
|
console.log(' /help /clear /files /exit\n');
|
|
66
81
|
continue;
|
|
67
82
|
}
|
|
68
|
-
|
|
69
|
-
const systemPrompt = `You are LUMINA CODE. You MUST output files using this EXACT format. Do NOT describe what you will do. DO IT.
|
|
83
|
+
const systemPrompt = `You are LUMINA CODE. Create COMPLETE production-grade websites.
|
|
70
84
|
|
|
71
|
-
OUTPUT
|
|
85
|
+
OUTPUT FORMAT — Use this EXACT format for EVERY file:
|
|
72
86
|
|
|
73
87
|
FILENAME: index.html
|
|
74
88
|
<!DOCTYPE html>
|
|
@@ -76,39 +90,38 @@ FILENAME: index.html
|
|
|
76
90
|
<head>
|
|
77
91
|
<meta charset="UTF-8">
|
|
78
92
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
79
|
-
<title>
|
|
80
|
-
<style>
|
|
81
|
-
/* ALL CSS here */
|
|
82
|
-
</style>
|
|
93
|
+
<title>Title</title>
|
|
94
|
+
<link rel="stylesheet" href="style.css">
|
|
83
95
|
</head>
|
|
84
96
|
<body>
|
|
85
|
-
<!--
|
|
86
|
-
<script>
|
|
87
|
-
|
|
88
|
-
</script>
|
|
97
|
+
<!-- Complete HTML here -->
|
|
98
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
|
99
|
+
<script src="script.js"></script>
|
|
89
100
|
</body>
|
|
90
101
|
</html>
|
|
91
102
|
END FILE
|
|
92
103
|
|
|
93
104
|
FILENAME: style.css
|
|
94
|
-
/*
|
|
105
|
+
/* Complete CSS here */
|
|
95
106
|
END FILE
|
|
96
107
|
|
|
97
108
|
FILENAME: script.js
|
|
98
|
-
//
|
|
109
|
+
// Complete JavaScript here
|
|
99
110
|
END FILE
|
|
100
111
|
|
|
101
112
|
RULES:
|
|
102
113
|
- Start IMMEDIATELY with FILENAME: index.html
|
|
103
|
-
- Output COMPLETE
|
|
114
|
+
- Output COMPLETE files — every line, no truncation
|
|
115
|
+
- Do NOT describe what you will do — JUST DO IT
|
|
104
116
|
- Do NOT output any text before FILENAME:
|
|
105
|
-
- Do NOT
|
|
106
|
-
- Do NOT output markdown code blocks
|
|
107
|
-
- ONLY use FILENAME: ... END FILE format
|
|
117
|
+
- Do NOT use markdown code blocks
|
|
108
118
|
- Create ALL files needed for a complete working project
|
|
119
|
+
- Use Three.js from CDN for 3D
|
|
120
|
+
- No placeholders, no TODOs, no lorem ipsum
|
|
109
121
|
|
|
110
122
|
Working directory: ${process.cwd()}`;
|
|
111
|
-
console.log('
|
|
123
|
+
console.log('');
|
|
124
|
+
console.log(' ⏳ Sending to AI...');
|
|
112
125
|
try {
|
|
113
126
|
const controller = new AbortController();
|
|
114
127
|
const timeout = setTimeout(() => controller.abort(), 300000);
|
|
@@ -126,7 +139,7 @@ Working directory: ${process.cwd()}`;
|
|
|
126
139
|
{ role: 'system', content: systemPrompt },
|
|
127
140
|
{ role: 'user', content: trimmed },
|
|
128
141
|
],
|
|
129
|
-
stream:
|
|
142
|
+
stream: false,
|
|
130
143
|
max_tokens: 16000,
|
|
131
144
|
temperature: 0.1,
|
|
132
145
|
}),
|
|
@@ -137,125 +150,45 @@ Working directory: ${process.cwd()}`;
|
|
|
137
150
|
const err = await res.text().catch(() => '');
|
|
138
151
|
throw new Error(`API error ${res.status}: ${err.slice(0, 200)}`);
|
|
139
152
|
}
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const lines = buffer.split('\n');
|
|
155
|
-
buffer = lines.pop();
|
|
153
|
+
console.log(' ⏳ AI is thinking...');
|
|
154
|
+
const data = await res.json();
|
|
155
|
+
const content = data.choices?.[0]?.message?.content || '';
|
|
156
|
+
if (!content) {
|
|
157
|
+
console.log(' ⚠ No response from model.\n');
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
console.log(' ✓ AI responded! Parsing files...\n');
|
|
161
|
+
const files = extractFiles(content);
|
|
162
|
+
if (files.length === 0) {
|
|
163
|
+
console.log(' ⚠ No files detected. Full output:\n');
|
|
164
|
+
console.log(' ──────────────────────────────────────');
|
|
165
|
+
// Print first 100 lines
|
|
166
|
+
const lines = content.split('\n').slice(0, 100);
|
|
156
167
|
for (const line of lines) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
}
|
|
168
|
+
console.log(' ' + line);
|
|
169
|
+
}
|
|
170
|
+
if (content.split('\n').length > 100) {
|
|
171
|
+
console.log(' ... (truncated)');
|
|
238
172
|
}
|
|
173
|
+
console.log(' ──────────────────────────────────────\n');
|
|
174
|
+
continue;
|
|
239
175
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
catch (e) {
|
|
254
|
-
console.log(` ✗ Error: ${currentFile}: ${e.message}`);
|
|
255
|
-
}
|
|
176
|
+
console.log(` 📁 Found ${files.length} file(s):\n`);
|
|
177
|
+
for (const file of files) {
|
|
178
|
+
try {
|
|
179
|
+
const filePath = join(process.cwd(), file.path);
|
|
180
|
+
const dir = dirname(resolve(filePath));
|
|
181
|
+
if (!existsSync(dir))
|
|
182
|
+
mkdirSync(dir, { recursive: true });
|
|
183
|
+
writeFileSync(filePath, file.content, 'utf-8');
|
|
184
|
+
createdFiles.add(file.path);
|
|
185
|
+
console.log(` ✅ ${file.path} (${file.content.length} chars)`);
|
|
186
|
+
}
|
|
187
|
+
catch (e) {
|
|
188
|
+
console.log(` ❌ ${file.path}: ${e.message}`);
|
|
256
189
|
}
|
|
257
190
|
}
|
|
258
|
-
console.log(`\n 📊
|
|
191
|
+
console.log(`\n 📊 Total files created: ${createdFiles.size}`);
|
|
259
192
|
console.log('');
|
|
260
193
|
}
|
|
261
194
|
catch (e) {
|