pi-studio 0.9.34 → 0.9.36
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/README.md +1 -1
- package/client/studio-client.js +71 -2
- package/client/studio.css +11 -1
- package/index.ts +38 -14
- 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.9.36] — 2026-07-13
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Added `max` to the Studio footer Pi thinking selector to match newer Pi thinking levels.
|
|
11
|
+
|
|
12
|
+
## [0.9.35] — 2026-07-13
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- Added Files-view sort options for name, newest/oldest modified time, and largest/smallest file size.
|
|
16
|
+
|
|
7
17
|
## [0.9.34] — 2026-07-02
|
|
8
18
|
|
|
9
19
|
### Added
|
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ _The video shows an earlier version of the Studio interface. The basic workflow
|
|
|
34
34
|
- Runs editor text directly, asks for structured critique (auto/writing/code focus), offers a manual **Suggest completion** action for short cursor-aware continuations (`Option/Alt+Tab` where available or `Cmd/Ctrl+Shift+Space` from the editor, `Tab` to insert a visible suggestion) with an optional editor-plus-latest-response context mode, or opens **Quiz me** for a Studio-native active-recall loop over the current editor text, selection, current file, folder, or repo, with optional focus guidance for shaping question selection
|
|
35
35
|
- Includes a live **Working** view for following current model/tool activity, with `All` / `Thinking` / `Tools` filters, image previews for image-producing tool outputs, plus **Load visible into editor** and **Copy visible** actions; when cycling response history, Working follows saved working details for the selected response when available, and `Cmd/Ctrl+Alt+1–7` switches directly between right-pane views while `Cmd/Ctrl+Alt+P` / `Cmd/Ctrl+Alt+E` / `Cmd/Ctrl+Alt+W` keep quick mnemonic shortcuts for Response Preview, Editor Preview, and Working
|
|
36
36
|
- Includes a right-pane **Changes** view for browsing the current git diff by file, previewing per-file diffs, opening changed files, loading the full diff into the editor, and copying the diff
|
|
37
|
-
- Includes a right-pane **Files** view for browsing the current Pi session/resource directory, opening folders, opening the Files root in Finder/the system file manager, loading text/code/CSV/TSV documents into the editor, previewing PDFs/images, opening PDF/image previews in a new Studio tab, converting DOCX/ODT documents to editable Markdown when Pandoc is available after confirmation, copying paths, setting the current folder as the Studio working directory, and revealing files in the file manager
|
|
37
|
+
- Includes a right-pane **Files** view for browsing the current Pi session/resource directory, sorting by name/modified time/size, opening folders, opening the Files root in Finder/the system file manager, loading text/code/CSV/TSV documents into the editor, previewing PDFs/images, opening PDF/image previews in a new Studio tab, converting DOCX/ODT documents to editable Markdown when Pandoc is available after confirmation, copying paths, setting the current folder as the Studio working directory, and revealing files in the file manager
|
|
38
38
|
- Includes an optional tmux-backed **REPL** view for Shell, Python, IPython, Julia, R, GHCi, and Clojure sessions, with Raw/Literate send modes, `Cmd/Ctrl+Shift+Enter` **Send to REPL**, session start/stop/interrupt controls, a compact refresh-persistent **Studio REPL Record** of user and Pi-sent code, a secondary raw tmux mirror, agent-facing `studio_repl_status` / `studio_repl_send` tools, and Markdown/PDF/HTML export
|
|
39
39
|
- 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, with a **Recent…** picker for recovering scratchpads saved under earlier file/draft identities
|
|
40
40
|
- 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
|
package/client/studio-client.js
CHANGED
|
@@ -2104,6 +2104,35 @@
|
|
|
2104
2104
|
const DEFAULT_RESPONSE_FONT_SIZE = studioUiRefreshEnabled ? 13.5 : 15;
|
|
2105
2105
|
let editorFontSize = DEFAULT_EDITOR_FONT_SIZE;
|
|
2106
2106
|
let responseFontSize = DEFAULT_RESPONSE_FONT_SIZE;
|
|
2107
|
+
function normalizeFileBrowserSortMode(sort) {
|
|
2108
|
+
const value = String(sort || "").trim().toLowerCase();
|
|
2109
|
+
if (value === "mtime-desc" || value === "modified-desc" || value === "newest") return "mtime-desc";
|
|
2110
|
+
if (value === "mtime-asc" || value === "modified-asc" || value === "oldest") return "mtime-asc";
|
|
2111
|
+
if (value === "size-desc" || value === "largest") return "size-desc";
|
|
2112
|
+
if (value === "size-asc" || value === "smallest") return "size-asc";
|
|
2113
|
+
return "name";
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
function readFileBrowserSortMode() {
|
|
2117
|
+
try {
|
|
2118
|
+
const stored = window.localStorage ? window.localStorage.getItem("piStudio.fileBrowserSort") : "";
|
|
2119
|
+
return normalizeFileBrowserSortMode(stored);
|
|
2120
|
+
} catch {
|
|
2121
|
+
return "name";
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
function writeFileBrowserSortMode(sort) {
|
|
2126
|
+
const normalized = normalizeFileBrowserSortMode(sort);
|
|
2127
|
+
try {
|
|
2128
|
+
if (window.localStorage) window.localStorage.setItem("piStudio.fileBrowserSort", normalized);
|
|
2129
|
+
} catch {
|
|
2130
|
+
// Ignore storage failures.
|
|
2131
|
+
}
|
|
2132
|
+
return normalized;
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
let fileBrowserSortMode = readFileBrowserSortMode();
|
|
2107
2136
|
let fileBrowserState = {
|
|
2108
2137
|
rootDir: "",
|
|
2109
2138
|
currentDir: "",
|
|
@@ -2112,6 +2141,7 @@
|
|
|
2112
2141
|
entries: [],
|
|
2113
2142
|
omitted: 0,
|
|
2114
2143
|
omittedIgnored: 0,
|
|
2144
|
+
sort: fileBrowserSortMode,
|
|
2115
2145
|
loading: false,
|
|
2116
2146
|
error: "",
|
|
2117
2147
|
loaded: false,
|
|
@@ -3292,7 +3322,7 @@
|
|
|
3292
3322
|
}
|
|
3293
3323
|
|
|
3294
3324
|
function getPiThinkingLevels() {
|
|
3295
|
-
return ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
3325
|
+
return ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
3296
3326
|
}
|
|
3297
3327
|
|
|
3298
3328
|
function renderFooterModelMenu() {
|
|
@@ -3309,7 +3339,9 @@
|
|
|
3309
3339
|
modelOptionsHtml.unshift("<option value='" + escapeHtml(currentValue) + "' selected>" + escapeHtml(label || "current model") + "</option>");
|
|
3310
3340
|
}
|
|
3311
3341
|
const thinking = piThinkingLevel || "off";
|
|
3312
|
-
const
|
|
3342
|
+
const thinkingLevels = getPiThinkingLevels();
|
|
3343
|
+
if (thinking && !thinkingLevels.includes(thinking)) thinkingLevels.push(thinking);
|
|
3344
|
+
const thinkingOptionsHtml = thinkingLevels.map((level) => {
|
|
3313
3345
|
return "<option value='" + escapeHtml(level) + "'" + (level === thinking ? " selected" : "") + ">Thinking: " + escapeHtml(level) + "</option>";
|
|
3314
3346
|
});
|
|
3315
3347
|
footerModelMenuEl.innerHTML = ""
|
|
@@ -8145,6 +8177,9 @@
|
|
|
8145
8177
|
critiqueViewEl.addEventListener("click", handleFilesPaneClick);
|
|
8146
8178
|
critiqueViewEl.addEventListener("click", handleGitChangesPaneClick);
|
|
8147
8179
|
critiqueViewEl.addEventListener("change", handleReplPaneChange);
|
|
8180
|
+
critiqueViewEl.addEventListener("change", (event) => {
|
|
8181
|
+
void handleFilesPaneChange(event);
|
|
8182
|
+
});
|
|
8148
8183
|
}
|
|
8149
8184
|
|
|
8150
8185
|
function replaceResponsePaneWithClone() {
|
|
@@ -9965,6 +10000,24 @@
|
|
|
9965
10000
|
return entry.extension ? entry.extension.replace(/^\./, "") : "file";
|
|
9966
10001
|
}
|
|
9967
10002
|
|
|
10003
|
+
function getFileBrowserSortOptions() {
|
|
10004
|
+
return [
|
|
10005
|
+
{ value: "name", label: "Sort: Name" },
|
|
10006
|
+
{ value: "mtime-desc", label: "Sort: Newest" },
|
|
10007
|
+
{ value: "mtime-asc", label: "Sort: Oldest" },
|
|
10008
|
+
{ value: "size-desc", label: "Sort: Largest" },
|
|
10009
|
+
{ value: "size-asc", label: "Sort: Smallest" },
|
|
10010
|
+
];
|
|
10011
|
+
}
|
|
10012
|
+
|
|
10013
|
+
function buildFileBrowserSortSelectHtml() {
|
|
10014
|
+
const currentSort = normalizeFileBrowserSortMode(fileBrowserSortMode || (fileBrowserState && fileBrowserState.sort));
|
|
10015
|
+
const options = getFileBrowserSortOptions().map((option) => {
|
|
10016
|
+
return "<option value='" + escapeHtml(option.value) + "'" + (option.value === currentSort ? " selected" : "") + ">" + escapeHtml(option.label) + "</option>";
|
|
10017
|
+
}).join("");
|
|
10018
|
+
return "<select class='files-sort-select' data-files-sort aria-label='Files sort order' title='Sort file browser entries. Folders remain grouped first.'>" + options + "</select>";
|
|
10019
|
+
}
|
|
10020
|
+
|
|
9968
10021
|
function buildFileBrowserPanelHtml() {
|
|
9969
10022
|
const state = fileBrowserState || {};
|
|
9970
10023
|
const entries = Array.isArray(state.entries) ? state.entries : [];
|
|
@@ -10019,6 +10072,7 @@
|
|
|
10019
10072
|
+ "<div class='files-toolbar'>"
|
|
10020
10073
|
+ "<div class='files-path-group'><span class='files-label'>Files</span><span class='files-path' title='" + escapeHtml(currentDir) + "'>" + escapeHtml(relativeDir || ".") + "</span></div>"
|
|
10021
10074
|
+ "<div class='files-toolbar-actions'>"
|
|
10075
|
+
+ buildFileBrowserSortSelectHtml()
|
|
10022
10076
|
+ "<button type='button' data-files-action='parent'" + parentDisabled + ">Parent</button>"
|
|
10023
10077
|
+ "<button type='button' data-files-action='refresh'>Refresh</button>"
|
|
10024
10078
|
+ (currentDir ? "<button type='button' data-files-action='copy-current' data-files-path='" + escapeHtml(currentDir) + "'>Copy path</button>" : "")
|
|
@@ -10045,6 +10099,7 @@
|
|
|
10045
10099
|
entries: [],
|
|
10046
10100
|
omitted: 0,
|
|
10047
10101
|
omittedIgnored: 0,
|
|
10102
|
+
sort: fileBrowserSortMode,
|
|
10048
10103
|
loading: false,
|
|
10049
10104
|
error: "",
|
|
10050
10105
|
loaded: false,
|
|
@@ -10079,8 +10134,10 @@
|
|
|
10079
10134
|
if (dir) query.dir = String(dir);
|
|
10080
10135
|
if (context.sourcePath) query.sourcePath = context.sourcePath;
|
|
10081
10136
|
if (context.resourceDir) query.resourceDir = context.resourceDir;
|
|
10137
|
+
query.sort = normalizeFileBrowserSortMode(fileBrowserSortMode);
|
|
10082
10138
|
const payload = await fetchStudioJson("/file-browser", { query });
|
|
10083
10139
|
if (nonce !== fileBrowserLoadNonce) return;
|
|
10140
|
+
fileBrowserSortMode = normalizeFileBrowserSortMode(payload.sort || fileBrowserSortMode);
|
|
10084
10141
|
fileBrowserState = {
|
|
10085
10142
|
rootDir: typeof payload.rootDir === "string" ? payload.rootDir : "",
|
|
10086
10143
|
currentDir: typeof payload.currentDir === "string" ? payload.currentDir : "",
|
|
@@ -10089,6 +10146,7 @@
|
|
|
10089
10146
|
entries: Array.isArray(payload.entries) ? payload.entries : [],
|
|
10090
10147
|
omitted: Number(payload.omitted) || 0,
|
|
10091
10148
|
omittedIgnored: Number(payload.omittedIgnored) || 0,
|
|
10149
|
+
sort: normalizeFileBrowserSortMode(payload.sort || fileBrowserSortMode),
|
|
10092
10150
|
loading: false,
|
|
10093
10151
|
error: "",
|
|
10094
10152
|
loaded: true,
|
|
@@ -10191,6 +10249,17 @@
|
|
|
10191
10249
|
setStatus(payload && payload.message ? payload.message : "Opened folder in file manager.", "success");
|
|
10192
10250
|
}
|
|
10193
10251
|
|
|
10252
|
+
async function handleFilesPaneChange(event) {
|
|
10253
|
+
if (rightView !== "files") return;
|
|
10254
|
+
const target = event.target;
|
|
10255
|
+
const sortSelect = target instanceof Element ? target.closest("[data-files-sort]") : null;
|
|
10256
|
+
if (!sortSelect || !("value" in sortSelect)) return;
|
|
10257
|
+
const nextSort = writeFileBrowserSortMode(sortSelect.value);
|
|
10258
|
+
if (nextSort === fileBrowserSortMode && fileBrowserState.loaded && !fileBrowserState.loading) return;
|
|
10259
|
+
fileBrowserSortMode = nextSort;
|
|
10260
|
+
await loadFileBrowserDirectory(fileBrowserState.currentDir || "", { user: true });
|
|
10261
|
+
}
|
|
10262
|
+
|
|
10194
10263
|
async function handleFilesPaneClick(event) {
|
|
10195
10264
|
if (rightView !== "files") return;
|
|
10196
10265
|
const target = event.target;
|
package/client/studio.css
CHANGED
|
@@ -3290,11 +3290,21 @@
|
|
|
3290
3290
|
}
|
|
3291
3291
|
|
|
3292
3292
|
.files-toolbar-actions button,
|
|
3293
|
-
.files-actions button
|
|
3293
|
+
.files-actions button,
|
|
3294
|
+
.files-sort-select {
|
|
3294
3295
|
padding: 4px 7px;
|
|
3295
3296
|
font-size: 11px;
|
|
3296
3297
|
}
|
|
3297
3298
|
|
|
3299
|
+
.files-sort-select {
|
|
3300
|
+
max-width: 150px;
|
|
3301
|
+
border: 1px solid var(--control-border);
|
|
3302
|
+
border-radius: 7px;
|
|
3303
|
+
background: var(--panel);
|
|
3304
|
+
color: var(--text);
|
|
3305
|
+
font-family: var(--font-ui);
|
|
3306
|
+
}
|
|
3307
|
+
|
|
3298
3308
|
.files-subtitle,
|
|
3299
3309
|
.files-notice,
|
|
3300
3310
|
.files-empty {
|
package/index.ts
CHANGED
|
@@ -44,6 +44,7 @@ type StudioReplRuntime = "shell" | "python" | "ipython" | "julia" | "r" | "ghci"
|
|
|
44
44
|
type StudioQuizAngle = "general" | "scientist" | "mathematician" | "statistician" | "developer" | "reviewer";
|
|
45
45
|
type StudioQuizScope = "selection" | "editor" | "file" | "folder" | "repo";
|
|
46
46
|
type StudioQuizThinking = "off" | "minimal" | "low" | "medium" | "high";
|
|
47
|
+
type StudioPiThinkingLevel = ModelThinkingLevel | "max";
|
|
47
48
|
|
|
48
49
|
const STUDIO_CSS_URL = new URL("./client/studio.css", import.meta.url);
|
|
49
50
|
const STUDIO_ANNOTATION_HELPERS_URL = new URL("./client/studio-annotation-helpers.js", import.meta.url);
|
|
@@ -358,7 +359,7 @@ interface PiModelSelectRequestMessage {
|
|
|
358
359
|
|
|
359
360
|
interface PiThinkingLevelRequestMessage {
|
|
360
361
|
type: "pi_thinking_level_request";
|
|
361
|
-
level:
|
|
362
|
+
level: StudioPiThinkingLevel;
|
|
362
363
|
}
|
|
363
364
|
|
|
364
365
|
interface PiThemeSelectRequestMessage {
|
|
@@ -2752,6 +2753,7 @@ const STUDIO_FILE_BROWSER_IGNORED_DIRS = new Set([
|
|
|
2752
2753
|
]);
|
|
2753
2754
|
|
|
2754
2755
|
type StudioLocalPreviewResourceKind = "pdf" | "text" | "image" | "office" | "other";
|
|
2756
|
+
type StudioFileBrowserSortMode = "name" | "mtime-desc" | "mtime-asc" | "size-desc" | "size-asc";
|
|
2755
2757
|
|
|
2756
2758
|
interface StudioLocalPreviewResource {
|
|
2757
2759
|
filePath: string;
|
|
@@ -2773,6 +2775,29 @@ interface StudioFileBrowserEntry {
|
|
|
2773
2775
|
hidden: boolean;
|
|
2774
2776
|
}
|
|
2775
2777
|
|
|
2778
|
+
function normalizeStudioFileBrowserSortMode(sort: string | null | undefined): StudioFileBrowserSortMode {
|
|
2779
|
+
const value = typeof sort === "string" ? sort.trim().toLowerCase() : "";
|
|
2780
|
+
if (value === "mtime-desc" || value === "modified-desc" || value === "newest") return "mtime-desc";
|
|
2781
|
+
if (value === "mtime-asc" || value === "modified-asc" || value === "oldest") return "mtime-asc";
|
|
2782
|
+
if (value === "size-desc" || value === "largest") return "size-desc";
|
|
2783
|
+
if (value === "size-asc" || value === "smallest") return "size-asc";
|
|
2784
|
+
return "name";
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
function compareStudioFileBrowserEntryNames(a: StudioFileBrowserEntry, b: StudioFileBrowserEntry): number {
|
|
2788
|
+
return a.name.localeCompare(b.name, undefined, { sensitivity: "base", numeric: true });
|
|
2789
|
+
}
|
|
2790
|
+
|
|
2791
|
+
function compareStudioFileBrowserEntries(a: StudioFileBrowserEntry, b: StudioFileBrowserEntry, sort: StudioFileBrowserSortMode): number {
|
|
2792
|
+
if (a.type !== b.type) return a.type === "directory" ? -1 : 1;
|
|
2793
|
+
if (a.hidden !== b.hidden) return a.hidden ? 1 : -1;
|
|
2794
|
+
if (sort === "mtime-desc") return (b.mtimeMs - a.mtimeMs) || compareStudioFileBrowserEntryNames(a, b);
|
|
2795
|
+
if (sort === "mtime-asc") return (a.mtimeMs - b.mtimeMs) || compareStudioFileBrowserEntryNames(a, b);
|
|
2796
|
+
if (sort === "size-desc" && a.type === "file") return (b.size - a.size) || compareStudioFileBrowserEntryNames(a, b);
|
|
2797
|
+
if (sort === "size-asc" && a.type === "file") return (a.size - b.size) || compareStudioFileBrowserEntryNames(a, b);
|
|
2798
|
+
return compareStudioFileBrowserEntryNames(a, b);
|
|
2799
|
+
}
|
|
2800
|
+
|
|
2776
2801
|
function resolveStudioPdfResourcePath(pdfPath: string | undefined, sourcePath: string | undefined, resourceDir: string | undefined, fallbackCwd: string): string {
|
|
2777
2802
|
const rawPath = typeof pdfPath === "string" ? pdfPath.trim() : "";
|
|
2778
2803
|
if (!rawPath) throw new Error("Missing PDF path.");
|
|
@@ -2922,8 +2947,10 @@ function listStudioFileBrowserDirectory(
|
|
|
2922
2947
|
sourcePath: string | undefined,
|
|
2923
2948
|
resourceDir: string | undefined,
|
|
2924
2949
|
fallbackCwd: string,
|
|
2925
|
-
|
|
2950
|
+
sortMode?: string | null,
|
|
2951
|
+
): { rootDir: string; currentDir: string; relativeDir: string; parentDir: string | null; entries: StudioFileBrowserEntry[]; omitted: number; omittedIgnored: number; sort: StudioFileBrowserSortMode } {
|
|
2926
2952
|
const context = resolveStudioFileBrowserDirectory(dirPath, sourcePath, resourceDir, fallbackCwd);
|
|
2953
|
+
const sort = normalizeStudioFileBrowserSortMode(sortMode);
|
|
2927
2954
|
const entries: StudioFileBrowserEntry[] = [];
|
|
2928
2955
|
let omitted = 0;
|
|
2929
2956
|
let omittedIgnored = 0;
|
|
@@ -2962,14 +2989,10 @@ function listStudioFileBrowserDirectory(
|
|
|
2962
2989
|
omitted += 1;
|
|
2963
2990
|
}
|
|
2964
2991
|
}
|
|
2965
|
-
entries.sort((a, b) =>
|
|
2966
|
-
if (a.type !== b.type) return a.type === "directory" ? -1 : 1;
|
|
2967
|
-
if (a.hidden !== b.hidden) return a.hidden ? 1 : -1;
|
|
2968
|
-
return a.name.localeCompare(b.name, undefined, { sensitivity: "base", numeric: true });
|
|
2969
|
-
});
|
|
2992
|
+
entries.sort((a, b) => compareStudioFileBrowserEntries(a, b, sort));
|
|
2970
2993
|
const limitedEntries = entries.slice(0, STUDIO_FILE_BROWSER_MAX_ENTRIES);
|
|
2971
2994
|
omitted += Math.max(0, entries.length - limitedEntries.length);
|
|
2972
|
-
return { ...context, entries: limitedEntries, omitted, omittedIgnored };
|
|
2995
|
+
return { ...context, entries: limitedEntries, omitted, omittedIgnored, sort };
|
|
2973
2996
|
}
|
|
2974
2997
|
|
|
2975
2998
|
function resolveStudioHtmlPreviewResourcePath(
|
|
@@ -8423,7 +8446,7 @@ function parseIncomingMessage(data: RawData): IncomingStudioMessage | null {
|
|
|
8423
8446
|
|
|
8424
8447
|
if (msg.type === "pi_thinking_level_request" && typeof msg.level === "string") {
|
|
8425
8448
|
const level = msg.level.trim().toLowerCase();
|
|
8426
|
-
if (level === "off" || level === "minimal" || level === "low" || level === "medium" || level === "high" || level === "xhigh") {
|
|
8449
|
+
if (level === "off" || level === "minimal" || level === "low" || level === "medium" || level === "high" || level === "xhigh" || level === "max") {
|
|
8427
8450
|
return {
|
|
8428
8451
|
type: "pi_thinking_level_request",
|
|
8429
8452
|
level,
|
|
@@ -11054,17 +11077,17 @@ export default function (pi: ExtensionAPI) {
|
|
|
11054
11077
|
}
|
|
11055
11078
|
};
|
|
11056
11079
|
|
|
11057
|
-
const getThinkingLevelSafe = ():
|
|
11080
|
+
const getThinkingLevelSafe = (): StudioPiThinkingLevel | undefined => {
|
|
11058
11081
|
try {
|
|
11059
|
-
return pi.getThinkingLevel() as
|
|
11082
|
+
return pi.getThinkingLevel() as StudioPiThinkingLevel;
|
|
11060
11083
|
} catch {
|
|
11061
11084
|
return undefined;
|
|
11062
11085
|
}
|
|
11063
11086
|
};
|
|
11064
11087
|
|
|
11065
|
-
const setThinkingLevelSafe = (level:
|
|
11066
|
-
// Pi's CLI/model config support "off"
|
|
11067
|
-
(pi.setThinkingLevel as (nextLevel:
|
|
11088
|
+
const setThinkingLevelSafe = (level: StudioPiThinkingLevel) => {
|
|
11089
|
+
// Pi's CLI/model config support "off" and newer levels such as "max"; some extension API typings still expose a narrower reasoning-only type.
|
|
11090
|
+
(pi.setThinkingLevel as (nextLevel: StudioPiThinkingLevel) => void)(level);
|
|
11068
11091
|
};
|
|
11069
11092
|
|
|
11070
11093
|
const refreshRuntimeMetadata = (ctx?: { cwd?: string; model?: { provider?: string; id?: string; name?: string; reasoning?: boolean } | undefined }) => {
|
|
@@ -14150,6 +14173,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
14150
14173
|
requestUrl.searchParams.get("sourcePath") ?? undefined,
|
|
14151
14174
|
requestUrl.searchParams.get("resourceDir") ?? undefined,
|
|
14152
14175
|
studioCwd,
|
|
14176
|
+
requestUrl.searchParams.get("sort") ?? undefined,
|
|
14153
14177
|
);
|
|
14154
14178
|
respondJson(res, 200, { ok: true, ...listing, entries: method === "HEAD" ? [] : listing.entries });
|
|
14155
14179
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-studio",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.36",
|
|
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",
|