pi-studio 0.5.52 → 0.5.54
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 +21 -0
- package/README.md +3 -3
- package/client/studio-annotation-helpers.js +67 -0
- package/client/studio-client.js +596 -89
- package/client/studio.css +176 -0
- package/index.ts +332 -3
- package/package.json +1 -1
- package/shared/studio-markdown-latex-literals.js +203 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,27 @@ All notable changes to `pi-studio` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.5.54] — 2026-04-13
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- Markdown editor-preview comment mapping now keeps standalone markdown image blocks aligned with rendered preview figures, preventing later preview comment targets from drifting after figures.
|
|
11
|
+
- Rendered Markdown fenced code blocks now once again support preview-side text-selection comments.
|
|
12
|
+
|
|
13
|
+
## [0.5.53] — 2026-04-10
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- Studio now includes a live right-pane **Working** view for following current model/tool activity as it streams.
|
|
17
|
+
- **Working** includes `All` / `Thinking` / `Tools` filters plus **Load visible into editor** and **Copy visible** actions.
|
|
18
|
+
- Markdown preview/PDF regression coverage now includes preservation of literal LaTeX prose commands such as `\cite{...}` and `\ref{...}`.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- The former standalone right-pane **Thinking** mode has been folded into **Working**.
|
|
22
|
+
- Working status/summary chips are quieter and read more like status labels than action buttons.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- Markdown preview and PDF export now preserve literal LaTeX prose commands like `\cite{...}` and `\ref{...}` instead of silently dropping them outside math/code contexts.
|
|
26
|
+
- Working-pane interaction handlers now survive response-pane replacement, so filters/actions keep working and scrolling up can pause live auto-follow until you return near the bottom.
|
|
27
|
+
|
|
7
28
|
## [0.5.52] — 2026-04-09
|
|
8
29
|
|
|
9
30
|
### Added
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pi-studio
|
|
2
2
|
|
|
3
|
-
Extension for [pi](https://pi.dev) that opens a local two-pane browser workspace for working with prompts, responses, Markdown and LaTeX documents, code files, and other common text-based files side by side. Annotate responses and files, add local comments, write, edit, and run prompts, browse prompt and response history, request critiques, and use live preview for code, Markdown, and LaTeX.
|
|
3
|
+
Extension for [pi](https://pi.dev) that opens a local two-pane browser workspace for working with prompts, responses, live working details, Markdown and LaTeX documents, code files, and other common text-based files side by side. Annotate responses and files, add local comments, write, edit, and run prompts, browse prompt and response history, request critiques, and use live preview for code, Markdown, and LaTeX.
|
|
4
4
|
|
|
5
5
|
## Screenshots
|
|
6
6
|
|
|
@@ -14,16 +14,16 @@ Extension for [pi](https://pi.dev) that opens a local two-pane browser workspace
|
|
|
14
14
|
|
|
15
15
|
## What it does
|
|
16
16
|
|
|
17
|
-
- Opens a two-pane browser workspace: **Editor** (left) + **Response/
|
|
17
|
+
- Opens a two-pane browser workspace: **Editor** (left) + **Response/Working/Editor Preview** (right)
|
|
18
18
|
- Supports one canonical full Studio view per Pi session, plus additional editor-only companion views when you just want extra editing/preview surfaces
|
|
19
19
|
- Runs editor text directly, or asks for structured critique (auto/writing/code focus)
|
|
20
|
+
- Includes a live **Working** view for following current model/tool activity, with `All` / `Thinking` / `Tools` filters plus **Load visible into editor** and **Copy visible** actions
|
|
20
21
|
- Includes a local persistent scratchpad for quick notes you want to keep out of the main editor until you're ready to copy or insert them
|
|
21
22
|
- Includes a docked **Outline** rail for navigating document structure in the current editor text, with clickable entries that jump in the raw editor and reveal matching preview locations when available
|
|
22
23
|
- Includes local comments anchored to selections/lines, shown in a docked **Comments** rail, with transient **Comment** / **Jump** actions from raw-editor selections plus editor-preview selections for Markdown, LaTeX, and code/text/diff previews, alongside optional inline `[an: ...]` toggles when you want comments reflected in the document text
|
|
23
24
|
- Browses response history (`Prev/Next/Last`) and loads either:
|
|
24
25
|
- response text
|
|
25
26
|
- critique notes/full critique
|
|
26
|
-
- assistant thinking (when available)
|
|
27
27
|
- the prompt that generated a selected response
|
|
28
28
|
- Supports an annotation workflow for `[an: ...]` markers:
|
|
29
29
|
- inserts/removes the annotated-reply header
|
|
@@ -187,7 +187,9 @@
|
|
|
187
187
|
|
|
188
188
|
if (index >= text.length || text[index] !== "]" || text[index + 1] !== "(") return null;
|
|
189
189
|
|
|
190
|
+
const label = text.slice(startIndex + 1, index);
|
|
190
191
|
index += 2;
|
|
192
|
+
const destinationStart = index;
|
|
191
193
|
let parenDepth = 0;
|
|
192
194
|
while (index < text.length) {
|
|
193
195
|
const ch = text[index];
|
|
@@ -210,6 +212,8 @@
|
|
|
210
212
|
type: "literal",
|
|
211
213
|
raw: text.slice(startIndex, index + 1),
|
|
212
214
|
end: index + 1,
|
|
215
|
+
label: label,
|
|
216
|
+
destination: text.slice(destinationStart, index),
|
|
213
217
|
};
|
|
214
218
|
}
|
|
215
219
|
parenDepth -= 1;
|
|
@@ -223,6 +227,68 @@
|
|
|
223
227
|
return null;
|
|
224
228
|
}
|
|
225
229
|
|
|
230
|
+
function readMarkdownAttributeBlockAt(source, startIndex) {
|
|
231
|
+
const text = String(source || "");
|
|
232
|
+
if (text[startIndex] !== "{") return null;
|
|
233
|
+
|
|
234
|
+
let depth = 0;
|
|
235
|
+
for (let index = startIndex; index < text.length; index += 1) {
|
|
236
|
+
const ch = text[index];
|
|
237
|
+
if (ch === "\\") {
|
|
238
|
+
index += 1;
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (ch === "\n") return null;
|
|
242
|
+
if (ch === "{") {
|
|
243
|
+
depth += 1;
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (ch === "}") {
|
|
247
|
+
depth -= 1;
|
|
248
|
+
if (depth === 0) {
|
|
249
|
+
return {
|
|
250
|
+
raw: text.slice(startIndex, index + 1),
|
|
251
|
+
end: index + 1,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function extractStandaloneMarkdownImageCaptionText(text) {
|
|
261
|
+
const source = String(text || "").replace(/\r\n/g, "\n").trim();
|
|
262
|
+
if (!source) return null;
|
|
263
|
+
|
|
264
|
+
const captions = [];
|
|
265
|
+
let index = 0;
|
|
266
|
+
let sawImage = false;
|
|
267
|
+
|
|
268
|
+
while (index < source.length) {
|
|
269
|
+
while (index < source.length && /\s/.test(source[index])) index += 1;
|
|
270
|
+
if (index >= source.length) break;
|
|
271
|
+
if (source[index] !== "!") return null;
|
|
272
|
+
|
|
273
|
+
const imageToken = readInlineMarkdownLinkAt(source, index + 1);
|
|
274
|
+
if (!imageToken) return null;
|
|
275
|
+
|
|
276
|
+
sawImage = true;
|
|
277
|
+
captions.push(normalizePreviewAnnotationLabel(imageToken.label || ""));
|
|
278
|
+
index = imageToken.end;
|
|
279
|
+
|
|
280
|
+
while (index < source.length && /\s/.test(source[index])) index += 1;
|
|
281
|
+
if (index < source.length && source[index] === "{") {
|
|
282
|
+
const attributeBlock = readMarkdownAttributeBlockAt(source, index);
|
|
283
|
+
if (!attributeBlock) return null;
|
|
284
|
+
index = attributeBlock.end;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (!sawImage) return null;
|
|
289
|
+
return captions.filter(Boolean).join(" ").trim();
|
|
290
|
+
}
|
|
291
|
+
|
|
226
292
|
function readDelimitedPreviewTokenAt(source, startIndex, open, close, allowNewlines) {
|
|
227
293
|
const text = String(source || "");
|
|
228
294
|
if (text.slice(startIndex, startIndex + open.length) !== open) return null;
|
|
@@ -596,6 +662,7 @@
|
|
|
596
662
|
collectInlineAnnotationMarkers: collectInlineAnnotationMarkers,
|
|
597
663
|
hasAnnotationMarkers: hasAnnotationMarkers,
|
|
598
664
|
normalizePreviewAnnotationLabel: normalizePreviewAnnotationLabel,
|
|
665
|
+
extractStandaloneMarkdownImageCaptionText: extractStandaloneMarkdownImageCaptionText,
|
|
599
666
|
prepareMarkdownForPandocPreview: prepareMarkdownForPandocPreview,
|
|
600
667
|
readInlineAnnotationMarkerAt: readInlineAnnotationMarkerAt,
|
|
601
668
|
renderPreviewAnnotationHtml: renderPreviewAnnotationHtml,
|