pi-studio 0.5.0 → 0.5.2

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 CHANGED
@@ -88,6 +88,27 @@ All notable changes to `pi-studio` are documented here.
88
88
 
89
89
  ## [Unreleased]
90
90
 
91
+ ## [0.5.2] — 2026-03-06
92
+
93
+ ### Changed
94
+ - Refined left-pane action grouping into clearer workflow rows (run/copy/send/load, annotation tools, critique/highlight controls).
95
+ - Refined right-pane action grouping with consistent rows below response output:
96
+ - mode toggles
97
+ - history navigation (`Get latest`, `Prev`, `History`, `Next`)
98
+ - response load/copy actions
99
+ - Moved **Export right preview as PDF** to the right-pane section header (next to response view selector).
100
+ - Annotation header scaffold now includes precedence guidance:
101
+ - `precedence: later messages supersede these annotations unless user explicitly references them`
102
+ - Inserted annotation scaffold now includes a closing boundary marker:
103
+ - `--- end annotations ---`
104
+ - Removing annotation header now strips the boundary marker as well.
105
+ - Updated default README dark/light workspace screenshots to the latest UI.
106
+ - Moved `sample.diff` example into `assets/` with other sample files.
107
+ - Added escaping guidance for embedded browser script/template changes to `WORKFLOW.md`.
108
+
109
+ ### Fixed
110
+ - Prevented Studio boot breakage caused by unescaped newline insertion in embedded script string updates.
111
+
91
112
  ## [0.5.0] — 2026-03-05
92
113
 
93
114
  ### Added
package/WORKFLOW.md CHANGED
@@ -87,6 +87,16 @@ Rules:
87
87
 
88
88
  ---
89
89
 
90
+ ## Escaping pitfalls (implementation note)
91
+
92
+ `index.ts` builds browser HTML as a TypeScript template string and embeds inline browser JavaScript. This creates multiple parse layers (TS string → HTML → JS), so incorrect escaping can break Studio boot (e.g. stuck at `Booting studio…`).
93
+
94
+ Rules of thumb:
95
+ - In embedded JS string literals authored from TS template context, use `\\n` (not `\n`) for runtime newlines.
96
+ - Escape regex backslashes for the embedding layer (`\\s`, `\\n`, `\\[`), so browser JS receives the intended regex.
97
+ - Prefer `JSON.stringify(value)` when injecting arbitrary text into inline script.
98
+ - After touching inline `<script>` sections in `index.ts`, do a `/studio` boot smoke test immediately.
99
+
90
100
  ## Acceptance criteria
91
101
 
92
102
  1. `/studio --last` opens with editor loaded and no required mode selection.
package/index.ts CHANGED
@@ -1952,6 +1952,31 @@ ${cssVarsBlock}
1952
1952
  background: var(--panel-2);
1953
1953
  font-weight: 600;
1954
1954
  font-size: 14px;
1955
+ display: flex;
1956
+ align-items: center;
1957
+ justify-content: space-between;
1958
+ gap: 8px;
1959
+ flex-wrap: wrap;
1960
+ }
1961
+
1962
+ .section-header-main {
1963
+ display: inline-flex;
1964
+ align-items: center;
1965
+ min-width: 0;
1966
+ }
1967
+
1968
+ .section-header-actions {
1969
+ display: inline-flex;
1970
+ align-items: center;
1971
+ gap: 8px;
1972
+ flex-wrap: wrap;
1973
+ justify-content: flex-end;
1974
+ }
1975
+
1976
+ .section-header-actions button {
1977
+ padding: 6px 9px;
1978
+ font-size: 12px;
1979
+ border-radius: 7px;
1955
1980
  }
1956
1981
 
1957
1982
  .section-header select {
@@ -2034,10 +2059,19 @@ ${cssVarsBlock}
2034
2059
  }
2035
2060
 
2036
2061
  .source-actions {
2062
+ display: flex;
2063
+ flex-direction: column;
2064
+ gap: 6px;
2065
+ align-items: stretch;
2066
+ width: 100%;
2067
+ }
2068
+
2069
+ .source-actions-row {
2037
2070
  display: flex;
2038
2071
  gap: 6px;
2039
2072
  flex-wrap: wrap;
2040
2073
  align-items: center;
2074
+ min-width: 0;
2041
2075
  }
