Commit Graph
424 Commits
Author SHA1 Message Date
Iuliia IvashkoandClaude Opus 5 4dfbb5bd1c test(ui): pin who may record an explicit Default effort
Nothing covered ModelControls, which is where the effort restore decides
between "the user chose Default" and "nothing was found". Three cases: a
concrete effort in the session history is restored, history without an effort
records no choice, and a preserved manual override keeps a recorded Default.
The middle one fails on the previous commit's parent — it recorded `null` and
then `undefined` for the same restore.

Also drops the `fetchAll` binding GitView stopped using when the post-bootstrap
refresh moved to a forced `fetchStatus`; it was failing `bun run lint:ui`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZuVVgziiLjD81W5vaxdH2
2026-09-04 17:41:35 +03:00
Iuliia Ivashko 94c90a16b6 fix(ui): reconcile git state after worktree changes 2026-09-04 16:41:39 +03:00
Bohdan Triapitsyn 6fa2cb66d0 fix: scope instance-served state to the connected instance
Linear and GitHub logins, quotas, MCP status, skills and agent memory are
served by whichever instance is connected, but each was cached globally or
by directory alone — which two instances can share. Switching instances left
the previous instance's answers on screen and its Linear login usable against
a runtime that has no Linear.

Reset them all through runtimeEndpointReset, each store guarding its in-flight
requests with a generation so a response for the previous instance cannot land
in the new one. The Linear team filter is now persisted per instance: a team
belongs to one workspace, so carrying it across filtered the new instance's
issue list down to nothing.

