pi-studio 0.9.46 → 0.9.47

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
@@ -4,6 +4,11 @@ All notable changes to `pi-studio` are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.9.47] — 2026-08-20
8
+
9
+ ### Fixed
10
+ - Fall back to Pandoc’s compatible self-contained resource mode when its capability probe times out, and evict failed probes so one transient delay cannot disable previews for the rest of the Studio process.
11
+
7
12
  ## [0.9.46] — 2026-08-20
8
13
 
9
14
  ### Fixed
package/index.ts CHANGED
@@ -29,6 +29,7 @@ import {
29
29
  } from "./shared/studio-markdown-latex-literals.js";
30
30
  import { escapeStudioPdfLatexTextFragment } from "./shared/studio-pdf-escape.js";
31
31
  import { resolveStudioPdfResourceFile } from "./shared/studio-pdf-resource.js";
32
+ import { createStudioPandocHtmlResourceFlagResolver } from "./shared/studio-pandoc-resource-flag.js";
32
33
  import { isStudioCmuxSession, openStudioUrlInBrowser } from "./shared/studio-browser-launcher.js";
33
34
  import { buildStudioReplTmuxStartArgs } from "./shared/studio-repl-tmux.js";
34
35
  import { buildStudioForwardingHint, buildStudioSshTunnelHint, isStudioSshSession as isSshSession } from "./shared/studio-ssh-hint.js";
@@ -6126,27 +6127,19 @@ function decorateStudioPandocSyntaxHtml(html: string): string {
6126
6127
  );
6127
6128
  }
6128
6129
 
6129
- const studioPandocHtmlResourceFlagCache = new Map<string, Promise<"--embed-resources" | "--self-contained">>();
6130
-
6131
- async function getStudioPandocHtmlResourceFlag(pandocCommand: string): Promise<"--embed-resources" | "--self-contained"> {
6132
- let cached = studioPandocHtmlResourceFlagCache.get(pandocCommand);
6133
- if (!cached) {
6134
- cached = runStudioSubprocess(pandocCommand, ["--help"], {
6135
- timeoutMs: 5_000,
6136
- stdoutMaxBytes: 250_000,
6137
- stderrMaxBytes: 20_000,
6138
- label: "pandoc capability probe",
6139
- notFoundMessage: "pandoc was not found. Install pandoc or set PANDOC_PATH to the pandoc binary.",
6140
- }).then((result) => {
6141
- if (result.code !== 0) {
6142
- throw new Error(`pandoc capability probe failed with exit code ${result.code}${result.stderr ? `: ${result.stderr}` : ""}`);
6143
- }
6144
- return result.stdout.includes("--embed-resources") ? "--embed-resources" : "--self-contained";
6145
- });
6146
- studioPandocHtmlResourceFlagCache.set(pandocCommand, cached);
6130
+ const resolveStudioPandocHtmlResourceFlag = createStudioPandocHtmlResourceFlagResolver(async (pandocCommand: string) => {
6131
+ const result = await runStudioSubprocess(pandocCommand, ["--help"], {
6132
+ timeoutMs: 5_000,
6133
+ stdoutMaxBytes: 250_000,
6134
+ stderrMaxBytes: 20_000,
6135
+ label: "pandoc capability probe",
6136
+ notFoundMessage: "pandoc was not found. Install pandoc or set PANDOC_PATH to the pandoc binary.",
6137
+ });
6138
+ if (result.code !== 0) {
6139
+ throw new Error(`pandoc capability probe failed with exit code ${result.code}${result.stderr ? `: ${result.stderr}` : ""}`);
6147
6140
  }
6148
- return cached;
6149
- }
6141
+ return result.stdout;
6142
+ });
6150
6143
 
6151
6144
  function preprocessStudioLatexFootnotemarksForPreview(latex: string): string {
6152
6145
  return String(latex ?? "").replace(/\\footnotemark\s*\[\s*([^\]\r\n]+?)\s*\]/g, (_match, marker: string) => {
@@ -6186,7 +6179,7 @@ async function renderStudioMarkdownWithPandoc(markdown: string, isLatex?: boolea
6186
6179
  await mkdir(htmlTemplateDir, { recursive: true });
6187
6180
  const htmlTemplatePath = join(htmlTemplateDir, "template.html");
6188
6181
  await writeFile(htmlTemplatePath, STUDIO_PANDOC_HTML_FRAGMENT_TEMPLATE, "utf-8");
6189
- if (resourcePath) args.push(await getStudioPandocHtmlResourceFlag(pandocCommand));
6182
+ if (resourcePath) args.push(await resolveStudioPandocHtmlResourceFlag(pandocCommand));
6190
6183
  args.push("--standalone", `--template=${htmlTemplatePath}`);
6191
6184
  }
6192
6185
  const normalizedMarkdown = isLatex
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-studio",
3
- "version": "0.9.46",
3
+ "version": "0.9.47",
4
4
  "description": "Two-pane browser workspace for pi with prompt/response editing, annotations, critiques, active quiz, prompt/response history, live previews, and tmux-backed REPL/literate REPL workflows",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -0,0 +1,34 @@
1
+ export function createStudioPandocHtmlResourceFlagResolver(probeHelp) {
2
+ if (typeof probeHelp !== "function") {
3
+ throw new TypeError("A Pandoc capability probe function is required.");
4
+ }
5
+
6
+ const cache = new Map();
7
+
8
+ async function getResourceFlag(pandocCommand) {
9
+ const command = String(pandocCommand || "pandoc");
10
+ let cached = cache.get(command);
11
+ if (!cached) {
12
+ cached = Promise.resolve()
13
+ .then(() => probeHelp(command))
14
+ .then((helpText) => String(helpText || "").includes("--embed-resources")
15
+ ? "--embed-resources"
16
+ : "--self-contained");
17
+ cache.set(command, cached);
18
+ void cached.catch(() => {
19
+ if (cache.get(command) === cached) cache.delete(command);
20
+ });
21
+ }
22
+ return cached;
23
+ }
24
+
25
+ return async function resolveStudioPandocHtmlResourceFlag(pandocCommand) {
26
+ try {
27
+ return await getResourceFlag(pandocCommand);
28
+ } catch {
29
+ // Old and current Pandoc versions accept --self-contained. The actual
30
+ // render can now succeed or report the executable's useful error.
31
+ return "--self-contained";
32
+ }
33
+ };
34
+ }