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.
Replace the 'What changed recently' draft chip with /catch-up, a command
whose hidden prompt branches on git state: reconstruct intent from an
in-progress diff, check an open PR's review state, or summarize recent
commits.
Add /debug as a new draft chip and command: a guided root-cause
investigation that captures the symptom, forms hypotheses, checks them
against the code, and confirms the cause before proposing a fix.
Both follow the /workspace-review 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.
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.
Queued messages now match the reverted message dock style
Added per-message edit and send actions
Sending one queued message no longer sends the full queue
Use browser keyboard resizing by default on mobile
Remove mobile-only autocomplete button and tabs
Keep autocomplete behavior consistent across mobile and desktop
* feat(chat): live markdown source-mode highlighting in composer
Highlight markdown syntax, fenced code blocks, and mention-style tokens
directly in the chat input via the existing transparent-textarea overlay
(color/decoration/background only, so caret alignment is preserved).
- Markdown source-mode: inline/fenced code, links, headings, blockquotes,
list markers, with dimmed syntax punctuation
- Per-language syntax highlighting inside fenced blocks, reusing the editor's
CodeMirror language resolver + Lezer (bash/js/ts/json/html/css/python/md);
highlighted blocks use a neutral base, plain fences keep the code color
- Token highlighting on match: @file, @agent, /command, /skill, #snippet
- Auto-pairing: wrap selection with markers, triple-backtick expands to a
fenced block; paste a URL over a selection to form a markdown link
- Add md/markdown to the shared code-block language resolver
* fix(chat): address composer highlight review
- Tilde (~~~) fenced blocks now get per-language syntax highlighting
- Share fence open/close detection between tokenizeMarkdown and
highlightFencedCode so they agree on boundaries (fence length + format),
fixing range bleed with 4-backtick fences and ```lang lines inside blocks
- Replace buildHighlightParts O(segments x ranges) scan with a sweep-line
over an active set (verified equivalent vs the prior algorithm across 30k
randomized cases, including overlaps and explicit class/priority)
- Cap per-block Lezer parsing at 20k chars; oversized blocks keep the neutral
code base without per-token coloring
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.
Shows loaded skills in slash autocomplete with clear type badges
Stabilizes keyboard navigation across autocomplete menus
Fixes skill link rendering and skill autocomplete scrolling
* chore: add .worktrees/ to gitignore for worktree workflow
* fix(chat): restore file attachments when reverting or forking messages
* fix(chat): address review findings in attachment restoration
- Move filePartsToAttachments helper below all imports into its own
'Attachment helpers' section (was incorrectly placed between imports)
- Compute size from base64 data URL for pasted screenshots instead of
hardcoding 0; file:// URLs keep size 0 which formatFileSize suppresses
gracefully
- Capture prevAttachedFiles before optimistic mutation and restore on
SDK revert failure
- Always use source: 'local' for restored attachments so they are
visible and removable in the composer regardless of URL scheme
* fix(chat): resolve merge conflicts and restore attachments in fork
- Merge upstream main which already added attachment restoration to
revertToMessage via addRestoredAttachment
- Add !isSyntheticPart filter to revertToMessage file part collection
(upstream was missing this)
- Add attachment restoration to forkFromMessage (was not fixed upstream)
- Use upstream's addRestoredAttachment approach for consistency
* fix(chat): clear restored attachments when opening new session draft
Reverted-message attachments (and any other pending attachments in the
global input store) were carrying over to the new session input because
openNewSessionDraft did not clear attachedFiles.
Clear attachedFiles in openNewSessionDraft, which is the navigation-away
event for new sessions (it already sets currentSessionId: null). This
matches the semantics of starting a fresh conversation.
---------
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 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
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
The previous system layered three hooks (useScrollEngine, useChatScrollManager,
useChatTimelineController) with overlapping responsibilities, four parallel
ResizeObservers/MutationObservers, and six entry points to "scroll to bottom"
(force-flag combinations, persistent follow loops, materialization recovery).
This produced bugs where users could not break free of auto-follow during
streaming: scrollbar drag, keyboard scrolling and find-in-page were not
detected as user intent, and observers kept restarting the follow loop on
every DOM mutation.
The new architecture replaces the two low-level hooks with a single
useChatAutoFollow that owns scroll behaviour end to end:
- One state: 'following' or 'released'. No follow modes, no pin flags,
no marker pixels.
- One scroll writer: a lerp loop that runs only while the session is
streaming and state is 'following'. Idle sessions never write scrollTop
programmatically.
- One user-intent detector: wheel up, touch drag down, keyboard
(PageUp / Home / ArrowUp), pointerdown on the OverlayScrollbar thumb,
and explicit releaseAutoFollow() calls all flip the state to 'released'.
- A 1.2s grace period after explicit release: re-pin will not auto-engage
inside this window, so a small wheel up cannot snap the user back even
while they remain near the bottom spacer.
- Re-pin and the scroll-to-bottom button share the same threshold: the
height of the empty bottom spacer (10vh on desktop, 40px on mobile).
Released users see the button only after they have scrolled past the
spacer that already exists at the end of the chat.
- Save/restore of scroll position uses ratio mapping, debounced at 150ms
on user-driven scroll events; programmatic writes are masked via a short
window so they never persist as user positions.
- Container reattachment is detected via a useLayoutEffect probe over
scrollRef.current. Listeners and observers re-bind when ChatViewport
mounts after hydration or after the first message promotes a draft
session into a real chat.
- A pending-restore queue replays restoreSnapshot once the scroll
container appears, fixing the case where a hydrating session landed at
the top instead of the bottom.
Removed: useScrollEngine.ts, useChatScrollManager.ts, the persistent
follow loop with its own ResizeObserver+MutationObserver pair, the
materialization-recovery .finally resume that yanked idle users to the
bottom on transient sync gaps, and the openchamber:session-reselected
event (re-select still works through the existing onSessionSelected
callback). The openchamber:chat-force-scroll-bottom event remains for
synthetic-message paths like git-message generation.
Net change: ~1300 lines removed, two hooks replaced with one, one
observer pair instead of four.
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.
Conflict resolution prompts now ask for an analysis-first strategy
Response style instructions are wrapped as system reminders
Prompt templates stay separate from reminder formatting
* 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>
* fix(ui): read textarea DOM value in queue handler to prevent truncation
When the user types quickly and clicks the Queue button, React may not
have committed the latest `message` state yet, causing handleQueueMessage
to capture a stale closure (often just the first character typed).
Read textareaRef.current.value directly from the DOM instead, which
always reflects the current input regardless of React's render cycle.
Fall back to the React state when the ref is unavailable.
Also recompute hasContent from the DOM value to ensure the guard check
is consistent with the actual message being queued.
* fix(ui): use current input value when sending
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
Use base-ui's transition-status pattern (data-starting-style /
data-ending-style) for Dialog, DropdownMenu, Select, Tooltip and Popover
so open/close animate consistently at 150ms ease-out without flicker.
Wrap dialog popups in a centered flex container so the scale animation
no longer fights with translate-based positioning, and switch
PendingChangesBar to a real Popover so it actually animates closed.
Convert ScheduledTaskEditorDialog from raw Radix to the shared Dialog
wrapper, give ScheduledTasksDialog a stable min-height to prevent layout
shift mid-animation, and reset NewWorktreeDialog form state on open
instead of close so fields don't empty during the close transition.
Drop tooltip delay from 700ms to 300ms globally and remove all
per-component overrides except the model/variant/agent selectors in the
chat input (600ms).
* feat: embedded preview proxy for local dev servers
Add a same-origin server proxy under /api/preview/proxy/:id and
matching UI surfaces so local dev servers (Vite, Next, etc.) can be
embedded inside OpenChamber.
Server (packages/web/server):
- New lib/preview/proxy-runtime.js: cookie-gated HTTP+WebSocket proxy
to loopback hosts only, with TTL'd targets and SSRF allowlist.
- index.js wires the runtime alongside terminal/event-stream.
UI (packages/ui):
- ContextPanel preview tab with iframe, reload, and open-in-browser.
- Inline html code-block preview in MarkdownRenderer.
- Terminal auto-detects loopback URLs and offers to open them.
- i18n keys across en, es, pt-BR, uk, zh-CN.
* perf(preview): cache proxy targets across PreviewPane remounts
Module-scoped Map keyed by upstream URL so tab switches and component
remounts within the same page session reuse the existing proxy
registration instead of POSTing a fresh target each time.
In-memory only by design: the server holds the target map in memory
and the auth cookie is HttpOnly + scoped to the proxy id, so a stale
persisted entry would 404 after a server restart. Entries are evicted
on registration error and on a 30s safety margin before TTL expiry.
* feat(preview): surface dev-server-down state with retry overlay
Iframes don't expose HTTP status to the parent, so when the proxy
returns a 502 (upstream dev server is offline) the iframe just renders
the raw JSON error body. Probe the proxy URL out-of-band with HEAD
(falling back to GET on 404/405) and replace the iframe with a
friendly 'Dev server is not responding' overlay + retry button when
the upstream is unreachable.
Re-probes on reload, on URL change, and on proxy re-registration.
* feat(preview): strip frame-busting response headers
Many dev servers (Next.js, others) send X-Frame-Options: SAMEORIGIN
and/or a CSP with frame-ancestors that block embedding inside the
OpenChamber iframe. The proxy is same-origin and already
authenticated per-target, so embedding is otherwise safe.
- Drop X-Frame-Options outright on proxied responses.
- Surgically remove only the frame-ancestors directive from
Content-Security-Policy and Content-Security-Policy-Report-Only,
preserving every other directive. Drops the header entirely if no
directives remain.
- Verified end-to-end: upstream sending both headers comes through
with X-Frame-Options removed, CSP retaining default-src/script-src
but no frame-ancestors, and unrelated headers untouched.
* docs(preview): design for remote-host relay agent
Design-only doc for the next phase of the embedded preview feature:
when OpenChamber runs remotely (cloud/shared/tunnel) and the user's
dev server runs on their local machine. Covers architecture (local
agent + outbound control WebSocket + server dispatch), pairing flow,
wire protocol, security model, failure modes, open questions, and
implementation milestones. No code changes.
* feat(preview): auto-open preview pane for loopback URLs in chat
Detect http(s) loopback URLs in incoming assistant messages and open the
preview pane automatically, deduped per (session, url) pair so re-renders
or repeated mentions do not steal focus. Add an inline Preview button
next to loopback links in chat markdown as a manual fallback when the
auto-open was dismissed or the URL appeared in an older message.
- url.ts: isLoopbackHttpUrl / extractLoopbackUrls helpers
- ChatContainer: module-level dedupe Set + effect on active session tail
- MarkdownRendererImpl: optional onPreviewLoopback in main renderer only
(SimpleMarkdownRenderer for tool diffs is intentionally untouched)
- Reuses existing terminalView.preview.open i18n keys
* feat: preview enhancements, dev shutdown, and reliability fixes
Add preview start/stop UI in ContextPanel/Header, improve URL detection (Python HTTP server logs, trailing punctuation, IPv6 loopback), fix proxy path filtering to avoid disrupting non-preview WebSockets. Add dev-only /api/system/dev-shutdown endpoint and Header button to terminate local dev processes and orphaned preview servers. Improve terminal cleanup with process group killing, event pipeline reconnect backoff. Update file read APIs with optional flag and cache control. Add /api/system/free-port endpoint, detectDevServer.ts utility, and preview/shutdown i18n strings for 5 languages.
* fix: harden preview support
* fix: keep terminal toolbar interactive
* fix: keep expanded terminal below header
* fix: keep preview iframe under proxy path
* fix: respect project action preview urls
* fix: rewrite preview asset urls
* feat: capture preview console logs
* feat: annotate preview elements
* feat: attach preview annotation screenshots
* fix: improve proxied preview hmr
* feat: refine preview action UX
* fix: address preview review feedback
* fix: show auto-discover preview wait state
---------
Co-authored-by: William Biggers <will@Williams-MacBook-Pro.local>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* feat: improve agent and quick model picker behavior
* fix: keep the active model highlighted in the quick picker
* feat: streamline mobile model selection
Open the full mobile model picker directly and remove the intermediate controls drawer so mobile model changes follow the same core selection flow as desktop.
Add inline thinking-mode chips that show each model's remembered or default variant, apply model and variant together on tap, and fall back to a dedicated overflow panel for larger variant sets. Also keep favorites and recents searchable on mobile and fix clearing remembered default variants so the picker stays consistent across sessions.
* fix: polish desktop model picker interactions
Stabilize desktop model picker behavior by keeping keyboard and hover selection in sync, preventing hover-driven closes, and making the footer hints visually stable.
Also make quick-picker thinking mode changes apply consistently when switching plan/build or agent mode inside the picker, clamp left/right variant cycling at the ends, and keep thinking feedback visible even when the selected variant cannot move further.
* fix: condense mobile model picker rows
Tighten the mobile model picker to use a more compact, consistent row layout across favorites, recents, and provider sections while keeping context length and capability icons easy to scan.
Also preserve inline thinking-mode selection, improve metadata spacing, and keep the mobile controls readable without reintroducing the heavier drawer-based flow.
* fix: include all primary-like agents in picker cycling
Keep desktop Tab cycling and mobile tap cycling aligned with the rest of the selection UI by including agents marked as all or left unset, not just strict primary agents.
* fix: preserve remembered agent variants in picker flows
* Fix model picker variant restore
* Polish favorite model drag handle
* Fix Korean model picker locale
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* fix: exclude file content from reverted prompt text
Revert and fork now restore only the user's original prompt, not server-injected file content
Uses existing isSyntheticPart helper for type-safe filtering
* fix: keep scrollbar visible when hovering over thumb
* fix: prevent ESC abort from triggering when terminal is focused
* fix: pass directory to permission/question reply calls so approvals actually resolve
* fix: default model selection not responding after Base UI migration
* fix: prevent modal content from shifting and clipping footer buttons
* fix: improve session switching performance and add sub-agent export with prompt collapse
Defer viewport anchor saving to eliminate ~800ms UI freeze when switching sessions
Add export dialog to include sub-agent tasks recursively in markdown export
Add collapse chevron button for expanded user prompts in sticky header
* fix: resolve sidebar scroll and TDZ crash in session sidebar
* perf: reduce CPU overhead and re-renders across chat, layout, and settings
* fix: position collapse button at top of message and prevent ESC abort in terminal
* fix: position collapse button at top and add padding only when expanded
* refactor: extract shared PATH utilities and mobile keyboard hook
* refactor: import shared path-utils in electron, use module-level style constants
- Electron now imports pathLooksUserConfigured/mergePathValues from
shared path-utils.js instead of inline duplication
- ToolPart collapsedCustomStyle moved from useMemo([]) to module const
* fix: resolve remaining merge conflicts and type errors
- Remove duplicate variable declarations in SessionNodeItem
- Remove orphaned export callback body from conflict resolution
- Fix HelpDialog description -> descriptionKey (i18n rename)
* fix: resolve type-check and lint errors in session-actions.test.ts
- Added missing bun:test type declarations (beforeEach, mock, mock.module)
- Removed unused State import
- Replaced 'as any' casts with proper OpencodeClient and ChildStoreManager types
- Added eslint-disable for unused _ parameter in mock function
* fix PR 1028 export and PATH edge cases
* fix startup retry exhaustion state
* remove opencode package lock change
* fix sub-session rename cancellation
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
Remove body position:fixed lock, visualViewport listener in MainLayout
(keyboard-inset heuristics, scroll-to-zero lock, focusin/focusout RAF),
[data-keyboard-avoid-active] translateY rule, and related CSS vars
(--oc-keyboard-inset, --oc-keyboard-avoid-offset, --oc-keyboard-home-indicator,
--oc-visual-viewport-offset-top). Strip data-keyboard-avoid* attrs and
keyboardAvoid props from Dialog/ScrollableOverlay and consumers. Drop
isKeyboardOpen from useUIStore.
With body unlocked and the layout plain flex-col (h-dvh), the browser
shrinks the viewport on keyboard open naturally — composer sits above
the keyboard, header stops lagging, input no longer jitters.
FilesView.nudgeEditorSelectionAboveKeyboard now derives the occluded
bottom locally from visualViewport + documentElement.clientHeight.
Add /review command with high-signal diff review instructions
Expose workspace review prompts in Magic Prompts settings
Show /review in command autocomplete with OpenChamber command metadata
Show commands with identical names from different sources
Add stable command IDs so selection no longer depends on name dedupe
Keep command insertion flow working across chat and prompt editors
Typing /summary (optionally with a topic hint) produces a structured
summary as a normal assistant message — without compacting or mutating
session history. Reuses the existing "Start new session from this answer"
button for hand-off.
Prompts are customizable in Settings → Magic Prompts under a new Session
group. Autocomplete shows an 'openchamber' badge to distinguish our
commands from OpenCode-built-in ones.
Recover stalled event streams without dropping the session
Wait briefly for reconnection before showing connection lost errors
Persist Electron server logs for easier disconnect debugging
- event-pipeline: onDisconnect now carries a reason tag (ws_closed:code=N, ws_error_frame, ws_closed_before_ready, sse_error)
- useConfigStore: store lastDisconnectReason, clear on reconnect
- send guards: embed reason in Connection lost toast so we can tell which path tripped
- lifecycle: isOpenCodeProcessHealthy hits /global/health (healthy flag) with 5s timeout instead of /session with 2s, avoids false restarts under stream load
* feat: add FileChangeSummary component for multi-file diff preview in ToolPart
Provides an aggregated diff card for apply_patch and multi-edit tools,
showing per-file stats with click-to-expand diff view.
* feat: add PendingChangesBar above chat input with collapse/expand and file opening
- Collapsed/expanded toggle with aggregate +N -N stats (green/red)
- Relative path display, chat-column alignment with ChatInput
- Click file to open in diff viewer (web/desktop) or editor (VS Code)
- Support edit/multiedit/apply_patch/write tool metadata extraction
- Add PendingChangesBar to main chat view (ChatContainer)
* feat: dual-mode ChangedFilesBar — Git diff state vs latest AI turn
Git mode: reads git status from useGitStore (status.files + diffStats),
auto-clears on commit/restore. Shows 'N files changed in workspace'.
Non-Git mode: latest assistant turn only (no accumulation), clears on new
user message or manual dismiss. Shows 'AI updated N files in the last reply'.
Both modes: dismiss button with signature-based tracking.
Add pendingChangesBarDismissed state to session-ui-store, cleared on sendMessage.
* fix: address code review issues in ChangedFilesBar
- Gate non-git mode on streaming state to prevent flicker during AI turns
- Return null when isGitRepo is unknown (loading state)
- Add group/row class for reject button visibility in FileChangeSummary
- Use per-session Map for dismiss tracking to prevent cross-session leaks
- Include additions/deletions in dismiss signature for re-edit detection
- Extract shared parsePatchStats/parseCount to fileChangeHelpers
* chore: revert local .opencode/package-lock.json changes from PR
* fix: per-part fallback guard and git-only reject button
- Fix extractChangedFiles to use per-part files.length snapshot instead
of global guard, preventing file entries from being skipped when
earlier parts already contributed files
- Hide reject button in FileChangeSummary when not in a git repo,
preventing silent revert failures
* refactor: remove FileChangeSummary — dead code redundant with ToolPart
FileChangeSummary duplicated diff rendering that ToolPart already
provides (PatchDiff, per-file stats, DiffViewToggle). The only unique
feature was a git revert button, which conflicts with the design
principle of not having accept/reject on file change previews.
Moved parsePatchStats/parseCount back into PendingChangesBar (sole
consumer) and deleted the shared helper module.
* chore: remove stray Tester.txt
* fix: deduplicate Fallback 4 'Diff' placeholder via seen set
* chore: update non-Git mode copy to neutral 'changed in the last reply'
* fix(chat): unify changes row with tasks
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>