pi-zentui 0.22.2 → 0.22.3
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/README.md
CHANGED
|
@@ -146,7 +146,7 @@ Useful shortcuts:
|
|
|
146
146
|
|
|
147
147
|
**Thinking (Experimental)** uses one private `AssistantMessageComponent` renderer for Rail, Tree, and Streaming, tested against exact Pi versions 0.80.5, 0.82.1, 0.83.0, 0.84.0, and 0.84.4. It is disabled by default and may break after Pi updates. Zentui installs an enabled startup mode before transcript restoration. A healthy installed controller lets active Streaming switch live to Rail or Tree, and lets Rail and Tree switch live between each other, without reinstalling its patch. Entering Streaming from Rail or Tree saves the choice but keeps the active structural mode until restart. Disabling live restores native thinking and releases Streaming resources. First enable and re-enable after a live disable are also restart-gated. Mode changes while disabled only preconfigure the next enable. Startup failures, missing constructors, incompatible private child layouts, parser limits, theme/render/width errors, and displaced patch ownership fail open to complete native thinking. If cleanup throws while leaving Streaming, disabling still restores native thinking and a structural selection still becomes active; the successful change warns that Streaming is unavailable for the rest of the session.
|
|
148
148
|
|
|
149
|
-
Rail shows every parsed label in each native contiguous thinking run (`│ Label`, with only the open final phase shown as `│ • Label`). Tree independently shows the latest five labels in each run (`├─ · Label`, settled `└─ · Label`, open `└─ • Label`); it never aggregates across intervening text or tool blocks. Rail and Tree follow Pi's thinking visibility
|
|
149
|
+
Rail shows every parsed label in each native contiguous thinking run (`│ Label`, with only the open final phase shown as `│ • Label`). Tree independently shows the latest five labels in each run (`├─ · Label`, settled `└─ · Label`, open `└─ • Label`); it never aggregates across intervening text or tool blocks. Rail and Tree follow Pi's thinking visibility. Complete strict SGR styling is stripped before parsing; every other terminal control and unsafe or unstructured content keeps the complete run native. Labels are rendered by fresh host-shaped Pi Markdown instances before cropping, so emphasis, code, links, HTML, LaTeX, custom transforms, and native `thinkingText` styling remain host-controlled. Every label occupies one terminal row: ANSI/OSC/grapheme-aware cropping adds `…` only when needed. Native horizontal padding stays external. Connectors are styled directly with the current theme's `accent` callback on every render, so custom themes control them independently. Hidden native thinking remains hidden and keeps Pi's native hidden label.
|
|
150
150
|
|
|
151
151
|
Streaming retains Pi's host-rendered final five rows under `Thinking 7.1s`, folds completed reasoning under `Thought` or current-session `Thought for 12.3s`, and owns the configured thinking-toggle binding (Ctrl+T by default) only when started in Streaming. Its input listener and timer are acquired only for an enabled Streaming session start; startup acquisition failure uses native thinking and marks Streaming unavailable. Restored completions cannot recover a duration because Pi does not persist the thinking-end timestamp. Expand/refold and lifecycle tracking are bounded to 256 retained assistant components; evicted entries are first restored natively. All modes restore/dispose on shutdown. Thinking (Experimental) never writes the Working line and does not change its existing **Thinking time** option, working text, Footer, Editor, statuses, or model behavior.
|
|
152
152
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sanitizeSgrOnlySourceText } from "./user-message-osc";
|
|
2
2
|
|
|
3
3
|
/** Hard limits keep private transcript parsing synchronous and bounded. Limits are inclusive. */
|
|
4
4
|
export const THINKING_STEPS_MAX_INPUT_LENGTH = 65_536;
|
|
@@ -109,9 +109,8 @@ function finishSteps(steps: MutableStep[]): ThinkingStep[] | undefined {
|
|
|
109
109
|
/** Parse source-level structure; fenced and display-math blocks remain opaque bodies. */
|
|
110
110
|
export function parseThinkingSteps(markdown: string): readonly ThinkingStep[] | undefined {
|
|
111
111
|
if (!markdown || markdown.length > THINKING_STEPS_MAX_INPUT_LENGTH) return undefined;
|
|
112
|
-
const source = markdown.replace(/\r\n/g, "\n");
|
|
113
|
-
|
|
114
|
-
if (sanitized !== source || !source.trim()) return undefined;
|
|
112
|
+
const source = sanitizeSgrOnlySourceText(markdown.replace(/\r\n/g, "\n"));
|
|
113
|
+
if (source === undefined || !source.trim()) return undefined;
|
|
115
114
|
|
|
116
115
|
const lines = source.split("\n");
|
|
117
116
|
const steps: MutableStep[] = [];
|
|
@@ -221,15 +221,29 @@ function filterBalancedUserMessageTerminalText(text: string, options: FilterOpti
|
|
|
221
221
|
return filterUserMessageTerminalText(text, { ...options, preserveValidOsc8: false }).text;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
const sourceFilterOptions = {
|
|
225
|
+
preserveValidOsc8: false,
|
|
226
|
+
preserveSourceWhitespace: true,
|
|
227
|
+
} as const;
|
|
228
|
+
|
|
224
229
|
/** Strip every terminal control from untrusted source text before Markdown rendering. */
|
|
225
230
|
export function sanitizeUserMessageSourceText(text: string): string {
|
|
226
231
|
return filterBalancedUserMessageTerminalText(text, {
|
|
227
|
-
|
|
228
|
-
preserveSourceWhitespace: true,
|
|
232
|
+
...sourceFilterOptions,
|
|
229
233
|
preserveSgr: false,
|
|
230
234
|
});
|
|
231
235
|
}
|
|
232
236
|
|
|
237
|
+
/** Strip strict 7-bit CSI SGR, rejecting source that contains any other terminal control. */
|
|
238
|
+
export function sanitizeSgrOnlySourceText(text: string): string | undefined {
|
|
239
|
+
const sgrPreserved = filterBalancedUserMessageTerminalText(text, {
|
|
240
|
+
...sourceFilterOptions,
|
|
241
|
+
preserveSgr: true,
|
|
242
|
+
});
|
|
243
|
+
if (sgrPreserved !== text) return undefined;
|
|
244
|
+
return sanitizeUserMessageSourceText(text);
|
|
245
|
+
}
|
|
246
|
+
|
|
233
247
|
/**
|
|
234
248
|
* Sanitize a predecessor-rendered row. Pi formatting needs only SGR and
|
|
235
249
|
* structurally valid 7-bit OSC 8; every other terminal control is removed.
|