pi-studio 0.5.38 → 0.5.39

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,15 @@ All notable changes to `pi-studio` are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.5.39] — 2026-03-30
8
+
9
+ ### Added
10
+ - Studio now supports the familiar `Cmd/Ctrl+S` shortcut for saving editor content.
11
+
12
+ ### Changed
13
+ - `Cmd/Ctrl+S` now triggers **Save editor** when a direct save path is available, and falls back to **Save editor as…** otherwise.
14
+ - Save button tooltips and the footer shortcut hint now advertise the save shortcut explicitly.
15
+
7
16
  ## [0.5.38] — 2026-03-29
8
17
 
9
18
  ### Added
@@ -878,6 +878,19 @@
878
878
  return true;
879
879
  }
880
880
 
881
+ function triggerEditorSaveShortcut() {
882
+ if (saveOverBtn && !saveOverBtn.disabled && !saveOverBtn.hidden) {
883
+ saveOverBtn.click();
884
+ return true;
885
+ }
886
+ if (saveAsBtn && !saveAsBtn.disabled && !saveAsBtn.hidden) {
887
+ saveAsBtn.click();
888
+ return true;
889
+ }
890
+ setStatus("Save is unavailable right now.", "warning");
891
+ return false;
892
+ }
893
+
881
894
  function handlePaneShortcut(event) {
882
895
  if (!event || event.defaultPrevented) return;
883
896
 
@@ -914,6 +927,18 @@
914
927
  return;
915
928
  }
916
929
 
930
+ const isSaveShortcut =
931
+ key.toLowerCase() === "s"
932
+ && (event.metaKey || event.ctrlKey)
933
+ && !event.altKey
934
+ && !event.shiftKey;
935
+
936
+ if (isSaveShortcut) {
937
+ event.preventDefault();
938
+ triggerEditorSaveShortcut();
939
+ return;
940
+ }
941
+
917
942
  if (plainEscape) {
918
943
  const activeKind = getAbortablePendingKind();
919
944
  if (activeKind === "direct" || activeKind === "critique") {
@@ -2525,11 +2550,11 @@
2525
2550
 
2526
2551
  var effectivePath = getEffectiveSavePath();
2527
2552
  if (effectivePath) {
2528
- saveOverBtn.title = "Overwrite file: " + effectivePath;
2553
+ saveOverBtn.title = "Overwrite file: " + effectivePath + " · Shortcut: Cmd/Ctrl+S.";
2529
2554
  return;
2530
2555
  }
2531
2556
 
2532
- saveOverBtn.title = "Save editor is available after opening a file, setting a working dir, or using Save editor as…";
2557
+ saveOverBtn.title = "Save editor is available after opening a file, setting a working dir, or using Save editor as…. Shortcut: Cmd/Ctrl+S falls back to Save editor as when needed.";
2533
2558
  }
2534
2559
 
2535
2560
  function syncActionButtons() {
package/index.ts CHANGED
@@ -5732,8 +5732,8 @@ ${cssVarsBlock}
5732
5732
  <header>
5733
5733
  <h1><span class="app-logo" aria-hidden="true">π</span> Studio <span class="app-subtitle">${appSubtitle}</span></h1>
5734
5734
  <div class="controls">
5735
- <button id="saveAsBtn" type="button" title="Save editor content to a new file path.">Save editor as…</button>
5736
- <button id="saveOverBtn" type="button" title="Overwrite current file with editor content." disabled>Save editor</button>
5735
+ <button id="saveAsBtn" type="button" title="Save editor content to a new file path. Cmd/Ctrl+S falls back here when no direct save path is available.">Save editor as…</button>
5736
+ <button id="saveOverBtn" type="button" title="Overwrite current file with editor content. Shortcut: Cmd/Ctrl+S.">Save editor</button>
5737
5737
  <label class="file-label" title="Load a local file into editor text.">Load file content<input id="fileInput" type="file" accept=".md,.markdown,.mdx,.qmd,.js,.mjs,.cjs,.jsx,.ts,.mts,.cts,.tsx,.py,.pyw,.sh,.bash,.zsh,.json,.jsonc,.json5,.rs,.c,.h,.cpp,.cxx,.cc,.hpp,.hxx,.jl,.f90,.f95,.f03,.f,.for,.r,.R,.m,.tex,.latex,.diff,.patch,.java,.go,.rb,.swift,.html,.htm,.css,.xml,.yaml,.yml,.toml,.lua,.txt,.rst,.adoc" /></label>
5738
5738
  <button id="loadGitDiffBtn" type="button" title="Load the current git diff from the Studio context into the editor.">Load git diff</button>
5739
5739
  <button id="getEditorBtn" type="button" title="Load the current terminal editor draft into Studio.">Load from pi editor</button>
@@ -5884,7 +5884,7 @@ ${cssVarsBlock}
5884
5884
  <footer>
5885
5885
  <span id="statusLine"><span id="statusSpinner" aria-hidden="true"> </span><span id="status">Booting studio…</span></span>
5886
5886
  <span id="footerMeta" class="footer-meta"><span id="footerMetaText" class="footer-meta-text">Model: ${initialModel} · Terminal: ${initialTerminal} · Context: unknown</span><button id="compactBtn" class="footer-compact-btn" type="button" title="Trigger pi context compaction now.">Compact</button></span>
5887
- <span class="shortcut-hint">Focus pane: F10 (or Cmd/Ctrl+Esc) to toggle · Run / queue steering: Cmd/Ctrl+Enter · Stop request: Esc</span>
5887
+ <span class="shortcut-hint">Focus pane: F10 (or Cmd/Ctrl+Esc) to toggle · Save editor: Cmd/Ctrl+S · Run / queue steering: Cmd/Ctrl+Enter · Stop request: Esc</span>
5888
5888
  </footer>
5889
5889
 
5890
5890
  <div id="scratchpadOverlay" class="scratchpad-overlay" hidden>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-studio",
3
- "version": "0.5.38",
3
+ "version": "0.5.39",
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",