ispbills-icli 8.6.3 → 8.6.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ispbills-icli",
3
- "version": "8.6.3",
3
+ "version": "8.6.5",
4
4
  "description": "iCli — IspBills AI network engineer in your terminal",
5
5
  "keywords": [
6
6
  "ispbills",
package/src/commands.js CHANGED
@@ -118,6 +118,7 @@ export const SLASH_COMMANDS = [
118
118
  // ── Help & Feedback ──
119
119
  { cmd: '/changelog', hint: '', desc: 'Show recent npm package releases', group: 'Help', local: true },
120
120
  { cmd: '/feedback', hint: '', desc: 'Show the feedback / bug-report URL', group: 'Help', local: true },
121
+ { cmd: '/bug', hint: '', desc: 'Report a bug (alias for /feedback)', group: 'Help', local: true },
121
122
  { cmd: '/update', hint: '', desc: 'Update iCli to the latest version', group: 'Help', local: true },
122
123
  { cmd: '/downgrade', hint: 'VERSION', desc: 'Roll back to a specific CLI version', group: 'Help', local: true },
123
124
  { cmd: '/app', hint: '', desc: 'Launch the GitHub Copilot desktop app', group: 'Help', local: true },
@@ -129,6 +130,7 @@ export const SLASH_COMMANDS = [
129
130
  { cmd: '/logout', hint: '', desc: 'Log out and clear credentials', group: 'Help', local: true },
130
131
  { cmd: '/help', hint: '', desc: 'Show help', group: 'Help', local: true },
131
132
  { cmd: '/exit', hint: '', desc: 'Exit iCli', group: 'Help', local: true },
133
+ { cmd: '/quit', hint: '', desc: 'Alias for /exit', group: 'Help', local: true },
132
134
  ];
133
135
 
134
136
  export function slashCompleter(line) {
package/src/tui/app.js CHANGED
@@ -67,7 +67,7 @@ function approxTokens(messages) {
67
67
  }
68
68
 
69
69
  const TOKEN_LIMIT = 100000;
70
- const SESSION_SORTS = ['relevance', 'last used', 'created', 'name'];
70
+ const SESSION_SORTS = ['relevance', 'created', 'name', 'last used'];
71
71
 
72
72
  function sessionAutoName(messages = []) {
73
73
  const firstUser = messages.find((m) => m?.role === 'user' && String(m.content || '').trim());
@@ -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}
@@ -70,20 +70,20 @@ function formatTs(ts) {
70
70
  } catch {
71
71
  return '';
72
72
  }
73
+ }
73
74
 
74
- function formatDate(ts) {
75
- if (!ts) return '';
76
- try {
77
- return new Date(ts).toLocaleString([], {
78
- year: 'numeric',
79
- month: 'short',
80
- day: '2-digit',
81
- hour: '2-digit',
82
- minute: '2-digit',
83
- });
84
- } catch {
85
- return '';
86
- }
75
+ function formatDate(ts) {
76
+ if (!ts) return '';
77
+ try {
78
+ return new Date(ts).toLocaleString([], {
79
+ year: 'numeric',
80
+ month: 'short',
81
+ day: '2-digit',
82
+ hour: '2-digit',
83
+ minute: '2-digit',
84
+ });
85
+ } catch {
86
+ return '';
87
87
  }
88
88
  }
89
89
 
@@ -529,16 +529,16 @@ export function Thinking({ label = 'Working', startedAt }) {
529
529
  <//>`;
530
530
  }
531
531
 
532
- 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 }) {
533
533
  // §13: tool approval uses exact spec format with Sep-style header
534
534
  if (isToolApproval) {
535
535
  return html`
536
536
  <${Box} flexDirection="column" marginTop=${1}>
537
- <${Sep} cols=${80} />
537
+ <${Sep} cols=${cols} />
538
538
  <${Box} paddingX=${2} marginTop=${1}>
539
539
  <${Text} color=${C.accent} bold>⚙ Tool request<//>
540
540
  <//>
541
- <${Sep} cols=${80} />
541
+ <${Sep} cols=${cols} />
542
542
  ${note ? html`<${Box} paddingX=${2} marginTop=${1}><${Text} color=${C.muted}>${note}<//><//>` : null}
543
543
  <${Box} flexDirection="column" marginTop=${1} paddingX=${2}>
544
544
  ${options.map((o, i) => {
@@ -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') { onSearch?.(); return; }
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; }
@@ -459,7 +463,7 @@ export function Composer({
459
463
  const empty = value.length === 0;
460
464
  const sugTok = menuOpen && matches[sel] ? (slashMode ? matches[sel].cmd : matches[sel].tag) : '';
461
465
  const ghost = sugTok && sugTok.startsWith(token) && cursor >= value.length ? sugTok.slice(token.length) : '';
462
- const promptGlyph = busy ? glyphs.busy : glyphs.prompt;
466
+ const promptGlyph = glyphs.prompt;
463
467
  const promptColor = busy ? C.warning : C.success;
464
468
  const ghostHint = busy ? 'Working…' : 'Enter @ to mention files or / for commands…';
465
469
  const modePrefix = mode === 'plan'
@@ -510,7 +514,7 @@ export function Composer({
510
514
  ${empty
511
515
  ? html`<${Box} flexGrow=${1}>
512
516
  <${Text} color="white" inverse> <//>
513
- <${Text} color=${C.muted}> ${ghostHint}<//>
517
+ <${Text} color=${C.muted} italic> ${ghostHint}<//>
514
518
  <//>`
515
519
  : html`<${Box} flexGrow=${1}>
516
520
  <${Text}>${before}<//><${Text} inverse>${at}<//><${Text}>${after}<//><${Text} color=${C.muted}>${ghost}<//>