@taj-special/dravix-code 1.1.27 → 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/cli/commands.js +34 -8
- package/dist/cli/index.js +24 -84
- package/dist/cli/repl.js +215 -65
- package/dist/services/ai.js +89 -11
- package/dist/services/auth.js +2 -2
- package/dist/services/context.js +107 -8
- package/dist/services/executor.js +244 -8
- package/dist/services/undo.js +181 -0
- package/dist/utils/display.js +58 -47
- package/package.json +1 -1
package/dist/cli/commands.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { execFileSync } from 'child_process';
|
|
2
2
|
import { buildContext } from '../services/context.js';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
3
|
import { banner, printHelp, printInfo, colors } from '../utils/display.js';
|
|
5
4
|
import { logout, getSavedUser, checkPlan } from '../services/auth.js';
|
|
5
|
+
import { undoLastSession, listUndoSessions } from '../services/undo.js';
|
|
6
6
|
export async function handleCommand(cmd, cwd, clearHistory, addFileToContext, getLastAI, retryLast) {
|
|
7
7
|
const parts = cmd.trim().split(/\s+/);
|
|
8
8
|
const name = parts[0].toLowerCase();
|
|
@@ -23,11 +23,11 @@ export async function handleCommand(cmd, cwd, clearHistory, addFileToContext, ge
|
|
|
23
23
|
}
|
|
24
24
|
const plan = email ? await checkPlan(email) : 'Free';
|
|
25
25
|
const planBadge = plan === 'Plus'
|
|
26
|
-
?
|
|
27
|
-
:
|
|
28
|
-
const W =
|
|
26
|
+
? colors.accent.bold('Plus')
|
|
27
|
+
: colors.muted('Free');
|
|
28
|
+
const W = colors.text;
|
|
29
29
|
process.stdout.write('\n ' + colors.success('✓') + ' ' + W(n) +
|
|
30
|
-
|
|
30
|
+
colors.subtext(' · ') + colors.muted(email ?? '') +
|
|
31
31
|
'\n ' + colors.muted(' Plan ') + planBadge + '\n\n');
|
|
32
32
|
return true;
|
|
33
33
|
}
|
|
@@ -40,9 +40,9 @@ export async function handleCommand(cmd, cwd, clearHistory, addFileToContext, ge
|
|
|
40
40
|
console.clear();
|
|
41
41
|
banner();
|
|
42
42
|
const { name: userName } = getSavedUser();
|
|
43
|
-
const C =
|
|
44
|
-
const DIM =
|
|
45
|
-
const W =
|
|
43
|
+
const C = colors.primary;
|
|
44
|
+
const DIM = colors.subtext;
|
|
45
|
+
const W = colors.text;
|
|
46
46
|
console.log(DIM(' ─────────────────────────────────────────────'));
|
|
47
47
|
console.log(colors.success(' ✓') + W(' New session started — your chat history is saved'));
|
|
48
48
|
console.log(colors.muted(' ') + colors.muted('Use ') + C('/resume') + colors.muted(' to return to any previous conversation'));
|
|
@@ -95,6 +95,32 @@ export async function handleCommand(cmd, cwd, clearHistory, addFileToContext, ge
|
|
|
95
95
|
colors.muted(' · by Taj Special\n\n'));
|
|
96
96
|
return true;
|
|
97
97
|
}
|
|
98
|
+
if (name === '/undo') {
|
|
99
|
+
const result = undoLastSession(cwd);
|
|
100
|
+
if (result.success) {
|
|
101
|
+
console.log('\n ' + colors.success('✓') + ' ' + colors.text(result.message) + '\n');
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
console.log('\n ' + colors.error('✗') + ' ' + colors.muted(result.message) + '\n');
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
if (name === '/history') {
|
|
109
|
+
const sessions = listUndoSessions();
|
|
110
|
+
if (sessions.length === 0) {
|
|
111
|
+
printInfo('No undo history found.');
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
console.log('\n ' + colors.primary('Undo History'));
|
|
115
|
+
console.log(' ' + colors.dim('─'.repeat(40)));
|
|
116
|
+
for (const s of sessions.slice(0, 10)) {
|
|
117
|
+
const time = new Date(s.timestamp).toLocaleString();
|
|
118
|
+
console.log(' ' + colors.muted('·') + ' ' + colors.text(time) + ' ' + colors.muted(`${s.ops} operation(s)`));
|
|
119
|
+
}
|
|
120
|
+
console.log('');
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
98
124
|
printInfo(`Unknown command: ${cmd} (type /help for list)`);
|
|
99
125
|
return true;
|
|
100
126
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -3,27 +3,15 @@ import * as path from 'path';
|
|
|
3
3
|
import { randomBytes } from 'crypto';
|
|
4
4
|
import { execSync } from 'child_process';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
|
-
import { banner, printHelp, printError, colors
|
|
6
|
+
import { banner, printHelp, printError, colors } from '../utils/display.js';
|
|
7
7
|
import { startRepl } from './repl.js';
|
|
8
8
|
import { isLoggedIn, logout, getSavedUser, saveConfig, checkPlan, AUTH_URL } from '../services/auth.js';
|
|
9
9
|
import { checkUsage, usageBar, fmtNum, formatResetTime } from '../services/usage.js';
|
|
10
|
-
const POLL_URL = 'https://dravix.app/cli-auth';
|
|
10
|
+
const POLL_URL = 'https://dravix.app/cli-auth.php';
|
|
11
11
|
const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
12
|
-
// OSC 8 terminal hyperlink — clickable in modern terminals
|
|
13
12
|
function link(url) {
|
|
14
13
|
return `\x1b]8;;${url}\x1b\\${url}\x1b]8;;\x1b\\`;
|
|
15
14
|
}
|
|
16
|
-
function openBrowser(url) {
|
|
17
|
-
try {
|
|
18
|
-
if (process.platform === 'win32')
|
|
19
|
-
execSync(`start "" "${url}"`, { stdio: 'ignore' });
|
|
20
|
-
else if (process.platform === 'darwin')
|
|
21
|
-
execSync(`open "${url}"`, { stdio: 'ignore' });
|
|
22
|
-
else
|
|
23
|
-
execSync(`xdg-open "${url}"`, { stdio: 'ignore' });
|
|
24
|
-
}
|
|
25
|
-
catch { /* ignore — user sees the URL */ }
|
|
26
|
-
}
|
|
27
15
|
async function pollSession(sessionId) {
|
|
28
16
|
try {
|
|
29
17
|
const res = await fetch(`${POLL_URL}?action=poll&session=${sessionId}`);
|
|
@@ -38,34 +26,18 @@ async function pollSession(sessionId) {
|
|
|
38
26
|
async function showWelcome() {
|
|
39
27
|
const cols = process.stdout.columns ?? 80;
|
|
40
28
|
const W = Math.min(cols, 64);
|
|
41
|
-
const P =
|
|
42
|
-
const PB =
|
|
43
|
-
const DIM =
|
|
44
|
-
const G =
|
|
45
|
-
const White =
|
|
46
|
-
const Muted =
|
|
29
|
+
const P = colors.primary;
|
|
30
|
+
const PB = colors.primary.bold;
|
|
31
|
+
const DIM = colors.muted;
|
|
32
|
+
const G = colors.success;
|
|
33
|
+
const White = colors.text;
|
|
34
|
+
const Muted = colors.muted;
|
|
47
35
|
const line = () => DIM(' ' + '─'.repeat(W - 4));
|
|
48
36
|
const pad = (s, w) => s + ' '.repeat(Math.max(w - s.length, 0));
|
|
49
37
|
console.clear();
|
|
50
|
-
|
|
51
|
-
console.log(chalk.hex('#6366f1').bold(`
|
|
52
|
-
██████╗ ██████╗ █████╗ ██╗ ██╗██╗██╗ ██╗
|
|
53
|
-
██╔══██╗██╔══██╗██╔══██╗██║ ██║██║╚██╗██╔╝
|
|
54
|
-
██║ ██║██████╔╝███████║██║ ██║██║ ╚███╔╝
|
|
55
|
-
██║ ██║██╔══██╗██╔══██║╚██╗ ██╔╝██║ ██╔██╗
|
|
56
|
-
██████╔╝██║ ██║██║ ██║ ╚████╔╝ ██║██╔╝ ██╗
|
|
57
|
-
╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═══╝ ╚═╝╚═╝ ╚═╝`));
|
|
58
|
-
console.log(PB(' Code') +
|
|
59
|
-
DIM(` v${VERSION}`) +
|
|
60
|
-
DIM(' ·') +
|
|
61
|
-
P(' AI-powered coding assistant') +
|
|
62
|
-
DIM(' ·') +
|
|
63
|
-
Muted(' by Taj Special'));
|
|
64
|
-
console.log(line() + '\n');
|
|
65
|
-
// ── Welcome ───────────────────────────────────────────────────
|
|
38
|
+
banner();
|
|
66
39
|
console.log(' ' + White.bold('Welcome to Dravix Code') + Muted(' — your AI coding partner'));
|
|
67
40
|
console.log(' ' + Muted('Works like Claude Code, Cursor, Copilot — but in your terminal.') + '\n');
|
|
68
|
-
// ── Features box ──────────────────────────────────────────────
|
|
69
41
|
const boxW = Math.min(W - 4, 58);
|
|
70
42
|
const inner = boxW - 2;
|
|
71
43
|
const BC = DIM;
|
|
@@ -83,13 +55,11 @@ async function showWelcome() {
|
|
|
83
55
|
console.log(row(G('✓'), 'Read files, folders and project structure'));
|
|
84
56
|
console.log(row(G('✓'), 'Works with TypeScript, Python, Go and more'));
|
|
85
57
|
console.log(' ' + BC('╰' + '─'.repeat(boxW - 2) + '╯') + '\n');
|
|
86
|
-
// ── Models ────────────────────────────────────────────────────
|
|
87
58
|
console.log(' ' + Muted('Powered by ') +
|
|
88
59
|
P.bold('Dravix 3 Titanium') +
|
|
89
60
|
Muted(' + ') +
|
|
90
61
|
P.bold('Dravix 3.5 Quantum'));
|
|
91
62
|
console.log(line() + '\n');
|
|
92
|
-
// ── CTA ───────────────────────────────────────────────────────
|
|
93
63
|
console.log(' ' + Muted('Sign in with your Google account to get started.') + '\n');
|
|
94
64
|
const enterKey = chalk.bgHex('#312e81').hex('#c7d2fe').bold(' Enter ');
|
|
95
65
|
const escKey = chalk.hex('#374151').bold(' Esc ');
|
|
@@ -121,21 +91,13 @@ async function showWelcome() {
|
|
|
121
91
|
async function browserAuth() {
|
|
122
92
|
const sessionId = randomBytes(16).toString('hex');
|
|
123
93
|
const authUrl = `${AUTH_URL}?session=${sessionId}`;
|
|
124
|
-
const DIM =
|
|
125
|
-
const W =
|
|
126
|
-
const P =
|
|
94
|
+
const DIM = colors.muted;
|
|
95
|
+
const W = colors.text;
|
|
96
|
+
const P = colors.primary;
|
|
127
97
|
const cols = process.stdout.columns ?? 80;
|
|
128
98
|
const line = DIM(' ' + '─'.repeat(Math.min(cols - 4, 51)));
|
|
129
99
|
console.clear();
|
|
130
|
-
|
|
131
|
-
██████╗ ██████╗ █████╗ ██╗ ██╗██╗██╗ ██╗
|
|
132
|
-
██╔══██╗██╔══██╗██╔══██╗██║ ██║██║╚██╗██╔╝
|
|
133
|
-
██║ ██║██████╔╝███████║██║ ██║██║ ╚███╔╝
|
|
134
|
-
██║ ██║██╔══██╗██╔══██║╚██╗ ██╔╝██║ ██╔██╗
|
|
135
|
-
██████╔╝██║ ██║██║ ██║ ╚████╔╝ ██║██╔╝ ██╗
|
|
136
|
-
╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═══╝ ╚═╝╚═╝ ╚═╝`));
|
|
137
|
-
console.log(chalk.hex('#6366f1').bold(' Code') + DIM(` v${VERSION} · `) + P('AI-powered coding assistant'));
|
|
138
|
-
console.log(line + '\n');
|
|
100
|
+
banner();
|
|
139
101
|
console.log(line);
|
|
140
102
|
console.log('\n ' + DIM('Step 1 — ') + W('Open this link in your browser:') + '\n');
|
|
141
103
|
console.log(' ' + colors.primary(link(authUrl)) + '\n');
|
|
@@ -145,14 +107,12 @@ async function browserAuth() {
|
|
|
145
107
|
let frameIdx = 0;
|
|
146
108
|
await new Promise((resolve, reject) => {
|
|
147
109
|
let done = false;
|
|
148
|
-
// Spinner runs fast (80ms)
|
|
149
110
|
const spinnerInterval = setInterval(() => {
|
|
150
111
|
if (done)
|
|
151
112
|
return;
|
|
152
113
|
process.stdout.write(`\r ${colors.muted(SPINNER[frameIdx % SPINNER.length])} ${colors.muted('Waiting for authentication...')}`);
|
|
153
114
|
frameIdx++;
|
|
154
115
|
}, 80);
|
|
155
|
-
// Polling runs every 2s
|
|
156
116
|
const poll = async () => {
|
|
157
117
|
if (done)
|
|
158
118
|
return;
|
|
@@ -162,10 +122,8 @@ async function browserAuth() {
|
|
|
162
122
|
clearInterval(spinnerInterval);
|
|
163
123
|
process.stdout.write('\r\x1b[K');
|
|
164
124
|
saveConfig({ token: result.token, name: result.name, email: result.email });
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
console.log(' ' + colors.success('✓') + ' ' + W2('Signed in as ') + colors.primary.bold(result.name) + DIM2(' · ') + colors.muted(result.email));
|
|
168
|
-
console.log(DIM2('\n ' + '─'.repeat(47)) + '\n');
|
|
125
|
+
console.log(' ' + colors.success('✓') + ' ' + W('Signed in as ') + colors.primary.bold(result.name) + DIM(' · ') + colors.muted(result.email));
|
|
126
|
+
console.log(DIM('\n ' + '─'.repeat(47)) + '\n');
|
|
169
127
|
resolve();
|
|
170
128
|
return;
|
|
171
129
|
}
|
|
@@ -183,7 +141,6 @@ async function browserAuth() {
|
|
|
183
141
|
});
|
|
184
142
|
}
|
|
185
143
|
async function main() {
|
|
186
|
-
// Ensure UTF-8 output on Windows
|
|
187
144
|
if (process.platform === 'win32') {
|
|
188
145
|
try {
|
|
189
146
|
execSync('chcp 65001', { stdio: 'ignore' });
|
|
@@ -218,48 +175,31 @@ async function main() {
|
|
|
218
175
|
else {
|
|
219
176
|
banner();
|
|
220
177
|
}
|
|
221
|
-
if (justAuthenticated) {
|
|
222
|
-
const _DIM = chalk.hex('#4b5563');
|
|
223
|
-
const _P = chalk.hex('#818cf8');
|
|
224
|
-
const _cols = process.stdout.columns ?? 80;
|
|
225
|
-
const _line = _DIM(' ' + '─'.repeat(Math.min(_cols - 4, 51)));
|
|
226
|
-
console.clear();
|
|
227
|
-
console.log(chalk.hex('#6366f1').bold(`
|
|
228
|
-
██████╗ ██████╗ █████╗ ██╗ ██╗██╗██╗ ██╗
|
|
229
|
-
██╔══██╗██╔══██╗██╔══██╗██║ ██║██║╚██╗██╔╝
|
|
230
|
-
██║ ██║██████╔╝███████║██║ ██║██║ ╚███╔╝
|
|
231
|
-
██║ ██║██╔══██╗██╔══██║╚██╗ ██╔╝██║ ██╔██╗
|
|
232
|
-
██████╔╝██║ ██║██║ ██║ ╚████╔╝ ██║██╔╝ ██╗
|
|
233
|
-
╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═══╝ ╚═╝╚═╝ ╚═╝`));
|
|
234
|
-
console.log(chalk.hex('#6366f1').bold(' Code') + _DIM(` v${VERSION} · `) + _P('AI-powered coding assistant'));
|
|
235
|
-
console.log(_line + '\n');
|
|
236
|
-
}
|
|
237
178
|
const { name, email } = getSavedUser();
|
|
238
179
|
const cwd = (arg && !arg.startsWith('--')) ? path.resolve(arg) : process.cwd();
|
|
239
|
-
// Fetch plan + usage in parallel
|
|
240
180
|
const token = (await import('../services/auth.js')).getToken() ?? '';
|
|
241
181
|
const [plan, usage] = await Promise.all([
|
|
242
182
|
email ? checkPlan(email) : Promise.resolve('Free'),
|
|
243
183
|
token ? checkUsage(token) : Promise.resolve(null),
|
|
244
184
|
]);
|
|
245
|
-
const C =
|
|
246
|
-
const DIM =
|
|
247
|
-
const W =
|
|
185
|
+
const C = colors.primary;
|
|
186
|
+
const DIM = colors.muted;
|
|
187
|
+
const W = colors.text;
|
|
248
188
|
const planBadge = plan === 'Plus'
|
|
249
|
-
?
|
|
250
|
-
:
|
|
189
|
+
? colors.accent.bold('Plus')
|
|
190
|
+
: colors.muted('Free');
|
|
251
191
|
console.log(DIM(' ' + '─'.repeat(45)));
|
|
252
192
|
console.log(colors.muted(' User ') + W(name ?? 'Unknown') + DIM(' · ') + colors.muted(email ?? ''));
|
|
253
193
|
console.log(colors.muted(' Plan ') + planBadge);
|
|
254
194
|
if (usage) {
|
|
255
195
|
const { bar, pct } = usageBar(usage.tokens_used, usage.limit);
|
|
256
|
-
const barColor = pct >= 80 ?
|
|
257
|
-
: pct >= 50 ?
|
|
258
|
-
:
|
|
196
|
+
const barColor = pct >= 80 ? colors.error
|
|
197
|
+
: pct >= 50 ? colors.warn
|
|
198
|
+
: colors.success;
|
|
259
199
|
const resetStr = formatResetTime(usage);
|
|
260
200
|
console.log(colors.muted(' Tokens ') +
|
|
261
201
|
barColor(bar) + ' ' +
|
|
262
|
-
|
|
202
|
+
colors.subtext(fmtNum(usage.tokens_used) + ' / ' + fmtNum(usage.limit)) +
|
|
263
203
|
DIM(' · resets in ' + resetStr));
|
|
264
204
|
}
|
|
265
205
|
console.log(colors.muted(' Project ') + W(path.basename(cwd)));
|