Commit Graph
2285 Commits
Author SHA1 Message Date
Bohdan Triapitsyn 0d603649dc perf(tooling): add automated streaming profiler
Adds `bun run profile:session`: creates a session, opens it in a real
browser, dispatches a prompt through the supported `openchamber session` CLI,
and records until the session reports itself idle. No input is synthesised, so
everything captured is the app reacting to its own event stream.

Streaming is judged by responsiveness rather than totals, so the report leads
with the long-task distribution, style recalculation and layout rates, frame
production, and the application's own stream counters.

Two failure modes are detected rather than reported as clean results. A session
belonging to a directory the browser is not viewing renders nothing and
produces a perfectly quiet profile, so the run verifies both new message
elements in the DOM and message-list render counters. And `RunTask` is only
emitted under the disabled-by-default timeline category, so a capture without
it reports zero long tasks; the missing-task case is now called out instead of
being shown as zero.

Metric helpers are shared with the idle profiler.
2026-08-03 15:24:30 +03:00
Bohdan Triapitsyn 74b2e0a7f1 perf(tooling): add scenario controls to the idle profiler
Idle cost depends on which surfaces are mounted, so the profiler needs to
reach those states without a human driving the UI.

`--panel <mode>` opens the context panel by seeding the persisted store the
app reads on boot, using the same tab identity rules as `useUIStore`.
`--then-tab <name>` navigates through the router after settling, which leaves
already-mounted surfaces mounted and measures what a screen keeps doing once
the user has moved on. Both drive real application state instead of
synthesising clicks, so the recorded window stays free of input-driven work.
2026-08-03 15:04:49 +03:00
Bohdan Triapitsyn 255c738b5e perf(tooling): add automated idle profiling harness
Adds `bun run profile:idle`: a fully unattended capture of what OpenChamber
does while nobody interacts with it. It reports main-thread busy time, style
recalculation and layout rates, DOM node and listener growth, heap trajectory,
a CPU sampling profile, and per-call-site attribution of timer, animation
frame, and observer work.

Chrome throttles timers and stops producing frames for occluded or backgrounded
windows, which silently reports an idle-looking renderer regardless of what the
page schedules. Launch flags now disable that throttling, and every run measures
frame liveness so a throttled capture is reported as a warning rather than as a
clean result.

CDP launch and client code is shared with the existing browser profiler.
2026-08-03 14:20:27 +03:00
Bohdan Triapitsyn e0bd787468 docs: changelog entries for the upcoming release 2026-08-03 13:55:51 +03:00
Bohdan Triapitsyn ce09ca6190 fix(walkthrough): offer German, and catch the next locale that is only half added
German was added to the interface but not to the walkthrough's own language
list, and nothing failed: the picker offered Deutsch because it is built from
the interface locales, the server resolved the tag to English, and a German
reader paid for a walkthrough written in English while the picker still said
Deutsch.

The two lists cannot be one — the server cannot import from packages/ui — so
a test reads i18n/runtime.ts and compares them, in both directions and through
normalizeLanguage. Drift this quiet needs a test rather than vigilance.
2026-08-03 13:55:51 +03:00
Bohdan Triapitsyn 2dca614849 fix(opencode): preserve managed process liveness 2026-08-03 13:24:01 +03:00
Bohdan Triapitsyn 7d311d99c9 feat: add custom/other OpenAI-compatible LLM providers #2571 2026-08-03 13:21:45 +03:00
Bohdan Triapitsyn 2a79c07d8b fix(chat): bound terminal output expansion 2026-08-03 12:56:19 +03:00
Bohdan Triapitsyn 753e4cccaa fix(ui): prevent status row controls from overlapping on narrow mobile #2590 2026-08-03 12:56:05 +03:00
RyderAsking b9447f0ffb fix(ui): preserve narrow desktop status-row behavior
Keep the active todo text hidden below 38rem, as before, while hiding only the changed-files secondary label below 30rem. This fixes the mobile collision without reintroducing the documented narrow desktop overlap.
2026-08-03 09:55:55 +00:00
Bohdan Triapitsyn 2c52240f8e fix(sync): route sessions by server-confirmed directory, unstick queued sends
Session directory resolution had no precedence contract: the selection-time
directory short-circuited every lookup, and a persisted runtime value was
consulted before the authoritative record. A worktree session selected before
its directory store bootstrapped kept the active-directory fallback, and that
guess was persisted, so it survived reloads and restarts.

