Commit Graph
925 Commits
Author SHA1 Message Date
Bohdan Triapitsyn 4506c18f53 UI refresh: Base UI migration + flat tinted button language + mobile polish (#960)
* deps: bump @opencode-ai/sdk to 1.4.6 and add @base-ui/react

* build: align vite configs with Base UI and packages update

* feat(ui): migrate primitives to Base UI

Replace Radix-based wrappers (button, checkbox, collapsible, command,
dialog, dropdown-menu, input, radio, scroll-area, select, separator,
sonner, switch, textarea, toggle, tooltip) with @base-ui/react
equivalents and a refreshed visual language: flexoki theme tokens,
typography utilities, and a redesigned CommandPalette. Add new
fancy-button variant set and a local slot helper for asChild composition.

* refactor(ui consumers): adopt Base UI primitives across the app

Update chat, layout, git views, settings, multirun, session and agent
management screens to use the new Base UI-backed primitives (anchor
width token rename, dropdown/select/dialog usage adjustments, new
component APIs).

* fix(ScrollableOverlay): forward `disabled` to inner element

Add `disabled` to the type so it propagates via rest spread to the
underlying element (e.g. textarea in simple mode). Resolves a type
error reported after the main merge.

* refactor(dropdown consumers): migrate preventDefault sites to closeOnClick

Base UI's Menu.Item does not check `event.defaultPrevented` before
closing the menu, so the Radix-era `onSelect={(e) => e.preventDefault()}`
pattern no longer keeps the menu open. Replace those sites with the
Base UI `closeOnClick={false}` prop (VSCodeLayout rate-limit info
rows; AgentGroupDetail worktree actions).

* docs(AGENTS): note Base UI as primary source for UI primitives

* fix(ContextPanel): center expand/close buttons in tab header

Header (h-8) had the action row pinned with items-end + pb-1.5, which
placed the h-7 buttons ~2px above the header top and made them look
cropped. Switch to items-center so they sit on the same baseline as
the tabs.

* style(tabs): drop transitions on default variant, soften active pill

Default (underline) variant now switches instantly — no transform/width
transition on the underline indicator, no color transition on tab
buttons. Active pill bg is color-mixed down to 55% of
--interactive-selection so light-theme selection doesn't scream.

* style(button): pill-style elevation and introduce chip variant

Solid variants (default/destructive/neutral/primary/basic) now use the
active-pill shadow stack — hairline navy outer ring + stacked tight/soft
drops — instead of the pure-black inset/border approach. Outline
variant (and FancyButton basic) gets the same elevation without the
white top highlight (no fill to catch light).

Add a new chip variant: flat `border border-border/60` button without
elevation, intended for one-of-N toggle groups where a raised
button would read as the wrong affordance.

* style(header): apply pill-style shadow to OpenIn and Project Actions

Both split-button wrappers previously used a 1px CSS border for
definition. Replace that with the pill elevation stack so the header
buttons match the new Button variants and feel less hard-edged.

* refactor(toggles): migrate one-of-N segmented groups to chip variant

Color Mode, When-sessions-expire, voice/STT providers, auth method,
agent mode, MCP transport, tunnel type and terminal Ctrl/Cmd modifier
toggles all read as flat chip selectors rather than raised buttons.
Switch them from variant="outline" to the new chip variant so the
raised pill-style elevation doesn't fight the selected-state tint.

* fix(elevation): theme-adaptive pill-style shadow for dark mode

The navy (rgba(14,18,27,*)) outer ring was invisible on dark surfaces,
erasing the button/pill edge. Add dark: variants that use a subtle
white outer ring (rgba(255,255,255,0.10)) and darker drop shadows
(rgba(0,0,0,0.30/0.20)) so the elevation reads on both themes.

Applies to Button solid/outline variants, FancyButton equivalents,
the OpenIn and Project Actions header split-buttons, and the active
pill indicator in SortableTabsStrip.

* style(button): flat tinted variants with squircle corner-shape

Replace elevated pill-shadow design with a flat tinted language: pale tinted
fill + hairline tinted border + saturated tinted text for default/destructive.
Add CSS corner-shape: squircle with @supports gate so Chrome 136+ gets the
softened superellipse corners at 50px, Safari falls back to a slightly larger
round radius.

* style(tabs): replace active pill shadow with tinted border

* style(header): flat border and squircle corners for OpenIn / Actions

Drop pill-style shadow stacks in favor of a plain hairline border and apply
the same squircle corner-shape treatment as Button so header controls match
the new visual language.

* style(checkbox): drop filled background for tinted checkmark

Checked / indeterminate states now keep the transparent box, show a
primary-base check/minus glyph, and use a softened primary-tinted inset
border (50% mix) so the control reads as selected without a solid swatch.

* style(layout): widen sidebar-to-chat corner radius to 10px

* style(button): retune tinted variants and unify outline fill

- Bump primary fill toward noticeable but still soft (light 10/16/22,
  dark 16/22/30) and weaken both primary and destructive borders
  (12% light / 20% dark) so the tone reads without shouting.
- Further calm destructive across fill and border so revert-style
  actions match the muted reference.
- Align the outline variant fill with --surface-elevated so git-view
  generate/commit buttons share the header action button surface.

* style(tabs): align pill variant with new button language

Active pill now uses --surface-elevated fill and border-border/60 to
match the outline button. Track and tab/pill geometry adopt the same
squircle treatment as Button: 9-10px fallback with 50px radius under
@supports(corner-shape:squircle). Also tighten track padding (inline
2px, block 2px) and grow active tab height so the indicator fills
the track instead of floating inside it.

* refactor(theme): hardcode radius scale, drop per-theme override

Radius values are now fixed in the design system (flexoki-dark's scale
becomes the app default). Themes can no longer override --radius-* — the
config.radius block is removed from every theme JSON, dropped from the
Theme type, and no longer emitted by the CSS generator.

* chore(ui): lint/type cleanup across Base UI wrappers

* style(tabs): dial pill track background down to near-invisible

* refactor(chip): aria-pressed drives the selected tinted state

The chip variant now carries the tinted primary palette (same as the
default filled button) under aria-pressed, so consumers toggle selection
via a single aria attribute instead of repeating the border/text/bg
override classes. All existing chip consumers migrate to aria-pressed
and drop their hand-rolled selected className.

* chore(defaults): humanize variant label in thinking selector

* fix(diff): render all lines in single-file mode

Single-file mode wrapped PierreDiffViewer in its own layout=fill which
creates a nested virtual-root; combined with the outer CSS containment
on the wrapper, Pierre's virtualizer measured a clamped viewport and
stopped rendering lines past ~150. Mirror the stacked-mode approach:
hoist a ScrollableOverlay as the sole virtual root/content and render
PierreDiffViewer inline, so the shared virtualizer sees the real scroll
viewport and paints every line.

Also drops an unused cn import in SessionRetentionSettings.

* feat(files): collapse floating editor controls behind icon button

The floating file editor toolbar now starts as a single pill icon button
and expands into the full control row on hover or click. Clicking outside
or moving the pointer away collapses it back, keeping the editor surface
unobstructed while the file is being read/edited. Fullscreen overlay
keeps its always-visible toolbar.

* fix(chat): align mobile session status bar radius with chat input

* fix(mobile): keep radio/checkbox/switch at their native size

Mobile CSS forced min 36x36px on every <button>, which swallowed our
Radio and Checkbox primitives (also buttons with role=radio/checkbox)
and ballooned them on touch devices. Exclude role=radio/checkbox/switch
from the touch-target rule and pin the Radio/Checkbox box size with
arbitrary px so padding-scale overrides cannot stretch them either.

* chore(mobile): drop unused cornerRadius prop plumbing

The status bar now hardcodes var(--radius-lg) on both views, so the
cornerRadius prop and the useUIStore selector that sourced it in
ChatInput are dead weight.
2026-04-19 15:52:54 +03:00
Bohdan Triapitsyn 3e52be95c5 feat: add configurable planning magic prompts 2026-04-19 01:49:50 +03:00
Bohdan Triapitsyn 46102ffbf3 feat: add ability to upload external plans and remove them from sidebar 2026-04-19 00:52:14 +03:00
Bohdan Triapitsyn f04d732e15 fix(chat): resolve parent project for worktree-session messages
Save-as-plan and Add-to-notes actions were disabled on messages whose session
ran in a worktree, because session.directory alone does not reflect the
worktree attachment — the authoritative cwd lives in session-worktree-store.

Use useEffectiveDirectory (attachment cwd > worktree metadata > session.directory)
and resolve the parent project via the worktree map the sidebar already builds,
extracted into lib/projectResolution so session-ui-store and chat actions share
one resolver. No extra git calls.
2026-04-18 16:05:55 +03:00
Bohdan Triapitsyn 4aa0dcdc1c fix(readme): remove vacation notice from README 2026-04-18 14:11:24 +03:00
Bohdan Triapitsyn df13a54f37 fix(vscode): hide Save-as-plan and Add-to-notes actions in VS Code runtime
Both flows write into ~/.config/openchamber which isn't reachable from the
VS Code webview, so the buttons were dead weight there.
2026-04-18 13:50:09 +03:00
Bohdan Triapitsyn 01b4f11e56 fix(agent-selector): read agents from active-directory config store
AgentSelector used useAgentsStore which is only warm after a chat session
loads, so the todo send dialog opened from the project context panel showed
an empty agent list. Prefer useConfigStore.agents (the same source ModelControls
uses in chat) with useAgentsStore as fallback, and load both on mount when
neither is populated.

Also set the primary-mode filter on the scheduled task editor agent selector
to keep its options consistent with the other flows.
2026-04-18 13:47:24 +03:00
Bohdan Triapitsyn 8d43678fea feat(notes): add selected chat text to project notes with AI-distilled insight
Extend the text selection popover with an Add to notes action that runs the
selection through the shared text summarizer in note mode and appends the
distilled insight to the active project's notes.
2026-04-18 13:47:16 +03:00
Bohdan Triapitsyn a7bc2a228c feat(todos): send todo to new session or worktree with model/agent/variant picker
Add a dedicated TodoSendDialog that lets the user pick provider/model,
reasoning variant and agent before opening a new session (or a fresh
worktree branch) pre-seeded with the todo text and a hidden instructions
prompt (plan.todo).
2026-04-18 13:47:11 +03:00
Bohdan Triapitsyn 799a202e99 feat(plans): save assistant messages as editable project plans with improve/implement flows
Add Save-as-plan action on assistant messages that writes a markdown plan
into the project plans directory and suggests a title from the text. Plan
view opens a specific saved plan via targetPath, supports inline edits, and
can kick off improve or implement flows in a new or worktree session.

Ship the matching hidden magic prompts (plan.todo/improve/implement) so the
instructions applied by these flows are visible and editable in the Magic
Prompts page.

Remove the plan editor font override, CodeMirror now uses the app font stack.
2026-04-18 13:47:05 +03:00
Bohdan Triapitsyn d203ba2ae0 feat(sidebar): project notes/todos live in right sidebar context tab
Replace the header sticky-note popover/mobile overlay with a dedicated Context
tab in the right sidebar. Context is cycled by the right-sidebar shortcut
alongside git and files, and persisted across reloads.
2026-04-18 13:46:57 +03:00
Bohdan Triapitsyn a9c51f115e refactor(text): extract shared summarization service with tts/note/notification modes
Move server-side summarization out of lib/tts/summarization.js into a shared
lib/text module exposing tts, note and notification modes. TTS and notification
runtimes now delegate to the shared service, note mode is used to distill a
selected excerpt into a short project note. Expose the new endpoint via
/api/text/summarize and route it through the common request middleware.

Client voice/summarize.ts accepts a mode option and points at the new
endpoint with an absolute URL that respects the desktop server origin.
VS Code webview swaps the stubbed tts summarize path for /api/text/summarize
and hardens URL parsing with window.location.href as the base.
2026-04-18 13:46:51 +03:00
Bohdan Triapitsyn 4901cf60b8 fix(projects): deterministic project identity + safe per-project persistence
Derive project.id from project.path (path_<base64url(path)>), shared helper on
both server (lib/projects/project-id.js) and client (lib/projectId.ts). Replace
random UUIDs so icons, notes, todos, actions, setup-worktree, plans and
scheduledTasks share one id across restarts and reinstalls.

Fix read-then-overwrite clobber in project-config.js: scheduled-task writes now
merge with the existing project json instead of replacing it, preserving
client-written fields that live in the same file.

On settings load migrate legacy UUID ids to canonical path ids, moving config
json, storage dir contents and icon files, and remap activeProjectId. Scan for
orphan non-path_* project configs and merge them into the canonical project
when a \$ROOT_PROJECT_PATH/<file> reference resolves on disk, logging any that
can't be matched.

Client openchamberConfig.writeOpenChamberConfig re-asserts server-owned keys
(version, scheduledTasks) on write to defeat the symmetric race. Stores and
persistence derive ids from path consistently.
2026-04-18 13:46:38 +03:00
Bohdan Triapitsyn 5710198864 release v1.9.6 2026-04-17 19:06:27 +03:00
Bohdan Triapitsyn 2766327a68 fix: tighten disconnect recovery guards 2026-04-17 19:00:44 +03:00
jwcrystal f5535dcaf1 fix: recover from sleep/wake disconnection with connection state tracking and immediate health check (#940)
When the computer sleeps and wakes, the SSE/WS event stream drops
silently. Messages appeared sent (optimistic insert) but never reached
the OpenCode server, and the user had no indication the system was
disconnected.

Three fixes:

1. Connection state tracking: add onDisconnect callback to the event
   pipeline. Stream failures set isConnected=false in useConfigStore;
   successful reconnect sets isConnected=true.

2. Send guard: optimisticSend, respondToPermission, and
   respondToQuestion now check isConnected before making API calls,
   throwing a clear error that surfaces as a toast to the user.
   The /compact command also checks connection with error feedback.

3. Faster server recovery: add triggerHealthCheck() to the server
   lifecycle and wire it into the WS event stream runtime. When the
   upstream OpenCode connection fails, the server immediately checks
   health and restarts if needed, instead of waiting up to 15s for
   the periodic health check.
2026-04-17 18:48:39 +03:00
Bohdan Triapitsyn b3f2732dff fix(vscode): make session markdown export save/reveal work 2026-04-17 18:46:13 +03:00
Bohdan Triapitsyn 89800146c0 fix: keep mobile overlay actions visible
Keep mobile overlay footers within the viewport
Preserve scrolling for long forms on mobile
Improve scheduled task editing on small screens
2026-04-17 18:26:08 +03:00
jwcrystal 6d5afe55db fix: harden SSE compression exclusion and add Caddy reverse proxy docs (#939)
The compression middleware filter runs before route handlers, so the
res.getHeader('Content-Type') check in shouldSkipCompression is always
undefined at decision time. SSE exclusion relied entirely on the Accept
header, which non-standard clients (curl, fetch) may omit.

Add deterministic path-based exclusion for all known SSE routes so
compression is skipped regardless of client behavior. Also add a Caddy
reverse proxy example and a CDN double-compression warning to docs.
2026-04-17 18:12:20 +03:00
Bohdan Triapitsyn c494d9f8b9 feat: add desktop LAN access setting 2026-04-17 18:05:53 +03:00
jwcrystalandBohdan Triapitsyn 304b14b4b1 feat: add response compression middleware to reduce bandwidth (#928) (#935)
* feat: add response compression middleware for HTTP responses

Add compression middleware to Express server with SSE route exclusion
and 1KB threshold. Reduces bandwidth for non-streaming API responses
(history, sessions, files, static assets) by 60-80%.

Closes #928

* fix: harden proxy compression and proxy docs

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-17 16:26:56 +03:00
Bohdan Triapitsyn 71eac0d2f6 fix: improve session export and empty chat states
Move session export into the sidebar menu
Add desktop save-and-reveal flow for exported markdown
Show empty-state UI instead of a loading skeleton for empty sessions
2026-04-17 15:33:26 +03:00
coldbrow a17d159e18 feat(chat): add export session as markdown workflow (#934)
Add a download button in the chat view that exports the current session's
messages as a formatted Markdown file. User and assistant turns are
separated by horizontal rules. The filename is derived from the session
title and today's date (e.g. fix-login-bug-2026-04-17.md).
2026-04-17 14:50:26 +03:00
coldbrow e87fd18c2a feat(files): add Copy Relative Path to file context menu (#932)
Add "Copy Relative Path" menu item below "Copy Path" in the file tree
context menu. Uses the existing getDisplayPath helper to compute a path
relative to the project root, which is more useful when sharing file
references in AI chat or commit messages.
2026-04-17 14:41:14 +03:00
Bohdan Triapitsyn 6bc415060b fix: default new users to live chat rendering 2026-04-17 14:39:06 +03:00
Bohdan Triapitsyn 2146e346a0 fix: show empty chat state for loaded sessions
Show the empty chat logo when a session has no messages
Keep skeletons only for real session hydration
Avoid misleading loading UI after reverting the last message
2026-04-17 14:33:08 +03:00
Bohdan Triapitsyn 4590e1684f fix: improve sorted chat activity rendering
Show tools and reasoning live in sorted mode
Keep ambiguous text deferred until final output
Avoid duplicate reasoning outside Activity
2026-04-17 14:26:55 +03:00
Bohdan Triapitsyn 767f423500 fix: suppress auto-approved permission notifications
Skip permission prompts when auto-approve is enabled
Keep request handling reliable after reconnect
Remove unused icon import to keep lint clean
2026-04-17 13:22:14 +03:00
Bohdan Triapitsyn 2bcac9c6f9 refactor: integrate go-to-line into files toolbar
Move go-to-line UI into the editor action bar for a unified layout
Keep toolbar height stable with compact inline line input and Go action
Align file action icons to a single always-enabled visual style
2026-04-17 13:12:53 +03:00
Bohdan Triapitsyn bae7cdc234 fix: make go-to-line shortcut work reliably in editor
Option+G now matches correctly on macOS keyboard layouts
Go-to-line shortcut no longer gets blocked by editor textbox guards
Prevents accidental symbol insertion when triggering go-to-line
2026-04-17 11:36:31 +03:00
Bohdan Triapitsyn f88decdf9b fix(files): scope go-to-line shortcut to editor focus 2026-04-17 11:17:52 +03:00
coldbrow ef4c6ee163 feat(files): add Go to Line workflow (#933)
Add a Go to Line dialog to the file editor that accepts a line number
and scrolls the CodeMirror editor to that position. Triggered via:
- Keyboard shortcut: Alt+G (macOS/Windows/Linux)
- Toolbar button next to the existing Find in file button
2026-04-17 11:15:36 +03:00
YifanandBohdan Triapitsyn bee9d19f3a feat(web): add WebSocket transport for message event streaming with SSE fallback (#764)
* feat: add websocket message stream transport

* fix: avoid false missing session directories in sidebar

* fix: re-probe project root session directories

* refactor: use button group for message stream transport

* fix: resolve chat input hook dependency warning

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-17 11:07:26 +03:00
Dave Otero fd8972a7d9 Add save actions and cross-platform file manager support (#848)
* files-download-feature

* feat: add save option to file directory context menus and viewer

* fix: open files in the system file manager
2026-04-16 23:33:55 +03:00
jwcrystal 79a9f93ae2 feat(files): auto-refresh file tree on external changes (#919) 2026-04-16 23:31:57 +03:00
ricautomationandBohdan Triapitsyn 324cf49755 feat: Latex support (#929)
* feat: implement LaTeX math rendering via KaTeX

- Add katex, remark-math, and rehype-katex dependencies
- Integrate KaTeX CSS with light/dark theme color overrides
- Wire remark-math and rehype-katex plugins into MarkdownRenderer
- Support inline ($...$) and display ($$...$$) math delimiters
- Add plan and task documentation

* fix(katex): display inline error messages for invalid LaTeX

- Configure rehypeKatex with throwOnError: false to render errors inline
- Use destructive color var for error text
- Update feature documentation with verification results

* chore: remove latex PR artifacts and hardcoded color fallback

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-16 23:30:52 +03:00
Jinwoo An (안진우) 2fbfd803f7 feat: add desktop quick open workflow (#925)
Introduce a dedicated Quick Open dialog, wire it to Cmd+P and the macOS app menu, and show file-type icons in quick-open results so file navigation matches the rest of the app.
2026-04-16 23:24:58 +03:00
Bohdan Triapitsyn 5bc52a15ad fix: remove risky worktree recovery on session switch 2026-04-16 23:10:31 +03:00
jwcrystalandBohdan Triapitsyn fccf4bad32 feat: session worktree isolation (#913)
* feat: add session-worktree contract types and canonicalizeWorktreeState API

- Add SessionWorktreeAttachment type and worktree metadata fields (worktreeRoot,
  worktreeStatus, headState, worktreeSource) to session/worktree types
- Add GitAPI.validateWorktreeDirectory() and canonicalizeWorktreeState() methods
  with full HTTP delegation chain (gitApiHttp → routes.js → service.js)
- Add canonicalizeWorktreeState() implementation that resolves worktreeRoot,
  headState (branch/detached/unborn), attentionReason (merge/rebase/etc), and
  worktreeStatus (ready/missing/invalid/not-a-repo) for a given directory
- Add validateWorktreeDirectory() to check whether a cwd is inside a worktreeRoot
- Add session-worktree-contract.ts: pure functions for resolving session worktree
  state, formatting badges, and building repair actions
- Add session-worktree-store.ts: authoritative Zustand store for session-to-worktree
  attachments, replacing session-ui-store as the source of truth for worktree binding
- Add unit tests for contract functions and store operations

* feat: canonicalize worktree metadata producers

- worktreeManager.listProjectWorktrees: derive headState (branch/detached/unborn)
  from worktree list entry instead of relying on external state, and populate
  all Phase 1 canonical fields (worktreeRoot, worktreeStatus, worktreeSource)
  for each discovered worktree entry
- worktreeManager.createWorktree: include all Phase 1 canonical fields
  (worktreeRoot, worktreeStatus, headState, worktreeSource) in returned metadata
- useDetectedWorktreeRoot: populate fallback canonical fields so that
  sessions without store-based metadata still have worktreeRoot/worktreeStatus/
  headState/worktreeSource when resolved through the fallback path

* feat: route sessions through authoritative worktree attachments

- session-ui-store: import session-worktree-store as the authoritative source
  for session↔worktree attachment state
- setWorktreeMetadata: mirror all writes to session-worktree-store so that
  session-worktree-store.attachments is always the authoritative record;
  local worktreeMetadata map is kept for backward-compatible reads
- Add session-ui-store.test.js with unit tests covering: valid cwd routing,
  degraded fallback, created-for-session attachments, legacy upgrade recovery,
  missing/not-a-repo status handling

* feat: clarify session worktree targets

- session-worktree-contract: extend buildSessionTargetOptions to accept
  pendingBootstrapDirectory and mark pending worktrees with pending=true;
  extend SessionTargetOption to include optional pending flag
- ChatInput: replace manual worktree branch options construction with
  buildSessionTargetOptions; add  prefix for pending bootstrap worktrees
- Add test for pending bootstrap worktree distinction

* feat: show worktree-backed session state

- Header: read worktree attachment from authoritative session-worktree-store
  and render needs-attention/degraded/missing badge with alert icon next to
  current session info when session has degraded/missing/invalid state
- GitView: show 'Worktree features are unavailable' message when session has
  missing worktree status and open-without-worktree-features repair action

* feat: enforce safe mutations for attached worktrees

- session-worktree-contract: add getMutationBlockingReasons helper that returns
  blocking reasons (missing/invalid/attention state) for high-risk mutations
- GitView: gate handleCheckoutBranch, handleCreateBranch, and handleRenameBranch
  with getMutationBlockingReasons; block with explicit toast message when
  worktree is missing, invalid, or has an in-progress git operation
- session-worktree-contract.test: add 7 tests covering mutation blocking for
  missing/invalid/attention states (merge/rebase/cherry-pick)

* feat: implement session worktree isolation

This adds a shared session↔worktree contract that makes session switching
worktree-backed. Sessions attached to different worktrees keep stable branch
context without shared-directory auto-checkout.

Commits:
- feat: add session-worktree contract types and canonicalizeWorktreeState API
- feat: canonicalize worktree metadata producers
- feat: route sessions through authoritative worktree attachments
- feat: clarify session worktree targets
- feat: show worktree-backed session state
- feat: enforce safe mutations for attached worktrees

* feat: make authoritative attachment first-priority source for session directory resolution

Phase A: resolveSessionDirectory, getDirectoryForSession, hooks read
authoritative attachment before falling back to worktreeMetadata.

Phase B: createSession canonicalizes and writes attachment on creation;
setCurrentSession recovers legacy/missing attachments via async
canonicalization.

* feat: make authoritative attachment the primary branch source in Header/GitView

Phase C: Header branch label and GitView project root now read from
authoritative SessionWorktreeAttachment first, falling back to live git
and legacy sources only when attachment is absent, degraded, or legacy.

Adds getAttachmentBranchLabel() helper with 7 tests.

* feat: add runtime parity for validateWorktreeDirectory and canonicalizeWorktreeState

Phase D: Web runtime API, VS Code bridge, and VS Code gitService now
expose validateWorktreeDirectory and canonicalizeWorktreeState, matching
the server-side implementations. All three runtimes (web, desktop, VS Code)
can now delegate worktree canonicalization without HTTP fallback.

* feat: add dirty-tree blocking to mutation safety gates

getMutationBlockingReasons now accepts an optional gitStatus param
and blocks branch mutations when the tree has uncommitted changes.
GitView passes live status to all three blocking call sites.
5 new tests covering dirty, clean, null, combined, and no-file-count cases.

* refactor: revert branch label to live-git-first, remove getAttachmentBranchLabel

Live git is the correct source for branch labels in all scenarios:
dedicated worktree sessions have identical live/attachment branches,
and shared-directory sessions must show the real current branch.

Attachment remains authoritative for worktreeRoot, cwd, degraded/
missing/repair status, and mutation blocking.

* chore: remove session worktree isolation plan doc

* refactor: simplify session worktree isolation implementation

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-16 20:13:59 +03:00
Bohdan Triapitsyn f96ccc58c3 chore(deps): bump @opencode-ai/sdk to v1.4.6 2026-04-16 19:16:32 +03:00
Bohdan Triapitsyn 2cedc443a5 fix(sync): keep deltas after initial part.updated coalescing 2026-04-16 19:16:32 +03:00
Bohdan Triapitsyn af7cf6ec9c fix(sync): prefer freshest session status and persist active-now list 2026-04-16 19:16:32 +03:00
Bohdan Triapitsyn 16ec1f605e fix(chat): show blocking requests in sub-session threads too 2026-04-16 19:16:32 +03:00
Bohdan Triapitsyn 758c0dc4b8 fix(sync): scope auto-approve to session tree and restore request UX 2026-04-16 19:16:32 +03:00
Bohdan Triapitsyn ddc1039d1c fix(sync): unify live session truth across chat and sidebar 2026-04-16 19:16:32 +03:00
Tom Rochette 4c4f24a404 Sort skills within groups (#915) 2026-04-16 16:31:37 +03:00
Yifan d0fa9d5a5f fix(vscode): avoid POSIX login shell opencode detection (#921) 2026-04-16 16:31:07 +03:00
Bohdan Triapitsyn 4f228f768d feat: add scheduled tasks with locale-aware scheduling and safer desktop quit flow (#920)
* feat: keep desktop app running in background when closing last window

Closing last window hides it instead of quitting — sidecar keeps running
Cmd+Q now shows confirmation dialog warning about stopping background processes
Clicking dock icon reopens hidden window or creates a new one

* docs: add scheduled tasks impl plan

* feat: add scheduled tasks runtime, api, and ui

* feat: conditionally confirm desktop quit on risks

* chore: remove scheduled tasks plan doc

* feat: add scheduled tasks runtime and management UI

Add server-side scheduled task runtime with project-backed config persistence
Add task scheduling UI and API integration for creating and editing schedules
Add tests for runtime scheduling behavior and project config validation

* feat: add locale display preferences for scheduled tasks

Add Appearance settings for time format and week start with settings.json persistence
Apply preferences in scheduled task editor for time display and weekday ordering
Rename Thinking level control and disable it when model variants are unavailable

* feat: improve scheduled tasks editor and sidebar action order

Reorder session sidebar header actions to separate creation and management tools
Polish scheduled tasks dialog layout and controls for clearer editing flow

* feat: polish scheduled task editor usability

Improve scheduled task dialog layout for clearer scheduling controls
Refine time and weekday inputs for more intuitive task configuration
Update editor labels and control states for better model variant guidance

* feat: add prompt autocomplete and command-aware scheduled runs

Add @ and / autocomplete support to task, multi-run, and agent manager prompt fields
Fix agent mention selection so subagents can be inserted from @ suggestions
Run scheduled prompts as commands when they match slash commands, with message fallback
2026-04-16 15:55:08 +03:00
jwcrystalandBohdan Triapitsyn ea5c19e934 fix(sync): deduplicate overlapping delta after coalesced part.updated (#916)
* fix: hide archived section and empty folders when no sessions remain

- Only push archived group in useSessionGrouping when there are archived
  sessions, preventing an empty archived section from rendering
- Hide empty folders in archived bucket via shouldKeepFolder check in
  SessionGroupSection (folders with no sessions and no content in
  children are filtered out)
- Always filter folders through shouldKeepFolder, not just during search

* perf: memoize archived folder filtering

* fix(sync): deduplicate overlapping delta after coalesced part.updated

When message.part.updated coalesces in the event pipeline and a
message.part.delta for the same part arrives in the same flush window,
the reducer appends the delta verbatim to the already-complete field
value, producing duplicated text in tool output and assistant messages.

Add targeted overlap reconciliation: only when a part.updated replaces
an existing part with overlapping string content, mark the next delta
for that field as dedupe-eligible. Normal streaming deltas remain
untouched (pure append).

Covers four cases:
- Full overlap: delta already present -> no-op
- Partial overlap: only non-overlapping suffix appended
- No overlap: unchanged append behavior
- Legitimate repeated output (ha + ha -> haha): preserved

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-15 10:12:30 +03:00
Bohdan Triapitsyn 9908f2dc9c release v1.9.5 2026-04-14 23:58:06 +03:00