Commit Graph
1356 Commits
Author SHA1 Message Date
Bohdan Triapitsyn 9faf97acbd ci: handle Electron app artifact shape
Wraps downloaded Contents folder back into OpenChamber.app
Unblocks Tauri-to-Electron migration repackage job
Documents GitHub artifact behavior
2026-05-22 02:22:19 +03:00
Bohdan Triapitsyn 07eb9d50d3 release v1.11.4 2026-05-22 02:07:11 +03:00
Bohdan Triapitsyn a22433ed71 fix: stabilize terminal layout resizing 2026-05-22 01:53:32 +03:00
Bohdan Triapitsyn 2d85cc86be fix: tune sidebar and context panel sizing
Keep the left sidebar open when the context panel opens
Reduce right sidebar and context panel default widths
Collapse only the sync button label at medium widths
2026-05-22 01:33:11 +03:00
Bohdan Triapitsyn 6fd3afd25a feat: replace prompt templates with snippets
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.
2026-05-21 20:00:35 +03:00
Bohdan Triapitsyn 7d98f388c0 ci: cut over desktop releases to Electron
Repackages Electron app for legacy Tauri updater migration
Stops release and manual DMG workflows from building Tauri
Documents transition flow and cleanup timing
2026-05-21 16:37:06 +03:00
Tom Rochette 6cc1afc963 Multi-run with configurable prompt templates (#1111)
* Multi-run with configurable prompt templates

* Fixes

* Fix handleDuplicate fire-and-forget: await createTemplate and handle failure

* Add Polish translations for prompt template and multirun group keys

* fix: migrate remaining Remix icons to Icon component in MultiRunLauncher

---------

Signed-off-by: Tom Rochette <roctom@gmail.com>
2026-05-21 16:35:42 +03:00
Isaac Sanchez-HawkinsandIsaac Sanchez 8dac0f73c0 fix(ui): revoke voice preview blob urls (#1342)
* fix(ui): revoke voice preview blob urls

* fix(ui): reset disposed preview audio

---------

Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
2026-05-21 15:51:49 +03:00
Isaac Sanchez-HawkinsandIsaac Sanchez 6fbdb22c7e fix(ui): avoid file search cache key collisions (#1343)
Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
2026-05-21 15:51:09 +03:00
Bohdan Triapitsyn 51c8d52ab5 perf(ui): improve VS Code chat session switching
Improve chat session switching and history pagination, with most of the aggressive limits scoped to the VS Code webview where the freezes were observed.

Session history loading and pagination:

- Reduce the VS Code message page size to 30 records so switching sessions does not immediately hydrate large histories into the webview.

- Keep manual Load older messages in VS Code fixed at 30 records per request instead of growing the request size over time.

- Add a bounded VS Code initial-tail expansion path from 30 to 50, 80, and 120 records only when the initial page has no user-message turn boundary, preventing large final turns from rendering as an empty chat.

- Lower the normal web message page size from 200 to 150 for a mild shared optimization without adopting the aggressive VS Code limits.

- Make session pagination metadata reactive per session so ChatContainer receives cursor updates from materialization and reconnect paths without requiring a switch away and back.

- Write pagination metadata before publishing newly materialized messages so the first render sees the correct has-more state.

- Store cursor information from direct materialization and reconnect message fetches in the shared session prefetch metadata cache.

VS Code cache and memory pressure reductions:

- Use a shared per-directory session recency map so cache eviction is based on app-level recency instead of whichever useSync instance happened to run.

- Limit VS Code warm session cache retention to 4 sessions and evict heavy inactive message caches after switching away from a large session.

- Disable sidebar session prefetch in VS Code because warming extra sessions was increasing webview memory and GC pressure during navigation.

- Remove dropdown background message prefetch so opening the switcher does not start additional session materialization work.

- Drop cached session-message-record snapshots when evicting session data so stale derived records do not remain after the raw session cache is cleared.

- Add bounded LRU caching for session message record snapshots, with much smaller VS Code limits and a VS Code cap that avoids caching snapshots above 30 messages.

- Bound the turn-window model cache in VS Code and avoid caching turn models for sessions above the VS Code message-page size.

Chat render-path reductions:

- Reuse ChatContainer's already-materialized message records in plan detection instead of adding a second active-session message subscription.

- Add a no-op guard when marking session plan availability so repeated detections do not create new Map references and fan out renders.

- Add no-op guards for session switcher and dropdown open state updates to avoid unnecessary store updates and renders.

- Convert several session-specific hooks to useSyncExternalStore with empty-session no-subscribe behavior so empty IDs do not subscribe to broad store updates.

- Remount the chat viewport when the current session changes, isolating per-session viewport and list state.

- Change the virtualized message-list fallback to render only a tail window when the virtualizer has not produced rows yet, instead of rendering an entire large history.

VS Code layout and header improvements:

- Remove the broad useSessions subscription from the VS Code layout header path and subscribe only to the active session title and initial-session existence.

- Unmount the compact VS Code session sidebar when the user is in chat view instead of keeping the hidden session list mounted and subscribed.

- Compute the latest assistant model and latest context-token usage in a single reverse scan of current-session messages instead of scanning the same list twice.

- Remove switcher git-status warmup work so the switcher reads already-loaded branch labels without starting extra background git status requests.

Markdown and file-reference safeguards:

- Skip expensive syntax highlighting for very large code blocks, with a 200-line cap in VS Code and a softer 1200-line cap in web.

- Add an LRU cap to file-reference stat lookups so the cache cannot grow without bound across many rendered messages.

- Limit the number of file references annotated per render to 40 in VS Code and 200 in web to prevent large assistant outputs from spawning too many stat checks.

- Clear file-link annotations when file-reference mode is disabled so stale attributes and handlers do not remain on previously annotated nodes.

Assistant-message action and preview reductions:

- Skip preview URL scanning on VS Code, mobile, and mini-chat surfaces so assistant text and tool output are not scanned where the preview action is unavailable.

- Skip Save-as-Plan project lookup on VS Code, mini-chat, and mobile surfaces.

- Hide Save-as-Plan and Start MultiRun assistant-message actions on VS Code, mini-chat, and mobile surfaces.

- Resolve the current session directory on demand for assistant actions instead of subscribing each assistant message to the full session list.

Tool and task rendering optimizations:

- Prefer finalized task metadata summaries without fetching child-session messages when the summary is already present.

- Avoid polling or final-fetching task child sessions once a final metadata summary is available.

- Use VS Code-specific task child fetch limits of 30 records for initial, active, and idle fetches.

- Parse diff stats by scanning patch text line-by-line instead of splitting large patches into arrays.

- Count write-tool lines by scanning content instead of allocating a split array for large files.

- Avoid trimming large patch strings just to test whether they contain content.

- Memoize diff and write statistics so unchanged tool parts do not recalculate them on every render.

VS Code bridge improvements:

- Return JSON and text proxy responses through the VS Code bridge as bodyText instead of base64 so the webview avoids synchronous base64 decoding for common API responses.

- Keep binary responses on the base64 path while making bodyBase64 optional in the bridge contract.

- Strip content-length, content-encoding, and transfer-encoding headers from proxied responses because the bridge reconstructs the Response body.

Validation:

- bun run type-check

- bun run lint

- bun run vscode:build
2026-05-21 15:45:44 +03:00
Bohdan Triapitsyn 80cf598d9f fix(ui): preserve reasoning collapse animation 2026-05-21 15:45:44 +03:00
Bohdan Triapitsyn 3f4259379d fix(ui): prevent completed reasoning collapse animation 2026-05-21 15:45:44 +03:00
Bohdan Triapitsyn 40210917c2 fix(ui): keep completed reasoning collapsed 2026-05-21 15:45:44 +03:00
Bohdan Triapitsyn b523dcae91 fix: improve unknown tool names
Format underscores and hyphens as spaces in fallback tool labels
Make third-party tool names easier to read
2026-05-21 15:45:44 +03:00
Bohdan Triapitsyn 4c2eeb4d78 fix(ui): live sidebar inner width during resize
Inner sidebar content was pinned to a fixed openWidth (derived from store state) so it kept its full size during open/close animation. But store state only updates on pointer-release during a drag, which meant inner content didn't reflow while the user was actively dragging — only after they let go.

Keep openWidth as the inner width when the sidebar is idle (so slide-out animation still shows full-width content under the clipping aside), but during an active resize bind the inner content to a CSS variable that applyLiveWidth updates on every pointermove. The aside continues to use direct px width for transition reliability; the variable is just a side channel for the inner element.
2026-05-21 15:45:44 +03:00
Bohdan Triapitsyn e57f66ccd3 refactor(ui): trim header trigger labels and fix dropdown anchoring
OpenInAppButton and ProjectActionsButton now render icon-only triggers in the header instead of icon + text. Padding is tightened accordingly and the now-unused selectedButtonLabel / formatActionButtonLabel helpers are gone.

With narrower triggers the previous center-aligned dropdown with translate -30px started overflowing the viewport on the left edge for ProjectActions. Switched ProjectActions dropdown to align="start" and OpenInApp dropdown to align="end" (matching their positions in the header) and removed the manual translate offset.

Also fixed a long-standing inconsistency where clicking an already-running action in the ProjectActions dropdown re-ran it instead of stopping; the non-compact branch was missing toggleStopIfRunning=true that the compact branch already passed.

MiniChat header now uses bg-sidebar to match the main desktop header palette.
2026-05-21 15:45:44 +03:00
Bohdan Triapitsyn a38e9b9cb9 feat(ui): animate sidebar open/close
Sidebars now slide open/closed with a 200ms cubic-bezier(0.22, 1, 0.36, 1) transition on width. Inline transitionProperty/Duration/TimingFunction are used directly on the aside so the change is browser-driven rather than relying on Tailwind arbitrary classes that didn't reliably trigger the width transition.

Inner sidebar content is pinned to the open width with shrink-0 so it stays full-size while the outer aside collapses around it, eliminating the vertical jitter that came from content reflowing when its container shrank. The chat-frame keeps a constant 1px border and 10px radius on all four sides — only the left/right border color toggles between border/50 and transparent — so no layout reflow happens when sidebars open. Mask-corner overlays are always mounted and animate their left/right offset and opacity in lockstep with the sidebars instead of mounting/unmounting.
2026-05-21 15:45:44 +03:00
Bohdan Triapitsyn 471ae69b1a refactor(ui): full-width header with framed chat shell
Header now spans the full window width above the [sidebar | chat | right-sidebar] row instead of nesting inside the central column. The chat area becomes a self-contained framed window with its own border and rounded corners on all four sides, and sidebars sit flush against the header sharing its bg-sidebar so the seam is invisible.

Removed the duplicated shell controls the old layout needed to fake header-height inside sidebars: portal host on RightSidebar, paddingTop reservation, top drag overlay, duplicated layout-left / chat-new buttons in SidebarHeader, the showDesktopSidebarChrome block in SessionSidebar, and the conditional traffic-lights inset on the desktop header. Mac WCO inset now lives only on the header.

Moved the new-session action into the SessionSwitcher dropdown as its first item, removed the standalone chat-new button from the header, relocated scheduled-tasks into the left action group of the sidebar header, and bumped ContextPanel tab strip to h-10 to balance the more prominent header.
2026-05-21 15:45:44 +03:00
luo jiyin 6243a51053 chore: unify zh-CN translation terminology (#1341)
* chore: unify zh-CN translation terminology

* doc:fix from review

---------

Signed-off-by: luojiyin <luojiyin@hotmail.com>
2026-05-21 00:30:52 +03:00
Bohdan Triapitsyn aaffd6c598 fix: improve OpenCode update and desktop menu behavior
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
2026-05-20 17:29:00 +03:00
Bohdan Triapitsyn 966f35da6c refactor: unify model picker behavior
Share model picker UI across chat, agents, and multi-run
Prefer live provider limits with metadata fallback
2026-05-20 16:26:40 +03:00
Bohdan Triapitsyn d3be82e3d7 fix: adjusted text selection background in light themes 2026-05-20 10:37:31 +03:00
Bohdan Triapitsyn f354762e22 release v1.11.3 2026-05-19 19:26:38 +03:00
Isaac Sanchez-HawkinsandIsaac Sanchez 2bf0c17b05 fix(ui): associate save plan title label (#1331)
* fix(ui): associate save plan title label

* test(ui): make save plan label test locale-independent

---------

Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
2026-05-19 17:42:14 +03:00
Isaac Sanchez-HawkinsandIsaac Sanchez 65e288bb71 fix: respect session prefetch page size (#1332)
Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
2026-05-19 17:39:37 +03:00
Isaac Sanchez-HawkinsandIsaac Sanchez 81c72df8ea fix(ui): ignore non-finite quota percentages (#1329)
Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
2026-05-19 17:38:11 +03:00
Isaac Sanchez-HawkinsandIsaac Sanchez 5189eb586e fix(ui): handle blocked storage getters (#1330)
Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
2026-05-19 17:32:36 +03:00
Isaac Sanchez-HawkinsandIsaac Sanchez 69ea4767f7 fix(ui): keep generated copy feedback stable (#1328)
Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
2026-05-19 17:32:03 +03:00
Isaac Sanchez-HawkinsandIsaac Sanchez 2f89757b9f fix: strip code before TTS markdown cleanup (#1327)
Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
2026-05-19 17:30:32 +03:00
Lam NguyenandBohdan Triapitsyn 4cfe7c80a3 feat(quota): add Wafer.ai quota provider (#1312)
* feat(quota): add Wafer.ai quota provider

- New provider: wafer.js fetches from https://pass.wafer.ai/v1/inference/quota
- Auth: reads wafer/wafer-ai/wafer_ai keys from auth file
- Timeout: AbortSignal.timeout(15_000) with timeoutSignal.aborted detection
- Response: parses remaining/limit/overage/usedPercent/window_end/plan_tier
- valueLabel: planTier + remaining/limit + overage suffix
- Window: 5h (18000s) via resolveWindowLabel
- Cross-runtime: added to web registry, UI types, VS Code dispatcher

* fix(quota): wafer provider fixes — auth alias, decompression, logo

- Add 'wafer.ai' auth alias to match actual auth key format
- Use 'Accept-Encoding: identity' header to fix Bun fetch
  decompression issue with Cloudflare-backed responses
- Match copilot valueLabel format: 'planTier · X / Y left'
- Add wafer logo alias so Providers and Usage pages resolve
  to the same wafer.ai logo from models.dev

* style(quota): fix indentation of timeoutSignal declaration

* fix(quota): derive window duration from API instead of hardcoding

Compute windowSeconds from window_end - window_start timestamps,
with WAFER_WINDOW_SECONDS (5h) as fallback if timestamps are missing.

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-05-19 17:29:36 +03:00
Bohdan Triapitsyn 6970cb45c0 fix: align markdown link favicons
Fixes favicon vertical alignment in inline markdown links
2026-05-19 17:20:00 +03:00
Isaac Sanchez-HawkinsandIsaac Sanchez 9ed44326f8 fix(ui): update viewport height without visualViewport (#1314)
* fix(ui): update viewport height without visualViewport

* fix(ui): initialize visual viewport state from helper

---------

Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
2026-05-19 16:58:18 +03:00
Roberto Bertó 46bef9b0c7 Fix/dismissible infinite toasts (#1319)
* 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.
2026-05-19 16:57:23 +03:00
Bohdan Triapitsyn bb87111c49 fix: refresh git changes after chat revert
Updates Git and Diff views after reverting a chat turn
Uses the existing git refresh hint path
2026-05-19 16:49:11 +03:00
Bohdan Triapitsyn 04f4b71396 fix: dedupe vscode notifications across panels
Prevents duplicate native notifications when a session is open in both sidebar and editor
Uses an extension-host claim step so only one VS Code webview displays each notification
Keeps notification behavior unchanged for single-panel sessions
2026-05-19 16:41:16 +03:00
Bohdan Triapitsyn c81441ecfc feat: improve VS Code editor chat actions
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
2026-05-19 15:53:54 +03:00
Bohdan Triapitsyn 25037ccab9 fix: open subtasks as sessions on mobile and VS Code
Restores session navigation for subtask links on mobile
Keeps desktop subtask links opening in the context panel
2026-05-19 14:58:09 +03:00
Bohdan Triapitsyn 2245f148d6 fix: limit changelog link hover styling
Underlines only the hovered changelog link
Removes misleading hover state from changelog sections
2026-05-19 14:51:15 +03:00
Bohdan Triapitsyn 3ac697adc7 fix: remove duplicate Zhipu usage provider
Keeps one Zhipu AI Coding Plan entry in usage settings
Preserves existing Zhipu aliases and config lookup
Removes duplicate backend quota registration
2026-05-19 14:49:03 +03:00
Bohdan Triapitsyn 0f015a495b fix: constrain oversized loading spinners (#1326)
Prevents loading icons from rendering too large
Adds explicit sizing to file and diff loading states
2026-05-19 14:33:42 +03:00
Bohdan Triapitsyn fd81c23414 fix: prevent duplicate desktop notifications
Desktop shells no longer subscribe to the browser notification stream
Electron keeps using the native desktop notification path only
Web browser notifications continue to use the notification stream
2026-05-19 14:32:07 +03:00
Bohdan Triapitsyn 237558130e fix: render multi-file tool diffs safely
Prevents chat crashes from multi-file apply_patch diffs
Splits aggregate patches before rendering each file diff
2026-05-19 14:24:05 +03:00
Bohdan Triapitsyn e0a194eed0 fix: improve favicon contrast in chat links
Adds a compact themed badge behind link favicons
Prevents favicon badge borders from clipping
Keeps external link icons readable across themes
2026-05-19 14:01:41 +03:00
Tom Rochette 25b328dcb8 Fix notification button text color in dark mode (#1324) 2026-05-19 13:26:04 +03:00
Bohdan Triapitsyn 87d13cf61b fix: enable web runtime notifications without push (#1322)
Web notifications now listen to the notification stream directly
Native notifications no longer depend on PWA push being enabled
Window focus is respected when deciding whether to send background push notifications
2026-05-19 13:16:47 +03:00
Bohdan Triapitsyn f40110698f fix: preserve markdown when saving notes
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.
2026-05-19 02:07:07 +03:00
Bohdan Triapitsyn 174fa4e96d chore: retire zen-backed summarization
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.
2026-05-19 02:06:52 +03:00
Bohdan Triapitsyn a57b02a308 fix: restore vscode native notification behavior
Move VS Code/Cursor desktop notifications onto the webview Notification API instead of the extension-host watcher path, which could not reliably produce native OS notifications.

Route OpenCode runtime events from the shared sync pipeline into the VS Code webview so completion, error, question, and permission notifications use the same live event stream as the UI.

Respect the OpenChamber notification settings in VS Code, including template rendering, completion cooldowns, permission auto-accept suppression, and the notify-while-focused mode.

Use VS Code's window focus signal from the extension host instead of document.hasFocus() inside the webview, so hidden-only notifications are suppressed while Cursor or VS Code is focused across platforms.
2026-05-19 02:06:32 +03:00
Bohdan Triapitsyn d928185640 fix: make opencode health checks resilient
Avoids restarting OpenCode after transient health probe failures
Coalesces concurrent health checks and briefly caches probe results
Adds configurable health timeout, retry threshold, interval, and cache settings
2026-05-18 21:17:02 +03:00
Bohdan Triapitsyn eb3c78e224 feat: show favicons for external chat links
Adds DuckDuckGo favicon lookup for external URLs
Shows favicons in markdown and fetch tool link rows
Hides missing icons automatically
2026-05-18 19:25:10 +03:00