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 +1 -1
- package/src/tui/app.js +20 -15
- package/src/tui/composer.js +5 -0
- package/src/tui/run.js +36 -13
package/package.json
CHANGED
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',
|
|
1110
|
-
{ id: 'openai/gpt-4o',
|
|
1111
|
-
{ id: 'openai/gpt-4.1',
|
|
1112
|
-
{ id: 'openai/
|
|
1113
|
-
{ id: 'openai/o3
|
|
1114
|
-
{ id: '
|
|
1115
|
-
{ id: 'anthropic/claude-
|
|
1116
|
-
{ id: 'anthropic/claude-3-
|
|
1117
|
-
{ id: '
|
|
1118
|
-
{ id: '
|
|
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 Codex — advanced coding' },
|
|
1113
|
+
{ id: 'openai/o3', desc: 'OpenAI o3 — reasoning' },
|
|
1114
|
+
{ id: 'openai/o3-mini', desc: 'OpenAI o3-mini — fast reasoning' },
|
|
1115
|
+
{ id: 'anthropic/claude-sonnet-4-6', desc: 'Claude Sonnet 4.6 — latest (recommended)' },
|
|
1116
|
+
{ id: 'anthropic/claude-3-5-sonnet', desc: 'Claude 3.5 Sonnet — strong' },
|
|
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
|
-
:
|
|
2134
|
-
|
|
2135
|
-
|
|
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=${
|
|
2262
|
+
<${Text} color=${footerStatusRightColor} bold wrap="truncate-end">${footerStatusRight}<//>
|
|
2258
2263
|
<//>
|
|
2259
2264
|
|
|
2260
2265
|
<${Box} paddingX=${1} width=${cols}>
|
package/src/tui/composer.js
CHANGED
|
@@ -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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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);
|