pi-studio 0.6.4 → 0.6.6
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 +10 -0
- package/client/studio-client.js +92 -6
- package/client/studio.css +37 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@ All notable changes to `pi-studio` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.6.6] — 2026-04-30
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Studio now opens the right pane on **Editor (Preview)** by default for file-backed and blank launches, while last-response launches still open on the response preview.
|
|
11
|
+
|
|
12
|
+
## [0.6.5] — 2026-04-30
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- Working view output blocks now show a compact 50-line preview by default with per-block **Show full** / **Collapse** controls for longer thinking, responses, and tool input/output.
|
|
16
|
+
|
|
7
17
|
## [0.6.4] — 2026-04-29
|
|
8
18
|
|
|
9
19
|
### Fixed
|
package/client/studio-client.js
CHANGED
|
@@ -174,8 +174,13 @@
|
|
|
174
174
|
let pendingKind = null;
|
|
175
175
|
let stickyStudioKind = null;
|
|
176
176
|
let initialDocumentApplied = false;
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
function getInitialRightView(source) {
|
|
178
|
+
if (isEditorOnlyMode) return "editor-preview";
|
|
179
|
+
return String(source || "").trim() === "last-response" ? "preview" : "editor-preview";
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
let editorView = "markdown";
|
|
183
|
+
let rightView = getInitialRightView(initialSourceState.source);
|
|
179
184
|
let followLatest = !isEditorOnlyMode;
|
|
180
185
|
let queuedLatestResponse = null;
|
|
181
186
|
let latestResponseMarkdown = "";
|
|
@@ -194,6 +199,9 @@
|
|
|
194
199
|
let traceFilter = "all";
|
|
195
200
|
let traceAutoScroll = true;
|
|
196
201
|
let traceRenderRaf = null;
|
|
202
|
+
const traceExpandedOutputs = new Set();
|
|
203
|
+
const TRACE_OUTPUT_PREVIEW_MAX_LINES = 50;
|
|
204
|
+
const TRACE_OUTPUT_PREVIEW_MAX_CHARS = 8000;
|
|
197
205
|
let studioRunChainActive = false;
|
|
198
206
|
let queuedSteeringCount = 0;
|
|
199
207
|
let agentBusyFromServer = false;
|
|
@@ -322,7 +330,11 @@
|
|
|
322
330
|
}
|
|
323
331
|
|
|
324
332
|
function replaceTraceState(nextState) {
|
|
333
|
+
const previousRunId = traceState && traceState.runId ? traceState.runId : null;
|
|
325
334
|
traceState = normalizeTraceState(nextState);
|
|
335
|
+
if ((traceState.runId || null) !== previousRunId) {
|
|
336
|
+
traceExpandedOutputs.clear();
|
|
337
|
+
}
|
|
326
338
|
renderTraceViewIfActive();
|
|
327
339
|
}
|
|
328
340
|
|
|
@@ -2971,6 +2983,21 @@
|
|
|
2971
2983
|
setTraceFilter(nextFilter);
|
|
2972
2984
|
return;
|
|
2973
2985
|
}
|
|
2986
|
+
const outputToggleBtn = target instanceof Element ? target.closest("[data-trace-output-key]") : null;
|
|
2987
|
+
if (outputToggleBtn) {
|
|
2988
|
+
event.preventDefault();
|
|
2989
|
+
const key = outputToggleBtn.getAttribute("data-trace-output-key") || "";
|
|
2990
|
+
if (key) {
|
|
2991
|
+
if (traceExpandedOutputs.has(key)) {
|
|
2992
|
+
traceExpandedOutputs.delete(key);
|
|
2993
|
+
} else {
|
|
2994
|
+
traceExpandedOutputs.add(key);
|
|
2995
|
+
}
|
|
2996
|
+
traceAutoScroll = false;
|
|
2997
|
+
renderTraceViewIfActive();
|
|
2998
|
+
}
|
|
2999
|
+
return;
|
|
3000
|
+
}
|
|
2974
3001
|
const actionBtn = target instanceof Element ? target.closest("[data-trace-action]") : null;
|
|
2975
3002
|
if (!actionBtn) return;
|
|
2976
3003
|
event.preventDefault();
|
|
@@ -3607,6 +3634,65 @@
|
|
|
3607
3634
|
return remaining < 56;
|
|
3608
3635
|
}
|
|
3609
3636
|
|
|
3637
|
+
function formatTraceOutputSize(text) {
|
|
3638
|
+
const value = String(text || "");
|
|
3639
|
+
const chars = value.length;
|
|
3640
|
+
const lines = value ? value.split(/\n/).length : 0;
|
|
3641
|
+
const compactChars = chars >= 1000 ? ((chars / 1000).toFixed(chars >= 10_000 ? 0 : 1) + "k") : String(chars);
|
|
3642
|
+
return lines + " line" + (lines === 1 ? "" : "s") + ", " + compactChars + " chars";
|
|
3643
|
+
}
|
|
3644
|
+
|
|
3645
|
+
function getTraceOutputPreview(text) {
|
|
3646
|
+
const value = String(text || "");
|
|
3647
|
+
const lines = value.split(/\n/);
|
|
3648
|
+
let preview = value;
|
|
3649
|
+
let truncated = false;
|
|
3650
|
+
if (lines.length > TRACE_OUTPUT_PREVIEW_MAX_LINES) {
|
|
3651
|
+
preview = lines.slice(0, TRACE_OUTPUT_PREVIEW_MAX_LINES).join("\n");
|
|
3652
|
+
truncated = true;
|
|
3653
|
+
}
|
|
3654
|
+
if (preview.length > TRACE_OUTPUT_PREVIEW_MAX_CHARS) {
|
|
3655
|
+
preview = preview.slice(0, TRACE_OUTPUT_PREVIEW_MAX_CHARS);
|
|
3656
|
+
truncated = true;
|
|
3657
|
+
}
|
|
3658
|
+
if (!truncated && value.length <= TRACE_OUTPUT_PREVIEW_MAX_CHARS) {
|
|
3659
|
+
return { text: value, truncated: false, hiddenChars: 0, hiddenLines: 0 };
|
|
3660
|
+
}
|
|
3661
|
+
if (!truncated && value.length > TRACE_OUTPUT_PREVIEW_MAX_CHARS) {
|
|
3662
|
+
preview = value.slice(0, TRACE_OUTPUT_PREVIEW_MAX_CHARS);
|
|
3663
|
+
truncated = true;
|
|
3664
|
+
}
|
|
3665
|
+
const hiddenChars = Math.max(0, value.length - preview.length);
|
|
3666
|
+
const previewLineCount = preview ? preview.split(/\n/).length : 0;
|
|
3667
|
+
const hiddenLines = Math.max(0, lines.length - previewLineCount);
|
|
3668
|
+
return { text: preview, truncated: true, hiddenChars, hiddenLines };
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3671
|
+
function renderTraceOutput(text, outputKey) {
|
|
3672
|
+
const value = String(text || "");
|
|
3673
|
+
const key = String(outputKey || "trace-output");
|
|
3674
|
+
const isExpanded = traceExpandedOutputs.has(key);
|
|
3675
|
+
const preview = getTraceOutputPreview(value);
|
|
3676
|
+
const visibleText = isExpanded || !preview.truncated ? value : preview.text;
|
|
3677
|
+
const body = "<pre class='plain-markdown trace-output'>" + escapeHtml(visibleText) + "</pre>";
|
|
3678
|
+
if (!preview.truncated) return body;
|
|
3679
|
+
|
|
3680
|
+
const hiddenParts = [];
|
|
3681
|
+
if (preview.hiddenLines > 0) hiddenParts.push(preview.hiddenLines + " more line" + (preview.hiddenLines === 1 ? "" : "s"));
|
|
3682
|
+
if (preview.hiddenChars > 0) hiddenParts.push(formatCompactNumber(preview.hiddenChars) + " chars hidden");
|
|
3683
|
+
const summary = isExpanded
|
|
3684
|
+
? "Showing full output (" + formatTraceOutputSize(value) + ")."
|
|
3685
|
+
: "Output truncated — " + (hiddenParts.join(", ") || "more hidden") + ".";
|
|
3686
|
+
const buttonLabel = isExpanded ? "Collapse" : "Show full";
|
|
3687
|
+
return "<div class='trace-output-wrap" + (isExpanded ? " is-expanded" : " is-truncated") + "'>"
|
|
3688
|
+
+ body
|
|
3689
|
+
+ "<div class='trace-output-truncation'>"
|
|
3690
|
+
+ "<span>" + escapeHtml(summary) + "</span>"
|
|
3691
|
+
+ "<button type='button' class='trace-output-toggle' data-trace-output-key='" + escapeHtml(key) + "' aria-expanded='" + (isExpanded ? "true" : "false") + "'>" + escapeHtml(buttonLabel) + "</button>"
|
|
3692
|
+
+ "</div>"
|
|
3693
|
+
+ "</div>";
|
|
3694
|
+
}
|
|
3695
|
+
|
|
3610
3696
|
function buildTracePanelHtml() {
|
|
3611
3697
|
const state = traceState || createEmptyTraceState();
|
|
3612
3698
|
const filter = normalizeTraceFilter(traceFilter);
|
|
@@ -3656,7 +3742,7 @@
|
|
|
3656
3742
|
sections.push(
|
|
3657
3743
|
"<div class='trace-section'>"
|
|
3658
3744
|
+ "<div class='trace-section-label'>Thinking</div>"
|
|
3659
|
-
+
|
|
3745
|
+
+ renderTraceOutput(entry.thinking, entry.id + ":thinking")
|
|
3660
3746
|
+ "</div>"
|
|
3661
3747
|
);
|
|
3662
3748
|
}
|
|
@@ -3664,7 +3750,7 @@
|
|
|
3664
3750
|
sections.push(
|
|
3665
3751
|
"<div class='trace-section'>"
|
|
3666
3752
|
+ "<div class='trace-section-label'>Response</div>"
|
|
3667
|
-
+
|
|
3753
|
+
+ renderTraceOutput(entry.text, entry.id + ":response")
|
|
3668
3754
|
+ "</div>"
|
|
3669
3755
|
);
|
|
3670
3756
|
}
|
|
@@ -3684,10 +3770,10 @@
|
|
|
3684
3770
|
|
|
3685
3771
|
const title = entry.label || entry.toolName || "tool";
|
|
3686
3772
|
const argsSummary = entry.argsSummary
|
|
3687
|
-
? "<div class='trace-section'><div class='trace-section-label'>Input</div
|
|
3773
|
+
? "<div class='trace-section'><div class='trace-section-label'>Input</div>" + renderTraceOutput(entry.argsSummary, entry.id + ":input") + "</div>"
|
|
3688
3774
|
: "";
|
|
3689
3775
|
const output = entry.output
|
|
3690
|
-
? "<div class='trace-section'><div class='trace-section-label'>Output</div
|
|
3776
|
+
? "<div class='trace-section'><div class='trace-section-label'>Output</div>" + renderTraceOutput(entry.output, entry.id + ":output") + "</div>"
|
|
3691
3777
|
: "<div class='trace-empty-inline'>No output yet.</div>";
|
|
3692
3778
|
const toolStatusLabel = entry.isError
|
|
3693
3779
|
? "Error"
|
package/client/studio.css
CHANGED
|
@@ -1822,17 +1822,51 @@
|
|
|
1822
1822
|
letter-spacing: 0.04em;
|
|
1823
1823
|
}
|
|
1824
1824
|
|
|
1825
|
-
.trace-output {
|
|
1826
|
-
padding: 10px 11px;
|
|
1827
|
-
border-radius: 8px;
|
|
1825
|
+
.trace-output-wrap {
|
|
1828
1826
|
border: 1px solid var(--panel-border);
|
|
1827
|
+
border-radius: 8px;
|
|
1829
1828
|
background: var(--panel);
|
|
1829
|
+
overflow: hidden;
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
.trace-output {
|
|
1833
|
+
margin: 0;
|
|
1834
|
+
padding: 10px 11px;
|
|
1835
|
+
border: 0;
|
|
1836
|
+
border-radius: 0;
|
|
1837
|
+
background: transparent;
|
|
1830
1838
|
overflow-x: auto;
|
|
1831
1839
|
white-space: pre-wrap;
|
|
1832
1840
|
overflow-wrap: anywhere;
|
|
1833
1841
|
font-size: var(--studio-working-font-size);
|
|
1834
1842
|
}
|
|
1835
1843
|
|
|
1844
|
+
.trace-section > .trace-output {
|
|
1845
|
+
border: 1px solid var(--panel-border);
|
|
1846
|
+
border-radius: 8px;
|
|
1847
|
+
background: var(--panel);
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
.trace-output-truncation {
|
|
1851
|
+
display: flex;
|
|
1852
|
+
align-items: center;
|
|
1853
|
+
justify-content: space-between;
|
|
1854
|
+
gap: 8px;
|
|
1855
|
+
padding: 6px 8px;
|
|
1856
|
+
border-top: 1px solid var(--border-subtle);
|
|
1857
|
+
color: var(--studio-info-text, var(--muted));
|
|
1858
|
+
font-size: 11px;
|
|
1859
|
+
background: var(--panel-2);
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
.trace-output-toggle {
|
|
1863
|
+
flex: 0 0 auto;
|
|
1864
|
+
padding: 3px 7px;
|
|
1865
|
+
border-radius: 999px;
|
|
1866
|
+
font-size: 11px;
|
|
1867
|
+
line-height: 1.2;
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1836
1870
|
.trace-empty,
|
|
1837
1871
|
.trace-empty-inline {
|
|
1838
1872
|
color: var(--muted);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-studio",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.6",
|
|
4
4
|
"description": "Two-pane browser workspace for pi with prompt/response editing, annotations, critiques, prompt/response history, and live Markdown/LaTeX/code preview",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|