ispbills-icli 8.5.7 → 8.5.9

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/bin/icli.js CHANGED
@@ -320,6 +320,9 @@ async function main() {
320
320
  if (has('--experimental')) {
321
321
  cfg.tui = { ...(cfg.tui || {}), experimental: true };
322
322
  }
323
+ if (has('--cloud')) {
324
+ cfg.tui = { ...(cfg.tui || {}), cloud: true };
325
+ }
323
326
  if (flag('--allow-tool')) {
324
327
  const tool = flag('--allow-tool');
325
328
  cfg.tui = { ...(cfg.tui || {}), allowedTools: [...(cfg.tui?.allowedTools || []), tool] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ispbills-icli",
3
- "version": "8.5.7",
3
+ "version": "8.5.9",
4
4
  "description": "iCli — IspBills AI network engineer in your terminal",
5
5
  "keywords": [
6
6
  "ispbills",
package/src/tui/app.js CHANGED
@@ -442,6 +442,17 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
442
442
  if (!trusted && !choice) openTrustDialog(process.cwd());
443
443
  }, [trusted, choice, openTrustDialog]);
444
444
 
445
+ // §2 (stage 3): auth check — once the folder is trusted, warn if no token.
446
+ const authNoticeRef = useRef(false);
447
+ useEffect(() => {
448
+ if (!trusted || authNoticeRef.current) return;
449
+ const isAuth = Boolean(cfg?.user?.name || cfg?.user?.email || cfg?.apiKey || cfg?._token);
450
+ if (!isAuth) {
451
+ authNoticeRef.current = true;
452
+ pushNotice(`${glyphs.warn} Not authenticated — run /login to connect.`, C.warning, false);
453
+ }
454
+ }, [trusted, cfg, pushNotice]);
455
+
445
456
  const doExit = useCallback(() => { onExit?.(plain.current); exit(); }, [exit, onExit]);
446
457
 
447
458
  const maybeProcessQueue = useCallback(() => {
@@ -695,7 +706,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
695
706
  setChoice({
696
707
  title: '⚙ Tool request',
697
708
  note: toolDesc,
698
- sel: 0, text: '', focusText: false, allowText: false,
709
+ sel: 0, text: '', focusText: false, allowText: true,
699
710
  isToolApproval: true,
700
711
  options: [
701
712
  { label: '1. Yes', value: 'yes, proceed with this tool call' },
@@ -1779,7 +1790,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
1779
1790
  case 'activity': return html`<${StatusLines} key=${it.id} lines=${it.status} busy=${false} />`;
1780
1791
  case 'notice': return html`<${Notice} key=${it.id} text=${it.text} color=${it.color} />`;
1781
1792
  case 'info': return html`<${LabeledNotice} key=${it.id} label="ℹ Info" text=${it.text} color=${C.muted} bodyColor=${it.color || C.white} cols=${c} ts=${it.ts} />`;
1782
- case 'error': return html`<${LabeledNotice} key=${it.id} label=" Error" text=${it.text} color=${C.error} bodyColor=${it.color || C.white} cols=${c} ts=${it.ts} />`;
1793
+ case 'error': return html`<${LabeledNotice} key=${it.id} label=" Error" text=${it.text} color=${C.error} bodyColor=${it.color || C.white} cols=${c} ts=${it.ts} />`;
1783
1794
  case 'system': return html`<${LabeledNotice} key=${it.id} label="⚙ System" text=${it.text} color=${C.muted} bodyColor=${it.color || C.white} cols=${c} ts=${it.ts} />`;
1784
1795
  case 'shell': return html`<${ShellOutput} key=${it.id} command=${it.command} output=${it.output} code=${it.code} cols=${c} ts=${it.ts} />`;
1785
1796
  case 'help': return html`<${HelpOverlay} key=${it.id} cols=${c} ts=${it.ts} />`;
@@ -90,7 +90,7 @@ function formatTs(ts) {
90
90
  function SpeakerLine({ label, color, cols = 80, ts, rightLabel = '' }) {
91
91
  const stamp = ts ? `[${formatTs(ts)}]` : '';
92
92
  return html`
93
- <${Box} paddingX=${2} marginTop=${1} width=${cols}>
93
+ <${Box} paddingX=${1} marginTop=${1} width=${cols}>
94
94
  <${Text} color=${color} bold>${label}<//>
95
95
  <${Box} flexGrow=${1} />
96
96
  ${rightLabel ? html`<${Text} color=${C.muted}>${rightLabel}<//>` : null}
@@ -118,10 +118,10 @@ export function TabBar({ active = 'session', cols = 80, mode = 'ask' }) {
118
118
  const on = t.id === active;
119
119
  return html`
120
120
  <${Box} key=${t.id}>
121
- ${i > 0 ? html`<${Text} color="cyan" backgroundColor="blue"> <//>` : null}
121
+ ${i > 0 ? html`<${Text} backgroundColor="blue"> <//>` : null}
122
122
  ${on
123
123
  ? html`<${Text} color="white" bold backgroundColor="blue">[${t.label}]<//>`
124
- : html`<${Text} color="cyan" backgroundColor="blue">${t.label}<//>`}
124
+ : html`<${Text} color="white" dimColor backgroundColor="blue">${t.label}<//>`}
125
125
  <//>`;
126
126
  })}
127
127
  <//>
@@ -221,7 +221,7 @@ export function UserMessage({ text, cols = 80, ts }) {
221
221
  <${Box} flexDirection="column" marginTop=${1}>
222
222
  <${Sep} cols=${cols} />
223
223
  <${SpeakerLine} label="You" color=${C.brand} cols=${cols} ts=${ts} />
224
- <${Box} paddingX=${2}>
224
+ <${Box} paddingX=${1}>
225
225
  <${Text}>${withMentions(text)}<//>
226
226
  <//>
227
227
  <//>`;
@@ -251,11 +251,13 @@ function StreamingText({ text = '' }) {
251
251
  }
252
252
 
253
253
  export function AssistantMessage({ text, cols = 80, ts, label = `${glyphs.copilotDot} iCopilot`, streaming = false }) {
254
+ // §11: response content box capped at 100 columns; separators stay full-width (§6).
255
+ const bodyWidth = Math.min(cols, 100);
254
256
  return html`
255
257
  <${Box} flexDirection="column" marginTop=${1}>
256
258
  <${Sep} cols=${cols} />
257
259
  <${SpeakerLine} label=${label} color=${C.accent} cols=${cols} ts=${ts} />
258
- <${Box} paddingX=${2} flexDirection="column">
260
+ <${Box} paddingX=${1} flexDirection="column" width=${bodyWidth}>
259
261
  ${streaming ? html`<${StreamingText} text=${text} />` : html`<${Markdown} content=${text} />`}
260
262
  <//>
261
263
  <//>`;
@@ -516,6 +518,7 @@ export function Choice({ title, note, options = [], sel = 0, allowText = false,
516
518
  <${Box} paddingX=${2} marginTop=${1}>
517
519
  <${Text} color=${C.accent} bold>⚙ Tool request<//>
518
520
  <//>
521
+ <${Sep} cols=${80} />
519
522
  ${note ? html`<${Box} paddingX=${2} marginTop=${1}><${Text} color=${C.muted}>${note}<//><//>` : null}
520
523
  <${Box} flexDirection="column" marginTop=${1} paddingX=${2}>
521
524
  ${options.map((o, i) => {
@@ -3,7 +3,7 @@
3
3
  // the input and is navigable with the arrow keys.
4
4
  import { html, useState, useEffect, useCallback, useRef } from './dom.js';
5
5
  import { Box, Text, useInput } from 'ink';
6
- import { C, glyphs } from './theme.js';
6
+ import { C, glyphs, asciiSafe } from './theme.js';
7
7
  import { SLASH_COMMANDS } from '../commands.js';
8
8
  import { readFileSync, writeFileSync, rmSync, readdirSync, statSync } from 'fs';
9
9
  import { join, basename, dirname, resolve } from 'path';
@@ -530,6 +530,6 @@ export function Composer({
530
530
  <//>`
531
531
  : null}
532
532
 
533
- <${Text} color=${C.separator}>${'─'.repeat(Math.max(1, width))}<//>
533
+ <${Text} color=${C.separator}>${(asciiSafe() ? '-' : '─').repeat(Math.max(1, width))}<//>
534
534
  <//>`;
535
535
  }
package/src/tui/run.js CHANGED
@@ -14,7 +14,7 @@ const LOGO = [
14
14
  ];
15
15
  const COLORS = ['35', '95', '94', '96', '97'];
16
16
 
17
- async function animateSplash() {
17
+ async function animateSplash(cfg = {}) {
18
18
  if (!process.stdout.isTTY) return;
19
19
  for (let frame = 0; frame < COLORS.length; frame++) {
20
20
  const color = COLORS[frame];
@@ -23,6 +23,21 @@ async function animateSplash() {
23
23
  await new Promise((resolve) => setTimeout(resolve, 110));
24
24
  if (frame !== COLORS.length - 1) process.stdout.write(`\x1b[${LOGO.length}A`);
25
25
  }
26
+ // §3: welcome text, quick-start tips and a visible /login instruction.
27
+ const DIM = '\x1b[2m';
28
+ const ACCENT = '\x1b[38;5;141m';
29
+ const WARN = '\x1b[38;5;179m';
30
+ const R = '\x1b[0m';
31
+ process.stdout.write(`\n ${ACCENT}iCopilot${R} ${DIM}— IspBills network engineer in your terminal${R}\n\n`);
32
+ process.stdout.write(` ${DIM}Quick start:${R}\n`);
33
+ process.stdout.write(` ${ACCENT}@${R}${DIM} mention files or devices${R}\n`);
34
+ process.stdout.write(` ${ACCENT}/${R}${DIM} slash commands${R}\n`);
35
+ process.stdout.write(` ${ACCENT}?${R}${DIM} quick help overlay${R}\n`);
36
+ process.stdout.write(` ${ACCENT}!${R}${DIM} run a shell command${R}\n`);
37
+ const isAuth = Boolean(cfg?.user?.name || cfg?.user?.email || cfg?.apiKey || cfg?._token);
38
+ if (!isAuth) {
39
+ process.stdout.write(`\n ${WARN}⚠ Not authenticated — run ${R}${ACCENT}/login${R}${WARN} to connect.${R}\n`);
40
+ }
26
41
  process.stdout.write('\n');
27
42
  }
28
43
 
@@ -33,7 +48,7 @@ export async function runTui(cfg, opts = {}) {
33
48
  const showAnimation = banner || !seen;
34
49
 
35
50
  if (showAnimation) {
36
- await animateSplash();
51
+ await animateSplash(cfg);
37
52
  cfg.tui = { ...(cfg.tui || {}), bannerSeen: true };
38
53
  try { saveConfig(cfg); } catch {}
39
54
  }