Commit Graph
2705 Commits
Author SHA1 Message Date
Bohdan Triapitsyn 83ea72de0e feat(chat): messenger-style context cards with message-level collapse 2026-08-24 12:46:14 +03:00
Bohdan Triapitsyn cd2a3efcdf fix(chat): keep selection comment popup below the desktop drag header 2026-08-24 12:17:13 +03:00
Bohdan Triapitsyn 58a193aa87 feat(ui): glass surfaces for selection menus and comment popovers
The chat selection menu (desktop pill and mobile sheet), the chat
comment input, the file-preview Comment pill, the shared inline comment
editor, and the composer's context chip preview popover now use the
same translucent blurred glass surface as the btw panel, keeping their
borders and soft shadow.
2026-08-24 01:49:10 +03:00
Bohdan Triapitsyn d678a4244e fix(mobile): knowledge panel tabs, autocomplete height floor, status row gap
The project knowledge panel's section sidebar becomes a horizontal pill
strip on mobile, where a half-width side column left no room for
content. The autocomplete popups get their 120px minimum height back —
browser keyboard panning could put the anchor above the measured
boundary and collapse them to nothing. The status row's 24px footer-swap
reservation now applies only to the assistant-status instance; the
accessory-only row above the composer (pending changes) takes the
normal 8px instead of floating a stray gap.
2026-08-24 01:44:15 +03:00
Bohdan Triapitsyn a547f83ebe docs: draft Unreleased changelog entries 2026-08-24 01:28:53 +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 538b532fb1 feat(composer): context chip previews with inline comment editing
Hovering (or tapping) a context chip opens a stacked preview of its
pending items above the composer: numbered entries with a muted header
band, the captured selection, and the user's comment, which can be
edited in place (save/cancel) or removed before sending. The chips
component now subscribes to the draft store itself; the per-kind count
plumbing in ChatInput is gone.
2026-08-24 00:16:26 +03:00
Bohdan Triapitsyn c3f89e0106 fix(ui): soften btw panel shadow
Replace the floating-glass elevation stack with the composer pill's
soft shadow and a plain theme border; the glass background and blur
stay.
2026-08-23 23:40:41 +03:00
Bohdan Triapitsyn f007d07bee fix(desktop): serve packaged index.html with no-store
The openchamber-ui:// handler returned index.html without cache
headers, so the renderer disk cache could keep a freshly installed
build loading the previous version's hashed bundles. Hashed assets
stay cacheable; only the document that names them must not be.
2026-08-23 23:40:40 +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 1af8b14bbb fix(chat): unify OpenCode notice styling 2026-08-23 19:13:14 +03:00
Bohdan Triapitsyn 264ea02ee1 fix(ui): constrain draft menus to chat area 2026-08-23 18:27:35 +03:00
Bohdan Triapitsyn 2ca3280b39 fix(ui): keep draft dropdowns below header 2026-08-23 17:24:59 +03:00
Bohdan Triapitsyn 421a868a1a feat(ui): add Linear and Cloudflare tool icons 2026-08-23 17:21:31 +03:00
Bohdan Triapitsyn 526bbe246d fix: delay sidebar item tooltip hover 2026-08-23 16:01:30 +03:00
Bohdan Triapitsyn 9a40eea7c1 fix: include archived sessions in header lookup
Header now finds the current session in archived sessions too.
2026-08-23 15:54:28 +03:00
CodeNebula 236accedc4 fix(ui): make timeline dialog fit small screens (#3090)
* fix(ui): make timeline dialog fit small screens

On phones the timeline dialog squeezed the message list to a couple of
rows: header, search box, and the fixed Actions/help block consumed
almost all of the 70vh dialog height, and the description text could end
up underneath the search box.

The dialog no longer scrolls as a whole. The header and search stay
fixed (shrink-0), the message list is the only scrollable region and
takes the remaining height (min-h-0 flex-1), the dialog is taller on
small screens (85dvh), the Actions/help footer collapses to a single
action row on phones, and the description is hidden on phones only.

Message timestamps no longer wrap either: the time column grows from a
fixed 64px minimum and forces nowrap, so "11:14 PM" stays on one line.

* fix(ui): keep dialog-level scroll fallback in timeline

overflow-y-visible removed the reusable dialog's built-in scrolling
fallback: the timeline's header, search, and footer are all shrink-0,
so under constrained layouts (very short desktop windows, enlarged
text) the fixed controls could leave the popup with no way to reach
them once the message list collapsed to zero.

Revert to overflow-y-auto. The list is still the only flex-1 min-h-0
child and absorbs space first, so normal mobile and desktop layouts do
not scroll; only when fixed content exceeds the dialog height does the
popup scroll again, keeping every control reachable.
2026-08-23 15:53:19 +03:00
Bohdan Triapitsyn fe80d246ea release v1.20.0 2026-08-23 02:10:48 +03:00
ChangeHowandBohdan Triapitsyn 3a78d86248 fix(ui): open app deep links from chat after confirmation (#2932)
* fix(ui): open app deep links from chat after confirmation

DOMPurify's default URI policy stripped href from anchors with custom
application schemes (obsidian://, vscode://, ...), so every app link
rendered in chat was dead across web, desktop, VS Code, and mobile.

- Classify safe app-link schemes in lib/url.ts (browser-handled,
  scriptable, webview-internal, network, and self-deep-link schemes
  stay excluded) and let openExternalUrl accept them
- Keep app-link hrefs through the markdown sanitize hook
- Intercept app-link clicks in the markdown renderer and route them
  through a confirmation dialog (Trust and open / Open once, dismiss
  to cancel) mounted in the desktop/web app root and the mobile shell
- Persist per-device trusted schemes in a zustand store; trusted
  schemes open without asking again

* feat(settings): manage trusted app link schemes in General

Add an App links section to Settings > General listing the application
schemes trusted on this device with a delete action; removing a scheme
restores the confirmation dialog for it. Register the section in
settings search.

* fix(ui): enforce app link confirmation

* fix(ui): handle app links by runtime

* fix(vscode): keep app links unsupported

* fix(settings): clarify trusted app links

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-08-23 01:53:21 +03:00
Bohdan Triapitsyn a5b0272f01 chore: update unreleased changelog 2026-08-23 01:05:14 +03:00
Bohdan Triapitsyn 8f2c1ecc8b fix(chat): hide autocomplete tooltips on mobile 2026-08-23 01:05:09 +03:00
Bohdan Triapitsyn 1a627e06ad docs(changelog): note /btw side questions and the status-line handoff 2026-08-23 00:42:23 +03:00
Bohdan Triapitsyn 3195fb1190 fix(chat): make the working status row swap seamlessly into the turn footer
The streaming status line and the finished turn footer are the same visual
line, but the swap used to jump: different font/color, a 2px left inset, a
20px row vs the footer's 32px (its h-8 action buttons set the height), and
the bottom-anchored chat pulling the line up because the finished message
carries more structure below its footer than the status row had.

Match the footer exactly: text-sm at muted-foreground/60, no left inset,
h-8 row, and mb-6 reserving the missing space below. Verified against the
live DOM: the footer appears at the exact pixel position the status row
occupied.
2026-08-23 00:41:40 +03:00
Jay GuptaandBohdan Triapitsyn 46426e8495 feat(chat): /btw — side questions in a temporary forked session (#2796)
* feat(chat): /btw command — side questions in a temporary forked session

/btw <question> forks the current session (full context inheritance) and
opens a compact peek panel docked above the composer. The composer itself
becomes the btw input while the panel is open: sends route to the fork,
the placeholder and a mode chip reflect the target, and the stop button
aborts the fork's turn. Closing the panel (or the chip's ✕) destroys the
fork, leaving the main conversation untouched.

The panel shows only the fork's own tail (messages at/after the fork
creation time) and live permission/question cards scoped to the fork.

- chat/btw/BtwPanel: peek sheet (desktop + mobile), fork-tail view,
  auto-close on disappearance, Esc to close
- lib/btw: startBtwSession (fork + rename + routed send), closeBtwPanel
  (close = destroy), filterBtwTailMessages
- ChatInput: btw-mode send routing via SendMessageOptions.sessionId,
  btw-aware activity (stop/abort), placeholder + mode chip
- useSessionActivity: exported for per-session activity reads
- i18n: btw keys across all 11 locales

* fix(chat): keep btw sends isolated

* refactor(chat): rework /btw into a metadata-scoped peek panel

- Link the active btw fork through the parent session's metadata
  (openchamber.btwSessionID) so the panel exists only in the session that
  invoked /btw, follows parent navigation, and survives reloads; the fork
  carries a kind:'btw' marker with its originalSessionID.
- Replace the wall-clock history boundary with the id of the newest cloned
  message (server-generated ascending ids), stored in fork metadata.
- Derive panel identity in useBtwPanelState; useBtwStore shrinks to
  transient per-parent UI state (collapsed/creating/destroying).
- Panel UX: dropdown-style glass surface, chat ScrollShadow, single
  title+chevron collapse toggle, muted header controls, promote action
  (keep as a full session and navigate to it), Esc collapses instead of
  destroying, reserved Working indicator row, streaming auto-follow via
  ResizeObserver keyed on content readiness.
- Add a 'peek' chat surface mode that suppresses per-message controls and
  turn footers inside the panel; user bubbles keep a small gap below.
- Hide btw forks from the sidebar, session switcher, and command palette
  until promoted; mark the fork before inserting it into local stores.
- Delete/archive lifecycle: removing the fork unlinks the parent; removing
  the parent also removes its temporary fork.
- patchSessionMetadata now mirrors updated sessions into live stores.
- Localize new strings across all 12 dictionaries; add unit tests for
  metadata helpers, the btw flow, and the UI store.

* fix(chat): clamp the btw panel below the app header when the keyboard is open

Reuse useMobileAutocompleteMaxHeight (the composer autocomplete precedent)
on the panel's scroll body, reserving the panel header and bottom spacer
height, so the sheet adapts to the visual viewport instead of riding under
the app header on mobile.

* fix(lint): drop unused destructured bindings in sessionBtwMetadata

CI eslint has no underscore ignore pattern; strip metadata keys with typed
copies and delete instead of discard-destructuring.

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-08-23 00:40:06 +03:00
Bohdan Triapitsyn a317a156cb test(ui): restore the two suites CI was failing on
Neither failure came from the change that surfaced them; both suites were
asserting behavior the product had already moved.

issue-2039 mocks `session-actions`, and session creation's authoritative
steps live there: the created session becomes current under the directory
the server confirmed, and that directory enters sync's routing index. The
mock did neither, so every assertion about current session and directory
routing read an empty store. It now performs both, which is what makes
those assertions test the store's real resolution order again.

issue-2903 pinned `<ChatEmptyState />` inside ChatContainer's empty-and-idle
branch. The draft transition animation moved that surface to the draft, and
the branch now returns a neutral placeholder. What the test is actually for
— the idle branch not rendering a status row of its own — is kept.
2026-08-22 20:39:27 +03:00
Bohdan Triapitsyn 2740c7b3a2 feat(projects): pin a thinking level next to a project's model
A project could pin the model new chats start on, but not the level to
run it at: the default cascade dropped any variant as soon as a project
model won, and only ever considered the global one — which belongs to
the global model.

Projects now carry `defaultVariant` alongside `defaultModel`, stored and
sanitized only next to that model, and the cascade passes it through.
Both controls sit in one "Defaults for new chats" group laid out like the
Sessions defaults, and the level appears only for models that offer them.
2026-08-22 20:31:31 +03:00
Bohdan Triapitsyn e2e55756e2 fix(settings): stop defaults from repointing a chat that has its own model
Changing the default model, variant or agent wrote the chat's live
selection unconditionally. For a session carrying its own choice the
effect was mostly transient — ModelControls restores that choice on the
next hydration — but a message sent right after the change went out on
the new model.

The guard is the same pair of signals ModelControls restores from
(shouldPreserveManualModelOverride): a manual selection plus a saved
selection for the current session. Chats following the default still
switch immediately.
2026-08-22 20:31:31 +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
Bohdan Triapitsyn ac0b17c9fd docs(changelog): note the providers and work status fixes 2026-08-22 20:31:31 +03:00
Bohdan Triapitsyn e970154809 fix(chat): yield the work status card to the context panel in project-less chats
The visibility hook looked the context panel up under the directory the
card reports about. A managed Chat reports about none, so the lookup ran
against an empty key and answered "closed" while the panel was open.

It now resolves the key the way the rail and the panel do, through
useEffectiveDirectory. The reporting directory is no longer an input to
this hook at all.
2026-08-22 20:31:31 +03:00
Bohdan Triapitsyn 887127b5d0 fix(providers): keep the settings provider selection under one owner
The selected provider on the Providers settings page shared a field with
the chat's model resolution. Changing the chat model or agent, and
`loadAgents` reconciling a selection, all wrote to it, so the page jumped
to an unrelated provider while the user was reading or editing one.

Only the sidebar click writes it now. A refresh no longer re-derives it
either: a provider missing from a refreshed list is expected while
OpenCode restarts and plugin-registered providers re-register.
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 f7a0d1f0f6 feat(ssh): rework remote instance setup and fix remote installs
Adding an SSH connection now starts from the hosts in the SSH config
instead of a blank command field, ports and install options sit behind
Advanced settings, and each connection reports one of three states with
the failure text and an action that resolves it.

Remote installs no longer touch the root-owned global npm prefix: npm is
pinned to a prefix under $HOME and bun is resolved at its known location,
because an SSH login shell exposes neither on PATH. The opencode CLI is
resolved the same way and handed to the remote server through
OPENCODE_BINARY, and the server is started and stopped through the
resolved binary rather than PATH — the HTTP shutdown route sits behind UI
authentication and never stopped anything.

A managed remote server can also be published to the remote machine's own
network. That requires a UI password, enforced in the form and again in
the SSH manager.
2026-08-22 16:45:56 +03:00
Bohdan Triapitsyn eed317f18d fix(chat): handle unavailable persisted models 2026-08-22 14:53:44 +03:00
Bohdan Triapitsyn 09f75b75e1 fix(desktop): retry Windows settings file replacement 2026-08-22 14:44:03 +03:00
Bohdan Triapitsyn 049ff52427 fix(queue): keep remote host identity stable 2026-08-22 13:22:42 +03:00
Bohdan Triapitsyn 171a03d8f1 fix(sync): reconcile completed turns after reconnect 2026-08-22 13:19:36 +03:00
Bohdan Triapitsyn 90f150bd0c chore: bump @opencode-ai/sdk to 1.18.21 2026-08-22 12:13:54 +03:00
Bohdan Triapitsyn fcbe2c0414 fix(settings): clean up orphaned temp files and harden atomic writes 2026-08-22 11:55:38 +03:00
Bohdan Triapitsyn 735a9463ca fix(chats): use a dedicated empty message
Show a localized Chats-specific empty state instead of reusing the project workspace session message.
2026-08-22 11:41:59 +03:00
Bohdan Triapitsyn 952e8d6463 feat: require Cmd/Ctrl+Enter to send in expanded chat composer
Plain Enter now inserts a newline in the expanded composer
Cmd/Ctrl+Enter still sends the message
Helps avoid accidental sends while writing long prompts
2026-08-22 11:33:30 +03:00
Bohdan Triapitsyn 556b151492 fix(chat): limit draft transition animation 2026-08-22 11:32:01 +03:00
Bohdan Triapitsyn 80068c634d fix(sessions): centralize global polling 2026-08-22 02:49:45 +03:00
Bohdan Triapitsyn c232d358da chore: update unreleased changelog entries 2026-08-22 02:48:02 +03:00
Bohdan Triapitsyn 11d7c7b481 fix(chat): keep long user messages expandable
Truncation was measured once on mount and watched through a ResizeObserver
on the clamped element, whose own height stops changing under line-clamp.
A message measured before its content settled never regained the expand
affordance, and a just-sent one measured before its turn finished laying
out could not be expanded at all.

Measure at click time so expanding depends on whether the text is clipped
right now, re-read once on the next frame after mount, and observe the
children (which keep their natural height) plus subtree swaps.
2026-08-22 02:45:34 +03:00
Bohdan Triapitsyn 77479127a5 fix: reduce code block highlight flicker
Preserve layout with invisible placeholders while worker highlighting loads
Reuse cached highlighted lines on first render when available
Differentiate loading from failed highlighting results for better fallback behavior
2026-08-22 02:10:03 +03:00
Bohdan Triapitsyn 4021dd4e26 fix(git): separate generated PR prompt blocks
The additional context and pull request template blocks ran into the file
list without a blank line, and the template's markdown headings blended into
the surrounding instructions. Each block now starts on its own, and template
content is fenced with explicit markers labelled as structure to reuse rather
than instructions to follow.

Claude-Session: https://claude.ai/code/session_01NzK8hD1hFHHHwv2FgZJwC2
2026-08-22 02:04:06 +03:00
Bohdan Triapitsyn cd46f0e3fb fix(chat): stop the just-sent user message from flickering
The server echo of an optimistic user message carries different part
ids, so the reducer dropped the optimistic part and appended the server
one at the end, and MessageBody keyed user parts by part id. The key
change remounted the text subtree (blank frame, markdown re-parse,
truncation state reset) and the append reordered text against file
parts.

Replace the optimistic part in place and key user parts positionally.
2026-08-22 01:55:52 +03:00
Bohdan Triapitsyn 514d2e82da feat(git): follow repository style when generating commit and PR text
Commit generation now samples the last 10 commit subjects and instructs the
model to match their language, prefix convention, and length, falling back to
Conventional Commits only when the history shows no consistent style.

PR generation probes the conventional pull request template locations and
reuses the repository's own sections and checklists as the body structure when
one is found.

Claude-Session: https://claude.ai/code/session_01NzK8hD1hFHHHwv2FgZJwC2
2026-08-22 01:52:19 +03:00