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.
Restart OpenCode after successful updates so the new version is active
Open native About menu into the app About dialog
Update desktop View menu actions for the new layout
* fix: make PWA install and OpenCode update toasts dismissible
Both 'Install OpenChamber' and 'OpenCode update available' toasts use
duration: Infinity with no close affordance, so they persist on screen
until the user accepts (install/update) or reloads the tab. For users
who do not want to install the PWA or upgrade right now, this is
intrusive and there is no opt-out.
Add a Dismiss button (sonner cancel action) to both toasts. When the
user dismisses:
- PWA: persist a flag in localStorage so the prompt does not reappear
on future sessions. Accepting Install still works as before.
- OpenCode update: persist the dismissed version in localStorage. The
toast will appear again only when a newer version becomes available.
Adds new i18n keys pwa.installPrompt.dismiss and
opencodeUpdate.toast.actions.dismiss across all seven locales (en,
es, ko, pl, pt-BR, uk, zh-CN).
* test: extract toast dedup helpers and cover with 28 unit tests
Lift the dismissal-decision logic out of usePwaInstallPrompt and
OpenCodeUpdateToast into a React-free sibling module so it can be
unit-tested directly. The React surfaces remain sole owners of side
effects (storage writes, toast.info, event listeners); the new module
only answers 'should we show?'.
New module openCodeUpdateDedup.ts exposes four helpers:
- shouldShowPwaInstallToast(input) - three gates: dismissed,
sessionShown, hasActiveToast.
- shouldShowOpenCodeUpdateToast(input) - empty version, seen set,
dismissed===version gates; a different dismissed version lets the
toast resurface for the new release.
- resolveOpenCodeUpdateVersion(detail) - parses CustomEvent payloads
defensively (null/non-object/non-string -> '').
- resolveOpenCodeUpgradeStatusVersion(status) - parses upgrade status
payloads (status falsy / available!==true / latestVersion non-string
-> '').
Consumers now call the helpers and only run the side-effect when the
decision is true. Behaviour is unchanged.
Coverage: 28 tests via bun:test, 33 expects, all pass first try.
Targets active editor chat before falling back to sidebar
Adds session open-in-editor action in the VS Code sidebar
Uses attachment badges for VS Code file and selection context
Change the chat text-selection Add to notes action to use the existing markdown selection payload, matching Add to chat formatting behavior while still falling back to plain text when markdown extraction is unavailable.
Stop distilling or summarizing selected text before saving it to project notes. The action now appends the selected content directly so code, lists, emphasis, and other markdown survive.
Increase the project notes text limit from 1000 to 3000 characters to account for saving raw selected text instead of a short generated summary.
Update user-facing copy across locales from distilled insight language to selected text language.
Disable the active Zen summarization flow because the unauthenticated/free Zen provider is no longer available and now returns usage-limit errors for this feature.
Keep /api/text/summarize as an API-compatible stub that returns local sanitized or distilled fallback text with summarized=false, rather than attempting external model calls.
Remove notification and voice playback summary behavior from runtime paths. Notification {last_message} now always uses normalized truncated text, and TTS playback ignores historical summarize request fields.
Hide the notification summary settings and voice summarize-before-playback controls while preserving legacy persisted settings for compatibility. Also disable Zen model startup validation and make Zen model list routes return empty results.
Update module documentation and tests to describe the retired provider behavior and the remaining compatibility stubs.
Shows loaded skills in slash autocomplete with clear type badges
Stabilizes keyboard navigation across autocomplete menus
Fixes skill link rendering and skill autocomplete scrolling
* feat: add copy-as-markdown and copy-as-json buttons to question card
Adds two small icon buttons in the QuestionCard header so users can copy
the full question payload (text, options, descriptions) to the clipboard
in either Markdown or JSON form. Useful for forwarding interactive
questions to an external LLM or note.
- Markdown serialization preserves question headers, multi-select hints
and option descriptions.
- JSON serialization mirrors the on-wire QuestionRequest shape for
programmatic reuse.
- Toast feedback on success/failure using the shared @/components/ui
wrapper and the existing copyTextToClipboard helper (clipboard API
with execCommand fallback).
- New i18n keys added across all 7 locales.
* test: extract question serializers and cover with 15 unit tests
The two serializers backing the copy-as-markdown and copy-as-json
buttons on QuestionCard were defined as top-level consts inside
QuestionCard.tsx. Exposing them for unit tests would trip the
react-refresh/only-export-components ESLint rule because that file
also exports the QuestionCard component.
Move serializeQuestionAsMarkdown and serializeQuestionAsJson into a
React-free sibling module, questionSerializers.ts, and re-import them
from QuestionCard.tsx. Behavior is byte-identical.
Add 15 unit tests via bun:test covering header fallback, multi-select
hint gating, blank-description elision, ordering across multiple
questions, JSON canonical shape (no transient id/sessionID), boolean
normalisation, and the empty-questions edge case.
* fix: remove max-h-80 cap on quick notes textarea so resized height is respected
* feat: add drag & drop reordering to project todo items
* feat: make todo panel resizable with density-aware sizing
* feat: open plan import file picker at project root
* feat: persist quick notes and todo panel sizes across sessions
* refactor(ui): scale content height with padding in projectnotestodopanel
* Update packages/ui/src/components/session/ProjectNotesTodoPanel.tsx
Signed-off-by: Erman HAVUÇ <ermanhavuc@gmail.com>
* fix(ui): harden context panel resizing and import
---------
Signed-off-by: Erman HAVUÇ <ermanhavuc@gmail.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* feat: add collapsible reasoning traces with animated labels
* feat(ui): redesign reasoning blocks with merged collapsible Thought view
- Replace per-part reasoning blocks with a single merged block per turn
(VSCode Copilot pattern), controlled by new `groupReasoningBlocks` store flag
- `ReasoningTimelineBlock` redesigned: chevron toggle, summary preview on
collapsed header, 'Thinking'/'Justification' label when expanded, BusyDots
while streaming, auto-scroll to bottom during live streaming
- Short texts (< 120 chars) render inline without a toggle
- Summary now strips markdown and truncates at a word boundary with ellipsis
- New `MergedReasoningPart` component merges all reasoning parts for a message
into one block at the position of the first reasoning part
- `defaultExpanded` prop lets callers override initial expand state
- Remove `.thinking-dot` CSS animation (replaced by BusyDots component)
- Fix reasoning markdown font-size: use `--text-markdown` instead of `--text-meta`
* refactor(ui): scope working phrases inside useAssistantStatus and simplify reasoning status
- Move WORKING_PHRASES array and getRandomWorkingPhrase() inside the hook
so they are no longer exported (were only consumed by ReasoningPart which
no longer needs them)
- Change the 'reasoning' activity status text from a random working phrase
to the deterministic string 'thinking' — matches the new UI label
* test(ui): expand ReasoningPart tests for new collapsible and summary behavior
- Update baseline test to use text long enough to trigger the collapsible
path (short texts now render inline) and assert on the correct aria markup
- Add test for 'Justification' label when pre-expanded via defaultExpanded
- Add test for 'Thinking' label for the thinking variant when expanded
- Add test verifying summary is a word-boundary-truncated excerpt ending with
an ellipsis character
* i18n: rename 'Reasoning Traces' to 'Thinking Blocks' and add thought key
- Rename settings label from 'Show Reasoning Traces' → 'Show Thinking Blocks'
across all supported locales (en, es, ko, pl, pt-BR, uk, zh-CN)
- Add `chat.reasoningTrace.thought` key to all locales (used by merged
reasoning block header in completed state)
* feat(ui): add collapsibleThinkingBlocks setting with full persistence wiring
- New boolean store field `collapsibleThinkingBlocks` (default true) with
`setCollapsibleThinkingBlocks` action; persisted to localStorage
- Threaded through DesktopSettings, SettingsPayload (API types), desktop
persistence (sanitize + apply), web appearance persistence, appearance
auto-save watcher, and server-side settings-helpers sanitize/format
- Server defaults to true when the field is absent in formatSettingsResponse
- MessageBody reads the flag: false → render reasoning as plain AssistantTextPart;
true → existing collapsible/merged block path
* feat(settings): expose Collapsible Reasoning Blocks toggle in visual settings
Add a checkbox under the 'Show Thinking Blocks' row (visible only when
showReasoningTraces is enabled) that toggles the collapsibleThinkingBlocks
preference. Follows the existing toggle pattern: div role=button, keyboard
handler for Enter/Space, Checkbox primitive, aria-pressed attribute.
* i18n: revert showReasoningTraces label rename and add collapsibleThinkingBlocks strings
- Revert 'Show Reasoning Traces' → 'Show Thinking Blocks' rename (the
collapsibleThinkingBlocks toggle is now a separate control, so the parent
label stays as 'Reasoning Traces' for clarity)
- Add `collapsibleThinkingBlocks` / `collapsibleThinkingBlocksAria` strings
across all seven supported locales (en, es, ko, pl, pt-BR, uk, zh-CN)
* test(server): add settings-helpers coverage for collapsibleThinkingBlocks
- Verify sanitizeSettingsUpdate accepts boolean true/false and rejects
non-boolean values (string, number)
- Verify formatSettingsResponse forwards the value correctly for both true
and false, and defaults to true when the field is absent
* fix(ui): respect defaultExpanded prop and remove dead alwaysShowActions from ReasoningTimelineBlock
The useEffect on [isStreaming] was firing on mount and immediately calling
setIsExpanded(false) (since isStreaming is false for completed blocks),
overriding any defaultExpanded={true} passed by callers. The fix uses a
prevIsStreamingRef so the effect only collapses the block on a true→false
transition and is a no-op on initial mount.
Also removes alwaysShowActions from ReasoningTimelineBlockProps — the new
header design always shows the chevron, making the prop obsolete. The prop
was already absent from the component destructuring (a dead type entry) and
was silently ignored at runtime. Removed it from ReasoningPartProps,
MergedReasoningPartProps, and the two call-sites in MessageBody as well.
* chore: remove unused reasoningpresentation module and test
* fix(ui): polish collapsible reasoning block UI
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* feat(ui): revert indicator with undo/redo, message list, and attachment restore
Add bidirectional undo/redo with redo stack navigation and expandable
revert indicator in StatusRow. List reverted messages with inline
revert/fork actions. Restore file attachments on revert.
- Add revert indicator with count, expandable popover, per-button spinner
- Restore file/image attachments when reverting to a message
- Clear previous attachments on revert when target has none
- Restore-all bypasses redo stack for direct unrevert
- Survive popover close/reopen without losing loading state
- Fix flash when sending message after revert
- Fix count disappearing on browser refresh
- Remove dead code (undoStack, getRevertHistory, fork-from-here)
- Fix toast grammar (Undid -> Reverted, Redid -> Redone)
- Add i18n keys for revert popover across all locales
* fix(ui): Greptile review fixes and i18n for revert toasts
- Fix handleSlashUndo toast always showing [No text] (moved getSyncParts before revertToMessage)
- Add inputStore rollback in revertToMessage catch (restore attachments + text on API failure)
- Change portal ID to per-session (prevent multi-session collisions)
- Add i18n keys for undo/redo/restored toasts across all 7 locales
- Use formatMessage in store for localized toast strings
* fix(ui): add missing sessionId to click-outside effect deps
* fix(ui): remove unused sessionActions import in ChatMessage
* fix(ui): derive revert dock from session state
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
Adds read-only embedded chat mode without hiding permission prompts
Opens subagent sessions in the context panel instead of replacing the main chat
Fixes context panel message loading for embedded sessions
Adds a setting to show or hide OpenCode update notifications
Dismisses the active update toast when notifications are disabled
Adds localized settings labels
Adds Run fusion for multi-run-like sessions
Combines sibling outputs into a new fusion session
Adds configurable Fusion prompts in Magic Prompts settings
Adds Cycle Agent to shortcut settings with Tab as the default
Applies custom shortcut in chat input and model selector
Updates help dialog to show saved shortcut values
Creates non-Git multi-runs in the same project directory
Shows concise footer info when worktree isolation is unavailable
Displays default model variants with a friendly label
Replace server-enforced structured output with local JSON parsing for Git generation
Render generated commit and PR JSON responses as compact chat cards
Tighten generation prompts while preserving active session context
- Add local Whisper STT via Transformers.js with Web Worker (no UI freeze)
- Default sttProvider to 'local' in Electron (browser STT unavailable)
- Fix infinite toast loop: stop auto-restart on network errors
- Add retry limit with exponential backoff for transient STT errors
- Append voice transcript to input field (append-inline), not replace
- Add model catalog with download/load button in Voice Settings
Use existing local PR branches instead of blocking worktree creation
Only block PR branches already checked out in another worktree
Clarify local branch validation messages across locales
Add dedicated Electron Mini Chat windows for focused chat sessions without the full desktop shell. Mini Chat can open existing sessions or draft sessions, supports pinning above other windows, transfers sessions or drafts back to the main window, and deduplicates existing-session windows.
Expose Mini Chat entry points from the main header, session sidebar, command palette, and `mod+alt+n`. Add a dedicated Vite entry and React runtime so the compact surface can stay isolated from full-app chrome while still sharing chat, sync, theme, locale, model, agent, and worktree behavior.
Keep Mini Chat behavior scoped to the compact surface:
- limit assistant/user message actions to the appropriate Mini Chat set
- hide workspace changed-files UI in Mini Chat
- keep draft worktree selection and streaming directory state in sync
- mark sessions viewed while they are open in Mini Chat
- support Mini Chat-specific keyboard shortcuts for input focus, model selection, thinking variant cycling, favorite model cycling, and opening new Mini Chat drafts
Harden Electron integration by gating Mini Chat controls on desktop IPC availability, restricting pin/unpin IPC to Mini Chat windows, and only closing Mini Chat after the main window handoff succeeds.
Replace placeholder conflict text with localized copy
Split in-progress operation details and actions into clearer rows
Keep merge and rebase status messages consistent
Add a Stashes dialog with create, apply, pop, and drop actions
Include untracked files automatically when stashing
Show file counts for current changes and stash entries
Combine fetch, pull with rebase, and push into one sync action
Keep remote dropdown focused on safe fetch actions
Block sync when uncommitted changes would conflict with rebase
* feat(chat): add active editor file context and related functionality
* feat(chat): improve active editor file context handling and update translations
* feat(i18n): standardize quotation marks in file attachment messages
* update Korean translation for image removal action in file attachment
* feat(chat): refine active editor file handling and optimize broadcast logic
* fix(chat): stabilize VS Code editor context chips
---------
Signed-off-by: David Saz <david.saz.g@gmail.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
Polls every 2.5s and transitions automatically once the CLI is reachable
Advanced settings and troubleshooting moved into collapsible accordions
New i18n keys added for status indicator and section titles across 6 locales