dsh-neotui 0.1.25 → 0.1.27

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/panels.js +15 -21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-neotui",
3
- "version": "0.1.25",
3
+ "version": "0.1.27",
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/panels.js CHANGED
@@ -1977,7 +1977,7 @@ export class ModelPanel extends Widget {
1977
1977
  formLines.push([{ t: ` ${truncate(it.sub, w - 8)}`, fg: K.FAINT, bg: T.BG2 }]);
1978
1978
  }
1979
1979
  }
1980
- formLines.push([{ t: isSub ? " ↑/↓ 移动 · Enter 编辑或执行 · Esc 返回" : " ↑/↓ 换供应商 · →/Tab 进表单(再按下移) · ← 上移/回列表 · Enter 编辑或执行 · Esc 退出", fg: K.FAINT }]);
1980
+ formLines.push([{ t: isSub ? " ↑/↓ 移动 · Enter 编辑或执行 · Esc 返回" : " ↑/↓ 移动 · → 进入选项 · ← 返回列表 · Enter 编辑或执行 · Esc 退出", fg: K.FAINT }]);
1981
1981
  }
1982
1982
  this.formView.setLines(formLines);
1983
1983
  }
@@ -2215,11 +2215,12 @@ export class ModelPanel extends Widget {
2215
2215
  }
2216
2216
  if (this.scanMode) {
2217
2217
  if (ev.name === "escape") { this.scanMode = false; this.#rebuild(); return true; }
2218
- if (ev.name === "up") { this.scanCursor = Math.max(0, this.scanCursor - 1); this.app.redraw(); return true; }
2219
- if (ev.name === "down") { this.scanCursor = Math.min(this.scanItems.length - 1, this.scanCursor + 1); this.app.redraw(); return true; }
2218
+ if (ev.name === "up") { this.scanCursor = Math.max(0, this.scanCursor - 1); this.#rebuild(); this.app.redraw(); return true; }
2219
+ if (ev.name === "down") { this.scanCursor = Math.min(this.scanItems.length - 1, this.scanCursor + 1); this.#rebuild(); this.app.redraw(); return true; }
2220
2220
  if (ev.name === "char" && ev.key === " " && !ev.ctrl) {
2221
2221
  const m = this.scanItems[this.scanCursor];
2222
2222
  if (m) { if (this.scanSel.has(m.id)) this.scanSel.delete(m.id); else this.scanSel.add(m.id); }
2223
+ this.#rebuild();
2223
2224
  this.app.redraw();
2224
2225
  return true;
2225
2226
  }
@@ -2231,11 +2232,13 @@ export class ModelPanel extends Widget {
2231
2232
  if (ev.name === "escape") { this.sub = null; this.#rebuild(); return true; }
2232
2233
  if (ev.name === "up" || (ev.name === "char" && ev.key === "k" && !ev.ctrl)) {
2233
2234
  this.sub.cursor = Math.max(0, this.sub.cursor - 1);
2235
+ this.#rebuild();
2234
2236
  this.app.redraw();
2235
2237
  return true;
2236
2238
  }
2237
2239
  if (ev.name === "down" || (ev.name === "char" && ev.key === "j" && !ev.ctrl)) {
2238
2240
  this.sub.cursor = Math.min(Math.max(0, this.#subItems().length - 1), this.sub.cursor + 1);
2241
+ this.#rebuild();
2239
2242
  this.app.redraw();
2240
2243
  return true;
2241
2244
  }
@@ -2243,39 +2246,30 @@ export class ModelPanel extends Widget {
2243
2246
  return false;
2244
2247
  }
2245
2248
  if (ev.name === "escape") { this.editing = null; return false; } // App falls back to chat mode
2246
- // ↑/↓ ALWAYS walk the provider column (the list is the primary axis —
2247
- // UCAS and + 添加供应商 are both reachable by the arrow keys alone)
2249
+ // dual-focus navigation: ↑/↓ move the cursor INSIDE the focused region —
2250
+ // the provider column in list focus, the option rows in form focus.
2251
+ // → enters the form, ← returns to the list.
2248
2252
  if (ev.name === "up" || (ev.name === "char" && ev.key === "k" && !ev.ctrl)) {
2249
- this.sel = Math.max(0, this.sel - 1);
2250
- this.mode = "list";
2253
+ if (this.mode === "list") this.sel = Math.max(0, this.sel - 1);
2254
+ else this.formIdx = Math.max(0, this.formIdx - 1);
2251
2255
  this.#rebuild();
2252
2256
  this.app.redraw();
2253
2257
  return true;
2254
2258
  }
2255
2259
  if (ev.name === "down" || (ev.name === "char" && ev.key === "j" && !ev.ctrl)) {
2256
- this.sel = Math.min(this.routes.length, this.sel + 1);
2257
- this.mode = "list";
2260
+ if (this.mode === "list") this.sel = Math.min(this.routes.length, this.sel + 1);
2261
+ else this.formIdx = Math.min(Math.max(0, this.formItems.length - 1), this.formIdx + 1);
2258
2262
  this.#rebuild();
2259
2263
  this.app.redraw();
2260
2264
  return true;
2261
2265
  }
2262
- // →/Tab: into the form, then down its rows; ←/Shift+Tab: up the form,
2263
- // and at the top back to the provider list
2264
2266
  if (ev.name === "right" || (ev.name === "char" && ev.key === "l" && !ev.ctrl) || ev.name === "tab") {
2265
- if (this.#route() != null) {
2266
- if (this.mode === "form") this.formIdx = Math.min(Math.max(0, this.formItems.length - 1), this.formIdx + 1);
2267
- else this.mode = "form";
2268
- this.#rebuild();
2269
- }
2267
+ if (this.#route() != null && this.mode !== "form") { this.mode = "form"; this.#rebuild(); }
2270
2268
  this.app.redraw();
2271
2269
  return true;
2272
2270
  }
2273
2271
  if (ev.name === "left" || (ev.name === "char" && ev.key === "h" && !ev.ctrl) || ev.name === "backtab") {
2274
- if (this.mode === "form") {
2275
- if (this.formIdx > 0) this.formIdx--;
2276
- else this.mode = "list";
2277
- this.#rebuild();
2278
- }
2272
+ if (this.mode === "form") { this.mode = "list"; this.#rebuild(); }
2279
2273
  this.app.redraw();
2280
2274
  return true;
2281
2275
  }