clarity-ai 1.0.0 → 1.1.1
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/package.json +1 -1
- package/src/commands/index.js +5 -2
- package/src/index.js +1 -0
- package/src/providers/index.js +2 -2
- package/src/ui/banner.js +16 -6
- package/src/ui/blocks.js +83 -28
- package/src/ui/chatbox.js +26 -20
- package/src/ui/colors.js +24 -19
- package/src/ui/prompt.js +16 -12
- package/src/ui/spinner.js +43 -37
package/package.json
CHANGED
package/src/commands/index.js
CHANGED
|
@@ -12,6 +12,9 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSy
|
|
|
12
12
|
import { resolve, dirname, basename, extname, join } from 'path';
|
|
13
13
|
import readline from 'readline';
|
|
14
14
|
|
|
15
|
+
const PKG = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url)));
|
|
16
|
+
const VERSION = PKG.version;
|
|
17
|
+
|
|
15
18
|
const commandRegistry = {
|
|
16
19
|
async execute(input, context = {}) {
|
|
17
20
|
const parts = input.trim().split(/\s+/);
|
|
@@ -624,7 +627,7 @@ const commandRegistry = {
|
|
|
624
627
|
status() {
|
|
625
628
|
const mem = process.memoryUsage();
|
|
626
629
|
const rows = [
|
|
627
|
-
['CLARITY',
|
|
630
|
+
['CLARITY', `v${VERSION}`],
|
|
628
631
|
['Node.js', process.version],
|
|
629
632
|
['Platform', `${process.platform} ${process.arch}`],
|
|
630
633
|
['Termux', isTermux() ? 'Yes' : 'No'],
|
|
@@ -640,7 +643,7 @@ const commandRegistry = {
|
|
|
640
643
|
},
|
|
641
644
|
|
|
642
645
|
version() {
|
|
643
|
-
blocks.info(
|
|
646
|
+
blocks.info(`CLARITY v${VERSION}`, 'AI Agent CLI for Termux\nNode.js ' + process.version + '\n' + (isTermux() ? 'Termux mode: active' : 'Standard terminal'));
|
|
644
647
|
},
|
|
645
648
|
|
|
646
649
|
summarize(target) {
|
package/src/index.js
CHANGED
package/src/providers/index.js
CHANGED
|
@@ -18,11 +18,11 @@ const capabilities = {
|
|
|
18
18
|
openai: { free: false, streaming: true, models: ['gpt-4o-mini', 'gpt-4o', 'gpt-3.5-turbo'], baseURL: 'https://api.openai.com/v1' },
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
function sendMessage(apiKey, messages, model, stream = true) {
|
|
22
22
|
const [providerName] = model.split('/');
|
|
23
23
|
const provider = providers[providerName];
|
|
24
24
|
if (!provider) throw new Error(`Unknown provider: ${providerName}`);
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
const modelName = model.includes('/') ? model.slice(model.indexOf('/') + 1) : model;
|
|
27
27
|
return provider.sendMessage(apiKey, messages, modelName, stream);
|
|
28
28
|
}
|
package/src/ui/banner.js
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
import figlet from 'figlet';
|
|
2
2
|
import gradient from 'gradient-string';
|
|
3
|
-
import
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const PKG = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url)));
|
|
6
|
+
const VERSION = PKG.version;
|
|
7
|
+
const grad = gradient(['#00d2ff', '#7b2ff7', '#bb88ff']);
|
|
8
|
+
|
|
9
|
+
function center(text) {
|
|
10
|
+
const width = process.stdout.columns || 80;
|
|
11
|
+
const lines = text.split('\n');
|
|
12
|
+
return lines.map(l => ' '.repeat(Math.max(0, Math.floor((width - l.length) / 2))) + l).join('\n');
|
|
13
|
+
}
|
|
6
14
|
|
|
7
15
|
function renderBanner() {
|
|
8
|
-
const
|
|
9
|
-
console.log(
|
|
10
|
-
console.log(
|
|
11
|
-
console.log(
|
|
16
|
+
const ascii = figlet.textSync('CLARITY', { font: 'ANSI Shadow' });
|
|
17
|
+
console.log();
|
|
18
|
+
console.log(center(grad(ascii)));
|
|
19
|
+
console.log();
|
|
20
|
+
const tag = '✦ AI Agent CLI — v' + VERSION + ' ✦';
|
|
21
|
+
console.log(center(grad(tag)));
|
|
12
22
|
console.log();
|
|
13
23
|
}
|
|
14
24
|
|
package/src/ui/blocks.js
CHANGED
|
@@ -1,54 +1,109 @@
|
|
|
1
|
-
import boxen from 'boxen';
|
|
2
1
|
import cliTable3 from 'cli-table3';
|
|
3
2
|
import c from './colors.js';
|
|
4
3
|
|
|
4
|
+
function hr(char = '─', color = c.dim) {
|
|
5
|
+
const w = process.stdout.columns || 80;
|
|
6
|
+
console.log(color(char.repeat(w)));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function gap(n = 1) {
|
|
10
|
+
console.log('\n'.repeat(n - 1));
|
|
11
|
+
}
|
|
12
|
+
|
|
5
13
|
const blocks = {
|
|
6
|
-
info(title,
|
|
7
|
-
|
|
14
|
+
info(title, msg) {
|
|
15
|
+
gap();
|
|
16
|
+
console.log(c.info(` ┌── ℹ ${title} ${'─'.repeat(Math.max(0, (process.stdout.columns || 80) - title.length - 10))}┐`));
|
|
17
|
+
msg.split('\n').forEach(l => console.log(c.info(' │') + c.white(` ${l}`.padEnd((process.stdout.columns || 80) - 4)) + c.info('│')));
|
|
18
|
+
console.log(c.info(` └${'─'.repeat((process.stdout.columns || 80) - 4)}┘`));
|
|
19
|
+
gap();
|
|
8
20
|
},
|
|
9
|
-
|
|
10
|
-
|
|
21
|
+
|
|
22
|
+
success(title, msg) {
|
|
23
|
+
gap();
|
|
24
|
+
console.log(c.success(` ┌── ✓ ${title} ${'─'.repeat(Math.max(0, (process.stdout.columns || 80) - title.length - 10))}┐`));
|
|
25
|
+
msg.split('\n').forEach(l => console.log(c.success(' │') + c.white(` ${l}`.padEnd((process.stdout.columns || 80) - 4)) + c.success('│')));
|
|
26
|
+
console.log(c.success(` └${'─'.repeat((process.stdout.columns || 80) - 4)}┘`));
|
|
27
|
+
gap();
|
|
11
28
|
},
|
|
12
|
-
|
|
13
|
-
|
|
29
|
+
|
|
30
|
+
warn(title, msg) {
|
|
31
|
+
gap();
|
|
32
|
+
console.log(c.warning(` ┌── ⚠ ${title} ${'─'.repeat(Math.max(0, (process.stdout.columns || 80) - title.length - 10))}┐`));
|
|
33
|
+
msg.split('\n').forEach(l => console.log(c.warning(' │') + c.white(` ${l}`.padEnd((process.stdout.columns || 80) - 4)) + c.warning('│')));
|
|
34
|
+
console.log(c.warning(` └${'─'.repeat((process.stdout.columns || 80) - 4)}┘`));
|
|
35
|
+
gap();
|
|
14
36
|
},
|
|
15
|
-
|
|
16
|
-
|
|
37
|
+
|
|
38
|
+
error(title, msg) {
|
|
39
|
+
gap();
|
|
40
|
+
console.log(c.error(` ┌── ✗ ${title} ${'─'.repeat(Math.max(0, (process.stdout.columns || 80) - title.length - 10))}┐`));
|
|
41
|
+
msg.split('\n').forEach(l => console.log(c.error(' │') + c.white(` ${l}`.padEnd((process.stdout.columns || 80) - 4)) + c.error('│')));
|
|
42
|
+
console.log(c.error(` └${'─'.repeat((process.stdout.columns || 80) - 4)}┘`));
|
|
43
|
+
gap();
|
|
17
44
|
},
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
console.log(c.
|
|
21
|
-
console.log(
|
|
45
|
+
|
|
46
|
+
code(lang, code) {
|
|
47
|
+
console.log(c.dim(` ┌─ ${lang} ${'─'.repeat(Math.max(0, (process.stdout.columns || 80) - lang.length - 8))}`));
|
|
48
|
+
code.split('\n').forEach(l => console.log(c.code(` │ ${l}`)));
|
|
49
|
+
console.log(c.dim(` └${'─'.repeat((process.stdout.columns || 80) - 4)}`));
|
|
22
50
|
},
|
|
51
|
+
|
|
23
52
|
file(path, content) {
|
|
24
|
-
console.log(
|
|
53
|
+
console.log(c.filename(` ┌─ ${path}`));
|
|
54
|
+
content.split('\n').forEach(l => console.log(c.white(` │ ${l}`)));
|
|
55
|
+
console.log(c.dim(` └${'─'.repeat((process.stdout.columns || 80) - 4)}`));
|
|
25
56
|
},
|
|
26
|
-
|
|
27
|
-
|
|
57
|
+
|
|
58
|
+
ai(msg) {
|
|
59
|
+
const w = process.stdout.columns || 80;
|
|
60
|
+
console.log(c.accent(` ╔${'═'.repeat(w - 4)}╗`));
|
|
61
|
+
msg.split('\n').forEach(l => console.log(c.accent(' ║') + c.ai(` ${l}`.padEnd(w - 4)) + c.accent('║')));
|
|
62
|
+
console.log(c.accent(` ╚${'═'.repeat(w - 4)}╝`));
|
|
63
|
+
gap();
|
|
28
64
|
},
|
|
29
|
-
|
|
30
|
-
|
|
65
|
+
|
|
66
|
+
user(msg) {
|
|
67
|
+
const w = process.stdout.columns || 80;
|
|
68
|
+
console.log(c.primary(` ┌${'─'.repeat(w - 4)}┐`));
|
|
69
|
+
msg.split('\n').forEach(l => console.log(c.primary(' │') + c.user(` ${l}`.padEnd(w - 4)) + c.primary('│')));
|
|
70
|
+
console.log(c.primary(` └${'─'.repeat(w - 4)}┘`));
|
|
71
|
+
gap();
|
|
31
72
|
},
|
|
73
|
+
|
|
32
74
|
table(headers, rows) {
|
|
33
|
-
const t = new cliTable3({
|
|
34
|
-
|
|
75
|
+
const t = new cliTable3({
|
|
76
|
+
head: headers.map(h => c.primary(h)),
|
|
77
|
+
style: { head: [], border: ['#2a2a4a'] },
|
|
78
|
+
chars: { 'top': '─', 'top-mid': '┬', 'top-left': '┌', 'top-right': '┐',
|
|
79
|
+
'bottom': '─', 'bottom-mid': '┴', 'bottom-left': '└', 'bottom-right': '┘',
|
|
80
|
+
'left': '│', 'left-mid': '├', 'mid': '─', 'mid-mid': '┼',
|
|
81
|
+
'right': '│', 'right-mid': '┤' }
|
|
82
|
+
});
|
|
83
|
+
rows.forEach(r => t.push(r.map(v => c.white(String(v)))));
|
|
35
84
|
console.log(t.toString());
|
|
36
85
|
},
|
|
86
|
+
|
|
37
87
|
divider(label) {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
88
|
+
const w = process.stdout.columns || 80;
|
|
89
|
+
if (label) {
|
|
90
|
+
const side = Math.floor((w - label.length - 4) / 2);
|
|
91
|
+
console.log(c.dim(` ${'─'.repeat(side)} ${label} ${'─'.repeat(side)}`));
|
|
92
|
+
} else {
|
|
93
|
+
hr();
|
|
94
|
+
}
|
|
41
95
|
},
|
|
96
|
+
|
|
42
97
|
badge(text, color = 'cyan') {
|
|
43
98
|
const colors = { cyan: c.primary, purple: c.accent, green: c.success, yellow: c.warning, red: c.error };
|
|
44
99
|
return (colors[color] || c.primary)(`[${text}]`);
|
|
45
100
|
},
|
|
101
|
+
|
|
46
102
|
progress(label, pct) {
|
|
47
|
-
const
|
|
48
|
-
const filled = Math.round(
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
console.log(`${c.muted(label)} ${c.primary(bar)} ${c.white(String(pct))}%`);
|
|
103
|
+
const w = 20;
|
|
104
|
+
const filled = Math.round(w * pct / 100);
|
|
105
|
+
const bar = c.primary('█'.repeat(filled)) + c.dim('░'.repeat(w - filled));
|
|
106
|
+
console.log(` ${c.muted(label)} ${bar} ${c.white(String(pct))}%`);
|
|
52
107
|
}
|
|
53
108
|
};
|
|
54
109
|
|
package/src/ui/chatbox.js
CHANGED
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
import readline from 'readline';
|
|
2
1
|
import c from './colors.js';
|
|
3
2
|
import renderBanner from './banner.js';
|
|
4
3
|
import settings from '../config/settings.js';
|
|
5
4
|
import { hasAnyKeys } from '../config/keys.js';
|
|
6
5
|
import { getKey, PROVIDER_NAMES } from '../config/keys.js';
|
|
7
6
|
import { sendMessage } from '../providers/index.js';
|
|
8
|
-
import { createPrompt, addToHistory, loadHistory } from './prompt.js';
|
|
7
|
+
import { createPrompt, showPrompt, addToHistory, loadHistory } from './prompt.js';
|
|
9
8
|
import blocks from './blocks.js';
|
|
10
9
|
import spin from './spinner.js';
|
|
11
|
-
import { renderMarkdown } from '../utils/markdown.js';
|
|
12
10
|
import commandRegistry from '../commands/index.js';
|
|
13
11
|
import memory from '../memory/store.js';
|
|
14
12
|
|
|
15
13
|
let rl = null;
|
|
16
14
|
let conversation = [];
|
|
17
15
|
|
|
18
|
-
function
|
|
16
|
+
function renderHeader() {
|
|
19
17
|
const model = settings.get('defaultModel') || 'groq/llama3-70b-8192';
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
18
|
+
const w = process.stdout.columns || 80;
|
|
19
|
+
const left = c.accent('◈');
|
|
20
|
+
const mid = c.muted(` ${model} `);
|
|
21
|
+
const right = c.muted('/help');
|
|
22
|
+
const total = 6 + mid.length + right.length + 2;
|
|
23
|
+
const pad = '.'.repeat(Math.max(0, w - total - 4));
|
|
24
|
+
console.log(c.border(` ${left}${c.dim(pad)}${mid}${c.dim(pad)}${right}`));
|
|
25
|
+
blocks.divider();
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
function startChat() {
|
|
@@ -31,27 +34,27 @@ function startChat() {
|
|
|
31
34
|
loadHistory();
|
|
32
35
|
console.clear();
|
|
33
36
|
renderBanner();
|
|
34
|
-
|
|
37
|
+
renderHeader();
|
|
35
38
|
console.log();
|
|
36
39
|
|
|
37
40
|
rl = createPrompt();
|
|
38
|
-
|
|
41
|
+
showPrompt();
|
|
39
42
|
|
|
40
43
|
rl.on('line', async (line) => {
|
|
41
44
|
const input = line.trim();
|
|
42
|
-
if (!input) {
|
|
45
|
+
if (!input) { showPrompt(); return; }
|
|
43
46
|
|
|
44
47
|
addToHistory(input);
|
|
45
48
|
|
|
46
49
|
if (input.startsWith('/')) {
|
|
47
|
-
const result = await commandRegistry.execute(input, { rl, conversation });
|
|
50
|
+
const result = await commandRegistry.execute(input, { rl, conversation, showPrompt });
|
|
48
51
|
if (result?.exit) { closeChat(); return; }
|
|
49
52
|
} else {
|
|
50
53
|
conversation.push({ role: 'user', content: input });
|
|
51
54
|
blocks.user(input);
|
|
52
55
|
await handleAIResponse();
|
|
53
56
|
}
|
|
54
|
-
|
|
57
|
+
showPrompt();
|
|
55
58
|
});
|
|
56
59
|
|
|
57
60
|
rl.on('close', () => {
|
|
@@ -61,7 +64,7 @@ function startChat() {
|
|
|
61
64
|
|
|
62
65
|
rl.on('SIGINT', () => {
|
|
63
66
|
console.log(c.muted('\nUse /exit to quit'));
|
|
64
|
-
|
|
67
|
+
showPrompt();
|
|
65
68
|
});
|
|
66
69
|
}
|
|
67
70
|
|
|
@@ -85,23 +88,26 @@ async function handleAIResponse() {
|
|
|
85
88
|
|
|
86
89
|
if (settings.get('stream')) {
|
|
87
90
|
spin.stop();
|
|
88
|
-
process.stdout.
|
|
91
|
+
const w = process.stdout.columns || 80;
|
|
92
|
+
console.log(c.accent(` ╔${'═'.repeat(w - 4)}╗`));
|
|
93
|
+
process.stdout.write(c.accent(' ║ ') + c.ai('CLARITY ') + c.white(''));
|
|
89
94
|
let full = '';
|
|
90
95
|
for await (const chunk of stream) {
|
|
91
96
|
full += chunk;
|
|
92
97
|
process.stdout.write(c.white(chunk));
|
|
93
98
|
}
|
|
94
|
-
|
|
99
|
+
console.log();
|
|
100
|
+
console.log(c.accent(` ╚${'═'.repeat(w - 4)}╝`));
|
|
101
|
+
console.log();
|
|
95
102
|
conversation.push({ role: 'assistant', content: full });
|
|
96
103
|
memory.add(conversation);
|
|
97
104
|
} else {
|
|
105
|
+
spin.stop();
|
|
98
106
|
let full = '';
|
|
99
107
|
for await (const chunk of stream) {
|
|
100
108
|
full += chunk;
|
|
101
109
|
}
|
|
102
|
-
|
|
103
|
-
const rendered = renderMarkdown(full);
|
|
104
|
-
blocks.ai(rendered);
|
|
110
|
+
blocks.ai(full);
|
|
105
111
|
conversation.push({ role: 'assistant', content: full });
|
|
106
112
|
memory.add(conversation);
|
|
107
113
|
}
|
|
@@ -109,7 +115,7 @@ async function handleAIResponse() {
|
|
|
109
115
|
if (settings.get('showTokens')) {
|
|
110
116
|
const inTokens = Math.ceil(conversation.reduce((s, m) => s + m.content.length, 0) / 4);
|
|
111
117
|
const outTokens = Math.ceil(conversation.filter(m => m.role === 'assistant').reduce((s, m) => s + m.content.length, 0) / 4);
|
|
112
|
-
console.log(c.
|
|
118
|
+
console.log(c.dim(` tokens: ${inTokens} in / ${outTokens} out • free`));
|
|
113
119
|
}
|
|
114
120
|
} catch (err) {
|
|
115
121
|
spin.fail('Error');
|
|
@@ -119,7 +125,7 @@ async function handleAIResponse() {
|
|
|
119
125
|
|
|
120
126
|
function closeChat() {
|
|
121
127
|
if (rl) rl.close();
|
|
122
|
-
console.log(c.muted('\
|
|
128
|
+
console.log(c.muted('\nGoodbye!'));
|
|
123
129
|
process.exit(0);
|
|
124
130
|
}
|
|
125
131
|
|
package/src/ui/colors.js
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
2
|
+
|
|
3
|
+
const c = {
|
|
4
|
+
primary: chalk.hex('#00d2ff'),
|
|
5
|
+
accent: chalk.hex('#7b2ff7'),
|
|
6
|
+
success: chalk.hex('#00ff88'),
|
|
7
|
+
warning: chalk.hex('#ffcc00'),
|
|
8
|
+
error: chalk.hex('#ff4466'),
|
|
9
|
+
info: chalk.hex('#44aaff'),
|
|
10
|
+
muted: chalk.hex('#555577'),
|
|
11
|
+
white: chalk.hex('#e0e0ff'),
|
|
12
|
+
user: chalk.bold.hex('#00d2ff'),
|
|
13
|
+
ai: chalk.bold.hex('#bb88ff'),
|
|
14
|
+
system: chalk.italic.hex('#666888'),
|
|
15
|
+
code: chalk.hex('#aaffcc'),
|
|
16
|
+
filename: chalk.underline.hex('#ffcc66'),
|
|
17
|
+
cmd: chalk.bold.hex('#ff8844'),
|
|
18
|
+
bgError: chalk.bgHex('#1a0008').hex('#ff4466'),
|
|
19
|
+
bgSuccess: chalk.bgHex('#001a0a').hex('#00ff88'),
|
|
20
|
+
bgInfo: chalk.bgHex('#000d1a').hex('#44aaff'),
|
|
21
|
+
bgWarn: chalk.bgHex('#1a1500').hex('#ffcc00'),
|
|
22
|
+
border: chalk.hex('#2a2a4a'),
|
|
23
|
+
glow: chalk.hex('#3a3a6a'),
|
|
24
|
+
dim: chalk.hex('#3a3a5a'),
|
|
21
25
|
};
|
|
26
|
+
|
|
22
27
|
export default c;
|
package/src/ui/prompt.js
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
import readline from 'readline';
|
|
2
|
-
import {
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
3
|
+
import { dirname } from 'path';
|
|
3
4
|
import paths from '../config/paths.js';
|
|
4
5
|
import c from './colors.js';
|
|
5
6
|
|
|
6
7
|
const HISTORY_FILE = paths.history;
|
|
7
8
|
const MAX_HISTORY = 500;
|
|
8
|
-
|
|
9
9
|
let history = [];
|
|
10
10
|
|
|
11
11
|
function loadHistory() {
|
|
12
12
|
try {
|
|
13
13
|
if (existsSync(HISTORY_FILE)) {
|
|
14
|
-
|
|
15
|
-
history = data.split('\n').filter(Boolean).slice(-MAX_HISTORY);
|
|
14
|
+
history = readFileSync(HISTORY_FILE, 'utf8').split('\n').filter(Boolean).slice(-MAX_HISTORY);
|
|
16
15
|
}
|
|
17
16
|
} catch {}
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
function saveHistory() {
|
|
21
20
|
try {
|
|
22
|
-
const dir =
|
|
23
|
-
if (!existsSync(dir))
|
|
24
|
-
|
|
21
|
+
const dir = dirname(HISTORY_FILE);
|
|
22
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
23
|
+
writeFileSync(HISTORY_FILE, history.slice(-MAX_HISTORY).join('\n'));
|
|
25
24
|
} catch {}
|
|
26
25
|
}
|
|
27
26
|
|
|
@@ -33,17 +32,22 @@ function addToHistory(line) {
|
|
|
33
32
|
}
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
function createPrompt(
|
|
35
|
+
function createPrompt() {
|
|
36
|
+
loadHistory();
|
|
37
37
|
const rl = readline.createInterface({
|
|
38
38
|
input: process.stdin,
|
|
39
39
|
output: process.stdout,
|
|
40
|
-
history
|
|
40
|
+
history,
|
|
41
41
|
historySize: MAX_HISTORY,
|
|
42
42
|
terminal: true,
|
|
43
|
-
prompt:
|
|
43
|
+
prompt: '',
|
|
44
44
|
});
|
|
45
|
-
|
|
46
45
|
return rl;
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
|
|
48
|
+
function showPrompt() {
|
|
49
|
+
const prefix = c.primary('◇');
|
|
50
|
+
process.stdout.write(` ${prefix} `);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { createPrompt, showPrompt, addToHistory, loadHistory, history };
|
package/src/ui/spinner.js
CHANGED
|
@@ -1,43 +1,49 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { isTermux } from '../utils/termux.js';
|
|
1
|
+
import c from './colors.js';
|
|
3
2
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
: ['|','/','-','\\'];
|
|
3
|
+
const frames = ['◐', '◓', '◑', '◒'];
|
|
4
|
+
let interval = null;
|
|
5
|
+
let currentText = '';
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
function start(text) {
|
|
8
|
+
stop();
|
|
9
|
+
currentText = text;
|
|
10
|
+
let i = 0;
|
|
11
|
+
process.stdout.write(c.accent(frames[i]) + c.muted(` ${text}`));
|
|
12
|
+
interval = setInterval(() => {
|
|
13
|
+
i = (i + 1) % frames.length;
|
|
14
|
+
process.stdout.clearLine(0);
|
|
15
|
+
process.stdout.cursorTo(0);
|
|
16
|
+
process.stdout.write(c.accent(frames[i]) + c.muted(` ${currentText}`));
|
|
17
|
+
}, 120);
|
|
18
|
+
return spin;
|
|
19
|
+
}
|
|
10
20
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
stop() {
|
|
18
|
-
if (spinner) { spinner.stop(); spinner = null; }
|
|
19
|
-
return spin;
|
|
20
|
-
},
|
|
21
|
-
succeed(text) {
|
|
22
|
-
if (spinner) { spinner.succeed(text); spinner = null; }
|
|
23
|
-
return spin;
|
|
24
|
-
},
|
|
25
|
-
fail(text) {
|
|
26
|
-
if (spinner) { spinner.fail(text); spinner = null; }
|
|
27
|
-
return spin;
|
|
28
|
-
},
|
|
29
|
-
info(text) {
|
|
30
|
-
if (spinner) { spinner.info(text); spinner = null; }
|
|
31
|
-
return spin;
|
|
32
|
-
},
|
|
33
|
-
warn(text) {
|
|
34
|
-
if (spinner) { spinner.warn(text); spinner = null; }
|
|
35
|
-
return spin;
|
|
36
|
-
},
|
|
37
|
-
update(text) {
|
|
38
|
-
if (spinner) spinner.text = text;
|
|
39
|
-
return spin;
|
|
21
|
+
function stop() {
|
|
22
|
+
if (interval) {
|
|
23
|
+
clearInterval(interval);
|
|
24
|
+
interval = null;
|
|
25
|
+
process.stdout.clearLine(0);
|
|
26
|
+
process.stdout.cursorTo(0);
|
|
40
27
|
}
|
|
41
|
-
|
|
28
|
+
return spin;
|
|
29
|
+
}
|
|
42
30
|
|
|
31
|
+
function succeed(text) {
|
|
32
|
+
stop();
|
|
33
|
+
if (text) console.log(c.success(` ✓ ${text}`));
|
|
34
|
+
return spin;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function fail(text) {
|
|
38
|
+
stop();
|
|
39
|
+
if (text) console.log(c.error(` ✗ ${text}`));
|
|
40
|
+
return spin;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function update(text) {
|
|
44
|
+
currentText = text;
|
|
45
|
+
return spin;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const spin = { start, stop, succeed, fail, update };
|
|
43
49
|
export default spin;
|