pi-stereo-view 0.1.3 → 0.1.4
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/CHANGELOG.md +11 -0
- package/README.md +2 -0
- package/package.json +1 -1
- package/src/content.ts +20 -1
- package/src/render-cache.ts +22 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.4 - 2026-10-20
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Keep the split layout active while Pi-Bolt streams thinking or text. Later replies no longer require a restart to restore the panels; saved panel sizes and layout settings stay intact.
|
|
8
|
+
- Hide empty self-rendered tool blocks without leaving blank spacing or timestamps, even when the tool returns images to the model. Normal tool output and visibly rendered images remain visible.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Show late output linked to a tool call directly below that call in Activity, even when other work has happened since. Activity search follows the same grouping; combined history keeps its original order.
|
|
13
|
+
|
|
3
14
|
## 0.1.3 - 2026-10-19
|
|
4
15
|
|
|
5
16
|
- Show the saved split layout from the first visible frame, without briefly displaying the normal layout first.
|
package/README.md
CHANGED
|
@@ -25,6 +25,8 @@ The chat becomes two zones: your conversation with the agent, and the agent's wo
|
|
|
25
25
|
|
|
26
26
|
Unrecognized content stays in Conversation unless its metadata links it to a known tool call.
|
|
27
27
|
|
|
28
|
+
Late output linked to a tool call appears directly below that call in Activity, even if other work has happened since. Combined history keeps its original order.
|
|
29
|
+
|
|
28
30
|
Messages and tools keep their familiar appearance. The input stays full width below both panels.
|
|
29
31
|
|
|
30
32
|
## See it in action
|
package/package.json
CHANGED
package/src/content.ts
CHANGED
|
@@ -24,6 +24,8 @@ interface NativeAssistant extends Container {
|
|
|
24
24
|
contentContainer: Container;
|
|
25
25
|
hasToolCalls: boolean;
|
|
26
26
|
lastMessage?: { content: { type: string; text?: string; thinking?: string }[] };
|
|
27
|
+
contentIsStale?: boolean;
|
|
28
|
+
buildContent?(message: NonNullable<NativeAssistant["lastMessage"]>): void;
|
|
27
29
|
setHideThinkingBlock(hidden: boolean): void;
|
|
28
30
|
}
|
|
29
31
|
|
|
@@ -50,6 +52,14 @@ function assistant(component: Component): NativeAssistant | undefined {
|
|
|
50
52
|
(native.lastMessage !== undefined && !Array.isArray(native.lastMessage.content))) {
|
|
51
53
|
throw new Error("Pi's assistant content metadata is not supported");
|
|
52
54
|
}
|
|
55
|
+
// Pi-Bolt builds streamed children lazily. Synchronize the real owner before
|
|
56
|
+
// indexing or cloning it, so a pane cannot rebuild both content kinds itself.
|
|
57
|
+
if (native.contentIsStale === true) {
|
|
58
|
+
if (!native.lastMessage || typeof native.buildContent !== "function") {
|
|
59
|
+
throw new Error("Pi's deferred assistant content is not supported");
|
|
60
|
+
}
|
|
61
|
+
native.buildContent(native.lastMessage);
|
|
62
|
+
}
|
|
53
63
|
return native;
|
|
54
64
|
}
|
|
55
65
|
|
|
@@ -120,7 +130,16 @@ export class NativeContentIndex {
|
|
|
120
130
|
}
|
|
121
131
|
spacing = [];
|
|
122
132
|
}
|
|
123
|
-
|
|
133
|
+
// Project late execution output beside its owner, never reorder native history.
|
|
134
|
+
const linked = new Map<Component, ContentEntry[]>();
|
|
135
|
+
for (const entry of entries) {
|
|
136
|
+
if (entry.owner === entry.source) continue;
|
|
137
|
+
const group = linked.get(entry.owner) ?? [];
|
|
138
|
+
group.push(entry);
|
|
139
|
+
linked.set(entry.owner, group);
|
|
140
|
+
}
|
|
141
|
+
this.content = entries.flatMap(entry => entry.owner === entry.source
|
|
142
|
+
? [entry, ...(linked.get(entry.source) ?? [])] : []);
|
|
124
143
|
this.signature = signature;
|
|
125
144
|
}
|
|
126
145
|
|
package/src/render-cache.ts
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { stripTerminalSequences, type Component } from "@earendil-works/pi-tui";
|
|
2
|
+
|
|
3
|
+
const imagePlacement = (line: string): boolean => line.includes("\x1b_G") || line.includes("\x1b]1337;File=");
|
|
4
|
+
|
|
5
|
+
function nativeLines(component: Component, width: number): string[] {
|
|
6
|
+
const lines = component.render(width);
|
|
7
|
+
const tool = component as Component & {
|
|
8
|
+
toolDefinition?: { renderShell?: string; renderCall?: unknown; renderResult?: unknown };
|
|
9
|
+
selfRenderHeight?: number;
|
|
10
|
+
};
|
|
11
|
+
const definition = tool.toolDefinition;
|
|
12
|
+
const height = tool.selfRenderHeight;
|
|
13
|
+
if (component.constructor.name !== "ToolExecutionComponent" || definition?.renderShell !== "self" ||
|
|
14
|
+
typeof definition.renderCall !== "function" || typeof definition.renderResult !== "function" ||
|
|
15
|
+
typeof height !== "number" || !Number.isInteger(height) || height < 0) return lines;
|
|
16
|
+
// Native self shells prepend one row, then append result images outside the custom UI.
|
|
17
|
+
// An intentionally empty custom UI must not be made visible by those automatic images.
|
|
18
|
+
const content = height ? lines.slice(1, height + 1) : [];
|
|
19
|
+
return content.some(line => imagePlacement(line) || stripTerminalSequences(line).trim().length > 0) ? lines : [];
|
|
20
|
+
}
|
|
2
21
|
|
|
3
22
|
interface Subscription {
|
|
4
23
|
original: Component["invalidate"];
|
|
@@ -180,9 +199,9 @@ export class NativeRenderCache {
|
|
|
180
199
|
const initial = components(this.component);
|
|
181
200
|
const observed = this.watch(initial);
|
|
182
201
|
const before = this.revision;
|
|
183
|
-
const lines = this.component
|
|
202
|
+
const lines = nativeLines(this.component, width);
|
|
184
203
|
this.outputVersion++;
|
|
185
|
-
this.imagePlacement = lines.some(
|
|
204
|
+
this.imagePlacement = lines.some(imagePlacement);
|
|
186
205
|
const links: NodeLinks[] = [];
|
|
187
206
|
const after = components(this.component, links);
|
|
188
207
|
const stableGraph = initial.length === after.length &&
|