ispbills-icli 8.7.8 → 8.7.10
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/banner.js +3 -3
- package/src/commands.js +2 -2
- package/src/tui/app.js +22 -30
- package/src/tui/components.js +6 -6
- package/src/tui/run.js +2 -2
package/package.json
CHANGED
package/src/banner.js
CHANGED
|
@@ -13,7 +13,7 @@ const LOGO = [
|
|
|
13
13
|
const LOGO_WIDTH = Math.max(...LOGO.map((l) => l.length));
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Full
|
|
16
|
+
* Full iCopilot banner. On narrow terminals falls back to a compact header.
|
|
17
17
|
* A full-width rule frames the header so it uses the whole window.
|
|
18
18
|
*
|
|
19
19
|
* @param {object} cfg Loaded config ({ url, user, _model }).
|
|
@@ -26,9 +26,9 @@ export function printBanner(cfg = {}, opts = {}) {
|
|
|
26
26
|
console.log();
|
|
27
27
|
if (width >= LOGO_WIDTH) {
|
|
28
28
|
for (const line of LOGO) console.log(ACCENT + BOLD + line + RESET);
|
|
29
|
-
console.log(` ${DIM}
|
|
29
|
+
console.log(` ${DIM}iCopilot — network engineer in your terminal${RESET}`);
|
|
30
30
|
} else {
|
|
31
|
-
console.log(` ${BOLD}
|
|
31
|
+
console.log(` ${BOLD}iCopilot${RESET} ${DIM}— IspBills AI terminal${RESET}`);
|
|
32
32
|
}
|
|
33
33
|
console.log();
|
|
34
34
|
|
package/src/commands.js
CHANGED
|
@@ -121,9 +121,9 @@ export const SLASH_COMMANDS = [
|
|
|
121
121
|
{ cmd: '/bug', hint: '', desc: 'Report a bug (alias for /feedback)', group: 'Help', local: true },
|
|
122
122
|
{ cmd: '/update', hint: '', desc: 'Update iCli to the latest version', group: 'Help', local: true },
|
|
123
123
|
{ cmd: '/downgrade', hint: 'VERSION', desc: 'Roll back to a specific CLI version', group: 'Help', local: true },
|
|
124
|
-
{ cmd: '/app', hint: '', desc: 'Show instructions to open the
|
|
124
|
+
{ cmd: '/app', hint: '', desc: 'Show instructions to open the iCopilot web app', group: 'Help', local: true },
|
|
125
125
|
{ cmd: '/user', hint: '', desc: 'Manage GitHub user list', group: 'Help', local: true },
|
|
126
|
-
{ cmd: '/login', hint: '', desc: 'Log in to
|
|
126
|
+
{ cmd: '/login', hint: '', desc: 'Log in to iCopilot', group: 'Help', local: true },
|
|
127
127
|
{ cmd: '/whoami', hint: '', desc: 'Show current user info', group: 'Help', local: true },
|
|
128
128
|
{ cmd: '/clikit', hint: '[component]', desc: 'Preview CLI UI components', group: 'Help', local: true },
|
|
129
129
|
{ cmd: '/extensions', hint: '[manage|mode]', desc: 'Manage CLI extensions', group: 'Help', local: true },
|
package/src/tui/app.js
CHANGED
|
@@ -439,7 +439,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
439
439
|
const [deviceError, setDeviceError] = useState(null);
|
|
440
440
|
const chipsRows = (!busy && chips.length && !choice && !search && !sessionPicker && !diffState) ? 1 : 0;
|
|
441
441
|
const composerRows = 2;
|
|
442
|
-
const chromeRows = 2 + composerRows + 1 + chipsRows +
|
|
442
|
+
const chromeRows = 2 + composerRows + 1 + chipsRows + 1; // tabBar + composer + sep + chips + 1 footer row
|
|
443
443
|
const viewportRows = Math.max(3, rows - chromeRows);
|
|
444
444
|
const scrollPage = Math.max(4, viewportRows - 2);
|
|
445
445
|
|
|
@@ -916,7 +916,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
916
916
|
options: [
|
|
917
917
|
{ label: '1. Yes', value: TOOL_APPROVAL_ONCE },
|
|
918
918
|
{ label: `2. Yes, and approve ${toolName} for the rest of the session`, value: TOOL_APPROVAL_SESSION },
|
|
919
|
-
{ label: '3. No, and tell
|
|
919
|
+
{ label: '3. No, and tell iCopilot what to do differently (Esc)', value: null },
|
|
920
920
|
],
|
|
921
921
|
});
|
|
922
922
|
} else if (type === 'prompt' || type === 'choice') {
|
|
@@ -1685,7 +1685,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
1685
1685
|
return;
|
|
1686
1686
|
}
|
|
1687
1687
|
if (q === '/app') {
|
|
1688
|
-
pushNotice('
|
|
1688
|
+
pushNotice('iCopilot web app — open your IspBills instance in the browser with /o or by typing the URL.', C.muted);
|
|
1689
1689
|
return;
|
|
1690
1690
|
}
|
|
1691
1691
|
if (q === '/user' || q.startsWith('/user ')) {
|
|
@@ -1776,7 +1776,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
1776
1776
|
if (value == null) {
|
|
1777
1777
|
if (currentChoice?.isToolApproval || /⚙ Tool request|tool request|approval|shell:/i.test(`${currentChoice?.title || ''} ${currentChoice?.note || ''}`)) {
|
|
1778
1778
|
setChoice({
|
|
1779
|
-
title: 'Tell
|
|
1779
|
+
title: 'Tell iCopilot what to do differently:',
|
|
1780
1780
|
note: '',
|
|
1781
1781
|
sel: 0,
|
|
1782
1782
|
text: '',
|
|
@@ -2133,23 +2133,23 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
2133
2133
|
const tokenCount = approxTokens(convo.current);
|
|
2134
2134
|
const tokenLabel = contextUsageLabel(tokenCount);
|
|
2135
2135
|
const modelLabel = streamerMode ? '' : shortModel(model || modelRef.current || 'server default');
|
|
2136
|
-
// §8:
|
|
2137
|
-
const
|
|
2136
|
+
// §8: single footer row (GH Copilot CLI style) — cwd·branch on left, mode·model·tokens on right
|
|
2137
|
+
const modeLabel = mode === 'autopilot' ? 'AUTOPILOT' : mode === 'plan' ? 'PLAN' : null;
|
|
2138
|
+
const footerRightEstLen = (modeLabel ? modeLabel.length + 3 : 0) + (modelLabel.length || 0) + (tokenLabel.length || 0) + 8;
|
|
2138
2139
|
const cwdMaxLen = Math.max(12, cols - footerRightEstLen - (branch ? branch.length + 6 : 0) - 4);
|
|
2139
2140
|
const cwd = shortenPath(process.cwd(), cwdMaxLen);
|
|
2140
|
-
const footerLeft =
|
|
2141
|
-
|
|
2142
|
-
// Status row: working indicator when busy, key hints when idle, hint message when set
|
|
2143
|
-
const footerStatusLeft = busy
|
|
2144
|
-
? `${glyphs.spinner} Working\u2026`
|
|
2141
|
+
const footerLeft = busy
|
|
2142
|
+
? `${glyphs.arrow} Working\u2026`
|
|
2145
2143
|
: hint
|
|
2146
2144
|
? hint
|
|
2147
|
-
:
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2145
|
+
: [cwd, branch ? `${glyphs.gitBranch}${branch}` : null].filter(Boolean).join(midDot());
|
|
2146
|
+
const footerLeftColor = busy ? C.warning : hint ? C.accent : C.muted;
|
|
2147
|
+
const footerRight = busy
|
|
2148
|
+
? `Ctrl+C cancel`
|
|
2149
|
+
: streamerMode
|
|
2150
|
+
? ''
|
|
2151
|
+
: [modeLabel, modelLabel, tokenLabel].filter(Boolean).join(midDot());
|
|
2152
|
+
const footerRightColor = busy ? C.warning : mode === 'autopilot' ? C.warning : mode === 'plan' ? C.accent : C.muted;
|
|
2153
2153
|
const composerMode = shellMode ? 'shell' : mode;
|
|
2154
2154
|
|
|
2155
2155
|
// ── Viewport slicing ───────────────────────────────────────────────────────
|
|
@@ -2175,9 +2175,8 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
2175
2175
|
|
|
2176
2176
|
const scrollPct = maxScrollRef.current > 0 ? Math.round((scrollOffset / maxScrollRef.current) * 100) : 100;
|
|
2177
2177
|
const scrollIndicator = hasAbove
|
|
2178
|
-
? html`<${Box} paddingX=${1} justifyContent="
|
|
2179
|
-
<${Text} color=${C.muted} dimColor>${glyphs.up} ${aboveCount} above ${midDot()}
|
|
2180
|
-
<${Text} color=${C.muted} dimColor>${scrollPct}%<//>
|
|
2178
|
+
? html`<${Box} paddingX=${1} justifyContent="flex-end" width=${cols}>
|
|
2179
|
+
<${Text} color=${C.muted} dimColor>${glyphs.up} ${aboveCount} above ${midDot()} ${scrollPct}%<//>
|
|
2181
2180
|
<//>`
|
|
2182
2181
|
: null;
|
|
2183
2182
|
|
|
@@ -2194,7 +2193,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
2194
2193
|
/>
|
|
2195
2194
|
${diffState.commentInput
|
|
2196
2195
|
? html`<${Choice}
|
|
2197
|
-
title=${`Tell
|
|
2196
|
+
title=${`Tell iCopilot what stands out about ${diffState.commentInput.file}:${diffState.commentInput.lineNumber || '?'}`}
|
|
2198
2197
|
note=${diffState.commentInput.content}
|
|
2199
2198
|
sel=${0}
|
|
2200
2199
|
allowText=${true}
|
|
@@ -2270,16 +2269,9 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
2270
2269
|
<${Text} color=${C.separator}>${'─'.repeat(Math.max(1, cols))}<//>
|
|
2271
2270
|
<${Box} paddingX=${1} width=${cols}>
|
|
2272
2271
|
<${Box} flexGrow=${1}>
|
|
2273
|
-
<${Text} color=${
|
|
2272
|
+
<${Text} color=${footerLeftColor} bold=${busy} dimColor=${!busy && !hint} wrap="truncate-end">${footerLeft}<//>
|
|
2274
2273
|
<//>
|
|
2275
|
-
<${Text} color=${
|
|
2276
|
-
<//>
|
|
2277
|
-
|
|
2278
|
-
<${Box} paddingX=${1} width=${cols}>
|
|
2279
|
-
<${Box} flexGrow=${1}>
|
|
2280
|
-
<${Text} color=${C.muted} dimColor wrap="truncate-end">${footerLeft}<//>
|
|
2281
|
-
<//>
|
|
2282
|
-
<${Text} color=${C.muted} dimColor wrap="truncate-end">${footerInfoRight}<//>
|
|
2274
|
+
<${Text} color=${footerRightColor} bold=${mode === 'autopilot' || mode === 'plan'} dimColor=${!busy && !modeLabel} wrap="truncate-end">${footerRight}<//>
|
|
2283
2275
|
<//>
|
|
2284
2276
|
<//>
|
|
2285
2277
|
<//>`;
|
package/src/tui/components.js
CHANGED
|
@@ -168,7 +168,7 @@ export function Banner({ cfg = {}, model, width = 80, compact = false, streamerM
|
|
|
168
168
|
if (compact) {
|
|
169
169
|
return html`
|
|
170
170
|
<${Box} marginBottom=${1}>
|
|
171
|
-
<${Text} color=${C.accent} bold>${glyphs.ring}
|
|
171
|
+
<${Text} color=${C.accent} bold>${glyphs.ring} iCopilot <//>
|
|
172
172
|
<${Text} color=${C.muted}>${midDot()}<//>
|
|
173
173
|
<${Text} color=${C.muted}>${m}<//>
|
|
174
174
|
${cfg.user?.name ? html`<${Text} color=${C.muted}>${midDot()}<//>` : null}
|
|
@@ -183,7 +183,7 @@ export function Banner({ cfg = {}, model, width = 80, compact = false, streamerM
|
|
|
183
183
|
<//>
|
|
184
184
|
|
|
185
185
|
<${Box} marginTop=${1} justifyContent="center">
|
|
186
|
-
<${Text} color=${C.accent} bold>${glyphs.ring}
|
|
186
|
+
<${Text} color=${C.accent} bold>${glyphs.ring} iCopilot<//>
|
|
187
187
|
<${Text} color=${C.muted}> ${dash()} IspBills network engineer in your terminal<//>
|
|
188
188
|
<//>
|
|
189
189
|
|
|
@@ -271,7 +271,7 @@ export function AssistantMessage({ text, cols = 80, ts, label, streaming = false
|
|
|
271
271
|
<${Sep} cols=${cols} />
|
|
272
272
|
<${Box} flexDirection="row" justifyContent="space-between" width=${cols} paddingX=${1}>
|
|
273
273
|
<${Box}>
|
|
274
|
-
<${Text} color=${C.accent} bold>${glyphs.copilotDot} <//><${Text} bold>
|
|
274
|
+
<${Text} color=${C.accent} bold>${glyphs.copilotDot} <//><${Text} bold>iCopilot${streaming ? ' ●' : ''}<//>
|
|
275
275
|
<//>
|
|
276
276
|
<${Text} color=${C.muted}>${stamp}<//>
|
|
277
277
|
<//>
|
|
@@ -380,7 +380,7 @@ export function StatusLines({ lines = [], busy = false, navigable = false }) {
|
|
|
380
380
|
useEffect(() => { setSel(-1); setExpanded(new Set()); }, [lines.length]);
|
|
381
381
|
|
|
382
382
|
useInput((input, key) => {
|
|
383
|
-
if (!navigable) return;
|
|
383
|
+
if (!navigable || !key) return;
|
|
384
384
|
if (key.upArrow || input === 'k') { setSel((i) => Math.max(0, (i < 0 ? lines.length - 1 : i) - 1)); return; }
|
|
385
385
|
if (key.downArrow || input === 'j') { setSel((i) => Math.min(lines.length - 1, (i < 0 ? -1 : i) + 1)); return; }
|
|
386
386
|
if ((key.return || input === ' ') && sel >= 0) {
|
|
@@ -388,7 +388,7 @@ export function StatusLines({ lines = [], busy = false, navigable = false }) {
|
|
|
388
388
|
return;
|
|
389
389
|
}
|
|
390
390
|
if (key.escape) { setSel(-1); return; }
|
|
391
|
-
});
|
|
391
|
+
}, { isActive: navigable });
|
|
392
392
|
|
|
393
393
|
if (!lines.length) return null;
|
|
394
394
|
const lastIdx = lines.length - 1;
|
|
@@ -686,7 +686,7 @@ export function Choice({ title, note, options = [], sel = 0, allowText = false,
|
|
|
686
686
|
${allowText
|
|
687
687
|
? html`<${Box} key="freetext" marginTop=${1}>
|
|
688
688
|
<${Text} color=${focusText ? C.accent : C.muted}>${focusText ? glyphs.prompt + ' ' : ' '}<//>
|
|
689
|
-
<${Text} color=${C.muted}>Tell
|
|
689
|
+
<${Text} color=${C.muted}>Tell iCopilot what to do differently: <//>
|
|
690
690
|
<${Text} color=${C.white}>${text}<//>${focusText ? html`<${Text} inverse> <//>` : null}
|
|
691
691
|
<//>`
|
|
692
692
|
: null}
|
package/src/tui/run.js
CHANGED
|
@@ -93,7 +93,7 @@ function exitAltScreen() {
|
|
|
93
93
|
altScreenActive = false;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
//
|
|
96
|
+
// iCopilot wordmark in block letters
|
|
97
97
|
const LOGO = [
|
|
98
98
|
' ██╗ ██████╗ ██████╗ ██████╗ ██╗██╗ ██████╗ ████████╗',
|
|
99
99
|
' ██║██╔════╝██╔═══██╗██╔══██╗██║██║ ██╔═══██╗╚══██╔══╝',
|
|
@@ -145,7 +145,7 @@ async function animateSplash(cfg = {}) {
|
|
|
145
145
|
const R = '\x1b[0m';
|
|
146
146
|
|
|
147
147
|
const hr = `${SEP}${'─'.repeat(cols)}${R}`;
|
|
148
|
-
const subtitle = `${ACC}◈
|
|
148
|
+
const subtitle = `${ACC}◈ iCopilot${R} ${DIM}IspBills network engineer in your terminal${R}`;
|
|
149
149
|
const subtitleLen = subtitle.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
150
150
|
const subPad = ' '.repeat(Math.max(0, Math.floor((cols - subtitleLen) / 2)));
|
|
151
151
|
|