Commit Graph
777 Commits
Author SHA1 Message Date
Bohdan Triapitsyn 2f1377ec01 fix: prevent duplicate desktop notifications 2026-04-06 20:55:32 +03:00
Bohdan Triapitsyn 8de1884f5c refactor: remove plan polling, add message-driven detection via usePlanDetection hook 2026-04-06 20:44:13 +03:00
Bohdan Triapitsyn a516650f96 fix: stabilize chat auto-scroll and bottom resume
- Unify send and session resumes around the latest chat tail
- Keep smooth follow active during assistant message growth
Remove staged chat rendering from the main scroll path
2026-04-06 20:18:20 +03:00
Bohdan Triapitsyn f884919165 fix: keep notification summaries in plain text
- Force notification summaries to avoid markdown formatting
- Normalize generated notification text before system display
- Cover plain-text notification formatting with tests
2026-04-06 17:40:20 +03:00
Bohdan Triapitsyn 9254ec0783 fix desktop notifications and chat scroll stability 2026-04-06 17:36:08 +03:00
Bohdan Triapitsyn e42471ee7b chore: update workspace dependencies and chat behavior
- Adjust package metadata and lockfiles across the workspace
- Refine chat sidebar and auto-scroll behavior in the UI
- Update PWA install handling alongside runtime package changes
2026-04-06 13:04:36 +03:00
Bohdan Triapitsyn 4db1e6baad perf: reduce active-turn chat rerenders during streaming
- Keep older assistant messages in the active turn stable while new content streams
- Prevent existing tool rows from rerendering when new tool activity is appended
- Tighten message and tool memo comparisons to isolate render work to changed rows
2026-04-06 00:43:19 +03:00
Bohdan Triapitsyn 4a3b7ec5c9 fix: restore smooth chat auto-scroll and live compaction updates
- Keep assistant auto-scroll smooth during active responses without periodic snaps
- Restore live `/compact` rendering and streamed compaction summaries without refresh
- Preserve global event handling while routing session and message updates efficiently
2026-04-05 23:01:12 +03:00
Bohdan Triapitsyn 8b41a620d9 fix: fixed issues with scrolling jumps 2026-04-05 22:14:09 +03:00
Bohdan Triapitsyn f2f57ca281 fix: restore live compaction updates in chat
- Show `/compact` command and streamed compaction summary live without refresh
- Handle versioned sync event types so message and part updates are processed
- Route session/message events via indexed lookup to avoid hot-path store scans
2026-04-05 21:22:17 +03:00
Bohdan Triapitsyn dfc61d7671 refactor: replace chat markdown renderer
- Replace Streamdown-based chat markdown rendering with the new renderer path
- Preserve OpenChamber table, code block, and mermaid presentation
- Remove leftover Streamdown dependencies and compatibility hooks
2026-04-05 19:24:23 +03:00
Bohdan Triapitsyn 3bf9947388 perf: reduce status row streaming churn
Replace live assistant-part status subscriptions with coarse session phase, retry, permission, and abort state so the composing row no longer rerenders on every text delta.
2026-04-05 17:29:14 +03:00
Bohdan Triapitsyn c88e68e5f7 perf: reduce chat streaming rerenders
- Keep historical chat messages stable during streaming
- Isolate active stream state to the current message path
- Reduce chat container churn from sync message updates
2026-04-05 16:56:05 +03:00
Bohdan Triapitsyn e56f2f99cf perf: freeze detached chat history updates
Stop historical chat view from waking on live tail deltas by suspending detached part updates, narrowing scroll manager dependencies, and hardening sync-context HMR behavior during dev.
2026-04-05 15:58:06 +03:00
Bohdan Triapitsyn 4663abd6f3 refactor: isolate chat hot paths and lazy server watchers
Split static history from live tail, stabilize chat data identities, and reduce scroll-shell churn so old viewport content stops waking on stream deltas. Also defer watcher startup and health polling so idle runtime work better matches actual usage.
2026-04-05 15:36:11 +03:00
Iuliia Ivashko fc44465c00 fix(chat): render LSP diagnostics in tool output (#837) 2026-04-04 11:15:32 +03:00
Bohdan Triapitsyn 8587db89b1 perf: reduce UI render fanout and scroll jitter
- Cut broad render fanout across the app by replacing shared-store whole-object subscriptions with leaf selectors, memoizing hot chrome boundaries, and isolating disabled global providers from live session/message state. This keeps header controls, composer toolbars, side panels, and other non-hot UI surfaces from repainting on every assistant update or keystroke.

- Rework sidebar session ordering so recent, project groups, and worktree groups derive from one ordering source while avoiding streaming-time thrash. The sidebar now uses a stabilized session snapshot, preserves structural identity for unchanged rows, reads live row status/details per session, and applies a one-shot sort bump on idle->busy instead of continuously resorting during activity.

- Fix chat/input scroll instability by separating viewport-resize handling from message-growth handling, disabling conflicting native scroll anchoring, and stopping textarea autosize from collapsing on every growth keystroke. This removes the multiline typing jiggle during streaming and reduces unnecessary composer rerenders.

- Also gate voice context wiring behind voice-mode enablement and codify the learned render/scroll/order anti-patterns in AGENTS.md so future changes avoid the same classes of regressions.
2026-04-04 02:19:55 +03:00
Bohdan Triapitsyn c5497e9823 perf: remove idle background polling hooks 2026-04-03 19:55:47 +03:00
Bohdan Triapitsyn d982171689 refactor: centralize git and pr store refresh 2026-04-03 19:47:01 +03:00
Bohdan Triapitsyn 2c56cb021f refactor: switch shine text to CSS shimmer 2026-04-03 19:38:37 +03:00
Bohdan Triapitsyn 246464a325 perf: remove animated logo from idle and loading surfaces 2026-04-03 16:44:31 +03:00
Bohdan Triapitsyn 5045d21821 perf: reduce idle desktop load by gating plan-mode checks
- Add startup feature flag for plan mode from OPENCODE_EXPERIMENTAL* env vars.
- Stop recurring app health polling and keep a one-time startup check.
- Skip plan-mode synthetic parsing and plan tab/file work when flag is off.
2026-04-03 13:59:10 +03:00
Bohdan Triapitsyn a36b11d54e fix: limit PWA input spacing behavior to mobile
- Prevent desktop chat input from inheriting mobile bottom safe-area gap
- Apply chat input safe-area classes only on mobile
- Scope standalone PWA safe-area and blur overlay CSS to mobile runtime
2026-04-03 12:45:00 +03:00
Bohdan Triapitsyn 9d78c48949 fix: keep selected session header details stable
- Prevent header flicker to Untitled during session refresh
- Resolve header session data from global sessions first
- Pass session directory hints on more session-switch paths
2026-04-03 12:38:03 +03:00
Dave Otero dd0587501f fix: recover SSE directory routing in sync pipeline (#830) 2026-04-03 11:46:19 +03:00
jwcrystalandBohdan Triapitsyn e63450ae2c fix: resync session state after SSE reconnect to prevent stuck subagent UI (#817)
* fix: resync session state after SSE reconnect to prevent stuck subagent UI

When a subagent completes while the page is in the background (common on
mobile PWA and desktop webview), the final SSE events are lost. The UI
then stays stuck on 'Waiting for subagent activity...' because:

- part.state.status never transitions to 'completed'
- session_status is never updated to 'idle'
- activeLatched remains true indefinitely

Fix:
- Add onReconnect callback to event pipeline, fired after SSE reconnect
- Add pageshow listener for bfcache restores (mobile PWA back-forward)
- On reconnect, re-fetch session list for directories with active sessions
- Pass explicit directory to useSessionActivity in ToolPart for subagents
  to ensure the correct child store is queried

Closes #810

* fix(chat): resolve pending subagent task binding before metadata arrives

* fix: restore subagent activity and tool visibility after reconnect

- Resyncs session status and child session data after SSE reconnect
- Ensures child task tool messages are read from the correct directory
- Prevents stale assistant fallback from keeping sessions stuck as active

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-03 00:29:49 +03:00
Bohdan Triapitsyn aef7b206ed fix: respect host when checking port availability 2026-04-02 14:11:32 +03:00
Willian Diaz Pabón c9d112871c fix(vscode): normalize Windows directory paths for SSE event store lookup (#818)
On Windows, SSE events from OpenCode arrive with native backslash
separators and system-cased drive letters (e.g. D:\Dev\...), while the
UI child store keys use forward slashes with lowercase drive letters
from VS Code's workspace folder (e.g. d:/Dev/...). This mismatch
caused the child store Map lookup to silently miss on every directory
event, preventing session data, messages, and streaming responses from
reaching the React UI.

Changes:
- sync-context.tsx: Normalize incoming SSE event directory paths by
  converting backslashes to forward slashes and uppercasing Windows
  drive letters before the child store lookup.
- useDirectoryStore.ts: Add drive letter uppercasing to
  normalizeDirectoryPath, aligning it with normalizeCandidatePath in
  client.ts and normalizeWorkspacePath in main.tsx.

Both normalizations are no-ops on macOS/Linux where paths already use
forward slashes and have no drive letters.

Closes #816
2026-04-02 11:47:32 +03:00
Bohdan Triapitsyn 507f429674 release v1.9.3 2026-04-01 19:42:13 +03:00
YifanandBohdan Triapitsyn 2b70ec6f3a feat(terminal): switch terminal transport to pure websocket with fallback (#762)
* feat(terminal): add resumable websocket transport

Unify terminal input and stream traffic on `/api/terminal/ws` with a v2 control-frame protocol and advertised transport capabilities.

Buffer recent PTY output on the server so rebinding clients can replay missed chunks after reconnects or startup races, while keeping SSE as a fallback stream path.

Update the web terminal client and store to negotiate the new transport, track tab lifecycle, and avoid reopening exited sessions when restoring tabs.

* fix(terminal): retry rehydrated websocket reconnects

* fix(terminal): keep reconnect retries silent

* fix(terminal): wire ws stream output and replay in runtime

* fix(web): enable ws proxy for /api in dev

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-01 19:31:21 +03:00
Nguyễn Ngô Thượng d68bec491c fix(chat): improve error message display with better styling and word-break (#767)
- Add error icon and colored background/border for error messages
- Add break-all and max-w-full to prevent long error text overflow
- CSS: word-break and overflow-wrap for inline code in error messages
2026-04-01 18:36:47 +03:00
jwcrystal aa071556bf fix(worktree): fix worktree detection and state reset when switching (#779)
* fix(worktree): reset IntegrateCommitsSection state when switching worktrees

Three fixes for the re-integrate commits panel getting stuck:

1. Add `key={worktreeMetadata.path}` to IntegrateCommitsSection so React
   fully remounts it when switching to a different worktree, clearing any
   stale `ui` state (conflict, loading, ready) from the previous session.

2. Add `cancelled` flag to the conflict-restore effect so that an async
   callback started for session A cannot overwrite session B's state after
   the user switches sessions. Without this guard the stale callback could
   restore the old session's conflict state on top of the new session's
   computed-ready state.

3. Fix off-by-one in continueIntegrate: `moved` was returning
   `remaining.length` (N-1, after shifting currentCommit out) instead of
   `state.remainingCommits.length` (N), undercounting the commit that was
   moved by `cherry-pick --continue`.

* fix(worktree): add git-based fallback detection when store metadata is missing

Root cause: the existing worktreeMetadata resolution relies entirely on
cached store state (worktreeMap + availableWorktrees). When the store
lookup fails—due to hydrateSessionWorktreeMetadata deleting entries on
API failure, availableWorktrees being stale, or worktrees created
externally via CLI—the "Re-integrate commits" section permanently shows
"Available in worktree mode." with no way to recover.

Fix: add useDetectedWorktreeMetadata hook that performs a lightweight
git probe (`git rev-parse --absolute-git-dir --abbrev-ref HEAD`) when
the store-based lookup returns undefined. If the current directory is a
secondary git worktree, a minimal WorktreeMetadata is synthesised with
the correct projectDirectory and branch, allowing IntegrateCommitsSection
and other worktree features to function regardless of store state.

The store-based lookup remains the primary fast path; the git probe only
runs as a fallback and caches its result per directory.

* fix(worktree): fix detection command and pass current branch from git status

Two bugs in the fallback worktree detection hook:

1. `git rev-parse --absolute-git-dir --abbrev-ref HEAD` combines two
   independent rev-parse options whose combined output is unreliable –
   the two-line assumption (`lines.length < 2`) caused silent null
   returns, meaning the fallback never actually set worktreeMetadata.
   Now uses only `git rev-parse --absolute-git-dir` (single-line,
   deterministic output) for worktree detection.

2. The hook was called before `useGitStatus`, so no branch was
   available. Move the call to after `const status = useGitStatus(...)`
   and pass `status?.current` as `currentBranch`, eliminating the need
   for a second git command and keeping the branch in sync with the
   already-polled git status.

Also removes `detected` from the useEffect deps array – it was an
unnecessary dep that triggered a re-run on every detected state change.

* fix(worktree): use worktree toplevel path and reset stale metadata immediately

Two bugs in useDetectedWorktreeMetadata:

1. path was set from currentDirectory (the active sub-folder) instead of the
   worktree root. git rev-parse --show-toplevel now provides the actual
   worktree toplevel, so operations like `git worktree remove` receive a valid
   root path regardless of which sub-directory is open.

2. When currentDirectory changed with no storeMetadata, the hook kept
   returning the prior detected value until the async git probe finished.
   Calling setDetected(undefined) before launching the async task eliminates
   the stale-metadata window.
2026-04-01 18:33:49 +03:00
Nguyễn Ngô ThượngandBohdan Triapitsyn 6180f388e8 feat(json): add interactive JSON tree viewer with collapse/expand and rainbow colors (#786)
- Add JsonTreeViewer component with collapse/expand for nested objects and arrays
- Add rainbow colors by depth level using CSS color-mix() with syntax theme tokens
- Add virtualization support (@tanstack/react-virtual) for large JSON files (>200 nodes)
- Add JsonTreeView wrapper with Expand All / Collapse All toolbar
- Integrate into FilesView: tree/text toggle button, JSON file detection
- Integrate into ToolPart: auto-detect JSON tool outputs, render as tree
- Integrate into ToolOutputDialog: JSON tree view in expanded dialog
- Add jsonTreeUtils.ts: parse, flatten, path utilities

No new dependencies - uses existing @tanstack/react-virtual.
Colors derived from existing syntax.* theme tokens - works across all themes.

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-01 17:30:28 +03:00
Bohdan Triapitsyn d9fdd39f99 fix: restore proxied chat event streaming
- Add dedicated SSE passthrough for proxied chat events
- Keep generic API proxy behavior for non-stream requests
- Add regression coverage for nginx-safe SSE headers
2026-04-01 17:01:35 +03:00
Bohdan Triapitsyn d99417c4a0 chore: update changelogs for unreleased features and fixes across desktop and vscode packages 2026-04-01 16:24:45 +03:00
Bohdan Triapitsyn 6921d75019 fix(desktop): honor vibrancy toggle for window transparency
Tie macOS window transparency to the vibrancy setting so disabling vibrancy actually removes transparent backgrounds. Clarify settings copy that full transparency changes take effect for new windows or after restart.
2026-04-01 16:22:54 +03:00
shekohex 7b0e279a30 fix(server): strip hop-by-hop proxy response headers (#813)
* fix(server): strip hop-by-hop proxy response headers

* chore(ui): remove unused markdown runtime destructures
2026-04-01 16:19:20 +03:00
Dave Otero 1af2b9468f feat(chat): add arrow key navigation for thinking mode in model selector (#769)
* feat(chat): add arrow key navigation for thinking mode in model selector

Adds keyboard arrow key navigation for thinking mode selection within the model picker, enabling a fully keyboard-driven workflow for model and variant selection.

Changes:
- Model Selector: Added ←/→ arrow key handling to cycle thinking variants while picker is open
- Introduced transient state to track per-model variant selections during picker lifecycle
- Updated metadata display logic to show thinking mode only after adjustment with arrow keys
- Added contextual footer hints that appear only when highlighted model supports thinking variants
- Modified Enter key behavior to apply both selected model and pending thinking variant together
- Help Dialog: Added in-picker navigation shortcuts (↑↓ navigate, ←→ adjust thinking)
- Documentation: Updated CHANGELOG.md files with feature entry

Behavior:
- Navigate models with ↑↓, adjust thinking with ←→, press Enter to apply both
- Footer hints update dynamically based on highlighted model capabilities
- Thinking display persists only for models adjusted with arrow keys
- No-op for models without variants (clean, no feedback)

Testing:
- Type-check, lint, and build all pass
- Manual testing verified on dev server
2026-04-01 16:17:04 +03:00
Nguyễn Ngô Thượng 744b29c492 feat(files): add HTML preview support in file viewer (#772)
- Add isHtmlFile() helper to detect .html/.htm files
- Add htmlViewMode state for preview/edit toggle
- Add localStorage persistence for HTML view mode preference
- Show PreviewToggleButton for HTML files
- Render HTML in sandboxed iframe with srcdoc
- Inject base tag for relative CSS/JS/image paths to work
- Sandbox permissions: allow-scripts, same-origin, forms
- Reset view mode when switching files
2026-04-01 15:33:17 +03:00
JovinesandJovines f032df2298 fix(mobile): close settings drawers and remove extra top spacing (#770)
* fix(mobile): close side drawers when opening settings

* fix(mobile): remove duplicate top inset in drawers

---------

Co-authored-by: Jovines <jovines@qq.com>
2026-04-01 15:32:32 +03:00
Bohdan Triapitsyn 81c41388ac refactor: simplify file reference interactions by removing unused validation logic 2026-04-01 12:25:58 +03:00
Bohdan Triapitsyn c38e00bd85 perf(desktop): reduce CPU/GPU overhead in Tauri shell
- SSH monitor: adaptive polling 2s→10s after stabilization, cheap TCP
  probe before expensive SSH subprocess check
- SSH setup: exponential backoff in wait_for_master_ready and
  wait_local_forward_ready (250ms→2s cap)
- Health checks: exponential backoff (100ms→1s / 250ms→2s) instead of
  flat intervals
- Startup recovery poll: cap at 15 retries instead of infinite
- Remove webview log target in release builds (eliminates IPC overhead)
- Set global NO_PROXY env var at startup for all loopback addresses
- Remove reqwest::blocking feature; use raw TCP for sidecar shutdown and
  SSH health checks
- Disable pinch-to-zoom on macOS via WKWebView.setAllowsMagnification
- Add WebView2 browser args on Windows (proxy bypass + disable unused
  UI features)
- Add Cargo release profile: thin LTO, codegen-units=1, strip
- Extract apply_platform_window_config for consistent window setup
- Add vibrancy toggle in Appearance settings (macOS desktop only) with
  solid background fallback when disabled
2026-04-01 11:54:35 +03:00
YifanandBohdan Triapitsyn 14fc741cc9 feat(fs): add stat API for markdown file validation (#774)
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-01 10:18:05 +03:00
0e70422835 fix: sync draft chat config to draft target directory (#777)
When opening a new conversation draft for a different workspace,
OpenChamber kept using the config snapshot from the previously active
directory. The draft agent picker showed wrong agents and the first
send inherited a stale agent selection.

Use useConfigStore.activateDirectory() whenever the draft target is
established or changed:

- openNewSessionDraft: activate config on draft open
- overrideNewSessionDraftTarget: activate config on external override
- setNewSessionDraftTarget: activate config on user target change
- sendMessage (draft path): await activation before reading agent/model

Removes the inline agent resolution block in openNewSessionDraft that
duplicated logic already handled by activateDirectory.

Co-authored-by: hkay-dev <14947763+hkay-dev@users.noreply.github.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-01 10:06:10 +03:00
kalac2232and郭皓楠 b59040ff18 feat: escape HTML in user messages (#782)
- Add HTML escaping for user messages in Markdown mode
- Fix agent mention link rendering order issue
- Plain mode remains unchanged (uses React elements)

Tested:
- User messages: <div> now displays as &lt;div&gt;
- Agent mentions render correctly as clickable links in Markdown mode

Co-authored-by: 郭皓楠 <guohaonan@MacBook-Neo.local>
2026-04-01 09:49:58 +03:00
kalac2232 086cf26cd7 feat: add ZhipuAI provider to quota tracking system (#793) 2026-04-01 09:46:19 +03:00
jwcrystalandBohdan Triapitsyn 58d7713581 fix(server): strip compression headers in generic OpenCode proxy (#795)
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-01 09:45:19 +03:00
Baruch Vitorino 060b37777c fix(quota): correct minimax coding plan URL and usage calculation (#796)
* fix(quota): correct minimax coding plan URL and usage calculation

Fixes #759

- Change endpoint from www.minimax.io to api.minimax.io (fixes 403 error)
- Fix usage calculation: use intervalUsage/weeklyUsage directly instead of
  computing remaining (total - usage), which was showing inverted percentage
- Remove minimax-shared.js - providers are now completely independent
- minimax-coding-plan.js: complete provider for minimax.io
- minimax-cn-coding-plan.js: complete provider for minimaxi.com

* Update packages/web/server/lib/quota/providers/minimax-coding-plan.js

Signed-off-by: Baruch Vitorino <9778282+baruchvitorino@users.noreply.github.com>

* Update packages/web/server/lib/quota/providers/minimax-cn-coding-plan.js

Signed-off-by: Baruch Vitorino <9778282+baruchvitorino@users.noreply.github.com>

---------

Signed-off-by: Baruch Vitorino <9778282+baruchvitorino@users.noreply.github.com>
2026-04-01 09:44:58 +03:00
Ariel SandorandAriel Sandor 1f21ab0886 fix(quota): show actual overusage percentage for GitHub Copilot (#805)
Remove the Math.min(100, ...) clamp on usedPercent in the Copilot quota
provider so overusage flows through as the real value (e.g. 353%).
Update formatPercent to display values above 100% instead of clamping,
matching what the GitHub Copilot settings page reports.

The progress bar remains capped at 100% width via its own independent
clampPercent call, so only the label text is affected.

Co-authored-by: Ariel Sandor <39200214+arielsandor@users.noreply.github.com>
2026-04-01 09:39:16 +03:00
Zakir JiwaniandBohdan Triapitsyn 598e28462a Suppress SSE proxy errors on expected upstream socket close (#799)
When the upstream OpenCode process restarts, the fetch connection is
terminated by the remote side (UND_ERR_SOCKET / "other side closed").
Previously the catch block would log this as a warning and the VSCode
sseProxy would reject its run promise (sending an error to the webview)
even though the termination was normal. Now both handlers treat
UND_ERR_SOCKET the same way they treat an explicit abort.

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-01 09:38:44 +03:00