Skip to content

release: v0.2.0 - #39

Merged
04mg merged 41 commits into
mainfrom
develop
Jul 21, 2026
Merged

release: v0.2.0#39
04mg merged 41 commits into
mainfrom
develop

Conversation

@04mg

@04mg 04mg commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

Release v0.2.0

Related Issue

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Refactor
  • Other

Testing

  • make build passes
  • make lint passes
  • make test passes
  • Manually tested in browser

Notes for Reviewer

04mg added 30 commits July 19, 2026 20:42
…appers

Load the sherpa-onnx WASM runtime from jsDelivr CDN at runtime instead
of importing a monolithic 20MB JS file from a HuggingFace Space. Vendor
the small JS glue files (sherpa-onnx-wasm-combined.js + sherpa-onnx-asr.js,
~163KB total) locally in public/wasm/. The ~13MB .wasm binary loads from
jsDelivr and is cached by the browser after first use.

- Remove KROKO_SDK_URL and the dynamic import() of kroko-sdk.js
- Add loadSherpaOnnx() that loads vendored Emscripten loader + ASR wrapper
- Rewrite createKrokoRecognizer() to write model blobs to Emscripten FS
  and use the standard sherpa-onnx createOnlineRecognizer() API
- Rename loadKrokoSdk to loadSherpaOnnx in useKrokoVoiceMode.ts
The vendored sherpa-onnx-asr.js has a namespace shim that expects
window.SherpaOnnx to exist (normally provided by sherpa-onnx-core.js).
Set an empty object before loading the script to suppress the error.
…ivity

OpenCode stores all sessions in a single shared SQLite DB. The existing
rebind logic gated on silentTicks (consecutive polls with no new data on
the bound session), but dbChanged() fires on writes to ANY session in the
shared DB — resetting silentTicks to 0 and preventing the rebind check
from ever firing when a user switches to a different session via /session
and sends a message there.

Track the bound session's time_updated separately so we can distinguish
"our" session advanced (reset silentTicks) from "another" session got a
write (set otherSessionActive). The rebind check now fires when the bound
session is silent AND a sibling session is active, so /session + message
switches are detected on the next tick (~2s).
…session theft

The mid-session re-bind pass in the Claude and OpenCode watchers was
missing the LastPtyActivity gate that codex, copilot, antigravity, and
pi already apply. Both agents share state per cwd (Claude via per-project
transcript files, OpenCode via a single shared SQLite DB), so a DB/
file modtime change alone is ambiguous and may come from a sibling agent
running in a different PTY.

When two same-type agents share a cwd and one goes idle while the other
keeps working, the idle watcher's re-bind would steal the sibling's
session and briefly report 'working' again with the sibling's task
under the idle agent's card (the 'idle for a second then working again'
flicker). Add the 3s PTY-activity gate so a watcher only re-binds when
its own PTY has produced output recently, matching the other watchers.
For OpenCode, also clear otherSessionActive when the PTY is silent so
the re-bind isn't re-evaluated every tick while the sibling keeps
writing.
A refactor (commit 2f3c63e) replaced the per-connection viewer struct
with bool in Session.conns, but manager.go:66 kept initializing the map
as map[*connWriter]*viewer, referencing the now-removed viewer type.
This broke go build with 'undefined: viewer'. Switch the literal to
map[*connWriter]bool to match the current Session field type.
04mg and others added 11 commits July 20, 2026 20:02
Replace every per-file/per-line lint override with scoped overrides
in .oxlintrc.json so the lint is respected via configuration rather
than overridden in source:

- react/no-multi-comp: off for src/components/*.tsx (shadcn/ui pattern
  of multiple forwardRef components per file; this is the canonical
  shadcn recommendation).
- no-console: off for src/features/shared/errors/errorReporter.ts
  (the module's purpose is to log errors to the devtools console).
- LazyNode.tsx / LazyFileNode.tsx: drop the react-hooks/exhaustive-deps
  override by adding the missing deps (expanded, load) to the
  refreshCounter effect's dependency array.

Twelve inline overrides removed; zero remain. make lint passes with
no warnings outside the third-party public/wasm bundle.
Wire a focus/blur signal from the frontend (TerminalPanel) through the
terminal WS into the agent status engine so the idle-timeout watchdog
and the watchers' re-bind pass can account for which terminal pane the
user is currently driving.

- terminal: add OnPtyFocus callback and a `focus` message type handled
  in HandleTerminalWS.
- agent: track ptyFocus (single-focus map) with IsPtyFocused accessor;
  clean up on session exit.
- idle-timeout watchdog: exempt the focused PTY from the auto-revert to
  idle even when its output has gone quiet (the user may be mid-prompt
  or reading a long answer).
- watchers (claude/codex/copilot/opencode): allow the re-bind to fire
  when the PTY is focused even without recent PTY output, so a /new or
  /resume issued in the focused pane re-binds before the agent emits
  bytes; an unfocused PTY stays conservative and won't steal a
  sibling's session.
- frontend: TerminalPanel sends focus/blur on isActive changes and
  mirrors the flag onto TerminalInstance so connectWs.onopen re-sends
  it after a reconnect, preventing stale unfocused state.
Cache dirty editor content per filePath in a module-level store so
switching tabs/panes and returning restores in-memory edits instead of
reloading from disk. Cache is cleared on successful save, explicit
reload, or disk-conflict resolution.

Fixes #35
fix(editor): preserve unsaved Monaco edits across tab switches
Use Monaco's multi-model API (path + keepCurrentModel + saveViewState)
so that the editor model survives React unmounts. When the user switches
tabs/panes and comes back, the editor restores the undo stack, cursor
position, scroll position, and unsaved edits — like VSCode.

A new editorDirtyStore module exposes isFileDirty / markFileDirty /
clearFileDirty / discardFileEdits / saveFileFromCache helpers backed by
a Set of dirty file paths and Monaco's singleton model store.

Refs #35
When the user closes a tab or pane containing an editor with unsaved
changes, show a confirmation dialog offering three actions:

- Save: persist the live Monaco model to disk, then close.
- Discard: dispose the Monaco model and close without saving.
- Cancel: abort the close action.

The existing agent-worktree confirmation dialog is preserved for panes
that are not editor-only.

Refs #35
Resolve conflict in EditorPanel.tsx: drop the legacy dirtyContentCache
(now superseded by Monaco's keepCurrentModel + editorDirtyStore) that
was re-introduced from develop during the merge.
…firm

feat(editor): preserve Monaco state across tabs + confirm closing unsaved files
… history after save

- Add reactive useFileDirty hook backed by a subscription store so tab
  labels re-render when a file's dirty state changes.
- Append '*' to modified file tab names (VS Code parity) and drop the
  yellow 'font-mono * unsaved' text from the editor action header.
- Unsaved Changes dialog: remove redundant Cancel button (the X close
  button already covers it), drop font-mono on the file name, and remove
  the 'Do you want to save before closing?' prompt text.
- Keep the Monaco model alive across saves (no dispose/setValue) and push
  a fresh undo stop on save so Ctrl+Z history is preserved until the file
  is closed, matching VS Code behavior.
…firm

feat(editor): dirty-aware tabs, cleaner unsaved dialog, preserve undo history after save
@04mg
04mg merged commit 3595ec0 into main Jul 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant