Commit Graph
154 Commits
Author SHA1 Message Date
Bohdan Triapitsyn 0b39efb0ae chore: bump @opencode-ai/sdk to 1.18.29 2026-09-05 12:11:20 +03:00
Bohdan Triapitsyn f42988c9bf chore: bump @opencode-ai/sdk to 1.18.28 2026-09-04 23:43:54 +03:00
Bohdan Triapitsyn bdda3c36bc release v1.22.0 2026-08-30 19:24:09 +03:00
Bohdan Triapitsyn 5871c36875 chore: bump @opencode-ai/sdk to 1.18.25 2026-08-28 16:01:07 +03:00
Bohdan Triapitsyn c3f3c5aeb7 Merge pull request #3040 from gaojunran/fix/cjk-markdown-links
fix(markdown): keep CJK/fullwidth punctuation out of bare-URL autolinks
2026-08-28 01:22:11 +03:00
Bohdan Triapitsyn cb18f8c9af chore: bump @opencode-ai/sdk to 1.18.23 2026-08-26 19:46:23 +03:00
Bohdan Triapitsyn ac880e8e62 Merge main (anchored-turn chat scrolling) into perf/switch-and-scroll
Main replaced the chat timeline scroll engine while this branch was in
flight, which obsoletes two of its subareas and reshapes a third:

- Chat timeline: main's LegendList-based MessageList/ChatContainer win;
  the activation-overscan staircase targeted the removed tanstack path
  (LegendList provides adaptive rendering natively) and is dropped along
  with its test.
- Scroll shadows: main's hook-based masks stay (the virtualized list owns
  its scroll element — there is no wrapper to hand the styling to); the
  viewport-wrapper ScrollShadow rewrite, its index.css replacement, its
  test, and the call-site viewportClassName adaptations are reverted to
  main. The chat OverlayScrollbar keeps this branch's disableHorizontal.
- OverlayScrollbar: the direct-DOM rewrite lands, but binding now follows
  the live container node instead of binding once per ref object — the
  chat scroller remounts on every session switch, and a bind-once
  contract left the scrollbar attached to a dead element.
- Markdown renderer: the detached-DOM cache and warm-block fast path
  merge with main's block-commit reveal (enter cascade), streaming code
  highlighting, and gutter reservation; the per-block reconcile keeps
  both the decoration-refresh path and the reveal cascade.
2026-08-26 00:59:45 +03:00
c_w_xiaohei 1c3c26f2bf perf(ui): batch Mermaid viewer initialization 2026-08-26 00:42:36 +08:00
Bohdan Triapitsyn 04f338cc49 feat(chat): upgrade @legendapp/list to 3.3.8 and let it own end following
3.3.x makes maintainScrollAtEnd follow content growth on its own — a
tail row growing in place included — which is exactly what the manual
totalSize correction existed for. Delete that correction (the totalSize
listener now only drives the anchored-turn glide) and pick up 3.3.x's
measurement batching, prepend-flash fixes, and web programmatic-scroll
fixes. Opt the explicit maintainScrollAtEnd config into footerLayout per
the 3.1.1 guidance.

The library's own released-on-user-scroll heuristic proved unreliable
one run in three against synthetic touch, so the gesture state machine
stays authoritative: while a real gesture owns the scroll, the list's
end pinning is switched off through a threaded endPinningReleased prop
and re-engages when the user returns to the end.

Validated with the CDP battery on a production build: stream follow
stays at distance 0, mobile drag releases with the pill shown in three
of three runs, resize oscillation stays at the reduced level, the rail
reaches the last turn, and profiled streaming cost per rendered
character matches the tuned 3.2.0 numbers.
2026-08-25 16:49:22 +03:00
Bohdan Triapitsyn d2d8669564 refactor(chat): replace timeline scroll engine with anchored-turn LegendList
Sending a message now parks that message near the top of the viewport
and streams the reply into reserved end space below it, instead of
jumping to the bottom and chasing it.

