Add a side-card preference 'browserAllowedLoopback' (comma-separated
host or host:port entries) that lets the sidebar browser navigate to
explicitly trusted loopback addresses. Bare hosts (localhost,
127.0.0.1) match every port; host:port entries match exactly.
Allowlisted local addresses additionally get the 'allow-same-origin'
sandbox token in the iframe: local dev servers (Vite etc.) need a real
origin for their module/HMR/fetch pipeline and would otherwise render
blank in the opaque-origin sandbox. The page stays cross-origin to the
GUI and to every other site.
The server-side browser.probe route mirrors the same allowlist so
probed local servers are not rejected as 'local addresses are not
probed'.
Terminal tabs resolved the shell from the dsh process environment only,
falling back to a hardcoded /bin/bash — service-managed launches without
SHELL therefore ignored the account's login shell (e.g. zsh). They also
spawned with an empty argv, so even a resolved zsh ran as a non-login
shell and skipped ~/.zprofile.
defaultShell() now falls back to the account's login shell (passwd) after
$SHELL, and both registries spawn POSIX shells with -l so the tab behaves
like a terminal emulator (loads ~/.profile / ~/.zprofile). Windows keeps
powershell.exe with no login flag.
Fixesomdsh-dev/DSH-better-sidebar#68
Some servers (e.g. aliyun consoles) answer HEAD without the
X-Frame-Options / Content-Security-Policy headers that only their
GET response carries. The embeddability probe then wrongly reported
the site as embeddable, leaving the plain iframe to surface the
browser's misleading "refused to connect" error (the site actually
forbids framing via frame-ancestors).
Retry once as GET when both embed signals are absent (the body is
discarded — only headers matter), mirroring the existing 405/501
HEAD fallback. The client then shows the friendly embed-refusal
panel with an "open in browser" action instead of the misleading
connection error.
Two failure modes of a sidebar render crash, fixed together:
1. Layout-push leak (root cause): the layout-push effect wrote
--dsh-sidebar-width/--dsh-sidebar-height on document.documentElement
without a cleanup, so ANY unmount of the Sidebar (error-boundary swap,
plugin disable, HMR) left the variables behind and layout.css kept
squeezing #root with a stale margin — "the sidebar cannot be hidden"
until a full reload. The effect now removes both properties on cleanup
(the CSS fallback 0px restores the layout).
2. Crash containment (UX): the root error boundary previously replaced the
WHOLE sidebar — toggle cluster included — with an error strip on any tab
crash. A new shared RenderBoundary (src/client/RenderBoundary.tsx) now
scopes containment per tab: a crashing viewer/editor shows a dismissible
strip inside its own pane while the toggle cluster, the other tabs, and
the panel stay alive. The descriptor is rendered as a real element
(createElement) so even top-level component throws land in the boundary,
not in TabContent's own render. The root boundary remains as the last
resort for Workbench/shell errors.
Tests (tests/sidebar-crash.spec.tsx, jsdom + real Sidebar/store harness):
- unmount clears both CSS variables (red before the fix: 307px leaked)
- a crashing tab is contained: strip in-pane, collapse button alive,
layout push still live
- the retry button recovers a tab whose crash has since been fixed
Full suite: 425 tests pass; tsc --noEmit clean.
node-pty@1.1.0 builds the spawn-helper executable only for OS=="mac"
(binding.gyp); linux uses forkpty directly and ships no helper at all.
The test's non-Windows premise was wrong for linux, and no candidate
exists there to assert on.
- checkout with fetch-depth: 0: the git log paging test needs the full
repository history (default shallow clone yields one commit)
- configure a global git identity on the runner: src/git.ts deliberately
never sets one and revert/cherry-pick rely on ambient config
- tests/unit.spec.ts: node-pty@1.1.0 ships a prebuilt spawn-helper only for
darwin/win32; on linux node-gyp compiles it into build/Release. Align the
assertion with ensureSpawnHelper's candidate list instead of hardcoding
the prebuilds/ path (the Linux test run was red for this reason)
The panel width lived in the per-session state (dsh-sidebar:v1:<id>), so a
drag in one conversation never carried to another: switching conversations
snapped the panel back to that session's own width. The width is a layout
preference, not session content, so it now persists under a cross-session
key (dsh-sidebar:v1:width):
- every persist writes the current width to the global key;
- loadState prefers the global width over a session's persisted one;
- a cache-hit session switch adopts the global width.
Backward compatible: with no global key present (first run / older data)
the behavior is unchanged. Adds a regression test covering drag-in-A ->
switch-to-B and drag-in-B -> switch-back-to-A.