Directory resolution now lives in one module and orders sources by whether the
server confirmed the path, not by whether the value is local or synced:
authoritative (the child store that holds the session) > server-confirmed
selection > worktree attachment/metadata (the requested path, pre-canonical) >
remembered. A guessed selection is no longer persisted, remembered, or ranked.
Chips read the same resolution the composer used, so queue keys cannot diverge.

Queued auto-send could strand an item indefinitely: backoff, missing send
configuration, and the recent-abort window all returned without scheduling a
wake-up, so the queue only retried when an unrelated status or directory change
re-ran the effect. A retry scheduler now wakes it at the earliest known time.

A rejected send rolls the optimistic message back while the composer stays
silent for transport failures, which makes it indistinguishable from nothing
happening. Failures are now recorded to a bounded in-memory log surfaced in the
About diagnostics report, alongside a directory-resolution breakdown, plus
__opencodeDebug.diagnoseSessionDirectory() and getRecentSendFailures().

Prompted by a report of worktree prompting silently failing. That failure was
not reproduced locally, so the diagnostics are what will identify it.
2026-08-03 12:51:12 +03:00
Bohdan Triapitsyn c5bf04b53a fix(chat): normalize bash output by stripping ANSI sequences and applying terminal control codes #2554 2026-08-03 12:50:56 +03:00
Serhii Dziupin 94c9ac3153 Merge pull request #2592 from openchamber/terminal-open-debug
fix(terminal): start PTY before viewport mounts without dropping output or replies
2026-08-03 12:50:19 +03:00
Serhii Dziupin 88937ade72 fix(terminal): start PTY before viewport mounts without dropping output or startup replies
Terminal creation no longer waits for the Ghostty viewport to report its
size: it starts the PTY immediately with a container/font-derived
provisional size (falling back to 80x24), then resizes once the real
viewport dimensions are known, with a dedupe guard while sizing settles.

Starting the shell earlier means it can emit device/theme queries before
a browser terminal is attached to answer them, so the server now answers
primary device attribute queries itself (Fish blocks ~10s on this at
startup) and bun-pty buffers output emitted before a data subscriber
attaches. Also fixes a few WebSocket transport reconnect races surfaced
by session creation now overlapping renderer setup.
2026-08-03 12:29:32 +03:00
Serhii Dziupin 42eb18f82a Merge pull request #2576 from openchamber/feat/repository-local-skills-discovery-41dc
fix: discover repository-local .agents skills (#1159)
2026-08-03 12:20:42 +03:00
Cursor AgentandSerhii Dziupin ebf1b027cc fix(i18n): add German strings for custom LLM providers
Merge of main brought the de locale without the custom-provider keys
added on this branch, which broke the UI build type cast to I18nDictionary.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-03 08:56:23 +00:00
Cursor AgentandSerhii Dziupin 094fb4fc40 merge main to pick up German locale for custom provider keys
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-03 08:53:06 +00:00
RyderAsking f0436492b4 fix(ui): prevent status row controls from overlapping on narrow mobile
On narrow mobile widths the chat status row rendered the edited-files
summary, diff totals, todo trigger, and chevron in a single flex line.
The left side has several fixed-width parts (file count, +/- counts,
chevron) so it could not shrink past the right side and the right-side
controls visually overlapped the truncated 'changed in workspace' label.

Fold the existing 24rem hide rule for status-row__changed-label into the
same 30rem container query that already hides status-row__active-todo,
and lower the breakpoint from 38rem to 30rem so the secondary label
remains visible on a wider range of mobile widths while the two
non-collapsible sides stop competing for space.

Validation:
  - bun run type-check   (all workspaces, exit 0)
  - bun run lint         (all workspaces, exit 0)
  - mobile HMR route     (HTTP 200)
  - visual: before/after screenshots at ~360-400px width
2026-08-03 08:45:50 +00:00
Cursor AgentandSerhii Dziupin 576791d024 fix: invalidate skills cache with loadSkills directory key
performConfigRefresh passed client-directory-first path into
invalidateSkillsLoadCache, missing the active-project cache key used by
loadSkills after the repository-local skills discovery fix.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-03 08:23:37 +00:00
Cursor AgentandSerhii Dziupin 66c5f0cdd4 fix custom provider edit to preserve config scope
Derive the effective OpenCode config layer (custom > project > user) from
provider sources and send it on PUT /api/provider so project/custom edits
update that layer instead of creating a global user override. Resolve
OPENCODE_CONFIG at call time and add UI/web/VS Code coverage for scoped
upserts.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-03 08:22:30 +00:00
catan271 0de1be65eb fix(chat): normalize bash output by stripping ANSI sequences and applying terminal control codes 2026-08-03 15:21:18 +07:00
Bohdan Triapitsyn 2ba8ae8bd4 feat(i18n): add German (de) locale #2263
feat(i18n): add German (de) locale
2026-08-03 09:29:26 +03:00
Serhii Dziupin 824d1fbbf4 Merge pull request #2584 from openchamber/docs/credit-bestsithineu-linux-desktop
docs(changelog): credit @BestSithInEU for Linux desktop AppImage work
2026-08-03 08:44:04 +03:00
Serhii Dziupin 97156eef87 docs(changelog): credit @BestSithInEU for Linux desktop AppImage work
path-open-utils.mjs and its smoke test are byte-for-byte identical to
his PR #1335 (opened 2026-05-19, review findings addressed the same
day, community-verified on CachyOS but never given a maintainer
review), and linux-app-discovery.mjs retains most of that PR's
implementation. The [1.17.0] changelog entry credited the PR that
carried this work forward but omitted the original author.
2026-08-03 08:42:58 +03:00
Bohdan Triapitsyn 82c540b9a3 feat(i18n): complete German localization 2026-08-03 02:26:52 +03:00
Bohdan Triapitsyn b7b4c089de Merge remote-tracking branch 'origin/main' into feat/german-locale 2026-08-03 01:57:04 +03:00
Bohdan Triapitsyn cf8c494329 fix: hide status row todo text sooner
Adjusts the status row collapse threshold to avoid text overlap
Keeps the todo and changed-files summary on one line more reliably
2026-08-03 01:32:03 +03:00
Bohdan Triapitsyn 1d17cb87b3 feat(walkthrough): write walkthroughs in the reader's language
A guided explanation is only useful in a language the reader reads, so the
panel header gets a language picker alongside the model one, defaulting to
the interface language. Like the model, it is request state rather than a
setting: the language travels with the read and the generation, and the one
a walkthrough was written in is stored with it, so reopening a review
describes what is there instead of what a fresh one would be.

