* feat(types): add parents to GitLogEntry and new commit action types
* feat(git): add parent hashes and --all flag to getLog
* fix(git): move record separator to start of log format string
* feat(git): add checkoutCommit server function and route
* feat(git): add cherryPick server function and route
* feat(git): add revertCommit server function and route
* feat(git): add resetToCommit server function and route
* fix(tests): make git service tests branch-name portable, add error path tests
* feat(client): add checkoutCommit, cherryPick, revertCommit, resetToCommit API wrappers
* feat(git-graph): add lane assignment algorithm with tests
* feat(git-graph): add GitGraphSegment per-row SVG renderer
* feat(i18n): add locale strings for git graph action buttons
* fix(git-graph): handle lane convergence, fix SVG path coords, add connector tests
* feat(git-graph): add ref badges and action buttons to HistoryCommitRow
* fix(git-graph): add loading guards to reset actions, use theme tokens for ref badges
* fix(git-graph): conditional hooks, stale graph log, conflict handling, i18n
* fix(types): replace toBeDefined with toBeTruthy, fix toast API usage
* fix(lint): remove unused variables
* fix(git-graph): fix SVG height causing 150px row spacing
* fix(git-graph): smooth bezier curves, fill row height, round line caps
* fix(git-graph): non-scaling-stroke fixes bezier white spaces, sort curves on top
* fix(git-graph): remove viewBox scaling, match SVG height to actual row height
* fix(git-graph): ResizeObserver tracks actual row height, eliminates SVG height mismatch
* feat(git-graph): replace SVG with Canvas for graph rendering
* fix(git-graph): isolate canvas from flex layout to prevent replaced-element height leak
* feat(git-graph): align action buttons, add confirmation popups for all actions
* fix(git-graph): address code review findings CR-001 through CR-005
- CR-001: VS Code getGitLog now forwards 'all' option and parses %P parents
- CR-002: VS Code bridge/gitService implement checkoutCommit, cherryPick,
revertCommit, resetToCommit with conflict detection and hard-reset guard
- CR-003: server-side commit hash validated with /^[0-9a-fA-F]{7,40}$/
in both routes.js and service.js; 12 new rejection tests added
- CR-004: cherry-pick/revert conflict path now refreshes fetchStatus/
fetchBranches/fetchLog; conflict toast uses i18n keys in all 7 locales
- CR-005: corrected O(n) comment to O(n x lanes)
* fix(i18n): add zh-TW locale and common.language.traditionalChinese key to all locales
upstream/main added zh-TW.ts after branch diverged; CI type-check fails
when PR is merged because zh-TW.ts was missing all gitView.history.actions.*
keys and loadMore/loadingMore. Also adds common.language.traditionalChinese
to en.ts and all 6 non-English files to match upstream en.ts.
* fix: harden git history actions
* feat: split git history graph view
* chore: remove git graph planning docs
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* fix: improve todo send dialog model picker
* fix: truncate long model selector labels
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* fix: make upstream sync actions target the selected remote
Ensure fetch and pull actually honor upstream selection so fork maintenance works from the Git sidebar, and surface upstream branch status alongside the primary origin-tracking indicators.
* feat: add Windows Electron desktop foundation
* fix(electron): stabilize Windows desktop packaging
* fix(electron): stabilize Windows desktop chrome
Use native Windows titlebar behavior with an Alt-accessible hidden menu, and harden Windows dev command launching so the desktop app follows platform conventions.
* fix(electron): stabilize Windows dev startup
* fix(electron): clarify desktop artifact names
* fix(electron): harden Windows desktop release and launch
* fix(electron): address Windows release review
* fix(electron): point updater and release links to org repo
* Fix Windows settings persistence fallback
* Fix Windows Electron dev startup
* Add Windows Electron window controls
* Fix Windows Electron install and opencode launch
* fix: resolve git status for repositories without upstream
Fixes repository detection stuck on Checking repository
Handles git status when no upstream is configured
Adds regression coverage for git status loading
* Add Windows app menu button
* fix: preserve file editor line endings
* ci: add desktop release smoke workflow
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* fix: session rename exits immediately due to focus race
Replace fragile onBlur handler with document mousedown listener for click-outside detection. Defer dropdown-initiated rename to onOpenChangeComplete (fires after CSS transition + cleanup). Use finalFocus instead of dead onCloseAutoFocus (never forwarded to Base UI).
* chore: remove dead editCancelledRef after onBlur removal
onBlur was replaced by document mousedown listener. editCancelledRef was only read in the old onBlur handler — its write in the Escape key handler was the sole remaining use.
* feat: add Traditional Chinese locale
* feat: add Traditional Chinese locale
* feat(i18n): Update Traditional Chinese translation
* fix(i18n): sync Traditional Chinese locale keys
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* fix: switch model when selecting an agent
The early return in setAgent() checked if the current model was valid
and returned immediately without ever falling through to the agent's
configured model. This meant selecting an agent never updated the
model dropdown to match the agent's preferred model.
Removing the early return allows the fallback chain to work correctly:
1. Persisted session-specific agent-model selection
2. Settings default model
3. Agent's own model (previously unreachable)
4. No change (current model stays)
* fix: prefer agent model over saved selection
* fix: preserve restored model on agent hydration
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
Prevents the context panel from overflowing past the right edge
Clamps resize width to the available layout space
Handles previously saved oversized panel widths
Add launch-at-startup support across the Electron desktop app and the web CLI.
Electron now supports macOS launch-at-login through the native login item API. Login launches start OpenChamber in the background without opening a window, while Dock activation, deep links, and second-instance launches still open or focus the normal app window. The desktop Settings UI now exposes a localized launch-at-login toggle in Desktop Network Access.
The web CLI now includes `openchamber startup status|enable|disable`, backed by native user services:
- macOS: launchd LaunchAgent
- Linux: systemd --user service
- Windows: Task Scheduler
Startup services run `openchamber serve --foreground` so the OS service manager owns process lifetime and restarts. Foreground service updates now defer restarts to the service manager instead of spawning duplicate CLI restarts.
Startup services snapshot useful environment variables by default so provider tokens, PATH, SSH agent settings, and OpenCode configuration survive login/reboot starts. The snapshot avoids shell/session-only state, uses systemd-compatible env quoting on Linux, and avoids unused env artifacts on macOS.
Also adds localized docs for startup services and environment variables.
Safely falls back to raw patch text for invalid diffs
Protects individual tool parts from crashing the chat
Covers malformed apply_patch and edit diff cases
Use browser keyboard resizing by default on mobile
Remove mobile-only autocomplete button and tabs
Keep autocomplete behavior consistent across mobile and desktop
* feat(settings): add opencode plugins page
Manage opencode `plugin` array entries (npm, scoped npm, versioned,
local paths) and auto-loaded plugin files in `~/.config/opencode/plugins/`
and `<project>/.opencode/plugins/`. Mirrors MCP CRUD pattern.
- Server: `plugins.js` data layer + `plugin-routes.js` REST routes
- UI: PluginsSidebar / PluginsPage / AddPluginDialog
- Store: usePluginsStore (cache TTL, in-flight dedup, narrow selectors)
- i18n: 41 keys across 7 locales
Whitelist /api/config/plugins in JSON body-parser so POST/PATCH bodies
parse; opencode plugin specs runtime-resolve OPENCODE_CONFIG dir so
parallel test files do not cross-pollute module-frozen consts.
* feat(settings/plugins): hook npm registry for update + invalid-version detection
Plugins page now consults registry.npmjs.org with a 1h server cache. Sidebar
rows show an update badge with the latest version, group headers show how
many updates are available, the kebab adds an "Update to latest" action
that reuses the existing PATCH+restart flow, and the editor surfaces a
banner for update-available / missing-version / missing-package / malformed
/ missing-path / unreadable-path / offline-registry states. A refresh
button in the sidebar header forces a cache bypass.
- Server: `npm-registry.js` (cache + in-flight dedup + 5s timeout, 404
cached, network failures NOT cached) + `plugin-spec.js` (parser + exact
semver detection) + `GET /api/config/plugins/registry?specs=...&refresh=`
- Routes accept up to 100 specs/request, dedup by npm package name before
fetching, classify each result by kind, never propagate network failure
as 500.
- Client: `registryInfo` slice + `loadRegistryInfo` (fire-and-forget after
loadPlugins, refreshes on mutations) + `updateToLatest(id)`.
- UI: `RegistryBadge` per-row + `RegistryBanner` per-entry editor, both
use theme tokens (text-only color, no new bg/border tokens) and the
shared Icon sprite. Per-spec subscriptions only.
- i18n: 24 new keys (incl. split singular/plural for "N update(s)
available" because the runtime does not parse ICU plural format).
* fix(settings/plugins): keep registry badge visible for long specs
Sidebar entry row used `inline-flex` with `truncate` only on the spec
text. With long npm specs the badge could be pushed past the row edge
and clipped by the parent overflow. Switch to `flex` with spec
`flex-1 min-w-0 truncate` and add `shrink-0` to the badge wrapper so
the update indicator stays anchored to the right of the row.
* fix(settings/plugins): use code-box icon to distinguish from MCP
Plugins nav entry used 'plug' which is visually too close to MCP's
'plug-2' icon. Swap to 'code-box' for clearer differentiation in the
Settings nav list.
* Update packages/ui/src/components/sections/plugins/PluginsPage.tsx
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Signed-off-by: Quat3rnion <81202811+Quat3rnion@users.noreply.github.com>
* Update packages/ui/src/stores/usePluginsStore.ts
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Signed-off-by: Quat3rnion <81202811+Quat3rnion@users.noreply.github.com>
* fix(settings/plugins): validate registry directory + surface save errors
- registry endpoint: return 400 on invalid directory query (was silently falling back to homedir, breaking relative path specs)
- save failure toast: prefer result.message over generic 'Reload failed'
* fix(settings/plugins): address review follow-ups
---------
Signed-off-by: Quat3rnion <81202811+Quat3rnion@users.noreply.github.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
Treat the mobile web surface as a constrained runtime so sync loads smaller message pages, keeps fewer warm session caches, and evicts heavy inactive sessions instead of retaining them across switches.
Limit mobile message-record and turn-model caches to reduce memory pressure on phones while preserving bounded initial page expansion for large final turns.
Split the mobile session status bar so the collapsed state avoids subscribing to the full session/status list; the expensive grouping work now only mounts for the expanded list.
Verified with bun run type-check and bun run lint.
Prevents queued messages from being sent to a newly opened session
Adds explicit session targeting for queued auto-send
Covers the behavior with a unit test
Reconnects and resyncs active sessions when live updates stall
Normalizes synthetic session status events
Uses authoritative status snapshots to clear stale busy states
* feat(chat): live markdown source-mode highlighting in composer
Highlight markdown syntax, fenced code blocks, and mention-style tokens
directly in the chat input via the existing transparent-textarea overlay
(color/decoration/background only, so caret alignment is preserved).
- Markdown source-mode: inline/fenced code, links, headings, blockquotes,
list markers, with dimmed syntax punctuation
- Per-language syntax highlighting inside fenced blocks, reusing the editor's
CodeMirror language resolver + Lezer (bash/js/ts/json/html/css/python/md);
highlighted blocks use a neutral base, plain fences keep the code color
- Token highlighting on match: @file, @agent, /command, /skill, #snippet
- Auto-pairing: wrap selection with markers, triple-backtick expands to a
fenced block; paste a URL over a selection to form a markdown link
- Add md/markdown to the shared code-block language resolver
* fix(chat): address composer highlight review
- Tilde (~~~) fenced blocks now get per-language syntax highlighting
- Share fence open/close detection between tokenizeMarkdown and
highlightFencedCode so they agree on boundaries (fence length + format),
fixing range bleed with 4-backtick fences and ```lang lines inside blocks
- Replace buildHighlightParts O(segments x ranges) scan with a sweep-line
over an active set (verified equivalent vs the prior algorithm across 30k
randomized cases, including overlaps and explicit class/priority)
- Cap per-block Lezer parsing at 20k chars; oversized blocks keep the neutral
code base without per-token coloring
* Fix mobile open file list cleanup and long names
- Remove deleted files from persisted open file tabs
- Invalidate cached file content when stat/delete/rename affects paths
- Keep mobile open-file close buttons visible for long filenames
- Add marquee scrolling for overflowing file names
* Fix bot comments
---------
Co-authored-by: Konstantin Zolin <zolin_ka@vk.com>
* fix: resolve symlinks in project directory paths
OpenCode stores sessions using the canonical (realpath) directory, but
OpenChamber passed the unresolved symlink path in several places. The
string-match directory filter would fail when a project was accessed via
a symlink, making sessions invisible.
Changes:
- Add safeRealpathSync to settings normalization — project paths and
lastDirectory are canonicalized at persistence time
- Add Express middleware before the API proxy to resolve symlinks in
?directory= query params on in-flight requests
- Resolve symlinks in /api/fs/list so the directory browser returns
canonical paths, allowing the "already added" check to work correctly
- Reconcile the in-memory projects store when the server responds with
normalized paths, preventing temporary duplicates
Fixes#1315
* fix: avoid sync realpath in opencode proxy
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>