2042
2076
 
2043
2077
  .source-actions button,
@@ -2585,11 +2619,29 @@ ${cssVarsBlock}
2585
2619
  }
2586
2620
 
2587
2621
  .response-actions {
2622
+ display: flex;
2623
+ flex-direction: column;
2624
+ align-items: stretch;
2625
+ gap: 8px;
2626
+ }
2627
+
2628
+ .response-actions-row {
2588
2629
  display: flex;
2589
2630
  align-items: center;
2590
- justify-content: flex-start;
2591
2631
  gap: 8px;
2592
2632
  flex-wrap: wrap;
2633
+ min-width: 0;
2634
+ }
2635
+
2636
+ .response-actions-row.history-row {
2637
+ flex-wrap: nowrap;
2638
+ overflow-x: auto;
2639
+ padding-bottom: 2px;
2640
+ scrollbar-width: thin;
2641
+ }
2642
+
2643
+ .response-actions-row.history-row > * {
2644
+ flex: 0 0 auto;
2593
2645
  }
2594
2646
 
2595
2647
  footer {
@@ -2765,55 +2817,61 @@ ${cssVarsBlock}
2765
2817
  <span id="syncBadge" class="source-badge sync-badge">No response loaded</span>
2766
2818
  </div>
2767
2819
  <div class="source-actions">
2768
- <button id="sendRunBtn" type="button" title="Send editor text directly to the model as-is. Shortcut: Cmd/Ctrl+Enter when editor pane is active.">Run editor text</button>
2769
- <button id="insertHeaderBtn" type="button" title="Insert annotated-reply protocol header (includes source metadata and [an: ...] syntax hint).">Insert annotated reply header</button>
2770
- <select id="annotationModeSelect" aria-label="Annotation visibility mode" title="On: keep and send [an: ...] markers. Hidden: keep markers in editor, hide in preview, and strip before Run/Critique.">
2771
- <option value="on" selected>Annotations: On</option>
2772
- <option value="off">Annotations: Hidden</option>
2773
- </select>
2774
- <select id="lensSelect" aria-label="Critique focus">
2775
- <option value="auto" selected>Critique focus: Auto</option>
2776
- <option value="writing">Critique focus: Writing</option>
2777
- <option value="code">Critique focus: Code</option>
2778
- </select>
2779
- <button id="critiqueBtn" type="button">Critique editor text</button>
2780
- <button id="sendEditorBtn" type="button">Send to pi editor</button>
2781
- <button id="getEditorBtn" type="button" title="Load the current terminal editor draft into Studio.">Load from pi editor</button>
2782
- <button id="copyDraftBtn" type="button">Copy editor text</button>
2783
- <button id="saveAnnotatedBtn" type="button" title="Save full editor content (including [an: ...] markers) as a .annotated.md file.">Save .annotated.md</button>
2784
- <button id="stripAnnotationsBtn" type="button" title="Destructively remove all [an: ...] markers from editor text.">Strip annotations…</button>
2785
- <select id="highlightSelect" aria-label="Editor syntax highlighting">
2786
- <option value="off">Syntax highlight: Off</option>
2787
- <option value="on" selected>Syntax highlight: On</option>
2788
- </select>
2789
- <select id="langSelect" aria-label="Highlight language">
2790
- <option value="markdown" selected>Lang: Markdown</option>
2791
- <option value="javascript">Lang: JavaScript</option>
2792
- <option value="typescript">Lang: TypeScript</option>
2793
- <option value="python">Lang: Python</option>
2794
- <option value="bash">Lang: Bash</option>
2795
- <option value="json">Lang: JSON</option>
2796
- <option value="rust">Lang: Rust</option>
2797
- <option value="c">Lang: C</option>
2798
- <option value="cpp">Lang: C++</option>
2799
- <option value="julia">Lang: Julia</option>
2800
- <option value="fortran">Lang: Fortran</option>
2801
- <option value="r">Lang: R</option>
2802
- <option value="matlab">Lang: MATLAB</option>
2803
- <option value="latex">Lang: LaTeX</option>
2804
- <option value="diff">Lang: Diff</option>
2805
- <option value="java">Lang: Java</option>
2806
- <option value="go">Lang: Go</option>
2807
- <option value="ruby">Lang: Ruby</option>
2808
- <option value="swift">Lang: Swift</option>
2809
- <option value="html">Lang: HTML</option>
2810
- <option value="css">Lang: CSS</option>
2811
- <option value="xml">Lang: XML</option>
2812
- <option value="yaml">Lang: YAML</option>
2813
- <option value="toml">Lang: TOML</option>
2814
- <option value="lua">Lang: Lua</option>
2815
- <option value="text">Lang: Plain Text</option>
2816
- </select>
2820
+ <div class="source-actions-row">
2821
+ <button id="sendRunBtn" type="button" title="Send editor text directly to the model as-is. Shortcut: Cmd/Ctrl+Enter when editor pane is active.">Run editor text</button>
2822
+ <button id="copyDraftBtn" type="button">Copy editor text</button>
2823
+ <button id="sendEditorBtn" type="button">Send to pi editor</button>
2824
+ <button id="getEditorBtn" type="button" title="Load the current terminal editor draft into Studio.">Load from pi editor</button>
2825
+ </div>
2826
+ <div class="source-actions-row">
2827
+ <button id="insertHeaderBtn" type="button" title="Insert annotated-reply protocol header (source metadata, [an: ...] syntax hint, precedence note, and end marker).">Insert annotated reply header</button>
2828
+ <select id="annotationModeSelect" aria-label="Annotation visibility mode" title="On: keep and send [an: ...] markers. Hidden: keep markers in editor, hide in preview, and strip before Run/Critique.">
2829
+ <option value="on" selected>Annotations: On</option>
2830
+ <option value="off">Annotations: Hidden</option>
2831
+ </select>
2832
+ <button id="stripAnnotationsBtn" type="button" title="Destructively remove all [an: ...] markers from editor text.">Strip annotations…</button>
2833
+ <button id="saveAnnotatedBtn" type="button" title="Save full editor content (including [an: ...] markers) as a .annotated.md file.">Save .annotated.md</button>
2834
+ </div>
2835
+ <div class="source-actions-row">
2836
+ <select id="lensSelect" aria-label="Critique focus">
2837
+ <option value="auto" selected>Critique focus: Auto</option>
2838
+ <option value="writing">Critique focus: Writing</option>
2839
+ <option value="code">Critique focus: Code</option>
2840
+ </select>
2841
+ <button id="critiqueBtn" type="button">Critique editor text</button>
2842
+ <select id="highlightSelect" aria-label="Editor syntax highlighting">
2843
+ <option value="off">Syntax highlight: Off</option>
2844
+ <option value="on" selected>Syntax highlight: On</option>
2845
+ </select>
2846
+ <select id="langSelect" aria-label="Highlight language">
2847
+ <option value="markdown" selected>Lang: Markdown</option>
2848
+ <option value="javascript">Lang: JavaScript</option>
2849
+ <option value="typescript">Lang: TypeScript</option>
2850
+ <option value="python">Lang: Python</option>
2851
+ <option value="bash">Lang: Bash</option>
2852
+ <option value="json">Lang: JSON</option>
2853
+ <option value="rust">Lang: Rust</option>
2854
+ <option value="c">Lang: C</option>
2855
+ <option value="cpp">Lang: C++</option>
2856
+ <option value="julia">Lang: Julia</option>
2857
+ <option value="fortran">Lang: Fortran</option>
2858
+ <option value="r">Lang: R</option>
2859
+ <option value="matlab">Lang: MATLAB</option>
2860
+ <option value="latex">Lang: LaTeX</option>
2861
+ <option value="diff">Lang: Diff</option>
2862
+ <option value="java">Lang: Java</option>
2863
+ <option value="go">Lang: Go</option>
2864
+ <option value="ruby">Lang: Ruby</option>
2865
+ <option value="swift">Lang: Swift</option>
2866
+ <option value="html">Lang: HTML</option>
2867
+ <option value="css">Lang: CSS</option>
2868
+ <option value="xml">Lang: XML</option>
2869
+ <option value="yaml">Lang: YAML</option>
2870
+ <option value="toml">Lang: TOML</option>
2871
+ <option value="lua">Lang: Lua</option>
2872
+ <option value="text">Lang: Plain Text</option>
2873
+ </select>
2874
+ </div>
2817
2875
  </div>
2818
2876
  </div>
2819
2877
  <div id="sourceEditorWrap" class="editor-highlight-wrap">
@@ -2826,11 +2884,16 @@ ${cssVarsBlock}
2826
2884
 
2827
2885
  <section id="rightPane">
2828
2886
  <div id="rightSectionHeader" class="section-header">
2829
- <select id="rightViewSelect" aria-label="Response view mode">
2830
- <option value="markdown">Response (Raw)</option>
2831
- <option value="preview" selected>Response (Preview)</option>
2832
- <option value="editor-preview">Editor (Preview)</option>
2833
- </select>
2887
+ <div class="section-header-main">
2888
+ <select id="rightViewSelect" aria-label="Response view mode">
2889
+ <option value="markdown">Response (Raw)</option>
2890
+ <option value="preview" selected>Response (Preview)</option>
2891
+ <option value="editor-preview">Editor (Preview)</option>
2892
+ </select>
2893
+ </div>
2894
+ <div class="section-header-actions">
2895
+ <button id="exportPdfBtn" type="button" title="Export the current right-pane preview as PDF via pandoc + xelatex.">Export right preview as PDF</button>
2896
+ </div>
2834
2897
  </div>
2835
2898
  <div class="reference-meta">
2836
2899
  <span id="referenceBadge" class="source-badge">Latest response: none</span>
@@ -2838,24 +2901,29 @@ ${cssVarsBlock}
2838
2901
  <div id="critiqueView" class="panel-scroll rendered-markdown"><pre class="plain-markdown">No response yet.</pre></div>
2839
2902
  <div class="response-wrap">
2840
2903
  <div id="responseActions" class="response-actions">
2841
- <select id="followSelect" aria-label="Auto-update response">
2842
- <option value="on" selected>Auto-update response: On</option>
2843
- <option value="off">Auto-update response: Off</option>
2844
- </select>
2845
- <select id="responseHighlightSelect" aria-label="Response markdown highlighting">
2846
- <option value="off">Syntax highlight: Off</option>
2847
- <option value="on" selected>Syntax highlight: On</option>
2848
- </select>
2849
- <button id="pullLatestBtn" type="button" title="Fetch the latest assistant response when auto-update is off.">Get latest response</button>
2850
- <button id="historyPrevBtn" type="button" title="Show previous response in history.">◀ Prev response</button>
2851
- <span id="historyIndexBadge" class="source-badge">History: 0/0</span>
2852
- <button id="historyNextBtn" type="button" title="Show next response in history.">Next response ▶</button>
2853
- <button id="loadHistoryPromptBtn" type="button" title="Load the prompt that generated the selected response into the editor.">Load response prompt into editor</button>
2854
- <button id="loadResponseBtn" type="button">Load response into editor</button>
2855
- <button id="loadCritiqueNotesBtn" type="button" hidden>Load critique notes into editor</button>
2856
- <button id="loadCritiqueFullBtn" type="button" hidden>Load full critique into editor</button>
2857
- <button id="copyResponseBtn" type="button">Copy response text</button>
2858
- <button id="exportPdfBtn" type="button" title="Export the current right-pane preview as PDF via pandoc + xelatex.">Export right preview as PDF</button>
2904
+ <div class="response-actions-row">
2905
+ <select id="followSelect" aria-label="Auto-update response">
2906
+ <option value="on" selected>Auto-update response: On</option>
2907
+ <option value="off">Auto-update response: Off</option>
2908
+ </select>
2909
+ <select id="responseHighlightSelect" aria-label="Response markdown highlighting">
2910
+ <option value="off">Syntax highlight: Off</option>
2911
+ <option value="on" selected>Syntax highlight: On</option>
2912
+ </select>
2913
+ </div>
2914
+ <div class="response-actions-row history-row">
2915
+ <button id="pullLatestBtn" type="button" title="Fetch the latest assistant response when auto-update is off.">Get latest response</button>
2916
+ <button id="historyPrevBtn" type="button" title="Show previous response in history.">◀ Prev response</button>
2917
+ <span id="historyIndexBadge" class="source-badge">History: 0/0</span>
2918
+ <button id="historyNextBtn" type="button" title="Show next response in history.">Next response ▶</button>
2919
+ </div>
2920
+ <div class="response-actions-row">
2921
+ <button id="loadHistoryPromptBtn" type="button" title="Load the prompt that generated the selected response into the editor.">Load response prompt into editor</button>
2922
+ <button id="loadResponseBtn" type="button">Load response into editor</button>
2923
+ <button id="loadCritiqueNotesBtn" type="button" hidden>Load critique notes into editor</button>
2924
+ <button id="loadCritiqueFullBtn" type="button" hidden>Load full critique into editor</button>
2925
+ <button id="copyResponseBtn" type="button">Copy response text</button>
2926
+ </div>
2859
2927
  </div>
2860
2928
  </div>
2861
2929
  </section>
@@ -5751,10 +5819,15 @@ ${cssVarsBlock}
5751
5819
  const sourceDescriptor = describeSourceForAnnotation();
5752
5820
  let header = "annotated reply below:\\n";
5753
5821
  header += "original source: " + sourceDescriptor + "\\n";
5754
- header += "annotation syntax: [an: your note]\\n\\n---\\n\\n";
5822
+ header += "annotation syntax: [an: your note]\\n";
5823
+ header += "precedence: later messages supersede these annotations unless user explicitly references them\\n\\n---\\n\\n";
5755
5824
  return header;
5756
5825
  }
