Releases: petronijus/waveterm
Release list
v0.14.5-pj.26
Fixed
Windows you closed no longer come back on every start.
window:restoreallwindows was consulted in the window close handler, where it made every close a no-op against the database: the window stayed in client.windowids forever and was reopened on the next launch. Closing it again changed nothing, so stray windows accumulated permanently — a window created by an accidental second launch would reappear on every start for weeks.
The setting was redundant there. Quitting already preserves every open window regardless of it, so it now applies where its name promises: at restore time. When false, only the primary window is restored and the rest are dropped from the restore set — keeping their workspaces, so switching the preference never destroys tabs.
Behaviour now:
- close a window → it is forgotten
- quit with two windows → both come back
window:restoreallwindows: false→ only the primary window is restored
Also fixes package-lock.json, which had been committed with unresolved merge conflict markers and was invalid JSON.
v0.14.5-pj.25 — undo close tab
Undo close tab
Closing a tab used to drop the tab, its blocks and its layout straight out of SQLite — a mis-click was unrecoverable. Now it isn't.
Cmd/Ctrl+Shift+Treopens the tab you closed last, at the index it was closed from, with its layout tree and its terminal scrollback intact.- Right-click any tab → Reopen Closed Tab to pick from the recently closed ones by name.
- The trash keeps the last 10 closed tabs per workspace for 7 days; eviction is what finally releases the blockfiles.
Processes are not resurrected — the block controllers still stop on close — but a reopened terminal starts in the same directory, and the fork's per-block Claude session id comes back with the block, so claude --resume still works.
Based on upstream 0.14.5.
Wave (petronijus fork) v0.14.5-pj.24 — Electron 44
Electron 44 (Chromium 152 / Node 24)
Electron 41 reached end-of-life on 2026-08-25 (upstream Wave is still on it). This release moves the fork to Electron 44.2.0.
- Chromium 152 carries the
graphite-insert-errorcrash key, which names the exact Metal failure behind the macOS 27 GPU-process crash that pj.23 worked around withwindow:disablegraphite(the workaround stays; the crash itself is not fixed by the bump). - macOS 13 (Ventura) is now the minimum — Electron 44 dropped macOS 12. The DMG's
minimumSystemVersionwas raised to match. - macOS notifications now go through
UNUserNotificationCenter, which refuses to show them from an unsigned bundle. Release builds are signed, so nothing changes for installed apps; localtask devbuilds log afailedline inwaveapp.loginstead of silently showing nothing. - Toolchain that moved with it:
@types/node24,node-abi4.35,electron-builder26.15, Vite bundle targetschrome152/node24,tsconfiglibes2022.
Regression smoke suite (badges, background throttling, webview throttling, hard-wrap copy, main-process notifications) passes on the new runtime.
Full details: FORK.md.
v0.14.5-pj.23
GPU-process crash fallback (macOS)
Chromium's Skia Graphite raster backend (Metal via Dawn) terminates the whole GPU process with a CHECK in gpu::GraphiteSharedContext::InsertRecordingImpl when an async shader compile fails, instead of falling back to Ganesh. Every WebGL context — so every terminal — goes with it. Reproduced twice on macOS 27 beta 6 (M3 Pro) with Electron 41 / Chromium 146; the same CHECK is still present through Chromium 152 (Electron 44).
- New opt-in launch setting
window:disablegraphitepasses--disable-features=SkiaGraphite. Hardware acceleration stays on (Ganesh on ANGLE/Metal), unlikewindow:disablehardwareacceleration. Requires an app restart. - The main process now logs every non-clean child-process exit (
[child-process-gone] type=GPU …) towaveapp.log, so a GPU crash has a matching line next to the OS.ipsreport.
macOS-only release (arm64 + x64, signed + notarized). Windows and Linux stay on pj.22 for now.
v0.14.5-pj.22
Fixed
-
Linux dock icon — the app window is once again matched to its
waveterm.desktopentry, so it shows the Wave icon instead of a blank one next to the launcher.Electron derives
CHROME_DESKTOPfrom the app name (Wave), and Chromium names both the systemd scope it relocates itself into and its XDG app id after it. GNOME resolves a window's desktop entry from that scope, so it looked forwave.desktop, found nothing, and left the window unmatched. Regressed with the Electron 41.1.0 → 41.10.3 bump in pj.20.
v0.14.5-pj.21 — upstream PR ports, inline images, git branch UI
Fork build on upstream base 0.14.5.
Git view
- The branch field in the git toolbar was capped at 40% of the toolbar width and ellipsised long
branch names even with free space next to it — it now sizes to its content and only shrinks
when the toolbar actually runs out of room (full name in the tooltip). - The branch switcher bolds the checked-out branch instead of only marking it with a check.
Ported upstream PRs
Upstream's main has not moved since 2026-07-29 and ~40 community PRs sit open. These were
cherry-picked in, each keeping its original author:
- wavetermdev#3406 —
Ctrl+[ \ ] /send their ASCII control codes on non-US keyboard layouts. Reworked
from the upstream patch, which derived a byte for anyCtrl+charviacharCode & 0x1f
(Ctrl+1 → DC1) and routed every Ctrl+letter around xterm's own encoding. - wavetermdev#3421 — SSH agent forwarding (
ForwardAgent/ssh:forwardagent), dialing the agent per
channel so forwarding survives an agent restart (1Password relock). - wavetermdev#3480 — configurable keybindings via
keybindings.json, editable in the config view. - wavetermdev#3484 — auto-attach a tmux session on remote blocks (
term:tmux:session) plus list/switch
from the remote block's context menu. - wavetermdev#3479 — Excalidraw diagram widget (
view: "excalidraw",wsh excalidraw). - wavetermdev#3443 — file/document bookmarks:
filebookmarks.json, star dropdown in the preview
toolbar, edit modal, and document-position restore for markdown/code views. - wavetermdev#3407 —
window:restoreallwindows: every window is restored on next launch, not just the
last one (default on). - wavetermdev#3440 —
preview:openfileinnewblock: Enter / double-click in the directory preview opens
the file in a new block (default off). - wavetermdev#3429 — a block losing focus no longer re-grabs it (two web blocks could flap forever).
- wavetermdev#3413 — web blocks respect the system color scheme.
- wavetermdev#3467 — Electron 41.1.0 → 41.10.3.
Note on inline terminal images
Sixel and iTerm2 inline images have rendered since pj.5, but nothing shows up unless something
emits them — install a producer (brew install chafa libsixel timg) and use chafa -f sixel.
chafa -f iterm2 sends TIFF inside the IIP envelope, which the browser cannot decode.
macOS builds are signed with a Developer ID certificate. Auto-update works from pj.11 onward.
v0.14.5-pj.20 — hard-wrap aware terminal copy & links
Fixes the most annoying terminal papercut: text copied from TUI programs (Claude Code, tmux, less, …) came out shredded into terminal-width lines, and URLs split across those lines weren't clickable.
Hard-wrap aware copy & links
TUI programs re-wrap their output themselves and print real newlines at the terminal width. xterm only bridges its own soft wraps, so those hard breaks survived into the clipboard and cut URLs in half.
- Links — the link detector now follows a URL across hard wraps: a line that runs right through its last column joins the next one. A URL Claude Code split over two lines is clickable again (Cmd/Ctrl+click), and the hover tooltip shows the full address.
- Copy — every copy path (Cmd+C, Ctrl+Shift+C, copy-on-select, context menu) re-joins lines hard-wrapped at the terminal width, so URLs and paragraphs paste as one line. Word-wrapped prose and short lines are untouched.
term:copyunwrapsetting (defaulttrue) gates the copy join; the terminal context menu gains Copy Raw as an exact-selection escape hatch.
Verification
Covered by new unit tests (link computer + copy pipeline) and a new copy-unwrap regression smoke check that writes a hard-wrapped URL into a live terminal buffer and asserts it copies as one line.
Artifacts: macOS (arm64 + x64, signed & notarized) attached; Windows and Linux builds will be added later.
v0.14.5-pj.19 — reconnect UX overhaul + claude session resume fix
Reconnect UX overhaul — backported from whoisjeremylam/waveterm-remote (Round 4), plus a Claude session-resume fix and an upstream refresh.
Remote sessions survive sleep and network flaps
The big one. Closing the lid on an SSH session used to freeze the remote process — it blocked inside a write() syscall until TCP recovered or the server-side keepalive timed out, which can be hours. A 5s send timeout now breaks that backpressure chain, so the freeze is bounded to ~5 seconds. Terminal output produced while you were disconnected is buffered to disk instead of being discarded past the 2 MB in-memory window, and is replayed on reconnect.
Reconnect that explains itself
- Reconnect triggered by tab switch and app focus, for all view types
- Overlay hysteresis so brief blips no longer flash a disconnect banner; flap-stable chrome
- "Gave up" overlay with a stop-retry button, plus an attention heartbeat
- Sticky suppress after an explicit Disconnect / Stop / password cancel — auto paths stay quiet until you reconnect
- Permanent failures (host key changed, auth rejected) stop retrying instead of hammering
- Per-connection retry jitter; scheduler bounds tuned, early terminate on auth-failed / connection-refused
Password prompts
- Serialized per window — one prompt at a time instead of a pile
- Cached password survives network flaps and involuntary disconnects; cleared only when the server actually rejects credentials
- "Incorrect password — please try again." instead of a silent re-prompt
- Cold-start prompt appears immediately for password-auth hosts (previously misclassified as silently reconnectable)
- Passphrase icons, auth-queue waiting state, accessibility support
Claude session resume fixed
The terminal's Resume session button handed back the wrong conversation after Wave restarted. The session watch was armed only from the shell-integration command marker, so a durable claude that outlived the wavesrv which saw it start kept whatever session id it held before the restart. A claude discovered by process probing (or reported via wsh agentstate) now reconciles the recorded id against the live process through Claude's own pid registry. An explicit claude --resume <id> also used to bind and then stop watching, so switching sessions from inside claude was never picked up — it now keeps following.
Fixes
- Terminal rendering restored after sleep/resume (xterm.js
_isPausedreset) - Linux/Windows resume parity
- Term-file corruption on stream supersession and sequence gaps
- Output-loop goroutine leak when a stream reader was superseded on reconnect
- Background terminal sessions now receive resize events
- ESC key and trailing-space trim on native copy
- SSH agent unavailability surfaced after sleep; port-forward bind errors surfaced on reconnect
Upstream
Merged wavetermdev/waveterm up to a4447c15: wsh tab list / wsh tab move, wsh deleteblock accepting a positional block ref, and dependency bumps including golang.org/x/net, grpc and tar.
Supersedes v0.14.5-pj.18, which shipped without macOS artifacts.
Full backport ledger — what was taken, what was deliberately dropped and why — is in BACKPORT.md.
v0.14.5-pj.18 — reconnect UX overhaul
Reconnect UX overhaul — backported from whoisjeremylam/waveterm-remote (Round 4), plus an upstream refresh.
Remote sessions survive sleep and network flaps
The big one. Closing the lid on an SSH session used to freeze the remote process — it blocked inside a write() syscall until TCP recovered or the server-side keepalive timed out, which can be hours. A 5s send timeout now breaks that backpressure chain, so the freeze is bounded to ~5 seconds. Terminal output produced while you were disconnected is buffered to disk instead of being discarded past the 2 MB in-memory window, and is replayed on reconnect.
Reconnect that explains itself
- Reconnect triggered by tab switch and app focus, for all view types
- Overlay hysteresis so brief blips no longer flash a disconnect banner; flap-stable chrome
- "Gave up" overlay with a stop-retry button, plus an attention heartbeat
- Sticky suppress after an explicit Disconnect / Stop / password cancel — auto paths stay quiet until you reconnect
- Permanent failures (host key changed, auth rejected) stop retrying instead of hammering
- Per-connection retry jitter; scheduler bounds tuned, early terminate on auth-failed / connection-refused
Password prompts
- Serialized per window — one prompt at a time instead of a pile
- Cached password survives network flaps and involuntary disconnects; cleared only when the server actually rejects credentials
- "Incorrect password — please try again." instead of a silent re-prompt
- Cold-start prompt appears immediately for password-auth hosts (previously misclassified as silently reconnectable)
- Passphrase icons, auth-queue waiting state, accessibility support
Fixes
- Terminal rendering restored after sleep/resume (xterm.js
_isPausedreset) - Linux/Windows resume parity
- Term-file corruption on stream supersession and sequence gaps
- Output-loop goroutine leak when a stream reader was superseded on reconnect
- Background terminal sessions now receive resize events
- ESC key and trailing-space trim on native copy
- SSH agent unavailability surfaced after sleep; port-forward bind errors surfaced on reconnect
Upstream
Merged wavetermdev/waveterm up to a4447c15: wsh tab list / wsh tab move, wsh deleteblock accepting a positional block ref, and dependency bumps including golang.org/x/net, grpc and tar.
Full backport ledger — what was taken, what was deliberately dropped and why — is in BACKPORT.md.
v0.14.5-pj.17 — grey window fix
Fixes the grey window
A tab could lose its rendered frame and show nothing but the dark background until you
switched tabs — most often after the window had been minimized, moved to another workspace,
covered by a fullscreen window, or left alone through a screen blank / lock.
Cause. The fork constructs tab views with backgroundThrottling: false, which sets
Electron's disable_hidden flag on the render widget. That flag turns
RenderWidgetHost::WasHidden() into a no-op, so Chromium never recorded the widget as hidden
when the compositor unmapped the window — while the browser side still evicted the compositor
surface. On the way back, WasShown() early-returned without asking the renderer for a new
frame. Switching tabs was the only thing that helped, because it is the one path that changes
a view's bounds and thereby forces a repaint.
Fix.
- Background throttling is enabled for real as soon as a tab is on screen. It is only needed
off while the detached hot-spare renderer boots, and Chromium throttles hidden pages only,
so a visible tab is unaffected. - Window
show/restore, andpowerMonitorunlock-screen/resume, force a repaint
through a hide/show cycle as a backstop — no bounds change, so nothing reflows and no
terminal is resized. - The regression smoke suite gained a
repaint-guardcheck (verified to fail against the
unfixed code).
Also: the smoke suite's background mode now parks its window correctly on Linux — it looked
for BrowserWindow where Wave uses BaseWindow, and the failure was swallowed.