C.UTF-8 does not exist on macOS, causing the terminal to fall back
to ASCII encoding when LANG is unset. Use en_US.UTF-8 on macOS and
C.UTF-8 on Linux. Also set LC_CTYPE with the platform-appropriate
value (UTF-8 on macOS, C.UTF-8 on Linux) for additional safety.
Subagent completion notifications respect notification settings
Permission auto-accept now suppresses notifications for known child sessions
Server notification checks use OpenCode session parent semantics
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
* fix: add concurrency controls for multiple sessions using the same provider
Adds OS-inspired scheduling primitives (from HiveMind/AIMD research) to prevent
concurrent sessions from the same provider from experiencing slowdowns, random
stops, and cascading failures.
Server-side:
- Health check skips OpenCode restart when sessions are actively busy — a busy
server under concurrent load can fail the health check timeout without being
dead. Staleness guard forces restart if unhealthy+busy persists >2 minutes.
- Upstream SSE stall timeout scaled from 20s to 60s to avoid unnecessary
reconnections when multiple sessions are waiting for LLM responses.
Client-side (HiveMind primitives, arXiv:2604.17111):
- Transparent retry with exponential backoff (1s→2s→4s, max 32s) for
429/502/503/504 errors — the #1 most effective primitive from the paper.
- Circuit breaker: opens after 3 consecutive retryable errors, cooldown
doubles each trip (30s→60s→120s, capped 128s), matching TCP AIMD.
- Per-provider session tracking with TTL eviction (1h idle sweep).
- Fetch-level retry gated on AbortError/TypeError only (not DNS failures).
Refs github-code-review skill findings (all 8 issues resolved).
* fix: use definite assignment assertion for response variable
Fixes TS2454: Variable 'response' is used before being assigned
in strict mode. The for-loop body always assigns it on every path
that reaches the post-loop code, but TS can't prove that.
* fix: add cleanupSession to error paths and remove unreachable code
P1 fixes (Greptile review):
- cleanupSession called on fetch error throw path
- cleanupSession called on non-retryable HTTP error throw path
- Removed unreachable post-loop code (loop always terminates via return or throw)
Adds explicit post-loop throw to satisfy TypeScript strict return check.
* fix: address Greptile review feedback on concurrent session controls
Removes client-side session tracking that leaked on normal completion paths.
The session tracking was redundant — the server-side health check already reads from
sessionRuntime.getSessionActivitySnapshot() for busy-session detection.
Changes:
- Remove activeSessions Set and all session-tracking functions from provider-tracker
- Remove trackSessionStarted/cleanupSession calls from client.ts
- Remove unreachable (response as Response) block after retry loop
- Make upstreamStallTimeoutMs conditional: 60s when >1 sessions, 20s otherwise
Refs #1069
* fix: enforce dynamic concurrency safeguards
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* fix(server): increase WS buffer/replay limits and add backpressure warning
During long-running agent sessions (e.g. ultrawork loops with many tool
calls), the browser WebSocket client can briefly fall behind the server.
When the outbound buffer exceeds the limit, the server force-disconnects
with close code 1013, and the small replay buffer (512 events) is
insufficient to recover all missed events — leaving the UI permanently
stalled.
Changes:
- Raise MESSAGE_STREAM_WS_MAX_BUFFERED_BYTES from 4 MB to 16 MB to
tolerate larger bursts without disconnecting
- Add MESSAGE_STREAM_WS_BACKPRESSURE_WARN_BYTES (12 MB) threshold that
sends a one-shot "backpressure" frame to the client before the hard
disconnect, giving it a chance to shed low-priority updates
- Raise MESSAGE_STREAM_GLOBAL_REPLAY_LIMIT from 512 to 2048 so more
events survive brief reconnection gaps
- Add tests for the backpressure warning behavior (emit, dedup, reset)
* fix(ui): batch event flushes under backpressure
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* fix: cross-verify update API claims against npm registry
* Update packages/web/server/lib/package-manager.js
Signed-off-by: Islam Nofl <islamnofl.official@gmail.com>
* fix: show live server version in AboutDialog instead of stale build-time constant
* fix: add comment to empty catch block to satisfy lint no-empty rule
* fix: preserve live about dialog version in electron
* fix: scope update checks by runtime
---------
Signed-off-by: Islam Nofl <islamnofl.official@gmail.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* 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>
* Add design spec: OpenCode readiness loading indicator
* Add implementation plan: OpenCode readiness loading indicator
* feat: add useOpenCodeReadiness hook
* feat: add i18n keys for common.loading
* feat: add loading state to ModelSelector
* feat: add loading state to AgentSelector
* feat: add loading state to ModelControls chat selectors
* update package-lock
* feat(github): add shared fork detection utility
* feat(github): make issue listing fork-aware
* feat(github): make PR listing fork-aware
* feat(types): add sourceRepo to issue/PR summary types
* feat(ui): add source badges to GitHub integration dialog
* feat(ui): add source badges to issue/PR picker dialogs
* feat(github): pass headRemote in PR creation for fork support
* feat(ui): add source→target label in PR tab for fork workflows
* fix(github): allow PR section on base branch when upstream remote exists
* fix(github): show PR section on any branch including main for fork→upstream PRs
* fix(github): allow PullRequestSection to render on base branch when upstream remote exists
* feat(github): auto-detect upstream repo for fork→upstream PR creation
- Add GET /api/github/repo/upstream endpoint to discover fork's upstream
- Fix PullRequestSection canShow to allow PR creation on base branch when repo is a fork
- Add virtual upstream target in remote dropdown (no explicit upstream remote needed)
- Add targetRepo parameter to /api/github/pr/create for direct upstream targeting
- Add repoUpstream() API client method and GitHubRepoUpstreamResult type
* feat(github): auto-detect upstream repo for fork→upstream PR creation
- Add GET /api/github/repo/upstream endpoint to discover fork's upstream
- Fix PullRequestSection canShow to allow PR creation on base branch when repo is a fork
- Add virtual upstream target in remote dropdown (no explicit upstream remote needed)
- Add targetRepo parameter to /api/github/pr/create for direct upstream targeting
- Add repoUpstream() API client method and GitHubRepoUpstreamResult type
* fix: complete fork→upstream PR workflow
- Server: return defaultBranch from /api/github/repo/upstream endpoint
- Server: fix cross-repo head ref construction (compare repos, not remote names)
- Server: filterActiveRemoteBranches checks all remotes, not just origin
- UI: set targetBaseBranch to upstream's default branch when using detected upstream
- UI: include all remote branches in base branch dropdown when using detected upstream
- UI: skip base===head check for cross-repo PRs (same branch name on different repos is valid)
- Types: add defaultBranch to GitHubRepoUpstreamResult
* chore: delete superpowers folder
* feat: add (local)/(remote) labels to PR branch display and adapt Repository button to selected remote
* feat: Repository button adapts to selected remote (upstream vs origin)
* fix: complete fork→upstream PR feature gaps
Server:
- Extend /api/github/repo/upstream to return defaultBranchSha and remoteName
- Reuse headRepo result instead of redundant resolveGitHubRepoFromDirectory call
- Return clear error when headRepo is null (invalid GitHub URL)
UI:
- Add upstream's default branch to availableBaseBranches when using detected upstream
- Use upstream's default branch SHA in git log for generate description (fixes 'No commits found in range main...main')
- Show qualified names (owner/repo · branch) in base branch dropdown when using detected upstream
Types:
- Add defaultBranchSha and remoteName to GitHubRepoUpstreamResult
* fix: move detectedUpstream state before availableBaseBranches to fix temporal dead zone
* fix: fetch upstream branches from GitHub API for base branch dropdown
- Add GET /api/github/repo/branches endpoint to fetch branches via Octokit
- Add repoBranches() to GitHub API client and interface
- Fetch upstream branches on detection and store in upstreamBranches state
- Include upstreamBranches in availableBaseBranches when using detected upstream
- Re-add availableBaseBranches memo and auto-correction effect that were lost
- Remove unnecessary qualified names from dropdown (upstream is already selected)
* fix: restore prStatusKey and statusEntry declarations lost during refactor
* fix: cleanly re-apply all fork→upstream PR UI changes
Restored PullRequestSection.tsx from clean base and re-applied:
- Expand detectedUpstream type with defaultBranch, defaultBranchSha, remoteName
- Add upstreamBranches state and fetch on upstream detection
- Include upstream branches in availableBaseBranches when using detected upstream
- Use upstream default branch SHA in generate description (fixes 'No commits found')
- Adapt Repository button URL to selected remote
- Add (local)/(remote)/(upstream) labels to branch display
* fix: move detectedUpstream/upstreamBranches before availableBaseBranches to fix TDZ
* style: add pill badge styling to upstream repo source labels
* fix: don't cache error PR status responses, allow force-bypass of server cache
* fix: resolve PR status cache bugs, stale directory fallback, and upstream re-detection
* fix: keep collapse button visible when scrolling long user messages
- Collapse button now sticks to top of scrollable user message content instead of scrolling away
* fix: checkbox focus ring blends into sidebar background
* fix: polish fork PR follow-ups
* fix: remove user message collapse artifact
* fix: tighten fork PR internals
* fix: check all remotes for fork PR status
* fix: recover sidebar PR status misses
---------
Signed-off-by: Islam Nofl <islamnofl.official@gmail.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>