lumina-code-agent 1.6.9 → 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 +65 -96
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24,15 +24,16 @@ function saveConfig(config) {
|
|
|
24
24
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
25
25
|
function ask(q) { return new Promise(r => rl.question(q, r)); }
|
|
26
26
|
async function onboarding() {
|
|
27
|
-
console.log('\n
|
|
28
|
-
|
|
27
|
+
console.log('\n╔══════════════════════════════════════╗');
|
|
28
|
+
console.log('║ ⚡ LUMINA CODE — AI Coding Agent ║');
|
|
29
|
+
console.log('╚══════════════════════════════════════╝\n');
|
|
30
|
+
const apiKey = await ask(' 🔑 OpenRouter API key: ');
|
|
29
31
|
if (!apiKey.trim() || apiKey.trim().length < 10) {
|
|
30
|
-
console.log(' ❌ Invalid
|
|
32
|
+
console.log(' ❌ Invalid.');
|
|
31
33
|
process.exit(1);
|
|
32
34
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
console.log(' ✓ Ready!\n');
|
|
35
|
+
saveConfig({ openrouterKey: apiKey.trim(), userName: 'User' });
|
|
36
|
+
console.log(' ✅ Ready!\n');
|
|
36
37
|
}
|
|
37
38
|
function extractFiles(text) {
|
|
38
39
|
const files = [];
|
|
@@ -43,88 +44,57 @@ function extractFiles(text) {
|
|
|
43
44
|
const content = match[2].trim();
|
|
44
45
|
if (!rawPath || rawPath.endsWith('/') || !extname(rawPath))
|
|
45
46
|
continue;
|
|
46
|
-
if (rawPath.includes('<') || rawPath.includes('
|
|
47
|
+
if (rawPath.includes('<') || rawPath.includes('"') || rawPath.includes('`'))
|
|
47
48
|
continue;
|
|
48
49
|
files.push({ path: rawPath, content });
|
|
49
50
|
}
|
|
50
51
|
return files;
|
|
51
52
|
}
|
|
52
53
|
async function chat(config) {
|
|
53
|
-
console.log(' Type what you want to build.
|
|
54
|
-
console.log(' Commands: /help /clear /files /exit\n');
|
|
54
|
+
console.log(' 💬 Type what you want to build. /exit to quit.\n');
|
|
55
55
|
const createdFiles = new Set();
|
|
56
|
-
|
|
57
|
-
const input = await ask(' > ');
|
|
58
|
-
const trimmed = input.trim();
|
|
59
|
-
if (!trimmed)
|
|
60
|
-
continue;
|
|
61
|
-
if (trimmed === '/exit' || trimmed === '/quit')
|
|
62
|
-
break;
|
|
63
|
-
if (trimmed === '/clear') {
|
|
64
|
-
console.log(' ✓ Cleared.\n');
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
if (trimmed === '/files') {
|
|
68
|
-
if (createdFiles.size === 0) {
|
|
69
|
-
console.log(' No files yet.\n');
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
console.log(' Files:');
|
|
73
|
-
for (const f of createdFiles)
|
|
74
|
-
console.log(` ${f}`);
|
|
75
|
-
console.log('');
|
|
76
|
-
}
|
|
77
|
-
continue;
|
|
78
|
-
}
|
|
79
|
-
if (trimmed === '/help') {
|
|
80
|
-
console.log(' /help /clear /files /exit\n');
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
const systemPrompt = `You are LUMINA CODE. Create COMPLETE production-grade websites.
|
|
84
|
-
|
|
85
|
-
OUTPUT FORMAT — Use this EXACT format for EVERY file:
|
|
56
|
+
const SYSTEM = `You are LUMINA CODE — the world's best AI coding agent.
|
|
86
57
|
|
|
58
|
+
OUTPUT FORMAT — MANDATORY:
|
|
87
59
|
FILENAME: index.html
|
|
88
60
|
<!DOCTYPE html>
|
|
89
61
|
<html lang="en">
|
|
90
62
|
<head>
|
|
91
63
|
<meta charset="UTF-8">
|
|
92
|
-
<meta name="viewport" content="width=device-width,
|
|
64
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
93
65
|
<title>Title</title>
|
|
94
66
|
<link rel="stylesheet" href="style.css">
|
|
95
67
|
</head>
|
|
96
68
|
<body>
|
|
97
|
-
<!--
|
|
69
|
+
<!-- COMPLETE HTML -->
|
|
98
70
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
|
71
|
+
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
|
|
72
|
+
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>
|
|
99
73
|
<script src="script.js"></script>
|
|
100
74
|
</body>
|
|
101
75
|
</html>
|
|
102
76
|
END FILE
|
|
103
77
|
|
|
104
78
|
FILENAME: style.css
|
|
105
|
-
/*
|
|
79
|
+
/* COMPLETE CSS */
|
|
106
80
|
END FILE
|
|
107
81
|
|
|
108
82
|
FILENAME: script.js
|
|
109
|
-
//
|
|
83
|
+
// COMPLETE JS
|
|
110
84
|
END FILE
|
|
111
85
|
|
|
112
|
-
RULES:
|
|
113
|
-
- Start IMMEDIATELY with FILENAME: index.html
|
|
114
|
-
- Output COMPLETE files — every line, no truncation
|
|
115
|
-
- Do NOT describe what you will do — JUST DO IT
|
|
116
|
-
- Do NOT output any text before FILENAME:
|
|
117
|
-
- Do NOT use markdown code blocks
|
|
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
|
|
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.
|
|
121
87
|
|
|
122
88
|
Working directory: ${process.cwd()}`;
|
|
123
|
-
|
|
124
|
-
|
|
89
|
+
while (true) {
|
|
90
|
+
const input = await ask(' > ');
|
|
91
|
+
const trimmed = input.trim();
|
|
92
|
+
if (!trimmed)
|
|
93
|
+
continue;
|
|
94
|
+
if (trimmed === '/exit')
|
|
95
|
+
break;
|
|
96
|
+
console.log('\n ⏳ Streaming...\n');
|
|
125
97
|
try {
|
|
126
|
-
const controller = new AbortController();
|
|
127
|
-
const timeout = setTimeout(() => controller.abort(), 600000); // 10 min timeout
|
|
128
98
|
const res = await fetch('https://openrouter.ai/api/v1/chat/completions', {
|
|
129
99
|
method: 'POST',
|
|
130
100
|
headers: {
|
|
@@ -136,58 +106,56 @@ Working directory: ${process.cwd()}`;
|
|
|
136
106
|
body: JSON.stringify({
|
|
137
107
|
model: 'openrouter/owl-alpha',
|
|
138
108
|
messages: [
|
|
139
|
-
{ role: 'system', content:
|
|
109
|
+
{ role: 'system', content: SYSTEM },
|
|
140
110
|
{ role: 'user', content: trimmed },
|
|
141
111
|
],
|
|
142
|
-
stream:
|
|
143
|
-
max_tokens:
|
|
112
|
+
stream: true,
|
|
113
|
+
max_tokens: 56000,
|
|
144
114
|
temperature: 0.1,
|
|
145
115
|
}),
|
|
146
|
-
signal: controller.signal,
|
|
147
116
|
});
|
|
148
|
-
clearTimeout(timeout);
|
|
149
117
|
if (!res.ok) {
|
|
150
118
|
const err = await res.text().catch(() => '');
|
|
151
|
-
throw new Error(`API
|
|
152
|
-
}
|
|
153
|
-
// Read response as text first, then parse
|
|
154
|
-
const rawText = await res.text();
|
|
155
|
-
let data;
|
|
156
|
-
try {
|
|
157
|
-
data = JSON.parse(rawText);
|
|
119
|
+
throw new Error(`API ${res.status}: ${err.slice(0, 200)}`);
|
|
158
120
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
121
|
+
// Stream and collect full text
|
|
122
|
+
const reader = res.body.getReader();
|
|
123
|
+
const decoder = new TextDecoder();
|
|
124
|
+
let buf = '';
|
|
125
|
+
let fullText = '';
|
|
126
|
+
let filesCreated = 0;
|
|
127
|
+
while (true) {
|
|
128
|
+
const { done, value } = await reader.read();
|
|
129
|
+
if (done)
|
|
130
|
+
break;
|
|
131
|
+
buf += decoder.decode(value, { stream: true });
|
|
132
|
+
const lines = buf.split('\n');
|
|
133
|
+
buf = lines.pop();
|
|
134
|
+
for (const line of lines) {
|
|
135
|
+
if (!line.startsWith('data: '))
|
|
136
|
+
continue;
|
|
137
|
+
const d = line.slice(6).trim();
|
|
138
|
+
if (d === '[DONE]')
|
|
139
|
+
continue;
|
|
140
|
+
let delta = '';
|
|
165
141
|
try {
|
|
166
|
-
|
|
142
|
+
delta = JSON.parse(d).choices?.[0]?.delta?.content || '';
|
|
167
143
|
}
|
|
168
|
-
catch
|
|
169
|
-
|
|
144
|
+
catch {
|
|
145
|
+
continue;
|
|
170
146
|
}
|
|
147
|
+
if (!delta)
|
|
148
|
+
continue;
|
|
149
|
+
fullText += delta;
|
|
150
|
+
process.stdout.write(delta);
|
|
171
151
|
}
|
|
172
|
-
else {
|
|
173
|
-
throw new Error('Response was truncated. Try a shorter prompt.');
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
const content = data.choices?.[0]?.message?.content || '';
|
|
177
|
-
if (!content) {
|
|
178
|
-
console.log(' ⚠ No response from model.\n');
|
|
179
|
-
continue;
|
|
180
152
|
}
|
|
181
|
-
console.log(
|
|
182
|
-
|
|
153
|
+
console.log('\n');
|
|
154
|
+
console.log(` ✅ Stream complete (${fullText.length} chars)`);
|
|
155
|
+
// Parse files from complete output
|
|
156
|
+
const files = extractFiles(fullText);
|
|
183
157
|
if (files.length === 0) {
|
|
184
|
-
console.log(' ⚠ No files detected
|
|
185
|
-
// Show first 50 lines of output
|
|
186
|
-
const lines = content.split('\n').slice(0, 50);
|
|
187
|
-
console.log(' ── Output preview ──');
|
|
188
|
-
for (const line of lines)
|
|
189
|
-
console.log(' ' + line);
|
|
190
|
-
console.log(' ── End ──\n');
|
|
158
|
+
console.log(' ⚠ No files detected.\n');
|
|
191
159
|
continue;
|
|
192
160
|
}
|
|
193
161
|
console.log(` 📁 Creating ${files.length} file(s):\n`);
|
|
@@ -199,16 +167,17 @@ Working directory: ${process.cwd()}`;
|
|
|
199
167
|
mkdirSync(dir, { recursive: true });
|
|
200
168
|
writeFileSync(filePath, file.content, 'utf-8');
|
|
201
169
|
createdFiles.add(file.path);
|
|
170
|
+
filesCreated++;
|
|
202
171
|
console.log(` ✅ ${file.path} (${file.content.length} chars)`);
|
|
203
172
|
}
|
|
204
173
|
catch (e) {
|
|
205
174
|
console.log(` ❌ ${file.path}: ${e.message}`);
|
|
206
175
|
}
|
|
207
176
|
}
|
|
208
|
-
console.log(`\n 📊 Total
|
|
177
|
+
console.log(`\n 📊 Created ${filesCreated} file(s) | Total: ${createdFiles.size}\n`);
|
|
209
178
|
}
|
|
210
179
|
catch (e) {
|
|
211
|
-
console.log(`
|
|
180
|
+
console.log(` ❌ ${e.message}\n`);
|
|
212
181
|
}
|
|
213
182
|
}
|
|
214
183
|
rl.close();
|