ispbills-icli 8.7.0 → 8.7.1
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 +18 -7
- package/src/tui/mouse.js +6 -6
- package/src/tui/run.js +55 -1
package/package.json
CHANGED
package/src/tui/app.js
CHANGED
|
@@ -434,7 +434,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
434
434
|
const [diffState, setDiffState] = useState(null);
|
|
435
435
|
const chipsRows = (!busy && chips.length && !choice && !search && !sessionPicker && !diffState) ? 1 : 0;
|
|
436
436
|
const composerRows = 2;
|
|
437
|
-
const chromeRows = 2 + composerRows + 1 + chipsRows +
|
|
437
|
+
const chromeRows = 2 + composerRows + 1 + chipsRows + 2; // +2 for two footer rows
|
|
438
438
|
const viewportRows = Math.max(3, rows - chromeRows);
|
|
439
439
|
const scrollPage = Math.max(4, viewportRows - 2);
|
|
440
440
|
|
|
@@ -2090,11 +2090,15 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
2090
2090
|
const cwdMaxLen = Math.max(12, cols - footerRightEstLen - (branch ? branch.length + 6 : 0) - 4);
|
|
2091
2091
|
const cwd = shortenPath(process.cwd(), cwdMaxLen);
|
|
2092
2092
|
const footerLeft = [cwd, branch ? `${glyphs.gitBranch}${branch}` : null].filter(Boolean).join(midDot());
|
|
2093
|
-
const
|
|
2093
|
+
const footerInfoRight = streamerMode ? '' : [modelLabel, tokenLabel].filter(Boolean).join(midDot());
|
|
2094
|
+
// Status row: working indicator when busy, key hints when idle, hint message when set
|
|
2095
|
+
const footerStatusLeft = busy
|
|
2096
|
+
? `${glyphs.spinner} Working\u2026`
|
|
2097
|
+
: hint
|
|
2094
2098
|
? hint
|
|
2095
|
-
:
|
|
2096
|
-
|
|
2097
|
-
|
|
2099
|
+
: `? help ${midDot()} / commands ${midDot()} \u2191\u2193 history ${midDot()} Tab mode`;
|
|
2100
|
+
const footerStatusColor = busy ? C.warning : hint ? C.warning : C.muted;
|
|
2101
|
+
const footerStatusRight = busy ? `Ctrl+C to cancel` : '';
|
|
2098
2102
|
const composerMode = shellMode ? 'shell' : mode;
|
|
2099
2103
|
|
|
2100
2104
|
// ── Viewport slicing ───────────────────────────────────────────────────────
|
|
@@ -2210,9 +2214,16 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
2210
2214
|
|
|
2211
2215
|
<${Box} paddingX=${1} width=${cols}>
|
|
2212
2216
|
<${Box} flexGrow=${1}>
|
|
2213
|
-
<${Text} color=${
|
|
2217
|
+
<${Text} color=${footerStatusColor} wrap="truncate-end">${footerStatusLeft}<//>
|
|
2214
2218
|
<//>
|
|
2215
|
-
<${Text} color=${
|
|
2219
|
+
<${Text} color=${footerStatusColor} dimColor wrap="truncate-end">${footerStatusRight}<//>
|
|
2220
|
+
<//>
|
|
2221
|
+
|
|
2222
|
+
<${Box} paddingX=${1} width=${cols}>
|
|
2223
|
+
<${Box} flexGrow=${1}>
|
|
2224
|
+
<${Text} color=${C.muted} dimColor wrap="truncate-end">${footerLeft}<//>
|
|
2225
|
+
<//>
|
|
2226
|
+
<${Text} color=${C.muted} dimColor wrap="truncate-end">${footerInfoRight}<//>
|
|
2216
2227
|
<//>
|
|
2217
2228
|
<//>
|
|
2218
2229
|
<//>`;
|
package/src/tui/mouse.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useEffect, useRef } from './dom.js';
|
|
2
|
-
import { useStdin } from 'ink';
|
|
3
2
|
|
|
4
3
|
function parseMouseData(chunk, emit) {
|
|
5
4
|
let i = 0;
|
|
@@ -28,15 +27,16 @@ function parseMouseData(chunk, emit) {
|
|
|
28
27
|
return '';
|
|
29
28
|
}
|
|
30
29
|
|
|
30
|
+
// Read directly from process.stdin (before Ink's filtered stream) so we see
|
|
31
|
+
// the raw mouse escape sequences that the filter strips out in run.js.
|
|
31
32
|
export function useMouse(handler, enabled = true) {
|
|
32
|
-
const { stdin } = useStdin();
|
|
33
33
|
const handlerRef = useRef(handler);
|
|
34
34
|
const bufferRef = useRef('');
|
|
35
35
|
|
|
36
36
|
handlerRef.current = handler;
|
|
37
37
|
|
|
38
38
|
useEffect(() => {
|
|
39
|
-
if (!enabled
|
|
39
|
+
if (!enabled) return;
|
|
40
40
|
|
|
41
41
|
try { process.stdout.write('\x1b[?1000h\x1b[?1006h'); } catch {}
|
|
42
42
|
|
|
@@ -47,11 +47,11 @@ export function useMouse(handler, enabled = true) {
|
|
|
47
47
|
});
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
-
stdin.on('data', onData);
|
|
50
|
+
process.stdin.on('data', onData);
|
|
51
51
|
return () => {
|
|
52
|
-
stdin.off('data', onData);
|
|
52
|
+
process.stdin.off('data', onData);
|
|
53
53
|
bufferRef.current = '';
|
|
54
54
|
try { process.stdout.write('\x1b[?1000l\x1b[?1006l'); } catch {}
|
|
55
55
|
};
|
|
56
|
-
}, [enabled
|
|
56
|
+
}, [enabled]);
|
|
57
57
|
}
|
package/src/tui/run.js
CHANGED
|
@@ -1,9 +1,58 @@
|
|
|
1
1
|
// Ink render entrypoint. Runs the TUI in a full-screen ALT-SCREEN viewport.
|
|
2
2
|
import { html } from './dom.js';
|
|
3
3
|
import { render } from 'ink';
|
|
4
|
+
import { Transform } from 'stream';
|
|
4
5
|
import { App } from './app.js';
|
|
5
6
|
import { saveConfig } from '../config.js';
|
|
6
7
|
|
|
8
|
+
// ── Mouse sequence filter ────────────────────────────────────────────────────
|
|
9
|
+
// Strips SGR (\x1b[<N;N;N[Mm]) and X10 (\x1b[M + 3 bytes) mouse escape
|
|
10
|
+
// sequences from the stdin stream before Ink sees it. Without this, unrecognised
|
|
11
|
+
// CSI sequences leak into the composer as raw characters when clicking/scrolling.
|
|
12
|
+
// mouse.js reads from process.stdin directly (before this filter) to get events.
|
|
13
|
+
class MouseFilterTransform extends Transform {
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
this.isTTY = process.stdin.isTTY;
|
|
17
|
+
this.setRawMode = process.stdin.setRawMode
|
|
18
|
+
? (mode) => process.stdin.setRawMode(mode)
|
|
19
|
+
: undefined;
|
|
20
|
+
this._buf = '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
_transform(chunk, _enc, cb) {
|
|
24
|
+
const text = Buffer.isBuffer(chunk) ? chunk.toString('latin1') : String(chunk);
|
|
25
|
+
this._buf += text;
|
|
26
|
+
let out = '';
|
|
27
|
+
let i = 0;
|
|
28
|
+
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
|
|
42
|
+
}
|
|
43
|
+
out += this._buf[i++];
|
|
44
|
+
}
|
|
45
|
+
this._buf = this._buf.slice(i);
|
|
46
|
+
if (out) this.push(out);
|
|
47
|
+
cb();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
_flush(cb) {
|
|
51
|
+
if (this._buf) { this.push(this._buf); this._buf = ''; }
|
|
52
|
+
cb();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
7
56
|
// ── Alt-screen management ────────────────────────────────────────────────────
|
|
8
57
|
// Switch to the alternate terminal buffer so the TUI owns the full viewport and
|
|
9
58
|
// nothing leaks into the user's native scrollback. Must run BEFORE Ink renders.
|
|
@@ -124,6 +173,11 @@ export async function runTui(cfg, opts = {}) {
|
|
|
124
173
|
try { saveConfig(cfg); } catch {}
|
|
125
174
|
}
|
|
126
175
|
|
|
176
|
+
// Pipe raw stdin through the mouse filter so Ink never sees mouse escape
|
|
177
|
+
// sequences. mouse.js reads from process.stdin directly to capture events.
|
|
178
|
+
const mouseFilter = new MouseFilterTransform();
|
|
179
|
+
process.stdin.pipe(mouseFilter);
|
|
180
|
+
|
|
127
181
|
const instance = render(
|
|
128
182
|
html`<${App}
|
|
129
183
|
cfg=${cfg}
|
|
@@ -134,7 +188,7 @@ export async function runTui(cfg, opts = {}) {
|
|
|
134
188
|
resumeMode=${resumeMode}
|
|
135
189
|
onExternal=${(a) => { externalAction = a; onExternal?.(a); }}
|
|
136
190
|
/>`,
|
|
137
|
-
{ exitOnCtrlC: false },
|
|
191
|
+
{ exitOnCtrlC: false, stdin: mouseFilter },
|
|
138
192
|
);
|
|
139
193
|
|
|
140
194
|
try {
|