ispbills-icli 8.7.3 → 8.7.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.7.3",
3
+ "version": "8.7.5",
4
4
  "description": "iCli — IspBills AI network engineer in your terminal",
5
5
  "keywords": [
6
6
  "ispbills",
package/src/tui/app.js CHANGED
@@ -1106,16 +1106,18 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
1106
1106
  // Show interactive model picker
1107
1107
  const cur = model || modelRef.current || '';
1108
1108
  const MODELS = [
1109
- { id: 'gpt-4o-mini', desc: 'Fast & affordable (default)' },
1110
- { id: 'openai/gpt-4o', desc: 'OpenAI GPT-4o — balanced' },
1111
- { id: 'openai/gpt-4.1', desc: 'OpenAI GPT-4.1 — latest' },
1112
- { id: 'openai/o3', desc: 'OpenAI o3reasoning' },
1113
- { id: 'openai/o3-mini', desc: 'OpenAI o3-minifast reasoning' },
1114
- { id: 'anthropic/claude-3-5-sonnet', desc: 'Claude 3.5 Sonnet strong' },
1115
- { id: 'anthropic/claude-3-opus', desc: 'Claude 3 Opusadvanced' },
1116
- { id: 'anthropic/claude-3-haiku', desc: 'Claude 3 Haikufast' },
1117
- { id: 'meta/llama-3.3-70b-instruct', desc: 'Llama 3.3 70B (open)' },
1118
- { id: 'mistral/mistral-large', desc: 'Mistral Large' },
1109
+ { id: 'gpt-4o-mini', desc: 'Fast & affordable (default)' },
1110
+ { id: 'openai/gpt-4o', desc: 'OpenAI GPT-4o — balanced' },
1111
+ { id: 'openai/gpt-4.1', desc: 'OpenAI GPT-4.1 — latest' },
1112
+ { id: 'openai/gpt-5.3-codex', desc: 'GPT-5.3 Codexadvanced coding' },
1113
+ { id: 'openai/o3', desc: 'OpenAI o3 — reasoning' },
1114
+ { id: 'openai/o3-mini', desc: 'OpenAI o3-minifast reasoning' },
1115
+ { id: 'anthropic/claude-sonnet-4-6', desc: 'Claude Sonnet 4.6latest (recommended)' },
1116
+ { id: 'anthropic/claude-3-5-sonnet', desc: 'Claude 3.5 Sonnetstrong' },
1117
+ { id: 'anthropic/claude-3-opus', desc: 'Claude 3 Opus — advanced' },
1118
+ { id: 'anthropic/claude-3-haiku', desc: 'Claude 3 Haiku — fast' },
1119
+ { id: 'meta/llama-3.3-70b-instruct', desc: 'Llama 3.3 70B (open)' },
1120
+ { id: 'mistral/mistral-large', desc: 'Mistral Large' },
1119
1121
  ];
1120
1122
  choiceActionRef.current = (val) => {
1121
1123
  if (val) {
@@ -2130,9 +2132,12 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
2130
2132
  ? `${glyphs.spinner} Working\u2026`
2131
2133
  : hint
2132
2134
  ? hint
2133
- : `? help ${midDot()} / commands ${midDot()} \u2191\u2193 history ${midDot()} Tab mode`;
2134
- const footerStatusColor = busy ? C.warning : hint ? C.warning : C.muted;
2135
- const footerStatusRight = busy ? `Ctrl+C to cancel` : '';
2135
+ : activeTab !== 'session'
2136
+ ? `Enter Session ${midDot()} r refresh ${midDot()} Tab next tab ${midDot()} 1-9 insert command`
2137
+ : `? help ${midDot()} / commands ${midDot()} @ mention ${midDot()} \u2191\u2193 history ${midDot()} Tab mode`;
2138
+ const footerStatusColor = busy ? C.warning : hint ? C.accent : C.brand;
2139
+ const footerStatusRight = busy ? `Ctrl+C cancel` : mode === 'autopilot' ? 'AUTOPILOT' : mode === 'plan' ? 'PLAN' : '';
2140
+ const footerStatusRightColor = busy ? C.warning : mode === 'autopilot' ? C.warning : mode === 'plan' ? C.accent : C.muted;
2136
2141
  const composerMode = shellMode ? 'shell' : mode;
2137
2142
 
2138
2143
  // ── Viewport slicing ───────────────────────────────────────────────────────
@@ -2252,9 +2257,9 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
2252
2257
 
2253
2258
  <${Box} paddingX=${1} width=${cols}>
2254
2259
  <${Box} flexGrow=${1}>
2255
- <${Text} color=${footerStatusColor} wrap="truncate-end">${footerStatusLeft}<//>
2260
+ <${Text} color=${footerStatusColor} bold=${busy} wrap="truncate-end">${footerStatusLeft}<//>
2256
2261
  <//>
2257
- <${Text} color=${footerStatusColor} dimColor wrap="truncate-end">${footerStatusRight}<//>
2262
+ <${Text} color=${footerStatusRightColor} bold wrap="truncate-end">${footerStatusRight}<//>
2258
2263
  <//>
2259
2264
 
2260
2265
  <${Box} paddingX=${1} width=${cols}>
@@ -248,6 +248,11 @@ export function Composer({
248
248
  };
249
249
 
250
250
  useInput((input, key) => {
251
+ // Drop any mouse escape sequences that leaked through the stdin filter.
252
+ // SGR: \x1b[<N;N;N[Mm] X10: \x1b[M... URXVT: \x1b[N;N;NM
253
+ if (input && input[0] === '\x1b') {
254
+ if (/^\x1b\[(?:<\d|M|\d+;\d+;\d+M)/.test(input)) return;
255
+ }
251
256
  const enter = key.return || input === '\r' || input === '\n';
252
257
  const ctrlEnter = busy && key.ctrl && enter;
253
258
  if (ctrlEnter || (busy && key.ctrl && input === 'q')) {
package/src/tui/run.js CHANGED
@@ -17,6 +17,10 @@ class MouseFilterTransform extends Transform {
17
17
  this.setRawMode = process.stdin.setRawMode
18
18
  ? (mode) => process.stdin.setRawMode(mode)
19
19
  : undefined;
20
+ // Ink calls ref()/unref() on whatever stream it receives as stdin.
21
+ // Transform streams don't have these; delegate to the underlying TTY.
22
+ this.ref = () => process.stdin.ref?.();
23
+ this.unref = () => process.stdin.unref?.();
20
24
  this._buf = '';
21
25
  }
22
26
 
@@ -26,20 +30,39 @@ class MouseFilterTransform extends Transform {
26
30
  let out = '';
27
31
  let i = 0;
28
32
  while (i < this._buf.length) {
29
- // SGR mouse: \x1b[<N;N;N[Mm]
30
- if (this._buf[i] === '\x1b' && this._buf[i + 1] === '[' && this._buf[i + 2] === '<') {
31
- const rest = this._buf.slice(i);
32
- const m = rest.match(/^\x1b\[<\d+;\d+;\d+[Mm]/);
33
- if (m) { i += m[0].length; continue; }
34
- if (rest.length < 32) break; // incomplete – wait for more bytes
35
- out += this._buf[i++]; // give up, pass through
36
- continue;
37
- }
38
- // X10 mouse: \x1b[M + 3 bytes
39
- if (this._buf[i] === '\x1b' && this._buf[i + 1] === '[' && this._buf[i + 2] === 'M') {
40
- if (i + 6 <= this._buf.length) { i += 6; continue; }
41
- break; // incomplete
33
+ const c0 = this._buf[i];
34
+ const c1 = this._buf[i + 1]; // may be undefined at end of buffer
35
+ const c2 = this._buf[i + 2]; // may be undefined
36
+
37
+ if (c0 === '\x1b' && c1 === '[') {
38
+ // SGR mouse: \x1b[<N;N;N[Mm] (e.g. \x1b[<0;5;3M \x1b[<64;10;5M)
39
+ if (c2 === '<') {
40
+ const rest = this._buf.slice(i);
41
+ const m = rest.match(/^\x1b\[<\d+;\d+;\d+[Mm]/);
42
+ if (m) { i += m[0].length; continue; }
43
+ if (rest.length < 40) break; // wait for more bytes (max SGR seq ~20 chars)
44
+ out += this._buf[i++]; // give up on this ESC, pass through
45
+ continue;
46
+ }
47
+ // X10 mouse: \x1b[M + 3 raw bytes (total 6 bytes)
48
+ if (c2 === 'M') {
49
+ if (i + 6 <= this._buf.length) { i += 6; continue; }
50
+ break; // incomplete X10 sequence — wait
51
+ }
52
+ // URXVT extended mouse: \x1b[N;N;NM (digits without '<', ends with M)
53
+ if (c2 !== undefined && c2 >= '0' && c2 <= '9') {
54
+ const rest = this._buf.slice(i);
55
+ const mu = rest.match(/^\x1b\[\d+;\d+;\d+M/);
56
+ if (mu) { i += mu[0].length; continue; }
57
+ // partial — if short, wait for more data
58
+ if (rest.length < 20) break;
59
+ // Not a mouse seq — fall through to pass through ESC
60
+ }
61
+ // Focus-gained/lost: \x1b[I \x1b[O — these look like keys in some
62
+ // terminals but are focus events; drop them silently.
63
+ if (c2 === 'I' || c2 === 'O') { i += 3; continue; }
42
64
  }
65
+
43
66
  out += this._buf[i++];
44
67
  }
45
68
  this._buf = this._buf.slice(i);