Commit Graph
3432 Commits
Author SHA1 Message Date
Bohdan Triapitsyn 60a4dccb32 fix(vscode): file an editor comment under the session it was delivered to
A comment written with no session tab open opens one, and that panel knows
its directory long before it has loaded the session list and selected its
session. The webview filed the draft on the first snapshot that had a
directory, with the session key falling back to "draft" because no session
was current yet. The panel's composer reads the session's key, so the chip
never appeared, while the editor thread saw the draft in the store snapshot
and reported it attached.

A session panel now stamps its session on every comment it delivers, and
the webview waits until it actually shows that session before filing. The
sidebar files on its current session or an open new-session draft, and no
longer falls back to "draft" merely because nothing is selected yet. The
resolver is a pure module with tests.

Claude-Session: https://claude.ai/code/session_01VqV56Hez25hTxXH4ipJfzH
2026-09-05 14:18:51 +03:00
Bohdan Triapitsyn 4f1f9e6650 feat(sidebar): show running project actions by directory 2026-09-05 14:12:07 +03:00
Bohdan Triapitsyn 7a3244bab2 test(web): remove two timing races that hung CI for a minute each
Both failures showed up as "Test timed out in 30000ms" followed by "Hook
timed out in 30000ms" on loaded PR runners, in files nobody had touched.

relay host-client: the scripted client dialed its WebSocket before awaiting
its WebCrypto setup and only then attached the open/message listeners. On a
loaded runner the loopback socket opened while key generation was still
queued on the threadpool, the open event found no listener, no hello was
sent, and the client waited forever. The socket is now dialed after the key
material is ready, in the same tick as the listeners. The fake relay also
terminates leftover sockets on stop so a failure is reported once, not
twice.

walkthrough routes: each test slept 20 ms and assumed the request had
reached the route by then. The tests now wait until the service has been
asked to generate one more time than before the request, and afterEach
closes idle keep-alive connections so server.close() cannot hang on a
response a failed test never received.

