lumina-code-agent 1.6.10 → 1.6.11
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 +45 -82
- 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');
|
|
@@ -35,6 +35,21 @@ async function onboarding() {
|
|
|
35
35
|
saveConfig({ openrouterKey: apiKey.trim(), userName: 'User' });
|
|
36
36
|
console.log(' ✅ Ready!\n');
|
|
37
37
|
}
|
|
38
|
+
function extractFiles(text) {
|
|
39
|
+
const files = [];
|
|
40
|
+
const fileRegex = /FILENAME:\s*([^\n]+)\n([\s\S]*?)END FILE/g;
|
|
41
|
+
let match;
|
|
42
|
+
while ((match = fileRegex.exec(text)) !== null) {
|
|
43
|
+
const rawPath = match[1].trim();
|
|
44
|
+
const content = match[2].trim();
|
|
45
|
+
if (!rawPath || rawPath.endsWith('/') || !extname(rawPath))
|
|
46
|
+
continue;
|
|
47
|
+
if (rawPath.includes('<') || rawPath.includes('"') || rawPath.includes('`'))
|
|
48
|
+
continue;
|
|
49
|
+
files.push({ path: rawPath, content });
|
|
50
|
+
}
|
|
51
|
+
return files;
|
|
52
|
+
}
|
|
38
53
|
async function chat(config) {
|
|
39
54
|
console.log(' 💬 Type what you want to build. /exit to quit.\n');
|
|
40
55
|
const createdFiles = new Set();
|
|
@@ -61,14 +76,14 @@ FILENAME: index.html
|
|
|
61
76
|
END FILE
|
|
62
77
|
|
|
63
78
|
FILENAME: style.css
|
|
64
|
-
/* COMPLETE CSS
|
|
79
|
+
/* COMPLETE CSS */
|
|
65
80
|
END FILE
|
|
66
81
|
|
|
67
82
|
FILENAME: script.js
|
|
68
|
-
// COMPLETE JS
|
|
83
|
+
// COMPLETE JS
|
|
69
84
|
END FILE
|
|
70
85
|
|
|
71
|
-
RULES: Start IMMEDIATELY with FILENAME: index.html. Do NOT describe. JUST OUTPUT COMPLETE FILES. No placeholders. No TODOs. Robot: Three.js primitives, PBR materials, wave/blink animations, scroll-driven sections (Hero=wave, Features=point, About=think, Contact=wave goodbye), particles, dark gradient bg.
|
|
86
|
+
RULES: Start IMMEDIATELY with FILENAME: index.html. Do NOT describe. JUST OUTPUT COMPLETE FILES. No placeholders. No TODOs. Robot: Three.js primitives, PBR materials, wave/blink animations, scroll-driven sections (Hero=wave, Features=point, About=think, Contact=wave goodbye), particles, dark gradient bg. 56000 tokens max.
|
|
72
87
|
|
|
73
88
|
Working directory: ${process.cwd()}`;
|
|
74
89
|
while (true) {
|
|
@@ -78,7 +93,7 @@ Working directory: ${process.cwd()}`;
|
|
|
78
93
|
continue;
|
|
79
94
|
if (trimmed === '/exit')
|
|
80
95
|
break;
|
|
81
|
-
console.log('\n ⏳
|
|
96
|
+
console.log('\n ⏳ Streaming...\n');
|
|
82
97
|
try {
|
|
83
98
|
const res = await fetch('https://openrouter.ai/api/v1/chat/completions', {
|
|
84
99
|
method: 'POST',
|
|
@@ -103,15 +118,11 @@ Working directory: ${process.cwd()}`;
|
|
|
103
118
|
const err = await res.text().catch(() => '');
|
|
104
119
|
throw new Error(`API ${res.status}: ${err.slice(0, 200)}`);
|
|
105
120
|
}
|
|
106
|
-
// Stream and
|
|
121
|
+
// Stream and collect full text
|
|
107
122
|
const reader = res.body.getReader();
|
|
108
123
|
const decoder = new TextDecoder();
|
|
109
124
|
let buf = '';
|
|
110
125
|
let fullText = '';
|
|
111
|
-
let fileBuf = '';
|
|
112
|
-
let inFile = false;
|
|
113
|
-
let fileName = '';
|
|
114
|
-
let fileContent = '';
|
|
115
126
|
let filesCreated = 0;
|
|
116
127
|
while (true) {
|
|
117
128
|
const { done, value } = await reader.read();
|
|
@@ -128,8 +139,7 @@ Working directory: ${process.cwd()}`;
|
|
|
128
139
|
continue;
|
|
129
140
|
let delta = '';
|
|
130
141
|
try {
|
|
131
|
-
|
|
132
|
-
delta = p.choices?.[0]?.delta?.content || '';
|
|
142
|
+
delta = JSON.parse(d).choices?.[0]?.delta?.content || '';
|
|
133
143
|
}
|
|
134
144
|
catch {
|
|
135
145
|
continue;
|
|
@@ -137,78 +147,31 @@ Working directory: ${process.cwd()}`;
|
|
|
137
147
|
if (!delta)
|
|
138
148
|
continue;
|
|
139
149
|
fullText += delta;
|
|
140
|
-
|
|
141
|
-
for (const ch of delta) {
|
|
142
|
-
if (!inFile) {
|
|
143
|
-
fileBuf += ch;
|
|
144
|
-
if (fileBuf.endsWith('FILENAME:')) {
|
|
145
|
-
inFile = true;
|
|
146
|
-
fileName = '';
|
|
147
|
-
fileContent = '';
|
|
148
|
-
fileBuf = '';
|
|
149
|
-
process.stdout.write(' 📄 ');
|
|
150
|
-
}
|
|
151
|
-
else if (fileBuf.length > 50) {
|
|
152
|
-
// Not matching, flush to output
|
|
153
|
-
process.stdout.write(fileBuf);
|
|
154
|
-
fileBuf = '';
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
if (ch === '\n' && !fileName.includes('.')) {
|
|
159
|
-
fileName = fileName.trim();
|
|
160
|
-
process.stdout.write(fileName + '\n');
|
|
161
|
-
}
|
|
162
|
-
else if (ch === '\n' && fileName && !fileContent) {
|
|
163
|
-
// First newline after filename, start content
|
|
164
|
-
fileContent = '';
|
|
165
|
-
}
|
|
166
|
-
else if (fileContent !== null) {
|
|
167
|
-
fileContent += ch;
|
|
168
|
-
if (fileContent.endsWith('END FILE')) {
|
|
169
|
-
const content = fileContent.slice(0, -8).trim();
|
|
170
|
-
try {
|
|
171
|
-
const fp = join(process.cwd(), fileName);
|
|
172
|
-
const dir = dirname(resolve(fp));
|
|
173
|
-
if (!existsSync(dir))
|
|
174
|
-
mkdirSync(dir, { recursive: true });
|
|
175
|
-
writeFileSync(fp, content, 'utf-8');
|
|
176
|
-
createdFiles.add(fileName);
|
|
177
|
-
filesCreated++;
|
|
178
|
-
console.log(` ✅ Saved: ${fileName} (${content.length} chars)`);
|
|
179
|
-
}
|
|
180
|
-
catch (e) {
|
|
181
|
-
console.log(` ❌ ${fileName}: ${e.message}`);
|
|
182
|
-
}
|
|
183
|
-
inFile = false;
|
|
184
|
-
fileName = '';
|
|
185
|
-
fileContent = null;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
fileName += ch;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
150
|
+
process.stdout.write(delta);
|
|
193
151
|
}
|
|
194
152
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
153
|
+
console.log('\n');
|
|
154
|
+
console.log(` ✅ Stream complete (${fullText.length} chars)`);
|
|
155
|
+
// Parse files from complete output
|
|
156
|
+
const files = extractFiles(fullText);
|
|
157
|
+
if (files.length === 0) {
|
|
158
|
+
console.log(' ⚠ No files detected.\n');
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
console.log(` 📁 Creating ${files.length} file(s):\n`);
|
|
162
|
+
for (const file of files) {
|
|
163
|
+
try {
|
|
164
|
+
const filePath = join(process.cwd(), file.path);
|
|
165
|
+
const dir = dirname(resolve(filePath));
|
|
166
|
+
if (!existsSync(dir))
|
|
167
|
+
mkdirSync(dir, { recursive: true });
|
|
168
|
+
writeFileSync(filePath, file.content, 'utf-8');
|
|
169
|
+
createdFiles.add(file.path);
|
|
170
|
+
filesCreated++;
|
|
171
|
+
console.log(` ✅ ${file.path} (${file.content.length} chars)`);
|
|
172
|
+
}
|
|
173
|
+
catch (e) {
|
|
174
|
+
console.log(` ❌ ${file.path}: ${e.message}`);
|
|
212
175
|
}
|
|
213
176
|
}
|
|
214
177
|
console.log(`\n 📊 Created ${filesCreated} file(s) | Total: ${createdFiles.size}\n`);
|