ispbills-icli 8.4.10 → 8.4.11

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/tui/app.js +34 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ispbills-icli",
3
- "version": "8.4.10",
3
+ "version": "8.4.11",
4
4
  "description": "iCli — IspBills AI network engineer in your terminal",
5
5
  "keywords": [
6
6
  "ispbills",
package/src/tui/app.js CHANGED
@@ -131,41 +131,60 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, ve
131
131
  });
132
132
 
133
133
  // ── Mouse event handling ────────────────────────────────────────────────────
134
- // Tab bar occupies row 1 (1-indexed y). Each tab is: 2-char prefix + label
135
- // + marginRight=2. paddingX=1 on the outer Box shifts all tabs one column
136
- // right, so column 2 is where the first tab starts.
134
+ // Tab bar x-ranges (1-indexed). Layout: paddingX=1 on the TabBar outer Box
135
+ // so text starts at column 2. Each tab = 2-char prefix (' ' or '❯ ') +
136
+ // label text, followed by marginRight=2 before the next tab.
137
137
  const tabClickRanges = useMemo(() => {
138
- let x = 2; // paddingX=1 → first content starts at column 2 (1-indexed)
138
+ let x = 2; // paddingX=1 → first tab starts at column 2
139
139
  return TABS.map((label) => {
140
140
  const start = x;
141
- const w = 2 + label.length; // ' ' or '❯ ' prefix + label chars
142
- x += w + 2; // +2 for marginRight
141
+ const w = 2 + label.length; // prefix (2 chars) + label
142
+ x += w + 2; // advance past tab + marginRight=2
143
143
  return { start, end: start + w - 1 };
144
144
  });
145
145
  }, []);
146
146
 
147
147
  useEffect(() => {
148
- const TAB_ROW = 1; // y=1 in SGR coords (first row)
149
-
150
148
  const onMouse = ({ btn, x, y, press }) => {
151
- // ── Scroll wheel UP → scroll the terminal viewport to reveal history ──
149
+ // ── Scroll wheel UP → scroll viewport to reveal history ──────────────
152
150
  if (btn === 64) {
153
151
  try { process.stdout.write('\x1b[3S'); } catch {}
154
152
  return;
155
153
  }
156
- // ── Scroll wheel DOWN → swallowed (no drifting below live area) ────────
154
+ // ── Scroll wheel DOWN → swallowed ─────────────────────────────────────
157
155
  if (btn === 65) return;
158
156
 
159
- // ── Left click (btn=0, press) on tab bar row ──────────────────────────
160
- if (btn === 0 && press && y === TAB_ROW) {
161
- const idx = tabClickRanges.findIndex((r) => x >= r.start && x <= r.end);
162
- if (idx >= 0) setActiveTab(idx);
157
+ // ── Left click tab bar ─────────────────────────────────────────────
158
+ // Ink renders INLINE at the bottom of the terminal — NOT at y=1.
159
+ // SGR y coordinates are 1-indexed from the terminal top.
160
+ //
161
+ // Layout rows at idle (bottom-to-top):
162
+ // rows = footer hint
163
+ // rows-1 = composer bottom border
164
+ // rows-2 = composer input
165
+ // rows-3 = composer top border
166
+ // rows-4 = blank (marginTop=1 before composer)
167
+ // rows-5 = tab separator
168
+ // rows-6 = tab labels ← TAB_ROW at idle
169
+ // rows-7 = compact header
170
+ //
171
+ // When there is live content of height h between tab separator and
172
+ // composer, each row shifts up by h: TAB_ROW = rows - 6 - liveH.
173
+ if (btn === 0 && press) {
174
+ const liveH = live
175
+ ? 1 + Math.min((live.status?.length || 0) + (live.text ? 2 : 0) + (!live.text && !live.reply?.steps ? 1 : 0), 12)
176
+ : 0;
177
+ const tabRowY = rows - 6 - liveH;
178
+ if (Math.abs(y - tabRowY) <= 1) { // ±1 row tolerance
179
+ const idx = tabClickRanges.findIndex((r) => x >= r.start && x <= r.end);
180
+ if (idx >= 0) setActiveTab(idx);
181
+ }
163
182
  }
164
183
  };
165
184
 
166
185
  mouseEvents.on('event', onMouse);
167
186
  return () => mouseEvents.off('event', onMouse);
168
- }, [tabClickRanges]);
187
+ }, [tabClickRanges, rows, live]);
169
188
 
170
189
  const setAutopilotMode = useCallback((next) => {
171
190
  apRef.current = next;