pi-studio 0.5.43 → 0.5.44
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 +8 -0
- package/client/studio-client.js +318 -36
- package/client/studio.css +60 -3
- package/index.ts +42 -37
- package/package.json +9 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@ All notable changes to `pi-studio` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.5.44] — 2026-04-03
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Studio browser tabs now show live browser-side activity state during Studio-owned work, including prefixes like `Running…`, `Responding…`, `Critiquing…`, or `Compacting…`, instead of only changing on completion.
|
|
11
|
+
- Studio favicons now use a clearer browser-side status badge: ready/completed states use a green circular badge, while active running states use an amber hollow ring so busy vs finished is easier to distinguish at a glance without relying on animation.
|
|
12
|
+
- Studio raw editor now has an optional line-number gutter, intended as a lightweight navigation aid when working in **Editor (Raw)** before switching back to preview.
|
|
13
|
+
- Studio editor controls now use a single combined **Syntax highlight** selector with `Off` plus all supported languages, replacing the separate highlight on/off and language selectors.
|
|
14
|
+
|
|
7
15
|
## [0.5.43] — 2026-04-01
|
|
8
16
|
|
|
9
17
|
### Changed
|
package/client/studio-client.js
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
const statusSpinnerEl = document.getElementById("statusSpinner");
|
|
5
5
|
const footerMetaEl = document.getElementById("footerMeta");
|
|
6
6
|
const footerMetaTextEl = document.getElementById("footerMetaText");
|
|
7
|
+
let faviconLinkEl = document.querySelector('link[rel="icon"], link[rel="shortcut icon"]');
|
|
8
|
+
if (!faviconLinkEl) {
|
|
9
|
+
faviconLinkEl = document.createElement("link");
|
|
10
|
+
faviconLinkEl.rel = "icon";
|
|
11
|
+
document.head.appendChild(faviconLinkEl);
|
|
12
|
+
}
|
|
7
13
|
const BRAILLE_SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
8
14
|
let spinnerTimer = null;
|
|
9
15
|
let spinnerFrameIndex = 0;
|
|
@@ -41,6 +47,9 @@
|
|
|
41
47
|
const sourceEditorWrapEl = document.getElementById("sourceEditorWrap");
|
|
42
48
|
const sourceTextEl = document.getElementById("sourceText");
|
|
43
49
|
const sourceHighlightEl = document.getElementById("sourceHighlight");
|
|
50
|
+
const lineNumberGutterEl = document.getElementById("lineNumberGutter");
|
|
51
|
+
const lineNumberGutterContentEl = document.getElementById("lineNumberGutterContent");
|
|
52
|
+
const lineNumberMeasureEl = document.getElementById("lineNumberMeasure");
|
|
44
53
|
const sourcePreviewEl = document.getElementById("sourcePreview");
|
|
45
54
|
const leftPaneEl = document.getElementById("leftPane");
|
|
46
55
|
const rightPaneEl = document.getElementById("rightPane");
|
|
@@ -84,7 +93,7 @@
|
|
|
84
93
|
const saveAnnotatedBtn = document.getElementById("saveAnnotatedBtn");
|
|
85
94
|
const stripAnnotationsBtn = document.getElementById("stripAnnotationsBtn");
|
|
86
95
|
const highlightSelect = document.getElementById("highlightSelect");
|
|
87
|
-
const
|
|
96
|
+
const lineNumbersSelect = document.getElementById("lineNumbersSelect");
|
|
88
97
|
const annotationModeSelect = document.getElementById("annotationModeSelect");
|
|
89
98
|
const compactBtn = document.getElementById("compactBtn");
|
|
90
99
|
const leftFocusBtn = document.getElementById("leftFocusBtn");
|
|
@@ -158,6 +167,7 @@
|
|
|
158
167
|
let titleAttentionMessage = "";
|
|
159
168
|
let titleAttentionRequestId = null;
|
|
160
169
|
let titleAttentionRequestKind = null;
|
|
170
|
+
let lastRenderedFaviconHref = "";
|
|
161
171
|
|
|
162
172
|
function parseFiniteNumber(value) {
|
|
163
173
|
if (value == null || value === "") return null;
|
|
@@ -203,6 +213,7 @@
|
|
|
203
213
|
const EDITOR_HIGHLIGHT_MAX_CHARS = 100_000;
|
|
204
214
|
const EDITOR_HIGHLIGHT_STORAGE_KEY = "piStudio.editorHighlightEnabled";
|
|
205
215
|
const EDITOR_LANGUAGE_STORAGE_KEY = "piStudio.editorLanguage";
|
|
216
|
+
const EDITOR_LINE_NUMBERS_STORAGE_KEY = "piStudio.editorLineNumbersEnabled";
|
|
206
217
|
// Single source of truth: language -> file extensions (and display label)
|
|
207
218
|
var LANG_EXT_MAP = {
|
|
208
219
|
markdown: { label: "Markdown", exts: ["md", "markdown", "mdx", "qmd"] },
|
|
@@ -258,6 +269,8 @@
|
|
|
258
269
|
let editorLanguage = "markdown";
|
|
259
270
|
let responseHighlightEnabled = false;
|
|
260
271
|
let editorHighlightRenderRaf = null;
|
|
272
|
+
let lineNumbersEnabled = false;
|
|
273
|
+
let lineNumbersRenderRaf = null;
|
|
261
274
|
let annotationsEnabled = true;
|
|
262
275
|
let scratchpadText = "";
|
|
263
276
|
let scratchpadReturnFocusEl = null;
|
|
@@ -664,14 +677,136 @@
|
|
|
664
677
|
updateDocumentTitle();
|
|
665
678
|
}
|
|
666
679
|
|
|
680
|
+
function truncateTitleSegment(text, maxLength) {
|
|
681
|
+
const normalized = normalizeActivityLabel(text);
|
|
682
|
+
if (!normalized) return "";
|
|
683
|
+
if (!Number.isFinite(maxLength) || maxLength <= 1 || normalized.length <= maxLength) {
|
|
684
|
+
return normalized;
|
|
685
|
+
}
|
|
686
|
+
return normalized.slice(0, maxLength - 1).trimEnd() + "…";
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
function readThemeColor(variableName, fallback) {
|
|
690
|
+
try {
|
|
691
|
+
const value = window.getComputedStyle(document.documentElement).getPropertyValue(variableName);
|
|
692
|
+
const trimmed = typeof value === "string" ? value.trim() : "";
|
|
693
|
+
return trimmed || fallback;
|
|
694
|
+
} catch {
|
|
695
|
+
return fallback;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
function getTitleActionMessage(kind) {
|
|
700
|
+
if (kind === "annotation") return "Replying…";
|
|
701
|
+
if (kind === "critique") return "Critiquing…";
|
|
702
|
+
if (kind === "direct") return "Running…";
|
|
703
|
+
if (kind === "compact") return "Compacting…";
|
|
704
|
+
if (kind === "send_to_editor") return "Sending to editor…";
|
|
705
|
+
if (kind === "get_from_editor") return "Loading from editor…";
|
|
706
|
+
if (kind === "load_git_diff") return "Loading git diff…";
|
|
707
|
+
if (kind === "refresh_from_disk") return "Refreshing from disk…";
|
|
708
|
+
if (kind === "save_as" || kind === "save_over") return "Saving…";
|
|
709
|
+
return "Working…";
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
function getTitleBusyMessage() {
|
|
713
|
+
const activeKind = pendingKind || (agentBusyFromServer ? stickyStudioKind : null);
|
|
714
|
+
const hasStudioOwnedBusyState = uiBusy
|
|
715
|
+
|| Boolean(pendingRequestId)
|
|
716
|
+
|| Boolean(pendingKind)
|
|
717
|
+
|| compactInProgress
|
|
718
|
+
|| Boolean(agentBusyFromServer && stickyStudioKind)
|
|
719
|
+
|| Boolean(agentBusyFromServer && studioRunChainActive);
|
|
720
|
+
|
|
721
|
+
if (!hasStudioOwnedBusyState) return "";
|
|
722
|
+
|
|
723
|
+
if (
|
|
724
|
+
pendingKind === "compact"
|
|
725
|
+
|| compactInProgress
|
|
726
|
+
|| (agentBusyFromServer && stickyStudioKind === "compact")
|
|
727
|
+
) {
|
|
728
|
+
return "Compacting…";
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
if (terminalActivityPhase === "tool") {
|
|
732
|
+
if (terminalActivityLabel && !isGenericToolLabel(terminalActivityLabel)) {
|
|
733
|
+
return truncateTitleSegment(withEllipsis(terminalActivityLabel), 34);
|
|
734
|
+
}
|
|
735
|
+
if (activeKind) return getTitleActionMessage(activeKind);
|
|
736
|
+
if (agentBusyFromServer && studioRunChainActive) return "Running…";
|
|
737
|
+
return "Working…";
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
if (terminalActivityPhase === "responding") {
|
|
741
|
+
if (activeKind === "critique") return "Critiquing…";
|
|
742
|
+
if (activeKind === "annotation") return "Replying…";
|
|
743
|
+
return "Responding…";
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
if (activeKind) return getTitleActionMessage(activeKind);
|
|
747
|
+
if (uiBusy || (agentBusyFromServer && studioRunChainActive)) return "Running…";
|
|
748
|
+
return "";
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
function getDynamicTitlePrefix() {
|
|
752
|
+
if (titleAttentionMessage) return titleAttentionMessage;
|
|
753
|
+
if (wsState === "Connecting") return reconnectAttempt > 0 ? "Reconnecting…" : "Connecting…";
|
|
754
|
+
if (wsState === "Disconnected") return "Disconnected";
|
|
755
|
+
return getTitleBusyMessage();
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
function buildStudioFaviconHref() {
|
|
759
|
+
const fg = readThemeColor("--text", "#111111");
|
|
760
|
+
const bg = readThemeColor("--bg", "#ffffff");
|
|
761
|
+
const accent = readThemeColor("--accent", fg);
|
|
762
|
+
const ok = readThemeColor("--ok", "#16a34a");
|
|
763
|
+
const warn = readThemeColor("--warn", accent);
|
|
764
|
+
const error = readThemeColor("--error", "#dc2626");
|
|
765
|
+
|
|
766
|
+
let badgeSvg = "";
|
|
767
|
+
|
|
768
|
+
if (titleAttentionMessage) {
|
|
769
|
+
badgeSvg = `<circle cx="50" cy="14" r="9" fill="${ok}" stroke="${bg}" stroke-width="4" />`;
|
|
770
|
+
} else if (wsState === "Disconnected") {
|
|
771
|
+
badgeSvg = `<circle cx="50" cy="14" r="9" fill="${error}" stroke="${bg}" stroke-width="4" />`;
|
|
772
|
+
} else if (wsState === "Connecting") {
|
|
773
|
+
badgeSvg = `<circle cx="50" cy="14" r="9" fill="${accent}" stroke="${bg}" stroke-width="4" />`;
|
|
774
|
+
} else if (getTitleBusyMessage()) {
|
|
775
|
+
badgeSvg = `<circle cx="50" cy="14" r="10" fill="none" stroke="${warn}" stroke-width="5" />`;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const svg = [
|
|
779
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">',
|
|
780
|
+
`<text x="32" y="35" text-anchor="middle" dominant-baseline="middle" font-size="50" font-weight="700" font-family="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" fill="${fg}">π</text>`,
|
|
781
|
+
badgeSvg,
|
|
782
|
+
"</svg>",
|
|
783
|
+
].join("");
|
|
784
|
+
return "data:image/svg+xml," + encodeURIComponent(svg);
|
|
785
|
+
}
|
|
786
|
+
|
|
667
787
|
function updateDocumentTitle() {
|
|
668
788
|
const modelText = modelLabel && modelLabel.trim() ? modelLabel.trim() : "none";
|
|
669
789
|
const terminalText = terminalSessionLabel && terminalSessionLabel.trim() ? terminalSessionLabel.trim() : "unknown";
|
|
670
790
|
const titleParts = ["pi Studio"];
|
|
671
791
|
if (terminalText && terminalText !== "unknown") titleParts.push(terminalText);
|
|
672
792
|
if (modelText && modelText !== "none") titleParts.push(modelText);
|
|
673
|
-
|
|
674
|
-
|
|
793
|
+
|
|
794
|
+
const titlePrefix = getDynamicTitlePrefix();
|
|
795
|
+
if (titlePrefix) titleParts.unshift(titlePrefix);
|
|
796
|
+
|
|
797
|
+
const nextTitle = titleParts.join(" · ");
|
|
798
|
+
if (document.title !== nextTitle) {
|
|
799
|
+
document.title = nextTitle;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
if (faviconLinkEl) {
|
|
803
|
+
const nextFaviconHref = buildStudioFaviconHref();
|
|
804
|
+
if (nextFaviconHref !== lastRenderedFaviconHref) {
|
|
805
|
+
faviconLinkEl.href = nextFaviconHref;
|
|
806
|
+
faviconLinkEl.type = "image/svg+xml";
|
|
807
|
+
lastRenderedFaviconHref = nextFaviconHref;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
675
810
|
}
|
|
676
811
|
|
|
677
812
|
function updateFooterMeta() {
|
|
@@ -705,7 +840,7 @@
|
|
|
705
840
|
function startFooterSpinner() {
|
|
706
841
|
if (spinnerTimer) return;
|
|
707
842
|
spinnerTimer = window.setInterval(() => {
|
|
708
|
-
spinnerFrameIndex
|
|
843
|
+
spinnerFrameIndex += 1;
|
|
709
844
|
renderStatus();
|
|
710
845
|
}, 80);
|
|
711
846
|
}
|
|
@@ -2410,6 +2545,9 @@
|
|
|
2410
2545
|
if (editorHighlightEnabled && editorView === "markdown") {
|
|
2411
2546
|
scheduleEditorHighlightRender();
|
|
2412
2547
|
}
|
|
2548
|
+
if (lineNumbersEnabled && editorView === "markdown") {
|
|
2549
|
+
scheduleEditorLineNumberRender();
|
|
2550
|
+
}
|
|
2413
2551
|
if (rightView === "editor-preview") {
|
|
2414
2552
|
scheduleResponseEditorPreviewRender(previewDelayMs);
|
|
2415
2553
|
}
|
|
@@ -2643,7 +2781,7 @@
|
|
|
2643
2781
|
syncRunAndCritiqueButtons();
|
|
2644
2782
|
copyDraftBtn.disabled = uiBusy;
|
|
2645
2783
|
if (highlightSelect) highlightSelect.disabled = uiBusy;
|
|
2646
|
-
if (
|
|
2784
|
+
if (lineNumbersSelect) lineNumbersSelect.disabled = uiBusy;
|
|
2647
2785
|
if (annotationModeSelect) annotationModeSelect.disabled = uiBusy;
|
|
2648
2786
|
if (saveAnnotatedBtn) saveAnnotatedBtn.disabled = uiBusy;
|
|
2649
2787
|
if (stripAnnotationsBtn) stripAnnotationsBtn.disabled = uiBusy || !hasAnnotationMarkers(sourceTextEl.value);
|
|
@@ -2710,6 +2848,9 @@
|
|
|
2710
2848
|
schedule(() => {
|
|
2711
2849
|
syncEditorHighlightScroll();
|
|
2712
2850
|
});
|
|
2851
|
+
if (lineNumbersEnabled && editorView === "markdown") {
|
|
2852
|
+
scheduleEditorLineNumberRender();
|
|
2853
|
+
}
|
|
2713
2854
|
|
|
2714
2855
|
updateAnnotatedReplyHeaderButton();
|
|
2715
2856
|
|
|
@@ -2745,7 +2886,11 @@
|
|
|
2745
2886
|
}
|
|
2746
2887
|
|
|
2747
2888
|
updateEditorHighlightState();
|
|
2748
|
-
|
|
2889
|
+
syncHighlightSelectUi();
|
|
2890
|
+
updateLineNumberGutterVisibility();
|
|
2891
|
+
if (!showPreview && lineNumbersEnabled) {
|
|
2892
|
+
scheduleEditorLineNumberRender();
|
|
2893
|
+
}
|
|
2749
2894
|
}
|
|
2750
2895
|
|
|
2751
2896
|
function setRightView(nextView) {
|
|
@@ -2765,6 +2910,115 @@
|
|
|
2765
2910
|
syncActionButtons();
|
|
2766
2911
|
}
|
|
2767
2912
|
|
|
2913
|
+
function lineNumbersShouldBeVisible() {
|
|
2914
|
+
return Boolean(
|
|
2915
|
+
lineNumbersEnabled
|
|
2916
|
+
&& editorView === "markdown"
|
|
2917
|
+
&& sourceEditorWrapEl
|
|
2918
|
+
&& lineNumberGutterEl
|
|
2919
|
+
&& lineNumberGutterContentEl
|
|
2920
|
+
&& lineNumberMeasureEl,
|
|
2921
|
+
);
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
function getEditorLineNumberGutterWidthCss(lineCount) {
|
|
2925
|
+
const digits = Math.max(2, String(Math.max(1, lineCount || 0)).length);
|
|
2926
|
+
return "calc(" + digits + "ch + 18px)";
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2929
|
+
function updateLineNumberGutterVisibility() {
|
|
2930
|
+
const visible = lineNumbersShouldBeVisible();
|
|
2931
|
+
if (sourceEditorWrapEl) {
|
|
2932
|
+
sourceEditorWrapEl.classList.toggle("line-numbers-enabled", visible);
|
|
2933
|
+
if (!visible) {
|
|
2934
|
+
sourceEditorWrapEl.style.setProperty("--editor-line-number-gutter-width", "0px");
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
if (lineNumberGutterEl) {
|
|
2938
|
+
lineNumberGutterEl.hidden = !visible;
|
|
2939
|
+
}
|
|
2940
|
+
if (!visible) {
|
|
2941
|
+
if (lineNumberGutterContentEl) lineNumberGutterContentEl.innerHTML = "";
|
|
2942
|
+
if (lineNumberMeasureEl) lineNumberMeasureEl.innerHTML = "";
|
|
2943
|
+
}
|
|
2944
|
+
return visible;
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2947
|
+
function renderEditorLineNumbersNow() {
|
|
2948
|
+
if (!updateLineNumberGutterVisibility()) return;
|
|
2949
|
+
|
|
2950
|
+
const text = String(sourceTextEl.value || "").replace(/\r\n/g, "\n");
|
|
2951
|
+
const lines = text.split("\n");
|
|
2952
|
+
const lineCount = Math.max(1, lines.length);
|
|
2953
|
+
sourceEditorWrapEl.style.setProperty("--editor-line-number-gutter-width", getEditorLineNumberGutterWidthCss(lineCount));
|
|
2954
|
+
|
|
2955
|
+
const styles = window.getComputedStyle(sourceTextEl);
|
|
2956
|
+
const lineHeightPx = parseFloat(styles.lineHeight) || 18.85;
|
|
2957
|
+
const paddingTop = parseFloat(styles.paddingTop) || 0;
|
|
2958
|
+
const paddingRight = parseFloat(styles.paddingRight) || 0;
|
|
2959
|
+
const paddingBottom = parseFloat(styles.paddingBottom) || 0;
|
|
2960
|
+
const paddingLeft = parseFloat(styles.paddingLeft) || 0;
|
|
2961
|
+
const contentWidth = Math.max(1, sourceTextEl.clientWidth - paddingLeft - paddingRight);
|
|
2962
|
+
|
|
2963
|
+
lineNumberGutterContentEl.style.paddingTop = paddingTop + "px";
|
|
2964
|
+
lineNumberGutterContentEl.style.paddingBottom = paddingBottom + "px";
|
|
2965
|
+
lineNumberMeasureEl.style.width = contentWidth + "px";
|
|
2966
|
+
lineNumberMeasureEl.innerHTML = lines
|
|
2967
|
+
.map((line) => "<div class='editor-line-number-measure-line'>" + (line.length ? escapeHtml(line) : "​") + "</div>")
|
|
2968
|
+
.join("");
|
|
2969
|
+
|
|
2970
|
+
const measureLines = Array.from(lineNumberMeasureEl.children);
|
|
2971
|
+
lineNumberGutterContentEl.innerHTML = measureLines
|
|
2972
|
+
.map((lineEl, index) => {
|
|
2973
|
+
const height = Math.max(lineHeightPx, lineEl.getBoundingClientRect().height || 0);
|
|
2974
|
+
return "<div class='editor-line-number-row' style='height:" + height.toFixed(2) + "px'>" + (index + 1) + "</div>";
|
|
2975
|
+
})
|
|
2976
|
+
.join("");
|
|
2977
|
+
|
|
2978
|
+
syncEditorHighlightScroll();
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2981
|
+
function scheduleEditorLineNumberRender() {
|
|
2982
|
+
if (lineNumbersRenderRaf !== null) {
|
|
2983
|
+
if (typeof window.cancelAnimationFrame === "function") {
|
|
2984
|
+
window.cancelAnimationFrame(lineNumbersRenderRaf);
|
|
2985
|
+
} else {
|
|
2986
|
+
window.clearTimeout(lineNumbersRenderRaf);
|
|
2987
|
+
}
|
|
2988
|
+
lineNumbersRenderRaf = null;
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
const schedule = typeof window.requestAnimationFrame === "function"
|
|
2992
|
+
? window.requestAnimationFrame.bind(window)
|
|
2993
|
+
: (cb) => window.setTimeout(cb, 16);
|
|
2994
|
+
|
|
2995
|
+
lineNumbersRenderRaf = schedule(() => {
|
|
2996
|
+
lineNumbersRenderRaf = null;
|
|
2997
|
+
renderEditorLineNumbersNow();
|
|
2998
|
+
});
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
function readStoredEditorLineNumbersEnabled() {
|
|
3002
|
+
return readStoredToggle(EDITOR_LINE_NUMBERS_STORAGE_KEY);
|
|
3003
|
+
}
|
|
3004
|
+
|
|
3005
|
+
function persistEditorLineNumbersEnabled(enabled) {
|
|
3006
|
+
persistStoredToggle(EDITOR_LINE_NUMBERS_STORAGE_KEY, enabled);
|
|
3007
|
+
}
|
|
3008
|
+
|
|
3009
|
+
function setLineNumbersEnabled(enabled) {
|
|
3010
|
+
lineNumbersEnabled = Boolean(enabled);
|
|
3011
|
+
persistEditorLineNumbersEnabled(lineNumbersEnabled);
|
|
3012
|
+
if (lineNumbersSelect) {
|
|
3013
|
+
lineNumbersSelect.value = lineNumbersEnabled ? "on" : "off";
|
|
3014
|
+
}
|
|
3015
|
+
updateLineNumberGutterVisibility();
|
|
3016
|
+
scheduleEditorLineNumberRender();
|
|
3017
|
+
if (editorHighlightEnabled && editorView === "markdown") {
|
|
3018
|
+
scheduleEditorHighlightRender();
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
|
|
2768
3022
|
function getToken() {
|
|
2769
3023
|
const query = new URLSearchParams(window.location.search || "");
|
|
2770
3024
|
const hash = new URLSearchParams((window.location.hash || "").replace(/^#/, ""));
|
|
@@ -3291,9 +3545,13 @@
|
|
|
3291
3545
|
}
|
|
3292
3546
|
|
|
3293
3547
|
function syncEditorHighlightScroll() {
|
|
3294
|
-
if (
|
|
3295
|
-
|
|
3296
|
-
|
|
3548
|
+
if (sourceHighlightEl) {
|
|
3549
|
+
sourceHighlightEl.scrollTop = sourceTextEl.scrollTop;
|
|
3550
|
+
sourceHighlightEl.scrollLeft = sourceTextEl.scrollLeft;
|
|
3551
|
+
}
|
|
3552
|
+
if (lineNumberGutterEl) {
|
|
3553
|
+
lineNumberGutterEl.scrollTop = sourceTextEl.scrollTop;
|
|
3554
|
+
}
|
|
3297
3555
|
}
|
|
3298
3556
|
|
|
3299
3557
|
function runEditorMetaUpdateNow() {
|
|
@@ -3521,14 +3779,22 @@
|
|
|
3521
3779
|
syncEditorHighlightScroll();
|
|
3522
3780
|
}
|
|
3523
3781
|
|
|
3782
|
+
function syncHighlightSelectUi() {
|
|
3783
|
+
if (!highlightSelect) return;
|
|
3784
|
+
if (!editorHighlightEnabled) {
|
|
3785
|
+
highlightSelect.value = "off";
|
|
3786
|
+
return;
|
|
3787
|
+
}
|
|
3788
|
+
highlightSelect.value = (editorLanguage && SUPPORTED_LANGUAGES.indexOf(editorLanguage) !== -1)
|
|
3789
|
+
? editorLanguage
|
|
3790
|
+
: "markdown";
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3524
3793
|
function setEditorHighlightEnabled(enabled) {
|
|
3525
3794
|
editorHighlightEnabled = Boolean(enabled);
|
|
3526
3795
|
persistEditorHighlightEnabled(editorHighlightEnabled);
|
|
3527
|
-
|
|
3528
|
-
highlightSelect.value = editorHighlightEnabled ? "on" : "off";
|
|
3529
|
-
}
|
|
3796
|
+
syncHighlightSelectUi();
|
|
3530
3797
|
updateEditorHighlightState();
|
|
3531
|
-
updateLangSelectVisibility();
|
|
3532
3798
|
}
|
|
3533
3799
|
|
|
3534
3800
|
function readStoredEditorLanguage() {
|
|
@@ -3552,9 +3818,7 @@
|
|
|
3552
3818
|
function setEditorLanguage(lang) {
|
|
3553
3819
|
editorLanguage = (lang && SUPPORTED_LANGUAGES.indexOf(lang) !== -1) ? lang : "markdown";
|
|
3554
3820
|
persistEditorLanguage(editorLanguage);
|
|
3555
|
-
|
|
3556
|
-
langSelect.value = editorLanguage;
|
|
3557
|
-
}
|
|
3821
|
+
syncHighlightSelectUi();
|
|
3558
3822
|
if (editorHighlightEnabled && editorView === "markdown") {
|
|
3559
3823
|
scheduleEditorHighlightRender();
|
|
3560
3824
|
}
|
|
@@ -3563,11 +3827,13 @@
|
|
|
3563
3827
|
}
|
|
3564
3828
|
}
|
|
3565
3829
|
|
|
3566
|
-
function
|
|
3567
|
-
if (
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3830
|
+
function setEditorHighlightMode(mode) {
|
|
3831
|
+
if (mode === "off") {
|
|
3832
|
+
setEditorHighlightEnabled(false);
|
|
3833
|
+
return;
|
|
3834
|
+
}
|
|
3835
|
+
setEditorLanguage(mode);
|
|
3836
|
+
setEditorHighlightEnabled(true);
|
|
3571
3837
|
}
|
|
3572
3838
|
|
|
3573
3839
|
function setResponseHighlightEnabled(enabled) {
|
|
@@ -3618,7 +3884,7 @@
|
|
|
3618
3884
|
queueSteerBtn.title = "Queue steering is unavailable in editor-only mode.";
|
|
3619
3885
|
}
|
|
3620
3886
|
if (critiqueBtn) {
|
|
3621
|
-
critiqueBtn.textContent = "Critique
|
|
3887
|
+
critiqueBtn.textContent = "Critique text";
|
|
3622
3888
|
critiqueBtn.classList.remove("request-stop-active");
|
|
3623
3889
|
critiqueBtn.disabled = true;
|
|
3624
3890
|
critiqueBtn.title = "Critique is unavailable in editor-only mode.";
|
|
@@ -3649,7 +3915,7 @@
|
|
|
3649
3915
|
}
|
|
3650
3916
|
|
|
3651
3917
|
if (critiqueBtn) {
|
|
3652
|
-
critiqueBtn.textContent = critiqueIsStop ? "Stop" : "Critique
|
|
3918
|
+
critiqueBtn.textContent = critiqueIsStop ? "Stop" : "Critique text";
|
|
3653
3919
|
critiqueBtn.classList.toggle("request-stop-active", critiqueIsStop);
|
|
3654
3920
|
critiqueBtn.disabled = critiqueIsStop ? wsState === "Disconnected" : (uiBusy || canQueueSteering);
|
|
3655
3921
|
critiqueBtn.title = critiqueIsStop
|
|
@@ -3657,8 +3923,8 @@
|
|
|
3657
3923
|
: (canQueueSteering
|
|
3658
3924
|
? "Critique queueing is not supported while Run editor text is active."
|
|
3659
3925
|
: (annotationsEnabled
|
|
3660
|
-
? "Critique
|
|
3661
|
-
: "Critique
|
|
3926
|
+
? "Critique text as-is (includes [an: ...] markers)."
|
|
3927
|
+
: "Critique text with [an: ...] markers stripped."));
|
|
3662
3928
|
}
|
|
3663
3929
|
}
|
|
3664
3930
|
|
|
@@ -4298,6 +4564,7 @@
|
|
|
4298
4564
|
root.style.setProperty(key, message.vars[key]);
|
|
4299
4565
|
}
|
|
4300
4566
|
});
|
|
4567
|
+
updateDocumentTitle();
|
|
4301
4568
|
}
|
|
4302
4569
|
}
|
|
4303
4570
|
|
|
@@ -4517,11 +4784,11 @@
|
|
|
4517
4784
|
if (!insertHeaderBtn) return;
|
|
4518
4785
|
const hasHeader = stripAnnotationHeader(sourceTextEl.value).hadHeader;
|
|
4519
4786
|
if (hasHeader) {
|
|
4520
|
-
insertHeaderBtn.textContent = "
|
|
4787
|
+
insertHeaderBtn.textContent = "Annotation header: On";
|
|
4521
4788
|
insertHeaderBtn.title = "Remove annotated-reply protocol header while keeping body text.";
|
|
4522
4789
|
return;
|
|
4523
4790
|
}
|
|
4524
|
-
insertHeaderBtn.textContent = "
|
|
4791
|
+
insertHeaderBtn.textContent = "Annotation header: Off";
|
|
4525
4792
|
insertHeaderBtn.title = "Insert annotated-reply protocol header (source metadata, [an: ...] syntax hint, precedence note, and end marker).";
|
|
4526
4793
|
}
|
|
4527
4794
|
|
|
@@ -4617,7 +4884,7 @@
|
|
|
4617
4884
|
|
|
4618
4885
|
if (highlightSelect) {
|
|
4619
4886
|
highlightSelect.addEventListener("change", () => {
|
|
4620
|
-
|
|
4887
|
+
setEditorHighlightMode(highlightSelect.value);
|
|
4621
4888
|
});
|
|
4622
4889
|
}
|
|
4623
4890
|
|
|
@@ -4627,9 +4894,9 @@
|
|
|
4627
4894
|
});
|
|
4628
4895
|
}
|
|
4629
4896
|
|
|
4630
|
-
if (
|
|
4631
|
-
|
|
4632
|
-
|
|
4897
|
+
if (lineNumbersSelect) {
|
|
4898
|
+
lineNumbersSelect.addEventListener("change", () => {
|
|
4899
|
+
setLineNumbersEnabled(lineNumbersSelect.value === "on");
|
|
4633
4900
|
});
|
|
4634
4901
|
}
|
|
4635
4902
|
|
|
@@ -4742,23 +5009,26 @@
|
|
|
4742
5009
|
});
|
|
4743
5010
|
|
|
4744
5011
|
sourceTextEl.addEventListener("scroll", () => {
|
|
4745
|
-
if (
|
|
5012
|
+
if (editorView !== "markdown") return;
|
|
4746
5013
|
syncEditorHighlightScroll();
|
|
4747
5014
|
});
|
|
4748
5015
|
|
|
4749
5016
|
sourceTextEl.addEventListener("keyup", () => {
|
|
4750
|
-
if (
|
|
5017
|
+
if (editorView !== "markdown") return;
|
|
4751
5018
|
syncEditorHighlightScroll();
|
|
4752
5019
|
});
|
|
4753
5020
|
|
|
4754
5021
|
sourceTextEl.addEventListener("mouseup", () => {
|
|
4755
|
-
if (
|
|
5022
|
+
if (editorView !== "markdown") return;
|
|
4756
5023
|
syncEditorHighlightScroll();
|
|
4757
5024
|
});
|
|
4758
5025
|
|
|
4759
5026
|
window.addEventListener("resize", () => {
|
|
4760
|
-
if (
|
|
5027
|
+
if (editorView !== "markdown") return;
|
|
4761
5028
|
syncEditorHighlightScroll();
|
|
5029
|
+
if (lineNumbersEnabled) {
|
|
5030
|
+
scheduleEditorLineNumberRender();
|
|
5031
|
+
}
|
|
4762
5032
|
});
|
|
4763
5033
|
|
|
4764
5034
|
insertHeaderBtn.addEventListener("click", () => {
|
|
@@ -5286,6 +5556,14 @@
|
|
|
5286
5556
|
reader.readAsText(file);
|
|
5287
5557
|
});
|
|
5288
5558
|
|
|
5559
|
+
if (sourceEditorWrapEl && typeof ResizeObserver === "function") {
|
|
5560
|
+
const editorResizeObserver = new ResizeObserver(() => {
|
|
5561
|
+
if (editorView !== "markdown" || !lineNumbersEnabled) return;
|
|
5562
|
+
scheduleEditorLineNumberRender();
|
|
5563
|
+
});
|
|
5564
|
+
editorResizeObserver.observe(sourceEditorWrapEl);
|
|
5565
|
+
}
|
|
5566
|
+
|
|
5289
5567
|
setSourceState(initialSourceState);
|
|
5290
5568
|
refreshResponseUi();
|
|
5291
5569
|
updateAnnotatedReplyHeaderButton();
|
|
@@ -5293,13 +5571,17 @@
|
|
|
5293
5571
|
setScratchpadText(readStoredScratchpadText() || "", { persist: false });
|
|
5294
5572
|
|
|
5295
5573
|
const storedEditorHighlightEnabled = readStoredEditorHighlightEnabled();
|
|
5296
|
-
const initialHighlightEnabled = storedEditorHighlightEnabled ?? Boolean(highlightSelect && highlightSelect.value
|
|
5574
|
+
const initialHighlightEnabled = storedEditorHighlightEnabled ?? Boolean(highlightSelect && highlightSelect.value !== "off");
|
|
5297
5575
|
setEditorHighlightEnabled(initialHighlightEnabled);
|
|
5298
5576
|
|
|
5299
5577
|
const initialDetectedLang = detectLanguageFromName(initialSourceState.path || initialSourceState.label || "");
|
|
5300
5578
|
const storedLang = readStoredEditorLanguage();
|
|
5301
5579
|
setEditorLanguage(initialDetectedLang || storedLang || "markdown");
|
|
5302
5580
|
|
|
5581
|
+
const storedLineNumbersEnabled = readStoredEditorLineNumbersEnabled();
|
|
5582
|
+
const initialLineNumbersEnabled = storedLineNumbersEnabled ?? Boolean(lineNumbersSelect && lineNumbersSelect.value === "on");
|
|
5583
|
+
setLineNumbersEnabled(initialLineNumbersEnabled);
|
|
5584
|
+
|
|
5303
5585
|
const storedResponseHighlightEnabled = readStoredResponseHighlightEnabled();
|
|
5304
5586
|
const initialResponseHighlightEnabled = storedResponseHighlightEnabled ?? Boolean(responseHighlightSelect && responseHighlightSelect.value === "on");
|
|
5305
5587
|
setResponseHighlightEnabled(initialResponseHighlightEnabled);
|
package/client/studio.css
CHANGED
|
@@ -87,14 +87,19 @@
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
#sendRunBtn,
|
|
90
|
-
#queueSteerBtn
|
|
91
|
-
#critiqueBtn {
|
|
90
|
+
#queueSteerBtn {
|
|
92
91
|
min-width: 10rem;
|
|
93
92
|
display: inline-flex;
|
|
94
93
|
justify-content: center;
|
|
95
94
|
align-items: center;
|
|
96
95
|
}
|
|
97
96
|
|
|
97
|
+
#critiqueBtn {
|
|
98
|
+
display: inline-flex;
|
|
99
|
+
justify-content: center;
|
|
100
|
+
align-items: center;
|
|
101
|
+
}
|
|
102
|
+
|
|
98
103
|
#sendRunBtn:not(:disabled):not(.request-stop-active),
|
|
99
104
|
#queueSteerBtn:not(:disabled),
|
|
100
105
|
#loadResponseBtn:not(:disabled):not([hidden]) {
|
|
@@ -412,6 +417,7 @@
|
|
|
412
417
|
}
|
|
413
418
|
|
|
414
419
|
.editor-highlight-wrap {
|
|
420
|
+
--editor-line-number-gutter-width: 0px;
|
|
415
421
|
position: relative;
|
|
416
422
|
display: flex;
|
|
417
423
|
flex: 1 1 auto;
|
|
@@ -424,13 +430,63 @@
|
|
|
424
430
|
overscroll-behavior: none;
|
|
425
431
|
}
|
|
426
432
|
|
|
433
|
+
.editor-line-number-gutter {
|
|
434
|
+
position: absolute;
|
|
435
|
+
inset: 0 auto 0 0;
|
|
436
|
+
width: var(--editor-line-number-gutter-width);
|
|
437
|
+
overflow: hidden;
|
|
438
|
+
border-right: 1px solid var(--border-muted);
|
|
439
|
+
background: var(--panel-2);
|
|
440
|
+
color: var(--muted);
|
|
441
|
+
pointer-events: none;
|
|
442
|
+
z-index: 0;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.editor-line-number-gutter-content {
|
|
446
|
+
min-height: 100%;
|
|
447
|
+
padding: 10px 8px 10px 0;
|
|
448
|
+
text-align: right;
|
|
449
|
+
font-family: var(--font-mono);
|
|
450
|
+
font-size: 12px;
|
|
451
|
+
line-height: 1.45;
|
|
452
|
+
font-variant-numeric: tabular-nums;
|
|
453
|
+
white-space: nowrap;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.editor-line-number-row {
|
|
457
|
+
display: block;
|
|
458
|
+
user-select: none;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.editor-line-number-measure {
|
|
462
|
+
position: absolute;
|
|
463
|
+
top: 0;
|
|
464
|
+
left: 0;
|
|
465
|
+
visibility: hidden;
|
|
466
|
+
pointer-events: none;
|
|
467
|
+
overflow: hidden;
|
|
468
|
+
white-space: pre-wrap;
|
|
469
|
+
word-break: normal;
|
|
470
|
+
overflow-wrap: break-word;
|
|
471
|
+
font-family: var(--font-mono);
|
|
472
|
+
font-size: 13px;
|
|
473
|
+
line-height: 1.45;
|
|
474
|
+
tab-size: 2;
|
|
475
|
+
z-index: -1;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.editor-line-number-measure-line {
|
|
479
|
+
display: block;
|
|
480
|
+
min-height: 1.45em;
|
|
481
|
+
}
|
|
482
|
+
|
|
427
483
|
.editor-highlight {
|
|
428
484
|
position: absolute;
|
|
429
485
|
inset: 0;
|
|
430
486
|
margin: 0;
|
|
431
487
|
border: 0;
|
|
432
488
|
border-radius: 8px;
|
|
433
|
-
padding: 10px;
|
|
489
|
+
padding: 10px 10px 10px calc(10px + var(--editor-line-number-gutter-width));
|
|
434
490
|
overflow: auto;
|
|
435
491
|
pointer-events: none;
|
|
436
492
|
white-space: pre-wrap;
|
|
@@ -457,6 +513,7 @@
|
|
|
457
513
|
resize: none;
|
|
458
514
|
outline: none;
|
|
459
515
|
overscroll-behavior: none;
|
|
516
|
+
padding: 10px 10px 10px calc(10px + var(--editor-line-number-gutter-width));
|
|
460
517
|
}
|
|
461
518
|
|
|
462
519
|
#sourceText.highlight-active {
|
package/index.ts
CHANGED
|
@@ -955,7 +955,7 @@ function rawDataToString(data: RawData): string {
|
|
|
955
955
|
if (typeof data === "string") return data;
|
|
956
956
|
if (data instanceof Buffer) return data.toString("utf-8");
|
|
957
957
|
if (Array.isArray(data)) return Buffer.concat(data).toString("utf-8");
|
|
958
|
-
return Buffer.from(data).toString("utf-8");
|
|
958
|
+
return Buffer.from(data as ArrayBuffer).toString("utf-8");
|
|
959
959
|
}
|
|
960
960
|
|
|
961
961
|
function isValidRequestId(id: string): boolean {
|
|
@@ -3259,7 +3259,7 @@ function renderStudioAnnotationPdfLatex(text: string): string {
|
|
|
3259
3259
|
function replaceStudioAnnotationMarkersForPdfInSegment(text: string): string {
|
|
3260
3260
|
const replaced = replaceStudioInlineAnnotationMarkers(
|
|
3261
3261
|
String(text ?? ""),
|
|
3262
|
-
(marker) => {
|
|
3262
|
+
(marker: { body: string }) => {
|
|
3263
3263
|
const cleaned = renderStudioAnnotationPdfLatex(marker.body);
|
|
3264
3264
|
if (!cleaned) return "";
|
|
3265
3265
|
return `\\studioannotation{${cleaned}}`;
|
|
@@ -3276,7 +3276,7 @@ function replaceStudioAnnotationMarkersForPdfInSegment(text: string): string {
|
|
|
3276
3276
|
|
|
3277
3277
|
function replaceStudioAnnotationMarkersForPdf(markdown: string): string {
|
|
3278
3278
|
if (!hasStudioMarkdownAnnotationMarkers(markdown)) return String(markdown ?? "");
|
|
3279
|
-
return transformStudioMarkdownOutsideFences(markdown, (segment) => replaceStudioAnnotationMarkersForPdfInSegment(segment));
|
|
3279
|
+
return transformStudioMarkdownOutsideFences(markdown, (segment: string) => replaceStudioAnnotationMarkersForPdfInSegment(segment));
|
|
3280
3280
|
}
|
|
3281
3281
|
|
|
3282
3282
|
interface StudioPdfRenderOptions {
|
|
@@ -4325,13 +4325,13 @@ function replaceStudioAnnotationMarkersInDiffTokenLine(line: string, macroName:
|
|
|
4325
4325
|
const wrapText = (text: string): string => text ? `\\${macroName}{${text}}` : "";
|
|
4326
4326
|
const rewritten = replaceStudioInlineAnnotationMarkers(
|
|
4327
4327
|
body,
|
|
4328
|
-
(marker) => {
|
|
4328
|
+
(marker: { body: string }) => {
|
|
4329
4329
|
const markerText = decodeStudioGeneratedCodeLatexText(normalizeStudioAnnotationText(marker.body));
|
|
4330
4330
|
const cleaned = makeStudioHighlightingMathScriptsVerbatimSafe(renderStudioAnnotationPdfLatex(markerText));
|
|
4331
4331
|
if (!cleaned) return "";
|
|
4332
4332
|
return `\\studioannotation{${cleaned}}`;
|
|
4333
4333
|
},
|
|
4334
|
-
(segment) => wrapText(segment),
|
|
4334
|
+
(segment: string) => wrapText(segment),
|
|
4335
4335
|
);
|
|
4336
4336
|
|
|
4337
4337
|
return rewritten === body ? line : (rewritten || wrapText(body));
|
|
@@ -5866,7 +5866,7 @@ ${cssVarsBlock}
|
|
|
5866
5866
|
<button id="sendEditorBtn" type="button">Send to pi editor</button>
|
|
5867
5867
|
</div>
|
|
5868
5868
|
<div class="source-actions-row">
|
|
5869
|
-
<button id="insertHeaderBtn" type="button" title="Insert annotated-reply protocol header (source metadata, [an: ...] syntax hint, precedence note, and end marker).">
|
|
5869
|
+
<button id="insertHeaderBtn" type="button" title="Insert annotated-reply protocol header (source metadata, [an: ...] syntax hint, precedence note, and end marker).">Annotation header</button>
|
|
5870
5870
|
<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.">
|
|
5871
5871
|
<option value="on" selected>Annotations: On</option>
|
|
5872
5872
|
<option value="off">Annotations: Hidden</option>
|
|
@@ -5876,46 +5876,51 @@ ${cssVarsBlock}
|
|
|
5876
5876
|
</div>
|
|
5877
5877
|
<div class="source-actions-row">
|
|
5878
5878
|
<select id="lensSelect" aria-label="Critique focus">
|
|
5879
|
-
<option value="auto" selected>Critique
|
|
5880
|
-
<option value="writing">Critique
|
|
5881
|
-
<option value="code">Critique
|
|
5879
|
+
<option value="auto" selected>Critique: Auto</option>
|
|
5880
|
+
<option value="writing">Critique: Writing</option>
|
|
5881
|
+
<option value="code">Critique: Code</option>
|
|
5882
5882
|
</select>
|
|
5883
|
-
<button id="critiqueBtn" type="button">Critique
|
|
5883
|
+
<button id="critiqueBtn" type="button">Critique text</button>
|
|
5884
5884
|
<select id="highlightSelect" aria-label="Editor syntax highlighting">
|
|
5885
5885
|
<option value="off">Syntax highlight: Off</option>
|
|
5886
|
-
<option value="
|
|
5886
|
+
<option value="bash">Syntax highlight: Bash</option>
|
|
5887
|
+
<option value="c">Syntax highlight: C</option>
|
|
5888
|
+
<option value="cpp">Syntax highlight: C++</option>
|
|
5889
|
+
<option value="css">Syntax highlight: CSS</option>
|
|
5890
|
+
<option value="diff">Syntax highlight: Diff</option>
|
|
5891
|
+
<option value="fortran">Syntax highlight: Fortran</option>
|
|
5892
|
+
<option value="go">Syntax highlight: Go</option>
|
|
5893
|
+
<option value="html">Syntax highlight: HTML</option>
|
|
5894
|
+
<option value="java">Syntax highlight: Java</option>
|
|
5895
|
+
<option value="javascript">Syntax highlight: JavaScript</option>
|
|
5896
|
+
<option value="json">Syntax highlight: JSON</option>
|
|
5897
|
+
<option value="julia">Syntax highlight: Julia</option>
|
|
5898
|
+
<option value="latex">Syntax highlight: LaTeX</option>
|
|
5899
|
+
<option value="lua">Syntax highlight: Lua</option>
|
|
5900
|
+
<option value="markdown" selected>Syntax highlight: Markdown</option>
|
|
5901
|
+
<option value="matlab">Syntax highlight: MATLAB</option>
|
|
5902
|
+
<option value="text">Syntax highlight: Plain Text</option>
|
|
5903
|
+
<option value="python">Syntax highlight: Python</option>
|
|
5904
|
+
<option value="r">Syntax highlight: R</option>
|
|
5905
|
+
<option value="rust">Syntax highlight: Rust</option>
|
|
5906
|
+
<option value="swift">Syntax highlight: Swift</option>
|
|
5907
|
+
<option value="toml">Syntax highlight: TOML</option>
|
|
5908
|
+
<option value="typescript">Syntax highlight: TypeScript</option>
|
|
5909
|
+
<option value="xml">Syntax highlight: XML</option>
|
|
5910
|
+
<option value="yaml">Syntax highlight: YAML</option>
|
|
5887
5911
|
</select>
|
|
5888
|
-
<select id="
|
|
5889
|
-
<option value="
|
|
5890
|
-
<option value="
|
|
5891
|
-
<option value="cpp">Lang: C++</option>
|
|
5892
|
-
<option value="css">Lang: CSS</option>
|
|
5893
|
-
<option value="diff">Lang: Diff</option>
|
|
5894
|
-
<option value="fortran">Lang: Fortran</option>
|
|
5895
|
-
<option value="go">Lang: Go</option>
|
|
5896
|
-
<option value="html">Lang: HTML</option>
|
|
5897
|
-
<option value="java">Lang: Java</option>
|
|
5898
|
-
<option value="javascript">Lang: JavaScript</option>
|
|
5899
|
-
<option value="json">Lang: JSON</option>
|
|
5900
|
-
<option value="julia">Lang: Julia</option>
|
|
5901
|
-
<option value="latex">Lang: LaTeX</option>
|
|
5902
|
-
<option value="lua">Lang: Lua</option>
|
|
5903
|
-
<option value="markdown" selected>Lang: Markdown</option>
|
|
5904
|
-
<option value="matlab">Lang: MATLAB</option>
|
|
5905
|
-
<option value="text">Lang: Plain Text</option>
|
|
5906
|
-
<option value="python">Lang: Python</option>
|
|
5907
|
-
<option value="r">Lang: R</option>
|
|
5908
|
-
<option value="rust">Lang: Rust</option>
|
|
5909
|
-
<option value="swift">Lang: Swift</option>
|
|
5910
|
-
<option value="toml">Lang: TOML</option>
|
|
5911
|
-
<option value="typescript">Lang: TypeScript</option>
|
|
5912
|
-
<option value="xml">Lang: XML</option>
|
|
5913
|
-
<option value="yaml">Lang: YAML</option>
|
|
5912
|
+
<select id="lineNumbersSelect" aria-label="Editor line numbers">
|
|
5913
|
+
<option value="off" selected>Line numbers: Off</option>
|
|
5914
|
+
<option value="on">Line numbers: On</option>
|
|
5914
5915
|
</select>
|
|
5915
5916
|
</div>
|
|
5916
5917
|
</div>
|
|
5917
5918
|
</div>
|
|
5918
5919
|
<div id="sourceEditorWrap" class="editor-highlight-wrap">
|
|
5920
|
+
<div id="lineNumberGutter" class="editor-line-number-gutter" hidden aria-hidden="true">
|
|
5921
|
+
<div id="lineNumberGutterContent" class="editor-line-number-gutter-content"></div>
|
|
5922
|
+
</div>
|
|
5923
|
+
<div id="lineNumberMeasure" class="editor-line-number-measure" aria-hidden="true"></div>
|
|
5919
5924
|
<pre id="sourceHighlight" class="editor-highlight" aria-hidden="true"></pre>
|
|
5920
5925
|
<textarea id="sourceText" placeholder="Paste or edit text here.">${initialText}</textarea>
|
|
5921
5926
|
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-studio",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.44",
|
|
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",
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"assets/screenshots"
|
|
26
26
|
],
|
|
27
27
|
"scripts": {
|
|
28
|
-
"test": "node --test"
|
|
28
|
+
"test": "node --test",
|
|
29
|
+
"typecheck": "tsc --noEmit"
|
|
29
30
|
},
|
|
30
31
|
"pi": {
|
|
31
32
|
"extensions": [
|
|
@@ -37,5 +38,11 @@
|
|
|
37
38
|
},
|
|
38
39
|
"dependencies": {
|
|
39
40
|
"ws": "^8.18.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@mariozechner/pi-coding-agent": "^0.64.0",
|
|
44
|
+
"@types/node": "^24.3.0",
|
|
45
|
+
"@types/ws": "^8.18.1",
|
|
46
|
+
"typescript": "^5.7.3"
|
|
40
47
|
}
|
|
41
48
|
}
|