- swap @tanstack/react-virtual for @legendapp/list in the chat timeline; the
  streaming tail becomes a normal list row rather than a separately rendered
  block, so one component owns the scroll position
- add timelineScrollAnchoring: pure anchored-turn geometry plus the three
  scroll modes (following-end / anchoring-new-turn / free-scrolling)
- replace useChatAutoFollow with useChatTimelineScroll, which opts out of
  automatic movement on real gestures via a generation counter instead of the
  timer windows the old implementation needed to recognise its own writes
- move the load-older button, question/permission cards, recap, status row and
  bottom spacer into the list header/footer, since the list owns its container
- extract useScrollShadow so the shadows can attach to that container

maintainScrollAtEnd and maintainVisibleContentPosition replace the manual
prepend anchor-hold and the mobile quiet-window prepend deferral.

Validated: workspace type-check, lint, web build, ui tests per file.
Scroll behaviour itself is unverified and needs manual testing on web, desktop
and iOS.
2026-08-25 01:10:00 +03:00
Bohdan Triapitsyn 841eca5720 feat(surface): switch app shells when the viewport crosses the phone threshold
The mobile-vs-desktop surface is stamped once at boot, so a browser
window narrowed past the phone threshold kept the desktop shell (and
its legacy squeezed layout) until a manual reload. A viewport watcher
now reloads into the other shell once the resize settles — the same
mechanism the old Settings toggle used. Fixed shells (Capacitor,
desktop, VS Code) and ?surface= overrides never switch.

