cd1816f63bd7b2ffbcabef586be396067e739bee
62
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
08e4ce5b99 | fix(chat): sync subagent prompting in context panel | ||
|
|
c22e1cbb15 |
refactor(chat): remove dead syntaxTheme plumbing
The Prism syntaxTheme prop is no longer read after code highlighting moved to the Shiki worker. Remove the now-dead prop threading and its source. - Drop syntaxTheme from interfaces, destructures, prop passes, and React.memo comparators across ChatMessage, MessageBody, ProgressiveGroup, ToolPart, TurnActivity, ToolOutputDialog, and ChatInput. - Drop the unused _syntaxTheme param from renderWebSearchOutput. - Remove the dead generateSyntaxTheme usages (ChatMessage memo, PlanView unassigned memo) and delete the now-unimported syntaxThemeGenerator module. |
||
|
|
25da8493fe |
fix: improve fallback model names
Shows readable model names when provider data is still loading Centralizes model display fallback logic Covers fallback formatting with tests |
||
|
|
3db5a3cc0b |
perf: avoid per-message review metadata checks
Compute review transfer state once per chat render Hide transfer actions when linked review sessions are inactive Remove session-list scans from individual message rows |
||
|
|
9c71119835 |
feat(ui): revert indicator with undo/redo, message list, and attachment restore (#1279)
* feat(ui): revert indicator with undo/redo, message list, and attachment restore Add bidirectional undo/redo with redo stack navigation and expandable revert indicator in StatusRow. List reverted messages with inline revert/fork actions. Restore file attachments on revert. - Add revert indicator with count, expandable popover, per-button spinner - Restore file/image attachments when reverting to a message - Clear previous attachments on revert when target has none - Restore-all bypasses redo stack for direct unrevert - Survive popover close/reopen without losing loading state - Fix flash when sending message after revert - Fix count disappearing on browser refresh - Remove dead code (undoStack, getRevertHistory, fork-from-here) - Fix toast grammar (Undid -> Reverted, Redid -> Redone) - Add i18n keys for revert popover across all locales * fix(ui): Greptile review fixes and i18n for revert toasts - Fix handleSlashUndo toast always showing [No text] (moved getSyncParts before revertToMessage) - Add inputStore rollback in revertToMessage catch (restore attachments + text on API failure) - Change portal ID to per-session (prevent multi-session collisions) - Add i18n keys for undo/redo/restored toasts across all 7 locales - Use formatMessage in store for localized toast strings * fix(ui): add missing sessionId to click-outside effect deps * fix(ui): remove unused sessionActions import in ChatMessage * fix(ui): derive revert dock from session state --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com> |
||
|
|
0ea573f766 |
refactor: redesign chat scroll system
The previous system layered three hooks (useScrollEngine, useChatScrollManager, useChatTimelineController) with overlapping responsibilities, four parallel ResizeObservers/MutationObservers, and six entry points to "scroll to bottom" (force-flag combinations, persistent follow loops, materialization recovery). This produced bugs where users could not break free of auto-follow during streaming: scrollbar drag, keyboard scrolling and find-in-page were not detected as user intent, and observers kept restarting the follow loop on every DOM mutation. The new architecture replaces the two low-level hooks with a single useChatAutoFollow that owns scroll behaviour end to end: - One state: 'following' or 'released'. No follow modes, no pin flags, no marker pixels. - One scroll writer: a lerp loop that runs only while the session is streaming and state is 'following'. Idle sessions never write scrollTop programmatically. - One user-intent detector: wheel up, touch drag down, keyboard (PageUp / Home / ArrowUp), pointerdown on the OverlayScrollbar thumb, and explicit releaseAutoFollow() calls all flip the state to 'released'. - A 1.2s grace period after explicit release: re-pin will not auto-engage inside this window, so a small wheel up cannot snap the user back even while they remain near the bottom spacer. - Re-pin and the scroll-to-bottom button share the same threshold: the height of the empty bottom spacer (10vh on desktop, 40px on mobile). Released users see the button only after they have scrolled past the spacer that already exists at the end of the chat. - Save/restore of scroll position uses ratio mapping, debounced at 150ms on user-driven scroll events; programmatic writes are masked via a short window so they never persist as user positions. - Container reattachment is detected via a useLayoutEffect probe over scrollRef.current. Listeners and observers re-bind when ChatViewport mounts after hydration or after the first message promotes a draft session into a real chat. - A pending-restore queue replays restoreSnapshot once the scroll container appears, fixing the case where a hydrating session landed at the top instead of the bottom. Removed: useScrollEngine.ts, useChatScrollManager.ts, the persistent follow loop with its own ResizeObserver+MutationObserver pair, the materialization-recovery .finally resume that yanked idle users to the bottom on transient sync gaps, and the openchamber:session-reselected event (re-select still works through the existing onSessionSelected callback). The openchamber:chat-force-scroll-bottom event remains for synthetic-message paths like git-message generation. Net change: ~1300 lines removed, two hooks replaced with one, one observer pair instead of four. |
||
|
|
6595322f1a |
fix: show tablet actions without hover
Makes hover-only controls visible on tablets Preserves existing mobile and desktop layouts Covers chat, session sidebar, file, tab, and picker actions |
||
|
|
4ad5d2f4b7 | fix(ui): tolerate invalid message parts | ||
|
|
6cb5e4342f | fix(chat): soften aborted turn message | ||
|
|
0bb30887b7 |
Improve assistant message action placement for split responses (#1032)
* Improve assistant message action placement for split responses * Add toggle for split assistant message actions * Address split message actions review feedback * Fix inline assistant actions --------- Co-authored-by: vhqtvn <8930337+vhqtvn@users.noreply.github.com> Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com> |
||
|
|
d40041fccd | Fix startup connection and chunk recovery | ||
|
|
ecb22e19c3 |
perf: lazy-load heavy dependencies (MarkdownRenderer + CodeMirror languages) (#997)
* perf: drastically improve cold-start, bundle size, and streaming performance
Cold-start optimizations:
- main.tsx: Remove blocking await on prefs I/O — render immediately with
defaults, hydrate persisted settings asynchronously. Cuts 50-200ms from
time-to-first-paint.
- bootstrap.ts: Split directory bootstrap into 3 phases:
* Phase 1 (blocking): path, config, provider, session status — minimum
data needed to render UI. Mark status complete after this phase.
path.get and session.status must both succeed; they have no fallback.
* Phase 2 (deferred): agents, commands, mcp, lsp, vcs, questions,
permissions — fetched after first paint without blocking.
* Phase 3 (lazy): session messages — loaded without blocking init.
- App.tsx: Keep identical provider tree before/after init to prevent
full subtree remount when isInitialized flips. FireworksProvider and
VoiceProvider are lightweight shells; overlays deferred until init.
Bundle-size optimizations:
- App.tsx + MainLayout.tsx + VSCodeLayout.tsx: Code-split heavy views
(SettingsView, GitView, DiffView, TerminalView, FilesView, PlanView,
OnboardingScreen, SettingsWindow, MultiRunWindow) with React.lazy.
Views load on demand when user switches panels.
- vite.config.ts: Lower chunkSizeWarningLimit from 1200KB to 500KB.
Streaming render optimizations:
- streaming.ts: Throttle streaming store writes ~60Hz → ~1Hz. Busy-session
only scan (Set, O(1)).
- MessageList.tsx: Lower virtualization threshold 40 → 15.
- ChatMessage.tsx: React.memo with areRenderRelevantMessagesEqual.
- MarkdownRenderer.tsx: React.memo with explicit prop comparators.
* fix: address Greptile review feedback on bootstrap and provider tree
- bootstrap.ts: Tighten Phase 1 error guard. path.get and session.status
must both succeed; they have no global fallback.
- bootstrap.ts: Replace dead .catch() on Promise.allSettled() with .then()
that inspects individual results for errors.
- App.tsx: Keep identical provider tree before/after init to prevent full
subtree remount when isInitialized flips.
* perf: lazy-load heavy dependencies (MarkdownRenderer + CodeMirror languages)
MarkdownRenderer dynamic import:
- Move heavy implementation (marked, react-markdown, beautiful-mermaid,
react-syntax-highlighter, ~1500 lines) to MarkdownRendererImpl.tsx
- Replace MarkdownRenderer.tsx with thin lazy wrapper using React.lazy
- All 11 existing imports work unchanged — no consumer code modified
- Full markdown stack loads on first render of markdown content
CodeMirror language lazy loading:
- languageByExtension.ts: remove static imports for 10+ less-common
language packages (@codemirror/lang-go, lang-rust, lang-sql, etc.)
- Keep only 6 most common languages static: javascript, json, css, html,
markdown, python, shell
- Less common languages return null from languageByExtension, causing
callers to fall back to loadLanguageByExtension which dynamically
loads from @codemirror/language-data
- Reduces initial bundle by ~200KB+ of language parsers
---------
Co-authored-by: Shyamalan Kannan <yabuku@Shyamalans-MacBook-Pro.local>
|
||
|
|
285c3bcaae |
Migrate desktop shell from Tauri to Electron (#964)
* feat(electron): scaffold Electron desktop package
Main + preload + ssh manager, packaging scripts, icons, root build/lint/type-check wiring.
* feat(ui): add Electron runtime detection and desktopNative facade
isElectronShell via window.__OPENCHAMBER_ELECTRON__, isDesktopShell now covers both. desktopNative wraps window/title/theme calls so UI avoids direct Tauri imports. revealDesktopPath added.
* refactor(ui): route window/title/theme/export through desktopNative
SessionSidebar, MultiRunLauncher, useWindowTitle, ThemeSystemContext, exportSession drop direct @tauri-apps imports.
* refactor(ui): treat all desktop shells uniformly
device.ts switches Tauri-only checks to isDesktopShell. Header OpenInApp button uses actionDirectory so it falls back to the active project path.
* fix(ui): menu Copy clipboard fallback and softer sidebar tint
useMenuActions falls back to Clipboard API for the native Copy action when the page doesn't intercept. cssGenerator lowers sidebar strong/soft alpha so the tinted surface reads gentler.
* chore(electron): mirror Tauri build/type-check script shape
build script becomes no-op so root 'bun run build' skips packaging. Syntax validation (node --check) moves into type-check. electron:build root script still runs full sidecar+bundle+electron-builder.
* fix(electron): sync app identity, preload path, boot outcome, dev entry
Read version from packages/electron/package.json so 'electron ./main.mjs' dev entry reports the app version instead of Electron's. Bump electron package to 1.9.6 for workspace parity.
Resolve preload via app.getAppPath() in prod (bundle lives in dist-bundle while preload.mjs ships at app root).
Compute and inject __OPENCHAMBER_DESKTOP_BOOT_OUTCOME__ in main + preload so the loading gate dismisses (mirrors Tauri Rust injection).
Dev entry uses ./main.mjs to bypass the stale dist-bundle so source edits apply.
* refactor(open-in-app): split directory and file flows
Header button now opens the project/worktree directory only — drop activeFilePath prop and its Header prop passthrough. FilesView editor dropdown opens the active file only via new openDesktopFileInApp.
Electron main.mjs mirrors Tauri's open-chain logic: buildOpenProjectSpecs (finder/terminal direct, vscode-like via CLI -n, JetBrains via open -na --args) and buildOpenFileSpecs (finder -R reveal, terminal opens parent dir, editors via CLI or open -a). runSpecChain falls through specs until one exits 0.
* fix(files-view): keep floating toolbar mounted while its dropdowns are open
Portalled Base UI menu popups render outside floatingToolbarRef. The document mousedown listener and onMouseLeave collapsed the toolbar as soon as the popup appeared, unmounting the DropdownMenu root and swallowing clicks on its items. Track open dropdowns via onOpenChange and skip the collapse while count > 0; also ignore mousedowns that land inside a dropdown-menu-content/item.
* feat(electron): add quit confirmation with risk poller
Mirrors Tauri's macOS-only behavior: poll /api/openchamber/scheduled-tasks/status and /api/openchamber/tunnel/status every 5s. If active tunnel or running/enabled scheduled tasks are detected, Cmd+Q / dock Quit / menu Quit shows a native warning dialog listing reasons; otherwise quit proceeds silently.
performConfirmedQuit persists window state, kills sidecar, shuts down SSH, and fires a 1500ms unref'd safety timeout that calls app.exit(0) if the normal quit sequence stalls.
* feat(notifications): fix payload parsing, restore-on-click, session deep-link
Normalize input so both sidecar stdout path (flat) and UI IPC path ({ payload: {...} }) work; previous destructuring missed requireHidden (camelCase) and the payload wrapper so notifications showed with empty body.
Click handler restores the window if minimized, shows it if hidden, and focuses. When the notification payload carries sessionId, emit openchamber:open-session which the App listener routes to setCurrentSession — matches the PWA service-worker deep-link behavior. macOS notifications now also use sound 'Glass' for parity with Tauri.
* chore(electron): bump to Electron 41 + latest updater/context-menu
electron ^38.2.0 -> ^41.2.1
electron-updater ^6.6.2 -> ^6.8.3
electron-context-menu ^4.0.4 -> ^4.1.2
Dev boot verified: main process starts, preload exposes globals, API server + quit risk poller + autoUpdater all initialize without errors.
* fix: keep todo row alignment stable when expanding text
Keep checkbox and action buttons vertically centered in collapsed todo rows
Prevent first todo line from shifting when expanding to multiple lines
* fix: make commit highlights visible and input behavior reliable
Switch commit message field to native textarea for predictable auto-resize
Fix AI highlights append flow so inserted text is applied consistently
Make chat scroll-to-bottom control fully circular
* style: increase chat bubble corner radius consistency
Use larger radius for user chat message bubbles
Match chat input container radius to user message styling
* feat(electron): adopt OpenCode playbook improvements
mac: hardenedRuntime + entitlements.mac.plist + notarize + dmg.sign for Apple notarization parity.
single-instance lock + openchamber:// protocol with session/project/host routing (host switch done fully in main via activateMainWindow).
setAppUserModelId for Win toast identity; proxy-bypass-list switch; chdir(homedir) for Finder-launch cwd safety.
shell env probe (\$SHELL -il -> -l) merged into sidecar spawn; PATH deduped.
electron-log with 5MB rotation + 7-day cleanup; autoUpdater.logger wired; startup info log.
webContents zoom locked to 1 (zoom-changed + did-finish-load).
UI: openchamber:open-project -> useDirectoryStore.setDirectory.
* fix(electron): make bootOutcome mutable across re-navigation + project deep-link
host deep-link used to land on chooser because contextBridge exposed bootOutcome as read-only; initScript re-assignment became a silent no-op. drop preload's contextBridge for bootOutcome, inject it via main-world initScript, and move injection from did-finish-load to dom-ready so it lands before React mounts.
project deep-link updated currentDirectory only; activeProjectId stayed stale so the sidebar didn't highlight the new project. switch to projectsStore.setActiveProject (or addProject for new paths) which updates both.
add log.info around deep-link dispatch + host switch for diagnostics.
* fix(electron): desktop_hosts_set IPC args + persist initialHostChoiceCompleted + re-eval bootOutcome
UI calls invoke('desktop_hosts_set', { input: {...} }) but main was reading args.config — every onboarding 'i've completed installation' / host-dialog save wrote nothing, so desktopDefaultHostId stayed null and the chooser screen looped forever.
also:
- writeDesktopHostsConfig now persists desktopInitialHostChoiceCompleted so the tauri-compat flag survives writes.
- readDesktopHostsConfig returns initialHostChoiceCompleted so the UI-side config mirror is complete.
- after writing hosts, recompute state.bootOutcome + state.initScript; a subsequent window.location.reload() picks up target=local/status=ok via dom-ready injection without needing a full app restart.
- app.setName('OpenChamber') early (pre log.initialize) so electron-log logs land in ~/Library/Logs/OpenChamber/ instead of the package-derived '@openchamber/electron' path.
* chore(electron): rename appId to dev.openchamber.desktop
ai.opencode.* is the OpenCode team's reverse-DNS namespace; OpenChamber should not squat there. now that we're on Electron, drop the tauri-era inherited identifier and claim our own under openchamber.dev.
user-facing productName stays "OpenChamber". tauri identifier left as-is — legacy shell on the way out.
* feat(ci): add electron build+notarize+publish jobs to release workflow
three new jobs in release.yml, running in parallel with tauri:
- build-desktop-electron-macos: matrix(arm64, x86_64) on macos-26; installs Developer ID via keychain, runs build:sidecar + bundle:main + electron-builder --mac --arch <> --publish=never (with APPLE_ID / APPLE_APP_SPECIFIC_PASSWORD / APPLE_TEAM_ID env mapped from existing secrets). verifies hardened runtime, stapled notary ticket, required entitlements. uploads DMG/ZIP/blockmaps to the release and emits per-arch latest-mac.yml as a GH artifact.
- combine-electron-manifests: downloads latest-yml-*-apple-darwin artifacts, runs the existing finalize-latest-yml.mjs to merge per-arch files entries into a single latest-mac.yml, uploads combined yml to the release.
- finalize-release: now also waits on the two new jobs before flipping the draft release to published.
also: explicit artifactName in electron-builder config so arm64 and x64 dmg/zip never collide.
electron-updater in main.mjs (setFeedURL btriapitsyn/openchamber) fetches this latest-mac.yml on desktop_check_for_updates; downloadUpdate / quitAndInstall wire through our existing IPC handlers unchanged.
* docs: future-agent brief for tauri -> electron auto-update cutover
self-contained plan for the one-shot migration release that carries existing tauri installs into the electron shell via tauri's updater. written so a fresh agent with no branch context can execute it.
covers: the trick (repackage signed electron .app as a tauri tarball, minisign with existing TAURI_SIGNING_PRIVATE_KEY), workflow surgery on release.yml, rollback plan, validation steps against a real tauri install, and edge cases (CFBundleIdentifier change, notification perms re-prompt, deep-link re-registration).
* docs: soften framing of cutover playbook (no user-shaming)
* chore: mark electron as primary desktop shell; tune dmg installer window
AGENTS.md: explicit note that new desktop work lands in packages/electron/, packages/desktop/ (tauri) is maintenance-only until the cutover described in docs/TAURI_TO_ELECTRON_CUTOVER.md. updated runtime/entry-points/build-commands sections accordingly.
electron/package.json build.dmg: cleaner title ("OpenChamber 1.9.6" without -arch suffix), 660x400 window matching the tauri layout users are used to, icon size 128, explicit app/Applications positions.
* refactor(web): drop bun-specific runtime deps from server
- 11 test files migrated bun:test -> vitest; API (describe/it/expect) is drop-in; all 73 tests pass under vitest run.
- bun:sqlite -> better-sqlite3 in git/service.js::syncSandboxesToOpenCodeDb. api shift is db.query().get()/run() -> db.prepare().get()/run().
- add "test": "vitest run" script in packages/web.
no production code used Bun.* APIs; server is Express-on-Node already. this commit removes the remaining bun-runtime shape so the server module can be imported and booted inside an electron main process.
* feat(electron): boot web server in-process, drop sidecar subprocess
the electron main process now imports @openchamber/web/server/index.js as a workspace dependency and calls startWebUiServer({...}) directly. the returned handle exposes getPort() / stop() and the notification emitter takes an onDesktopNotification callback, so we no longer spawn a bun-compiled sidecar binary and no longer parse stdout for the one-line notify protocol.
- packages/electron/package.json: +@openchamber/web (workspace:*); extraResources drops 'sidecar'; build:sidecar script renamed to build:web-assets (kept the vite build step, dropped the bun compile step).
- packages/electron/main.mjs: remove spawn/kill-stale-sidecar/sidecar path resolver/stdout-prefix parser; rewrite spawnLocalServer to probe a free port (stored | DEFAULT_DESKTOP_PORT | OS-assigned) then import server and await startWebUiServer; killSidecar calls handle.stop({ exitProcess: false }); hoist user shell env (PATH, etc.) onto process.env once so opencode / git / rg children still inherit the expected runtime environment.
- packages/web/server/lib/notifications/emitter-runtime.js: accept an onDesktopNotification callback (late-bindable via setOnDesktopNotification). when set, notifications are dispatched through the callback instead of process.stdout; tauri path still uses stdout when no callback is bound.
- packages/web/server/index.js: main() wires options.onDesktopNotification to notificationEmitterRuntime.setOnDesktopNotification.
- release.yml + AGENTS.md updated for the new script name + runtime shape.
payoff: -300ms cold start on mac, single process in activity monitor, no stdio IPC, no bun binary in the packaged app. tauri sidecar path is untouched.
* build(electron): rebuild native deps explicitly, bump electron-builder
the previous build failed because electron-builder 24.13.3 tried to run \`bun rebuild\` on native deps (better-sqlite3, node-pty) and bun has no rebuild subcommand; it also couldn't find prebuild-install because bun hoists under node_modules/.bun/<pkg>@<ver>/ and never populates node_modules/.bin for transitive deps.
fix:
- bump electron-builder devDep to ^26, whose packageManager detection understands bun workspace layouts.
- add @electron/rebuild devDep + scripts/rebuild-native.mjs. the script rebuilds better-sqlite3 / node-pty / bun-pty against the installed electron version before electron-builder is invoked.
- set build.npmRebuild=false so electron-builder no longer attempts its own broken PM-based rebuild.
- package script: build:web-assets -> bundle:main -> rebuild:native -> electron-builder.
verified: CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:build produces signed-ad-hoc dmg/zip/blockmap/latest-mac.yml; artifacts land under packages/electron/dist as expected. cold-start from Applications should work (native bindings now match electron 41 node ABI).
* fix(electron): externalize web server + native deps from main bundle
the ESM bundle was statically inlining @openchamber/web transitively, which pulled in bun-pty/src/terminal.ts with its top-level \`import { dlopen } from "bun:ffi"\`. node's ESM loader parses every static import when the bundle loads, so the bun:ffi scheme crashed the packaged app at startup with ERR_UNSUPPORTED_ESM_URL_SCHEME — the runtime guard (if (globalThis.Bun) { await import('bun-pty') }) never got a chance to skip it.
fix: bundle-main.mjs marks @openchamber/web (+ its bun-pty / node-pty / better-sqlite3 transitives) as external. the dynamic \`await import('@openchamber/web/server/index.js')\` in main.mjs stays a runtime resolution; the conditional bun-pty import stays dynamic; native modules load from node_modules via the standard resolver.
* perf(web): classify UI-only deps as devDependencies, shrink packaged app
packages/web is a hybrid package: server code in server/, react UI source in src/, compiled UI output in dist/. the server serves dist/ as static files — it never imports react/radix/codemirror/etc. at runtime. but electron-builder, npm install, and similar tools treat everything under "dependencies" as shipping surface, so all of react + @radix-ui/* + @codemirror/* + @fontsource/* + @simplewebauthn/browser + cmdk + ghostty-web + ... were landing in app.asar even though the same code is already baked into dist/ chunks.
move ~24 UI-only packages to devDependencies. vite + its plugins still install them in dev (bun install fetches devDependencies in workspaces), so \`bun run build\` is unchanged. consumers doing \`npm install @openchamber/web\` no longer pull ~150MB of unused browser-side modules.
measured on aarch64 darwin build:
- app.asar: 281MB -> 44MB (-237MB, -84%)
- .dmg: 320MB -> 132MB (-59%)
- .zip: 305MB -> 129MB (-58%)
verified type-check, ui build, 73 vitest tests, packaged launch.
* chore(electron): center dmg installer icons, use cream brand background
dmg-builder 26 ignored our previous dmg.contents positions against its template background (they stayed at template coords, producing misalignment with the drawn arrow). switch to a solid backgroundColor (#FFFCF0, the splash light tone) so the template image is dropped entirely and our coordinates are authoritative. window tuned to 540x340, iconSize 100, iconTextSize 13.
dmgbuild treats contents coordinates as icon *centers* (not top-left), so with iconSize=100 in a 540 window, x=180 and x=360 place left and right clusters with equal 130px gaps on both sides of the window. y=140 vertically centres the icon+label pair.
* fix(electron): eliminate main-thread freezes in in-process server
Three blocking paths were running sync work on the Electron main event
loop, causing multi-second UI freezes under the new in-process server:
- package-manager.detectPackageManagerDetails fired spawnSync(pnpm/npm/
yarn/bun bin -g) with 10s timeouts. In desktop runtime PM detection is
pointless (app is .app bundle, updates via electron-updater) — short-
circuit when OPENCHAMBER_RUNTIME=desktop. This was the ~5s freeze.
- buildInstalledApps iterated 22 OPEN_IN_APPS × spawnSync(mdfind, sips).
Converted to execFile promises so child waits yield to the loop.
- orphan-project-file recovery re-scanned disk on every settings read
(3+/s from fs/list/etc). Cache the outcome per process lifetime.
Also: resolveProjectDirectory prefers settings.lastDirectory over
activeProjectId so file-open from sidebar/chat doesn't 400 with
"Path is outside of active workspace" after the user navigates.
Plus dropdown typeahead fixes in DesktopHostSwitcher/BranchSelector:
stopPropagation on input keys so cmdk doesn't swallow typing.
* feat(electron): restore desktop LAN access for in-process server
spawnLocalServer now reads settings.desktopLanAccessEnabled and binds
on 0.0.0.0 when enabled, so phones/tablets on the same Wi-Fi can open
the app via http://<lan-ip>:<port>. Adds desktop_get_lan_address IPC
(UDP-connect route lookup with networkInterfaces fallback) for the
settings UI to show the reachable URL.
UI and settings plumbing already existed from the sidecar build; only
the Electron main-process wiring was missing.
* chore: added electron package to version bump script
* fix(electron): address PR review — harden IPC surface + polish
P1 security:
- Gate openchamber:invoke and openchamber:dialog:open by webContents
origin. Only local (loopback / dev file://) senders can call desktop_*.
Blocks remote hosts loaded via DesktopHostSwitcher from reading local
files, opening apps, relaunching, etc.
- desktop_read_file now refuses paths outside $HOME / tmpdir and denies
.ssh/.aws/.gnupg/.config/gh/credentials + .env/.pem/.key by name
(defense-in-depth behind the origin gate).
P2:
- webPreferences.sandbox:false: add comment explaining preload needs Node
(contextBridge+ipcRenderer) and why flipping to true would break IPC.
- desktop_set_vibrancy: comment the intentional no-op (no Electron
equivalent for the Tauri NSVisualEffectView path), drop requiresRestart.
- desktopNative.ts: replace isTauriShell() guards with isDesktopShell()
so the semantics match (previous check worked only because Electron
preload exposes a __TAURI__ shim).
- AGENTS.md: correct entry description — server runs in-process, not as
a sidecar subprocess.
* fix(electron): stop leaking desktop shell APIs to remote renderer pages
Preload was exposing __TAURI__ and __OPENCHAMBER_ELECTRON__ unconditionally,
so after DesktopHostSwitcher navigated the window to a remote OpenChamber
instance the remote UI saw isDesktopShell() === true and tried to invoke
desktop_* IPC. The main-process origin gate then threw "IPC not available
for this origin", surfacing as a user-visible error on the onboarding
screen of the remote.
Preload re-runs on cross-origin navigation; compute current origin up
front and only expose the shell globals + the openchamber:emit listener
when the document is loopback / state.localOrigin / file://. Remote
pages now look like a plain web runtime — no IPC path to reject.
* fix(electron): restore remote UI shell integration via per-command gate
Previous commit stripped __TAURI__ / __OPENCHAMBER_ELECTRON__ from remote
pages wholesale, which broke DesktopHostSwitcher for anyone switched to
a remote instance: no hosts list, "Unknown" probe status, open-in-new-
window dead. Also lost window chrome affordances that the remote UI
needs to render correctly inside the Electron shell.
Switch from an origin-level gate to a per-command allowlist:
- preload.mjs exposes __TAURI__ and __OPENCHAMBER_ELECTRON__ on every
page (shell identity + IPC channel). __OPENCHAMBER_LOCAL_ORIGIN__ and
__OPENCHAMBER_MACOS_MAJOR__ also go everywhere since HostSwitcher and
window chrome depend on them and neither grants capability.
__OPENCHAMBER_HOME__ stays local-only (leaks the OS username and is
misleading if consumed as a workspace hint on a remote page).
- main.mjs ipcMain.handle accepts a curated COMMANDS_SAFE_FOR_REMOTE set
(hosts_get, host_probe, new_window, new_window_at_url, set_window_*,
is_window_fullscreen, start_window_drag, get_app_version,
get_lan_address). Filesystem, shell.openPath, installed-apps scans,
app relaunch, auto-update, hosts_set, dialog:open, read_file stay
local-only — remote UI doesn't need them and can't weaponize them.
* ci(release): rebuild native modules against Electron ABI before packaging
Electron job skipped rebuild:native so bun install's Node-ABI builds of
better-sqlite3/node-pty/bun-pty shipped into the asar — packaged app
would crash on require. Local bun run package runs the step via
scripts/rebuild-native.mjs (npmRebuild is disabled in package.json);
mirror it in CI and pass ELECTRON_BUILDER_ARCH so the x64 matrix
cross-builds from the arm64 runner.
Tauri job untouched — both builds continue to produce side-by-side
release artifacts (latest.json for Tauri, latest-mac.yml for Electron)
so each shell's updater finds its own manifest.
* ci(release): split Electron arm64/x64 onto native macOS runners
Both Electron matrix entries were running on macos-26 (arm64) and
cross-building x64 from there. Works for Rust/Tauri; brittle for
native Node modules — better-sqlite3, node-pty, bun-pty (with its
rust-pty crate) each have their own cross-target quirks.
Pin arm64 → macos-14 and x64 → macos-13 so node-gyp and
@electron/rebuild build against the host arch. ELECTRON_BUILDER_ARCH
now just mirrors the runner for clarity.
* Revert "ci(release): split Electron arm64/x64 onto native macOS runners"
This reverts commit f217880e49609cf1418818af0f837b333dbb6f42.
* ci(test-build): add Electron DMG job to arm64 dispatch workflow
Parallel job to the existing Tauri DMG builder, same runner + Apple
cert path. Mirrors the release workflow steps (build:web-assets,
bundle:main, rebuild:native, electron-builder) so maintainers can
smoke-test a signed+notarized Electron DMG before merging.
* ci: use electron-builder v26 boolean arch flags
v26 dropped --arch <name> in favour of per-arch booleans (--arm64,
--x64, etc.). Test build was failing at dispatch time; release job
had the same bug latent. Switch both to the supported form.
* fix(electron): route external links to the system browser
<a href> clicks and window.open calls with non-local URLs were loading
inside the Electron BrowserWindow (or spawning a second Electron window
as a makeshift browser). Add an origin-aware navigation guard to each
window: loopback / state.localOrigin / configured desktop hosts keep
their existing in-window behaviour (HostSwitcher, in-window probes);
everything else hands off to shell.openExternal so http/https links
open in the user's default browser.
|
||
|
|
b91a72c74b |
fix(chat): replace hover bridge with padding to unblock desktop interactions (#885)
* fix(chat): replace hover bridge with padding to unblock desktop interactions PR #826 removed pointer-events-none from the hover bridge div to fix short user message revert button hover, but the transparent 44px full-width bridge blocked all interactions (clicks, text selection) with messages below it on Tauri desktop where the rendering difference made the overlay consume pointer events across the entire message area. Replacing the bridge div approach with pb-12 padding on the message bubble container (max-w-[85%]) when sticky inline hover is active. This extends the hover hit area downward within the bubble's own padding, maintaining continuous hover path from bubble to action buttons without any overlay that could block sibling elements. The padding approach works because: - The 48px bottom padding extends max-w-[85%]'s hover area to cover the gap between bubble bottom and the absolute-positioned buttons - Hovering the padding counts as hovering group/user-shell (parent) - No absolute-positioned invisible layer means nothing blocks the next message's interactive content * fix(chat): reduce hover padding from pb-12 to pb-5 for tighter spacing |
||
|
|
4fd1d68eb9 | fix(chat): allow revert button hover on short user messages (#826) | ||
|
|
46d166e205 |
fix: drop stale chat memo boundaries
Remove remaining chat row and body memo comparators that were still keeping finished background session responses blank or stale in the UI. |
||
|
|
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 |
||
|
|
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 |
||
|
|
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. |
||
|
|
c9e31a0e6c |
perf: harden sync architecture and modularize runtimes (#803)
* fix: added desktop app background throttling
* perf: add streaming debug metrics panel
- Show streaming performance metrics in the debug panel
- Auto-enable stream profiling while the panel is open
- Add JSON export for sharing UI and VS Code metrics
* perf: batch streaming updates more aggressively
- Buffer message deltas and metadata updates to cut render churn
- Skip no-op part updates before they touch the message store
- Fix the desktop debug panel shortcut binding
* perf: split streaming event handling and coalesce deltas
- Move streaming content events onto a dedicated fast path
- Defer non-critical stream side effects off the hot path
- Merge repeated message delta events before they reach the UI
* perf: isolate streaming rows from chat rerenders
- Memoize chat rows against render-relevant message changes only
- Read live assistant text directly from store to narrow streaming updates
- Split the active streaming entry from the stable message list path
* perf: streamline chat streaming and SSE proxying
- Reduce chat rerenders around the active streaming path
- Simplify server SSE forwarding to avoid duplicate proxy work
* fix: preserve the first streaming text chunk
- Show the initial text chunk immediately before batched deltas arrive
- Bypass batching for the first text or reasoning part update
- Keep later streaming updates buffered for performance
* perf: align streaming/render hot paths with opencode parity
* perf: harden turn/cache stability and stale delta suppression
* fix: stabilize chat rendering and disable timeline interactions
- Disabled timeline dialog access from shortcuts, commands, and chat input
- Reduced chat render churn by simplifying message list and turn staging behavior
- Improved session-switch stability to prevent update-depth crashes
* perf: track static message rerenders during streaming
* perf: reduce sorted-mode activity rerender fanout
* perf: reduce chat rerender fanout and add active-turn metrics
- Reduced sorted-mode rerender coupling by tightening turn context propagation
- Added a metric for static rerenders outside the active turn during streaming
- Exposed new chat render counters in the debug panel for parity tracking
* fix: keep sorted activity mounted while stream grows
* fix: stabilize session and history scroll rendering
* refactor: decouple server routes from index
* refactor: extract fs module from server index
* refactor: move opencode route ownership into module
* refactor: extract notification route registration
* refactor: extract opencode and notification runtimes from index
* refactor: extract settings runtime and complete server modularization pass
* refactor: modularize server config, skills, icons, and tunnel routes
* refactor: extract server modules from monolithic index.js
Split proxy, routes, runtime helpers, and notification emitter
into dedicated modules under packages/web/server/lib/.
* refactor: replace session/message stores with SSE-driven sync layer
Delete ~9200 lines of old architecture (useEventStream, messageStore,
sessionStore, useSessionStore, questionStore, useTodoStore, client SSE).
New sync layer: event pipeline with coalescing + 16ms flush, pure event
reducer, per-directory child stores with LRU eviction, cursor pagination,
optimistic updates, deferred timeline staging, text throttle.
Migrate all UI consumers to sync hooks (useSessionMessages,
useSessionMessageRecords, useSessionStatus, useSessionPermissions, etc).
Strip session-ui-store to UI-only state, delegate SDK ops to
session-actions with abort-if-busy, optimistic store updates, and
response merging for revert/fork/archive/delete.
Add notification-store for SSE-driven session attention tracking,
cross-directory GlobalSessionStatusStore for sidebar indicators,
client-side diff snapshot sanitization to prevent memory bloat,
and revert message filtering via useVisibleSessionMessages.
* feat: notification store, session actions, activity detection
Add notification-store.ts for SSE-driven attention tracking.
Add sanitize.ts to strip diff snapshot memory bloat.
Add session-actions.ts with optimistic revert/fork/archive/delete.
Improve useSessionActivity with incomplete-message fallback.
Delete useServerSessionStatus polling hook.
* fix: add directory param to all SDK calls, fix command/shell/abort routing
All SDK calls in session-actions.ts now pass directory parameter —
required by OpenCode server to scope session operations. Without it,
abort, commands, revert, fork, and other operations returned 500.
Add routeMessage() in session-ui-store for shell mode (session.shell),
slash commands (session.command), and normal prompts. Command lookup
checks both sync child store and useCommandsStore. Handle /compact
locally via session.summarize().
Implement getContextUsage() to restore header context usage display —
reads token counts from last assistant message in sync store.
* refactor: replace custom API proxy with http-proxy-middleware
Remove ~280 lines of custom proxy code: forwardSseRequest,
forwardGenericApiRequest, collectRequestBodyBuffer, header
manipulation, hop-by-hop filtering, SSE block buffering.
Replace with single createProxyMiddleware() call that handles
SSE streaming, large bodies, and timeouts out of the box.
Dynamic router for OpenCode port changes after restarts.
Auth headers injected via proxyReq hook.
Keep: readiness gate, Windows session merge, API prefix detection.
* perf: targeted event draft cloning to fix streaming render cascade
Event handler was eagerly cloning all state slices on every event,
breaking Zustand selector referential equality. During streaming
(~60 events/sec), this caused every subscriber to re-render regardless
of which slice actually changed.
Now only clones fields the specific event type mutates. Also extracts
StatusRowContainer to isolate high-frequency useAssistantStatus
subscription, removes dead messageStreamStatesMap subscription from
ChatContainer, and narrows useAssistantStatus to only track last
assistant message parts.
MessageList renders: 1972 → 296 per streaming session (-85%).
* fix: null safety for sync state slices
Add defensive ?? {} guards on permission, question, session_status,
and message record access. Prevents crashes when child store state
is partially initialized during bootstrap.
* perf: dedup inflight SDK calls, extract concurrency util, delay PR tracking
Extract mapWithConcurrency to shared lib/concurrency.ts. Add in-flight
dedup for loadProviders/loadAgents to prevent concurrent duplicate SDK
calls. Delay initial PR background tracking by 5s to reduce startup
CPU burst.
* fix: header session lookup across all child stores
Session title and context panel click failed when session belonged to
a different directory than the current child store. Fall back to
getAllSyncSessions() to search all initialized stores.
* chore: bump @opencode-ai/sdk to 1.3.5
* docs: add sync event handling guide
* Optimize session prefetch and improve delete/archive UX
- Add settlement delay to session prefetch to avoid race conditions on
rapid session switches
- Reduce git diff prefetch and session cache limits for better performance
- Implement optimistic UI updates for session delete/archive operations
with proper rollback on failure
- Wire session prefetch hook into SessionSidebar with sync integration
* Add file content cache and sync optimizations
- Wrap FilesAPI with in-memory LRU cache for file content with dual
constraints (entry count and byte size)
- Optimize chat timeline scroll restoration using useLayoutEffect
- Preserve React references in message and part arrays to prevent
unnecessary re-renders when prepending history
- Add session prefetch TTL cache to prevent redundant fetches
- Integrate session prefetch cache clearing with eviction flow
* Improve session sidebar error handling and add diff prefetch filtering
Load active and archived sessions independently using Promise.allSettled
to prevent one failure from blocking the other. Add retry logic to session
API calls and skip large files during diff prefetch to improve performance.
* Replace sendMessage with optimisticSend wrapper
Introduces optimistic UI updates for normal chat messages to provide
instant feedback. Messages appear immediately in the UI while the API
call executes in the background, with automatic rollback on errors.
* perf: split stores, proper optimistic send, fix revert/directory bugs
- split session-ui-store into voice/input/selection/viewport stores
to reduce subscriber re-evaluation during streaming
- wire optimisticSend through useSync shadow Map infrastructure
matching OpenCode's pattern (no heuristic part detection)
- port OpenCode Identifier.ascending ID format for correct sorting
- pass messageID to promptAsync to prevent duplicate messages
- fix worktree directory not propagating to session actions
(dynamic dir() via opencodeClient.getDirectory)
- fix setCurrentSession accepting directoryHint for new sessions
- fix revert not hiding messages (session limit was 5, bumped to match loaded count)
- fix revert optimistic message removal from store
- fix load-more flicker (useLayoutEffect scroll compensation)
- add prefetch TTL cache, file content LRU cache
- add session prefetch for adjacent sessions
- add instant archive/delete (optimistic before SDK call)
- migrate legacy window.__zustand_session_store__ to session-ui-store
- add retry + independent error handling for archived sessions
- add AGENTS.md performance rules
* perf: startup optimization — dedup, caching, light git status, diff rendering gates
- defer diff prefetch to git tab open, reduce concurrency 4→2, skip >500 changed lines
- cap project git checks concurrency (2), directory status probe (3)
- dedup provider/agent loading, github auth, worktree list (in-flight + TTL caches)
- delay PR tracking 5s, cache 403 search failures per-repo
- coalesce settings PUT (200ms debounce), cache settings GET (2s TTL)
- cache canonical directory resolution (60s TTL)
- persist missing directory status to localStorage (10min TTL)
- light/heavy git status: polling skips numstat+line counting+rev-list
- large diff rendering gate (>500 lines → "render anyway" button)
- tokenization degradation for >500KB files in Pierre
- parallelize main.tsx pre-render awaits
- batch sidebar file tree expanded paths restoration (3 at a time)
- remove bare useConfigStore() subscription in AgentsPage
- sync worktree sandboxes to OpenCode SQLite DB
- fix RightSidebarTabs ternary → explicit tab matching
- defensive guards on sync state (session_status, permission, question, message)
* fix: add defensive guards on remaining sync state field accesses
guard session_status, permission, message, todo, part, config with ?? {}
in useDirectorySync selectors, session-cache, and bootstrap
* fix: add missing directory dep to useCallback in use-sync.ts
* fix: preserve diffStats when light-mode polling overwrites status
* perf: optimize startup git status polling and diff rendering
Preserves diff stats when lightweight polling updates repository status
Reduces startup overhead with smarter git polling and store updates
Adds detailed optimization and migration docs for next performance steps
* fix: keep chat diff stats stable during git status updates
Prevents lightweight git polling from dropping diff statistics
Keeps MessageList diff indicators consistent while status refreshes
Improves reliability of git-aware chat rendering
* fix: user animation replay, queued message variant, startup provider loading
- consume animation ID after first play to prevent re-animation
on neighbor assistant message completion
- capture send config (model/agent/variant) at queue time matching
OpenCode's FollowupDraft pattern instead of re-resolving at send time
- replace one-shot startup recovery effect with polling interval
that retries every 2s until providers and agents load
- fix optimistic bridge to avoid re-render loop (stable ref wrappers)
* chore: update tauri to 2.10.3 and all plugins to latest
- tauri 2.9.4 → 2.10.3
- tauri-build 2.5.3 → 2.5.6
- tauri-plugin-dialog 2.4.2 → 2.6.0
- tauri-plugin-log 2.7.1 → 2.8.0
- tauri-plugin-shell 2.3.3 → 2.3.5
- tauri-plugin-updater 2 (floating) → 2.10.0 (pinned)
- @tauri-apps/api ^2.9.0 → ^2.10.1
- wry 0.53.5 → 0.54.4 (transitive)
* refactor: decouple web server index orchestration runtimes
* fix: align VS Code runtime behavior with web and reduce draft view CPU load
- Queue VS Code bridge and SSE startup requests until API readiness to avoid false bootstrap failures
- Make agent manager actions directory-aware and remove real worktrees with safer partial-failure handling
- Replace heavy logo animation path with a lightweight pulse to cut draft-session CPU usage
* fix: restore auto-selected file sending in chat input
- Send server-selected files as proper file URLs in the message payload
- Include server-backed attachments in submit flow instead of dropping them
- Restore queued-message attachments through the refactored input store
* fix: restore session model selection consistently on session switch
- Restore agent, model, and variant from the latest loaded user message for each session
- Wait for session messages before applying restored selections to avoid stale or missing state
- Remove legacy session-choice inference paths that caused overlap and instability
* fix: restore permission replies and auto-accept across sessions
- Scope permission and question replies to the target session directory so answers take effect reliably
- Make permission auto-accept immediately handle pending requests and react to new permission prompts
- Keep parent-session handling working for child-session requests through the shared response path
* feat: add reusable fuzzy branch fuzzy-search helper and dialog integration (#798)
* feat: add reusable fuzzy branch search for worktrees
* chore: drop planning docs from feature branch
* feat: make worktree branch refresh manual
* feat: add configurable session retention action
* refactor: centralize global session state in ui store
* fix: cancel debounced permission push after reply
* docs: clarify global and directory session store architecture
* docs: refine agent development rules and session activity guidance
- Clarify agent code of conduct and durable development patterns
- Add explicit shared-store rerender and live-state guidance
- Narrow session activity fallback to avoid stale working state
* chore: updated .gitignore
---------
Co-authored-by: Iuliia Ivashko <yulia.ivashko@gmail.com>
|
||
|
|
321cc7252a |
Major UI refresh: sidebar redesign, theme expansion, and chat performance optimizations (#706)
## Summary Complete sidebar redesign and comprehensive UI polish pass with performance optimizations, theme system refinements, and desktop integration improvements. ## Key Changes **Sidebar & Navigation Redesign** - Redesigned sessions sidebar layout with unified button primitives - Added activity sections with project grouping and improved session organization - Refined sidebar corners, spacing, and visual hierarchy - Removed NavRail component in favor of streamlined sidebar - Stabilized sessions bar toggle position in fullscreen mode **Performance Optimizations** - Reduced chat streaming CPU usage and storage churn - Optimized task tool polling and live timers with debouncing - Prevented chat state races and reduced background request load - Debounced draft writes and coalesced session reloads - Optimized message store updates and turn tracking **Theme & Visual System** - Added theme-aware window corners (desktop) and border radius tokens - Introduced glassmorphism effects on desktop sidebar - Added backdrop blur to UI elements **Chat Experience** - Added session-based permission auto-accept toggle in chat input - Polished permission shield UX with improved icon sizing and spacing - Fixed chat scroll-to-bottom behavior and timeline tracking - Enhanced tool output display with better path label detection - Removed duplicate draft context details in chat header - Added text selection menu to chat messages **Git Improvements** - Refreshed git history visual design with cleaner dividers - Added remote removal action in sync selector - Stabilized git polling to prevent excessive requests - Improved tool output rendering for git operations **Settings & Panels** - Fixed mobile scrolling on settings pages - Made outside-click settings close instantly - Reduced settings load churn and CPU spikes - Improved services dropdown layout and spacing - Softened panel resize handles **Desktop Integration** - Synced macOS window theme with app theme - Restored window dragging in sidebar header zones - Fixed system window corners on macOS - Improved header session metadata and action controls **Button & Component Standardization** - Unified button primitives across all components - Standardized destructive action patterns - Removed unused button variants (button-large, button-small) - Aligned context tab close hit areas --------- Co-authored-by: Iuliia Ivashko <yulia.ivashko@gmail.com> |
||
|
|
fab32ca992 |
refactor(chat): complete turn-based pipeline and stabilize streaming, scroll, and tool UX (#629)
* refactor: add canonical turn projection pipeline for chat Centralizes turn/activity/summary derivation, migrates render consumers to shared projection sources, and adds projector regression coverage for retries, malformed parent fallbacks, and activity segmentation. * refactor: stream assistant text live in turn-first render path * refactor: complete phase-3 turn timeline history/navigation * refactor: complete phase-4 turn pipeline cutover Remove legacy grouping adapters and lock key edge cases with executable regression tests so turn-centric rendering stays stable across retry/history/navigation flows. * fix: align chat history loading path with opencode parity * fix: stabilize chat streaming and reduce render churn * feat: add blurIn streaming text animation and smooth lerp-based auto-scroll Streaming markdown now uses Streamdown blurIn animation (150ms, ease-out) for per-word reveal Auto-scroll during streaming uses continuous exponential smoothing (lerp) instead of restarting spring animations One-shot scroll-to-bottom (button click) uses motion spring for natural deceleration * fix: respect user scroll-up during streaming and re-pin on scroll back to bottom * fix: stabilize activity stream and tool progress rendering Activity now stays chronologically consistent and avoids duplicate reasoning/justification. Tool rows show running state and duration earlier with smoother pending behavior. Removed legacy trim/timestamp paths to prevent message drops and simplify Activity UI. * fix: reverted regression of revert functionality * fix: stabilize chat activity layout and tool progress behavior Stopped user messages from re-animating when new user messages appear. Made Activity and aggregated tool rows wrap inline consistently without misaligned headers/icons. Fixed tool part matching so duration and shine no longer reset across pending/in-progress status updates. * fix: restore activity mode behavior and stabilize tool rendering Re-enabled Collapsed/Summary/Detailed/Changes defaults for Activity and tool expansion. Fixed tool row wrapping/alignment, removed user fade re-animations, and disabled FadeInOnReveal animations. Improved tool status handling to reduce timer/shine resets and made reasoning bold render as normal text. * refactor: simplify chat tool and message rendering Replace activity-group rendering with flat inline part rendering Remove obsolete tool output and justification activity settings Keep user message animation and improve edit/apply-patch file path headers * style: narrow chat and composer columns equally * fix: Tool status checks and abort flow regression * fix: improve multi-file apply patch header rendering * fix: make timeline message jump scroll to selected chat entry Conversation Timeline clicks now reliably scroll to the selected message in chat Timeline dialog waits for navigation result before closing to avoid silent failures Chat message scrolling now resolves the active chat scroller consistently * chore: remove branch-added chat tests and clean lint leftovers Removes newly added chat and message test files from this branch Fixes lint blockers in ProgressiveGroup, ToolPart, and messageStore Keeps type-check, lint, and build passing after cleanup * fix: keep composer status row closest to the input Status/todo row now renders below queued messages and attachments. Linked GitHub issue/PR chips stay above status so input context order is consistent. Improves chat composer readability while assistant is working. * fix: disable assistant header animations and polish chat status behavior Assistant message header now renders without transition effects Removed a lint issue from the working placeholder props Chat status and message flow updates improve consistency during active turns * feat: increase bottom spacer in mobile chat for better scrolling * feat: add sorted chat mode with progressive activity rendering Adds global chat render mode settings for sorted and live behavior Renders non-stop assistant output in Activity as messages complete Disables streaming text animation in sorted mode and restores classic reasoning/justification blocks * fix: stabilize chat timeline navigation and older history loading Prevents auto-loading older history from scroll and keeps loading behind the button Fixes timeline jump-to-message behavior that snapped back to the bottom Reduces chat list flicker and empty-state glitches on large session pagination * fix: stabilize sorted activity text and hide reasoning timers Prevented sorted justification from appearing before message completion by requiring explicit non-stop finish. Removed duration values for sorted Thinking and Justification blocks. Kept smooth sorted auto-follow behavior tuned to reduce bottom-jump jitter. * refactor: simplify chat tool rendering paths and add parts docs Centralized tool icon mapping into a shared presentation helper used by grouped and expandable rows. Removed static-tool-specific branches from ToolPart to keep it focused on expandable tools. Added a new DOCUMENTATION.md explaining where to change tool descriptions and rendering behavior. * feat: enhance event stream handling for message parts - Refactor event key building functions to improve clarity and reduce redundancy. - Introduce `applyPartDelta` method in message store for handling delta updates to message parts. - Update `useEventStream` to utilize the new `applyPartDelta` method for processing incoming deltas. - Enhance text extraction logic to accommodate new part types and improve merging behavior. - Implement logic to skip delta-driven updates for ongoing text/reasoning parts to prevent overwriting. - Adjust server-side text merging logic to handle trimmed text comparisons and improve consistency. * feat: enhance OpencodeService with delta handling and stale delta management - Introduced globalSseStaleDeltas to track stale deltas. - Added methods to generate keys for delta and updated part events. - Updated global SSE loop to skip processing stale deltas. - Refactored global SSE event handling to improve performance and reliability. refactor: remove unused streaming part handling in messageStore - Eliminated streaming part queue and associated logic. - Simplified message merging logic by removing redundant checks. - Streamlined message handling to improve clarity and maintainability. chore: clean up unused streaming text normalization functions - Removed deprecated functions related to streaming text identity and merging. - Simplified normalizeStreamingTextPayload to focus on current functionality. * refactor: simplify streaming event passthrough Use SDK-native global event streaming in the UI client Remove dead server-side SSE normalization helpers Keep streaming payloads closer to upstream behavior * revert: remove message memory settings UI Drop the restored message memory settings screen Keep session settings focused on current defaults Preserve chat history limits as internal behavior * feat: add compact collapsed Activity preview in sorted mode Collapsed Activity now shows a live preview of the latest 7 entries Older activity rows roll up behind a +N more indicator The +N more indicator is clickable to expand the full Activity * fix: adjusted activity changed files text prominence * fix: make sorted mode snap to bottom when not streaming * perf: show chat scrollbar only on user-driven scrolling Chat scrollbar now stays hidden during automatic follow-to-bottom Scrollbar visibility is gated by real user scroll intent Reduced scroll overhead by removing timer-based intent tracking * refactor: align web and vscode session activity streaming Route VS Code SSE through SDK-based proxy flow Restore controlled web session activity tracking and cooldowns Keep chat activity behavior consistent across runtimes * fix: adjusted muted foreground themes color * fix: stabilize session activity and attention updates Keep streamed chat state in sync as sessions complete Restore reliable attention indicators for inactive sessions Tighten server and UI event handling for chat updates * feat: add chat render previews and file icon visibility setting Added animated chat render mode previews in Chat settings. Added a new toggle to show or hide file icons across tool rows. Persisted chat render, activity, and mermaid modes to shared settings file. * fix: update default GitHub OAuth client ID Use the new OpenChamber org GitHub OAuth app ID by default. Keep web server and VS Code auth defaults in sync. * fix: sync chat settings across VS Code chat views Broadcast settings changes to both sidebar and editor chat webviews. Apply synced settings in each webview via shared settings refresh. Ensures chat render mode updates appear immediately in editor tabs. * fix: stop writing session folders file in VS Code workspaces Disable disk persistence for session folders in VS Code webview runtime Keep session folder state in VS Code/webview storage instead of project files Preserve existing behavior for non-VS Code runtimes * style: polish expanded tool panels and bash output readability Removed extra borders/labels in expanded tool cards for a cleaner UI Added softer scroll shadows and full-height decorative activity line Switched bash command/output to code-style typography with tighter spacing * feat: add default-open tool controls for chat activity Added Chat settings toggles to open Bash and Edit tools by default Default-open behavior now applies across both sorted and live activity rendering Users can still manually collapse default-open tools, plus bash output height was reduced * fix: align chat loading skeleton with message layout Match skeleton width and horizontal alignment to chat message column Add one-line tool-style skeleton rows with subtle circular placeholders Increase top spacing so loading state no longer touches chat header * fix: prevent blank screen when adding inline diff comments Sanitize persisted inline comment drafts to ignore invalid data Harden diff annotations against malformed line numbers Fail safely when annotation updates error instead of crashing the view * fix: streamline VS Code archived sessions sidebar Show archived sessions in VS Code only for the active workspace directory. Render archived sessions as a flat list in VS Code without project-root subfolders. Hide the "Open in Side Panel" session action in VS Code. |
||
|
|
a7f11121e8 |
refactor: modularize session sidebar and add GitHub PR tracking (#610)
* feat: switch sessions sidebar to global paginated loading with archived flow Load sessions via global endpoint with progressive 500-item pagination and legacy fallback Add dedicated archived sidebar section for archived and unassigned sessions Change remove behavior to archive outside archived and hard-delete inside archived * feat: improve archived sessions UX and folder persistence Archive sessions on worktree removal while keeping worktree deletion Streamline archived sidebar actions, icons, metadata, and tooltips Persist session folders to ~/.config/openchamber/sessions-directories.json with startup hydration * fix: align archived session actions and clean empty archived folders Apply archived dropdown behavior consistently for folder-contained sessions Remove archived-only folder actions while keeping standard folder behavior elsewhere Auto-prune empty archived folders during session cleanup and persistence sync * refactor: modularize session sidebar and stabilize behavior Split monolithic sidebar logic into focused hooks and components Kept session, archive, folder, and project interactions working with cleaner state persistence Added sidebar DOCUMENTATION.md summarizing file roles and refactor outcomes * fix: improve fork PR detection and smart remote tracking Added centralized PR status store for shared polling and refresh Auto-selects the remote that has an existing PR when current remote has none Stops periodic polling for closed or merged PRs to reduce unnecessary requests * fix: make chat and toast corners follow active theme radius Toast corners now use theme radius tokens instead of hardcoded rounding User message bubble now uses theme-configured max radius with preserved tail corner Square-corner themes now consistently affect both toasts and chat bubbles * feat: show live PR status across git view and session sidebar Added a shared GitHub PR status store with adaptive background polling and terminal-state pause Improved fork remote detection and auto-selection so existing PRs are found more reliably Updated session group headers to show clickable PR number with branch and state-colored branch icon * feat: centralize GitHub PR tracking and enrich session sidebar PR details Moved PR status polling to a single global pipeline keyed by directory and branch Improved fork-aware PR resolution and reduced duplicate GitHub status fetches across views Added richer session sidebar PR display with clickable number, state-aware styling, and structured tooltip details * fix: adjust PR indicator icon vertical alignment Fine-tuned PR indicator icon vertical alignment in session sidebar Reduced icon translate-y from 2px to 0.5px for better visual balance * feat: improve session sidebar status display * feat: enhance session display logic for minimal mode and improve dropdown menu accessibility * feat: refactor session row to include tooltip for minimal display mode |
||
|
|
79143bff4c |
feat: massive chat reliability + UX pass (web/desktop/mobile/vscode) (#593)
## Added Features - Add VS Code save-as-image flow for assistant messages via webview bridge + native save dialog. - Add hourly desktop update checks after startup. - Add new tool output display mode: `Changes` (auto-expand edit/write/patch only; keep activity expanded; mode guidance text). - Add GitHub PR attachment flow in chat input with PR picker + attached PR chip/details. - Add mobile overlay presentation for GitHub Issue and PR pickers (shared with desktop picker content). ## Fixes - Save-gate project icon updates until explicit Save; allow icon removal with same save-gated behavior. - Restore clickable chat action buttons in sticky header mode (desktop + Firefox hit-target issue). - Clamp sticky user messages to bounded chat height and allow internal scrolling. - Prevent drawer context crash during iPad/tablet orientation switching. - Improve text-selection action menu placement on narrow screens. - Move assistant message time into clock tooltip; keep duration display clean. - Hide `Link GitHub Issue` row in VS Code chat input area (GitHub flow is not yet ready there). - Remove laggy close animation in text-selection popover; keep open motion/positioning behavior. - Fetch branches when picker opens and cache empty; show loading state instead of false “No branches found”. - Fix share-image export metadata rendering (theme background resolution, timestamp rendering, footer alignment). - Scope MCP services status/toggles to active directory to avoid cross-project leakage. - Improve long user-message clamp behavior (40% cap variant, hidden scrollbar, scroll shadows, expansion detection). - Fix desktop `Check for Updates` menu handler; prevent duplicate checks; show clear success/error toasts. - Stabilize long user-message scrolling behavior (follow-up hardening). - Avoid premature web update failure on slower servers. - Restore user message image previews + fullscreen gallery navigation payload. - Repair desktop chat drag-and-drop image attachments when native drop coords are missing. - Move GitHub issue linking entry into Add attachment menu. - Align header context usage percentage visuals with context panel. - Align `@` file search with active project in all runtimes. - Route `@` file discovery through OpenCode SDK `find.files`; remove legacy `/api/fs/search` reliance. - Make chat `@` mention behavior consistent with files-style behavior. - Keep status-row todos in stable order after status changes; add compact status icons; replace noisy priority labels. ## Refactors / UX Consistency - Simplify chat attachment model and remove project file picker path. - Keep composer focused on `@` mention file flow. - Use direct `Attach files` action in VS Code instead of attachment dropdown path. - Unify issue/PR picker behavior between desktop and mobile overlays. |
||
|
|
b4cd16f55b |
feat(ui): polish chat and git workflows with mobile UX and reliability fixes (#569)
* feat: add chat option for user message rendering mode * feat: add chat option to toggle sticky user header * feat(ui): overhaul context panel with reusable tabs and embedded session chat Enable parallel context workflows with persistent tabbed views and isolated session chat while reducing resize and background runtime overhead. * feat: polish context panel and git sidebar tabs Refined context panel tab behavior and visuals for smoother switching and resizing Reused the new tabs component in right sidebar and git sidebar with fit layout Improved git section spacing, selection controls, and bulk revert confirmation flow * feat: open diff files in editor at changed lines Add edit actions in diff views to open files at the first changed line Support per-file open-in-editor from All Files headers and icon-only action in single-file view Improve file jump UX with load-aware navigation and reduced visual blink during line targeting * fix: stabilize pill tabs and prevent git commit pathspec failures Unified sortable tab variants to match animated styling behavior with responsive spacing and cleaner sidebar chrome Fixed active tab pill measurement so size/position recalculates correctly when dropdowns reopen Commit API now filters stale file paths before staging to avoid pathspec errors on deleted files * fix: align user message action row spacing and hover behavior * fix: persist user message view preferences in settings Save plain-text and sticky-header toggles to settings.json when changed Restore both chat display preferences from settings.json on startup Validate and accept both preference fields in the settings API * fix: improve git and sidebar tab layout on mobile * fix: refine mobile user message action row spacing Show mobile user-message actions in a consistent external row for sticky and non-sticky modes Tune button row height and vertical position to match both mobile variants Reduce sticky-header gradient tail and tighten assistant gap after user messages * fix: improve chat action hover zones and mobile top shadow logic Expand desktop trigger area so user action buttons reveal across the full row Add sticky-header phantom hover row so inline actions appear from the whole button lane Hide chat top scroll shadow on mobile only when sticky user headers are enabled * fix: remove commit message input scrollbar flicker Added optional scrollbar class support to shared textarea wrapper. Disabled overlay scrollbar for Git commit message input. Kept auto-resize behavior while preventing one-line empty-state micro-scroll. * feat: make model provider groups collapsible in selector Add collapsible provider headers in the chat model dropdown Persist expanded/collapsed provider state across sessions Refine provider header UX with inline chevrons and no hover highlight * feat: arrange chat settings into a compact two-column layout Places User Message Rendering next to Mermaid Rendering. Places Diff Layout next to Diff View Mode. Reduces right-column spacing to better match other settings sections. * fix: show worktree branch edit controls in draft sessions Detect worktree mode from current directory when session metadata is not yet bound Enable immediate branch rename UI in Git sidebar without session switching * feat: add beta badge to side panel menu action |
||
|
|
be413771dc |
feat(chat): align activity timing UI with hover-only end timestamps (#557)
* feat(chat): add shared activity timestamp formatter * feat(chat): pass assistant created timestamp to message body * feat(chat): render footer timestamp beside elapsed time * feat(chat): pass timing metadata in reasoning text blocks * feat(chat): propagate justification timing to timeline block * feat(chat): show thinking duration with hover end time * feat(chat): reveal tool end time on activity hover |
||
|
|
1d8ff97c95 |
feat(ui): add dynamic window title and sprite-based project/file icons (#529)
* feat(ui): add dynamic titles and sprite-based project/file icons * feat(files): add viewer syntax fallback and tab file icons * fix(files): restore file viewer highlighting and add diff file icons * feat(git): add file icons and async file-viewer syntax fallback * fix(files): force codemirror token colors in file viewer * feat(files): add shiki view mode for file viewer * fix(files): force codemirror parse after programmatic content updates * feat(files): support markdown frontmatter preview * feat(chat): use pierre diffs for tool previews * feat(chat): add configurable beautiful-mermaid rendering * feat(perf): virtualize chat rendering and add react-scan toggle * feat(build): enable React Compiler in Vite React apps * fix(chat): reduce rerenders from tooltips and streamed activity * fix(ui): make MessageList React Compiler safe * chore(ui): batch commit remaining pending ui updates * fix: polish chat and diff preview rendering - Keep Mermaid action buttons fixed while diagram content scrolls - Align Diff All Files headers and match Git-style path truncation - Default chat tool diffs to unified view with lightweight indicators disabled * fix: preserve file tree expansion and delay git action label collapse * fix: refine project icon controls in settings --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com> |
||
|
|
10851bd7ac |
feat: move projects to sidebar rail and speed up session switching (#506)
* feat: move projects from header tabs to left sidebar rail * refactor: remove variant from git generation session context * feat: implemented drandrop action for navrails * refactor: improve sidebar drag-and-drop smoothness and remove floating overlay * fix: prevent mobile nav rail touch from closing drawer and opening menu * fix: hide header tabs on desktop * fix: prevent session flicker when switching projects * style: soften chat panel divider borders * style: improve icon contrast across core navigation * fix: stabilize session selection during project switching * style: unify sidebar surfaces and transparent section layers * style: remove UI shadows and keep only scroll shadow * perf: speed up project switching with cached session loading * perf: speed up Git changes view and background refresh * perf: make session switching lighter and less aggressive * perf: optimized sessions list loading while project switching * perf: smooth chat rendering and reduce interaction spikes * fix: restore reliable load older messages visibility |
||
|
|
fc06a9c499 |
fix(chat): reduce user message padding and hide top scroll shadow on mobile (#496)
* fix(chat): reduce user message padding on mobile * fix(mobile): limit drawer swipe gesture to status bar only * fix(chat): hide top scroll shadow on mobile * fix: add mobile edge-swipe drawer fallback and normalize comments - Adds narrow left/right mobile edge swipe zones for drawer gestures - Keeps drawer swipe access even when the mobile status bar is hidden - Replaces remaining non-English comments in touched chat/layout files * fix: remove edge swipe settings and tighten mobile chat spacing --------- Co-authored-by: Jovines <jovines@qq.com> Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com> |
||
|
|
4a8c69e36a |
refactor: move git generation to session structured output
- Use active session prompts for commit/PR generation and drop backend git generation routes. - Improve tool activity UX with Structured Output rendering, description styling tweaks, and detailed-mode expansion fixes. |
||
|
|
d2d39c48ac |
feat(chat): add Mermaid fullscreen preview and harden file preview paths (#490)
* feat(chat): add mermaid preview popups and fullscreen diagram viewer Enable opening Mermaid diagrams from markdown and file attachments with a dedicated fullscreen dialog, while tightening preview loading behavior and sizing for more reliable interaction. * refactor(chat): extract shared preview overlay hooks Centralize fullscreen preview transition and viewport lifecycle logic so image and Mermaid dialogs stay behaviorally aligned while reducing maintenance overhead. * fix(security): enforce workspace boundaries for fs read endpoints Validate /api/fs/read and /api/fs/raw paths against active workspace roots and canonical realpaths to block traversal and symlink escapes before serving file contents. * fix(chat): remove dead Mermaid copy component Drop an unused merge-leftover component in MarkdownRenderer to keep lint clean without changing Mermaid preview behavior. |
||
|
|
47cecfc356 |
refactor: unify clipboard copy flow across desktop/web/vscode runtimes (#458)
* fix: prevent copying incomplete diagnostics report * refactoring: clipboard writes to unified cross-runtime fallback helper |
||
|
|
50a66bb6f1 | fix(auth): show actionable provider re-auth errors (#450) | ||
|
|
85f21cb945 |
feat(chat): align command, shell, and subtask UX (#444)
* feat: reload interface after skills operations - Adds configurable delay before interface reload after skills changes - Introduces polling to wait for application health after reload - Updates UI to show reload message when installing or modifying skills * feat: distinguish skills from commands in UI - Displays skill badge for commands that are registered skills - Prevents editing skills through command management interface - Triggers interface reload after skill operations to reflect changes * feat(chat): align command and subtask UX with opencode parity Route commands/shell via parity paths, render delegated subtasks cleanly, and surface child-session permission/question prompts in parent chat. * fix(ProjectEditDialog): improve layout consistency * fix: update task icon and session handling in ToolPart * feat(chat): add shell-mode input and collapse shell bridge output Switch leading ! to shell mode UX and fold synthetic shell bridge assistant messages into the user shell bubble with inline output actions. * fix: remove AI agent icon from file mention autocomplete * fix: remove unused icon import from file mention component |
||
|
|
47c943b487 |
feat(ui): redesign workspace shell with context panel, tabbed sidebars, and faster diff UX (#433)
* feat: tabbed right sidebar, context panel, floating diff comments * fix: auto-close left sidebar when context panel opens - Increase default context panel width from 520 to 600 pixels - Increase sidebar minimum width from 200 to 300 pixels - Replace collapsible component with custom button in diff view * refactoring: rework sidebars, tabs, and file tree layout - Rewrite AnimatedTabs as segment-style with sliding indicator - Upgrade SidebarFilesTree to match FilesView features (context menus, git status, file icons, CRUD dialogs, fuzzy search ranking) - Restructure FilesView header: tabs row + actions row, remove breadcrumbs - Show relative path in context panel header, track active tab - Allow left sidebar to stay open alongside context panel - Hide diff/files tabs from header on desktop (mobile-only) - Move chevron after group name in session sidebar - Compact tab heights in right sidebar and git view - Size PreviewToggleButton to match other action buttons - Remove directory loading spinner from folder icons * feat: add project icon and color customization - Enable users to assign custom icons to projects - Allow users to choose accent colors for projects - Stabilize repo status UI during project switching * feat: add scroll fade indicators to editor tabs * style: reduce spacing and icon sizes in header * style: adjust tab component padding from uniform to vertical-horizontal * feat: Add session state indicators to project tabs * feat: Enhance session status handling and improve UI responsiveness * fix: preserve upstream tracking on branch rename * fix: improve initial remote selection for pull requests - Uses saved remote name from previous session when available - Selects remote based on tracking branch when possible - Falls back to origin or first available remote * perf(diff): faster highlight, stable stacked scroll - split/unified Pierre worker pools; prefer shiki-wasm - align diff CSS line-height; disable scroll anchoring; drop WebKit compositing hacks - harden stacked pin/align (cancel on user scroll/input); prevent overscroll - make overlay scrollbar MutationObserver optional; disable for diff container * feat: handle binary files in diff view * fix: adjust project tabs layout and drag regions * style: update drag overlay visual styling * feat: enable number keys to switch projects in the sidebar * fix: recognize octet-stream as text-based MIME type * feat: add keyboard navigation to context panel * feat: add session pinning to sidebar - Pin important sessions to keep them at the top - Pinned sessions persist across browser sessions * refactor: move context usage display from chat input to header |
||
|
|
d94d688112 |
Fix/Autocorrect On Git And Message Overlap (#401)
* hive(01-add-mobile-autocorrect-to-commit-message-input): Added mobile autocorrect to commit message input. * hive(02-add-mobile-autocorrect-to-pr-title-inputs): Added mobile autocorrect to PR title inputs in Pul * hive(03-add-mobile-autocorrect-to-pr-description-textareas): Added mobile autocorrect to PR description textare * Fix chat last message overlap |
||
|
|
844562749d |
feat(ui): enable drag-and-drop attachments and image previews in chat (#390)
* feat(BottomTerminalDock): add close button next to the fullscreen toggle in the dock * style: replace hardcoded gradient with theme value in shine text variant * fix(header): adapt instance button for desktop only * refactor(chat): polish sticky turn UX and message action rows for better readability Switch to stable sticky-only turn behavior and redesign user/assistant action controls (placement, hover rules, ordering, spacing, selection-safe clamp) to reduce visual noise and improve interaction flow. * feat(chat/message): refactor buttons in messages footer * feat: enhance image preview functionality in chat messages - Added a new ImagePreviewDialog component to handle image previews with navigation support. - Updated ToolOutputDialog to utilize the new ImagePreviewDialog for displaying images. - Modified the ToolPopupContent type to include a gallery of images and an index for the current image. - Removed the old inline image display logic from ToolOutputDialog. - Improved file handling in the file store, including better MIME type guessing and handling of server paths. - Introduced a new API endpoint for handling large session message payloads, allowing for better management of multi-file attachments. - Updated the VSCode bridge to support session message requests with appropriate headers and body handling. * feat(proxy): implement SSE forwarding and enhance generic API request handling * feat(chat): support submitting only queued messages * feat: add image preview transition state * fix: default VSCode view to draft and fixed sessions list regression |
||
|
|
ddedc02687 |
feat: introduced a token-based theming system across the UI
* feat: added themes system * feat: smart sidebar auto-hide for files/diff tabs + lower files sidebar threshold * feat: added Checkbox component and update theming - Add reusable Checkbox component for toggles across UI - Replace several inputs with Checkbox in settings and commands panels - Add DiffIcon and apply surface/border theming to key UI areas * feat: Add convert-vscode-theme.cjs to convert VS Code themes to OpenChamber format * refactor: remove unused permission logic from ChatInput - Remove unused permission rules parsing logic from ChatInput - Memoize renderTheme in DiffWorkerProvider to avoid unnecessary recalculations - Remove forceOpaque helper in vscode theme adapter * fix: guard VSCode theme loading in MarkdownRenderer * feat: add custom user themes loading and reload - Load user themes from ~/.config/openchamber/themes at runtime - Expose /api/config/themes to fetch custom themes - Allow theme reloading from Settings → Theme → Reload themes in the UI |
||
|
|
2d305d18c6 |
feat(desktop): enable macOS version awareness for UI adjustments
- Fetch macOS major version from Rust to determine layout - Adjust header padding and height for macOS versions |
||
|
|
f34027df10 |
Optimize chat rendering & add web session activity tracking (#214)
* feat: add chat virtualization and turn grouping infrastructure Implement VirtualMessageList with virtualization and overscan for smooth scrolling Refactor MessageList to render only visible messages and pass scroll refs Introduce TurnGroupingContext and provider to stabilize per-turn rendering and reduce re-renders * feat: add web server session activity endpoint for visibility restore Add /api/session-activity endpoint to expose tracked session activity Use web server activity first when restoring visibility, with fallback to global status Update server SSE to set session phase on activity events * feat(chat): split TurnGroupingContext into UI/Streaming contexts Add separate UI state and streaming contexts to reduce re-renders. Skip animations for items visible in collapsed view when expanding. Track shown parts in collapsed mode to fade in progressively * feat(ui): cache turn groups with expand state and guard web activity Add isExpanded to the turn cache key to trigger updates correctly Expose isGroupExpanded from UI state so groups reflect expand/collapse Limit web server session activity fetch to web runtime only |
||
|
|
f4da45a8ad |
Add plan mode and plan view with per-session agent context (#210)
* feat: add plan/build mode switching and Plan view tab Add PlanView view and integrate plan tab into main layout Introduce plan_enter and plan_exit tools with icons and status strings Persist per-session agent selections in context to reduce UI flicker during mode switches * feat: enchanced plan discovery checks in header and plan view * fix(ui): align PlanView and Header with sessionDirectory logic Remove dependency on context store in header and compute sessionDirectory from session or currentDirectory Compute display and repo paths using sessionDirectory for PlanView and update path resolution Poll plan content every 3 seconds to reflect changes without heavy retries * feat(ui): improve header tab switching and add copy buttons for plan Switch header tab navigation to central UI store and auto-switch when plan is unavailable Show checkmark icon after copying file contents or path with auto-hide timeout Extend plan view path resolution to prefer session directory when present |
||
|
|
d97181bcd2 |
feat(UI): Introduce new UI components for file attachments and related views (#191)
Add file management API and UI components Implement directory listing, search and CRUD operations in desktop backend Expose new Files API on frontend to list, search, and modify files |
||
|
|
6544b12e78 |
refactor: streamline chat scroll manager
- Removed unused activeTurnAnchorId and activeTurnSpacerHeight from MemoryDebugPanel. - Simplified useChatScrollManager by eliminating unnecessary state and functions related to active turn anchoring. - Updated loadMessages function signatures to accept an optional limit parameter across message and session stores. - Enhanced scroll behavior in useScrollEngine to support dynamic bottom tracking during animations. - Improved event stream handling to allow for resyncing messages with a specified limit. - Cleaned up session memory state to remove active turn properties, focusing on viewport anchoring. |
||
|
|
80aef8ec2d | fix: copy is not working on firefox macos (#180) | ||
|
|
28d9324735 |
Fix/active session tracking (#176)
* refactor(chat): enhance scroll management Add bottom detection with epsilon tolerance for precise positioning Introduce pending anchor restoration for seamless session switching Include active turn anchor and spacer height in message store |
||
|
|
84650e16c3 | feat(chat): add turn duration display | ||
|
|
699fc7596a | feat: rename summarize command to compact and update related descriptions for session compression | ||
|
|
8e777a94c2 | feat: add support for model variants across chat components and session management | ||
|
|
f2507d58cf |
feat: migrate to OpenCode SDK v2
Update all import statements to use @opencode-ai/sdk/v2 Modify Vite configurations to alias new SDK path Update API client method signatures for SDK v2 compatibility |
||
|
|
025a9a6b80 |
feat: implement Undo/Redo/Timeline and Fork Features and fixed opencode.json reading issue on broken json (#99)
* feat: add /undo, /redo, /timeline slash commands and fork button
- Add /undo command to revert to previous user message
- Add /redo command to redo previously undone messages
- Add /timeline command to show conversation history
- Add fork button on user messages (hover) to create new session
- Add TimelineDialog component for navigating conversation history
- Show undo/redo/timeline in autocomplete when session exists
- Fix fork to use SDK session.fork API
- Silent no-op behavior for undo/redo when no messages (matches OpenCode CLI)
* fix: correct fork session endpoint and session switching
- Add hybrid SDK approach using v1 for existing methods and v2 for fork only
- v2 SDK has correct endpoint /session/{sessionID}/fork instead of broken /session/{id}/fork
- Fix forkFromMessage to use setCurrentSession instead of direct set
- Ensures both useSessionStore and useSessionManagementStore are consistent
- Fixes issue where forked sessions appeared empty until sending a new message
* fix: use direct fetch for fork to avoid v2 SDK build errors
- Remove v2 SDK imports and hybrid SDK approach
- Use direct fetch() call to /api/session/{sessionID}/fork endpoint
- Avoids type conflicts between v1 and v2 SDK
- Bypasses broken v1 SDK fork endpoint (wrong path parameter)
- All codebase now uses v1 SDK consistently
* fix: use jsonc-parser for config file parsing
- Replace strip-json-comments + JSON.parse with jsonc-parser
- Handles comments, trailing commas, and unquoted keys
- Matches OpenCode CLI config parsing behavior
- Fixes SyntaxError when reading global opencode.json config
* feat: improve timeline dialog with loading state and search
- Add loading spinner on fork button during operation (~30s on big sessions)
- Refresh session list after fork so new session appears in sidebar immediately
- Add search bar to filter messages by prompt text content
- Show 'No messages found' when search has no results
- Disable fork button while forking to prevent duplicate operations
|