Commit Graph
32 Commits
Author SHA1 Message Date
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
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 11d2b69651 fix(ui): complete context tab menu icons 2026-08-29 00:41:57 +03:00
Bohdan Triapitsyn 421a868a1a feat(ui): add Linear and Cloudflare tool icons 2026-08-23 17:21:31 +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 52ac367b1e feat: update annotate toolbar icon to markup 2026-08-15 16:33:07 +03:00
Serhii DziupinandSerhii Dziupin 70f8f2e15b fix(icons): inject missing sprite symbols for newly added icons
The icon sprite was injected once and never updated, so HMR/new glyphs
like telegram-fill left <use> refs empty. Append missing symbols on render.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-14 15:19:25 +00:00
Serhii DziupinandSerhii Dziupin a838f62b41 feat(integrations): add Discord/Telegram Coming soon placeholders
Show greyed non-interactive messenger cards with a Coming soon badge
(matching integration card chrome, no expandable controls), and refresh
third-party statuses immediately after Apply & Restart clears pending
plugin restarts.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-14 15:19:25 +00:00
Serhii DziupinandSerhii Dziupin 2303740b4a fix(integrations): restore brand icons and provider logo fallbacks
The Integrations cards render Icon(plugin.icon), so Claude Code /
Command Code / Cursor brand glyphs belong in the sprite. Also restore
claude-code.svg and the Command Code ProviderLogo fallback used after
Set up opens the Providers page. Leave out unused opencode.svg.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-14 15:19:25 +00:00
Serhii DziupinandSerhii Dziupin 53ab67ea35 refactor(integrations): drop unused logos, brand icons, and card wrapper
Keep only the Settings Integrations page wiring: three plugins, i18n,
search/metadata, and the plugins-store registry boolean needed for
failure status. Remove ProviderLogo fallbacks, SVG assets, custom sprite
icons, and the separate IntegrationCard layer.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-14 15:19:25 +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 f4743ea060 feat(chat): work-status panel, and MCP auth and settings fixes (#2776)
Adds a work-status panel beside the transcript. Context fill, model and
cost, todos, running subagents and the permission requests blocking
them, branch and working-tree state, MCP servers, pinned messages and
context sources were scattered across the header, the composer and the
context panel — a blocked subagent was reported nowhere at all. The
panel reads them from live channels rather than persisted history, and
becomes an overlay where the chat is too narrow to seat a column.

It is on by default, including for existing installs. Because it now
carries these readouts, the desktop header and composer drop the ones it
duplicates: todo and changed-files chips, usage and MCP tabs. VS Code
and mobile keep theirs — neither hosts the panel.

Fixes MCP authorization, which was broken from the panel, invalidated by
a directory switch through a redirect URI that encoded the working
directory, and left the desktop app in the background because browsers
will not follow a custom-protocol link without a user gesture. The
settings page no longer asks the user to understand the MCP spec before
adding a server: one field takes the command or the link, with the kind
inferred and a visible override, and client-registration fields appear
only when a server actually asks for its own credentials.

Also: skills load from the panel instead of only when the composer's
slash autocomplete opens; the header button names the current instance
rather than falling through to the word "Instance" for relay hosts.

Three new optional UI settings keys, all migrated. No change to stored
MCP server configuration.
2026-08-09 19:30:25 +03:00
Bohdan Triapitsyn 0d83ebfeba fix(ui): align context surface icons 2026-08-02 23:23:04 +03:00
Bohdan Triapitsyn 34d0ff7383 feat(walkthrough): guided AI walkthrough for diffs, branches, and PRs (#2572)
A diff is ordered by file path, which is almost never the order in which a
change makes sense. This adds a Walkthrough surface that reorders it: the model
groups related hunks into stops, explains what each group changes about
behavior, and orders the stops so each builds on the last. It explains and
orders; judging code stays with the existing Review action.

Reviews uncommitted work (all, staged, unstaged), a branch against its base, or
a pull request. Generation is always user-initiated — nothing runs on a timer,
on a file change, or as a side effect of opening a panel.

Invariants worth preserving:

- Hunk identity is derived on the server and only there. Ids are content
  hashes, so an anchor that no longer resolves is proof the code it described
  changed, and staleness needs no heuristics. The client matches ids to ids and
  never recomputes them; two implementations would have to agree forever.
- The digest is never truncated. A diff that does not fit the model's context
  is refused with an actionable reason, because a walkthrough written against
  half a diff reads as confident and is wrong.
- Nothing disappears. Lockfiles and other generated output are excluded from
  the model's input by name — never by size — and everything no stop covers is
  listed at the end, so "have I seen all of it" stays answerable.
- Cost is explicit. Results are content-addressed, so returning the working
  tree to an earlier state costs nothing; generation outlives its request, so a
  refresh detaches the client rather than discarding paid-for work, and only an
  explicit cancel stops it.

Supporting changes to shared modules:

- git: expose the existing getRangeDiff as GET /api/git
  listUntrackedPaths and getUntrackedDiffs. The latter resolve the repository
  once for a batch instead of per file, taking a panel
  ~340ms on an 80-file working tree.
- small-model: structured output across four wire forma
  and abort signal, and an onOverflow policy so an oversized prompt fails
  loudly instead of being silently clipped. A provider
  remembered so the prompt-side fallback goes first next time.
- models.dev metadata: surface structured_output as tri
  false blocks a model, a missing field does not, because the catalog omits it
  for roughly half of all models.

Desktop and tablet only: VS Code serves Git through its
these routes, and the mobile shell does not consume the surface registry.

Docs: packages/docs walkthrough page in English and all eight locales.
2026-08-02 16:22:55 +03:00
Bohdan Triapitsyn 86ef96302d feat(mobile): mobile app navigation rework and beta-feedback closeout (#2561)
Navigation model rebuilt around two full-width drawers and a minimal
header (sessions / title-switcher / usage ring / workspace):

- Left sessions drawer: cross-project tree with live status indicators,
  swipe actions on sessions (rename/archive/delete) and on group headers
  (project edit / two-step close, worktree delete), reorder-only edit
  mode with collapsible project cards and draggable worktrees, app-level
  footer (connected instance, settings, pending web update).
- Right workspace drawer: Changes / Files / Terminal / Notes / MCP as
  pill tabs (inactive tabs icon-only); panes stay mounted once visited.
  The full desktop file editor serves the Files tab; read/skill tool taps
  in chat open the file there at the requested line.
- Header session switcher on title tap: 10 cross-project recents with
  live busy/attention indicators and project · branch metadata; the
  usage ring opens a metadata overlay with an explicit loading state.
- The overflow menu is gone on phones (its destinations moved into the
  drawers); iPad keeps it until its dedicated layout pass.

Correctness and continuity:

- /auth/session answers bearer-first, so a stale WebView cookie can no
  longer mask a revoked device token; cold launches classify failures
  fast and land on an explicit connect screen.
- Authoritative session snapshots raise frozen ordering baselines and
  stale live ranks — recents stay truthful after the app slept.
- Cold launches reopen the last active session per instance (persisted
  pointer, confirmed against a sessions snapshot; a user-opened draft
  clears it), with a logo hold instead of a draft flash.

Also: collapsed pill composer gains the stop control; chat tool rows
share one 36px rhythm; Task subtool rows truncate; larger bottom safe
area so the composer clears big-screen corner radii; Capacitor build
hides About/Update (store updates apply there); widgets link to the
sessions drawer with a list icon; MobileApp split into focused modules;
five mobile-surface detectors unified; translucent borders normalized to
70%; all new strings translated across the 10 locales.

iPad and foldable layouts are intentionally untouched - separate next version PR.
2026-08-01 21:16:36 +03:00
Bohdan Triapitsyn e2fa7dbad2 feat(ui): context panel 2.0 - surface rail, changes-first git view, live PR surface (#2418)
* feat(ui): add context surface registry and rail switcher

* feat(ui): move git and project notes into context surfaces, embed editor file tree

* feat(ui): replace right sidebar with context surfaces, per-surface panel widths

* refactor(ui): retire legacy main-tab overlays and right-sidebar state

* feat(ui): rail polish, right-docked file tree, terminal surface

* feat(ui): move terminal into context surface, per-surface tab closing, editor empty state

* feat(ui): tune default rail order and activity dot

* fix(ui): keep context panel controls anchored during width animations

* feat(ui): lazy-follow context panel resize with window-level drag tracking

* feat(ui): panel dividers, right-dock tree icon, muted outline folder icons

* feat(ui): restructure git view into changes-first surface with standalone PR surface

- Remove commit/update/pr tabs; git view is always changes + commit
- Promote pull request to its own rail surface with shared repo context
- Move update-branch and re-integrate flows into separate dialogs
- Add PR status chip and repo actions menu to the git header row
- Seed new PR-status entries from resolved sibling remotes to avoid
  a false "checking status" state when the PR is already known
- History/graph dialog refresh button, fingerprint global identity icon,
  muted outline folder icons follow-ups

* feat(ui): progressive-disclosure PR surface with live checks and pinned chat context

- Segment the PR surface into Overview / Checks / Comments pill tabs with
  live badges; merge controls move to the status row
- Live checks segment: progress bar, per-run rows with workflow names,
  elapsed timers, expandable failures, auto-refresh while pending
- PR comments and failed checks pin as chat-context drafts (like terminal
  selections) instead of sending an immediate message; works on new-session
  drafts too
- Shared prContext cache client+server, ETag conditional requests in the
  octokit wrapper (304s bypass rate limits), extended checks aggregate
  (inProgress/queued/startedAt)
- Resolve gh-CLI auth login for merge-permission checks
- Full-width description editor with matched control heights

* fix(ui): single source of truth for PR checks and status readers

- Derive the checks aggregate from the visible run list and sync it into
  the PR-status store so bar, badges, header, and git-view chip agree
- Route PR body hydration through the shared context cache
- Git-view PR chip reads the freshest entry across remote keys

* fix(github): freshness stamps prevent stale cache responses from regressing PR state

- pr/status and pulls/context responses carry a server-side fetchedAt that
  survives cache serves
- The status store rejects responses older than the held snapshot (only
  clearing the loading flag), and the checks sync adopts the context's
  stamp so stale status polls cannot flip fresher derived checks
- Regression test for the stale-response guard

* perf(github): repo-level pull-list cache collapses per-branch PR resolution

- One pulls.list per repo per state per 45s answers every branch (10
  worktrees = 1 call, not 10 query fans); in-flight fetches coalesce
- A complete repo list makes a no-PR miss authoritative, skipping the
  per-owner head queries AND the Search API fallback (the 30/min killer)
- force refresh bypasses the repo list cache; PR create/merge/ready
  invalidate it

* perf(github): back off Search API misses per repo+branch

A branch without a PR re-searched on every poll; with >100 closed PRs the
list miss is never authoritative, so the search fallback still ran and
burned the 30/min search quota. Remember misses for 10 minutes; PR
creation clears remembered misses for the repo.

* fix(github): dedupe re-run check runs to the latest per (app, name)

listForRef returns the superseded completed run alongside its re-run;
GitHub's UI shows only the latest per name. Mirror that in both pr/status
and pulls/context so counts and run lists match github.com.

* fix(ui): address review findings on registry test, surface docs, and PR-context keys

- Rail-order test asserts against the registry itself (was stale after the
  'pr' surface landed and failed)
- surfaces DOCUMENTATION.md describes actual behavior: has-content surfaces
  hide until content exists; only multi-instance/terminal panes are
  keep-alive, singleton surfaces remount and restore from stores
- PR-context cache keys are runtime-scoped JSON tuples; invalidation
  compares the directory exactly instead of by string prefix (+ test)

* fix(ui): wrap long unbreakable tokens in check-run details

Annotation messages with long SHAs/URLs overflowed the panel; break-words
on annotation title/message/rawDetails and output summary/text, and the
expanded run body clips instead of widening the panel.

* fix(ui): busy state for context-attach buttons and honest attach labels

- 'Attach failed checks' / 'Attach all to chat' show a spinner and disable
  while the context request runs (previously nothing happened for seconds)
- Action labels/tooltips reworded from send-to-agent to attach-to-chat
  semantics across all locales

* fix(i18n): Ukrainian attach wording uses 'прикріпити' with proper cases

* fix(ui): runtime-scope PR-view remote caches, correct surfaces doc on preview

- Remote/remote-url caches in PullRequestView are keyed by runtime +
  directory so a backend switch never serves another runtime's remotes
- surfaces DOCUMENTATION.md: preview is not keep-alive; preview tabs
  remount on switch like singleton surfaces

* fix(ui): rail active color, clearer collapse icon, remove dead bottom-terminal dock

Design-review feedback on the context panel:

- Context rail: icons enlarged 16px -> 18px; the active surface is now
  highlighted with the primary color only (no background, no scale
  animation), replacing the previous scale-up effect that read as a
  resize rather than a selected state.
- Files tree: the icon-only 'collapse all folders' toolbar button now
  uses collapse-vertical instead of contract-up-down, which was easily
  mistaken for a close button. The labelled 'Collapse all' dropdown item
  in the session sidebar keeps its icon since text removes the ambiguity.
- Terminal: removed the leftover bottom-dock expand/close buttons that
  rendered in the context-panel terminal but controlled a dock that no
  longer exists (nothing toggles it anymore), so the expand button
  appeared to do nothing and duplicated the panel-header fullscreen
  control. Cleaned up the entire inert layer with it: four useUIStore
  fields (isBottomTerminalOpen/Expanded, bottomTerminalHeight,
  hasManuallyResizedBottomTerminal), five actions, their persistence,
  the MainLayout resize listener that only served the dock height, the
  dock-driven refit effect in TerminalView, and the
  terminalView.bottomDock.* keys across all 10 locale dictionaries.

Validated: ui type-check and lint clean; messages parity test (2 pass)
and useUIStore contextPanel test (13 pass) green; icon sprite
regenerated via icons:generate.

* refactor: use PR visual state for git header icon

Derives the pull request icon color from a single visual state
Covers merged, closed, draft, blocked, and open PR states
Removes conditional class handling from the git header icon
2026-07-27 23:07:42 +03:00
Bohdan Triapitsyn e908db637b feat: agent and CLI control plane for sessions, worktrees, and scheduled tasks (#2408)
Add a shared OpenChamber control service with two thin adapters — a native
`openchamber` tool injected into managed OpenCode, and new CLI commands — so
users can manage parallel sessions, worktrees, and scheduled tasks
conversationally through agents or from the terminal.

Control plane:
- New openchamber-control service owning a fixed action contract:
  projects.list, models.list, session list/create/send/fork/status/messages,
  and schedule list/create/run/delete/toggle. Session and worktree deletion
  and project registration are deliberately not exposed.
- New openchamber-sessions module owning create/worktree/prompt orchestration,
  Goal Mode dispatch, wait semantics (initial idle never counts as completion;
  timeout and cancellation are failures), and explicit partial-failure results.
- Scheduled-task logic extracted into a service shared by routes, CLI, and the
  agent tool.

Agent tool:
- Managed OpenCode gets a materialized plugin registering one typed tool with
  a loopback-only callback, per-child ephemeral bearer (timing-safe, never
  persisted or logged), and abort propagation into the service.
- The ~1.5k-token schema applies progressive disclosure: short descriptions,
  server-side validation returning actionable usage errors, and intent
  guardrails — created sessions/tasks are user-facing work (not age
  self-delegation); worktree/goal/agent/variant/wait are omit-by-default;
  dispatches produce no completion notification, and later result r
  to session.messages, which now returns the authoritative sessionStatus.
- session.create without a user-named model picks from favorites/re
  send/fork omit the selection and the service reuses the target session's
  last user-message model, agent, and variant before falling back t
- An "Agent control tool" setting (default on, Save + Reload to apply)
  disables plugin injection entirely.

CLI:
- New `openchamber session`, `schedule`, `projects`, and `models` commands
  with automatic instance targeting, --wait/--timeout/--last-assist
  worktree flags, and Goal Mode, preserving interactive, non-TTY, --quiet,
  and --json contracts. The control HTTP timeout derives from the w
  instead of the 4-second default.

UI:
- New built-in "Schedule a Task" starter (/schedule-task) running a
  dialogue that defines a task and offers to create it via the tool after
  explicit confirmation; Craft a Goal and Feature Planning gain the
  handoff offer, and guided starters reserve the question tool for concrete
  option choices. Localized in all 10 locales, migrated into custom
  starter lists, hidden on VS Code.
- Sidebar shows CLI/agent-created sessions live via the control eve
- openchamber tool calls render with per-action titles and metadata.
2026-07-24 21:54:28 +03:00
Bohdan Triapitsyn 3fd6627196 feat: move sessions to new worktrees
Add a root-session action that creates a generated worktree from the session directory's current branch, transfers uncommitted changes, and moves the parent session plus its descendants through OpenCode's control-plane API.

Reuse existing project/worktree topology and quick-create behavior, keep the UI non-blocking, reconcile live and global session state across directories, and roll back partial moves and failed worktree creation safely.

Split worktree bootstrap readiness into directory-created, git-ready, and setup-ready phases across web and VS Code. Session moves wait for Git readiness while existing setup-aware flows continue waiting for full setup completion, and worktree removal is serialized with active bootstrap tasks.

Expose the move only for idle root sessions, show localized progress and explanatory tooltips in the sidebar, and keep pending/ready worktree metadata synchronized with authoritative session attachments to avoid stale setup indicators.

Add coverage for control-plane payloads, session-state migration, bootstrap phase ordering and compatibility, removal races, progress metadata, and fast-ready attachment races.
2026-07-19 00:00:31 +03:00
17f1b24709 Standardize Settings layout and save feedback (#2122)
* Group settings navigation menu

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Revert "Group settings navigation menu"

This reverts commit 5983a4e82074b8dab1084af1cadd803ba28ea65d.

* Standardize settings layout feedback

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Fix settings save status timer typing

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Retain settings save status

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Report color mode save state

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Match Appearance settings to two-column layout

Rebuild Appearance into Color mode & Theme, Localization, and Density & type sections with responsive two-column grids, consistent section headers, page description, and green save status.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Migrate settings pages to SettingsPageLayout and SettingsSection

Replace ScrollableOverlay/max-w-3xl shells with the shared settings
layout primitives across entity and static settings pages, normalize
section headers, and add settings.page.behavior.description locales.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Unify remaining settings pages on shared section chrome

Wire Appearance, Projects, and Remote Instances through SettingsSection/SettingsPageLayout so every settings surface shares the same header, divider, and page shell treatment.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Align settings UI with OpenChamber design system kit

Apply kit geometry and control specs: 840px content width, 32/48 padding, fixed 260/280 sidebars, radius/spacing tokens, settings select height, stepper dimensions, and shared field/link typography.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Migrate OpenChamberVisualSettings to shared settings primitives

Replace ad-hoc radio/checkbox/chip/field layouts with SettingsSection
shared chrome for Appearance, Density, Navigation, Chat/behavior, and
Privacy while preserving handlers and data-settings-item anchors.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Migrate settings pages to shared field/checkbox/radio primitives

Unify Defaults, Notifications, Behavior, Git, Session Retention, Passkeys,
OpenCode CLI, Commands, About, Keyboard Shortcuts, and Desktop Network on
SettingsFieldRow / SettingsCheckboxRow / SettingsRadioGroup / SettingsChipGroup
for consistent grid, spacing, and DRY layout. Also remove the GitPage double
SettingsSection wrap around GitHubSettings.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Unify remaining settings pages onto shared field primitives

Migrate Agents, Snippets, Skills, Usage, MCP identity rows and selects to
SettingsFieldRow/CheckboxRow/ChipGroup and SETTINGS_SELECT_*; align page
titles; light-touch Voice/Tunnel/Providers/Plugins without rewriting
complex OAuth, permissions, or tunnel flows.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Polish settings section dividers and transport helper text

Slightly stronger section borders for clearer group separation, and keep
message-stream transport description under the chip control.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Fix settings grid alignment, control heights, and Chat section titles

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Tighten settings grid: flat Chat 2x2 and full-width stacked selects

Message options use a flat two-column grid so row headers share a baseline.
Stacked selects fill their column; field-row selects keep a fixed sm:w-56 width.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Align mixed settings controls to shared FieldRow/CheckboxRow grid

Separate FieldRows from CheckboxRows with SettingsInset, move enum
radios into ControlGroups, and convert misplaced StackedFields to
full-width FieldRows so left edges no longer clash.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Translate Behavior response-style preset labels for es and pl

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Group settings nav into categories and improve icons/order

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Fix settings layout: fewer hrs, shared control widths, chat transport section

Remove SettingsInset top borders, align App install/Density controls to full cluster width, give Message Stream Transport its own Chat section, and fold Sessions Small Model into the first section to cut extra dividers.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Align Voice and MCP settings labels with shared heading classes

Swap form field labels to SETTINGS_FIELD_LABEL_CLASS and use
SettingsGroupTitle for MCP control-group headings (manual auth fallback,
request headers).

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Differentiate settings heading levels by context

Page titles are larger and quieter than section titles; group and field
labels use dedicated shared classes so hierarchy is consistent across
settings surfaces without ad-hoc typography mixes.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Use shared settings title classes in SettingsView home

Wire home and unavailable headings through the shared L1/L2 class
constants so they stay aligned with SettingsPageLayout.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Keep settings number steppers from stretching +/- buttons

Density & type NumberInputs no longer flex-grow across the row, and
NumberInput locks minus/plus to fixed width so the plus side cannot
inflate when the control is placed in a full-width cluster.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Place spacing and input-bar offset on their own row

Density & type now lays out as font families, then font sizes, then
Spacing Density / Input Bar Offset on the row below.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Regroup settings nav and improve Voice layout

Drop Advanced/Usage/Git nav categories: Voice and About under
Interface, Usage under OpenCode, Git under Workspace. Voice provider
chips and STT model cards use shared settings primitives with roomier
spacing and a two-column model grid.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* Space out chat feature groups in visual settings

* Polish settings: save-state wiring, container-query layouts, unified dropdown triggers

- Wire shared save indicator into Behavior page saves and git identity CRUD
- Convert settings layout primitives and page rows from viewport to container
  queries so narrow panes stack instead of clipping
- Unify custom dropdown triggers (model/agent/provider pickers) and remaining
  page selects on the settings control size
- Bump global radius scale by 1px; align variant input with select size
- Migrate stray raw controls (MCP OAuth checkbox, worktree remove button,
  git identity dialog rows, skills dialog labels) onto shared primitives
- Make settings nav items span full sidebar width; trim nav to 240px

* Add General settings page, regroup nav, cap control widths, promote chat feature headers

* Mobile settings nav: plain background and touch-sized rows

* Hide secondary settings descriptions behind clickable info hints

* Move quota credentials to Usage, navigation settings to General, rename External Tunnel

* Quiet settings save indicator: silent success, delayed spinner, visible errors

* Rewrite settings-ui-patterns skill around shared primitives and refactored conventions

* Remove settings starter page; open last visited page, defaulting to General

* Settings polish: spacing, control sizes, trigger widths, readable model names, device dates

* Centralize dropdown trigger chrome, settings nav polish, mobile-only input bar offset

* Fix global line-height regression, auto-hide first-section divider, shortcut row spacing

* Global line-height 1.45, align scheduled tasks header button with select

* Hide editor toolbar and About in VS Code, animate chat render preview outside desktop dialog

* Rebuild agent tool permissions on source-of-truth model

Edit the agent's own permission map verbatim (inherit vs explicit actions, pattern rules only for pattern-capable keys), save permission-only, drop the server-side non-wildcard re-merge that resurrected deleted rules, and surface session-granted rules as read-only.

* Agents model parameters polish: row spacing, variant dropdown, unified widths, dash for unset numbers

---------

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-07-18 00:11:05 +03:00
Bohdan Triapitsyn 65ed6ba0e6 chore(icons): remove unused video chat icon
Regenerate the shared UI icon sprite from current source usages. The video-chat icon is no longer referenced anywhere under packages/ui/src, so the generator removes its stale SVG path from the generated asset.
2026-07-17 10:33:46 +03:00
Bohdan Triapitsyn 1c1456892a feat: add sort-desc icon for sidebar project sorting
Replaces the sidebar sort action icon with a dedicated descending sort glyph
Adds the new icon to the shared sprite set
2026-07-12 15:18:17 +03:00
Bohdan Triapitsyn bb45164ae8 feat: session goals - server-driven goal loop with independent small-model audit (#2148)
Arm the target button in the composer and the next prompt becomes a goal:
the server keeps the session working toward it (idle tick -> small-model
audit -> continuation) until the objective is verifiably complete, blocked,
or out of budget — even with the UI closed.

Server (packages/web/server/lib/session-goal):
- event-driven loop on the global SSE hub; goal state lives in
  session.metadata.openchamber.goal (merge-safe patches, stale-write guard
  by goal id), so it survives restarts and syncs to every client for free
- the small-model audit (objective + last assistant turn only, language
  pinned to the objective) is the sole termination authority; blocked needs
  3 consecutive verdicts, audit outages tolerate one unaudited continuation
  then stop the goal as resumable-blocked
- hard stops: optional token budget, auto-continuation cap (Resume grants a
  fresh allowance), turn errors; user abort pauses the goal instead of
  blocking it, and resuming over an aborted tail nudges immediately
- token accounting as a snapshot of the latest turn (input + cache.read +
  output), goal-relative via a creation baseline and segmented across
  compactions; a compaction summary skips the audit and continues
- continuations reuse the session's own provider/model/agent/variant

UI:
- three-mode target button (arm / disarm / manage dialog), informational
  goal strip with inline pause/resume and an Evaluating indicator, sidebar
  state glyph, objective length counter (2000-char server clamp),
  read-only completed goals
- goal entry points: composer (sessions and drafts), start-new-session-
  from-answer dialog, plan implement dialog (plan content becomes the
  objective), scheduled tasks (Run as goal + budget)
- Settings -> Chat -> Goal: feature toggle + default token budget with
  three-layer parity (web server, client persistence, VS Code bridge);
  VS Code renders goal state but hides the entry points (the loop runs in
  the web server only)

Notifications: per-turn "ready" notifications are suppressed while a goal
is active; settling sends one final notification (desktop, web-push, APNs
generic titles with the session name as body) honoring the completion
toggle. Error/question/permission notifications are untouched.

Docs: user guide (session-goals) in all 9 locales + sidebar entry,
scheduled-tasks cross-reference, server module DOCUMENTATION.md.
2026-07-12 01:23:22 +03:00
Bohdan Triapitsyn 086982c1b3 feat: add temporary sidebar share opinion prompt
Adds a dialog with call booking and survey actions for user feedback
Shows a one-time sidebar toast prompting users to share what’s useful or missing
Adds localized copy for the new feedback entry points
2026-07-06 00:37:24 +03:00
Bohdan Triapitsyn 28f0736d69 feat: small-model utility calls on existing OpenCode providers (#2049)
Adds a server-side "small model" capability: direct, cheap LLM calls that
reuse the user's existing OpenCode provider logins — the mechanism OpenCode
uses internally for titles and summaries but does not expose through the
SDK or plugins. Zero new dependencies; plain fetch with per-provider wire
formats, credentials never leave the server.

Core (packages/web/server/lib/small-model):
- Resolution mirrors OpenCode's session scoping: explicit settings override
  → small_model from the OpenCode config → family scan within the session's
  provider → the session's own model. The global provider scan only serves
  callers without a session context, and background callers forbid it
  entirely (restrictToPreferredProvider), so conversation content never
  reaches a provider the user didn't pick — explicit choices excepted.
- Per-provider auth replicating OpenCode's plugin loaders: GitHub Copilot
  (device token as bearer, no exchange), ChatGPT plan via the codex
  Responses API (single-flight OAuth refresh written back to auth.json),
  Anthropic messages, Google generateContent, generic OpenAI-compatible.
- OpenCode's free models (opencode/big-pickle, *-free) are never called
  directly; unauthenticated providers are skipped by design.
- Prompt clamping to the model's catalog context limit; thinking disabled
  where a wire switch exists (Z.AI/GLM, MiniMax-M3, Gemini Flash); robust
  content parsing with a clear error when a thinking model spends its whol
  budget on reasoning.
- Settings → Sessions gains a Small Model group: use-default checkbox plus
  an override picker limited to authenticated providers, persisted with
  web/desktop/VS Code sanitization parity.

Consumers:
- Session assist: a server-side watcher on the global SSE hub generates a
  short recap and one suggested follow-up after a session idles quietly fo
  a minute, stored on session metadata (openchamber.assist). Freshness is
  keyed to the last assistant message id, so new activity invalidates the
  payload everywhere with no extra writes. The chat shows the recap under
  the last message after five quiet minutes and the suggestion as a
  dismissible chip above the composer (tap fills the input, never sends).
  Gated by a new Chat setting (default on) that is a hard generation
  switch. Language is anchored to the conversation itself, with a
  script-mismatch guard against model/backend language hallucination.
- TTS: a third input mode, summarized — long replies are condensed to
  spoken prose before playback on any TTS engine.
- Git: commit-message and PR generation moved off the active chat session
  onto the small model fed with real diffs and the commit list (bodies
  included), with a session-transport fallback for free-model-only setups.
- Notes: Add to notes distills long selections into 1-3 dense sentences
  preserving exact identifiers, with verbatim fallback on failure.

Fixes along the way:
- The global event watcher now starts unconditionally; it was gated behind
  the desktop-notify env, leaving the server-side event hub dead in
  packaged apps.
- OpenCode re-emits message.updated for old user messages after idle; the
  watcher no longer mistakes those for new activity.
- Session metadata merges from a fresh read right before the PATCH, so
  writes made during the generation window (suggestion dismissals, review
  links) are preserved; the assist runtime stops during graceful shutdown.
2026-07-05 23:19:10 +03:00
Bohdan Triapitsyn 8f685f8db7 feat: improve mobile header and toast placement
Move mobile and VS Code toasts to the top
Respect safe-area spacing for Capacitor toasts
Add dedicated mobile metadata button and update header icons
2026-07-01 20:13:53 +03:00
Bohdan Triapitsyn 8174ede976 Improve Changes diff experience 2026-06-14 01:39:49 +03:00
Bohdan Triapitsyn a3908232ae feat: render LSP tool output in chat
Adds expandable LSP tool rows with scan icon and stable file path display
Adds formatted/raw JSON output toggle and copy action
Improves compact LSP input formatting
2026-06-03 17:15:52 +03:00
Bohdan Triapitsyn b09c6b7047 feat: add /weigh approach-comparison command to draft welcome
Add /weigh as a draft chip and command for the moment before planning —
when you know what to build but not how. Its hidden prompt investigates
the code, then lays out 2-3 genuinely distinct approaches with trade-offs
(complexity, risk, blast radius, effort) and a clear recommendation,
without writing a plan or code.

Follows the established command pattern: visible + hidden magic prompts
wired into command autocomplete, the submit handler, draft preset chips,
and the Magic Prompts settings page, with i18n across all locales. Adds a
scales-3 icon to the sprite.
2026-05-30 02:04:32 +03:00
Bohdan Triapitsyn 2b08a51946 feat: desktop draft welcome presets and /plan-feature command
Add starter preset chips under the composer on the desktop draft welcome
screen (explore, what changed, plan, review). Clicking a chip submits
immediately; prompt chips send a natural-language prompt, command chips
reuse built-in slash commands.

Add a new /plan-feature built-in command, modeled on /workspace-review:
visible + hidden magic prompts that run a guided, batched-question
planning dialogue (investigate the code, ask up to 3 clarifying
questions at a time, surface pitfalls, then produce an implementation
plan). Wired into command autocomplete, the submit handler, the draft
plan chip, and the Magic Prompts settings page, with i18n across all
locales.
2026-05-30 02:04:32 +03:00
Dave OteroandBohdan Triapitsyn becd240168 Add Windows Electron desktop support (#1093)
* fix: make upstream sync actions target the selected remote

Ensure fetch and pull actually honor upstream selection so fork maintenance works from the Git sidebar, and surface upstream branch status alongside the primary origin-tracking indicators.

* feat: add Windows Electron desktop foundation

* fix(electron): stabilize Windows desktop packaging

* fix(electron): stabilize Windows desktop chrome

Use native Windows titlebar behavior with an Alt-accessible hidden menu, and harden Windows dev command launching so the desktop app follows platform conventions.

* fix(electron): stabilize Windows dev startup

* fix(electron): clarify desktop artifact names

* fix(electron): harden Windows desktop release and launch

* fix(electron): address Windows release review

* fix(electron): point updater and release links to org repo

* Fix Windows settings persistence fallback

* Fix Windows Electron dev startup

* Add Windows Electron window controls

* Fix Windows Electron install and opencode launch

* fix: resolve git status for repositories without upstream

Fixes repository detection stuck on Checking repository
Handles git status when no upstream is configured
Adds regression coverage for git status loading

* Add Windows app menu button

* fix: preserve file editor line endings

* ci: add desktop release smoke workflow

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-05-26 18:13:59 +03:00
Bohdan Triapitsyn 6fd3afd25a feat: replace prompt templates with snippets
Replace the prompt-template workflow with snippet support that is compatible with opencode snippet conventions. Snippets are now stored and loaded from global and project snippet directories, including legacy pluralized paths, with frontmatter metadata for aliases and descriptions. Snippet expansion supports recursive references plus prepend and append sections, while inject sections are treated as unsupported no-ops so OpenChamber remains compatible without requiring an external plugin.

Add the snippets settings experience and remove the old prompt-template settings surface. The new settings page and sidebar support creating, editing, deleting, selecting, and describing snippets, with localized copy across every supported locale. The settings navigation now exposes Snippets with a dedicated icon and metadata.

Wire snippets into all prompt-entry surfaces that need them. Chat, multi-run groups, and scheduled task prompts now offer hash-trigger snippet autocomplete and expand snippets before sending work to OpenCode. Chat also uses an adaptive compact placeholder on mobile or narrow composer widths so helper trigger guidance stays readable in constrained layouts.

Keep multi-run aligned with grouped prompts. Multi-run sessions now use a shared title builder that handles both legacy titles and the newer g1, g2 prompt-group title format. Fusion parsing now recognizes grouped multi-run titles, scopes fusion sources to the same prompt group, and creates fusion sessions under the matching group so outputs from different prompts are not mixed accidentally.

Harden the icon sprite pipeline. The sprite generator now discovers icon names used through typed icon maps, JSX icon props, IconName returns, and generated-value flows without scanning unrelated string literals or the generated sprite itself. The generated sprite is strictly typed so invalid icon names are caught by type checking, and existing invalid or unsafe icon references were cleaned up across settings, provider, Git identity, scheduled task, voice, header, and sidebar surfaces.

Update backend configuration routes and documentation for snippets. The OpenCode config route layer now exposes snippet CRUD and expansion endpoints, accepts JSON bodies for snippet writes, and removes the old prompt-template provider. Scheduled task runtime expansion now uses snippets before dispatching messages.

Add regression coverage for snippet storage and expansion, config-route JSON handling, and multi-run title parsing. Validated with full type checking, full linting, targeted multi-run title tests, and targeted OpenCode snippet/config route tests.
2026-05-21 20:00:35 +03:00
Bohdan Triapitsyn 14357257ae perf(ui): migrate icons to SVG sprite system
Replace @remixicon/react with a shared Icon component that renders
via <use href> references to a single hidden SVG sprite. This reduces
DOM node count by replacing inline SVGs with lightweight references.

- Create Icon component with sprite injection (packages/ui/src/components/icon/)
- Migrate all 164 files from @remixicon/react to Icon component
- Auto-generate sprite data from remixicon bundle (scripts/generate-icon-sprite.mjs)
- Add bun run icons:generate to package.json
- Move @remixicon/react to devDependencies
- Add icon usage instructions to theme-system skill
2026-05-13 13:26:35 +03:00