ispbills-icli 8.6.2 → 8.6.4
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.js +1 -0
- package/src/tui/app.js +2 -2
- package/src/tui/components.js +20 -7
- package/src/tui/composer.js +6 -2
package/package.json
CHANGED
package/src/commands.js
CHANGED
|
@@ -129,6 +129,7 @@ export const SLASH_COMMANDS = [
|
|
|
129
129
|
{ cmd: '/logout', hint: '', desc: 'Log out and clear credentials', group: 'Help', local: true },
|
|
130
130
|
{ cmd: '/help', hint: '', desc: 'Show help', group: 'Help', local: true },
|
|
131
131
|
{ cmd: '/exit', hint: '', desc: 'Exit iCli', group: 'Help', local: true },
|
|
132
|
+
{ cmd: '/quit', hint: '', desc: 'Alias for /exit', group: 'Help', local: true },
|
|
132
133
|
];
|
|
133
134
|
|
|
134
135
|
export function slashCompleter(line) {
|
package/src/tui/app.js
CHANGED
|
@@ -761,7 +761,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
761
761
|
if (q.startsWith('!')) { runShellCommand(q.slice(1)); return; }
|
|
762
762
|
if (q === '?') { push({ type: 'help', text: 'help' }); return; }
|
|
763
763
|
|
|
764
|
-
if (q === '/exit' || q === 'exit' || q === 'quit') { doExit(); return; }
|
|
764
|
+
if (q === '/exit' || q === '/quit' || q === 'exit' || q === 'quit') { doExit(); return; }
|
|
765
765
|
if (q === '/clear') { clearAll(); return; }
|
|
766
766
|
if (q === '/new') {
|
|
767
767
|
sessionIdRef.current = Date.now().toString(36);
|
|
@@ -1892,7 +1892,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
1892
1892
|
|
|
1893
1893
|
<${Box} flexDirection="column">
|
|
1894
1894
|
${choice
|
|
1895
|
-
? html`<${Choice} ...${choice} />`
|
|
1895
|
+
? html`<${Choice} ...${choice} cols=${cols} />`
|
|
1896
1896
|
: sessionPicker
|
|
1897
1897
|
? html`<${SessionPicker} sessions=${sessionPicker.sessions} sel=${sessionPicker.sel} sort=${sessionPicker.sort} cols=${cols} />`
|
|
1898
1898
|
: html`<${Composer}
|
package/src/tui/components.js
CHANGED
|
@@ -117,17 +117,30 @@ export function TabBar({ active = 'session', cols = 80, mode = 'ask' }) {
|
|
|
117
117
|
const modeBadge = mode !== 'ask'
|
|
118
118
|
? ` ${mode === 'autopilot' ? '⚡ AUTO' : mode === 'shell' ? '⌘ SHELL' : '📋 PLAN'}`
|
|
119
119
|
: '';
|
|
120
|
+
const badgeLen = modeBadge ? modeBadge.length + 2 : 0;
|
|
121
|
+
const available = cols - 2 - badgeLen; // -2 for paddingX={1}
|
|
122
|
+
|
|
123
|
+
// §11: clip tab labels when terminal is narrow (~50 cols)
|
|
124
|
+
// Full: [Session] Devices Customers Alarms = ~42 chars
|
|
125
|
+
// Short: [Ses] Dev Cus Alm = ~26 chars
|
|
126
|
+
const fullWidth = TABS.reduce((sum, t, i) => {
|
|
127
|
+
const w = t.id === active ? t.label.length + 2 : t.label.length;
|
|
128
|
+
return sum + (i > 0 ? 3 : 0) + w;
|
|
129
|
+
}, 0);
|
|
130
|
+
const abbreviated = fullWidth > available;
|
|
131
|
+
|
|
120
132
|
return html`
|
|
121
133
|
<${Box} width=${cols} backgroundColor="blue">
|
|
122
134
|
<${Box} paddingX=${1} flexGrow=${1}>
|
|
123
135
|
${TABS.map((t, i) => {
|
|
124
136
|
const on = t.id === active;
|
|
137
|
+
const lbl = abbreviated ? t.label.slice(0, 3) : t.label;
|
|
125
138
|
return html`
|
|
126
139
|
<${Box} key=${t.id}>
|
|
127
140
|
${i > 0 ? html`<${Text} backgroundColor="blue"> <//>` : null}
|
|
128
141
|
${on
|
|
129
|
-
? html`<${Text} color="white" bold backgroundColor="blue">[${
|
|
130
|
-
: html`<${Text} color="white" dimColor backgroundColor="blue">${
|
|
142
|
+
? html`<${Text} color="white" bold backgroundColor="blue">[${lbl}]<//>`
|
|
143
|
+
: html`<${Text} color="white" dimColor backgroundColor="blue">${lbl}<//>`}
|
|
131
144
|
<//>`;
|
|
132
145
|
})}
|
|
133
146
|
<//>
|
|
@@ -280,7 +293,7 @@ export function ShellOutput({ command, output, cols = 80, ts, code = 0 }) {
|
|
|
280
293
|
ts=${ts}
|
|
281
294
|
rightLabel=${code === 0 ? '' : `exit ${code}`}
|
|
282
295
|
/>
|
|
283
|
-
<${Box} paddingX=${
|
|
296
|
+
<${Box} paddingX=${1} flexDirection="column">
|
|
284
297
|
<${Text} color=${C.warning}>$ ${command}<//>
|
|
285
298
|
<${Text}>${output || '(no output)'}<//>
|
|
286
299
|
<//>
|
|
@@ -509,23 +522,23 @@ export function Thinking({ label = 'Working', startedAt }) {
|
|
|
509
522
|
}, []);
|
|
510
523
|
const secs = startedAt ? Math.max(0, Math.round((Date.now() - startedAt) / 1000)) : 0;
|
|
511
524
|
return html`
|
|
512
|
-
<${Box} marginTop=${1} paddingX=${
|
|
525
|
+
<${Box} marginTop=${1} paddingX=${1}>
|
|
513
526
|
<${Text} color=${C.warning}><${Spinner} type=${spinnerType()} /><//>
|
|
514
527
|
<${Text} color=${C.warning} bold> ${label}<//>
|
|
515
528
|
<${Text} color=${C.muted}>… (${secs}s ${midDot()}esc to interrupt)<//>
|
|
516
529
|
<//>`;
|
|
517
530
|
}
|
|
518
531
|
|
|
519
|
-
export function Choice({ title, note, options = [], sel = 0, allowText = false, text = '', focusText = false, isToolApproval = false }) {
|
|
532
|
+
export function Choice({ title, note, options = [], sel = 0, allowText = false, text = '', focusText = false, isToolApproval = false, cols = 80 }) {
|
|
520
533
|
// §13: tool approval uses exact spec format with Sep-style header
|
|
521
534
|
if (isToolApproval) {
|
|
522
535
|
return html`
|
|
523
536
|
<${Box} flexDirection="column" marginTop=${1}>
|
|
524
|
-
<${Sep} cols=${
|
|
537
|
+
<${Sep} cols=${cols} />
|
|
525
538
|
<${Box} paddingX=${2} marginTop=${1}>
|
|
526
539
|
<${Text} color=${C.accent} bold>⚙ Tool request<//>
|
|
527
540
|
<//>
|
|
528
|
-
<${Sep} cols=${
|
|
541
|
+
<${Sep} cols=${cols} />
|
|
529
542
|
${note ? html`<${Box} paddingX=${2} marginTop=${1}><${Text} color=${C.muted}>${note}<//><//>` : null}
|
|
530
543
|
<${Box} flexDirection="column" marginTop=${1} paddingX=${2}>
|
|
531
544
|
${options.map((o, i) => {
|
package/src/tui/composer.js
CHANGED
|
@@ -357,7 +357,11 @@ export function Composer({
|
|
|
357
357
|
return;
|
|
358
358
|
}
|
|
359
359
|
if (key.ctrl && input === 's') { submit(value, { preserve: true }); return; }
|
|
360
|
-
if (key.ctrl && input === 'f') {
|
|
360
|
+
if (key.ctrl && input === 'f') {
|
|
361
|
+
// §18: Ctrl+F = cursor forward one char when input non-empty; §17: open search when empty
|
|
362
|
+
if (value.length === 0) { onSearch?.(); return; }
|
|
363
|
+
setCursor((c) => Math.min(value.length, c + 1)); return;
|
|
364
|
+
}
|
|
361
365
|
if (key.shift && enter) {
|
|
362
366
|
snapshot('type');
|
|
363
367
|
setValue((v) => insertAt(v, cursor, '\n'));
|
|
@@ -418,7 +422,7 @@ export function Composer({
|
|
|
418
422
|
return;
|
|
419
423
|
}
|
|
420
424
|
if (key.home || (key.ctrl && input === 'a')) { setCursor(0); return; }
|
|
421
|
-
if (key.end || (key.ctrl && input === 'e' && value.indexOf('\n') === -1)) { setCursor(value.length); return; }
|
|
425
|
+
if (key.end || (key.ctrl && input === 'e' && value.indexOf('\n') === -1 && value.length > 0)) { setCursor(value.length); return; }
|
|
422
426
|
if (key.ctrl && key.home) { setCursor(0); return; }
|
|
423
427
|
if (key.ctrl && key.end) { setCursor(value.length); return; }
|
|
424
428
|
if (key.meta && key.leftArrow) { setCursor(wordLeft(value, cursor)); return; }
|