Repository navigation
Releases
Morse v0.27.2
🔧 Improvements
- Panels announce the correct build version in the handshake
📝 Contributors
Full Changelog: v0.27.1...v0.27.2
Morse v0.27.1
npm i -g @supanadit/morse-web works again, copying in VS Code 1.143 keeps what you selected, and the usage
panel speaks OpenCode as fluently as it speaks pi.
New
- The usage panel fills in for OpenCode sessions. The Messages / User / Assistant / Tool calls columns and
the speed figures were only ever fed by the pi adapter, so an OpenCode session showed a column of em dashes.
One walk of the stored message list now feeds the whole panel — and because OpenCode timestamps each of its
messages itself, the average, peak and slowest generation speeds come straight from its own clock, with no
host-side stopwatch needed.
Fixed
- Installing or updating
@supanadit/morse-webno longer fails with a 404. The published package listed
two internal library names as install-time dependencies, and those are never published to the npm registry —
sonpm i -g @supanadit/morse-webstopped partway withThe requested resource '@morse/agent@*' could not be found, andmorse updatefailed the same way. The libraries were always packed inside the package
itself; the install instructions that pointed at the registry are gone. A new regression workflow packs the
artifact and installs it into a clean directory on every change, so an install that a user cannot complete
fails CI before it can ship. (reported as #3) - Ctrl+C and Copy in VS Code 1.143 keep the transcript selection. VS Code 1.143 restores focus to the
webview's last focused element right before a clipboard command; when that element is the composer, taking
focus back collapses the selection, so both shortcuts copied nothing. The focus restore is now given no
composer to land on while a copy runs. Upstream fixed it in VS Code 1.144; this keeps 1.143 usable.
Morse v0.27.0
🚀 New Features
- OpenCode joins Morse as a full engine — pick one per session
- MCP panel manages OpenCode's servers, never mixing the two engines' lists
- Prompt editor edits OpenCode commands, from markdown files and opencode.json
- Live markdown preview while you type in the composer
- Maximize the composer and drag-resize it to fit long prompts
- Model picker redesigned; engine, mode and thinking level picked per draft
- New search panel finds text across your project's files
- Watch a subagent's session live, its transcript updating as it works
- Ask-form questions arrive one at a time with compact choice rows
- Session pins and prompt templates keep their column layout
🐛 Bug Fixes
- A running session no longer drops out of its project's list
- Subagent tool rows link to the right child and no longer cover the transcript
- OpenCode failures, context usage and modes show instead of vanishing
- The caret renders on an empty line after a trailing newline
- Restoring a session shows a clear loading state instead of a bare panel
🔧 Improvements
- No more flashing console windows on Windows while Morse runs pi
- The composer status line shows engine, mode and context usage
📝 Contributors
Full Changelog: v0.26.1...v0.27.0
Morse v0.26.1
Full Changelog: v0.26.0...v0.26.1
Morse v0.26.0
The usage panel says what the cache saved and how fast the model answered, and Morse finds pi however it was
installed.
New
- Cache split and generation speed in the usage panel. The session totals now answer four questions they
could not before: how many prompt tokens the cache served versus missed, and how fast the model actually
generated — average, peak and slowest. Cached reads pi'scacheReadTokensand Miss itsinputTokens(pi's
promptTokens = input + cacheRead + cacheWrite, soinputis exactly the part the cache did not cover).
Speed is different: pi keeps no clock, so the host times each assistant message (message_start→
message_end) and persists the totals per session, so a resumed session continues its history instead of
starting from zero. A message under 25 output tokens is refused — at that size the span measures request
latency, not speed — and all three figures share one counted set, so the average can never sit outside the
range the extremes show.
Fixed
- Fixed the "Morse could not read the built-in slash commands" warning, and the missing builtins behind it,
for most ways of installing pi. Morse read the pi package by walking up from thepibinary, which only
works whenpiis a symlink intonode_modules— true of exactly one install method. A managed install
(curl pi.dev/install.sh, the PowerShellinstall.ps1) has no manifest anywhere above its launcher; pnpm
writes a copied shell shim into its store; Windows.cmd/.ps1shims are scripts outside the package; and
bun on Windows writes a compiled.exebeside a.bunxsidecar. The package is now resolved through whichever
of those shapes is present — the launcher's installer marker, thenode_modulespath named inside a shim, or
the sidecar's target — so the palette gets its builtins and the "unreadable install" banner is gone. The
"a newer pi is out" notice is restored with it, since the version reads the same way. - Fixed the usage panel sitting on stale numbers until a run ended. Every figure came from a single pull
that only ran at attach, compaction and settle, so during a run the panel showed attach-time totals — exactly
when the reader wanted to watch the context grow. It now re-reads per completed message, and the in-flight
response's cumulative usage is shown as it streams (guarded so a provider that reports zeros mid-message
cannot wipe the panel, and so the same figure is not rebroadcast per token).
Morse v0.25.0
Every project keeps its place in the sidebar, and a hidden shell keeps running.
New
- Every project in the sidebar. The session list sorted all projects' sessions together and kept only the
newest 50, so a busy project could crowd every other one out entirely — a project is derived from its
sessions, so one whose newest session fell outside that slice vanished from the sidebar and the filter. The
cap is now per project, so every project is always represented, with a Load more row to page in the rest
and true session counts per project.morse.sessions.perProject/MORSE_SESSIONS_PER_PROJECTsets the page
size (default 10). - The palette searches every stored session. Its Sessions rows came from the sidebar's first page per
project, so a session beyond those pages could not be found. The search now runs on the host — one cold read
warms a cache every later search scans in memory — and the palette merges the remote matches with the pages
it already holds, dropping a late answer for a query the reader has moved past.
Fixed
- A terminal keeps its shell across a tab switch. A running terminal in a session the reader left reset to
a fresh shell. Two independent defects did it: the bottom panel unmounted its tool when a session switch made
the panel's per-session viewundefined, taking every session'sTerminalwith it; and a repeat
terminal/openon the same connection was treated as a close, the one call that ends a shell and drops its
scrollback. The panel now keeps the last tool it mounted, and a remount reattaches to the live shell and
replays what that viewer missed. - A closed terminal takes its whole job with it.
terminal/close, closing the tab or session, and
morse stopleft a dev server the reader had launched —pnpm start:dev, a watcher — running: node-pty
signals only the shell's own pid, so the job reparented to init and kept its port, and the oldSIGKILL
fallback targeted that same, already-dead pid. The process table is now read and the shell, every descendant
and each of their process groups are signalled — a gracefulSIGHUPfirst so a server still prints its
shutdown log, then aSIGKILLpass that re-reads the table by pty session and catches children that
reparented while the shell died. Shutdown force-kills synchronously, since the scheduled fallback timer is
unref'd and would not fire before the process exits. - The git panel follows a project switch. It keyed its repository state by the relative
path, which is
''for the session's own repository in every project, so switching to a session in another directory
reused the previous project's stale name, branch and root while only the history refreshed — the panel read
one project's name over another's session until the first message forced a reopen. State is now keyed by the
absolute root and the relative path. - An untouched draft tab survives a session pick. Focusing another session removed a "New session" tab
nobody had typed into, treating the reader's own tab as noise. It stays until the reader closes it. - A draft tab re-targets the host across projects. Selecting a draft only sent
session/newwhen the host
was on a real session, so clicking one project's draft while the host sat on another's left both showing the
second project's workspace. The message now goes whenever the clicked draft's project differs from the host's
current workspace.
Morse v0.24.0
The browser host updates itself in one click, and every list is now one tree.
New
- Update the browser host without leaving it. The footer's "Update available" notice is a button: it asks
the host to install the latest release and relaunch, and the page reloads on the new build — no terminal, no
re-running a command. It is off unless the host was started withMORSE_SELF_UPDATE=1, and the install never
runs in the process it replaces: a detached helper waits for the old daemon to exit, installs, and starts it
again. Refusals (not opted in, a caller that is not on loopback, an install that is not a writable
npm-global) answer with a reason and the notice falls back to the command it already printed.morse update
does the same from a terminal, andmorse startnow remembers its port so a restart lands on the same URL. - A session chimes when its run finishes. The completion notice only ever spoke visually, and a reader who
stepped away from the panel — the case it exists for — had nothing to hear. A synthesized two-note chime now
follows the same away/always policy as the toast, with its own mute switch. The palette gains "Mute/Play a
sound…" and "Send a test notification", the latter firing on demand so the channel can be checked without
waiting for a run. - Every repository under a project is in the git panel. A project can hold more than one repository — its
own plus a nested submodule or checkout — and the panel only ever saw the one the session sat in. It now
lists them all, each stage/commit/checkout/pull/push acting on the open repository, and the badges merge
every repository's status. Sections expand in place, one at a time, the way VS Code's Source Control lists
them. - The Explorer and the session list share one tree. They were the same list drawn twice and had begun to
drift. One component now renders both; the session list also nests a forked session under the session it
was forked from. - The prompt-template editor has a toolbar button. It was wired but reachable only by keyboard shortcut and
the palette, so on the web it looked missing next to MCP and Git. It now sits beside them, lit while its tab
is in front. - A session in front comes back across a window reopen. The VS Code host advertised no workbench
capability, so a reopened window started on an empty draft. It now saves and restores the session in front,
the same behaviour the browser already had. - Prompt-template argument fields grow to fit. They were single-line, so a pasted stack trace or paragraph
hid all but the first line. Every field is now an auto-growing textarea — one row tall at first, growing to
a cap before it scrolls — with Enter inserting a newline and Ctrl/Cmd+Enter sending. - The annotation editor splits into Write and Preview tabs. The old overlay drew a live mirror of the
markdown under a transparent textarea, and the two layers would not stay on one character grid — the prose
slid out from under the caret. Source and rendering are now two surfaces, each with the whole box, and the
caret and draft survive the round trip.
Fixed
- Stop asks before it ends a run. It sat beside Steer and Follow up, so a stray press killed the run
outright. It now confirms, like compaction, and the question retracts itself when the run it is about ends. - Compaction acts on the session its dialog was opened over.
session/compactnamed no session, so a
dialog opened on one conversation and a switch in between silently rewrote another's memory. The message
now carries the pinned session, and a confirm against a closed session fails loudly instead of compacting
the wrong conversation. - The composer holds a prompt while the model and thinking levels settle. Switching models could send a
prompt against the previous model's reasoning level, and a fast Enter could reach the agent before the model
pick did. The mutating messages are now ordered, and Send stays disabled until the new levels are read. - A prompt sent with a picked model no longer carries the previous model's level. While a model's levels
load, the picker reports thinking off and no options, instead of showing the stale list. - pi is found and started on Windows. Detection read only the extensions in
PATHEXT, which a window
opened from the Start Menu rarely inherits and which omits.ps1on purpose — and a foundpi.cmdstill
failed to launch, becauseCreateProcesscannot start a batch file. Resolution now returns a spawn plan:
.exe/.comrun directly,.cmd/.batthrough a shell, a lone.ps1through PowerShell. - Morse activates when you grant trust. A first-time window opens untrusted, so the extension stayed
disabled in Restricted Mode and the panel came up blank until a manual reload. It now declares its untrusted
behaviour and starts when trust is granted. - A session's editor tab closes when the session does. Closing or deleting a session from the sidebar used
to leave its tab behind, and a tab whose session was deleted while the window was closed came back pinned to
a conversation that no longer exists. - The status bar stops counting tabs a host cannot close. In VS Code the editor's own tabs are the strip, so
the sidebar's tab count listed conversations that were not open and could not be closed by hand. The count is
hidden where there is no Morse tab strip, and the strip reconciles against the host's session list. - The browser host's caches are bounded. Three structures grew for the host's whole lifetime: the
workspace index kept a listing for every project ever browsed (now an 8-entry LRU), and an LSP client kept
every document ever opened and its diagnostics (now a 256-entry LRU that closes evicted files). A diagnostics
wait also now ends when the server dies, instead of leaving the preview spinning until its timeout. - A retired session frees its transcript. A session the registry evicted on its own left its whole
conversation and tool index in the transcript store for the host's lifetime. Eviction, close and delete now
all release it. - The model chooser and the thinking panel no longer overlap. Opening the chooser left the thinking panel
up, and the two dropdowns stacked. They now share one positioning context and close each other. - The palette's key hints stay readable at every width. The hint bar stacked only below 520px, but the card
is already too narrow for one row well before that, so the source prefixes between 520px and 672px were
ellipsised away. The breakpoint now tracks the card. - A deep tree stays readable. Each level cost two columns, so a folder five deep was a wall of bars. A level
is now one guide line, with the tree pulled left and the caret, gutter and row padding brought in with it. - A nested row steps in past its parent's corner. A child drew its corner in its parent's column, so the two
rows read as one label rather than a parent and its child. - The New session blurb is spaced from its search field. The projects screen dropped the sub-heading
straight onto the input. - The redundant Attach Selection button is gone from the toolbar. The composer already offered it; the
command stays in the palette for keyboard use.
Improved
morse startreuses the workspace and port it had before. A restart — including the one the self-update
runs — comes back on the same URL, so the browser tab that is reloading finds it there. A remembered port
taken while Morse was down falls back to a free one instead of refusing to start.
Morse v0.23.0
A pinned range can carry your own note, and the Explorer finds a file by typing.
New
- Annotate a pinned range with your own words. Every pinned range — a chip in the composer, a band in
the file preview, a change row in either diff layout, or a chip in the transcript — now carries a ✎ that
opens a comment box. The note is written with a formatting toolbar and shortcuts, rendered in place as you
type, saved as Markdown, and read back as a formatted card on hover. It rides the wire with its pin as one
mention, so the note can never be read as your own prose. - Find a file in the Explorer without opening folders. The sidebar Explorer has a filter box: a query
replaces the tree with a flat, ranked list of matching files, each row naming the folder it sits in, and the
title bar counts the matches (3 of 41) instead of claiming a smaller project. A name hit outranks a path
hit, soreadmeputsREADME.mdabovedocs/README.md. - A focused file previews as a whole-file chip. The chip used to appear only while a range was
highlighted; a file merely in front of the editor now shows the same chip — no line numbers, because
nothing is selected — and it locks into a whole-file pin when you click it.
Fixed
- The branch picker spans the panel. It hung off the branch chip and spilled past the panel's edge,
where the panel's own overflow clipped it — half the switcher was gone. It now pins under the pane's title
bar and spans the column. - A file added on disk reaches the Explorer a poll sooner. The decision to re-read the list used the
previous tick's working tree, so a new file waited one extra tick (4 s). The status is now read first, and
the list follows the tree in the same tick. - Dialogs and the palette fit a narrow window. The command palette's hints stack and centre below 520px,
and dialogs centre in the viewport with side padding instead of stretching to the full height.
Improved
- One toolbar, and no duplicate header. The chat header is gone: the tab strip, composer and status bar
carry what it said, the conversation's own buttons moved to the toolbar beside the MCP icon, and the
agent's lifecycle now lives there too. - One frame for every panel. The Explorer, git panel, sessions and the rest share one title bar, one fold
chevron, one resize handle and one dialog shell — the same panel looks the same wherever it sits. - The toolbar wraps instead of clipping. Below 759px the command centre drops to a second row, and the
navigation column becomes a full-height drawer that leaves a dismissable strip rather than sliding away.
Morse v0.22.0
A session gets its own editor tab, and the browser's preview gets a language server.
New
- A session opens as its own editor tab. A conversation could only be read inside the sidebar panel, which
is narrow and follows whatever session is in front. "Open in editor tab" now puts one session in an editor
tab beside any file, and running it again re-focuses the tab it already opened instead of making a second.
The tab is pinned to the conversation it names, so the sidebar switching sessions cannot pull the tab's next
prompt into another chat. - The browser host's preview reads code through a language server. Hover a symbol for its type, click a
name to follow its definition with a jump to the line, see errors and warnings underlined with a count in the
header and a problem list, and find every reference to a symbol in a panel. The server runs on the host's
machine, is kept warm per project and language, and is found fromMORSE_LSP_<KEY>, the project's own
node_modules/.bin, yourPATH, thennpx. A file whose language has no server says so, instead of
showing a clean zero. - pi's own TUI slash commands are in the palette.
/settings,/model,/reloadand the rest were
missing because pi's RPC lists only extension commands, prompt templates and skills. Morse now reads them
from the pi install the session runs, so api updateshows up on the next palette refresh. The ones Morse
can route —/model,/thinking,/new,/compact,/settings,/hotkeys,/quit— open the matching
surface, and the rest say they are pi's own instead of being sent as literal prompt text. - The thinking picker says so while it reads. pi scopes the levels to the current model, so a model pick
has to re-read them. The trigger now spins and the list showsReading this model's levels…, with the
previous model's rows still on screen but not selectable — they may name a level this model does not have.
A model the host has already probed applies in the same frame as the pick, with no wait at all.
Fixed
- The Explorer stays where you put it. The reveal ran on every file list, including the 4-second poll, so
the pane kept re-opening the active file's folders and scrolling back to it — a directory could not be
browsed without closing the file first. A file is now revealed only when it newly comes forward. - A code-split view no longer opens blank. The webview's policy trusted only scripts carrying a nonce, and
a lazily imported chunk carries none of them, so the request was blocked and the panel stayed empty. The
prompt editor was broken the same way. Trusting what the entry itself loads is what fixes it. - A folded sidebar no longer collapses an embedded surface. Inside a session tab the embedded column lost
to the persisted "sidebar collapsed" rule, so anyone who had ever folded the sidebar got a tab with no width.
Morse v0.21.0
A tool's task list is on screen, and the chrome extensions send arrives as clean text.
New
- A tool's task list shows up in Morse. pi's terminal draws a todo widget above the editor, but the RPC channel cannot carry it — so Morse rebuilds the list from the data the tool already returned. A tool result shaped like a task list draws a board inside its expanded row, and the session's newest one docks above the composer, hiding itself once there is no work left. Any extension returning that shape works with no Morse change and no plugin registry.
Fixed
- No more
[38;2;…mgarbage where status text should be. An extension that colors a widget line, footer status or notice with a theme color sends terminal escape codes, and the UI painted them literally. They are stripped at the boundary now — status, notices and widget lines render as the text you were meant to see, while any literal brackets a tool prints survive. - A pi crash now names its cause. When the agent died, the UI showed only "the pi agent stopped (code=1)" and the real error went to a host log that is off by default. The last lines pi wrote to stderr are attached to the failure, so the message itself says what went wrong.
- Running Morse from inside pi no longer hijacks the spawned session. Morse started from a pi session — or a shell pi exported into — inherited that session's identity, so every agent it launched tried to resume the wrong conversation. Those session variables are now dropped before a
piprocess is spawned, exactly as pi does for its own children.