Commit Graph
7 Commits
Author SHA1 Message Date
Shyamalan KannanandBohdan Triapitsyn bcbf34b1d1 feat: add Behavior settings page for global AGENTS.md (#1079)
* feat: add Behavior settings page for global AGENTS.md

- Add new 'Behavior' settings page to manage global system prompt
- Sync global behavior prompt to ~/.config/opencode/AGENTS.md
- Add GET/PUT /api/behavior/agents-md endpoints with 1MB size limit
- Add AbortController guards and parallel fetches in BehaviorPage
- Add i18n translations for en, es, ko, pt-BR, uk, zh-CN
- Add globalBehaviorPrompt to DesktopSettings type and sanitizer
- Add /api/behavior to express.json() body-parser whitelist
- Ensure atomic save: AGENTS.md written before settings updated

* fix: address Greptile review feedback

- Rename misleading 'trimmed' variable to 'value' in settings-helpers.js
- Add Content-Length guard for /api/behavior before 50mb JSON parser
- Use express.json({ limit: '1mb' }) for behavior endpoints
- Add actual translations for es, ko, pt-BR, uk, zh-CN locales

* fix(vscode): support behavior settings endpoint

* fix(behavior): wait for settings persistence

* fix(behavior): end agents file with newline

* fix(behavior): avoid duplicate textarea resize handles

* fix(behavior): clarify global rules copy

* fix(behavior): move rules note into tooltip

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-05-01 00:39:55 +03:00
Shyamalan Kannan fa71954ef1 fix: invalidate model metadata cache after OpenCode restart (#1065)
After OpenCode restarts (via 'Reload Opencode' or server reconnection),
the UI's cached model metadata (context windows, pricing, etc.) was
never refreshed — the cache was fetched once at boot and reused forever.
This meant new/updated models from providers were invisible until a full
page reload.

Add invalidateModelMetadataCache action to useConfigStore that clears
the metadata cache and resets the in-flight tracker. Call it from
performConfigRefresh before re-loading providers.
2026-04-30 12:25:42 +03:00
Shyamalan Kannan 67d05a23fc fix(ui): center skills empty state and fix terminal toolbar overlap (#1064)
* fix(ui): center skills empty state and fix terminal toolbar overlap

Fix two UI layout issues in the settings and terminal views.

Skills empty state:

- Add h-full to the max-w-3xl content wrapper so flex centering works

- Make book icon responsive (h-10 w-10 sm:h-12 sm:w-12)

- Add px-4 padding for narrow viewports

Terminal toolbar:

- Reserve right padding (pr-20) for dock fullscreen/close buttons

- Remove pb-1 from quick keys to fix vertical misalignment

- Change shrink-0 to min-w-0 for graceful shrinking on narrow widths

* ref(ui): gate pr-20 padding on desktop runtime only
2026-04-29 12:30:00 +03:00
Shyamalan KannanandBohdan Triapitsyn 6ab363f8df fix(ui): keep settings sidebar open, center content, and fix worktree refresh (#1058)
* fix(ui): keep settings sidebar open, center content, and fix worktree refresh

- Prevent settings nav from collapsing on split pages (Magic Prompts, Agents, etc.)

- Center settings content with max-w-3xl for better layout on wide screens

- Widen settings window from 960px to 1200px max-width

- Fix source branch dropdown overflow with max-height and scrolling

- Add worktreeRefreshNonce to trigger immediate sidebar refresh after worktree creation

* ref(ui): address Greptile review — remove dead isNavCollapsed code and split worktree effect

- Remove isNavCollapsed variable and all dead branches (resize handle, renderSettingsNav param, SETTINGS_NAV_RAIL_WIDTH)

- Split SessionSidebar effect so worktreeRefreshNonce only triggers discoverWorktrees, not refreshGlobalSessions

- Both type-check and lint pass

* fix(ui): refine settings and worktree dropdown behavior

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-28 14:52:57 +03:00
Shyamalan KannanandShyamalan Kannan 632e6cc97b fix: make todo list update dynamically when task status changes (#999)
areRenderRelevantPartsEqual did not compare the tool part output field,
so when the AI updated a todo list (e.g., marking items completed) the
ToolPart memo comparator returned true and skipped re-render. The UI
stuck showing stale task status.

Fix: add output reference comparison for tool parts in
areRenderRelevantPartsEqual so streaming tool output updates trigger
re-renders correctly.

Co-authored-by: Shyamalan Kannan <yabuku@Shyamalans-MacBook-Pro.local>
2026-04-26 15:10:20 +03:00
a9830cfcf1 perf: drastically improve cold-start, bundle size, and streaming performance (#1000)
* perf: drastically improve cold-start, bundle size, and streaming performance

Cold-start optimizations:
- main.tsx: Remove blocking await on prefs I/O — render immediately with
  defaults, hydrate persisted settings asynchronously. Cuts 50-200ms from
  time-to-first-paint.
- bootstrap.ts: Split directory bootstrap into 3 phases:
  * Phase 1 (blocking): path, config, provider, session status — minimum
    data needed to render UI. Mark status complete after this phase.
    path.get and session.status must both succeed; they have no fallback.
  * Phase 2 (deferred): agents, commands, mcp, lsp, vcs, questions,
    permissions — fetched after first paint without blocking.
  * Phase 3 (lazy): session messages — loaded without blocking init.
- App.tsx: Keep identical provider tree before/after init to prevent
  full subtree remount when isInitialized flips. FireworksProvider and
  VoiceProvider are lightweight shells; overlays deferred until init.

Bundle-size optimizations:
- App.tsx + MainLayout.tsx + VSCodeLayout.tsx: Code-split heavy views
  (SettingsView, GitView, DiffView, TerminalView, FilesView, PlanView,
  OnboardingScreen, SettingsWindow, MultiRunWindow) with React.lazy.
  Views load on demand when user switches panels.
- vite.config.ts: Lower chunkSizeWarningLimit from 1200KB to 500KB.

Streaming render optimizations:
- streaming.ts: Throttle streaming store writes ~60Hz → ~1Hz. Busy-session
  only scan (Set, O(1)).
- MessageList.tsx: Lower virtualization threshold 40 → 15.
- ChatMessage.tsx: React.memo with areRenderRelevantMessagesEqual.
- MarkdownRenderer.tsx: React.memo with explicit prop comparators.

* fix: address Greptile review feedback on bootstrap and provider tree

- bootstrap.ts: Tighten Phase 1 error guard. path.get and session.status
  must both succeed; they have no global fallback.
- bootstrap.ts: Replace dead .catch() on Promise.allSettled() with .then()
  that inspects individual results for errors.
- App.tsx: Keep identical provider tree before/after init to prevent full
  subtree remount when isInitialized flips.

* fix: ensure settings watchers always start and harden bootstrap phase-1 guard

- main.tsx: Start appearance/model/typography watchers unconditionally
  after initializing appearance preferences. Previously they only started
  inside the secondary settings Promise.all().then(), so a transient I/O
  failure would silently leave auto-save disabled for the entire session.

- VSCodeLayout.tsx: Move React.lazy SettingsView const after all imports
  to satisfy ESLint import/first rule.

- bootstrap.ts: Replace fragile hardcoded array indices in Phase 1 guard
  with destructuring so reordering the Promise.allSettled array won't
  silently break the critical-failure check.

---------

Co-authored-by: Shyamalan Kannan <yabuku@Shyamalans-MacBook-Pro.local>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-23 13:54:15 +03:00
Shyamalan KannanandShyamalan Kannan ecb22e19c3 perf: lazy-load heavy dependencies (MarkdownRenderer + CodeMirror languages) (#997)
* perf: drastically improve cold-start, bundle size, and streaming performance

Cold-start optimizations:
- main.tsx: Remove blocking await on prefs I/O — render immediately with
  defaults, hydrate persisted settings asynchronously. Cuts 50-200ms from
  time-to-first-paint.
- bootstrap.ts: Split directory bootstrap into 3 phases:
  * Phase 1 (blocking): path, config, provider, session status — minimum
    data needed to render UI. Mark status complete after this phase.
    path.get and session.status must both succeed; they have no fallback.
  * Phase 2 (deferred): agents, commands, mcp, lsp, vcs, questions,
    permissions — fetched after first paint without blocking.
  * Phase 3 (lazy): session messages — loaded without blocking init.
- App.tsx: Keep identical provider tree before/after init to prevent
  full subtree remount when isInitialized flips. FireworksProvider and
  VoiceProvider are lightweight shells; overlays deferred until init.

Bundle-size optimizations:
- App.tsx + MainLayout.tsx + VSCodeLayout.tsx: Code-split heavy views
  (SettingsView, GitView, DiffView, TerminalView, FilesView, PlanView,
  OnboardingScreen, SettingsWindow, MultiRunWindow) with React.lazy.
  Views load on demand when user switches panels.
- vite.config.ts: Lower chunkSizeWarningLimit from 1200KB to 500KB.

Streaming render optimizations:
- streaming.ts: Throttle streaming store writes ~60Hz → ~1Hz. Busy-session
  only scan (Set, O(1)).
- MessageList.tsx: Lower virtualization threshold 40 → 15.
- ChatMessage.tsx: React.memo with areRenderRelevantMessagesEqual.
- MarkdownRenderer.tsx: React.memo with explicit prop comparators.

* fix: address Greptile review feedback on bootstrap and provider tree

- bootstrap.ts: Tighten Phase 1 error guard. path.get and session.status
  must both succeed; they have no global fallback.
- bootstrap.ts: Replace dead .catch() on Promise.allSettled() with .then()
  that inspects individual results for errors.
- App.tsx: Keep identical provider tree before/after init to prevent full
  subtree remount when isInitialized flips.

* perf: lazy-load heavy dependencies (MarkdownRenderer + CodeMirror languages)

MarkdownRenderer dynamic import:
- Move heavy implementation (marked, react-markdown, beautiful-mermaid,
  react-syntax-highlighter, ~1500 lines) to MarkdownRendererImpl.tsx
- Replace MarkdownRenderer.tsx with thin lazy wrapper using React.lazy
- All 11 existing imports work unchanged — no consumer code modified
- Full markdown stack loads on first render of markdown content

CodeMirror language lazy loading:
- languageByExtension.ts: remove static imports for 10+ less-common
  language packages (@codemirror/lang-go, lang-rust, lang-sql, etc.)
- Keep only 6 most common languages static: javascript, json, css, html,
  markdown, python, shell
- Less common languages return null from languageByExtension, causing
  callers to fall back to loadLanguageByExtension which dynamically
  loads from @codemirror/language-data
- Reduces initial bundle by ~200KB+ of language parsers

---------

Co-authored-by: Shyamalan Kannan <yabuku@Shyamalans-MacBook-Pro.local>
2026-04-23 12:31:42 +03:00