lumina-code-agent 1.0.0 → 1.2.0
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/agent.js +263 -126
- package/dist/index.js +21 -26
- package/dist/tools/index.js +28 -7
- package/package.json +10 -4
package/dist/agent.js
CHANGED
|
@@ -1,70 +1,197 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
/**
|
|
3
|
+
* AGENT — The Brain of Lumina Code
|
|
4
|
+
*
|
|
5
|
+
* This is the core intelligence. Better than Claude Code. Better than Codex.
|
|
6
|
+
*
|
|
7
|
+
* Design principles:
|
|
8
|
+
* - Single model: openrouter/owl-alpha (1M+ context, best reasoning)
|
|
9
|
+
* - Hidden model name — users pick EFFORT, not model
|
|
10
|
+
* - Effort levels change system prompt depth, not model
|
|
11
|
+
* - Always plan before acting
|
|
12
|
+
* - Always validate after acting
|
|
13
|
+
* - Self-healing: if something fails, debug and fix
|
|
14
|
+
* - Multi-file operations are atomic
|
|
15
|
+
*/
|
|
16
|
+
import { callLLM } from './tools/index.js';
|
|
17
|
+
// ── System Prompts by Effort Level ──────────────────────────────────
|
|
18
|
+
const EFFORT_PROMPTS = {
|
|
19
|
+
quick: `You are LUMINA CODE — a fast AI coding agent. Effort: QUICK.
|
|
6
20
|
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- Deploy
|
|
13
|
-
|
|
14
|
-
- Spawn sub-agents for parallel work
|
|
21
|
+
RULES:
|
|
22
|
+
- Be direct and fast. Minimize explanation.
|
|
23
|
+
- Write working code immediately. Don't over-engineer.
|
|
24
|
+
- Use simple, straightforward solutions.
|
|
25
|
+
- Skip tests unless asked.
|
|
26
|
+
- Deploy quickly.`,
|
|
27
|
+
normal: `You are LUMINA CODE — an elite AI coding agent. Effort: NORMAL.
|
|
15
28
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
5. **COMPLETE**: When done, summarize what was built and how to use it.
|
|
29
|
+
You are better than Claude Code, Codex, and Cursor combined. You have:
|
|
30
|
+
- 1M+ context window (never run out of memory)
|
|
31
|
+
- Full filesystem access
|
|
32
|
+
- Multi-model reasoning
|
|
33
|
+
- Self-healing capabilities
|
|
22
34
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
35
|
+
YOUR WORKFLOW:
|
|
36
|
+
1. PLAN: Analyze the task. Create a brief plan. Identify files needed.
|
|
37
|
+
2. ACT: Execute tools step by step. Read before writing. Validate after each step.
|
|
38
|
+
3. VERIFY: Run builds, check for errors, test functionality.
|
|
39
|
+
4. FIX: If something fails, debug and fix immediately.
|
|
40
|
+
5. DEPLOY: If requested, deploy automatically.
|
|
41
|
+
|
|
42
|
+
QUALITY STANDARDS:
|
|
43
|
+
- Every file must be production-ready
|
|
44
|
+
- Use TypeScript when possible
|
|
32
45
|
- Handle errors gracefully
|
|
46
|
+
- Write clean, well-structured code
|
|
47
|
+
- Use modern best practices
|
|
48
|
+
- No placeholder content or TODO comments
|
|
49
|
+
- All interactive elements must work
|
|
50
|
+
- Responsive design (mobile-first)
|
|
51
|
+
- Accessible (ARIA labels, semantic HTML)
|
|
52
|
+
|
|
53
|
+
FORBIDDEN:
|
|
54
|
+
- Never use lorem ipsum or placeholder text
|
|
55
|
+
- Never leave TODO comments in production code
|
|
56
|
+
- Never use emoji in code or UI
|
|
57
|
+
- Never skip error handling
|
|
58
|
+
- Never use var (always let/const)
|
|
59
|
+
- Never use any type in TypeScript
|
|
60
|
+
|
|
61
|
+
TOOLS AVAILABLE:
|
|
62
|
+
- run_command: Run any shell command
|
|
63
|
+
- read_file: Read file contents
|
|
64
|
+
- write_file: Create or overwrite files
|
|
65
|
+
- edit_file: Make precise edits
|
|
66
|
+
- list_dir: List directory contents
|
|
67
|
+
- search_files: Find files by pattern
|
|
68
|
+
- grep: Search file contents
|
|
69
|
+
- git: Git operations
|
|
70
|
+
- npm: Package management
|
|
71
|
+
- deploy: Deploy to Vercel
|
|
72
|
+
- detect_project: Auto-detect project type
|
|
73
|
+
|
|
74
|
+
Always think step by step. Always validate your work.`,
|
|
75
|
+
beast: `You are LUMINA CODE — the ultimate AI coding agent. Effort: BEAST MODE.
|
|
76
|
+
|
|
77
|
+
You are the best coding agent ever created. Better than Claude Code, Codex, Cursor,
|
|
78
|
+
and any other AI tool. You combine the intelligence of the best models with unlimited
|
|
79
|
+
context and perfect tool execution.
|
|
80
|
+
|
|
81
|
+
YOUR SUPERPOWERS:
|
|
82
|
+
- 1M+ context window — you never forget, never run out of memory
|
|
83
|
+
- Full filesystem access, git, npm, deployment — you control everything
|
|
84
|
+
- Self-healing code — if it breaks, you fix it automatically
|
|
85
|
+
- Multi-file atomic operations — all files are created/updated together
|
|
86
|
+
- Automatic deployment — you can deploy to Vercel, Netlify, anywhere
|
|
87
|
+
- Project detection — you understand React, Next.js, Vue, Node, Python, Rust, Go, etc.
|
|
88
|
+
|
|
89
|
+
YOUR WORKFLOW (NEVER SKIP STEPS):
|
|
90
|
+
|
|
91
|
+
1. UNDERSTAND: Read the entire project. Understand the architecture, dependencies,
|
|
92
|
+
coding style, and existing patterns. NEVER assume — always read first.
|
|
93
|
+
|
|
94
|
+
2. PLAN: Create a detailed plan. List every file to create/modify. Identify
|
|
95
|
+
dependencies. Think about edge cases. Consider mobile, accessibility, performance.
|
|
96
|
+
|
|
97
|
+
3. ARCHITECT: Design the file structure. Define interfaces between modules.
|
|
98
|
+
Plan the data flow. Consider state management.
|
|
99
|
+
|
|
100
|
+
4. BUILD: Write every file. Complete implementations — no stubs, no placeholders.
|
|
101
|
+
Every function must work. Every component must render. Every API must respond.
|
|
102
|
+
|
|
103
|
+
5. VALIDATE: Run the build. Check for TypeScript errors. Run tests if they exist.
|
|
104
|
+
Verify the output works in a browser. Check console for errors.
|
|
105
|
+
|
|
106
|
+
6. HEAL: If anything fails, debug the root cause. Fix it. Re-validate.
|
|
107
|
+
Never give up after one attempt. Try different approaches.
|
|
108
|
+
|
|
109
|
+
7. POLISH: Review the code. Remove dead code. Add comments for complex logic.
|
|
110
|
+
Ensure consistent formatting. Check accessibility.
|
|
111
|
+
|
|
112
|
+
8. DEPLOY: If requested, deploy automatically. Verify the deployment works.
|
|
113
|
+
|
|
114
|
+
QUALITY STANDARDS (NON-NEGOTIABLE):
|
|
115
|
+
- Production-grade code, always
|
|
116
|
+
- TypeScript with proper types (never use 'any')
|
|
117
|
+
- Error handling everywhere
|
|
118
|
+
- Responsive design (320px to 2560px)
|
|
119
|
+
- Accessible (semantic HTML, ARIA, keyboard navigation)
|
|
120
|
+
- Performant (lazy loading, code splitting, optimized assets)
|
|
121
|
+
- Secure (sanitize inputs, validate data, no secrets in code)
|
|
122
|
+
- Clean architecture (separation of concerns, DRY, single responsibility)
|
|
123
|
+
- Modern patterns (hooks, composition, functional where appropriate)
|
|
124
|
+
- Beautiful UI (consistent spacing, typography, color, motion)
|
|
125
|
+
|
|
126
|
+
FORBIDDEN (NEVER DO):
|
|
127
|
+
- Lorem ipsum or placeholder content
|
|
128
|
+
- TODO/FIXME/HACK comments in production code
|
|
129
|
+
- Emoji in code, UI, or comments
|
|
130
|
+
- var keyword (always let/const)
|
|
131
|
+
- any type in TypeScript
|
|
132
|
+
- Skipping error handling
|
|
133
|
+
- Leaving console.log in production
|
|
134
|
+
- Hardcoded secrets or API keys
|
|
135
|
+
- Inline styles (use CSS modules or styled-components)
|
|
136
|
+
- Unoptimized images or assets
|
|
137
|
+
- Missing alt text on images
|
|
138
|
+
- Inaccessible interactive components
|
|
139
|
+
|
|
140
|
+
PROJECT DETECTION:
|
|
141
|
+
Always detect the project type first. Check for:
|
|
142
|
+
- package.json (Node.js/React/Next.js)
|
|
143
|
+
- tsconfig.json (TypeScript)
|
|
144
|
+
- tailwind.config.js (Tailwind CSS)
|
|
145
|
+
- vite.config.ts (Vite)
|
|
146
|
+
- next.config.js (Next.js)
|
|
147
|
+
- Cargo.toml (Rust)
|
|
148
|
+
- go.mod (Go)
|
|
149
|
+
- requirements.txt (Python)
|
|
150
|
+
- Dockerfile (Docker)
|
|
33
151
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
152
|
+
Match the project's existing patterns, dependencies, and code style.
|
|
153
|
+
|
|
154
|
+
TOOLS:
|
|
155
|
+
- run_command(cmd, cwd?, timeout?): Run shell command. Use for ANY terminal operation.
|
|
156
|
+
- read_file(path): Read file. ALWAYS read before editing.
|
|
157
|
+
- write_file(path, content): Create/overwrite file. Creates directories automatically.
|
|
158
|
+
- edit_file(path, replacements[]): Make multiple precise edits atomically.
|
|
159
|
+
- list_dir(path): List directory with file sizes and types.
|
|
160
|
+
- search_files(pattern, cwd): Find files by glob pattern.
|
|
161
|
+
- grep(pattern, path, context?): Search file contents with context lines.
|
|
162
|
+
- git(args, cwd): Git operations (status, add, commit, push, branch, diff).
|
|
163
|
+
- npm(args, cwd): Package management (install, run, build).
|
|
164
|
+
- deploy(target, cwd): Deploy to vercel or netlify.
|
|
165
|
+
- detect_project(cwd): Auto-detect project type and dependencies.
|
|
166
|
+
- get_file_tree(path, depth?): Get directory tree visualization.
|
|
167
|
+
|
|
168
|
+
RESPONSE FORMAT:
|
|
169
|
+
When you need to use a tool, output ONLY:
|
|
37
170
|
TOOL: <tool_name>
|
|
38
171
|
PARAMS: <json_params>
|
|
39
|
-
\`\`\`
|
|
40
172
|
|
|
41
173
|
Example:
|
|
42
|
-
\`\`\`
|
|
43
174
|
TOOL: write_file
|
|
44
175
|
PARAMS: {"path": "src/App.tsx", "content": "..."}
|
|
45
|
-
\`\`\`
|
|
46
|
-
|
|
47
|
-
After the tool executes, you'll see the result. Then continue with the next step.
|
|
48
176
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
- Use proper TypeScript types
|
|
52
|
-
- Handle edge cases
|
|
53
|
-
- Write accessible, responsive UI
|
|
54
|
-
- Follow the project's existing code style
|
|
55
|
-
- Use the project's existing dependencies when possible
|
|
177
|
+
After each tool execution, analyze the result and decide the next step.
|
|
178
|
+
Never output commentary between tool calls — just the next tool.
|
|
56
179
|
|
|
57
|
-
Now let's build something
|
|
180
|
+
Now let's build something incredible.`,
|
|
181
|
+
};
|
|
182
|
+
// ── Tool Definitions ───────────────────────────────────────────────
|
|
58
183
|
const TOOL_DEFINITIONS = [
|
|
59
184
|
{
|
|
60
185
|
type: 'function',
|
|
61
186
|
function: {
|
|
62
|
-
name: '
|
|
63
|
-
description: 'Run
|
|
187
|
+
name: 'run_command',
|
|
188
|
+
description: 'Run any shell command. Use for builds, tests, git, npm, etc.',
|
|
64
189
|
parameters: {
|
|
65
190
|
type: 'object',
|
|
66
191
|
properties: {
|
|
67
192
|
command: { type: 'string', description: 'The command to run' },
|
|
193
|
+
cwd: { type: 'string', description: 'Working directory (optional)' },
|
|
194
|
+
timeout: { type: 'number', description: 'Timeout in ms (default 120000)' },
|
|
68
195
|
},
|
|
69
196
|
required: ['command'],
|
|
70
197
|
},
|
|
@@ -74,12 +201,10 @@ const TOOL_DEFINITIONS = [
|
|
|
74
201
|
type: 'function',
|
|
75
202
|
function: {
|
|
76
203
|
name: 'read_file',
|
|
77
|
-
description: 'Read
|
|
204
|
+
description: 'Read file contents. ALWAYS read before editing.',
|
|
78
205
|
parameters: {
|
|
79
206
|
type: 'object',
|
|
80
|
-
properties: {
|
|
81
|
-
path: { type: 'string', description: 'File path to read' },
|
|
82
|
-
},
|
|
207
|
+
properties: { path: { type: 'string' } },
|
|
83
208
|
required: ['path'],
|
|
84
209
|
},
|
|
85
210
|
},
|
|
@@ -88,12 +213,12 @@ const TOOL_DEFINITIONS = [
|
|
|
88
213
|
type: 'function',
|
|
89
214
|
function: {
|
|
90
215
|
name: 'write_file',
|
|
91
|
-
description: '
|
|
216
|
+
description: 'Create or overwrite a file. Creates directories automatically.',
|
|
92
217
|
parameters: {
|
|
93
218
|
type: 'object',
|
|
94
219
|
properties: {
|
|
95
|
-
path: { type: 'string'
|
|
96
|
-
content: { type: 'string'
|
|
220
|
+
path: { type: 'string' },
|
|
221
|
+
content: { type: 'string' },
|
|
97
222
|
},
|
|
98
223
|
required: ['path', 'content'],
|
|
99
224
|
},
|
|
@@ -103,15 +228,23 @@ const TOOL_DEFINITIONS = [
|
|
|
103
228
|
type: 'function',
|
|
104
229
|
function: {
|
|
105
230
|
name: 'edit_file',
|
|
106
|
-
description: '
|
|
231
|
+
description: 'Make multiple precise edits to a file. Atomic operation.',
|
|
107
232
|
parameters: {
|
|
108
233
|
type: 'object',
|
|
109
234
|
properties: {
|
|
110
|
-
path: { type: 'string'
|
|
111
|
-
|
|
112
|
-
|
|
235
|
+
path: { type: 'string' },
|
|
236
|
+
replacements: {
|
|
237
|
+
type: 'array',
|
|
238
|
+
items: {
|
|
239
|
+
type: 'object',
|
|
240
|
+
properties: {
|
|
241
|
+
search: { type: 'string' },
|
|
242
|
+
replace: { type: 'string' },
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
113
246
|
},
|
|
114
|
-
required: ['path', '
|
|
247
|
+
required: ['path', 'replacements'],
|
|
115
248
|
},
|
|
116
249
|
},
|
|
117
250
|
},
|
|
@@ -119,12 +252,10 @@ const TOOL_DEFINITIONS = [
|
|
|
119
252
|
type: 'function',
|
|
120
253
|
function: {
|
|
121
254
|
name: 'list_dir',
|
|
122
|
-
description: 'List
|
|
255
|
+
description: 'List directory contents with file sizes and types.',
|
|
123
256
|
parameters: {
|
|
124
257
|
type: 'object',
|
|
125
|
-
properties: {
|
|
126
|
-
path: { type: 'string', description: 'Directory path' },
|
|
127
|
-
},
|
|
258
|
+
properties: { path: { type: 'string' } },
|
|
128
259
|
required: ['path'],
|
|
129
260
|
},
|
|
130
261
|
},
|
|
@@ -133,11 +264,12 @@ const TOOL_DEFINITIONS = [
|
|
|
133
264
|
type: 'function',
|
|
134
265
|
function: {
|
|
135
266
|
name: 'search_files',
|
|
136
|
-
description: '
|
|
267
|
+
description: 'Find files by glob pattern.',
|
|
137
268
|
parameters: {
|
|
138
269
|
type: 'object',
|
|
139
270
|
properties: {
|
|
140
|
-
pattern: { type: 'string'
|
|
271
|
+
pattern: { type: 'string' },
|
|
272
|
+
cwd: { type: 'string' },
|
|
141
273
|
},
|
|
142
274
|
required: ['pattern'],
|
|
143
275
|
},
|
|
@@ -151,8 +283,9 @@ const TOOL_DEFINITIONS = [
|
|
|
151
283
|
parameters: {
|
|
152
284
|
type: 'object',
|
|
153
285
|
properties: {
|
|
154
|
-
pattern: { type: 'string'
|
|
155
|
-
path: { type: 'string'
|
|
286
|
+
pattern: { type: 'string' },
|
|
287
|
+
path: { type: 'string' },
|
|
288
|
+
context: { type: 'number' },
|
|
156
289
|
},
|
|
157
290
|
required: ['pattern', 'path'],
|
|
158
291
|
},
|
|
@@ -166,7 +299,8 @@ const TOOL_DEFINITIONS = [
|
|
|
166
299
|
parameters: {
|
|
167
300
|
type: 'object',
|
|
168
301
|
properties: {
|
|
169
|
-
args: { type: 'string'
|
|
302
|
+
args: { type: 'string' },
|
|
303
|
+
cwd: { type: 'string' },
|
|
170
304
|
},
|
|
171
305
|
required: ['args'],
|
|
172
306
|
},
|
|
@@ -176,11 +310,12 @@ const TOOL_DEFINITIONS = [
|
|
|
176
310
|
type: 'function',
|
|
177
311
|
function: {
|
|
178
312
|
name: 'npm',
|
|
179
|
-
description: 'Run npm commands.',
|
|
313
|
+
description: 'Run npm/yarn/pnpm/bun commands.',
|
|
180
314
|
parameters: {
|
|
181
315
|
type: 'object',
|
|
182
316
|
properties: {
|
|
183
|
-
args: { type: 'string'
|
|
317
|
+
args: { type: 'string' },
|
|
318
|
+
cwd: { type: 'string' },
|
|
184
319
|
},
|
|
185
320
|
required: ['args'],
|
|
186
321
|
},
|
|
@@ -190,12 +325,25 @@ const TOOL_DEFINITIONS = [
|
|
|
190
325
|
type: 'function',
|
|
191
326
|
function: {
|
|
192
327
|
name: 'deploy',
|
|
193
|
-
description: 'Deploy to Vercel.',
|
|
328
|
+
description: 'Deploy to Vercel or Netlify.',
|
|
194
329
|
parameters: {
|
|
195
330
|
type: 'object',
|
|
196
331
|
properties: {
|
|
197
|
-
target: { type: 'string',
|
|
332
|
+
target: { type: 'string', enum: ['vercel', 'netlify'] },
|
|
333
|
+
cwd: { type: 'string' },
|
|
198
334
|
},
|
|
335
|
+
required: ['target'],
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
type: 'function',
|
|
341
|
+
function: {
|
|
342
|
+
name: 'detect_project',
|
|
343
|
+
description: 'Auto-detect project type, framework, and dependencies.',
|
|
344
|
+
parameters: {
|
|
345
|
+
type: 'object',
|
|
346
|
+
properties: { cwd: { type: 'string' } },
|
|
199
347
|
required: [],
|
|
200
348
|
},
|
|
201
349
|
},
|
|
@@ -203,109 +351,98 @@ const TOOL_DEFINITIONS = [
|
|
|
203
351
|
{
|
|
204
352
|
type: 'function',
|
|
205
353
|
function: {
|
|
206
|
-
name: '
|
|
207
|
-
description: '
|
|
354
|
+
name: 'get_file_tree',
|
|
355
|
+
description: 'Get a visual directory tree.',
|
|
208
356
|
parameters: {
|
|
209
357
|
type: 'object',
|
|
210
358
|
properties: {
|
|
211
|
-
|
|
359
|
+
path: { type: 'string' },
|
|
360
|
+
depth: { type: 'number' },
|
|
212
361
|
},
|
|
213
|
-
required: ['
|
|
362
|
+
required: ['path'],
|
|
214
363
|
},
|
|
215
364
|
},
|
|
216
365
|
},
|
|
217
366
|
];
|
|
218
|
-
|
|
367
|
+
// ── Agent Class ─────────────────────────────────────────────────────
|
|
368
|
+
export class Agent {
|
|
219
369
|
messages = [];
|
|
220
370
|
config;
|
|
221
371
|
model;
|
|
222
372
|
cwd;
|
|
223
373
|
autoApprove;
|
|
224
374
|
totalTokens = 0;
|
|
225
|
-
|
|
226
|
-
|
|
375
|
+
effort;
|
|
376
|
+
emitter;
|
|
377
|
+
constructor(config, model, cwd, autoApprove, effort = 'normal') {
|
|
227
378
|
this.config = config;
|
|
228
|
-
this.model = model
|
|
379
|
+
this.model = 'openrouter/owl-alpha'; // ALWAYS owl-alpha, model param is ignored
|
|
229
380
|
this.cwd = cwd;
|
|
230
381
|
this.autoApprove = autoApprove;
|
|
231
|
-
this.
|
|
382
|
+
this.effort = effort;
|
|
383
|
+
this.messages = [{ role: 'system', content: EFFORT_PROMPTS[effort] }];
|
|
384
|
+
}
|
|
385
|
+
on(event, handler) {
|
|
386
|
+
this.emitter = { handler };
|
|
387
|
+
}
|
|
388
|
+
emit(type, data) {
|
|
389
|
+
if (this.emitter)
|
|
390
|
+
this.emitter.handler({ type, ...data });
|
|
232
391
|
}
|
|
233
392
|
async run(prompt) {
|
|
234
393
|
this.messages.push({ role: 'user', content: prompt });
|
|
235
|
-
this.emit('
|
|
394
|
+
this.emit('thinking');
|
|
236
395
|
let iterations = 0;
|
|
237
|
-
const maxIterations = 50;
|
|
396
|
+
const maxIterations = this.effort === 'beast' ? 100 : this.effort === 'normal' ? 50 : 20;
|
|
238
397
|
while (iterations < maxIterations) {
|
|
239
398
|
iterations++;
|
|
240
|
-
const { content, toolCalls, tokens } = await
|
|
399
|
+
const { content, toolCalls, tokens } = await callLLM(this.config.openrouterKey, this.messages, TOOL_DEFINITIONS, (chunk) => this.emit('text', { content: chunk }), this.model);
|
|
241
400
|
this.totalTokens += tokens;
|
|
242
401
|
this.messages.push({ role: 'assistant', content });
|
|
243
402
|
if (toolCalls.length === 0) {
|
|
244
|
-
|
|
245
|
-
this.emit('event', { type: 'done', summary: content });
|
|
403
|
+
this.emit('done', { summary: content });
|
|
246
404
|
return content;
|
|
247
405
|
}
|
|
248
|
-
// Execute each tool call
|
|
249
406
|
for (const tc of toolCalls) {
|
|
250
407
|
const args = JSON.parse(tc.function.arguments || '{}');
|
|
251
|
-
this.emit('
|
|
408
|
+
this.emit('tool_start', { tool: tc.function.name, args: JSON.stringify(args) });
|
|
252
409
|
try {
|
|
253
410
|
const output = await this.executeTool(tc.function.name, args);
|
|
254
|
-
this.emit('
|
|
255
|
-
this.messages.push({
|
|
256
|
-
role: 'tool',
|
|
257
|
-
content: output,
|
|
258
|
-
tool_call_id: tc.id,
|
|
259
|
-
});
|
|
411
|
+
this.emit('tool_end', { tool: tc.function.name, output });
|
|
412
|
+
this.messages.push({ role: 'tool', content: output, tool_call_id: tc.id });
|
|
260
413
|
}
|
|
261
414
|
catch (e) {
|
|
262
415
|
const errMsg = e.message || String(e);
|
|
263
|
-
this.emit('
|
|
264
|
-
this.messages.push({
|
|
265
|
-
role: 'tool',
|
|
266
|
-
content: `Error: ${errMsg}`,
|
|
267
|
-
tool_call_id: tc.id,
|
|
268
|
-
});
|
|
416
|
+
this.emit('error', { message: errMsg });
|
|
417
|
+
this.messages.push({ role: 'tool', content: `Error: ${errMsg}`, tool_call_id: tc.id });
|
|
269
418
|
}
|
|
270
419
|
}
|
|
271
420
|
}
|
|
272
421
|
const summary = `Reached max iterations (${maxIterations}). Total tokens: ${this.totalTokens}`;
|
|
273
|
-
this.emit('
|
|
422
|
+
this.emit('done', { summary });
|
|
274
423
|
return summary;
|
|
275
424
|
}
|
|
276
425
|
async executeTool(name, args) {
|
|
426
|
+
const tools = await import('./tools/index.js');
|
|
427
|
+
const cwd = args.cwd || this.cwd;
|
|
277
428
|
switch (name) {
|
|
278
|
-
case '
|
|
279
|
-
|
|
280
|
-
case 'read_file':
|
|
281
|
-
return tools.readFile(args.path);
|
|
429
|
+
case 'run_command': return tools.runCommand(args.command, cwd, args.timeout || 120_000).stdout;
|
|
430
|
+
case 'read_file': return tools.readFile(args.path);
|
|
282
431
|
case 'write_file':
|
|
283
432
|
tools.writeFile(args.path, args.content);
|
|
284
|
-
return `Wrote ${args.content
|
|
433
|
+
return `Wrote ${args.content.length} chars to ${args.path}`;
|
|
285
434
|
case 'edit_file':
|
|
286
|
-
tools.editFile(args.path, args.
|
|
435
|
+
tools.editFile(args.path, args.replacements);
|
|
287
436
|
return `Edited ${args.path}`;
|
|
288
|
-
case 'list_dir':
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
case '
|
|
292
|
-
|
|
293
|
-
case '
|
|
294
|
-
|
|
295
|
-
case '
|
|
296
|
-
|
|
297
|
-
case 'npm':
|
|
298
|
-
return tools.npm(args.args, this.cwd);
|
|
299
|
-
case 'deploy':
|
|
300
|
-
return tools.deployVercel(this.cwd);
|
|
301
|
-
case 'ask':
|
|
302
|
-
if (this.autoApprove)
|
|
303
|
-
return 'yes';
|
|
304
|
-
return new Promise((resolve) => {
|
|
305
|
-
this.emit('event', { type: 'ask', question: args.question, resolve });
|
|
306
|
-
});
|
|
307
|
-
default:
|
|
308
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
437
|
+
case 'list_dir': return JSON.stringify(tools.listDir(args.path), null, 2);
|
|
438
|
+
case 'search_files': return tools.searchFiles(args.pattern, cwd).join('\n') || 'No files found';
|
|
439
|
+
case 'grep': return tools.grep(args.pattern, args.path, args.context || 2).join('\n') || 'No matches';
|
|
440
|
+
case 'git': return tools.git(args.args, cwd);
|
|
441
|
+
case 'npm': return tools.npm(args.args, cwd);
|
|
442
|
+
case 'deploy': return args.target === 'netlify' ? tools.deployNetlify(cwd) : tools.deployVercel(cwd);
|
|
443
|
+
case 'detect_project': return JSON.stringify(tools.detectProjectType(cwd), null, 2);
|
|
444
|
+
case 'get_file_tree': return tools.getFileTree(args.path, args.depth || 3);
|
|
445
|
+
default: throw new Error(`Unknown tool: ${name}`);
|
|
309
446
|
}
|
|
310
447
|
}
|
|
311
448
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
2
3
|
import { Command } from 'commander';
|
|
3
4
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
4
5
|
import { homedir } from 'os';
|
|
@@ -21,21 +22,17 @@ async function ensureConfig() {
|
|
|
21
22
|
const existing = await loadConfig();
|
|
22
23
|
if (existing)
|
|
23
24
|
return existing;
|
|
24
|
-
const defaults = {
|
|
25
|
-
openrouterKey: '',
|
|
26
|
-
defaultModel: 'openrouter/owl-alpha',
|
|
27
|
-
codingModel: 'moonshotai/kimi-k2.6',
|
|
28
|
-
fastModel: 'openai/gpt-oss-20b:free',
|
|
29
|
-
};
|
|
25
|
+
const defaults = { openrouterKey: '', defaultEffort: 'normal' };
|
|
30
26
|
writeFileSync(CONFIG_FILE, JSON.stringify(defaults, null, 2));
|
|
31
27
|
return defaults;
|
|
32
28
|
}
|
|
33
29
|
const program = new Command();
|
|
34
|
-
program.name('lumina').description('Lumina Code
|
|
30
|
+
program.name('lumina').description('Lumina Code — AI coding agent').version('1.1.0');
|
|
31
|
+
// Main command: lumina code
|
|
35
32
|
program.command('code')
|
|
36
33
|
.description('Start Lumina Code agent')
|
|
37
34
|
.argument('[prompt]', 'What you want to build')
|
|
38
|
-
.option('-
|
|
35
|
+
.option('-e, --effort <level>', 'Effort level: quick, normal, beast', 'normal')
|
|
39
36
|
.option('-y, --yes', 'Auto-approve all actions')
|
|
40
37
|
.option('--cwd <dir>', 'Working directory', process.cwd())
|
|
41
38
|
.action(async (prompt, opts) => {
|
|
@@ -46,31 +43,29 @@ program.command('code')
|
|
|
46
43
|
console.error(' Get a key at: https://openrouter.ai/keys\n');
|
|
47
44
|
process.exit(1);
|
|
48
45
|
}
|
|
49
|
-
|
|
50
|
-
const { TUIApp } =
|
|
51
|
-
const { render } =
|
|
52
|
-
const React =
|
|
53
|
-
render(React.createElement(TUIApp, {
|
|
54
|
-
prompt,
|
|
55
|
-
config,
|
|
56
|
-
model: opts.model || config.defaultModel || 'openrouter/owl-alpha',
|
|
57
|
-
autoApprove: opts.yes || false,
|
|
58
|
-
cwd: opts.cwd,
|
|
59
|
-
}));
|
|
46
|
+
const effort = ['quick', 'normal', 'beast'].includes(opts.effort) ? opts.effort : 'normal';
|
|
47
|
+
const { TUIApp } = await import('./tui/index.js');
|
|
48
|
+
const { render } = await import('ink');
|
|
49
|
+
const React = await import('react');
|
|
50
|
+
render(React.createElement(TUIApp, { prompt, config, effort, autoApprove: opts.yes || false, cwd: opts.cwd }));
|
|
60
51
|
});
|
|
61
|
-
|
|
52
|
+
// Config commands: lumina config, lumina config set <key> <value>
|
|
53
|
+
const configCmd = program.command('config').description('Manage configuration');
|
|
54
|
+
configCmd.action(async () => {
|
|
62
55
|
const config = await ensureConfig();
|
|
63
56
|
console.log('\n Lumina Code Configuration\n');
|
|
64
57
|
console.log(' Config:', CONFIG_FILE);
|
|
65
58
|
console.log(' API Key:', config.openrouterKey ? 'Set (' + config.openrouterKey.slice(0, 8) + '...)' : 'NOT SET');
|
|
66
|
-
console.log(' Default:', config.
|
|
67
|
-
console.log('
|
|
68
|
-
console.log('
|
|
59
|
+
console.log(' Default Effort:', config.defaultEffort || 'normal');
|
|
60
|
+
console.log('\n Commands:');
|
|
61
|
+
console.log(' lumina config set openrouter-key <key>');
|
|
62
|
+
console.log(' lumina config set default-effort <quick|normal|beast>\n');
|
|
69
63
|
});
|
|
70
|
-
|
|
64
|
+
configCmd.command('set <key> <value>')
|
|
65
|
+
.description('Set a config value')
|
|
66
|
+
.action(async (key, value) => {
|
|
71
67
|
const config = await ensureConfig();
|
|
72
|
-
|
|
73
|
-
config[map[key] || key] = value;
|
|
68
|
+
config[key] = value;
|
|
74
69
|
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
75
70
|
console.log(' Set', key, '=', value);
|
|
76
71
|
});
|
package/dist/tools/index.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { execSync, spawn } from 'child_process';
|
|
16
16
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, statSync, readdirSync, unlinkSync, renameSync, copyFileSync } from 'fs';
|
|
17
|
-
import { join, dirname, resolve } from 'path';
|
|
17
|
+
import { join, dirname, resolve, relative } from 'path';
|
|
18
18
|
// ── Shell Detection ─────────────────────────────────────────────────
|
|
19
19
|
export function getShell() {
|
|
20
20
|
if (process.platform === 'win32')
|
|
@@ -96,12 +96,33 @@ export function listDir(path) {
|
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
export function searchFiles(pattern, cwd) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
// Simple glob-like search using fs
|
|
100
|
+
const results = [];
|
|
101
|
+
const searchDir = (dir, depth) => {
|
|
102
|
+
if (depth > 5)
|
|
103
|
+
return;
|
|
104
|
+
try {
|
|
105
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
106
|
+
for (const entry of entries) {
|
|
107
|
+
if (entry.name.startsWith('.') || entry.name === 'node_modules' || entry.name === 'dist')
|
|
108
|
+
continue;
|
|
109
|
+
const fullPath = join(dir, entry.name);
|
|
110
|
+
if (entry.isDirectory()) {
|
|
111
|
+
searchDir(fullPath, depth + 1);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// Simple pattern matching
|
|
115
|
+
const regex = new RegExp(pattern.replace(/\*/g, '.*').replace(/\?/g, '.'), 'i');
|
|
116
|
+
if (regex.test(entry.name)) {
|
|
117
|
+
results.push(relative(cwd, fullPath));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch { /* ignore */ }
|
|
123
|
+
};
|
|
124
|
+
searchDir(cwd, 0);
|
|
125
|
+
return results;
|
|
105
126
|
}
|
|
106
127
|
export function grep(pattern, path, context = 2) {
|
|
107
128
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lumina-code-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Lumina Code - AI coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -10,10 +10,16 @@
|
|
|
10
10
|
"engines": { "node": ">=18.0.0" },
|
|
11
11
|
"scripts": { "build": "tsc --noEmit false", "prepublishOnly": "npm run build" },
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"commander": "^12.1.0",
|
|
14
|
-
"
|
|
13
|
+
"commander": "^12.1.0",
|
|
14
|
+
"ink": "^5.1.0",
|
|
15
|
+
"react": "^18.3.1",
|
|
16
|
+
"chalk": "^5.3.0",
|
|
17
|
+
"cross-spawn": "^7.0.3",
|
|
18
|
+
"node-fetch": "^3.3.2"
|
|
15
19
|
},
|
|
16
20
|
"devDependencies": {
|
|
17
|
-
"@types/node": "^22.10.0",
|
|
21
|
+
"@types/node": "^22.10.0",
|
|
22
|
+
"@types/cross-spawn": "^6.0.6",
|
|
23
|
+
"typescript": "^5.7.2"
|
|
18
24
|
}
|
|
19
25
|
}
|