Claude-Session: https://claude.ai/code/session_01VqV56Hez25hTxXH4ipJfzH
2026-09-05 12:40:07 +03:00
Felipe GenéandBohdan Triapitsyn a12b9be443 feat(chat): Comments and review in VS Code, like the OpenChamber desktop app (#1724)
* feat(chat): render code comments as cards instead of fenced text

* fix(vscode): route Add Comment to the active session editor panel

* fix(chat): persist queued inline comments and tighten file-chip path matching

* feat(vscode): comment on code from the editor

* fix(chat): keep attached context in the message and broadcast comment removal

* fix(vscode): hold every pending comment and gate both entry points on the workspace

* fix(vscode): let only the owning surface decide its comment threads

* fix(vscode): drop a comment removed while its delivery was still in flight

* test(vscode): cover the in-flight comment removal guard

* test(vscode): cover comment removal reaching every chat surface

* fix(vscode): give up on a comment the chat never confirmed holding

* fix(vscode): retract a comment everywhere before reporting it discarded

* fix(chat): preserve queued comment cards

* fix: preserve inline comment context across send paths

* fix(chat): preserve command routing with context

* fix(chat): keep unavailable actions on normal send path

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-09-05 12:28:17 +03:00
Bohdan Triapitsyn d323b51a0a fix(queue): deliver a queued slash command with context as a prompt
OpenCode's command route accepts file parts only. The server queue was
attaching captured context as text parts to POST /session/:id/command, so
a slash command queued with a comment, quote, or PR diff was rejected with
400 and retried forever.

A command queued without context still takes the command route with its
files. One queued with context now takes the prompt route the way the
composer does: the command's template is expanded with its arguments, a
skill keeps its text and gets the explicit skill-invocation instruction,
and the context rides along.

Claude-Session: https://claude.ai/code/session_01VqV56Hez25hTxXH4ipJfzH
2026-09-05 12:27:55 +03:00
Bohdan Triapitsyn 0b39efb0ae chore: bump @opencode-ai/sdk to 1.18.29 2026-09-05 12:11:20 +03:00
Bohdan Triapitsyn d37ce34a2e fix(terminal): reconcile project action executions across clients (#3362) 2026-09-05 12:05:39 +03:00
Matt Visnovsky 4e0eed717d fix: Project action terminal lifecycle (#3287)
* fix(terminal): make command sessions own action lifecycle

* fix(ui): reconcile project action terminal state

* feat(ui): show running project actions in terminal tabs

* feat(ui): run project actions from linked worktrees

* fix(ui): guard project action reconciliation

* fix(ui): scope project action preview fallback

* fix(ui): default project actions to worktrees

* fix(ui): reveal project action terminals

* fix(ui): retain terminal output after snapshot replay

* fix(ui): restore running action terminals on revisit
2026-09-05 12:04:36 +03:00
Bohdan Triapitsyn 58dfc789a2 fix(queue): clear the queue card after the last queued message is sent
When the server delivered the last item of a session's queue it deleted
the session entry and broadcast the update with an empty directory. The
UI keys its projection by directory, could not build the key, and dropped
the event, so the delivered message stayed in the "Queued messages" card
until the next full hydration.

The server now remembers a session's directory beyond the emptying of its
queue so that broadcast names it. The UI additionally treats an empty
session without a directory as "this session's queue is done" for every
projection keyed under that session id, which covers clients talking to
an older server.

Claude-Session: https://claude.ai/code/session_01VqV56Hez25hTxXH4ipJfzH
2026-09-05 11:21:39 +03:00
Bohdan Triapitsyn 7c9fdd1ee5 fix: complete goal resume and comment input follow-ups (#3361) 2026-09-05 10:53:34 +03:00
ChangeHow f3f844463b fix(ui): preserve IME composition in comment inputs (#3228)
Thanks for extending the existing IME handling to comment inputs and documenting the browser-event checks. We will also protect the annotation Escape handlers from cancelling composition.
2026-09-05 10:49:05 +03:00
ChangeHow df7e018e60 fix(chat): size markdown table columns by content (#3268)
Thanks for fixing the cramped table columns and covering the streaming-to-settled transition. The content-sized layout and horizontal scrolling look ready to merge.
2026-09-05 10:46:22 +03:00
Leonidandalvins82 c5086e0250 fix(session-goal): bound length recovery after truncation (#3278)
Thanks to alvins82 for tracing the truncation failure and to bashrusakh for adding bounded recovery and error precedence. We will finish the explicit Resume behavior in the same batch.

Closes #3255

Co-authored-by: alvins82 <alvins82@gmail.com>
2026-09-05 10:46:18 +03:00
ChangeHow 47e2049427 fix(ui): show send action in collapsed mobile composer (#3247)
Thanks for refining the action placement. This keeps New chat available while idle and preserves Abort while a response is running. We will finish the repository-specific cleanup in the same batch.
2026-09-05 10:46:13 +03:00
Leonid c8d8d4a384 fix(sync): paginate child session discovery to avoid >200 truncation (#3271)
Thanks for fixing the child-session discovery cutoff and covering the paginated discovery path with a provider-level regression test.
2026-09-05 10:46:09 +03:00
Bohdan Triapitsyn 260bfe666b fix: complete config path and review follow-ups (#3348) 2026-09-05 02:19:59 +03:00
tdoherty 0543b954c3 fix(web): honor XDG_CONFIG_HOME for OpenCode paths (#3305)
Closes #3304. Thanks for consolidating the global OpenCode paths. VS Code path parity and effective-path display follow-ups are maintainer-owned.
2026-09-05 02:14:26 +03:00
fitzgpt 64f9f3aba7 feat(vscode): localize loading splash and dev-server status for Turkish (#3303)
Thanks for filling in the Turkish bootstrap messages. Glossary and evidence-text follow-ups are maintainer-owned.
2026-09-05 02:14:21 +03:00
Leonid ec86d738e2 fix(vscode): stop gating list-derived permission auto-accept on the V2 preflight (#3318)
Thanks for fixing both permission reconciliation paths. The fetchPermission documentation follow-up is maintainer-owned; #3259 remains open.
2026-09-05 02:14:17 +03:00
Andrea V 578b1c2f86 fix(chat): bound oversized tool diff previews (#3293)
Closes #3292. Keep #3286 open for the separate context-panel DiffView path. Thanks for fixing oversized tool-card previews.
2026-09-05 02:14:13 +03:00
Leonid 2d4e920fbd refactor(client): remove dead legacy file/command wrappers (#3290)
Thanks for removing the unused wrappers and keeping the live file and command APIs intact.
2026-09-05 02:14:07 +03:00
fitzgpt 3073db9481 feat(vscode): add Turkish localization for extension strings (#3300)
Thanks for completing the Turkish translations for the extension commands and notifications.
2026-09-05 02:13:59 +03:00
pttydou ed987a576d fix(vscode): normalize status path comparison (#3322)
Closes #3308. Thanks for fixing the misleading Windows status diagnostic and adding the focused regression tests.
2026-09-05 02:13:54 +03:00
𝖎𝖚𝖑𝖎𝖎𝖆andClaude Fable 5.1 188c7aa369 fix(docker): apply patch-package in the builder stage and set a UTF-8 locale (#3346)
* fix(docker): apply patch-package in the builder stage

The deps stage installs with --ignore-scripts, so the root postinstall never
runs and patches/ghostty-web+0.4.0.patch is never applied. The web bundle in
the Docker image therefore shipped an unpatched ghostty-web renderer.

Run patch-package explicitly in the builder stage, after the full source copy,
before building the web assets.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(docker): set a UTF-8 locale in the runtime image

The oven/bun base image ships with the POSIX locale, so bash readline in the
built-in terminal treated each byte of a multibyte character separately and
garbled the echo of pasted Unicode input.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 01:47:26 +03:00
Bohdan Triapitsyn 07c4053f42 Merge pull request #3330 from hehuaiyu/fix/vscode-custom-provider-protocol-parity
fix(vscode): support custom provider protocols
2026-09-05 01:36:12 +03:00
Bohdan Triapitsyn 214d9a916b Merge main and preserve custom provider protocols 2026-09-05 01:29:16 +03:00
Bohdan Triapitsyn f742775be4 feat: streamline release preparation and changelog checks
Exports the release package list so release prep stages the same versioned files as the bump script.
Validates that CHANGELOG.md contains the target release section before preparing a release.
Updates the suggested release steps to commit only release files and push the tag explicitly.
2026-09-05 01:26:10 +03:00
Bohdan Triapitsyn 74a065fd10 Merge pull request #3332 from hehuaiyu/fix/windows-bun-shim-resolution
fix(tooling): resolve Bun executable on Windows
2026-09-05 01:24:34 +03:00
Bohdan Triapitsyn d9f7bc199e Merge pull request #3329 from hehuaiyu/fix/preserve-custom-provider-model-metadata
fix(providers): preserve custom model metadata on edit
2026-09-05 01:24:23 +03:00
Bohdan Triapitsyn 05e2903815 release v1.22.1 2026-09-04 23:51:03 +03:00
Bohdan Triapitsyn f42988c9bf chore: bump @opencode-ai/sdk to 1.18.28 2026-09-04 23:43:54 +03:00
Bohdan Triapitsyn d6f0f2f23c feat(settings): retire the third-party plugin integrations
Settings → Integrations offered install cards for the Claude Code and
Cursor provider plugins. They are gone: the section, its plugin catalog,
its own i18n module and tests, the settings search entries, the page
keywords, and the two sprite icons only it used. The page now holds the
built-in GitHub and Linear cards, so it is hidden in VS Code where neither
applies; its title and description live in the settings dictionaries.

Docs follow: the Integrations page in every locale now documents GitHub
(pointing at its own page) and Linear in full, the GitHub page names
Settings → Integrations as the place to connect and covers linking an
issue or PR to a message, and the Providers pages no longer promise Claude
or Cursor subscriptions.

Claude-Session: https://claude.ai/code/session_01HB9wdLQoZX2vfyDjwv6Rso
2026-09-04 23:34:15 +03:00
Bohdan Triapitsyn 34bf631157 feat(queue): queue a message with everything the composer had attached
Queueing captured only the text and files. Context chips (inline comments,
terminal selections, browser annotations, PR comments and checks, quotes,
linked issue/PR/Linear references, pending synthetic parts) stayed in the
composer and only left with the next manual send, so a queued message the
server delivered went out without them and the chips rode an unrelated
message later.

A queued message now carries what the composer would have sent: the text
with its agent mention stripped and file mentions resolved into
attachments, the attached context as structured parts, and the skill
instruction derived from the text. The server delivers those parts in the
composer's order, the VS Code auto-send does the same, and editing a queued
message puts the chips and linked references back. A failed queue restores
the composer completely. Snapshots and broadcasts omit the captured
context like attachment payloads; a take returns it.

Claude-Session: https://claude.ai/code/session_01HB9wdLQoZX2vfyDjwv6Rso
2026-09-04 22:56:27 +03:00
Bohdan Triapitsyn ce5c0c068e feat(mcp): reconnect failed MCP servers in managed OpenCode
OpenCode marks an MCP server failed when it does not come up at startup
or when a live connection drops, and never retries. A new managed plugin
reconnects those servers with a per-server backoff (1s doubling to a 30s
cap), wakes early on mcp.tools.changed, and stops on dispose. Only the
failed state is retried; disabled and auth states stay untouched.

The OPENCODE_CONFIG_CONTENT merge that agent-tool and system-prompt each
carried is now one shared helper so the three managed plugins compose.

Claude-Session: https://claude.ai/code/session_01VqV56Hez25hTxXH4ipJfzH
2026-09-04 22:56:27 +03:00
Bohdan Triapitsyn caac24ac3d Merge pull request #3320 from openchamber/fix/ui-thinking-effort-draft-project-rename
Various session UI fixes: drafts, rename, worktree creation, thinking effort
2026-09-04 20:00:42 +03:00
Bohdan Triapitsyn f81bc26fe5 docs: clarify uncommitted changes warning text 2026-09-04 19:54:16 +03:00
Bohdan Triapitsyn b4a38061bc fix(ui): route answer worktrees from source session 2026-09-04 19:46:21 +03:00
Bohdan Triapitsyn f160f3aac4 Merge remote-tracking branch 'origin/main' into fix/ui-thinking-effort-draft-project-rename 2026-09-04 18:58:08 +03:00
Iuliia IvashkoandClaude Opus 5 16f6f27027 fix(ui): stop the echo of a Default send from erasing the recorded Default
The send write was fixed, but the message that send echoes back arrives with
model metadata and no effort, and its model matches the one the send just
saved. That is exactly when `shouldPreserveManualModelOverride` declines to
protect the selection, so the history branch ran with no variant and recorded
"no choice" over the user's explicit `Default`. Picking Default, sending, then
switching agent and back still put the settings default in the picker.

A message carrying no effort is not evidence that the session has none. The
history branch now keeps whatever the session already recorded when the message
carries no variant, and a concrete historical effort still replaces it.

The behavior test ran the real guard through a mock that returned a fixed
answer, so the failing branch had no coverage. It now calls the real function
unless a test opts out, and the new case fails without this change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZuVVgziiLjD81W5vaxdH2
2026-09-04 18:39:05 +03:00
Iuliia IvashkoandClaude Opus 5 9299e2a28d fix(ui): keep an explicit Default effort across the send that follows it
A send carries no effort both when nothing was chosen and when the user picked
"Default", so `sendMessage` could not tell the two apart and recorded the raw
value, which clears the entry. Picking "Default", sending, then switching agent
and back put the settings default back in the picker — the shape of the bug
this branch set out to fix.

`materializeOpenDraftSession` already read the live selection to keep that
distinction on the draft path. Both paths now share `resolveVariantToRecord`,
which prefers `currentVariantSelection.override` while the live selection still
describes the agent and model being sent to, and falls back to the sent value
when it does not.

Three tests go through the real `sendMessage`; two of them fail without this
change. The existing ones seeded the record directly, which is why the send
path was never covered.

Also documents the `oc.chatInput.lastDraftTarget` record in the owning sync
documentation: its three `target` values, what a pre-`target` record and a
removed project fall back to, and why a chat scratch directory is not a project
target.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZuVVgziiLjD81W5vaxdH2
2026-09-04 17:53:11 +03:00
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 IvashkoandClaude Opus 5 025cd3d46c fix(ui): let restore paths report no effort without pinning Default
`commitVariantSelectionForModel` turned every `undefined` into an explicit
`Default` (`null`), but it serves two kinds of caller. The picker means "the
user chose Default"; the history and manual-override restores mean "nothing
was found". Restoring a session therefore recorded a choice nobody made, and
`resolveModelVariantSelection` collapsed that `null` back to `undefined`, so
the next restore recorded it again. Because an explicit `Default` outranks the
agent and settings defaults by design, the session latched onto `Default` and
the concrete effort its own history carried could not come back.

Move the decision to the callers: the four picker paths pass `variant ?? null`,
the restore paths pass their result through, and the resolver returns the
selection store's three states instead of two. The follow-up write in the
history restore goes with it — the apply above it already recorded the same
agent and model, and a second write could only disagree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZuVVgziiLjD81W5vaxdH2
2026-09-04 17:32:40 +03:00
Iuliia Ivashko cb3bc3bd1b merge: bring bulk session archiving and background worktree removal into the thinking-effort branch 2026-09-04 16:54:28 +03:00
Iuliia Ivashko 0ef189f3c8 perf(sessions): archive a worktree's sessions through one server batch
Removing a worktree archived its sessions one SDK call at a time and
then re-rendered the whole sidebar once per streamed session.updated
echo. On a worktree with 121 sessions that meant 14.8s of main-thread
work, 121 requests, and 328 localStorage writes.

- Add POST /api/openchamber/sessions/archive: validates a batch (max
  500 ids, per-request archivedAt), archives sequentially, and reports
  partial failures instead of dropping the batch. VS Code serves no
  such route and answers 501; the shared UI then falls back to the
  per-session path.
- Plan batches from the sessions this client actually holds, live
  directory stores first, so worktree-only sessions still batch.
- Claim (id, archivedAt) pairs before the request and consume the
  matching session.updated echoes, so the server's own confirmations
  no longer fan out into 121 store publications. Runtime-scoped, TTL
  30s, released on response or fallback; non-matching updates pass.
- Make the managed-chats persistence a real trailing debounce instead
  of a 50ms throttle, so a burst of publications coalesces into one
  localStorage write.

Benchmark (121 sessions, production build, real Chrome): 14785ms ->
~1030ms, long tasks 100 -> 1, global store publications 236 -> 1,
persistence writes 328 -> 3.
2026-09-04 16:50:03 +03:00
Iuliia Ivashko 94c90a16b6 fix(ui): reconcile git state after worktree changes 2026-09-04 16:41:39 +03:00
Bohdan Triapitsyn 8a58054551 docs: refresh README wording and product messaging 2026-09-04 14:22:49 +03:00
Iuliia Ivashko bde6fed8a2 Revert "revert(ui): restore inherited semantics for Default thinking effort"
This reverts commit 35875e818c.
2026-09-04 14:12:56 +03:00
Iuliia Ivashko 3cd31a090a Revert "fix(ui): stop pinning inherited effort as a session choice on send"
This reverts commit 0a47b306d6.
2026-09-04 14:12:56 +03:00
Iuliia Ivashko 0b803468a3 Revert "fix(ui): stop restoring inherited effort from history as an explicit choice"
This reverts commit 7519167031.
2026-09-04 14:12:56 +03:00
Bohdan Triapitsyn 07fa83cc72 feat(queue): deliver queued messages from the server
Messages queued while a session is busy used to live in the browser tab and
were sent by that tab once the session went idle, so closing the tab (or
losing the connection) stranded them. The web server now owns the queue:
it persists to <data-dir>/message-queue.json, watches session.status on the
global event hub, re-verifies idleness against OpenCode before sending, and
delivers the head of the queue via prompt_async (or /command for slash
commands) with the model, agent, variant, attachments, and agent mention
captured at queue time. Failed sends stay queued and retry with backoff; a
user abort holds delivery briefly; every change is broadcast so all clients
see one queue.

The shared UI store becomes a projection of the server queue outside VS
Code (hydrate on connect, apply broadcasts, optimistic mutations settled on
the server's copy, one-time upload of locally queued messages from older
builds). Edit / send-now take the full message back from the server. A
UI-driven auto-review run asks the server to hold that session's queue.
VS Code keeps its local queue and foreground auto-send.

Claude-Session: https://claude.ai/code/session_01HB9wdLQoZX2vfyDjwv6Rso
2026-09-04 14:08:08 +03:00