Only prose is translated. Hunk aliases resolve back to hunk ids and
icon/importance are validated against fixed English values, so a translated
one would be dropped by the normalizer — silently losing an anchor or a
style. Identifiers and paths stay as they appear in the code.

The language is part of the cache key, and a read now asks the cache for the
exact request it was given before falling back to the pointer. Without that
the panel answered a request to switch languages with the text it already
had, leaving the other language unused in the cache.

Alongside it:

- The answer budget is derived from the resolved model instead of a flat 24k.
  That number was the same for a 64k-context model and for one that admits to
  384k output tokens, and on the latter it was the only reason generation
  failed: the model spent the whole allowance reasoning and returned nothing.
  It is now min(96k, max(24k, a quarter of the context)) capped by the
  catalog's output limit, decided once so the input reserve and the request
  cannot drift apart.
- A read no longer offers Cancel. It is a few hundred milliseconds of git with
  nothing to cancel, and the button flickered on every model or language
  change. When the panel is showing a fallback, a banner names what is on
  screen versus what was asked for — only once the read has settled.
- The header keeps one 32px control height and drops its labels below 680px
  instead of squeezing them to two letters and an ellipsis.

Docs and module documentation updated in every locale.
2026-08-03 01:27:27 +03:00
Bohdan Triapitsyn e5799c0c67 docs: refresh product positioning 2026-08-03 00:32:02 +03:00
Bohdan Triapitsyn e10eaf4f5b fix(ui): align multi-file patch icon spacing 2026-08-02 23:23:08 +03:00
Bohdan Triapitsyn 0d83ebfeba fix(ui): align context surface icons 2026-08-02 23:23:04 +03:00
Bohdan Triapitsyn 134d055ee6 fix(git): support secure SSH config 2026-08-02 23:02:14 +03:00
Bohdan Triapitsyn 8ebf711f93 chore: updated the unreleased changelog with performance improvements 2026-08-02 21:47:04 +03:00
Bohdan Triapitsyn 17c2d5ec36 fix(ui): keep diff refreshes targeted 2026-08-02 21:46:22 +03:00
Bohdan Triapitsyn 75832876fa fix(ui): align multi-file patch interactions 2026-08-02 21:32:27 +03:00
Bohdan Triapitsyn 89399ec1c2 fix(ui): simplify walkthrough action label 2026-08-02 21:17:39 +03:00
Bohdan Triapitsyn 9d48d5d02b fix(git): clean up in-progress merge/rebase banner
Use the real status-warning tokens (--status-warning-bg did not exist, so
the card rendered without a fill), drop the decorative icons, and fold the
conflict count into the title as a single full-message key per locale.
The operation description now wraps instead of truncating, and both the
conflict and ready-to-continue states share the same action layout.
2026-08-02 20:27:05 +03:00
Bohdan Triapitsyn 25e22f007a perf: fix bundle chunking to slash initial load #1846 2026-08-02 20:26:01 +03:00
Bohdan Triapitsyn 3a50bfb6f9 Merge main and fix lazy image export loading 2026-08-02 20:17:37 +03:00
Bohdan Triapitsyn 728bf54825 refactor: remove unused delete session worktree options 2026-08-02 19:47:00 +03:00
Bohdan Triapitsyn 75606a4ecd chore: update changelogs with recent mobile and UI fixes 2026-08-02 19:38:23 +03:00
Bohdan Triapitsyn bc7ef044b7 fix(sync): guard delete actions by default #2578 2026-08-02 19:37:04 +03:00
Bohdan Triapitsyn 39a321a29b fix(mobile): widen Android edge swipe zones 2026-08-02 19:31:22 +03:00
Bohdan Triapitsyn a96a2310a9 fix(mobile): support QR scanning without Play Services 2026-08-02 19:09:46 +03:00
Bohdan Triapitsyn 2b446dd164 fix(ui): avoid clipping session titles 2026-08-02 18:39:53 +03:00
Alexandre Reyes Martins d19ff96c02 fix(sync): guard delete actions by default
Follow-up to #2574 and f95f1ab18, which guarded the archive path. The
delete path had the same two defects and worse consequences.

