dsh-neotui 0.0.24 → 0.0.25

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/views.js +19 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-neotui",
3
- "version": "0.0.24",
3
+ "version": "0.0.25",
4
4
  "description": "Neo-TUI: mouse-driven terminal UI client for DeepSeek Harness (B-tier per dsh-tui-design.md)",
5
5
  "type": "module",
6
6
  "bin": { "dsh-neotui": "bin/dsh-tui.js" },
package/src/views.js CHANGED
@@ -570,6 +570,7 @@ export class ChatView extends Widget {
570
570
  this.thinkMode = "expanded"; // think blocks: expanded by default (t toggles)
571
571
  this.bashMode = "expanded"; // tool blocks: expanded | collapsed (b toggles)
572
572
  this.todosVisible = true; // todo block above the input (Shift+T toggles)
573
+ this.todoSeen = false; // once seen, the todo box keeps its height
573
574
  this.running = false;
574
575
  this.hasMore = false;
575
576
  this.loadingOlder = false;
@@ -717,11 +718,16 @@ export class ChatView extends Widget {
717
718
  }
718
719
  }
719
720
 
720
- /** Height of the collapsible todo block (0 when empty or collapsed). */
721
+ /** Height of the collapsible todo block. FROZEN at the max (1 header + 6
722
+ * items) once the session has ever shown todos: the harness updates the
723
+ * list in the background while the user reads, and a height that tracks
724
+ * the count reflows the whole layout every time (the idle 2-line shifts). */
721
725
  todoHeight() {
722
726
  const todos = this.app.todos;
723
- if (!this.todosVisible || !todos || todos.length === 0) return 0;
724
- return Math.min(todos.length, 6) + 1; // 1 header row + up to 6 todos
727
+ if (!this.todosVisible) return 0;
728
+ if (!todos || todos.length === 0) return this.todoSeen ? 7 : 0;
729
+ this.todoSeen = true;
730
+ return 7; // fixed max height — short lists just show fewer rows
725
731
  }
726
732
 
727
733
  inputChanged() {
@@ -1719,7 +1725,9 @@ export class App {
1719
1725
  }
1720
1726
 
1721
1727
  footerHeight() {
1722
- return 2 + (this.jobs?.length ? 1 : 0);
1728
+ // Constant 3 rows: the jobs summary row is always present, so jobs
1729
+ // arriving/completing in the background never reflow the layout.
1730
+ return 3;
1723
1731
  }
1724
1732
 
1725
1733
  layout() {
@@ -2859,11 +2867,13 @@ export class App {
2859
2867
  if (stats.ttftMs) row1.right.push({ t: ` 首响${Math.round(stats.ttftMs / stats.ttftSteps)}ms `, fg: T.FAINT, bg: T.STATUSBG });
2860
2868
  }
2861
2869
  rows.push(row1);
2862
- // ── row 2: background jobs — one summary line, never per-job noise ──
2863
- if (this.jobs?.length) {
2864
- const running = this.jobs.filter((j) => j.status === "running").length;
2865
- const done = this.jobs.filter((j) => j.status === "completed").length;
2866
- const failed = this.jobs.filter((j) => j.status === "failed").length;
2870
+ // ── row 2: background jobs — one summary line, always present so its
2871
+ // appearance/disappearance never reflows the layout ──
2872
+ {
2873
+ const jobs = this.jobs ?? [];
2874
+ const running = jobs.filter((j) => j.status === "running").length;
2875
+ const done = jobs.filter((j) => j.status === "completed").length;
2876
+ const failed = jobs.filter((j) => j.status === "failed").length;
2867
2877
  const row2 = { left: [], right: [] };
2868
2878
  row2.left.push({
2869
2879
  t: ` ${running > 0 ? `${running} 个任务正在后台运行` : "没有任务正在后台运行"} `,