ispbills-icli 8.6.5 → 8.6.7
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/tui/app.js +1 -1
- package/src/tui/components.js +24 -15
- package/src/tui/run.js +71 -25
package/package.json
CHANGED
package/src/tui/app.js
CHANGED
|
@@ -1822,7 +1822,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
1822
1822
|
<${Box} flexDirection="column" width=${cols}>
|
|
1823
1823
|
<${Static} key=${clearEpoch} items=${staticItems}>
|
|
1824
1824
|
${(it) => it.type === 'banner'
|
|
1825
|
-
? html`<${Box} key=${it.id} flexDirection="column" alignItems="center">
|
|
1825
|
+
? html`<${Box} key=${it.id} flexDirection="column" alignItems="center" width=${cols}>
|
|
1826
1826
|
<${Banner} cfg=${cfg} model=${model} width=${cols} compact=${compact} streamerMode=${streamerMode} />
|
|
1827
1827
|
<//>`
|
|
1828
1828
|
: renderItem(it)}
|
package/src/tui/components.js
CHANGED
|
@@ -187,32 +187,41 @@ export function Banner({ cfg = {}, model, width = 80, compact = false, streamerM
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
return html`
|
|
190
|
-
<${Box} flexDirection="column" marginBottom=${1} alignItems="center">
|
|
190
|
+
<${Box} flexDirection="column" marginBottom=${1} alignItems="center" width=${width}>
|
|
191
191
|
${wide
|
|
192
|
-
? html`<${Box} flexDirection="column" alignItems="center">
|
|
192
|
+
? html`<${Box} flexDirection="column" alignItems="center" width=${width}>
|
|
193
193
|
${LOGO.map((l, i) => html`<${Text} key=${'l' + i} color=${C.accent} bold>${l}<//>`)}
|
|
194
|
-
<${Text} color=${C.muted}>iCopilot ${dash()} IspBills network engineer in your terminal<//>
|
|
195
194
|
<//>`
|
|
196
|
-
: html`<${Text} color=${C.accent} bold
|
|
197
|
-
|
|
195
|
+
: html`<${Text} color=${C.accent} bold>◈ iCopilot ${html`<${Text} color=${C.muted}>${dash()} IspBills AI terminal<//>`}<//>` }
|
|
196
|
+
|
|
197
|
+
${wide ? html`<${Text} color=${C.separator}>${'─'.repeat(Math.max(1, width))}<//>\n` : null}
|
|
198
|
+
|
|
199
|
+
<${Box} marginTop=${wide ? 0 : 1} justifyContent="center">
|
|
200
|
+
<${Text} color=${C.accent} bold>◈ iCopilot<//>
|
|
201
|
+
<${Text} color=${C.muted}> ${dash()} IspBills network engineer in your terminal<//>
|
|
202
|
+
<//>
|
|
203
|
+
|
|
204
|
+
${wide ? html`<${Text} color=${C.separator}>${'─'.repeat(Math.max(1, width))}<//>\n` : null}
|
|
205
|
+
|
|
206
|
+
${meta.length ? html`<${Box} marginTop=${1} justifyContent="center">
|
|
198
207
|
${meta.map(([label, val], i) => html`
|
|
199
208
|
<${Box} key=${'m' + i}>
|
|
200
209
|
${i > 0 ? html`<${Text} color=${C.muted}>${midDot()}<//>` : null}
|
|
201
210
|
<${Text} color=${C.muted}>${label} <//>
|
|
202
211
|
<${Text} color=${label === 'model' ? C.accent : C.brand}>${val}<//>
|
|
203
212
|
<//>`)}
|
|
213
|
+
<//>` : null}
|
|
214
|
+
|
|
215
|
+
${cfg.url ? html`<${Box} justifyContent="center"><${Text} color=${C.muted}>${cfg.url}<//><//>` : null}
|
|
216
|
+
|
|
217
|
+
<${Box} flexDirection="column" marginTop=${1} alignItems="center" width=${width}>
|
|
218
|
+
<${Box} paddingX=${2} flexDirection="column">
|
|
219
|
+
<${Text} color=${C.muted} dimColor> ${' @ '}${html`<${Text} color=${C.accent}>@<//>`} mention files · ${html`<${Text} color=${C.accent}>/<//>`} commands · ${html`<${Text} color=${C.accent}>?<//>`} help · ${html`<${Text} color=${C.accent}>!<//>` } shell<//>
|
|
220
|
+
<//>
|
|
204
221
|
<//>
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
<${Box} flexDirection="column" marginTop=${1} paddingX=${2} alignSelf="flex-start">
|
|
208
|
-
<${Text} color=${C.muted} bold>Quick start:<//>\n
|
|
209
|
-
<${Text} color=${C.muted}> <${Text} color=${C.accent}>@<//> mention files or devices<//>
|
|
210
|
-
<${Text} color=${C.muted}> <${Text} color=${C.accent}>/<//> slash commands<//>
|
|
211
|
-
<${Text} color=${C.muted}> <${Text} color=${C.accent}>?<//> quick help overlay<//>
|
|
212
|
-
<${Text} color=${C.muted}> <${Text} color=${C.accent}>!<//> run shell command<//>
|
|
213
|
-
<//>
|
|
222
|
+
|
|
214
223
|
${!isAuth
|
|
215
|
-
? html`<${Box} marginTop=${1}>
|
|
224
|
+
? html`<${Box} marginTop=${1} justifyContent="center">
|
|
216
225
|
<${Text} color=${C.warning}>⚠ Not authenticated — run <//>
|
|
217
226
|
<${Text} color=${C.slash} bold>/login<//>
|
|
218
227
|
<${Text} color=${C.warning}> to connect.<//><//>`
|
package/src/tui/run.js
CHANGED
|
@@ -4,39 +4,85 @@ import { render } from 'ink';
|
|
|
4
4
|
import { App } from './app.js';
|
|
5
5
|
import { saveConfig } from '../config.js';
|
|
6
6
|
|
|
7
|
+
// iCopilot wordmark in block letters
|
|
7
8
|
const LOGO = [
|
|
8
|
-
'██╗ ██████╗ ██████╗ ██████╗ ██╗██╗ ██████╗ ████████╗',
|
|
9
|
-
'██║██╔════╝██╔═══██╗██╔══██╗██║██║ ██╔═══██╗╚══██╔══╝',
|
|
10
|
-
'██║██║ ██║ ██║██████╔╝██║██║ ██║ ██║ ██║ ',
|
|
11
|
-
'██║██║ ██║ ██║██╔═══╝ ██║██║ ██║ ██║ ██║ ',
|
|
12
|
-
'██║╚██████╗╚██████╔╝██║ ██║███████╗╚██████╔╝ ██║ ',
|
|
13
|
-
'╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ',
|
|
9
|
+
' ██╗ ██████╗ ██████╗ ██████╗ ██╗██╗ ██████╗ ████████╗',
|
|
10
|
+
' ██║██╔════╝██╔═══██╗██╔══██╗██║██║ ██╔═══██╗╚══██╔══╝',
|
|
11
|
+
' ██║██║ ██║ ██║██████╔╝██║██║ ██║ ██║ ██║ ',
|
|
12
|
+
' ██║██║ ██║ ██║██╔═══╝ ██║██║ ██║ ██║ ██║ ',
|
|
13
|
+
' ██║╚██████╗╚██████╔╝██║ ██║███████╗╚██████╔╝ ██║ ',
|
|
14
|
+
' ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
// ANSI gradient: dim purple → bright purple → bright blue → bright cyan
|
|
18
|
+
const FRAMES = [
|
|
19
|
+
LOGO.map((l) => `\x1b[2;35m${l}\x1b[0m`), // dim magenta
|
|
20
|
+
LOGO.map((l) => `\x1b[1;35m${l}\x1b[0m`), // bold magenta
|
|
21
|
+
LOGO.map((l, i) => i < 3 ? `\x1b[1;35m${l}\x1b[0m` : `\x1b[1;34m${l}\x1b[0m`), // split
|
|
22
|
+
LOGO.map((l) => `\x1b[1;34m${l}\x1b[0m`), // bold blue
|
|
23
|
+
LOGO.map((l, i) => i < 3 ? `\x1b[1;34m${l}\x1b[0m` : `\x1b[1;36m${l}\x1b[0m`), // split
|
|
24
|
+
LOGO.map((l) => `\x1b[1;36m${l}\x1b[0m`), // bold cyan
|
|
25
|
+
LOGO.map((l) => `\x1b[1;35m${l}\x1b[0m`), // back to bold magenta
|
|
14
26
|
];
|
|
15
|
-
const COLORS = ['35', '95', '94', '96', '97'];
|
|
16
27
|
|
|
17
28
|
async function animateSplash(cfg = {}) {
|
|
18
29
|
if (!process.stdout.isTTY) return;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
const cols = process.stdout.columns || 80;
|
|
31
|
+
const logoW = LOGO[0].length;
|
|
32
|
+
const pad = ' '.repeat(Math.max(0, Math.floor((cols - logoW) / 2)));
|
|
33
|
+
|
|
34
|
+
// Phase 1: reveal lines one-by-one dim
|
|
35
|
+
for (let i = 0; i < LOGO.length; i++) {
|
|
36
|
+
process.stdout.write(`${pad}\x1b[2;35m${LOGO[i]}\x1b[0m\n`);
|
|
37
|
+
await new Promise((r) => setTimeout(r, 55));
|
|
25
38
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
|
|
40
|
+
// Phase 2: colour-cycle animation
|
|
41
|
+
for (let fi = 1; fi < FRAMES.length; fi++) {
|
|
42
|
+
process.stdout.write(`\x1b[${LOGO.length}A`);
|
|
43
|
+
for (const line of FRAMES[fi]) {
|
|
44
|
+
process.stdout.write(`${pad}${line}\n`);
|
|
45
|
+
}
|
|
46
|
+
await new Promise((r) => setTimeout(r, 90));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Welcome section — centered
|
|
50
|
+
const DIM = '\x1b[2m';
|
|
51
|
+
const BOLD = '\x1b[1m';
|
|
52
|
+
const ACC = '\x1b[38;5;141m'; // #A371F7 purple
|
|
53
|
+
const BLU = '\x1b[38;5;75m'; // #58A6FF blue
|
|
54
|
+
const WARN = '\x1b[38;5;179m'; // #D29922 amber
|
|
55
|
+
const SEP = '\x1b[38;5;237m'; // #30363D separator
|
|
56
|
+
const R = '\x1b[0m';
|
|
57
|
+
|
|
58
|
+
const hr = `${SEP}${'─'.repeat(cols)}${R}`;
|
|
59
|
+
const subtitle = `${ACC}◈ iCopilot${R} ${DIM}IspBills network engineer in your terminal${R}`;
|
|
60
|
+
const subtitleLen = 10 + 2 + 46; // approx visual length
|
|
61
|
+
const subPad = ' '.repeat(Math.max(0, Math.floor((cols - subtitleLen) / 2)));
|
|
62
|
+
|
|
63
|
+
process.stdout.write(`\n${hr}\n`);
|
|
64
|
+
process.stdout.write(`${subPad}${subtitle}\n`);
|
|
65
|
+
process.stdout.write(`${hr}\n\n`);
|
|
66
|
+
|
|
67
|
+
// Quick-start tips in a two-column grid, centered
|
|
68
|
+
const tips = [
|
|
69
|
+
[`${ACC}@${R}`, 'mention files, devices, ONUs'],
|
|
70
|
+
[`${ACC}/${R}`, 'slash commands & autocomplete'],
|
|
71
|
+
[`${ACC}?${R}`, 'quick help overlay'],
|
|
72
|
+
[`${ACC}!${R}`, 'run shell command directly'],
|
|
73
|
+
[`${BLU}Shift+Tab${R}`, 'cycle Ask → Plan → Autopilot'],
|
|
74
|
+
[`${BLU}Ctrl+T${R}`, 'toggle reasoning display'],
|
|
75
|
+
];
|
|
76
|
+
const tipW = 42;
|
|
77
|
+
const tipPad = ' '.repeat(Math.max(0, Math.floor((cols - tipW) / 2)));
|
|
78
|
+
process.stdout.write(`${tipPad}${DIM}Quick start:${R}\n`);
|
|
79
|
+
for (const [key, desc] of tips) {
|
|
80
|
+
process.stdout.write(`${tipPad} ${BOLD}${key}${R} ${DIM}${desc}${R}\n`);
|
|
81
|
+
}
|
|
82
|
+
|
|
37
83
|
const isAuth = Boolean(cfg?.user?.name || cfg?.user?.email || cfg?.apiKey || cfg?._token);
|
|
38
84
|
if (!isAuth) {
|
|
39
|
-
process.stdout.write(`\n
|
|
85
|
+
process.stdout.write(`\n${tipPad}${WARN}⚠ Not authenticated${R} ${DIM}run${R} ${ACC}/login${R} ${DIM}to connect${R}\n`);
|
|
40
86
|
}
|
|
41
87
|
process.stdout.write('\n');
|
|
42
88
|
}
|