dsh-neotui 0.0.6 → 0.0.8
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 +1 -1
- package/src/panels.js +1 -0
- package/src/views.js +33 -24
package/package.json
CHANGED
package/src/panels.js
CHANGED
|
@@ -222,6 +222,7 @@ export function buildCommandPalette(app) {
|
|
|
222
222
|
const w = Math.min(70, app.screen.w - 4), h = Math.min(26, app.screen.h - 4);
|
|
223
223
|
const items = [
|
|
224
224
|
{ label: "新建会话", hint: "n", action: () => app.newSession(), keywords: "new session create" },
|
|
225
|
+
{ label: "新建工作区…", action: () => app.addWorkspace(), keywords: "new workspace create directory" },
|
|
225
226
|
{ label: "打开会话…", hint: "o", action: () => app.openSessionPicker(), keywords: "open session" },
|
|
226
227
|
{ label: "搜索会话", hint: "/", action: () => app.startSearch(), keywords: "search find" },
|
|
227
228
|
{ label: "重命名当前会话", action: () => app.renameCurrent(), keywords: "rename title" },
|
package/src/views.js
CHANGED
|
@@ -111,12 +111,12 @@ function diffText(oldText, newText, width) {
|
|
|
111
111
|
|
|
112
112
|
// ---- Chat node model ----
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
/** Apply ONE event onto a mutable nodes array (shared by full-window
|
|
115
|
+
* derivation and the incremental mux merge — the two paths must agree). */
|
|
116
|
+
function applyEvent(nodes, event, view, log) {
|
|
116
117
|
const cur = () => nodes[nodes.length - 1];
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
switch (event.type) {
|
|
118
|
+
const d = event.data ?? {};
|
|
119
|
+
switch (event.type) {
|
|
120
120
|
case "user/message": {
|
|
121
121
|
const text = partsToText(d.content ?? d.message?.content);
|
|
122
122
|
const images = partsToImages(d.content ?? d.message?.content);
|
|
@@ -238,7 +238,12 @@ function nodeForEvents(events, log) {
|
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
|
-
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Re-derive the whole node list from a complete event window (open/poll). */
|
|
244
|
+
function nodeForEvents(events, log) {
|
|
245
|
+
const nodes = [];
|
|
246
|
+
for (const { event, view } of events) applyEvent(nodes, event, view, log);
|
|
242
247
|
return nodes;
|
|
243
248
|
}
|
|
244
249
|
|
|
@@ -455,11 +460,19 @@ class SidebarTree extends Widget {
|
|
|
455
460
|
if (ev.kind === "press" && ev.button === 2) {
|
|
456
461
|
const idx = this.scrollY + (ev.y - this.y - 2);
|
|
457
462
|
const row = this.rows[idx];
|
|
458
|
-
if (!row)
|
|
463
|
+
if (!row) {
|
|
464
|
+
// right-click on empty sidebar space → workspace-level actions
|
|
465
|
+
this.app.openMenu([
|
|
466
|
+
{ label: "新建工作区…", action: () => this.app.addWorkspace() },
|
|
467
|
+
{ label: "新建会话", action: () => this.app.newSessionIn(null) },
|
|
468
|
+
], ev);
|
|
469
|
+
return true;
|
|
470
|
+
}
|
|
459
471
|
this.sel = idx;
|
|
460
472
|
if (row.kind === "group") {
|
|
461
473
|
const items = [
|
|
462
474
|
{ label: "新建会话", action: () => this.app.newSessionIn(row.group) },
|
|
475
|
+
{ label: "新建工作区…", action: () => this.app.addWorkspace() },
|
|
463
476
|
{ label: "折叠全部", action: () => { this.collapseAll(); this.app.redraw(); } },
|
|
464
477
|
{ label: "展开全部", action: () => { this.expandAll(); this.app.redraw(); } },
|
|
465
478
|
];
|
|
@@ -557,23 +570,13 @@ export class ChatView extends Widget {
|
|
|
557
570
|
}
|
|
558
571
|
|
|
559
572
|
/** Queue a rebuild; flushed on the next frame render (throttles streaming). */
|
|
560
|
-
/** Merge freshly arrived events (mux frames
|
|
573
|
+
/** Merge freshly arrived events (mux frames) into the tail INCREMENTALLY —
|
|
574
|
+
* each event mutates this.nodes directly via the same applyEvent the
|
|
575
|
+
* full-window re-derivation uses, so a lone reasoning-delta appends to the
|
|
576
|
+
* existing block instead of wiping it (the old "shows then deleted" bug). */
|
|
561
577
|
mergeEvents(entries) {
|
|
562
|
-
const
|
|
563
|
-
|
|
564
|
-
const last = nodes[nodes.length - 1];
|
|
565
|
-
const mine = this.nodes[this.nodes.length - 1];
|
|
566
|
-
// Only merge into the ACTIVE streaming node; a newly started turn is pushed
|
|
567
|
-
// as its own node (merging into a finalized turn would overwrite it).
|
|
568
|
-
if (last.kind === "assistant" && mine && mine.kind === "assistant" && mine.streaming) {
|
|
569
|
-
mine.blocks = last.blocks;
|
|
570
|
-
mine.images = last.images ?? mine.images;
|
|
571
|
-
mine.id = last.id ?? mine.id;
|
|
572
|
-
mine.streaming = last.streaming;
|
|
573
|
-
mine.finalized = false;
|
|
574
|
-
} else {
|
|
575
|
-
this.nodes.push(...nodes);
|
|
576
|
-
this.expanded.add(this.nodes.length - 1);
|
|
578
|
+
for (const { event, view } of entries) {
|
|
579
|
+
applyEvent(this.nodes, event, view, this.app.log);
|
|
577
580
|
}
|
|
578
581
|
this.running = this.nodes.some((n) => n.kind === "assistant" && n.streaming);
|
|
579
582
|
this.queueRebuild();
|
|
@@ -737,6 +740,9 @@ export class ChatView extends Widget {
|
|
|
737
740
|
this.nodes = [{ kind: "system", text: `加载失败: ${e.message}` }];
|
|
738
741
|
}
|
|
739
742
|
this.#rebuild();
|
|
743
|
+
// Jump to the LIVE tail (the newest content) on open — the view would
|
|
744
|
+
// otherwise sit at the top showing the oldest turns.
|
|
745
|
+
this.view.scrollY = this.view.maxScroll();
|
|
740
746
|
}
|
|
741
747
|
|
|
742
748
|
async loadOlder() {
|
|
@@ -2265,7 +2271,10 @@ export class App {
|
|
|
2265
2271
|
if (ev.ctrl && ev.key === "m") { this.overlay = buildModelPicker(this); this.redraw(); return; }
|
|
2266
2272
|
if (ev.name === "f8") { this.rotatePermission(); return; }
|
|
2267
2273
|
if (ev.name === "f9") { this.showModePicker(); return; }
|
|
2268
|
-
if (ev.ctrl && ev.key === "w") {
|
|
2274
|
+
if (ev.ctrl && ev.key === "w") {
|
|
2275
|
+
if (ev.shift) { this.addWorkspace(); return; }
|
|
2276
|
+
this.setMode("workspace"); return;
|
|
2277
|
+
}
|
|
2269
2278
|
if (ev.ctrl && ev.key === "t") { this.setMode("trajectory"); return; }
|
|
2270
2279
|
if (ev.ctrl && ev.key === "j") { this.showJobs(); return; }
|
|
2271
2280
|
if (ev.ctrl && ev.key === "g") { this.showGoal(); return; }
|