lumina-code-agent 1.5.0 → 1.6.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/index.js +89 -165
- package/package.json +3 -7
package/dist/index.js
CHANGED
|
@@ -1,30 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// @ts-nocheck
|
|
3
|
-
// Check if we have a proper TTY for the TUI
|
|
4
|
-
const hasTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
5
|
-
if (!hasTTY) {
|
|
6
|
-
// Non-TUI mode: just show help
|
|
7
|
-
console.log('');
|
|
8
|
-
console.log(' ⚡ LUMINA CODE — AI Coding Agent');
|
|
9
|
-
console.log('');
|
|
10
|
-
console.log(' Lumina Code requires a proper terminal (TTY) to run.');
|
|
11
|
-
console.log(' Please open one of these and type: lumina');
|
|
12
|
-
console.log('');
|
|
13
|
-
console.log(' • Windows Terminal (recommended)');
|
|
14
|
-
console.log(' • PowerShell');
|
|
15
|
-
console.log(' • Command Prompt (cmd.exe)');
|
|
16
|
-
console.log(' • iTerm2 / Terminal.app (macOS)');
|
|
17
|
-
console.log(' • Any Linux terminal');
|
|
18
|
-
console.log('');
|
|
19
|
-
console.log(' If you\'re in Git Bash, try running from Windows Terminal instead.');
|
|
20
|
-
console.log('');
|
|
21
|
-
process.exit(0);
|
|
22
|
-
}
|
|
23
|
-
import React, { useState, useCallback, useRef } from 'react';
|
|
24
|
-
import { Box, Text, useInput, useApp, Spacer } from 'ink';
|
|
25
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from 'fs';
|
|
26
4
|
import { homedir } from 'os';
|
|
27
5
|
import { join, dirname, resolve, relative } from 'path';
|
|
6
|
+
import { createInterface } from 'readline';
|
|
7
|
+
import { execSync } from 'child_process';
|
|
28
8
|
const CONFIG_DIR = join(homedir(), '.lumina');
|
|
29
9
|
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
30
10
|
function loadConfig() {
|
|
@@ -42,68 +22,59 @@ function saveConfig(config) {
|
|
|
42
22
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
43
23
|
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
44
24
|
}
|
|
45
|
-
|
|
46
|
-
function
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
25
|
+
const rl = createInterface({ input: process.stdin, output: stdout });
|
|
26
|
+
function ask(question) {
|
|
27
|
+
return new Promise(resolve => rl.question(question, resolve));
|
|
28
|
+
}
|
|
29
|
+
async function onboarding() {
|
|
30
|
+
console.log('');
|
|
31
|
+
console.log(' ⚡ LUMINA CODE — AI Coding Agent');
|
|
32
|
+
console.log(' Better than Claude Code. Better than Codex.');
|
|
33
|
+
console.log('');
|
|
34
|
+
console.log(' Welcome! Let\'s get you set up.');
|
|
35
|
+
console.log('');
|
|
36
|
+
const apiKey = await ask(' Enter your OpenRouter API key: ');
|
|
37
|
+
if (!apiKey.trim() || apiKey.trim().length < 10) {
|
|
38
|
+
console.log(' ❌ Invalid API key. Please try again.');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
const name = await ask(' What should I call you? (optional): ');
|
|
42
|
+
saveConfig({ openrouterKey: apiKey.trim(), userName: name.trim() || 'User' });
|
|
43
|
+
console.log('');
|
|
44
|
+
console.log(' ✓ Setup complete! Let\'s build something amazing.');
|
|
45
|
+
console.log('');
|
|
46
|
+
}
|
|
47
|
+
async function chat(config) {
|
|
48
|
+
console.log(' Type what you want to build. I\'ll handle the rest.');
|
|
49
|
+
console.log(' Commands: /help /clear /exit');
|
|
50
|
+
console.log('');
|
|
51
|
+
let messages = [];
|
|
52
|
+
while (true) {
|
|
53
|
+
const input = await ask(' > ');
|
|
54
|
+
const trimmed = input.trim();
|
|
55
|
+
if (!trimmed)
|
|
56
|
+
continue;
|
|
57
|
+
if (trimmed === '/exit' || trimmed === '/quit')
|
|
58
|
+
break;
|
|
59
|
+
if (trimmed === '/clear') {
|
|
60
|
+
messages = [];
|
|
61
|
+
console.log(' ✓ Cleared.');
|
|
62
|
+
continue;
|
|
68
63
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (step === 2)
|
|
73
|
-
setName(v => v + input);
|
|
64
|
+
if (trimmed === '/help') {
|
|
65
|
+
console.log(' Commands: /help /clear /exit');
|
|
66
|
+
continue;
|
|
74
67
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
// ── Chat Screen ─────────────────────────────────────────────────────
|
|
79
|
-
function ChatScreen({ config }) {
|
|
80
|
-
const { exit } = useApp();
|
|
81
|
-
const [messages, setMessages] = useState([]);
|
|
82
|
-
const [input, setInput] = useState('');
|
|
83
|
-
const [status, setStatus] = useState('Ready');
|
|
84
|
-
const [thinking, setThinking] = useState(false);
|
|
85
|
-
const scrollRef = useRef(0);
|
|
86
|
-
const visibleMessages = messages.slice(-50);
|
|
87
|
-
const handleSubmit = useCallback(async (text) => {
|
|
88
|
-
const trimmed = text.trim();
|
|
89
|
-
if (!trimmed || thinking)
|
|
90
|
-
return;
|
|
91
|
-
setInput('');
|
|
92
|
-
setThinking(true);
|
|
93
|
-
setStatus('Thinking...');
|
|
94
|
-
scrollRef.current++;
|
|
95
|
-
const userMsg = { role: 'user', content: trimmed };
|
|
96
|
-
const newMessages = [...messages, userMsg];
|
|
97
|
-
setMessages(newMessages);
|
|
68
|
+
messages.push({ role: 'user', content: trimmed });
|
|
69
|
+
console.log('');
|
|
98
70
|
try {
|
|
99
|
-
const OPENROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions';
|
|
100
71
|
const tools = [
|
|
101
72
|
{ type: 'function', function: { name: 'run_command', description: 'Run any shell command', parameters: { type: 'object', properties: { command: { type: 'string' }, cwd: { type: 'string' }, timeout: { type: 'number' } }, required: ['command'] } } },
|
|
102
|
-
{ type: 'function', function: { name: 'read_file', description: 'Read file contents
|
|
103
|
-
{ type: 'function', function: { name: 'write_file', description: 'Create or overwrite a file
|
|
104
|
-
{ type: 'function', function: { name: 'edit_file', description: 'Make precise edits to a file
|
|
73
|
+
{ type: 'function', function: { name: 'read_file', description: 'Read file contents', parameters: { type: 'object', properties: { path: { type: 'string' } }, required: ['path'] } } },
|
|
74
|
+
{ type: 'function', function: { name: 'write_file', description: 'Create or overwrite a file', parameters: { type: 'object', properties: { path: { type: 'string' }, content: { type: 'string' } }, required: ['path', 'content'] } } },
|
|
75
|
+
{ type: 'function', function: { name: 'edit_file', description: 'Make precise edits to a file', parameters: { type: 'object', properties: { path: { type: 'string' }, search: { type: 'string' }, replace: { type: 'string' } }, required: ['path', 'search', 'replace'] } } },
|
|
105
76
|
{ type: 'function', function: { name: 'list_dir', description: 'List directory contents', parameters: { type: 'object', properties: { path: { type: 'string' } }, required: ['path'] } } },
|
|
106
|
-
{ type: 'function', function: { name: 'search_files', description: 'Find files by
|
|
77
|
+
{ type: 'function', function: { name: 'search_files', description: 'Find files by pattern', parameters: { type: 'object', properties: { pattern: { type: 'string' }, cwd: { type: 'string' } }, required: ['pattern'] } } },
|
|
107
78
|
{ type: 'function', function: { name: 'grep', description: 'Search file contents', parameters: { type: 'object', properties: { pattern: { type: 'string' }, path: { type: 'string' } }, required: ['pattern', 'path'] } } },
|
|
108
79
|
{ type: 'function', function: { name: 'git', description: 'Run git commands', parameters: { type: 'object', properties: { args: { type: 'string' }, cwd: { type: 'string' } }, required: ['args'] } } },
|
|
109
80
|
{ type: 'function', function: { name: 'npm', description: 'Run npm/yarn/pnpm/bun commands', parameters: { type: 'object', properties: { args: { type: 'string' }, cwd: { type: 'string' } }, required: ['args'] } } },
|
|
@@ -111,19 +82,17 @@ function ChatScreen({ config }) {
|
|
|
111
82
|
];
|
|
112
83
|
let iterations = 0;
|
|
113
84
|
const maxIterations = 30;
|
|
114
|
-
let currentMessages = [...
|
|
85
|
+
let currentMessages = [...messages];
|
|
115
86
|
while (iterations < maxIterations) {
|
|
116
87
|
iterations++;
|
|
117
|
-
|
|
118
|
-
const res = await fetch(
|
|
88
|
+
process.stdout.write(` ⏳ Working (step ${iterations})...\r`);
|
|
89
|
+
const res = await fetch('https://openrouter.ai/api/v1/chat/completions', {
|
|
119
90
|
method: 'POST',
|
|
120
91
|
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.openrouterKey}`, 'HTTP-Referer': 'https://luminaai.co.in', 'X-Title': 'Lumina Code' },
|
|
121
92
|
body: JSON.stringify({
|
|
122
93
|
model: 'openrouter/owl-alpha',
|
|
123
94
|
messages: [{ role: 'system', content: `You are LUMINA CODE — an elite AI coding agent.
|
|
124
95
|
|
|
125
|
-
MODEL: openrouter/owl-alpha (1M+ context, best reasoning)
|
|
126
|
-
|
|
127
96
|
WORKFLOW:
|
|
128
97
|
1. PLAN: Analyze the task. Create a brief plan.
|
|
129
98
|
2. ACT: Execute tools step by step. Read before writing.
|
|
@@ -131,23 +100,10 @@ WORKFLOW:
|
|
|
131
100
|
4. FIX: If something fails, debug and fix immediately.
|
|
132
101
|
5. DEPLOY: If requested, deploy automatically.
|
|
133
102
|
|
|
134
|
-
QUALITY
|
|
135
|
-
|
|
136
|
-
- TypeScript with proper types (never use 'any')
|
|
137
|
-
- Error handling everywhere
|
|
138
|
-
- Responsive design (320px to 2560px)
|
|
139
|
-
- Accessible (semantic HTML, ARIA, keyboard navigation)
|
|
140
|
-
- Clean architecture, modern patterns
|
|
141
|
-
- Beautiful UI (consistent spacing, typography, color)
|
|
103
|
+
QUALITY: Production-grade code. No placeholders. No TODOs. No emoji in code.
|
|
104
|
+
Handle errors. TypeScript. Responsive. Accessible. Clean architecture.
|
|
142
105
|
|
|
143
|
-
FORBIDDEN:
|
|
144
|
-
- Lorem ipsum or placeholder content
|
|
145
|
-
- TODO/FIXME comments in production code
|
|
146
|
-
- Emoji in code or UI
|
|
147
|
-
- var keyword (always let/const)
|
|
148
|
-
- any type in TypeScript
|
|
149
|
-
- Skipping error handling
|
|
150
|
-
- Hardcoded secrets
|
|
106
|
+
FORBIDDEN: lorem ipsum, TODO comments, emoji in code, var keyword, any type, skipping error handling, hardcoded secrets.
|
|
151
107
|
|
|
152
108
|
When using a tool, output ONLY:
|
|
153
109
|
TOOL: <name>
|
|
@@ -171,30 +127,29 @@ Working directory: ${process.cwd()}` }, ...currentMessages],
|
|
|
171
127
|
const content = choice.message?.content || '';
|
|
172
128
|
const toolCalls = choice.message?.tool_calls || [];
|
|
173
129
|
currentMessages.push({ role: 'assistant', content });
|
|
174
|
-
setMessages([...currentMessages]);
|
|
175
|
-
scrollRef.current++;
|
|
176
130
|
if (toolCalls.length === 0) {
|
|
177
|
-
|
|
131
|
+
messages = currentMessages;
|
|
132
|
+
console.log(' ✓ ' + content.slice(0, 500));
|
|
133
|
+
if (content.length > 500)
|
|
134
|
+
console.log(' ...');
|
|
135
|
+
console.log('');
|
|
178
136
|
break;
|
|
179
137
|
}
|
|
180
138
|
for (const tc of toolCalls) {
|
|
181
139
|
const args = JSON.parse(tc.function.arguments || '{}');
|
|
182
140
|
const toolName = tc.function.name;
|
|
183
|
-
|
|
184
|
-
scrollRef.current++;
|
|
141
|
+
console.log(` ⚙ ${toolName}(${JSON.stringify(args).slice(0, 80)})`);
|
|
185
142
|
let output = '';
|
|
186
143
|
try {
|
|
187
|
-
const { execSync } = await import('child_process');
|
|
188
144
|
switch (toolName) {
|
|
189
145
|
case 'run_command': {
|
|
190
146
|
const cwd = args.cwd || process.cwd();
|
|
191
147
|
output = execSync(args.command, { cwd, encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024, timeout: args.timeout || 120000, shell: true }) || '(no output)';
|
|
192
148
|
break;
|
|
193
149
|
}
|
|
194
|
-
case 'read_file':
|
|
150
|
+
case 'read_file':
|
|
195
151
|
output = readFileSync(args.path, 'utf-8');
|
|
196
152
|
break;
|
|
197
|
-
}
|
|
198
153
|
case 'write_file': {
|
|
199
154
|
const dir = dirname(resolve(args.path));
|
|
200
155
|
if (!existsSync(dir))
|
|
@@ -204,19 +159,17 @@ Working directory: ${process.cwd()}` }, ...currentMessages],
|
|
|
204
159
|
break;
|
|
205
160
|
}
|
|
206
161
|
case 'edit_file': {
|
|
207
|
-
let
|
|
208
|
-
if (!
|
|
209
|
-
throw new Error(`
|
|
210
|
-
|
|
211
|
-
writeFileSync(args.path,
|
|
162
|
+
let fc = readFileSync(args.path, 'utf-8');
|
|
163
|
+
if (!fc.includes(args.search))
|
|
164
|
+
throw new Error(`Not found: "${args.search.slice(0, 50)}"`);
|
|
165
|
+
fc = fc.replace(args.search, args.replace);
|
|
166
|
+
writeFileSync(args.path, fc, 'utf-8');
|
|
212
167
|
output = `Edited ${args.path}`;
|
|
213
168
|
break;
|
|
214
169
|
}
|
|
215
|
-
case 'list_dir':
|
|
216
|
-
|
|
217
|
-
output = entries.map(e => `${e.isDirectory() ? '📁' : '📄'} ${e.name}`).join('\n');
|
|
170
|
+
case 'list_dir':
|
|
171
|
+
output = readdirSync(args.path, { withFileTypes: true }).map(e => `${e.isDirectory() ? '📁' : '📄'} ${e.name}`).join('\n');
|
|
218
172
|
break;
|
|
219
|
-
}
|
|
220
173
|
case 'search_files': {
|
|
221
174
|
const results = [];
|
|
222
175
|
const search = (dir, depth) => {
|
|
@@ -224,7 +177,7 @@ Working directory: ${process.cwd()}` }, ...currentMessages],
|
|
|
224
177
|
return;
|
|
225
178
|
try {
|
|
226
179
|
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
227
|
-
if (e.name.startsWith('.') || e.name === 'node_modules'
|
|
180
|
+
if (e.name.startsWith('.') || e.name === 'node_modules')
|
|
228
181
|
continue;
|
|
229
182
|
const fp = join(dir, e.name);
|
|
230
183
|
if (e.isDirectory())
|
|
@@ -240,76 +193,47 @@ Working directory: ${process.cwd()}` }, ...currentMessages],
|
|
|
240
193
|
break;
|
|
241
194
|
}
|
|
242
195
|
case 'grep': {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
const regex = new RegExp(args.pattern, 'gi');
|
|
246
|
-
output = lines.map((l, i) => regex.test(l) ? `${i + 1}: ${l}` : null).filter(Boolean).join('\n') || 'No matches';
|
|
196
|
+
const c = readFileSync(args.path, 'utf-8');
|
|
197
|
+
output = c.split('\n').map((l, i) => new RegExp(args.pattern, 'gi').test(l) ? `${i + 1}: ${l}` : null).filter(Boolean).join('\n') || 'No matches';
|
|
247
198
|
break;
|
|
248
199
|
}
|
|
249
|
-
case 'git':
|
|
200
|
+
case 'git':
|
|
250
201
|
output = execSync(`git ${args.args}`, { cwd: args.cwd || process.cwd(), encoding: 'utf-8', maxBuffer: 1024 * 1024 }) || '(ok)';
|
|
251
202
|
break;
|
|
252
|
-
}
|
|
253
203
|
case 'npm': {
|
|
254
204
|
const pm = existsSync(join(args.cwd || process.cwd(), 'bun.lockb')) ? 'bun' : existsSync(join(args.cwd || process.cwd(), 'yarn.lock')) ? 'yarn' : 'npm';
|
|
255
205
|
output = execSync(`${pm} ${args.args}`, { cwd: args.cwd || process.cwd(), encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024, timeout: 120000 }) || '(ok)';
|
|
256
206
|
break;
|
|
257
207
|
}
|
|
258
|
-
case 'deploy':
|
|
208
|
+
case 'deploy':
|
|
259
209
|
output = execSync('npx vercel deploy --prod --yes', { cwd: args.cwd || process.cwd(), encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024, timeout: 300000 }) || '(deployed)';
|
|
260
210
|
break;
|
|
261
|
-
}
|
|
262
|
-
default:
|
|
263
|
-
output = `Unknown tool: ${toolName}`;
|
|
211
|
+
default: output = `Unknown tool: ${toolName}`;
|
|
264
212
|
}
|
|
265
213
|
}
|
|
266
214
|
catch (e) {
|
|
267
215
|
output = `Error: ${e.message}`;
|
|
268
216
|
}
|
|
269
217
|
currentMessages.push({ role: 'tool', content: output.slice(0, 2000), tool_call_id: tc.id });
|
|
270
|
-
|
|
271
|
-
scrollRef.current++;
|
|
218
|
+
console.log(` ✓ ${output.slice(0, 100)}`);
|
|
272
219
|
}
|
|
273
220
|
}
|
|
274
|
-
if (iterations >= maxIterations)
|
|
275
|
-
setStatus('Reached max iterations');
|
|
276
221
|
}
|
|
277
222
|
catch (e) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
setThinking(false);
|
|
282
|
-
}, [input, thinking, messages, config]);
|
|
283
|
-
useInput((input, key) => {
|
|
284
|
-
if (key.ctrl && input === 'c')
|
|
285
|
-
exit();
|
|
286
|
-
if (key.ctrl && input === 'd')
|
|
287
|
-
exit();
|
|
288
|
-
if (key.return) {
|
|
289
|
-
handleSubmit(input);
|
|
290
|
-
}
|
|
291
|
-
else if (key.backspace || key.delete) {
|
|
292
|
-
setInput(v => v.slice(0, -1));
|
|
293
|
-
}
|
|
294
|
-
else if (!key.ctrl && !key.meta) {
|
|
295
|
-
setInput(v => v + input);
|
|
223
|
+
console.log(` ⚠ Error: ${e.message}`);
|
|
224
|
+
console.log('');
|
|
296
225
|
}
|
|
226
|
+
}
|
|
227
|
+
rl.close();
|
|
228
|
+
}
|
|
229
|
+
// ── Main ────────────────────────────────────────────────────────────
|
|
230
|
+
const config = loadConfig();
|
|
231
|
+
if (!config?.openrouterKey) {
|
|
232
|
+
onboarding().then(() => {
|
|
233
|
+
const newConfig = loadConfig();
|
|
234
|
+
chat(newConfig).then(() => process.exit(0));
|
|
297
235
|
});
|
|
298
|
-
return React.createElement(Box, { flexDirection: 'column', height: '100%' }, React.createElement(Box, { borderStyle: 'round', borderColor: '#7C5CFC', paddingX: 2, paddingY: 1 }, React.createElement(Text, { bold: true, color: '#7C5CFC' }, ' ⚡ LUMINA CODE'), React.createElement(Spacer, null), React.createElement(Text, { color: '#52525B' }, thinking ? ' ⏳ ' + status : ' ● ' + status)), React.createElement(Box, { flexDirection: 'column', flexGrow: 1, paddingX: 2, paddingY: 1, overflowY: 'hidden' }, visibleMessages.map((m, i) => {
|
|
299
|
-
if (m.role === 'user') {
|
|
300
|
-
return React.createElement(Box, { key: i, marginTop: 1 }, React.createElement(Text, { color: '#7C5CFC', bold: true }, '> '), React.createElement(Text, { color: '#FAFAFA' }, m.content));
|
|
301
|
-
}
|
|
302
|
-
if (m.role === 'tool') {
|
|
303
|
-
return React.createElement(Box, { key: i, marginTop: 0, paddingLeft: 2 }, React.createElement(Text, { color: '#52525B' }, ' ' + m.content.slice(0, 200)));
|
|
304
|
-
}
|
|
305
|
-
return React.createElement(Box, { key: i, marginTop: 1, paddingLeft: 2 }, React.createElement(Text, { color: '#A1A1AA' }, m.content.slice(0, 500)));
|
|
306
|
-
}), thinking && React.createElement(Text, { color: '#F59E0B' }, ' ⏳ thinking...')), React.createElement(Box, { borderStyle: 'single', borderColor: '#3F3F46', paddingX: 1 }, React.createElement(Text, { color: '#7C5CFC' }, ' > '), React.createElement(Text, { color: '#FAFAFA' }, input || 'What do you want to build?'), React.createElement(Text, { color: '#52525B' }, '▌')), React.createElement(Box, { paddingX: 2 }, React.createElement(Text, { color: '#3F3F46' }, ' Ctrl+C to exit | OWL-Alpha ')));
|
|
307
236
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const config = loadConfig();
|
|
311
|
-
if (!config?.openrouterKey) {
|
|
312
|
-
return React.createElement(Onboarding, { onComplete: () => { } });
|
|
313
|
-
}
|
|
314
|
-
return React.createElement(ChatScreen, { config });
|
|
237
|
+
else {
|
|
238
|
+
chat(config).then(() => process.exit(0));
|
|
315
239
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lumina-code-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Lumina Code - AI coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -9,13 +9,9 @@
|
|
|
9
9
|
"files": ["dist/", "README.md"],
|
|
10
10
|
"engines": { "node": ">=18.0.0" },
|
|
11
11
|
"scripts": { "build": "tsc --noEmit false", "prepublishOnly": "npm run build" },
|
|
12
|
-
"dependencies": {
|
|
13
|
-
"ink": "^5.1.0",
|
|
14
|
-
"react": "^18.3.1",
|
|
15
|
-
"chalk": "^5.3.0"
|
|
16
|
-
},
|
|
12
|
+
"dependencies": {},
|
|
17
13
|
"devDependencies": {
|
|
18
|
-
"@types/
|
|
14
|
+
"@types/node": "^22.10.0",
|
|
19
15
|
"typescript": "^5.7.2"
|
|
20
16
|
}
|
|
21
17
|
}
|