Commit Graph
3203 Commits
Author SHA1 Message Date
Bohdan Triapitsyn 65c7f27eb4 docs: add Turkish localization 2026-08-29 12:14:19 +03:00
Bohdan Triapitsyn 50159d3747 docs(triage): waiting-on-author bucket, read reviews not only comments, deliberate-behavior premise check 2026-08-29 11:15:02 +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
𝖎𝖚𝖑𝖎𝖎𝖆 3f993fffec fix(sidebar): search the managed chats along with project sessions (#3212)
* fix(sidebar): search the managed chats along with project sessions

The sidebar builds search data per group, and every group renders
`filteredNodes ?? []` while a query is active. Only project groups were ever
given that data, so the managed chats — which render outside any project
section — collapsed to an empty list as soon as anything was typed, however
well a title matched. The header count ignored them for the same reason.

Pass the chats group to the sections hook as a standalone group so it takes
the same search pass and joins the match count. Building it before the hook
runs keeps search-data ownership in one place instead of registering entries
from the rendering component.

No CHANGELOG entry: it is left out deliberately to keep this branch free of
conflicts with other open PRs, and is to be written at release time.

fixes #3200

* fix(sidebar): report the real search match count to the header

The header rendered whatever `SessionSidebar` passed it, and that was a
literal `0` — so "0 matches" was shown no matter how many sessions matched.
The count exists: the sections hook already computes it, but only the session
list can see it, and the header renders above the list.

Report it upwards from the list instead of recomputing it in the header, so
the number and the visible rows cannot disagree, and reset it to 0 when the
list unmounts.

fixes #3200

* fix(sidebar): keep chat-only search results on screen

The chats render inside the scroller's top content, and the branch that
handles "no project section matched" replaced the whole list with the empty
state. A query matching only a chat therefore showed "No matching sessions"
while the header — now reporting the real count — said one match, and the
chat itself stayed hidden. That is the exact reproduction in the issue; the
earlier manual check missed it because the query used also matched a project
session.

Tell the scroller when its top content holds results, and keep it on screen
in that branch. The decision moves to `sessionProjectRender` next to the
other render-selection helpers, where it can be tested without mounting the
Vite-only component graph.

fixes #3200
2026-08-29 02:36:05 +03:00
Bohdan Triapitsyn 736586f802 docs(triage-prs): the report carries each ready action verbatim, never paraphrased 2026-08-29 02:31:25 +03:00
Bohdan Triapitsyn d066e888e9 chore(agents): rename the review bot agent to pr-review-bot 2026-08-29 02:24:00 +03:00
Bohdan Triapitsyn dd998ef495 chore(agents): pr-reviewer stays read-only by instruction, not permission rules 2026-08-29 02:21:42 +03:00
Bohdan Triapitsyn 71653d287b feat(agents): add the pr-reviewer subagent; triage fans out through it 2026-08-29 02:18:56 +03:00
Bohdan Triapitsyn eead353326 docs(pr-review): unverifiable is not verified; author-named gaps always land on a list 2026-08-29 02:13:42 +03:00
Bohdan Triapitsyn fb9e13a3a7 fix(chat): list quote-only user messages in the prompt navigator
Context parts are marked synthetic, so a message made only of quoted
fragments was skipped as an injected message and could not be navigated
to. Such turns now appear with the same caption the bubble shows.
2026-08-29 02:02:30 +03:00
Bohdan Triapitsyn e26f647404 fix(chat): re-pin to the measured content end after a resize, not the list's content length
Opening or closing the context panel re-wrapped the timeline; the settle
handler then scrolled to LegendList's total content length, which still
carried pre-wrap sizes for unmounted rows, leaving a viewport-sized blank
tail under the last message.
2026-08-29 01:51:47 +03:00
Bohdan Triapitsyn 8d80224a1e docs(pr-review): decide PUSH-BACK vs MERGE-THEN-FIX by who owns the residue, not its size 2026-08-29 01:25:58 +03:00
Bohdan Triapitsyn 6cd318ddf3 docs(pr-review): a fix earns MERGE only when the symptom's path is shown to be closed 2026-08-29 01:22:38 +03:00
Bohdan Triapitsyn a9172e516e chore: changelog entries for the herjarsa batch
Claude-Session: https://claude.ai/code/session_017TK5JAYDfT3Fotc23UEg98
2026-08-29 01:15:56 +03:00
Bohdan Triapitsyn 8aba30ac43 revert: stop forwarding the Small Model override into the managed OpenCode config
Reverts #2687. In real use the injected small_model behaves poorly with
OpenCode: its internal small-model consumers and OpenChamber's own small
model are different things and must stay configured separately.
2026-08-29 01:14:02 +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 a182f4f4ff fix(server): allow reading files through workspace-internal symlinks (#2872)
fix(server): allow reading files through workspace-internal symlinks
2026-08-29 00:53:22 +03:00
Bohdan Triapitsyn 3e0a9622aa refactor(server): own the requested project directory in the runtime
Drop the canonical-containment 403 guard and the extra realpath(base) the
read routes (stat/read/raw/serve) had gained. Every workspace resolution
returns insideWorkspace: true and outside-file grants use
base = dirname(canonicalPath), so the guard could never fire; the flag had
no remaining reader and is gone with it. The read routes are back to the
single realpath(resolved.resolved) they had before.

Move the lexical-base fallback out of the inline header parsing in
routes.js. x-opencode-directory decoding belongs to
project-directory-runtime, so resolveProjectDirectory now also returns
requestedDirectory, the pre-realpath candidate that validated.
resolveWorkspacePathFromContext retries against it when the canonical base
rejects a path, which keeps files under a symlinked project root
addressable without a second copy of the header/query parsing.
2026-08-29 00:53:06 +03:00
Bohdan Triapitsyn 25c2e7b3ff fix(providers): refresh credentials after auth save (#2884)
fix(providers): refresh credentials after auth save
2026-08-29 00:51:02 +03:00
Bohdan Triapitsyn c788cd2237 fix(providers): keep declared env vars as a credential signal
Providers that read credentials from several environment variables
(Bedrock, Azure, Vertex) never get a single resolved Provider.key from
OpenCode, so dropping the env signal made them show "Credentials
missing", auto-open the auth panel, and hide their models even when
fully configured.

providerHasCredentials takes an envDeclared input again, and both
call sites in ProvidersPage pass whether the provider declares any
non-empty env var name.
2026-08-29 00:50:49 +03:00
Bohdan Triapitsyn 8b7ebca187 feat(projects): add multiple projects at once in the directory picker (#2877)
feat(projects): add multiple projects at once in the directory picker
2026-08-29 00:50:32 +03:00
Bohdan Triapitsyn 5c2e3a6955 feat(directory-explorer): show success toast after batch project add 2026-08-29 00:50:22 +03:00
Bohdan Triapitsyn e13f27c1a3 Merge remote-tracking branch 'origin/main' into port-2884
# Conflicts:
#	CHANGELOG.md
2026-08-29 00:49:02 +03:00
Bohdan Triapitsyn 7052d94c2a Merge remote-tracking branch 'origin/main' into port-2877
# Conflicts:
#	CHANGELOG.md
2026-08-29 00:48:50 +03:00
Bohdan Triapitsyn 55ae41bde2 Merge remote-tracking branch 'origin/main' into port-2872 2026-08-29 00:48:36 +03:00
Bohdan Triapitsyn 11d2b69651 fix(ui): complete context tab menu icons 2026-08-29 00:41:57 +03:00
Angel Davila a78ecf8a7c feat(ui): add right-click close menu for context panel tabs (#3217)
Resolves openchamber/openchamber#3123.

The right panel's tab strip (browser, files, chat, and other
multi-instance surfaces) now supports a right-click context menu with
Close, Close others, Close to the left, Close to the right, and Close
all. These act on the current surface's tabs and reuse the new bulk
close action, so closing the active surface's last tab still closes the
panel while other surfaces remain.

- Add closeContextPanelTabs(directory, ids) to useUIStore
- Add opt-in tabContextMenu prop to SortableTabsStrip (no impact on other consumers)
- Wire the menu in ContextPanel with full i18n coverage across 11 locales
- Cover the bulk close with store tests
2026-08-29 00:35:24 +03:00
Bohdan Triapitsyn cbe908009b chore: changelog entries for the second contribution batch
Claude-Session: https://claude.ai/code/session_017TK5JAYDfT3Fotc23UEg98
2026-08-29 00:31:49 +03:00
Bohdan Triapitsyn d557c168de feat(ui): attach large text pastes as virtual files (#2619)
feat(ui): attach large text pastes as virtual files
2026-08-29 00:31:04 +03:00
Bohdan Triapitsyn ef0755da8b fix(sync): settle completed turns and finished messages promptly (#2667)
fix(sync): settle completed turns and finished messages promptly
2026-08-29 00:30:01 +03:00
Bohdan Triapitsyn 6b17c0b4e2 chore(ui): finish large text paste merge into main
Adds the Turkish dictionary entries main introduced after this branch was
opened, keeps the composer's four-space style in the new paste modules,
and drops the unused offer-action type plus the widening return
annotation flagged by the anti-slop lint.
2026-08-29 00:30:01 +03:00
Bohdan Triapitsyn 10634c4512 fix(sync): settle completed turns and finished messages promptly
A lost or delayed turn-ending `session.idle` left the busy spinner up until
the watchdog poll caught it (5-10s). An assistant `message.updated` carrying
`time.completed` now schedules one status check for that session, and
`streaming.ts` stops treating a completed trailing message as streaming.

The check is deferred by 750ms and re-reads the session status when the timer
fires, so the overwhelmingly common case — the turn's own `session.idle`
arriving right behind the completed message — settles on its own and costs
zero extra requests; only a session the store still believes busy spends a
fetch. The poll shares the watchdog's in-flight directory guard, so the
deferred check and the periodic poll cannot overlap on one directory.
Status authority is unchanged: the monotonic pass never lowers status, and an
authoritative resync runs only when the snapshot disagrees.
2026-08-29 00:29:42 +03:00
Bohdan Triapitsyn 15ff5c750e fix(chat): show context text before a pending question (#2655)
fix(chat): show context text before a pending question
2026-08-29 00:27:21 +03:00
Bohdan Triapitsyn 5fd86a420d fix(chat): match question tool name exactly
Use an exact-match comparison for the question tool name instead of
toLowerCase(), matching the convention used elsewhere in this file.
2026-08-29 00:27:06 +03:00
Bohdan Triapitsyn 63755a8e45 Merge remote-tracking branch 'origin/main' into port-2619
# Conflicts:
#	packages/ui/src/components/sections/openchamber/OpenChamberVisualSettings.tsx
2026-08-29 00:26:49 +03:00
Bohdan Triapitsyn 5c26c6ae21 Merge remote-tracking branch 'origin/main' into port-2667 2026-08-29 00:26:15 +03:00
Bohdan Triapitsyn 340e20f996 Merge remote-tracking branch 'origin/main' into port-2655 2026-08-29 00:25:56 +03:00
Bohdan Triapitsyn ddc8ab91d9 chore: consolidate the unreleased changelogs by theme
Claude-Session: https://claude.ai/code/session_017TK5JAYDfT3Fotc23UEg98
2026-08-28 23:59:10 +03:00
Bohdan Triapitsyn 635c24e396 chore: changelog entries for the merged contribution batch
Claude-Session: https://claude.ai/code/session_017TK5JAYDfT3Fotc23UEg98
2026-08-28 23:55:32 +03:00
Bohdan Triapitsyn 2a5a25d5a2 fix(small-model): harden configured headers 2026-08-28 23:50:04 +03:00
Bohdan Triapitsyn 46284301b8 fix(ui): add in-document search to the Markdown file preview (#2697)
fix(ui): add in-document search to the Markdown file preview
2026-08-28 23:48:56 +03:00
Bohdan Triapitsyn 2e9fd75925 fix(ui): prevent Shiki template-call OOM on backtick JS files (#2618)
fix(ui): prevent Shiki template-call OOM on backtick JS files
2026-08-28 23:48:37 +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
Bohdan Triapitsyn b6e78fbed5 fix(ui): stop shiki template-call backtracking from OOMing the renderer
Shiki's bundled JS/TS/JSX/TSX grammars carry a `template-call` rule whose
triple-nested lookahead sends the Oniguruma WASM engine into exponential
backtracking on ordinary backtick templates. The WASM heap grows until the
renderer runs out of memory and the window goes black.

Strip `template-call` from those four grammars as they are loaded in the
Shiki worker. Plain backticks and simple tagged templates still highlight;
only the rare `ident<TypeArgs>` tagged-template form loses its specialized
type-argument coloring.

Add a 5s per-request budget on the worker client as a safety net for any
other pathological pattern. Matching is synchronous inside the worker, so
the only way to reclaim its heap is to terminate it from the main thread.
A timed-out request resolves `null` like any other failure, so the caller
keeps plain text and nothing is written to the result cache.

Closes #2587
2026-08-28 23:48:15 +03:00
Bohdan Triapitsyn 08fe004b83 fix(chat): render completed reasoning in full instead of simulating streaming (#2736)
fix(chat): render completed reasoning in full instead of simulating streaming
2026-08-28 23:46:49 +03:00
Bohdan Triapitsyn 49ca62a8a2 fix(sidebar): keep permission badge and hover actions from overlapping (#2738)
fix(sidebar): keep permission badge and hover actions from overlapping
2026-08-28 23:46:43 +03:00
Bohdan Triapitsyn 88812e791a fix(chat): clamp text selection menu Y position to the viewport (#2733)
fix(chat): clamp text selection menu Y position to the viewport
2026-08-28 23:46:33 +03:00
Bohdan Triapitsyn e64fc710fc fix(chat): render completed reasoning in full instead of simulating streaming
Reasoning streaming state now derives only from the live stream phase
(streaming/cooldown), never from missing persisted timing data. A cached
part without time.end is no longer treated as live just because the
timing field is absent, so completed reasoning renders in full on load
instead of replaying a fake stream.

While resolving the merge onto main, also fixed a regression the merge
uncovered: main had added block-level streaming reveal (commitStreamedText)
to ReasoningPart since this fix was authored, which caused the busy
"Thinking…" header to stay hidden for the first moments of a short,
single-paragraph streaming response (no committed line yet). The busy
header now mounts as soon as streaming starts, independent of whether
any text has been committed for display.

Closes #2020
2026-08-28 23:46:14 +03:00
Bohdan Triapitsyn 627add0dd0 fix(chat): clamp text selection menu Y position to the viewport
Selecting text that crosses the top scroll edge could push the
floating selection menu above the viewport because only the X
position was clamped, not Y. Add getDesktopClampedY alongside the
existing X clamp in selectionMenuPosition.ts, measure the menu's
height the same way its width is measured, and re-clamp Y in
showMenu, the layout effect, and the resize handler.

Ported by hand: TextSelectionMenu.tsx changed significantly on main
(comment mode, glass surfaces, header drag-zone push-down) since this
fix was written, so main's file was kept and the fix re-applied on
top of it.

Closes #2257
2026-08-28 23:46:12 +03:00
Dmitrii 3903cb53b1 fix(small-model): send configured provider headers (#3214)
readProviderConfig read only options.baseURL and options.apiKey, and the
OpenAI-compatible dispatch hardcoded a bearer token, so provider
options.headers never reached the request. OpenCode sends those headers on
every chat turn, which left the small model authenticating differently from
the request path against the same URL.

Providers behind a gateway that authenticates on its own header, such as the
Ocp-Apim-Subscription-Key default of Azure API Management, answered 401 for
walkthroughs, session goal audits, titles and commit summaries while the same
model worked in chat.

Read options.headers alongside the API key, resolve {env:...} and {file:...}
in the values with the existing resolveConfigApiKey, and merge them into the
request after the bearer default so a gateway whose header is the credential
can override it.

Closes #3213
2026-08-28 23:46:05 +03:00