Usage also waits for the instance to report itself initialised before loading.
Providers report themselves as configured only once the instance can read their
credentials, so a fetch fired at mount answered "nothing configured" for every
provider and cached it — which is why Usage stayed missing from the work-status
panel until Settings -> Usage forced a fresh fetch.
2026-09-03 11:49:34 +03:00
Bohdan Triapitsyn 29ca970362 fix: refresh terminal renderer after fonts load 2026-09-03 11:49:34 +03:00
𝖎𝖚𝖑𝖎𝖎𝖆 e885afbe89 Improve branch switch safety and recent branch status (#3302)
* feat(ui): block branch switches on dirty trees

* feat(ui): show unpushed commits in git branch selector

* feat(ui): show recent branches in git selector

* fix(ui): persist recent branch status

* feat(ui): add mobile branch picker

* fix(ui): guard mobile branch checkout

* fix(i18n): restore Turkish git empty state labels

* feat(ui): flag dirty draft directories on the branch selector

Replaces the draft dirty-directory banner with an indicator on the branch
selector: a warning icon plus a hover tooltip that opens by itself for five
seconds when the dirty state first appears, then stays hover-only. The copy
states the situation and the options (commit or worktree) without prescribing
either.

* feat(ui): optional push in the dirty branch switch dialog

Commit-and-switch gains an opt-in "Push after commit" checkbox. When the
push fails the commit stands but the switch is cancelled with an explicit
toast, so the user is never moved off a branch without knowing its push did
not happen. Without the checkbox the toast states the commit is local only.

* fix(i18n): align dirty-directory copy across locales

* fix(a11y): name the unpushed-commit badge in the branch picker

The badge showed a bare arrow and number with no accessible name or tooltip.
Both the desktop recents list and the mobile picker now carry a localized
"N commits not pushed" title and aria-label.

* fix(mobile): push before switching dirty branches

Honor the dirty-switch dialog's push option on the mobile Changes surface.
A failed push leaves the new commit on its source branch, refreshes state, and
cancels checkout. Mobile branch selection now also shows the existing dirty
switch notice.
2026-09-03 01:42:50 +03:00
Bohdan Triapitsyn 65054a5f4a feat(ui): gate the pull-request surface on GitHub, move the account into it, and GitHub sign-in into Integrations
The pull-request rail icon now appears only while GitHub is connected
(OAuth or gh CLI), like Linear; Linear sits after the walkthrough in the
default rail order. The GitHub account avatar and switcher leave the
header for the pull-request panel, where the walkthrough, refresh, and
account controls share one row and one height, and the account stays
visible on the panel's empty state. A manual refresh keeps its spinner on
screen long enough to read as work done.

GitHub sign-in moves from Settings → Git to Settings → Integrations →
Built-in integrations as a card before Linear; search and the connect
buttons follow it.
2026-08-30 14:17:12 +03:00
Bohdan Triapitsyn e338a9c561 fix(ui): nested repositories open diffs and report status from the selected repo
Opening a file from the Git panel while a nested repository was selected
created the diff tab under the repository path, a key the context panel
never displays. Tabs are keyed by the project root; the diff surface
resolves the selected nested repository itself.

The work-status Project section now reads branch, changes, and PR from the
same resolved repository as the Git tab and names the nested folder under
the branch so the reader knows which repository the readouts describe.
2026-08-30 11:17:38 +03:00
jaygupta17 f6ffb0a1fe Merge remote-tracking branch 'origin/main' into feat/nested-git-repos
# Conflicts:
#	packages/ui/src/components/views/GitView.tsx
#	packages/ui/src/stores/DOCUMENTATION.md
#	packages/ui/src/stores/useGitStore.ts
2026-08-30 09:48:35 +05:30
Alex Kutas 49f0a9e62f OPE-296: Add linear integration for starting sessions from issues (#3235)
* feat(linear): start sessions from Linear issues
Authorize a Linear workspace on this OpenChamber server, map teams to
projects, attach an issue from chat, start a session or worktree from an
issue, and post started/completed/failed comments that open the session.
Hidden in VS Code.

* feat(linear): connect more than one Linear workspace

Store each OAuth grant on this OpenChamber server and keep one current, so Settings can add and switch workspaces without dropping the others. Project mapping is per workspace. Remove the Linear button next to New Chat; start-from-issue stays on New Worktree.

* feat(linear): add a right-hand issues panel

Browse and filter issues in the rail, open a card to change status or start a session, and collapse search plus most filters to icons on a narrow panel.

* feat(linear): open issues in the rail and filter by Linear status

The rail icon only shows after Linear is connected. Clicking a Linear row on work status opens the panel. Status options match the card, including Done, Canceled, and Duplicate. The Integrations experimental warning sits under Third-party integrations.

* fix(linear): use stable OAuth callback broker

* fix(chat): preview Linear issue attachments

The context switch missed linear-issue, so tsc treated the preview helpers as incomplete.

* fix(ui): restore Linear i18n parity and the #2903 sync harness

Turkish was missing the Linear dictionaries, and the subagent test still wrapped only SyncContext after reads moved to SyncRuntimeContext.

* fix(linear): drop changelog hunks and close review races

Keep changelogs out of this PR, restore CodeMirror ranges, ignore stale Linear list pages, and leave a persisted Linear tab open until auth has actually resolved.

* fix(linear): tint active issue filters and clear them in one click

* fix(markdown): read escaped brackets as text, not display math

`\[...\]` is display math in LaTeX and an escaped bracket pair in
CommonMark. The block tokenizer claimed every `\[`, so prose like
`[title \[Bug\] more](url)` was handed to KaTeX: "Bug" rendered as a
centered formula and the block token split the paragraph, tearing the
link into three pieces. Linear, GitHub and any other source that escapes
brackets the way CommonMark requires hit this.

Display math now has to own its line — `\[` starts one and `\]` ends
one. A formula on its own line still renders; `\[` mid-sentence stays an
escape, which is what CommonMark says it is and what prose almost always
means. Inline `\(...\)` keeps the same ambiguity, but inline math is
legitimately mid-sentence, so there is no position to judge it by.

Covered by regression tests, including the verbatim comment body that
surfaced this.

* feat(linear): make session status comments opt-in and public-only

A status comment lands in a Linear workspace the whole team reads, and
the link it carried pointed at whatever origin started the session —
usually loopback or a LAN address. Everyone but its author got a dead
link, and nobody had agreed to the comments in the first place.

Comments are now off until the user turns them on in Settings ->
Integrations -> Linear, and the check lives on the server: the event hub
posts completed and failure without going through the interface, so a
client-side gate would not hold. When the resolved origin is not
publicly reachable the server posts nothing at all rather than a link
only its author can open; `isPublicSessionOrigin` rejects loopback,
private LAN, carrier-grade NAT, link-local and single-label hosts. The
desktop deep-link origin is gone with it, since no one else can follow
one either.

The comment body also dropped the session title. It repeated the issue
the comment already sits on, and issue titles routinely carry brackets
("[Bug] ...") that broke the markdown link. The body is now one short
link, and `sessionTitle` is gone from the route, client and types.

Also caps the dedupe file at the newest 500 sessions; it grew forever.

* fix(linear): match the pull request panel and clear review findings

Comments in the Linear panel now render as the same avatar timeline the
pull request panel uses, with the shared time-format preference instead
of a raw locale string. Comment authors carry `avatarUrl`, which the
GraphQL selection was not requesting.

Review findings from the same pass:

- `status-runtime.js` hand-rolled `typeof` narrowing and failed the
  vendored anti-slop lint; it now parses through `parse.js` like every
  other file in the module.
- `useLinearAuthStore` turned any failed request into `connected: false`
  with `hasChecked: true`. Since the rail icon, the composer entry and
  the worktree option all gate on `connected === true`, one network blip
  hid Linear for the rest of the session, and Settings only re-checked
  when it had never checked. It now keeps the last known status and
  leaves `hasChecked` false so the next caller retries.
- `LinearIssuesView` (1096 lines) was a static import in `ContextPanel`,
  shipping in the main bundle although its rail icon stays hidden until
  a workspace is connected. It is lazy now, like `GitView`.
- Dropped dead code: the unused port helpers left over from the loopback
  callback, two re-exported default values nothing read, and a redundant
  export in `linkedIssues`.
- Integrations is no longer badged beta.
2026-08-30 02:18:40 +03:00
Bohdan Triapitsyn 123c14260a fix(files): let Cmd/Ctrl+F reach the Markdown preview find bar
The find_in_file keybind only opens the preview find bar when the event
target sits inside the preview container, but that container was a plain
div that never held focus, so the shortcut did nothing in read-only preview.
Both preview containers are focusable now and take focus when a Markdown
file opens in preview or is clicked, without stealing focus from a field
the user is typing in.

Claude-Session: https://claude.ai/code/session_017TK5JAYDfT3Fotc23UEg98
2026-08-29 15:06:54 +03:00
Naputt1 523a62e4db fix(git-graph): keep passing for reused merge parent to close lane gap (#3222)
Thanks for the crisp fix and regression test! Merging.
2026-08-29 10:36:24 +03:00
Bohdan Triapitsyn 48bcac1758 fix: harden and de-slop the merged sidebar/chat/settings batch
Post-merge follow-ups for #2740 #2735 #2734 #2690 #2676 #2738 #2684
#2689 #2733 #2739 #2462 #2687 #2736 #2618 #2697, plus three regressions
found while reviewing them:

- ctrl/cmd+digit while typing no longer switches session tabs (#2503 was
  still open in practice: the guard only covered the mod+alt surface binding)
- Shiki template-call sanitizer now covers every bundled grammar, including
  the js/ts aliases and embedding grammars; timed-out highlight requests are
  memoized and no longer cancel unrelated in-flight requests
- settings flush on suspend uses keepalive and also fires on Capacitor
  appStateChange; keeps the selected model persisted across mode switches
- remote-only branches fetch before checkout; range helpers fail clearly
- git status invalidation now fires for runtime adapters too
- settings number inputs and select triggers size in ch so they scale with
  the interface font
- recent-activity timestamps tick from one list-level ticker
- Markdown preview find goes through the shared find_in_file keybind with
  containment, no longer counts its own bar, and debounces observer runs
- #2676 reverted; #2524 fixed by fading the sticky header's own background
  instead of overlaying the content below it
- sticky group headers in the model picker and sidebar render again
  (oc-sticky-fade-scroller class restored after 9b9d7069c)
- project switcher names are left-aligned again (wrapper lost in 26dbc2f30)
- tool card quick-open icon is always visible and opens the same line as the
  expanded card's button
- tautological tests replaced or removed; new oxlint findings fixed
2026-08-29 01:06:43 +03:00
Bohdan Triapitsyn e47d87c3d6 feat(ui): add in-document search to the Markdown file preview
Ctrl/Cmd+F (and a toolbar button) opens a compact find bar over the
rendered Markdown preview, with match highlighting, a live count, and
next/previous navigation that scrolls the current match into view.
Escape closes the bar and returns focus where it was.

Merge follow-ups on top of the contribution: mount the bar in the
fullscreen viewer as well as the inline preview, combine it with the
FilePreviewCommentMenu wrapper that landed on main, debounce the
highlight pass so typing does not re-walk the whole document on every
keystroke, use the status-warning theme utilities instead of raw CSS
variables for the highlights, and add the Turkish strings for the
locale added after the branch was cut.

Closes #2401
2026-08-28 23:48:35 +03:00
Iuliia Ivashko 01b3e3346f fix(git): check out a local tracking branch when a remote branch is picked 2026-08-28 15:45:43 +03:00
Bohdan Triapitsyn b8465ae133 fix: harden and de-slop the merged contribution batch
Follow-ups promised on merge, plus review findings on the batch itself:

- chat: task-tool output now respects the 512KiB render cap; quick-open
  icon is visible at rest on coarse pointers and reachable by keyboard
  (row keydown no longer swallows inner-button Enter/Space); composer
  inline-code decoration drops the metric-shifting padding; a btw fork
  send carries only the boundary instruction, never the promotion notice
- sync: cascade revert/unrevert aborts busy descendants, busy state is
  read from every child store at the moment of use; rule 9 documents
  redo clearing all descendant revert markers
- electron: renderer recovery keeps memory-eviction (a valid
  render-process-gone reason) and both windows share one
  attachRendererRecovery helper
- vscode: process registry is a thin re-export of the web module
  (provider-env-aliases precedent) with ordered register/unregister
  writes and an awaited close
- server/cli: managed-process registry takes injectable deps (fixes the
  unreaped-orphans ReferenceError), corrupt settings errors name the
  file, getWorktrees test restores console.warn
- tests: module-mock harnesses removed (AgentsSidebar, SettingsView
  mobile focus — behaviors stay live but uncovered, accepted trade),
  QuestionMarkdown asserts rendered DOM
- i18n: German gains the debug-panel request keys, Japanese/German drop
  removed worktree keys, Ukrainian unit spacing fixed
- changelog: Copilot AI Credits entries (main + VS Code)
2026-08-28 02:08:09 +03:00
Bohdan Triapitsyn f64d8b59c8 Merge pull request #3109 from bashrusakh/fix/2982-mobile-agent-duplicate
fix(agents): open duplicate editor on mobile
2026-08-28 01:23:34 +03:00
Bohdan Triapitsyn 073c55a129 Merge pull request #2858 from TomzxForks/issue-2847
Remove the 5-model limit on multi-run groups
2026-08-28 01:23:28 +03:00
Bohdan Triapitsyn 43c4cc625f fix(ui): open saved plans against their owning project
Saved Project knowledge plans opened as an empty editor whenever the
viewer could not resolve the owning project from the current directory:
managed chats (openchamber:chats is not a registered project), worktrees
outside the repo path, and plan tabs restored after a reload. Titles
still rendered because the list reads the manifest through the correct
owner.

- Thread the owner explicitly (savedProjectPlan = { projectRef, planId })
  from the panel, mobile surfaces, and persisted context tabs; PlanView
  no longer guesses the project.
- An unrecognized directory resolves to no owner instead of borrowing
  the active project's knowledge.
- Serialize plan writes per document (planSaveQueue) so close/switch
  within the autosave debounce no longer drops the last edits, saves
  cannot land out of order, and a recovered save clears the error banner.
- Send saved-plan contents inline in Improve/Implement prompts (they
  have no file path); disable those actions for managed-chat plans,
  which have no project directory to create a session in.
- Drop persisted plan tabs that carry an id without an owner rather than
  reopening them against a guessed project.
2026-08-27 20:18:12 +03:00
Bohdan Triapitsyn f2ec9b1003 feat(ui): add session history navigation, permission keys, and review shortcuts
mod+alt+arrows step through this window's session-open history (or between
neighbouring tabs when session tabs are on), mod+k r renames the current
session inline, and mod+k a toggles permission auto-accept. Pending
permission cards respond to alt+enter / alt+shift+enter / alt+backspace with
the keys printed on the buttons. The commit message box commits on
mod+enter, alt+arrows step the diff review between changed files, and the
command palette gains search-only commands for rare actions so the initial
list stays short.
2026-08-26 15:46:44 +03:00
Bohdan Triapitsyn 94f6b5fd38 feat(ui): migrate all shortcut surfaces to the centralized registry 2026-08-26 10:59:04 +03:00
jaygupta17 e19b6ad3be Merge remote-tracking branch 'origin/main' into feat/nested-git-repos
# Conflicts:
#	packages/ui/src/lib/addSelectionToChat.test.ts
2026-08-26 09:22:57 +05:30
Bohdan Triapitsyn f0b1c889f0 Merge main into pr1-large-file-preview
The floating editor toolbar this branch was based on was removed on main
(the toolbar is always docked now); the file-view region resolves to
main's structure with this branch's virtualizer-bound ScrollableOverlay.
2026-08-26 02:26:20 +03:00
jaygupta17 72c1d28fc6 fix(ui): drop unused nestedRepoSelection binding and stale review-flow dependency 2026-08-25 21:09:39 +05:30
jaygupta17 11a48958e8 fix(git): resolve blank nested-repo surfaces; add repository pickers
The resolution gate on the pull-request, walkthrough, and mobile changes
surfaces stayed on forever (rootIsGitRepo stays false on a non-repo
root) while NestedRepoResolutionStates exits once the selected
repository probes as a repository, so those surfaces rendered nothing.
The gate now shows resolution states only while the operating directory
has not proven to be a repository, matching GitView.

Extract GitHeader's repository switcher into git/NestedRepoPicker and
mount it in the diff toolbar, a new slim header in the pull-request
view, the walkthrough header, and the mobile changes header. The pick
is shared per root, so every surface follows.

The walkthrough tab mounts keep-alive and hidden; it now receives a
visible prop so discovery waits until the tab is actually opened. Add
component tests for the shared resolution states.
2026-08-25 20:47:02 +05:30
jaygupta17 e26b55e067 fix(git): exit nested-repo states once resolution succeeds
NestedRepoResolutionStates had no success exit: on a non-repo root
rootIsGitRepo stays false forever, so once repositories were found the
pull-request and walkthrough tabs kept showing 'Checking repository'
even after the selected repository probed as a repository. GitView never
hit this because its call site sits inside its own isGitRepo === false
branch. The component now takes the operating directory's probe and
returns null when it resolves true.

DiffView also still keyed its not-a-repository gate and every diff
fetch off the raw project root, so opening a change from a nested
repository showed 'This directory is not a Git repository'. It now
resolves the nested repository for git data and diff operations while
session-scoped lookups (session messages, review-flow directory) stay
on the root.
2026-08-25 19:55:00 +05:30
jaygupta17 cda273d69f feat(git): resolve nested repositories in the other git surfaces
Extract GitView's resolution flow into hooks/useNestedGitDirectory (root
probe, discovery, auto-select, stale-selection recovery) so the flow no
longer depends on SessionSidebar probing the root first, and reuse it in
the pull-request view, walkthrough view, and mobile changes surface —
all three now operate on the selected nested repository instead of
dead-ending on a non-repo root. Shared pending/failed/unsupported/empty
states live in git/NestedRepoResolutionStates; desktop changes inherits
the behavior through GitView. Selection stays shared per root, so the
picker's pick carries across surfaces.
2026-08-25 19:15:53 +05:30
jaygupta17 f56b934dc9 Merge remote-tracking branch 'origin/main' into feat/nested-git-repos
# Conflicts:
#	packages/web/server/lib/fs/routes.test.js
2026-08-25 18:39:25 +05:30
Bohdan Triapitsyn b6e14cbf21 refactor(settings): always-docked editor toolbar; reorder Navigation
The 'Always show editor toolbar' preference is gone — the docked
toolbar under the file tabs is now the only mode, and the floating
hover toolbar branch in the files editor (with its open-state and
outside-click machinery) is deleted. The stored preference is dropped
by a store migration and removed from desktop settings persistence,
settings search and every locale.

Navigation section order now reads: file editor keymap, auto-save,
terminal shell + login shell, Terminal Quick Keys, and the Session
tabs group last.
2026-08-25 00:32:09 +03:00
bashrusakh a894a80c0d fix(agents): open duplicate editor on mobile 2026-08-25 07:37:02 +11:00
Bohdan Triapitsyn c82f188fc8 refactor(surface): remove the main-area surface concept entirely
activeSurface was permanently 'chat' after the legacy mobile layout
removal, so the whole concept is gone: the store field, surfaceGuard,
setActiveSurface/setSurfaceGuard, the per-runtime surface memory in
prepare/restoreForRuntimeSwitch, and WorkspaceSurface itself. All ~30
setActiveSurface('chat') call sites were no-ops and are deleted;
always-true 'is the chat active' checks in keyboard shortcuts, Header
and ChatContainer are unconditional now. FilesView's dirty-file guard
kept its file-switch and close protection but drops the surface-switch
branch nothing could trigger. TerminalView visibility comes only from
its callers. The router keeps parsing legacy ?tab= links (they open the
matching context-panel surface) via its own RouteTab type and no longer
serializes a tab or diff file into URLs — desktop URLs never carried
them anyway.
2026-08-24 16:36:41 +03:00
Bohdan Triapitsyn 4da7604d7d refactor(surface): drop the deprecated main-tab aliases and dead diagram surface
MainTab/activeMainTab/setActiveMainTab/setMainTabGuard were deprecated
mirrors of the surface names — every call site now uses
activeSurface/setActiveSurface/setSurfaceGuard directly and the aliases
are gone, including the persisted mirror field.

The 'diagram' surface had no way to open it (navigateToDiagram had no
callers except a .drawio attachment click that navigated to a surface
nothing rendered); the surface, DiagramView, and its store plumbing are
removed, and a .drawio attachment now opens in the file panel.

?tab= deep links map to the matching context-panel surface instead of
setting a main-area surface nothing renders, and a persisted non-chat
surface can no longer rehydrate into a blank main area.
2026-08-24 16:21:05 +03:00
Bohdan Triapitsyn b8716fe808 refactor(search): unify dropdown filtering on the shared ranked matcher
Branch, project, agent, model, provider, stash, SSH-host, skill-catalog
and archive filters each had their own toLowerCase().includes (or no
ordering at all); the git branch and gitmoji pickers also let cmdk
re-filter and reorder on top of the manual filter, silently dropping
rows. All of them now go through rankByQuery/matchesRankQuery: results
are relevance-ordered, multi-word queries match in any order, matching
ignores punctuation, and cmdk filtering is disabled where the ranked
list is already final. rankBranchesForQuery keeps relevance order
instead of re-sorting matches alphabetically; the model picker now also
matches model ids.
2026-08-24 15:00:52 +03:00
Bohdan Triapitsyn 2f27f0ec4b fix(terminal): reconcile tabs with server sessions and keep shown terminals alive
The tab list lived only in per-tab sessionStorage, so a new browser
tab, another device, or cleared storage showed an empty terminal
sidebar while PTYs kept running server-side, and orphans leaked until
the idle sweep. Add GET /api/terminal/sessions and adopt unknown
server sessions into the local tab projection (additive only; a failed
listing changes nothing).

The idle sweep also reaped terminals in background tabs because only
the active tab holds a WebSocket attachment. Add POST
/api/terminal/touch and have open clients periodically refresh
activity for every session their tabs reference.
2026-08-24 14:30:00 +03:00
Bohdan Triapitsyn eb03ffaa80 feat(files): comment on selection in read-only markdown previews
Selecting text in a rendered markdown preview shows a Comment pill;
attaching stores a file-quote context draft carrying the file path, the
selected fragment (not whole lines), the user's comment, and a
best-effort source line range resolved by anchoring the fragment's
first and last lines in the raw content — a partially located fragment
gets no range rather than a misleading one. The fragment stays
highlighted while the comment input is open, using the selection
overlay rects shared with chat quote comments, and the preview's
native selection color now matches chat messages. file-quote flows
through the same context contract: composer chip previews, the message
context card, and the metadata round-trip.
2026-08-24 01:21:35 +03:00
Bohdan Triapitsyn e47c027ea0 feat(diff): unified comment UI with gutter plus and content-drag selection
The diff comment editor is restyled as the shared comment pill (context
line inside the box, auto-growing textarea, round attach button;
Cmd/Ctrl+Enter attaches, Enter breaks the line) and the saved-comment
card matches the composer preview entries. Pierre's gutter utility is
enabled: hovering a line shows a small primary-colored plus that opens
a comment for the line, dragging from it selects a range, and it rides
the bottom of an active selection. Clicking a diff line toggles a
single-line comment, and dragging over content maps to the same line
selection the number column produces — the native text selection is
suppressed once a drag crosses a line boundary — opening the editor for
the range on release. Placeholders and meta lines are dimmed relative
to typed text.
2026-08-24 01:02:33 +03:00
Bohdan Triapitsyn 1ae3aeff5f feat(chat): structured context attachments with metadata round-trip
Every user-attached context item (diff/file/plan comments, terminal
selections, browser annotations, PR comments and failed checks, linked
issues/PRs, and new chat-quote comments from the selection menu) is now
sent as its own synthetic text part carrying an openchamberContext
metadata payload. The model-facing text keeps the previous wording; the
timeline reads the metadata back and renders each item as a context card
instead of raw prompt text. Legacy messages still render via the old
text sniffing.

The selection menu gains a Comment option with an inline multiline
input, the quoted fragment stays highlighted while commenting, and on
mobile the input overlays the composer pill by rendering inside the
composer form. Add to chat is renamed Add to input; the menu is
restyled and the mobile Copy tile removed. Terminal drafts move their
terminal id out of the language field (persisted-draft migration v3),
and the dead preview-console source is deleted.
2026-08-23 23:40:32 +03:00
Bohdan Triapitsyn 0079347edc refactor(settings): scope the settings project selector to settings
Picking a project in Settings called setActiveProject, which relocates
the chat, the session list, the file tree and the Git surface. Reading
another project's MCP servers or agents moved the user's whole app.

It had to, because the configuration stores resolved the directory
themselves from the active project and held one flat list. Each of them
now takes an explicit directory — omitted still means the active project,
so every caller outside Settings is unchanged — and keys loaded data by
directory next to a flat mirror of the active project. Chat, autocompletes
and pickers keep reading that mirror; a load for another directory writes
only the map. A failed load restores that directory's previous list.

Settings resolves its own directory through useSettingsDirectory, backed
by a session-local settingsProjectPath that follows the active project
until the user picks something else.
2026-08-22 20:31:31 +03:00
Pascal André c452a8092c fix(files): refresh expired outside-workspace grants (#3078)
* fix(files): refresh expired outside file grants

* fix(files): scope outside grants to local runtime
2026-08-22 20:26:20 +03:00
Bohdan Triapitsyn 0b01f5ae2d feat(diff): add branch scope to context panel diff view
Show every change on the current branch relative to its base in the
Changed/Staged/Last turn dropdown. The base comes from the branch's
reflog record or an explicit per-branch user choice (persisted), never
a main/master guess; when git has no record the user picks a base once
from a searchable branch list.

- server: GET /api/git/branch-base (reflog-derived base),
  GET /api/git/range-files (name-status -z with rename/copy
  destination paths and -C copy detection)
- shared UI: optional getBranchBase/getGitRangeFiles runtime APIs
  with boundary parsing; persisted per-branch overrides keyed by
  runtime+directory+branch
- DiffView: branch scope with confirmed-unavailability coercion of
  persisted tabs (detached HEAD, default-branch checkout, metadata
  settled without a default), range-invalidated diff cache guarded
  against stale completions, bounded branch-metadata retry, read-only
  diff actions in branch scope; hidden in VS Code
- helper module branchDiffScope.ts with tests for coercion,
  availability, race conditions, and retry exhaustion
2026-08-22 01:10:19 +03:00
Bohdan Triapitsyn f29844b2f1 feat(settings): mark integrations as experimental 2026-08-22 01:10:19 +03:00
Bohdan Triapitsyn 70a7a77ded refactor(ui): name workspace surfaces 2026-08-22 01:10:19 +03:00
gaojunran ae1c6de470 feat(ui): virtualize large file preview in FilesView
Files above the editable size cap (MAX_VIEW_CHARS) now render their full
content through pierre's Virtualizer (viewport-only DOM) with highlighting on
the shared Shiki worker pool instead of a 200k-char main-thread-highlighted
slice.

Also fixes a pierre virtualization deadlock: forcing the virtualized host to
viewport height decoupled the IntersectionObserver judgment box from the
scroll content height, so a large scroll jump blanked the file (0 lines).
The large-file host now keeps no fixed height; the observer always sees it
intersecting.

Addresses #2868 (part 1: large-file preview virtualization).
2026-08-22 02:33:28 +08:00
99873a7b12 fix(files): harden drag-and-drop uploads
Co-authored-by: Serhii Dziupin <serkraser@gmail.com>

Co-authored-by: Alan Chen <2144783+alanzchen@users.noreply.github.com>
2026-08-18 23:16:46 +03:00
Bohdan Triapitsyn 34e8a24b20 feat(knowledge): rebuild the project notes panel as Project knowledge (#2973)
The panel stored notes, todos and plans inside one shared JSON file that
six unrelated domains also wrote to, synchronised itself through window
CustomEvents, and could only read plans. It is now Project knowledge:
server-owned storage with explicit routes, a store with rollback, a
section sidebar, plans that open and edit in place, and search across
all of it.

Notes and plans the user pins travel with every message sent in that
project. Pinning is project state, not an attachment to one message, so
it holds until unpinned and the work status panel names what is riding
along and can detach it.

Agent memory is added alongside, in two scopes: what is true about the
user, and what is true about this codebase. The split is not cosmetic —
a wrong project fact costs one project and is noticed, while a wrong
global fact quietly shapes every session everywhere and the user has no
code to check it against. It stays separate from notes so an agent
mistake cannot land in what the user wrote. Sessions receive an index of
titles only; bodies are read on demand, because an index carrying full
text grows until it crowds out the conversation.

Deciding what a session must be told, and whether it has been told, now
lives on the server. The client owned it before, which meant sessions
started without a UI — scheduled tasks, sessions the agent dispatches —
received nothing at all, and a tab's record of what it had sent outlived
the conversation: after compaction the agent no longer held the block
while the tab went on believing it did. What was delivered is recorded
in the session's own metadata, and compaction restores it through the
runtime that already restores pinned messages, in the same turn.

Agent memory ships dark behind OPENCHAMBER_MEMORY_ENABLE: unset, there
is no tool, no routes, no session index, no settings row and no panel
tab. Absent rather than switched off, so nothing invites turning on a
feature that has not been announced. Pinned notes and plans are
unaffected and ship as normal.
2026-08-18 02:59:04 +03:00
Bohdan Triapitsyn 268f9ea9f2 fix(github): keep merged PRs as branch history instead of hiding them
Branch status resolves an open PR across the whole fork network first, so a
merged fork PR can never hide an open upstream PR for the same head. Only when
no target has an open PR does the branch's newest closed/merged PR come back,
as history.

The panel shows that history as a compact note and offers creating the next PR
below it, instead of either sticking on a terminal PR or going blank after a
merge. Terminal associations stay persisted for reload continuity but are never
treated as authority: they revalidate on the discovery cadence and on focus.

History is looked up only for the branch's own remote and name, and remembered
per repo+branch, so the extra lookup cannot exhaust the route's resolve budget.
The checks summary and merge-permission lookup are skipped for a closed or
merged PR, where neither is actionable.
2026-08-15 17:56:55 +03:00
Serhii DziupinandSerhii Dziupin 5e9e35897f fix(github): harden terminal PR revalidation after critical review
Recompute focus/visibility staleness at event time, retry closed/merged
sidebar associations on the no-PR cadence, and assert refresh failures
preserve prior PR status.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-15 04:27:02 +00:00
Serhii DziupinandSerhii Dziupin 962b016cbd fix(github): stop stale merged PRs from sticking in branch status
Branch PR status now resolves open PRs only, revalidates closed/merged
associations on a discovery cadence, and clears authoritative empty
results so the panel can self-heal without a manual refresh.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-15 04:27:02 +00:00
Serhii DziupinandSerhii Dziupin 903638db94 fix(ui): show embedded subagent history while visibility stays inactive
Busy context-panel session chats could render only the working-status row
when the iframe booted inactive or lost its visibility handshake, because
message reads shared the composer/background-work gate. Keep message
subscriptions enabled in the mounted session-chat panel so materialized
history remains visible (#2903, #2892).

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-15 03:40:37 +00:00
Serhii DziupinandSerhii Dziupin af380081c2 feat(settings): add third-party integrations dashboard
Add a Settings → Integrations page for installing and managing the three
supported OpenCode provider plugins (Claude Code, Command Code, Cursor),
with search, i18n, and plugin-registry status wiring.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-14 15:19:25 +00:00
Bohdan Triapitsyn 2a5be62c58 fix(git): clarify GitHub pull request link 2026-08-13 23:44:49 +03:00