dsh-neotui 0.1.14 → 0.1.16

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": "dsh-neotui",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
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": {
package/src/config.js CHANGED
@@ -62,3 +62,14 @@ export function userName() {
62
62
  export function userPrefix() {
63
63
  return `${userName()} > `;
64
64
  }
65
+
66
+ /** Fold defaults (settings → 默认展开/折叠): think/tool blocks and the
67
+ * todo list, with the shipped defaults when nothing is configured. */
68
+ export function foldDefaults() {
69
+ const fd = loadTuiConfig().foldDefaults ?? {};
70
+ return {
71
+ think: fd.think !== false, // think blocks default expanded
72
+ bash: fd.bash === true, // tool blocks default collapsed
73
+ todos: fd.todos !== false, // todo list default visible
74
+ };
75
+ }
package/src/panels.js CHANGED
@@ -10,7 +10,7 @@ import { join, basename, extname } from "node:path";
10
10
  import { spawn, execFileSync } from "node:child_process";
11
11
 
12
12
  import { T, cycleTheme, themeName } from "./theme.js";
13
- import { loadTuiConfig, saveTuiConfig, userPrefix, userName } from "./config.js";
13
+ import { loadTuiConfig, saveTuiConfig, userPrefix, userName, foldDefaults } from "./config.js";
14
14
  // Live theme accessor: K.K.DIM etc. resolve against the active palette at render time.
15
15
  const K = new Proxy({}, { get(_k, key) { return T[key]; } });
16
16
 
@@ -950,14 +950,16 @@ export class TrajectoryPanel extends Widget {
950
950
  lines.push(segs);
951
951
  this.stepLines[lines.length - 1] = si;
952
952
  if (open) {
953
- // 详细 mode: the step's events inline under its color block, each
954
- // with its deep-dive elapsed time since the step started (web-style).
955
- const t0 = step.events[0]?.time;
953
+ // 详细 mode = deep dive: the step's events inline under its color
954
+ // block, each with its OWN duration (web-style Δ timer: time since
955
+ // the previous event; the first is measured from the step start).
956
956
  const evs = step.events.slice(0, 12);
957
+ let prev = null;
957
958
  for (const e of evs) {
958
- const dt = t0 != null && e.time != null ? ` +${fmtMs(e.time - t0)}` : "";
959
+ const dt = prev != null && e.time != null ? ` Δ${fmtMs(e.time - prev)}` : "";
959
960
  lines.push([{ t: ` #${String(e.seq).padStart(4)}${dt} ${truncate(this.#eventSummary(e), w - 12 - strWidth(dt))}`, fg: K.DIM, bg }]);
960
961
  this.stepLines[lines.length - 1] = si;
962
+ prev = e.time;
961
963
  }
962
964
  if (step.events.length > evs.length) {
963
965
  lines.push([{ t: ` …共 ${step.events.length} 个事件(右键 → 查看详情)`, fg: K.FAINT, bg }]);
@@ -1591,6 +1593,13 @@ export class SettingsPanel extends Widget {
1591
1593
  ns: "TUI 界面", applies: "live", local: true,
1592
1594
  value: { userPrefix: userName() },
1593
1595
  });
1596
+ // 默认展开/折叠: the fold-related defaults as a local sub-panel of
1597
+ // booleans (click to toggle), persisted to the TUI config file.
1598
+ const fd = foldDefaults();
1599
+ this.namespaces.splice(1, 0, {
1600
+ ns: "默认展开/折叠", applies: "live", local: true,
1601
+ value: { 思考块默认展开: fd.think, 工具块默认展开: fd.bash, 任务清单默认显示: fd.todos },
1602
+ });
1594
1603
  this.selectNs(0);
1595
1604
  }
1596
1605
  selectNs(i) {
@@ -1719,6 +1728,27 @@ export class SettingsPanel extends Widget {
1719
1728
  if (ns.local) {
1720
1729
  // TUI-local config: write the config file, apply instantly.
1721
1730
  const v = applyOps(ns.value, this.pendingOps);
1731
+ if (ns.ns === "默认展开/折叠") {
1732
+ const patch = { foldDefaults: { think: !!v.思考块默认展开, bash: !!v.工具块默认展开, todos: !!v.任务清单默认显示 } };
1733
+ if (saveTuiConfig(patch)) {
1734
+ this.pendingOps = [];
1735
+ this.app.toast("已保存展开/折叠默认值(即时生效)");
1736
+ // apply live to the current chat
1737
+ const chat = this.app.chat;
1738
+ if (chat) {
1739
+ chat.thinkMode = v.思考块默认展开 ? "expanded" : "collapsed";
1740
+ chat.bashMode = v.工具块默认展开 ? "expanded" : "collapsed";
1741
+ chat.todosVisible = !!v.任务清单默认显示;
1742
+ chat.expanded.clear();
1743
+ chat.collapsedBlocks.clear();
1744
+ chat.queueRebuild();
1745
+ }
1746
+ await this.load();
1747
+ } else {
1748
+ this.app.toast("保存失败:无法写入 TUI 配置文件");
1749
+ }
1750
+ return;
1751
+ }
1722
1752
  const name = String(v.userPrefix ?? "").trim();
1723
1753
  if (saveTuiConfig({ userPrefix: name })) {
1724
1754
  this.pendingOps = [];
package/src/views.js CHANGED
@@ -5,8 +5,8 @@ import { truncate, strWidth, bars, fmtDuration, fmtClock, fmtDateTime } from "./
5
5
  import { readFileSync, appendFileSync, mkdirSync } from "node:fs";
6
6
  import { join } from "node:path";
7
7
  import { Widget, List, ScrollView, Input, Popup, Menu, StatusBar } from "./widgets.js";
8
- import { userPrefix, saveTuiConfig, loadTuiConfig, userName } from "./config.js";
9
- export { userPrefix, saveTuiConfig, loadTuiConfig, userName } from "./config.js";
8
+ import { userPrefix, saveTuiConfig, loadTuiConfig, userName, foldDefaults } from "./config.js";
9
+ export { userPrefix, saveTuiConfig, loadTuiConfig, userName, foldDefaults } from "./config.js";
10
10
  import {
11
11
  Picker, buildCommandPalette, buildModelPicker, buildModePicker, buildPermissionPicker,
12
12
  modeName, permName, WorkspacePanel, TrajectoryPanel, DirPicker,
@@ -595,9 +595,10 @@ export class ChatView extends Widget {
595
595
  this.expanded = new Set(); // node indexes (user-message full text)
596
596
  this.expandedTools = new Set();
597
597
  this.collapsedBlocks = new Set(); // per-block COLLAPSE (default expanded): `${realIdx}:${bi}`
598
- this.thinkMode = "expanded"; // think blocks: expanded by default (t toggles)
599
- this.bashMode = "collapsed"; // tool blocks: collapsed by default (b toggles)
600
- this.todosVisible = true; // todo block above the input (Shift+T toggles)
598
+ const fd = foldDefaults();
599
+ this.thinkMode = fd.think ? "expanded" : "collapsed"; // t toggles
600
+ this.bashMode = fd.bash ? "expanded" : "collapsed"; // b toggles
601
+ this.todosVisible = fd.todos; // Shift+T toggles
601
602
  this.todoSeen = false; // once seen, the todo box keeps its height
602
603
  this.running = false;
603
604
  this.hasMore = false;