`useSessionUIStore.deleteSession`/`deleteSessions` declared an `options`
parameter and discarded it on both paths, so a caller-supplied runtime
key was a silent no-op. `SessionDialogs.tsx:416` already passes options
today and they never reach the action.

The delete path also never rechecked the runtime. Session IDs are not
unique across runtimes, so a response produced by a previous runtime
could commit `finalizeConfirmedSessionDeletion` against the runtime the
user switched to: evicting an unrelated session from the live and global
stores and calling `cleanupPersistedSessionState`, which erases queued
messages, todos, folder membership, inline-comment drafts, chat draft,
and pins. That is user data loss, not stale cache.

`cleanupPersistedSessionState` already rejects an identity whose runtime
is no longer active, but `finalizeConfirmedSessionDeletion` defeated that
check by passing the live `getRuntimeKey()` at commit time, comparing a
value with itself. It now forwards the captured key.

Adopt the default-on shape from f95f1ab18: `expectedRuntimeKey` defaults
to the active runtime in `deleteSession`, `deleteSessionInDirectory` and
the new canonical `deleteSessions` action, and is rechecked before the
request and before every reconciliation. A `404` still means "already
deleted" and commits cleanup, but only while the captured runtime is
active; after a switch it describes the wrong runtime and the action
reports failure instead of committing.

Also documents the throw contract of `patchSessionMetadata`, a
non-blocking nit raised by the review bot on #2574.
2026-08-02 15:13:06 +00:00
Bohdan Triapitsyn ad862d4025 docs: update changelogs for walkthrough and UI changes
Adds an unreleased summary for the new guided walkthrough and mobile/tablet layout.
Documents session, sidebar, chat, and VS Code fixes.
2026-08-02 17:48:50 +03:00
Bohdan Triapitsyn e59f6dff66 fix(vscode): open apply_patch diffs at the correct path #2567 2026-08-02 17:32:27 +03:00
Bohdan Triapitsyn c6ab199fef Merge pull request #2573 from alexandrereyes/fix/archived-session-query-boundary
fix(sync): narrow the archived session query at the data boundary
2026-08-02 17:09:32 +03:00
Bohdan Triapitsyn f95f1ab18f fix(sync): guard archive actions by default 2026-08-02 16:48:02 +03:00