* feat(injection): 统一面板宿主——固定含块层 + 挂载自检降级 + body 锚点守卫 - Sidebar 渲染根包 [data-dsh-panel-host](fixed inset-0 pointer-events:none) - 面板/开关簇由 fixed 改 absolute(层内视口坐标等价),免疫套壳中间层 transform 劫持 - 挂载后一次性几何自检:页面级 transform 时降级 absolute + rAF 视口同步 - MutationObserver(body childList)守卫锚点被宿主清空时重挂 * perf(injection): 几何写路径统一为 writeGeometry + 面板 layout 隔离 - 拖拽帧与打开态共用单一推挤写入器(--dsh-sidebar-width/height) - .panel/.bottomPanel contain: layout style——内部重排不外泄 - 拖拽期(body[data-dsh-sidebar-dragging])才挂 will-change: transform * perf(chunks): HMR 激活保留未变 chunk 的已解析 exports + ETag HEAD 重验证 - 新增 revalidateChunksOnReactivate():激活时 HEAD 每个已加载 chunk 对比 ETag, 未变保留内存缓存(跳过重注入/重执行),变更或不可达则 fail-open 重取 - 测试夹具与孤儿缓存条目不跨激活存活 - index.tsx 激活路径由 resetChunks() 改为 revalidateChunksOnReactivate() * fix(layout): 推挤锚点改 data 属性 + #root calc 宽度防桌面壳溢出 - nth-child(2) → #root [data-dsh-frame] > [data-pane="conversation"](实证同元素) - #root 宽度 calc(100% - var) 与 margin 同步过渡:web 视觉不变(实测 1140+300=1440 无溢出), Desktop 壳(#208)width:100% 的加性溢出根因消除 * feat(desktop): 桌面信号自动探测 + win32 顶栏 overlay 自动避让 + 键盘/safe-area 适配 - 新增 desktop-env.ts:解析 dsh-desktop-mode/platform URL 信号与 preload 标记 - win32 advanced 壳自动启用 titleBarCompat(32px overlay),手动 pref 仍可覆盖 - visualViewport 键盘 inset:底部面板/窄屏抽屉键盘弹起时上移 - 面板与开关簇 safe-area-inset 适配(env() 桌面端为 0) - 单测 7 例(含 URLSearchParams 前导 ? 剥除修复) * docs+e2e: 注入方案实施记录(路线B关闭、偏差记录、基线数据)+ 契约同步 + e2e 新断言 - 设计文档:路线 B 标记关闭、§8.1 改单 PR 步骤(含 commit 对照)、拖拽基线数据、实施偏差记录 - AGENTS.md §8:data-dsh-panel-host 含块层、推挤锚点契约(禁 nth-child)、桌面信号 - mount.e2e:data-dsh-panel-host 断言 + win32 advanced 桌面信号场景 * fix(cr): 响应 #232 CR 三条 findings - P1 降级同步:按未修正几何判定(跟踪自身补偿量),祖先 transform 消失才退出循环—— 修正后矩形不再被误判为无需修正(自清除缺陷) - P1 chunk 重验证成为 loadChunk 屏障:重验证挂起期间不提供缓存,杜绝 HMR 竞态陈旧 exports; 测试夹具加载不再被误记为生产加载 - P2 键盘 inset:innerHeight - (vv.height + vv.offsetTop),并监听 scroll(offsetTop 变化) - 新增屏障单测 1 例;设计文档偏差记录更新 * fix(chunks): 屏障 HEAD 加超时兜底 + resetChunks 清 revalidation - revalidateChunksOnReactivate 的 HEAD 与 recordEtag 均带 AbortSignal.timeout(5s):路由挂起时 fail-open(drop + 重取), 屏障不再可能无限期阻塞所有懒加载 chunk(CR #232 P1 修复的健壮性缺口) - resetChunks 同步清 revalidation:重验证挂起期间重置后, loadChunk 不再等待已丢弃状态的孤儿任务(finally 身份判断 no-op) - 单测 +2:HEAD 挂起超时 fail-open(fake AbortSignal.timeout 触发中止)、 resetChunks 清屏障后 loadChunk 立即放行 * fix(deps): align @deepseek-ai/* peers with DSH 0.1.0-rc.8 - peer/devDependencies: 13 个 @deepseek-ai/* 从 ^0.1.0-rc.7 升至 ^0.1.0-rc.8;删除随 rc.8 消失的 dsh-client-web-react / dsh-client-schema-form (无 rc.8 发布、rc.8 依赖树与壳 bundle 零引用、插件 src 零引用); cordis peer/devDep 同步升 ^4.0.0-rc.8 - 版本 0.13.1 -> 0.14.0(package.json / dsh.plugin.json / SIDEBAR_SERVICE_VERSION 三处同步) - CHUNK_EXTERNALS / CLIENT_EXTERNALS / CLIENT_REQUIRE_ALLOWED 三处镜像 同步删除两个死包(primitives/slots 仍是 rc.8 壳静态模块表种子,保留) - CI 挂载冒烟钉版 @deepseek-ai/dsh@0.1.0-rc.7 -> rc.8 - pnpm clean --lockfile 全量重解析:lockfile 内 @deepseek-ai/* rc.7 残留 清零(传递链同升 rc.8,杜绝 #206 式混用树);pnpm-workspace.yaml minimumReleaseAgeExclude 按 #207 模式整体换为 rc.8 列表 - 文档同步:README 安装说明、AGENTS.md CI 钉版、外部插件指南与设计文档 cordis 示例、issue 模板版本示例 * feat(prefs): editorExplorer 默认独立(关)——文件各自新开 tab - SIDEBAR_PREFS_DEFAULTS 与 host PrefsSchema 的 editorExplorer 默认 true -> false:新会话树点击/打开文件按 path 新开 tab,无路径窗口即 纯资源管理器;合并模式保留为可选手动开启(持久化过的用户设置不受影响) - 测试同步:prefs.spec 默认断言翻转、plugin-shape.spec 与 smoke.spec 默认对象翻转;editor-host 合并模式用例显式开启 editorExplorer(split 用例本已显式);side-card-section-rows 的 select 行用例固定选中 Merged - e2e 重写:mount.e2e 文件打开流程从 in-place 断言改为独立模式 (新开 hello.txt tab、Files home tab 保留),文件头注释同步 - 契约文档同步:AGENTS.md §3.4 editor 行默认描述翻转 + CI 冒烟描述、 README/README_EN v0.13.0 特性描述 + v0.14.0 changelog * fix(client): rc.8 模块系统经 ctx.modules 注入 + chunk 副本全局共享 rc.8 不再暴露 window.__DSH_MODULES__ 页面全局(改由 ctx.modules 服务 提供),chunk 外部依赖解析全面失效(terminal/editor/mermaid 全部 "client module system unavailable")。修复: - src/client/index.tsx: inject 增加 'modules'(Cordis 服务访问守卫, 此前直接读 ctx.modules 抛 "cannot get property modules without inject");apply() 激活时 setChunkModuleSystem(ctx.modules) - package.json dsh.client.inject 增加 @deepseek-ai/dsh-client-modules - chunk-loader: 注入写插件自有页面全局 __dshSidebarModuleSystem__—— 懒加载 chunk bundle 各自内联一份 loader(rc.7 靠官方全局回退工作, rc.8 全局消失后副本注入变量恒空);moduleSystem() 按 注入变量 → 插件全局 → rc.7 全局回退解析 - context-types: Context 镜像补 modules 服务声明(client half) - e2e: assertNoCrash 失败时输出错误条文本;独立模式断言修正 (Files 数量按存在性、mermaid 流程先切回 Files、md 预览 locator 去掉 重复的 [data-dsh-better-sidebar] 嵌套) 验证:typecheck / 639 测试全绿;本地 rc.8 CLI + Chromium 挂载冒烟 3/3 通过(drag-layout、mount 深扫含 editor/mermaid chunk、桌面信号) * feat(settings): 终端 shell/shellArgs 可在设置页配置(bash 管理) - SidebarPrefs 新增 terminalShell / terminalShellArgs(默认空 = 保持 yaml config.shell → $SHELL / 登录 shell / powershell.exe 的既有解析) - 终端卡齿轮二级页面新增两行 text 配置(与字体行同列) - host 侧生效链路:UI 终端 WS 打开与 agent terminal_create 均读取 设置文档覆盖(ptyManager.open / AgentPtyRegistry.create 增加可选 shell 覆盖参数;shellOverridesOf 解析设置文档);设置页写入即时 影响之后打开的终端(既有 pty 保持原 shell) - locales zh/en 文案;parsePrefs 校验新字段;测试同步 * feat(settings): 侧边卡片设置页加 DSH-better-sidebar 版本徽标 - 设置页 intro 下新增身份徽标:名称 + v{service.version}(服务实例 版本,与 package.json 由 tests/service.spec.ts 保持同步) - token 驱动样式(--dsw-alias-*),名称/版本 pill 布局 * fix(drag): 快速拖动提交最后位置 + HMR 后中心列重定位兜底 快速释放(浏览器合并/丢失 pointermove 突发,超快速 flick 甚至可能 完全无 move)时的回退问题: - pointerup 优先采用最后一次已知拖动值(rAF pending),而非 up 位置 (事件合并时可能等于按下位置) - pointercancel / lostpointercapture 中断时同样提交最后已知位置; 无 move 时用中断事件自身的坐标计算(clamp 后提交)——只有真正 未产生位移的拖动才回滚 - commitDrag 统一 flush + 同值提交 + 立即重测中心列(消除提交后 React 用旧 centerRect 覆盖底栏 right 的中间帧) HMR 重激活后底栏空白(输入框被推挤上移、强制刷新恢复): - 根因:新组件实例重跑 locate 时壳的 centerCol 尚未就绪,而壳重建 复用 #root 子节点(childList 观察器不触发)→ centerRect 卡 {0,0} → 底栏 visibility:hidden 永久空白 - 修复:额外观察 <html> 的 style 属性(layout push 写回 --dsh-sidebar-* 时重定位重测);底栏打开时 effect 重跑 locate/measure 兜底 - 底栏未测量时由「不渲染」改为 visibility:hidden(渲染链不被几何 门控,jsdom 测试不回归) e2e 新增:极快拖动(单 move 立即 up)提交拖动位置、稳定后不回退 * feat(plugins): 添加插件目录支持搜索/分组/独立滚动(多插件场景) - PluginListBody 顶部加实时搜索框(按名称/id/描述过滤,空结果提示) - PluginEntry 增加可选 category 分组字段(i18n 友好),目录条目按组 渲染(未分类条目保持平铺);数量徽标跟随过滤结果 - 条目列表 max-height + overflow-y 独立滚动,插件多时弹窗不再无限 增长;渲染数量由搜索天然收敛 - locales zh/en(搜索占位、无匹配);测试文件固定英文环境 (vitest 4.1.11+ jsdom 跟随系统 locale,本机 zh-CN 导致英文文案 断言漂移) * chore(deps): 适配 pnpm 11.8 supply-chain 校验(exclude 通配) pnpm 11.8.0 起对 lockfile 既有条目强制 minimumReleaseAge 校验, 且精确 exclude(@scope/pkg@version)对带 peer 依赖后缀的解析条目 匹配失效(44 条误报违规,CI 全红)。@deepseek-ai/* scope 为官方 可信 scope,minimumReleaseAgeExclude 改为 '@deepseek-ai/*' 通配 (保留 rc.1 历史与 stable 条目);通配经实测通过全部 504 条校验。 * docs: v0.14.0 changelog 补全(自 v0.13.1 全部更改 + 特别声明 rc.8 适配) 新增条目:终端 shell/shellArgs 设置页配置、设置页版本徽标、 添加插件目录搜索/分组/滚动、rc.8 模块系统迁移、拖拽健壮性修复; 版本说明块醒目声明本版适配 DSH 0.1.0-rc.8(rc.7 及更早无法解析依赖)
dsh-better-sidebar
A dual workbench (right sidebar + bottom panel) that opens its
ctx.betterSidebar service to every plugin —register new sidebar pages and file viewers via
registerTab / registerFileViewer.
✨ Features
- 🗂️ File Workbench: file explorer (lazy-loading tree; symlinks show their target kind — directory links expand, dangling links flagged) + CodeMirror editor; inline preview for images / Markdown (incl. Mermaid diagrams, strict-mode safe rendering + click-to-zoom) / HTML / PDF / Office
- 🌐 Embedded Browser: multiple web tabs with back / forward / refresh; content runs in a sandboxed iframe; external links are routed by protocol by default — HTTP opens in the sidebar, HTTPS goes to the system browser (both adjustable in settings)
- 💻 Real Terminal: xterm.js + node-pty real shell, reconnect with transcript replay; optionally injects
terminal_*tools for the model - 🌿 Git Panel: real diff + VSCode-style diff tabs, history, right-click to stage / commit / revert
- 🧩 Background Tasks: agent topology + background tasks (exit codes / live output / force-kill)
- 🪟 Dual Workbench: right sidebar + bottom panel; drag tabs to split / merge panes (cross-panel), mobile auto-merges into a full-width drawer
- 🔁 Session Isolation: layout / tabs / panels persisted per session, stale state auto-purged
- ⚙️ Declarative Settings: per-item toggles in the "Side Cards" settings section, secondary settings via the gear dialog
- ⚡ On-demand Loading: only ~325KB core at startup; heavy deps (terminal / editor / mermaid diagrams) load on demand (design)
- 🌏 i18n: UI text follows DSH's language (zh / en) with live switching
🔌 Core principle: service-first — the 7 built-in tabs + 6 viewers register through the same
ctx.betterSidebarAPI as third-party plugins, with fully equal capabilities; anything the ecosystem can provide better is delegated to ecosystem plugins. See the "🔌 Service" section below and the external plugin guide.
🆕 Recent Updates
v0.14.0
⚠️ This release adapts to DSH 0.1.0-rc.8: every
@deepseek-ai/*peer/devDependency is raised to^0.1.0-rc.8(transitives included — zero rc.7 leftovers in the lockfile),cordisto^4.0.0-rc.8, and the CI mount lane pins@deepseek-ai/dsh@0.1.0-rc.8. DSH environments on rc.7 or earlier can no longer resolve this release's dependencies — upgrade DSH first. All changes since v0.13.1:
✨ New features
- 🖼️ Unified panel-host injection refactor (#232): panels/toggle clusters moved into a
[data-dsh-panel-host]fixed containing block (fixed inset-0 z-40), immune to desktop-shell intermediate transforms hijackingfixed; mount self-check (page-level transform →data-dsh-panel-host-degradeddegraded sync, judged on uncorrected geometry, exits only when the ancestor transform is gone); push anchor switched to#root [data-dsh-frame] > [data-pane="conversation"]+#rootcalc width against desktop-shell additive overflow; chunk revalidation on activation (HEAD+ETag keeps unchanged chunks, 5s timeout fails open); desktop signal auto-detection (win32 advanced title-bar compat 32px avoidance, manual pref overrides);visualViewportkeyboard inset +env(safe-area-inset-*)mobile adaptation - 📂 Separate file windows by default (#232):
editorExplorernow defaults to separate — tree clicks / file opens create a new tab per path and the path-less window is a pure file manager; merged mode stays available as an opt-in - 🖥️ Terminal shell / shellArgs configurable from the settings page (#232): the terminal card's gear popup gains "Shell path" and "Shell arguments" rows (previously yaml-only via
cordis.patch.yml) — saved values take effect immediately for terminals opened afterwards (UI terminals and modelterminal_createalike); empty keeps the existing yaml →$SHELL/ login shell /powershell.exeresolution order - 🏷️ Version badge on the settings page (#232): the side-card settings section now opens with a
DSH-better-sidebar v0.14.0identity badge (version synced with the service instance, test-guarded) - 🔍 Add-plugin catalog: search / grouping / independent scroll (#232): built for a growing plugin ecosystem — a live search box (filters by name / id / description), optional
categorygrouping for entries, and an independently scrolling list (the modal no longer grows unbounded with catalog size)
🐛 Fixes
- 🔧 Adapted to DSH 0.1.0-rc.8 (#232): all 13
@deepseek-ai/*peer/devDependencies raised to^0.1.0-rc.8(transitives included; zero rc.7 leftovers in the lockfile),cordisto^4.0.0-rc.8;dsh-client-web-react/dsh-client-schema-formremoved (no rc.8 publish, no longer in the shell module table, zero plugin references); CI mount lane pins@deepseek-ai/dsh@0.1.0-rc.8; pnpm 11.8 supply-chain verification adapted - 🧩 rc.8 module-system migration (#232): rc.8 no longer exposes the
window.__DSH_MODULES__page global (it moved to thectx.modulesservice), which broke every lazy chunk's externals resolution — the client now injects themodulesservice and shares it with chunk-bundle copies through a plugin-owned global (terminal / editor / Mermaid on-demand loading restored) - 🧩 Chunk revalidation barrier hardening (#232): HEAD revalidation gains a 5s timeout (fails open on a stuck route so the barrier can never wedge lazy loads);
resetChunksclears a pending revalidation barrier - 🖱️ Drag robustness (#232): fast releases (browsers merge/lose pointermove bursts) commit the last known dragged position instead of rolling back;
pointercancel/ lost-capture interruptions keep the drag result too; the center column is re-measured right after commit (no mid-frame bottom-panel width jump); HMR re-activation re-locates the center column via an<html>style observer plus a retry when the bottom panel opens (fixes the blank bottom panel / shifted input bar after a hot reload)
v0.13.1### v0.13.1
✨ New features
- 📊 Safe Mermaid rendering in the Markdown preview (#164): when a previewed md file contains mermaid fences, a
client-mermaid.jschunk (~7MB) is served on demand (zero load without mermaid); defense-in-depth rendering —securityLevel: 'strict'+htmlLabels: false(node labels use real SVG<text>) + a second sanitize pass before SVG injection (foreignObject/script/foreign HTML elements removed,@*/on*/hrefattributes stripped); click a diagram to zoom in a modal overlay (wheel zoom centered on the cursor, drag pan, toolbar & shortcuts), re-renders with light/dark theme, falls back to the raw code block on parse failure - 🖥️ Configurable terminal shell & shellArgs (#125):
cordis.patch.ymlbetter-sidebar.configcan setshell/shellArgs(a non-emptyshellArgsfully replaces the defaults; unset keeps the previous auto-resolution of$SHELL/ login shell /powershell.exe), applied to both UI terminals and agent terminals (terminal_create); terminal tab titles now show the shell name (bash/zsh/powershell) and internal tab ids use UUIDs so the same shell can open multiple terminals
🐛 Fixes
- 🔗 Aggregate double-mount auto-yield (#200): when an aggregate package (e.g. dsh-web-ui-all) mounts the same package under its own entry id, the guard expression in
cordis.patch.ymldisables the plugin's ownbetter-sidebarrow so/sidebar/apiis no longer registered twice (duplicate prefix routecrashing the whole plugin tree /dsh web); standalone installs behave as before - 🔧 Peer dependencies aligned to DSH 0.1.0-rc.7 (#207, fixes #206): all
@deepseek-ai/*peer/devDependencies raised from^0.1.0-rc.6to^0.1.0-rc.7, and the CI mount lane pins the same version — eliminating the mixed rc.6/rc.7 dependency tree (after the main framework moved to rc.7) that surfaced asagent-presets: refusing to compose an unscoped contextwhen picking a model / sending a message
v0.13.0
✨ New features
- 📁 Files window merged with the explorer (#151): new
editorExplorersetting (editor card gear) — file tabs gain a path-input header plus a toggleable right-docked file tree (per-tab open/width memory, drag-resize 160–480px from the left edge, global filename search via the hostfs.searchroute with a hard budget, skipping.gitand symlink dirs); in separate mode (default) tree clicks / Enter in the path input open each file in its own new tab, merged mode switches the current tab in place; fresh sessions seed an empty Files window instead of the explorer tab, and a path-less window is a bare file manager in separate mode / a chrome'd empty file window in merged mode; the tree context menu offers "Open in new tab" and "Open to the side" (split) - 🎛️ Select rows for declarative settings (#151): settings rows gain
type: 'select'(optionswith value/title/desc/icon,multistores the picked values as an array); options with icons render big-icon option cards and keep the icon in the closed anchor;editorExplorerbecame an iconed select (merged vs separate); the capability list gainedsettingSelect - 🔀 Mutual exclusion with the dsh-web-ui family right panel (#181): reads the
aionui-panelsettings namespace's provider choice — when "Use aionui-panel" is selected, the whole better-sidebar (right sidebar / bottom panel / floating entry / all takeovers) does not mount; with DSH-better-sidebar (or no aionui installed) it behaves as before. Takes effect live after a settings save (settings-document push), no reload needed
📝 Other
- Install / update commands unified to
dsh-better-sidebar@latest(bilingual README sync)
v0.12.3
✨ New features
- 🎨 Skin compatibility (token-driven): fully consumes DSH design tokens and follows the dsh-web-ui skin center's 10 skins automatically; terminal/editor surfaces fall back to opaque backgrounds under transparent/translucent-glass token values so text never scrolls over the skin art (#110, fixes #106 #105 #90 #60, also #52 #57 #92)
- 🗂️ Unified path handling: UNC / symlink classification (directory symlinks expandable, broken links highlighted) + HTML-route platform guards (#134, #65 #67 #43 #79 #115)
- 🖥️ Configurable terminal shell: custom shell setting with Windows pwsh auto-probe (#95)
- 📝 Editor languages: C# / Kotlin / Swift syntax highlighting (#120)
- 🧭 Settings nav icon: settings-page navigation icon and layout polish (#114)
- ➕ Recommended-plugin catalog: added
dsh-git-remotes— Git Remotes tab (branches/upstream/ahead-behind, fetch with prune, ff-only pull, confirm-before-push; does not replace the built-in stage/commit tab) (#91); anddsh-video-preview— inline video preview (.mp4/.webm/.mov/.mkv/.avi etc.) backed by a /video host route with HTTP Range (206) scrubbing, not capped by the 20MB mediaLimit (#126)
🐛 Fixes
- 🔧 xterm migration: deprecated xterm dependency migrated to
@xterm/xterm(Closes #122, #128) - 📝 Markdown editor: selection-to-conversation popup restored (#24)
- 🐛 node-pty load failure no longer crashes the server (#140): the host half now lazy-loads node-pty — when it is missing the plugin still mounts, the terminal shows a repair banner (copyable command + Retry button), and agent terminal tools are skipped
- 🧪 Test engineering: unit spec split (#141) + flaky smoke cleanup fix
🚀 Engineering
- npm publishing wired to GitHub Releases (Trusted Publishing, provenance-attached tarballs); tagging a release publishes automatically (#148)
v0.12.2
- 📐 Position compat mode: new "Position compatibility mode" setting: reserves top space for the native Windows title bar (top-right) so the sidebar buttons and content sit below it (off by default); the shift distance is customizable in the gear popup (0–120px)
- 🔌 Service API base: complete type exports +
version/featurescapability detection, state subscription (getSnapshot/subscribeState), tabbadge,onOpen/onActivate/onCloselifecycle callbacks,updateTab/activateTab/openFile, targeted open,metapersisted across reloads, plugin-owned settings (pluginToggles/render), external-link claim (urlTarget) - ➕ Add Plugins: recommended plugin catalog in settings + one-click copy install command; built-in Office preview moved to the recommended plugin
- 🖱️ Tab-bar scroll: mouse-wheel horizontal scrolling on the tab bar
- 🐛 Fixes: remote access 403 (trust fence now uses
trustedHosts), sidebar crash #31, Windows HTML-preview drive-path
v0.12.1
- 🔌 Service API base: complete type exports +
version/featurescapability detection, state subscription (getSnapshot/subscribeState), tabbadge,onOpen/onActivate/onCloselifecycle callbacks,updateTab/activateTab/openFile, targeted open,metapersisted across reloads, plugin-owned settings (pluginToggles/render) - ➕ Add Plugins: recommended plugin catalog in settings + one-click copy install command; built-in Office preview moved to the recommended plugin
- 🖱️ Tab-bar scroll: mouse-wheel horizontal scrolling on the tab bar
- 🐛 Fixes: remote access 403 (trust fence now uses
trustedHosts), sidebar crash #31, Windows HTML-preview drive-path
📝 Note: the 0.12.0 final could not be reused (npm reported the version as already published), so the public release became 0.12.1 — both carry identical content.
v0.12.0
- 🔌 Service API base: complete type exports +
version/featurescapability detection, state subscription, tab badges, lifecycle callbacks, targeted open,metapersisted across reloads, plugin-owned settings - ➕ Add Plugins: recommended plugin catalog in settings + one-click copy install command; built-in Office preview moved to the recommended plugin
- 🖱️ Tab-bar scroll: mouse-wheel horizontal scrolling on the tab bar
- 🐛 Fixes: remote access 403 (trust fence now uses
trustedHosts), sidebar crash #31, Windows HTML-preview drive-path
🚀 Installation
Prerequisites: DSH installed (dsh web boots), Node.js ≥ 20, pnpm ≥ 10.
dsh plugin --profile web add dsh-better-sidebar@latest
Then hard-refresh the browser (Cmd/Ctrl+Shift+R) to see the sidebar (DSH hot-reloads client changes; only host-half updates need a restart).
Updating
dsh plugin --profile web add dsh-better-sidebar@latest
or bump the version in ~/.dsh/profiles/web/package.json (e.g. "^0.13.0") and run pnpm install. Then hard-refresh the browser (Cmd/Ctrl+Shift+R) — client changes do not need a DSH restart.
Troubleshooting
| Symptom | Cause & fix |
|---|---|
Ignored build scripts |
pnpm 11 blocked build scripts. Run pnpm approve-builds --all in the profile directory (~/.dsh/profiles/web). |
minimum release age / version < 24h |
The release is younger than 24 hours. Wait, or re-run once (pnpm auto-adds minimumReleaseAgeExclude). |
| "profile directory not found" | Run dsh web once so it initializes ~/.dsh/profiles/web. |
| Two sidebars on the page | Double-mount. Old hand-written line: ~/.dsh/profiles/web/cordis.patch.yml still has - insert: ... better-sidebar ... — delete it (a same-id duplicate mount makes the loader fail loudly with duplicate loader entry id). When an aggregate bundle (e.g. @linxin666/dsh-web-ui-all) mounts this package under a different id, the plugin's own bundle patch backs off automatically since 0.13.x (it detects an already-enabled mount of the same package name and does not mount itself) — no manual fix needed; if it still double-mounts, make sure the aggregate bundle precedes dsh-better-sidebar in dsh.profile.bundles. |
| Terminal fails on Windows | node-pty relies on prebuilt binaries; if none match your Node version, install a build toolchain (VS Build Tools). Mainstream Node versions are usually covered. |
| Terminal shows "node-pty failed to load" | The node-pty install is missing or broken (e.g. pnpm skipped its build script). The terminal banner shows a repair command — copy it into a terminal/cmd on the DSH machine and run it (in ~/.dsh/profiles/web: pnpm approve-builds --all && pnpm rebuild node-pty), then restart DSH and click Retry. The plugin and DSH core share the same node-pty@^1.1.0, so the repair restores both. |
dsh: command not found |
Install DSH first, or run npx -y --package @deepseek-ai/dsh dsh plugin --profile web add dsh-better-sidebar@latest. |
Install from source / develop (optional — alternative to the npm flow)
To debug local changes or track the dev branch, point the dependency at a local clone and build it yourself:
1. git clone https://github.com/omdsh-dev/DSH-better-sidebar.git ~/Code/DSH-better-sidebar
cd ~/Code/DSH-better-sidebar && pnpm install && pnpm build
2. In ~/.dsh/profiles/web/package.json dependencies write "dsh-better-sidebar": "link:<absolute path of the clone>"
3. Append this mount line to ~/.dsh/profiles/web/cordis.patch.yml (to pick the terminal shell, add `config.shell`; `config.shellArgs` starts it with explicit args — when non-empty they replace the default `-l`. When omitted the host resolves `$SHELL` / the login shell / powershell.exe):
- insert:
- id: better-sidebar
name: 'dsh-better-sidebar'
config:
shell: /bin/zsh
shellArgs:
- --noprofile
- --no-rc
4. Run pnpm install in ~/.dsh/profiles/web
5. Restart DSH and hard-refresh
Update: git pull && pnpm install && pnpm build → just hard-refresh the browser (client changes hot-reload; only host-half changes need a DSH restart). To switch back to the npm channel, restore "dsh-better-sidebar": "^0.13.0" and re-run pnpm install.
Install via plugin-registry (optional — use either this or the main flow)
Prerequisite: DSH with plugin-registry integrated (dsh registry available). Enabling both channels double-mounts (the Node half loads twice, the page gets two sidebars).
git clone https://github.com/omdsh-dev/DSH-better-sidebar.git && cd DSH-better-sidebar
pnpm install && pnpm build
node scripts/package-registry.mjs # assemble the registry/ staging (manifest + artifacts + README, not committed)
dsh registry install ./registry # install (disabled by default)
dsh registry enable dsh-external/dsh-better-sidebar
Update: git pull && pnpm install && pnpm build → node scripts/package-registry.mjs → dsh registry uninstall/install/enable. Remove the other channel's mount before switching.
⌨️ Keyboard Shortcuts
| Action | Keys |
|---|---|
| Save edits | Ctrl/Cmd + S |
| Git commit | Ctrl + Enter |
| Close tab | Middle mouse button |
| Split / merge panes | Drag tab to pane edge / middle |
| Reference file to input | Hover the @file button at end of line |
| Copy file path | Right-click row → copy relative/absolute path |
🔌 Service: register tabs & file viewers
Since v0.4.0 the plugin exposes the ctx.betterSidebar service — other plugins can register sidebar pages and file viewers (the 7 built-in tabs + 6 viewers register through the same service):
import type {} from 'dsh-better-sidebar' // triggers the ctx.betterSidebar type merge
export const inject = ['betterSidebar']
export function apply(ctx: Context) {
ctx.effect(() => ctx.betterSidebar.registerTab({
id: 'my-plugin:db', title: 'Database', component: ({ scope }) => <DbView sessionId={scope.sessionId} />,
}))
}
v0.12.1+ base capabilities (complete type exports, capability detection, state subscription, tab badge, lifecycle callbacks, targeted open, plugin-owned settings, etc.) — see the integration docs below.
Full integration docs:
AGENTS.md— the in-repo integration doc (full fields, matching algorithm, HMR pitfalls, declarative settings, version detection);docs/external-plugin-guide.md— the external-plugin guide (with a complete minimal example).
➕ Add Plugins (recommended plugin catalog)
The dashed cards at the end of the "Sidebar content" / "File viewers" grids in the "Side Cards" settings section open the Add tab plugins / Add preview plugins modals: each declares its open extension point, offers a "Browse more plugins on GitHub" button (the GitHub topic dsh-better-sidebar), and lists the recommended catalog (name / repo / description / install script) — "Open" jumps to the repo, "Copy" writes the install command to the clipboard.
Curating a new plugin: append a PluginEntry to src/client/plugins-tabs.ts (tab registrations) or src/client/plugins-viewers.ts (file-previewer registrations) and tag your repo with the dsh-better-sidebar topic; data integrity is guarded by tests/plugin-list.spec.ts.
🛠️ Development & Build
pnpm install # @deepseek-ai/* resolved from npm (^0.1.0-rc.8, published) — no token needed
pnpm typecheck # tsc --noEmit
pnpm build # → lib/index.js + lib/invariant.js + lib/client.js + lib/client-registry.js + lib/types
pnpm test # vitest (includes manifest consistency guard; build first)
pnpm watch # tsdown --watch
Architecture: a single npm package with host/client halves — host (src/index.ts): /sidebar/api/* JSON API, /sidebar/file media route, /sidebar/html preview route, /sidebar/ws/terminal WebSocket (fs / git / pty / preview, all session-scoped with a trust fence); client (src/client/index.tsx): portal sidebar + views + interception; state persisted per session in localStorage. Organized per DSH official conventions (no default export, dual client bundles); no dependency on npm / checkout at runtime (@deepseek-ai/* provided by the web profile).
🔐 Security
- Routes protected by a Host-header trust fence (same as
/api);fs.writeis atomic; media/preview routes only serve files inside the session cwd; git only shells out to the CLI and never sets identity - HTML preview and browser tab content render in opaque-origin sandboxed iframes (no
allow-same-origin/allow-top-navigation,no-referrer, all permission policies disabled); the/sidebar/htmlroute carries a CSPsandbox+ size/path bounds; the address bar rejectsjavascript:/data:/file:and local addresses like localhost - The UI shows the sandbox status live (red warning when off) and can temporarily unlock the current page; the settings page can disable the sandbox per feature (disabled by default, with a warning) — when off, content shares the origin with the UI; only recommended for fully trusted content
⚠️ Known Limitations
- Git has no push/pull/fetch; no file watcher (manual refresh); tool inline file-open buttons cannot be intercepted
- Dragging a terminal tab to another pane remounts it (shell restarts)
- Office-suite preview (.docx/.xlsx/.pptx) moved to the recommended office plugin (see the "Add plugins" modals in settings); without it these files fall through to the code/download fallbacks
- Browser sandbox has no login state / third-party cookies are restricted; some sites need popup login; sites that refuse embedding via
X-Frame-Options/frame-ancestors(e.g. arxiv.org) show a reason panel (with "Open in browser"); in-iframe navigation does not enter the back stack - HTML preview renders the saved file (not unsaved drafts)
- No bottom panel on mobile (<768px): on narrow screens its tabs merge into the right sidebar once (after migrating back to desktop they stay in the right sidebar); the desktop bottom panel is only available on wide viewports; auto-open terminal on first bottom-panel expand does not trigger on mobile
🖥️ Platform Support
Windows / Linux / macOS (macOS validated daily; the rest covered by unit tests); node-pty prefers prebuilt binaries, otherwise a build toolchain is required (Windows VS Build Tools / Linux make+g+++python3 / macOS Xcode CLT).
🔗 Friends
- dsh-tianshu-tui: an interactive terminal UI plugin for DeepSeek Harness (its rendering core evolved from the self-developed harness agent Tianshu-Tui), adding TDD and evidence-gate workflows on top of the official harness
- dsh-TUI: a Claude Code-style fullscreen interactive TUI plugin — pixel-whale top bar, live working-status row, streaming thought expansion, double-Esc rollback, context progress bar + TPS meter; one-command npm install
- dshfind Plugin Market: a third-party plugin marketplace — a listing of public repos under the GitHub topic
dsh-plugin, with stars, contributors and growth data synced daily - DeepSeek Harness Desktop: a modern desktop client for the DeepSeek Harness ecosystem — start and manage a local Harness service without configuring Node.js or running commands; official site