Commit Graph
1774 Commits
Author SHA1 Message Date
Bohdan Triapitsyn 069d9ad5c9 feat: cap subagent list height in work status panel
Limits the expanded subagents list to eight rows
Adds independent scrolling so other sections stay visible
Documents the new subagents panel behavior
2026-08-12 02:10:27 +03:00
Bohdan Triapitsyn 5917325d49 feat: switch OpenCode Go usage to API
OpenCode Go now reads quota usage with a bearer API key from OpenCode auth.json
Removes the old workspace ID and browser cookie credential flow
Deletes legacy OpenCode Go credential files during upgrade
2026-08-12 01:49:22 +03:00
Bohdan Triapitsyn 22b3665077 feat: show work status on draft sessions and resolve project worktrees
Keeps the work status panel aligned to the draft's target directory
Resolves project labels for sibling worktrees using shared session-directory logic
Adds coverage for resolving a worktree back to its registered project
2026-08-11 17:00:23 +03:00
Bohdan Triapitsyn a20b87e984 fix(work-status): label project details clearly 2026-08-11 17:00:23 +03:00
Serhii DziupinandSerhii Dziupin c3c47e8956 perf(ui): tighten Shiki highlight caches and parallelize fences
Use content fingerprints instead of full source as cache keys, record
entry sizes once (no TextEncoder/JSON.stringify on get/evict), and
highlight multiple markdown fences concurrently.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-11 13:23:43 +00:00
Andrea VandChangeHow 454119ac25 fix(ui): mount only the active session chat iframe (#2816)
* fix(ui): mount only the active session chat iframe

* repro(ui): mount-all-persisted session-chat iframes (#2815)

Adds a regression-style reproduction for issue #2815: ContextPanel
renders one full-application iframe for every chat tab (inactive tabs
are only hidden via the Tailwind 'hidden' class, never unmounted), so a
reload restores all persisted session-chat tabs from the ui-store and
mounts N embedded OpenChamber apps in one browser tab.

The test reads the real ContextPanel.tsx render block, drives the real
useUIStore with the issue's persisted scenario (11 tabs, 8 read-only
session-chat tabs), and models the render block with the real
buildEmbeddedSessionChatURL helper, showing 8 live src iframes (7
hidden but loaded).

* test(ui): adapt issue 2815 reproduction for active chat

* fix(ui): unmount session chat when panel closes

---------

Co-authored-by: ChangeHow <23733347+ChangeHow@users.noreply.github.com>
2026-08-11 16:11:25 +03:00
Bohdan Triapitsyn b55152db6f fix(usage): refresh work status quotas automatically 2026-08-11 12:58:36 +03:00
Dawnfz-Lenfeng 5b8ff22d35 fix(ui): always show /init command in autocomplete
The /init command was only offered in the autocomplete when the current session had no messages yet, and it was filtered out entirely once any message existed. Since the underlying session.command endpoint works in any session, keep /init available whenever a session exists so AGENTS.md setup stays reachable mid-conversation.
2026-08-11 17:45:15 +08:00
Bohdan Triapitsyn a0207e3857 test: cover work-status empty panel recovery 2026-08-10 23:31:58 +03:00
Aaron Hogue 02872ff9d3 fix: keep work-status panel reachable when all sections are hidden (#2805)
* fix: keep work-status panel reachable when all sections are hidden

When every section was unchecked in the Panel Sections dialog, the panel
went transparent and inert, making the settings gear icon unreachable.
The only recovery was knowing to toggle the panel off and on from the
header, which still rendered the same empty/inert state.

Changes:
- Panel stays interactive (not inert) when visible, even with zero
  rendered sections. This matches how other panels in the app use inert
  only for visually-collapsed (width/height = 0) states.
- Empty state shows 'No sections selected' with a link to reopen the
  sections dialog, matching the centered text-muted-foreground pattern
  used by the file tree, review panel, and home page empty states.
- Sections dialog gains a 'Show all' link (visible whenever any section
  is hidden) and a warning when all sections are unchecked, matching the
  keybinds settings 'Reset to defaults' pattern.
- Added i18n keys to all 10 locale files (English fallback).

Fixes #2804

* Round 1: fix interactive guard for fresh-mount; translate i18n keys

Address openchamber-bot review findings:

1. (blocker) Replace English fallback strings in all 10 non-English
   locale files with real translations per locale-ui-patterns guidance.

2. (non-blocker) Restore the renderedSections > 0 guard for the
   transient no-data-on-mount state so the panel doesn't flash a bare
   bordered card. The interactive condition is now:
     visible && (renderedSections > 0 || allSectionsHidden)
   Empty-state rendering is gated on allSectionsHidden alone (not
   renderedSections === 0) so it works correctly on fresh mount when
   all sections were already hidden in persisted settings.

Validation:
  tsc --noEmit: 0 errors
  bun test work-status: 34 pass, 0 fail

* Round 2: use .every() guard, dedup chooseLabel key, add tests

1. Replace >= length check with areAllWorkStatusSectionsHidden() helper
   that uses .every() — stale section ids left in persisted settings
   from a future removal can no longer inflate the count.

2. Remove duplicate chooseLabel i18n key from all 11 locales — the
   empty-state link now reuses the existing sections.open key.

3. Add 6 focused tests for areAllWorkStatusSectionsHidden covering
   empty, null/undefined, partial, full, stale-id, and stale+full.

Validation:
  tsc --noEmit: 0 errors
  bun test work-status: 40 pass (6 new), 0 fail
2026-08-10 23:28:50 +03:00
Bohdan Triapitsyn fb286653f1 fix: adjust model picker scroll shadows 2026-08-10 20:55:39 +03:00
Bohdan Triapitsyn 75978cf188 fix(mcp): reliable OAuth across runtimes and honest pre-restart UI
MCP authorization was broken in several stacked ways. The browser return
leg landed on the SPA behind the auth gate, so the system browser saw a
login page instead of finishing; the pending-context store silently
saved nothing because its route had no JSON body parser; and the
callback-URL config write started deferring behind Apply & Restart, so
authorization ran against a runtime without the URL and dead-ended on
OpenCode's loopback listener.

The return leg is now completed entirely server-side by an
unauthenticated GET /mcp/oauth/callback that only forwards a code whose
state matches a parked context. Desktop with the local server and VS
Code switch to OpenCode's native flow over its fixed loopback port —
no config writes or restarts at all, with a one-time cleanup of the
previously written callback URL — and its completion signal drives the
page instead of blind status polling. Remote, hosted-web, and mobile
keep the server-callback flow, applying a queued callback-URL write
immediately since authorization cannot wait for a manual restart.

Also: a server queued behind Apply & Restart now shows an Awaiting
restart badge and explanation instead of connect/reauthorize buttons
that can only fail, and Reauthorize is offered only while the server is
actually connected.
2026-08-10 20:23:45 +03:00
Bohdan Triapitsyn 3feee346da fix: replace glass dialog styling with solid background
Dialogs and settings window now use the standard background color
Removed dialog from the glass utility styles
Preserves existing glass effects for other surfaces
2026-08-10 18:49:45 +03:00
Serhii DziupinandSerhii Dziupin 6ab12fdb61 fix(ui): stop sustained Shiki re-highlight of unchanged markdown
Content-address the markdown HTML cache and memoize Shiki worker/client
results so remounts and long sessions no longer re-tokenize stable code
blocks (openchamber/openchamber#2769).

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-10 13:50:20 +00:00
Bohdan Triapitsyn f9595cb80b fix(projects): open draft after adding project 2026-08-10 16:10:03 +03:00
Bohdan Triapitsyn e5eab8c8be style: soften diff action container shadow 2026-08-10 15:10:37 +03:00
Bohdan Triapitsyn 5e26390ad2 fix: make the composer caret more visible
Thickens the CodeMirror cursor to 2px
Adds a slight vertical scale so the caret stands out above glyphs
Covers the new cursor styling with a test
2026-08-10 15:10:37 +03:00
Bohdan Triapitsyn 2c30af5807 refactor: remove macOS vibrancy support and unify glass surfaces
Drops the macOS vibrancy toggle, IPC, and related settings copy
Updates dialogs, popovers, tooltips, and dropdowns to use shared glass styles
Adds sticky header fade behavior to model picker and sidebar lists
2026-08-10 15:10:37 +03:00
Bohdan Triapitsyn 90a16d1d44 fix(chat): refresh work status from git hints 2026-08-10 15:10:36 +03:00
Bohdan Triapitsyn dfa7b45dd0 fix(mobile): recover pending questions after cold start 2026-08-10 15:10:36 +03:00
RyderAsking 0b2b697aa5 fix(chat): prevent shell prefix from corrupting input 2026-08-10 09:22:56 +00:00
Bohdan Triapitsyn e13b4526c6 feat(tasks): manage markdown loops from scheduled tasks 2026-08-09 21:43:16 +03:00
Bohdan Triapitsyn 121685e564 revert: restore auto-hiding overlay scrollbars 2026-08-09 19:53:49 +03:00
Bohdan Triapitsyn f4743ea060 feat(chat): work-status panel, and MCP auth and settings fixes (#2776)
Adds a work-status panel beside the transcript. Context fill, model and
cost, todos, running subagents and the permission requests blocking
them, branch and working-tree state, MCP servers, pinned messages and
context sources were scattered across the header, the composer and the
context panel — a blocked subagent was reported nowhere at all. The
panel reads them from live channels rather than persisted history, and
becomes an overlay where the chat is too narrow to seat a column.

It is on by default, including for existing installs. Because it now
carries these readouts, the desktop header and composer drop the ones it
duplicates: todo and changed-files chips, usage and MCP tabs. VS Code
and mobile keep theirs — neither hosts the panel.

Fixes MCP authorization, which was broken from the panel, invalidated by
a directory switch through a redirect URI that encoded the working
directory, and left the desktop app in the background because browsers
will not follow a custom-protocol link without a user gesture. The
settings page no longer asks the user to understand the MCP spec before
adding a server: one field takes the command or the link, with the kind
inferred and a visible override, and client-registration fields appear
only when a server actually asks for its own credentials.

Also: skills load from the panel instead of only when the composer's
slash autocomplete opens; the header button names the current instance
rather than falling through to the word "Instance" for relay hosts.

Three new optional UI settings keys, all migrated. No change to stored
MCP server configuration.
2026-08-09 19:30:25 +03:00
Floze 901d34bc5f fix: keep GitHub settings mounted during refresh 2026-08-09 15:41:58 +04:00
jaygupta17 9c9c28a552 feat(git): support nested git repositories in the Git tab
When the project root is not itself a git repository, discover nested
repositories (depth- and visit-capped readdir walk via a new
/api/fs/git-dirs route), auto-select the first one, and show a repository
picker next to the branch dropdown to switch. Selections persist per
runtime and root; discovery failure is a distinct marker with a retry
action, never an empty success.
2026-08-08 19:08:42 +05:30
Bohdan Triapitsyn 4faf660a38 feat(usage): add xAI quota reporting #2628
feat(usage): add xAI quota reporting
2026-08-07 11:48:56 +03:00
Bohdan Triapitsyn c19418cba0 Merge origin/main into deferred OpenCode restart branch 2026-08-07 10:08:50 +03:00
Serhii DziupinandSerhii Dziupin bc380e6e1b perf: cut cold-start download 58% and startup heap 22% via measured chunk-graph fixes (#2742)
* fix(ui): update session-switch-resync test to current handleEvent/setSessionTodos signatures

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* perf(build): split Shiki grammars/themes, CodeMirror legacy modes, and @pierre/diffs into on-demand chunks

Merging @shikijs/langs into one manual vendor chunk made the first language
request download every grammar (7.4 MB raw / 1 MB gzip). Letting Rollup split
these packages per dynamically imported module downloads only the languages,
themes, and modes actually used — matching how the worker build already
behaves. @pierre/diffs is split the same way so its pure patch parser (used by
the eager tool renderer) no longer drags the Shiki-importing render stack into
the startup graph.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* perf(ui): restore lazy heavy views and stop eager settings-graph loading

- MainLayout: DiffView/FilesView/GitView/PlanView return to lazyWithChunkRecovery
  (they were silently made static in 2031e3b4 while their Suspense wrappers
  remained), keeping the CodeMirror and @pierre/diffs stacks out of startup.
- ContextPanel: same lazy treatment for its Diff/Files/Git/Plan/Walkthrough
  tabs, with null Suspense fallbacks.
- CommandPalette imported getSettingsNavIcon from SettingsView, statically
  pulling the entire settings surface (SkillsPage -> CodeMirrorEditor -> vim
  mode, theme registry -> @pierre/diffs) into the eager graph; the helper now
  lives in lib/settings/metadata.
- The windowed SettingsWindow mounts only after its first open: rendering the
  lazy component closed made React fetch the SettingsView chunk graph at
  startup.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* perf(ui): keep @pierre/diffs + Shiki out of the eager chat graph and defer diff worker warmup

- DiffWorkerProvider no longer statically imports @pierre/diffs/worker or the
  theme registry, and no longer spawns 3 workers plus a main-thread shared
  highlighter during mount. Pools are created on demand through a dynamic
  module load, warmed via requestIdleCallback after startup settles, and
  useWorkerPool notifies consumers when a pool becomes available.
- ToolPart's rich diff preview moves to lazily loaded ToolPartDiffPreview;
  the plain-text patch (PlainDiffFallback) renders while the chunk loads,
  mirroring the existing error fallback. Theme registration happens during
  render inside the lazy module so PatchDiff never renders unregistered ids.
- ChatInput mounts its lazy ToolOutputDialog only after the first attachment
  preview opens instead of fetching the dialog chunk on the draft screen.
- getMarkdownSyntaxVars moves to a pierre-free markdownSyntaxVars module so
  eager code-rendering consumers stop importing the registration module.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* perf(web): load ghostty-web and Nerd Fonts on first terminal use

- ghostty-web (638 KB raw JS + WASM VT) is dynamically imported when a
  terminal actually mounts; TerminalView stays eagerly importable for the
  bottom dock.
- The ~2 MB of CDN Nerd Fonts are no longer preloaded and force-loaded on
  every cold start. index.html exposes an idempotent
  __openchamberEnsureNerdFonts hook; TerminalViewport requests it on mount
  and waits up to 2s so a cached font is in place before the glyph atlas is
  built, while a cold CDN fetch never blocks the terminal. Runtimes without
  the hook (VS Code, mobile) resolve immediately, matching their existing
  fallback-font behavior.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

---------

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-07 09:01:31 +03:00
Bohdan Triapitsyn da3d467f82 fix(desktop): recover from macOS directory permission failures #2744 2026-08-07 08:52:36 +03:00
deatheros f5603153df fix(ui): use readable permission error color 2026-08-07 02:29:27 +03:00
deatheros d8518bf053 fix(desktop): recover from macOS directory permission failures 2026-08-07 01:49:44 +03:00
Wsyjq 70226149ce fix(chat): pin existing-session sends to captured target (#2424)
* fix(chat): pin sends to captured session

* fix(chat): handle runtime cancellation consistently
2026-08-07 00:46:21 +03:00
Serhii Dziupin 834d2edb87 feat(ui,server): surface active instance service URLs in About settings (#2669)
Show the running instance's local server URL and tunnel URL (when a
tunnel is active) as labeled, click-to-open buttons on the About page.
/api/system/info now reports the instance port and tunnel URL, resolved
lazily from the tunnel runtime so each Git-worktree instance identifies
itself in the UI without parsing terminal output.

Refs OPE-194
2026-08-07 00:25:57 +03:00
Serhii DziupinandSerhii Dziupin 604da92fd9 fix(sidebar): keep permission badge and hover actions from overlapping (#2284)
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-06 19:57:07 +00:00
Serhii DziupinandSerhii Dziupin 652e9c0124 fix(sidebar): make file tree rows reliably clickable (#2368)
Native HTML5 drag starts after ~4px of pointer travel and suppresses the
click event for the gesture, so the draggable sidebar file tree rows
randomly ignored clicks on macOS trackpads/Magic Mouse: folders neither
expanded nor collapsed and files did not open.

Keep the rows draggable (dragging a file into the chat input inserts an
@mention) and recover the suppressed click on dragend: a drag that ended
within a small slop radius of its origin without dropping anywhere runs
the row's primary action. Also drop the misleading grab cursor so rows
read as clickable, matching FilesView.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-06 19:55:42 +00:00
Serhii DziupinandSerhii Dziupin d4cb73a1b3 fix(chat): render completed reasoning in full instead of simulating streaming (#2020)
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-06 19:55:17 +00:00
Serhii Dziupin c006f96811 fix(settings): let fixed-width controls scale with font size and density (#2320) 2026-08-06 19:54:33 +00:00
Serhii DziupinandSerhii Dziupin 6183ca6629 fix(chat): clamp text selection menu Y position to the viewport (#2257)
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-06 19:46:21 +00:00
Aman Tahiliani bcc64f7586 fix(settings): preserve notification template edits (#2300) 2026-08-06 21:17:16 +03:00
Sérgio Pedro fa63866cbb fix(ui): make overlay scrollbar persistent on desktop shells (#2581)
PR #2520 fixed #2475 in the wrong layer (overflow classes on
SettingsView.tsx wrapper divs that aren't the actual scroll containers),
so the "no scrollbar in Settings" bug shipped in v1.17.2 unchanged, and
the sessions feed has the same underlying issue (#2402).

The actual scroll containers render through ScrollableOverlay ->
OverlayScrollbar, which hides the native scrollbar and draws its own
JS thumb that auto-hides ~1s after scroll activity stops, with a
second CSS rule fully hiding that thumb inside Settings specifically.

Fix both at the shared component/CSS layer so every consumer (Settings,
sessions feed, git panels, chat, etc.) gets a persistent scrollbar on
desktop shells (Electron + VS Code webview) in one change:

- OverlayScrollbar.tsx: skip the auto-hide timer and show the thumb
  immediately on mount when content overflows, on desktop runtimes.
  userIntentOnly consumers (chat auto-follow scroll, reasoning blocks)
  keep today's intent-gated behavior unchanged.
- index.css: scope the Settings-specific hide rule to non-desktop, so
  mobile/web keep existing behavior and desktop gets the thumb back.
2026-08-06 21:10:22 +03:00
Pascal André 7d9af7aa3a fix(chat): expand shell output by default (#2492) 2026-08-06 20:58:49 +03:00
Serhii Dziupin 9368d44b99 Merge pull request #2685 from makeittech/fix/gh-2558-ios-shift-enter
fix(composer): restore Shift+Enter newline on iOS
2026-08-06 18:13:29 +03:00
Serhii Dziupin 99a6dcd052 Merge branch 'main' into feat/gh-2634-pending-question 2026-08-06 13:04:16 +03:00
Serhii Dziupin 5964a7d8ba Merge pull request #2698 from makeittech/feat/gh-2583-markdown-loops
feat(tasks): support markdown scheduled-task loops in .agents/loops
2026-08-06 09:57:49 +03:00
makeittech 59a6c1b70d fix(tasks): guard loop name length and surface loop ownership in the UI
Review follow-up:

- Reject loop files whose frontmatter name exceeds MAX_TASK_NAME_LENGTH
  (80): task names are clamped at storage time, so a raw name longer than
  the limit could never match the stored task identity. The file is treated
  as malformed (definition: null) instead of creating an unreachable
  definition; MAX_TASK_NAME_LENGTH is now exported from project-config.js
  and shared with loops.js.
- Surface loop-sourced tasks in the scheduled-tasks dialog: tasks carrying
  loopFile show a 'Managed by loop file <path>' note, and the enable
  toggle / edit / delete actions are disabled with an explanatory tooltip,
  since the file remains authoritative and would revert any such change.
  run-now stays available. New locale keys added to all 11 message files
  (i18n parity test enforces exact key sets).
- ScheduledTask type gains an optional loopFile field (additive, unknown
  to older clients).
2026-08-06 09:38:18 +03:00
Cursor AgentandSerhii Dziupin 938e58868f fix(ui): let Escape reach the terminal PTY from the context panel
The desktop ContextPanel captured Escape on the panel aside and closed
the whole pane before ghostty-web's bubble-phase listener could forward
the key. Skip closing when the event target is inside the terminal so
apps like Vim can leave insert mode.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-05 17:11:41 +00:00
Serhii Dziupin 23a677b45e Merge pull request #2679 from makeittech/feat/gh-2364-git-changes-count
feat(ui): show the changed-files count badge on the Git rail surface
2026-08-05 17:06:24 +03:00
Serhii DziupinandSerhii Dziupin 341b4b45c8 fix(ui): stop painting git activity dots on non-git rail surfaces
The badge PR inverted showActivityDot to !== 'git', so editor/terminal/diff
picked up the blue activity dot whenever git had changes. Git already shows
a numeric badge; other surfaces should stay quiet. Also split the count
aria/tooltip strings into singular/plural keys.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-05 13:26:46 +00:00
Serhii Dziupin 17d5b90d83 fix(ui): add in-document search to the Markdown file preview
The rendered Markdown preview had no way to search: the Electron desktop
shell implements no find-in-page at all, and CodeMirror's search panel only
exists in edit mode, so Ctrl/Cmd+F in the preview was a dead shortcut (web
browsers happen to find plain-DOM text natively, but desktop does not).

Adds a compact find bar for the rendered preview (Ctrl/Cmd+F or the search
button): case-insensitive match highlighting with a live count, Enter /
Shift+Enter and arrow buttons to navigate matches, Esc to close. Matches
are wrapped in <mark> elements and re-applied via MutationObserver when the
markdown renderer re-morphs the container (theme/content changes); svg
(mermaid) and script/style text is skipped. The pure match-range logic is
unit-tested.

Fixes #2401
2026-08-05 14:05:12 +03:00