@modelstatus/cli 0.1.45 → 0.1.47

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": "@modelstatus/cli",
3
- "version": "0.1.45",
3
+ "version": "0.1.47",
4
4
  "description": "Track which AI models you use, where, and never get surprised by a retirement. Free offline model-health for any repo (mm status), browser sign-in for cloud inventory + alerts.",
5
5
  "keywords": [
6
6
  "llm",
package/src/tui/app.js CHANGED
@@ -47,9 +47,22 @@ function useTermDims() {
47
47
  const [dims, setDims] = React.useState({ cols: (stdout && stdout.columns) || 80, rows: (stdout && stdout.rows) || 24 });
48
48
  React.useEffect(() => {
49
49
  if (!stdout) return undefined;
50
- const on = () => setDims({ cols: stdout.columns || 80, rows: stdout.rows || 24 });
50
+ // Functional update that returns the SAME object when nothing changed, so a
51
+ // re-measure that finds identical dims doesn't trigger a needless re-render.
52
+ const on = () => setDims((prev) => {
53
+ const cols = stdout.columns || 80, rows = stdout.rows || 24;
54
+ return prev.cols === cols && prev.rows === rows ? prev : { cols, rows };
55
+ });
51
56
  stdout.on("resize", on);
52
- return () => stdout.off("resize", on);
57
+ // Re-measure a few beats after mount. When the TUI REMOUNTS right after the
58
+ // game leaves the alternate screen, some terminals (notably Warp's block
59
+ // model) re-flow the viewport a moment LATER and report stdout.{columns,rows}
60
+ // stale at mount-time — so the first frame is too SHORT and Ink falls back to
61
+ // cursor-up diffing, which drifts/scrolls the window off the top (and Ctrl-L
62
+ // can't fix it because it redraws at the same wrong height). These one-shot
63
+ // re-reads pick up the settled size and snap the window back to full screen.
64
+ const timers = [60, 250, 600].map((ms) => setTimeout(on, ms));
65
+ return () => { stdout.off("resize", on); timers.forEach(clearTimeout); };
53
66
  }, [stdout]);
54
67
  const fw = Number(process.env.MM_TUI_WIDTH);
55
68
  const fh = Number(process.env.MM_TUI_HEIGHT);
@@ -73,7 +73,19 @@ export async function playGameInTui({ dir, width, height, initialView = "scan",
73
73
  try { if (cacheFile) fs.unlinkSync(cacheFile); } catch { /* ignore */ }
74
74
  }
75
75
 
76
- // (4) Remount the TUI where the player was (so quitting returns you there).
76
+ // (4) Reset the terminal to a clean full screen BEFORE remounting. The game
77
+ // left the alternate screen (\x1b[?1049l), which restores the PRE-game main
78
+ // buffer + cursor — i.e. wherever Ink sat when it unmounted (below the old
79
+ // frame). Ink renders its first frame from that cursor, so without this the
80
+ // TUI comes back shifted down / not full-height until the next resize. Reset
81
+ // the scroll region (\x1b[r), clear the screen, and home the cursor so the
82
+ // remounted tree fills the whole terminal from the top (same as Ctrl-L).
83
+ try { process.stdout.write("\x1b[r\x1b[2J\x1b[3J\x1b[H"); } catch { /* ignore */ }
84
+ // Let the terminal re-flow after leaving the alt screen before Ink measures —
85
+ // some terminals (Warp's block model) report a stale size for a beat, which
86
+ // would make Ink render too short and drift. useTermDims also re-measures a
87
+ // few beats post-mount as a backstop.
88
+ await new Promise((r) => setTimeout(r, 80));
77
89
  appController.remount({ initialView, fresh: false });
78
90
  } catch (e) {
79
91
  if (onError) onError(e); else throw e;