With the new mobile app reachable this way, the old/new mobile layout
preference is gone: phones always get the mobile app.
2026-08-24 16:08:04 +03:00
Bohdan Triapitsyn 90f150bd0c chore: bump @opencode-ai/sdk to 1.18.21 2026-08-22 12:13:54 +03:00
gaojunran 19c5cc1f1e fix(markdown): keep CJK punctuation out of bare-URL autolinks
marked's GFM url tokenizer swallows any non-space text after a bare URL,
including fullwidth punctuation and Chinese annotations written directly
after it ("https://x.com/docs(说明)了解更多"). Switch the autolink
tokenizer to marked-linkify-it, which treats Unicode punctuation as a URL
boundary, so fullwidth parens and CJK punctuation are trimmed naturally.
2026-08-21 13:10:42 +08:00
Bohdan Triapitsyn 1ed3f1f575 feat(skills): curated GitHub catalog redesign (#3016)
* feat(skills): remove ClawHub catalog integration

Drop the ClawHub registry as a skills catalog source across web server,
shared UI, VS Code, docs, and locales. The catalog now serves git-based
sources only: the curated Anthropic repo and user-defined repositories.
Also removes the now-unused adm-zip dependency.

* feat(skills): redesign catalog around curated GitHub repositories

Replace the single-source dropdown with a card grid of curated GitHub
repositories (Anthropic, OpenAI, Cursor pstack/skills, Matt Pocock) plus
user-defined sources. Source cards show skill counts, GitHub stars, and
last-updated time; a global search covers all loaded sources.

Server: curated sources gain GitHub repo metadata (stars, pushed_at)
fetched best-effort with a 3-hour in-memory and on-disk cache; scans
run through a concurrency-limited, deduplicated cache with 3-hour TTL
persisted across restarts. Refresh still bypasses the cache.

Shared UI: source cards, global search with clear button, per-skill
GitHub links, install/installed states. VS Code curated list updated
to match. All new copy translated across 12 locales.

* fix(skills): address catalog review findings

- GitHub metadata fetch timeout drops to 1.5s (under the catalog
  client's 3s deadline) and failed lookups cache briefly (5 min) so
  repeated catalog loads do not re-hit a failing API.
- Disk cache files are written with owner-only permissions (0o600);
  rename preserves the mode.
- loadSource deduplicates concurrent in-flight requests per source and
  the shared isLoadingSource flag now clears only when the last active
  source load finishes.
2026-08-20 01:40:10 +03:00
Bohdan Triapitsyn 584b9304fd fix(ui): use CodeMirror selection handles on iOS 2026-08-18 21:37:57 +03:00
Bohdan Triapitsyn 51aef5e316 chore(lint): vendor anti-slop oxlint plugin and add batched cleanup pipeline
Vendor the anti-slop Oxlint plugin at tools/oxlint/anti-slop and register it
in oxlint.config.ts, with Oxlint's own rule categories disabled so ESLint
stays the general-purpose linter.

Add scripts/anti-slop.mjs (bun run deslop) mirroring the React Doctor batch
interface: next-batch, check-batch, active, release, top, file. Batch handoff
directories now double as file claims shared across clones via
~/.openchamber/maintenance-claims, so concurrent maintenance batches from
either pipeline never select the same file.

Harden both scheduled maintenance flows: stop on a dirty worktree, stop on
NO BATCH AVAILABLE, validate per package instead of workspace-wide, and pin
react-doctor to 0.9.12. The anti-slop task command documents concrete
good and bad fixes and forbids laundering types to satisfy a rule.
2026-08-16 15:55:08 +03:00
Bohdan Triapitsyn 7c5fcb535e chore: bump @opencode-ai/sdk to 1.18.18 2026-08-14 00:26:07 +03:00
Bohdan Triapitsyn a5aa32446d feat(browser): replace the preview proxy with a real browser panel and an agent web tool (#2883)
The preview panel worked by proxying a dev server through OpenChamber's own
origin and rewriting the HTML that came back. Anything the rewriter did not
anticipate broke, and pages that refuse to be embedded never loaded at all.
This deletes the proxy (-1604 lines and its tests) and merges the preview and
browser panels into one surface backed by a real Chromium view.

What the panel is now

- A `<webview>` in its own session partition: logins and cookies persist, hot
  reload works because nothing is rewritten, DevTools are one click away.
- Annotation: pick one element, drag a region, or draw freehand, write a note,
  and it reaches chat with a screenshot of the visible page with the marks on it.
- Toolbar: hard reload, page zoom, device sizes, a light/dark switch that
  applies to the page rather than the app, and cookie/cache clearing scoped to
  the panel alone.
- Several pages at once, each tab showing the page's own favicon, and an address
  bar that suggests pages already visited in this project.
- Dev servers are listed from what is actually listening on the machine, checked
  against what a project announced, so a server is offered no matter how it was
  started. One that is still starting is waited for instead of failing.

Remote dev servers

The desktop app binds a local port and pipes raw bytes to the OpenChamber host
over the existing authenticated connection, so the page keeps its own origin at
the root of its own host. The reachable set is exactly what discovery reports
and is re-checked per connection, so an authenticated client cannot dial
arbitrary local services on the host. Links and redirects to another loopback
port stay on the machine that served the page. A tunnel that cannot be opened is
reported; it is never replaced by the plain loopback URL, which would answer
from the user's own machine under a remote address.

Agent control

Browser actions are a separate `openchamber_web` tool: open, snapshot, click,
type, scroll, inspect computed styles, resize between mobile/tablet/desktop, and
capture a screenshot into `.openchamber/screenshots/` in the project. The
existing `openchamber` tool keeps sessions, worktrees and scheduled tasks. Each
has its own setting in the new Settings -> General -> OpenChamber Tools section,
and the plugin is not injected at all when both are off.

Capability belongs to the connected client, not to configuration: a client
declares on its event stream that it can drive a page, which only a Chromium
host does. Exactly one client performs each request — it claims the request
before acting, and the first claim wins — because deciding by whose result
arrives first would be too late for a click that already happened. No client
listening is answered immediately with an explanation rather than a timeout.

Runtime boundaries

Web tabs get a plain iframe that can display a page but not inspect one. The
VS Code extension no longer offers the surface at all, since nothing that makes
the panel worth having works there. Mobile is unaffected.

Native boundary

Camera, microphone, location and device-picker requests from panel pages are
denied — Electron grants them by default when no handler is set, and the panel
loads whatever address the user types. Page capture, appearance emulation and
storage clearing verify that their target belongs to the panel's own session
instead of trusting a web-contents id from the renderer.

Persisted state

Stored `preview` tabs migrate to `browser` (v13 -> v14). Context panel tab
limits are now per surface, so filling one surface no longer evicts another's
tabs. Address history is stored per project and per runtime.

Documentation

`preview.mdx` and `desktop-browser.mdx` rewritten across all locales, the agent
tool settings path corrected, new `DOCUMENTATION.md` for the browser-control
broker and the dev tunnel, and the `ui-api-decoupling` skill updated where it
still described the deleted proxy.
2026-08-13 22:44:13 +03:00
Bohdan Triapitsyn cf2e53b973 chore: update workspace lockfile versions 2026-08-13 13:57:56 +03:00
pablogonzalez b8df186822 feat(desktop): upgrade Electron to 43.3 for Linux frameless rounded corners (#2765)
* feat(desktop): upgrade Electron to 43.3 for Linux frameless rounded corners

- electron ^41.2.1 -> ^43.3.0 (electron/electron#51459/#52111: rounded
  corners for frameless windows on Linux, default-on; disable via
  roundedCorners: false)
- @electron/rebuild ^3.7.0 -> ^4.2.0 to build native modules against
  the new Electron ABI
- pin node-abi to 4.33.0 via root overrides so @electron/rebuild (and
  electron-builder's internal rebuild) can resolve Electron 43's ABI
- README: Electron 43 ships its own fixed extractor (extract-zip 2.0.1
  Node-24 unpack bug no longer applies; ensure-electron remains a
  safety net for interrupted/wrong-arch installs)

* chore: re-trigger pr-review after adding visual evidence

* fix(desktop): scope node-abi to Electron rebuild tooling

* chore: re-trigger pr-review after dependency fix

* chore: re-trigger pr-review with drag evidence

* chore: retry pr-review after evidence confirmation
2026-08-11 17:25:32 +03:00
Bohdan Triapitsyn 59d988deda release v1.18.2 2026-08-10 20:57:44 +03:00
Bohdan Triapitsyn f8b33be5eb chore: bump @opencode-ai/sdk to 1.18.15 2026-08-09 20:03:06 +03:00
Mel0ny 7e0e22f6e2 fix(deps): upgrade adm-zip to 0.6.0 to fix GHSA-xcpc-8h2w-3j85 (#2643)
adm-zip <0.6.0 allows a crafted ZIP to trigger a ~4GB memory
allocation (GHSA-xcpc-8h2w-3j85). Bump the dependency in the web
and vscode packages to ^0.6.0. The new AdmZip(buffer) and
extractAllTo(dir, overwrite) APIs are unchanged, so no call-site
adaptation is needed.

Add a vitest regression test for the ClawdHub install path that
builds a real ZIP with adm-zip and asserts extractAllTo restores
files (including nested subdirectories) into the target skill dir.
2026-08-06 22:59:08 +03:00
Bohdan Triapitsyn 67965ced2f release v1.18.1 2026-08-04 19:39:40 +03:00
Bohdan Triapitsyn 56f2b972f0 chore(deps): drop better-sqlite3 and its desktop packaging support
The SQLite write into OpenCode's database was the only consumer of
better-sqlite3 in the repository. Everything that existed to ship its native
binary went with it:

- the dependency in @openchamber/web and @openchamber/electron
- the afterPack hook staging better_sqlite3.node into app.asar.unpacked
- a dedicated @electron/rebuild pass (onlyModules) and its binary assertion,
  so desktop packaging now runs one native rebuild instead of two
- the bundler external entry and the AppImage required-native-module check

Desktop packaging, the AppImage verification tests, and the extension bundle
were re-validated after a clean reinstall, so no stale module could satisfy a
missed import.
2026-08-03 23:38:01 +03:00
Serhii Dziupin 94c9ac3153 Merge pull request #2592 from openchamber/terminal-open-debug
fix(terminal): start PTY before viewport mounts without dropping output or replies
2026-08-03 12:50:19 +03:00
Serhii Dziupin 88937ade72 fix(terminal): start PTY before viewport mounts without dropping output or startup replies
Terminal creation no longer waits for the Ghostty viewport to report its
size: it starts the PTY immediately with a container/font-derived
provisional size (falling back to 80x24), then resizes once the real
viewport dimensions are known, with a dedupe guard while sizing settles.

Starting the shell earlier means it can emit device/theme queries before
a browser terminal is attached to answer them, so the server now answers
primary device attribute queries itself (Fish blocks ~10s on this at
startup) and bun-pty buffers output emitted before a data subscriber
attaches. Also fixes a few WebSocket transport reconnect races surfaced
by session creation now overlapping renderer setup.
2026-08-03 12:29:32 +03:00
Bohdan Triapitsyn 134d055ee6 fix(git): support secure SSH config 2026-08-02 23:02:14 +03:00
Bohdan Triapitsyn 3a50bfb6f9 Merge main and fix lazy image export loading 2026-08-02 20:17:37 +03:00
Serhii Dziupin aa1875b6f0 perf: start terminal sessions before renderer mounts 2026-08-02 16:03:32 +03:00
Bohdan Triapitsyn 37ff3a8164 release v1.17.2 2026-08-01 23:17:28 +03:00
Bohdan Triapitsyn 86ef96302d feat(mobile): mobile app navigation rework and beta-feedback closeout (#2561)
Navigation model rebuilt around two full-width drawers and a minimal
header (sessions / title-switcher / usage ring / workspace):

- Left sessions drawer: cross-project tree with live status indicators,
  swipe actions on sessions (rename/archive/delete) and on group headers
  (project edit / two-step close, worktree delete), reorder-only edit
  mode with collapsible project cards and draggable worktrees, app-level
  footer (connected instance, settings, pending web update).
- Right workspace drawer: Changes / Files / Terminal / Notes / MCP as
  pill tabs (inactive tabs icon-only); panes stay mounted once visited.
  The full desktop file editor serves the Files tab; read/skill tool taps
  in chat open the file there at the requested line.
- Header session switcher on title tap: 10 cross-project recents with
  live busy/attention indicators and project · branch metadata; the
  usage ring opens a metadata overlay with an explicit loading state.
- The overflow menu is gone on phones (its destinations moved into the
  drawers); iPad keeps it until its dedicated layout pass.

Correctness and continuity:

- /auth/session answers bearer-first, so a stale WebView cookie can no
  longer mask a revoked device token; cold launches classify failures
  fast and land on an explicit connect screen.
- Authoritative session snapshots raise frozen ordering baselines and
  stale live ranks — recents stay truthful after the app slept.
- Cold launches reopen the last active session per instance (persisted
  pointer, confirmed against a sessions snapshot; a user-opened draft
  clears it), with a logo hold instead of a draft flash.

Also: collapsed pill composer gains the stop control; chat tool rows
share one 36px rhythm; Task subtool rows truncate; larger bottom safe
area so the composer clears big-screen corner radii; Capacitor build
hides About/Update (store updates apply there); widgets link to the
sessions drawer with a list icon; MobileApp split into focused modules;
five mobile-surface detectors unified; translucent borders normalized to
70%; all new strings translated across the 10 locales.

iPad and foldable layouts are intentionally untouched - separate next version PR.
2026-08-01 21:16:36 +03:00
Bohdan Triapitsyn 0716797efb chore: bump @opencode-ai/sdk to 1.18.9 2026-07-29 20:16:58 +03:00
Bohdan Triapitsyn 7331ee626e feat: add one-command mobile simulator dev loop
Adds `mobile:sim:dev` / `sim:dev` to build, install, launch, and stream the iOS simulator in one command
Updates mobile docs and serve-sim guidance with the new workflow and correct preview URL behavior
Bumps `serve-sim` to a newer version
2026-07-28 23:34:06 +03:00
Bohdan Triapitsyn fbc064c16f docs: add agent control tool guide
Adds a new docs page explaining the OpenChamber agent control tool and its capabilities.
Includes localized versions for supported languages and adds the page to the docs sidebar.
Updates the lockfile with the new better-sqlite3 dependency.
2026-07-28 12:58:20 +03:00
Bohdan Triapitsyn 3a5c399298 chore: bump @opencode-ai/sdk to 1.18.8 2026-07-28 12:26:20 +03:00
Bohdan Triapitsyn 3fa0c5be57 chore: bump @opencode-ai/sdk to 1.18.7 2026-07-27 23:13:21 +03:00
Bohdan Triapitsyn b6cdf7b6a7 chore: update opencode sdk version to 1.18.5 2026-07-26 18:53:58 +03:00
Bohdan Triapitsyn 16df9412fd fix: update keyboard shortcut abort logic
Use current session activity to determine when abort shortcuts are available
Prevent abort priming when there is no active session
2026-07-24 22:13:38 +03:00
Bohdan Triapitsyn fd0f6a6bac feat: support Office documents in chat attachments
Users can now attach Microsoft Office documents (.docx, .pptx, and .xlsx) and OpenDocument files (.odt, .odp, and .ods) from the shared web, desktop, mobile, and VS Code chat surfaces.

Document text is extracted locally and sent as a text/plain file part with the original filename, keeping the visible user message clean. Supported embedded PNG, JPEG, GIF, and WebP images are sent as separate image parts, with matching [filename] citations preserved near their source paragraph, slide object, spreadsheet cell anchor, or OpenDocument position. Presentation notes, spreadsheet values, headers, and footers are included where available.

Document expansion is metadata-validated and bounded against oversized entries, excessive uncompressed data, unsafe paths, invalid image signatures, attachment-name races, and dangling citations after truncation. Generated document parts are published to the composer atomically.

Add fflate for worker-backed ZIP extraction and narrowly allow blob workers in the VS Code webview CSP without permitting blob scripts. Include focused fixtures for every supported format, extraction limits, positional citations, collision recovery, atomic attachment state, and CSP behavior.
2026-07-22 13:11:42 +03:00
Bohdan Triapitsyn 55013ecb25 chore: update opencode sdk version 2026-07-22 11:44:47 +03:00
Bohdan Triapitsyn 85400459e9 perf: overhaul session loading, caching, and runtime isolation (#2360)
Improve OpenChamber responsiveness under large session workloads while fixing
cache, synchronization, and persistence correctness across runtimes, projects,
directories, and worktrees.

- prioritize selected and visible sessions during bootstrap and defer
  non-critical enrichment work
- reduce redundant message loading, event processing, store publication, and
  hidden sidebar work
- prevent stale session and message requests from overwriting newer
  authoritative state
- preserve existing data when authoritative fetches fail instead of treating
  failures as successful empty responses
- scope session materialization, messages, drafts, queues, todos, pins,
  permissions, folders, tabs, Git state, and pull request data by runtime and
  directory identity
- harden runtime switching, reconnect, cleanup, mutation reconciliation, and
  persisted-state ordering
- preserve live subagent Task linkage when metadata arrives after an older
  message request or while streaming parts are suspended
- coalesce overlapping tail refreshes without losing newer refresh demand
- improve cold-session loading by moving deferrable work out of the critical
  bootstrap path
- isolate URL authentication, mobile credentials, native secrets, and other
  runtime-owned state across endpoint changes
- bound long-lived caches and remove avoidable allocations from event and
  rendering hot paths
- limit virtualization to archive collections where it improves rendering
  without disrupting active sidebar layout
- stabilize session folders, pin ordering, expanded state, and persisted
  sidebar behavior
- open skill files through the same secure editor and outside-workspace grant
  flow used by file navigation, including worktree sessions
- expand regression coverage for stale completions, runtime collisions,
  reconnect behavior, persistence races, authoritative empty results, and
  subagent refresh ordering
- document the updated synchronization, cache ownership, performance, and
  runtime-isolation invariants
2026-07-21 20:52:20 +03:00
Bohdan Triapitsyn 61c87feeaf fix: clamp virtual scroll offset and update patch paths
Clamps TanStack virtualizer scroll offsets to valid bounds
Updates patched dependency references to bun-patches
Refreshes ghostty-web patch for invalid codepoint handling
2026-07-18 09:57:25 +03:00
Bohdan Triapitsyn 66f3969273 chore: bump @opencode-ai/sdk to 1.18.3
Updates the SDK dependency across web, UI, and VS Code packages.
Refreshes the lockfile and package versions to match the release.
Adds unreleased changelog notes for the current set of user-facing changes.
2026-07-18 01:19:15 +03:00
Bohdan Triapitsyn 6c2e657511 chore: draft unreleased changelog, bump opencode sdk to 1.17.18
Changelog leads with the private relay and the native mobile apps (TestFlight
beta + Android APK links), followed by pairing v2 and the device management,
desktop multi-transport, and chat items; VS Code changelog gets the shared
chat-render entries.
2026-07-10 13:42:52 +03:00
Bohdan Triapitsyn de1b85ac56 feat(voice): first-class voice input and local TTS across web, desktop, and mobile (#2018)
Complete rebuild of voice input on a server-authoritative streaming
architecture, replacing the legacy Web Speech / whole-blob / WASM engines
and the dead voice-agent layer (~4k lines removed).

Speech-to-text (dictation):
- Client streams 16 kHz mono PCM16 chunks over /api/dictation/ws with
  seq/ack ordering; buffered audio is retained and replayed on reconnect
- Server transcribes and streams live partial transcripts back;
  segments auto-commit every ~15s with silence suppression and adaptive
  finalization timeouts
- Local provider (default, zero config): sherpa-onnx models in a forked
  worker process — auto-download with progress, staged extraction with
  verification, corrupt-model auto-recovery, idle shutdown after 5 min
- Model catalog with settings picker (accuracy/speed ratings, sizes,
  download/delete): Parakeet TDT v2 (English) and v3 (25 European
  languages, auto-detected), Whisper base and tiny (multilingual, light)
- OpenAI-compatible provider for any Whisper endpoint
- Composer overlay with live transcript, volume meter, timer, and
  cancel / insert / insert-and-send actions; failed transcriptions keep
  their audio for retry or accepting the partial text as-is
- Configurable keyboard shortcut (default mod+alt+v) toggles dictation;
  Enter confirms and Escape cancels while recording
- Overlay is pixel-aligned with the composer (measured footer height,
  matching paddings/typography/gaps) — no layout shift when toggling

Text-to-speech:
- Local Kokoro provider (English, 11 voices) synthesized in the same
  worker via /api/dictation/tts/speak, managed by the shared model
  pipeline; sentence-pipelined playback keeps time-to-first-audio at
  ~1 sentence regardless of message length, and stop cancels in-flight
  synthesis
- Sanitizer keeps inline-code content (strips backticks only), reads
  interword slashes aloud, and removes only absolute file paths

Settings:
- Voice page unified: a single read-aloud toggle owns all playback
  options (the confusing "Enable Voice Mode" is gone); a new "Enable
  voice input" toggle (default on, persisted to settings.json) hides
  the composer mic entirely when disabled

Mobile and transport:
- iOS/Android microphone permissions added (dictation was previously
  impossible on mobile)
- Fixed Android WebSocket upgrades: the Capacitor WebView origin
  (https://localhost) was missing from the packaged-client allowlist,
  403-ing every WS connection — root cause of the old mobile SSE lock,
  which is now removed for all transports

Security and conventions:
- All HTTP routes sit behind the global /api auth gate; the WS upgrade
  explicitly validates the UI session and origin, with oc_url_token
  narrowly allowlisted and covered by tests; the dictation socket mints
  a fresh URL token before connecting
- Routes register before the generic OpenCode proxy; the client goes
  through runtimeFetch/getRuntimeUrlResolver, and runtime switches
  reset the dictation socket
- VS Code deliberately reports dictation as unavailable (no server
  process in that runtime)

CI: workflow Node bumped 20 -> 22 to match the repo engines and fix
better-sqlite3 installs broken by node-gyp@latest on Node 20.

New dependency: sherpa-onnx-node (prebuilt N-API; macOS/Linux x64+arm64,
Windows x64 — Windows-on-ARM falls back to the OpenAI-compatible provider)
2026-07-04 02:48:07 +03:00
Bohdan Triapitsyn 2bce38cfbb feat(chat): migrate history list to @tanstack/react-virtual with deterministic mobile history loading
- Replace virtua with @tanstack/react-virtual for chat history on all
  surfaces: bottom anchoring (anchorTo: end), key-stable prepend
  preservation, and native iOS touch/momentum deferral live in the core
- Patch virtual-core to clamp the render range to real scroll bounds
  during transient adjustments
- Rows render in normal flow inside a translated wrapper so sticky user
  headers keep working; measurement snapshots cached per session
- Pre-write container height in scrollToFn so the browser cannot clamp
  anchor corrections to the stale height; hold the prepend anchor for up
  to 180 frames on mobile while fresh rows settle (cancelled by user
  input; desktop relies on core anchoring alone)
- Adaptive row-size estimate from per-session measured averages; disable
  reveal fade-in for virtualized history rows
- Mobile loads older history only through an explicit localized top
  button: no scroll-position trigger and no post-mount background
  prepend, so every insert happens from a resting state; a quiet-window
  hold defers any stray prepend commit while a touch gesture is active
- Desktop/VS Code keep the seamless scroll-up trigger and progressive
  background prepend
2026-07-03 18:43:40 +03:00
Bohdan Triapitsyn 33ecd628bd feat(desktop): bundle pinned OpenCode CLI
Bundle the official OpenCode CLI into Electron desktop builds instead of relying on whichever opencode executable happens to be first on PATH. Pin @opencode-ai/sdk to an exact version and use that version as the source of truth for the downloaded CLI artifact.

Add an Electron prepare script that maps the current platform/arch to the official OpenCode release artifact, downloads it from GitHub releases, caches the archive under packages/electron/.cache, stages the binary under resources/opencode-cli, verifies opencode --version, and skips work when the staged binary already matches.

Prefer explicit OpenCode binary overrides first, then the bundled Electron CLI, then PATH/system installs. Keep rejecting the Windows OpenCode desktop app executable as a CLI candidate and add resolver tests for bundled priority, explicit override priority, resourcesPath lookup, and desktop-app rejection.

Suppress OpenCode CLI update prompts when the active CLI source is bundled. The server now reports upgrade-status as unavailable for bundled CLI while still returning the current OpenCode version for About, and rejects direct upgrade attempts with a 409 instead of trying to mutate the bundled binary.

Update desktop release, smoke, and manual macOS DMG workflows to prepare and verify the bundled CLI before packaging, verify the packaged app contains the expected CLI, cache downloads by OS/arch/OpenCode version, and align the Windows smoke runner with production windows-2022.

Document desktop bundling behavior, ignore generated CLI/cache files, add oc-dev helpers, and keep Web/VS Code behavior dependent on installed OpenCode CLI rather than desktop bundled resources.
2026-07-02 17:43:33 +03:00
Bohdan Triapitsyn 37a9179656 chore: remove bundled IBM Plex fonts 2026-07-02 00:45:59 +03:00
Bohdan Triapitsyn b60a794e80 fix: recover chat state after idle reconnects
Resyncs active sessions after hidden upstream stream reconnects
Recovers orphaned streaming parts with active-session snapshots
Adds coverage for event-stream reconnect behavior
2026-07-01 17:21:19 +03:00