5757
5826
 
5827
+ function stripAnnotationBoundaryMarker(text) {
5828
+ return String(text || "").replace(/\\n{0,2}--- end annotations ---\\s*$/i, "");
5829
+ }
5830
+
5758
5831
  function stripAnnotationHeader(text) {
5759
5832
  const normalized = String(text || "").replace(/\\r\\n/g, "\\n");
5760
5833
  if (!normalized.toLowerCase().startsWith("annotated reply below:")) {
@@ -5773,7 +5846,7 @@ ${cssVarsBlock}
5773
5846
 
5774
5847
  return {
5775
5848
  hadHeader: true,
5776
- body: normalized.slice(cursor),
5849
+ body: stripAnnotationBoundaryMarker(normalized.slice(cursor)),
5777
5850
  };
5778
5851
  }
5779
5852
 
@@ -5786,7 +5859,7 @@ ${cssVarsBlock}
5786
5859
  return;
5787
5860
  }
5788
5861
  insertHeaderBtn.textContent = "Insert annotated reply header";
5789
- insertHeaderBtn.title = "Insert annotated-reply protocol header (includes source metadata and [an: ...] syntax hint).";
5862
+ insertHeaderBtn.title = "Insert annotated-reply protocol header (source metadata, [an: ...] syntax hint, precedence note, and end marker).";
5790
5863
  }
5791
5864
 
5792
5865
  function toggleAnnotatedReplyHeader() {
@@ -5800,7 +5873,8 @@ ${cssVarsBlock}
5800
5873
  return;
5801
5874
  }
5802
5875
 
5803
- const updated = buildAnnotationHeader() + stripped.body;
5876
+ const cleanedBody = stripAnnotationBoundaryMarker(stripped.body);
5877
+ const updated = buildAnnotationHeader() + cleanedBody + "\\n\\n--- end annotations ---\\n\\n";
5804
5878
  if (isTextEquivalent(sourceTextEl.value, updated)) {
5805
5879
  setStatus("Annotated reply header already present.");
5806
5880
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-studio",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Browser GUI for structured critique workflows in pi",
5
5
  "type": "module",
6
6
  "license": "MIT",