Add a packaged-client runtime boundary so the shared UI can talk to local,
desktop, remote, and VS Code runtimes through the right transport instead of
assuming one same-origin web server.
Centralize OpenChamber-owned API access behind RuntimeAPIs, runtimeFetch, and
runtime URL helpers, while keeping official OpenCode traffic on the SDK path.
Support runtime switching, remote host selection, desktop client credentials,
and headless connection links for pairing packaged clients with remote
OpenChamber servers.
Harden the new auth model by moving long-lived client tokens out of browser
URLs, introducing short-lived scoped URL tokens for browser-owned transports,
restricting URL-token access to explicit readable/realtime routes, and making
client-token management session-scoped or self-scoped as appropriate.
Update browser-owned assets and preview proxy flows to work with the split
runtime model, including authenticated project icons, preview token propagation,
CSP-safe preview bridge injection, and preview proxy auth that survives
short-lived URL-token expiry.
Tighten Electron security boundaries for packaged clients by gating privileged
preload state to trusted origins and requiring explicit confirmation before
connect deep-links import or switch remote runtimes.
Also refresh agent guidance and project skills so future runtime/API, auth,
preview, UI, CLI, settings, locale, and drag-to-reorder work follows the new
architecture.
* fix(ui): use absolute positioning for pending changes popover to prevent z-index occlusion by revert dock
* refactor(ui): reuse changedFilesPopover constants instead of inlining styles
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
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).
* fix(chat): restore desktop editor file-open in PendingChangesBar (#979)
Commit d1553ba removed the runtime?.editor branch from handleOpenFile,
breaking file-click in VS Code and Electron desktop runtimes.
Restore the 3-branch logic: editor.openDiff(patch) → editor.openFile()
→ openContextDiff() web fallback. Display paths remain relative.
* fix(chat): route non-git changed files to file view in desktop
DiffView requires a git repository to display diffs. In desktop
(Electron/Tauri), runtime.editor is unavailable, so non-git files
fell through to openContextDiff which shows "Not a git repository".
Route non-git files to openContextFile instead, which works without
git. Git-tracked files continue to use openContextDiff.
* feat(chat): per-turn changes dropdown for non-git; self-sufficient git sync in bar
- PendingChangesBar seeds git store + listens to onGitRefreshHint; works without RightSidebarTabs (fixes VS Code where bar never rendered).
- Bar is git-only now; non-git shows per-turn dropdown at end of completed assistant turns.
- Dropdown uses base-ui Popover for collision-aware position; icon-only collapse with tooltips at narrow container widths.
- Extract shared helpers (changedFiles.ts), popover list (ChangedFilesList.tsx), styles (changedFilesPopover.ts).
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* 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>