daoyu1993-lab/dsh-plugin-sidebar-polish ↗★ 0

dsh-plugin-sidebar-polish

Polish the DSH left sidebar: drop the brand row, redraw New Session as a panel row, unify row heights and indents, tune the fill for dark and light, pin the collapse toggle, add a settings entry, and mark idle sessions. 适合需要精简侧边栏布局、提升界面整洁度与对齐美感的视觉强迫症用户。

パッケージ
dsh-plugin-sidebar-polish
互換性
未検証
バージョン
0.5.0
ライセンス
MIT
最終更新
2026/10/03

インストール

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:daoyu1993-lab/dsh-plugin-sidebar-polish

ドキュメント

README 全文を読む ↗

dsh-plugin-sidebar-polish

去掉 DSH 左侧栏的顶部品牌行,让工作区/会话列表整体向上补位; 把**「新会话」按钮改画成与它下面那组全局面板行(插件 / Skill-MCP / 自动化任务 / 乔木 RSS) 同款的列表行(此前这个按钮被整条隐藏,现在回来了:新会话 就是这份列表的第一行); 把面板行 / 工作区行 / 会话行的 pill 与文字对齐到同一条线; 并给无状态(idle)的会话行**左侧补一个与官方彩色状态点同尺寸的灰色圆点 (官方只在运行 / 待审批 / 刚完成时画点,无状态行留空)。

改造前后对照

「新会话」按钮改造前后(上排静止、下排 hover):

新会话按钮:官方 38px 卡片 vs 与面板行同款的一行

官方原版现在
顶部品牌行(鲸鱼 + deepseek HARNESS)有移除
「新会话」按钮有(38px 独立卡片:0.5px 描边 + elevated 半透明底 + 内容居中 + 下外边距 12px)保留,改画成面板行同款的一行(32px 胶囊 / 16px 图标 / 图标→文字 8px / 文字 40px / 下外边距 4px / 无描边无底色)
折叠开关(面板图标)展开态在侧栏最右(x = 240..268)、收起态在红绿灯右侧(x = 88..116),两态之间横跳 152px两态都钉在红绿灯右侧(x = 88..116)
列表位置从第 ~110px 开始直接顶到顶部
面板 pill 左右边距14px8px(与列表 pill 对齐)
侧边栏左右内边距12px8px
图标→文字间距(面板 / 工作区 / 会话)8 / 6 / 4px8 / 8 / 8px
「工作区」区段标题 x16px16px(与图标同线)
行高(面板 / 工作区 / 会话 / 更多会话)36 / 34 / 32 / 28px全部 32px(含新会话行与「工作区」标题行)
工作区与工作区之间4px(组内行距的 2 倍)8px(组内行距的 4 倍,分组一眼可辨)
侧边栏底色(暗色)基色 #1b1b1c + 顶部淡蓝/底部淡紫渐变基色 #151517(= 对话区)+ 去掉渐变,50% 半透明保留
侧边栏底色(亮色)基色 #f9fafb,40% 不透明基色 #ffffff(= 对话区)+ 不透明度 90%,渐变去掉;实测 rgb(227,227,228) → rgb(248,248,250)(对话区 255,255,255)
激活工作区的文件夹图标蓝色强调 rgb(122,170,255)与行文字同色 rgb(249,250,251)
无状态(idle)会话行的左侧空的(只有运行/待审批/刚完成才有圆点)补一个 6px 灰点(官方 idle 状态色,与彩色点同尺寸同心)
文字左对齐线(新会话 / 面板 / 工作区 / 会话)居中 / 46 / 42 / 40px40 / 40 / 40 / 40px
设置行(头像 + 名字)右侧空的(整行本身就是账号菜单的触发按钮)补一个齿轮入口:真实按钮、自己的热区、点击直接打开设置面板;盒子与「新建工作区」按钮完全重合(28×28,列宽 − 8px 那条线)
工作区/会话列表、设置行、面板入口保留保留(原样)
收起后的 56px 轨道展开按钮有保留
「展开其余 N 个会话」按钮28px 高 / 12px 字 / hover 无底色 / 文案「展开其余 N 个会话」32px 高 / 14px 字 / hover 同款胶囊 / 文案「更多会话」

预览页 preview/compare.html 由 tools/build-preview.mjs 在本地生成(不随仓库分发:页面内联了 DSH 官方样式表,生成方式见「自检」一节的第 0 步),生成后可直接在浏览器打开; 细粒度对齐见 preview/align.png,新会话行见 preview/new-session.png。 图中侧边栏外壳的 CSS 与 DOM 结构取自真实包,会话条目为示意内容。


安装

插件目录就是本目录。两种装法二选一,不要同时启用(会插入两行同名插件):

# 本地目录(本仓库 clone 下来之后)
dsh plugin --profile desktop add "link:$PWD"

# 或直接从 GitHub
dsh plugin --profile desktop add "github:daoyu1993-lab/dsh-plugin-sidebar-polish"

它会把这个包加进 profile 的 dependencies 与 dsh.profile.bundles,并在 node_modules/ 下 建一个指向本目录的软链接(登记的是 link: 依赖,pnpm install 不会把它清掉), 所以在这里改 client.js 会被热更新直接读到。应用运行中也能安装。

// ~/.dsh/profiles/desktop/package.json
"dependencies": {
  "dsh-plugin-sidebar-polish": "link:"
},
"dsh": { "profile": { "bundles": [ ..., "dsh-plugin-sidebar-polish" ] } }

验证装载点:

dsh --profile desktop --dump-config | grep sidebar-polish

在本机(macOS 桌面版)实测核实:

  • 运行中应用的实时模块图里包含本插件(/plugins/events SSE 的 graph 事件);
  • 客户端产物可下发:/plugins/??dsh-plugin-sidebar-polish/client.js&rev=… 返回 200,内容与本目录文件一致;
  • 安装后没有产生新的崩溃日志。

页面需要刷新一次(⌘R)才能看到效果 —— 当前页面是在插件加入之前加载的。

卸载 / 回滚

dsh plugin --profile desktop remove dsh-plugin-sidebar-polish   # 需完全退出 App

或直接编辑 ~/.dsh/profiles/desktop/package.json:从 dependencies 与 dsh.profile.bundles 里各删掉一行,重启应用。插件本身不改任何官方文件, 删掉之后界面立即回到原样;样式表由 ctx.effect 管理,插件卸载时会自动移除,不会残留。


实现方式:为什么是「一个样式表」而不是「一个组件」

左侧栏的外壳(品牌行、新会话按钮、折叠行为)由官方包 @deepseek-ai/dsh-client-ui-sidebar 渲染。 DSH 的槽位系统里有两条硬规则(已实测):

  1. 声明即认领:只有声明了某个子槽的注册者才能渲染它;
  2. 遮蔽者不能重复声明别人的子槽(会抛 slot "..." is already declared)。

所以想「改外壳」只有两条路:

  • 接管整个 sidebar 座位 → 会连同它声明的 7 个子座位一起失效(会话树、设置行、插件入口……全都要自己重写),除非先把官方外壳从组合里禁用掉,再自己声明同一套座位。
  • 只加样式 → 外壳、座位、占用者全部保持原样,只是视觉上隐藏品牌行、并把「新会话」按钮重画一遍。

本插件整体上是第二条:样式表打底,零构建,只在自己真正需要行为的地方才碰槽位。 13 条规则全是纯 CSS,最坏情况只是「选择器失效 → 品牌行回来了、新会话按钮变回官方那张卡片」, 永远不会把侧边栏弄坏。

只有一处例外 —— 规则 14 的设置入口是真实的组件:它要的不只是「看起来像一个入口」, 而是「点它直接开设置,而不是弹账号菜单」,还要和旁边的账号行分成两个热区。 伪元素做不到这两件事(它只能继承所在按钮的行为),所以那里注册了一个真正的 `` 到官方外壳的 sidebar.footer.action 座位,由 CSS 排到设置行右端 (见 规则 14)。这一段是本插件唯一的 JS 逻辑。

选择器为什么这么写

DSH 的 class 名是 CSS Modules 哈希(_3WPZCG_logoRow),每次构建都会变,不能用来写皮肤。 这里只用两种跨版本稳定的锚点:

/* 1. 顶部品牌行:只在「渲染了展开态品牌标识」时命中 */
[data-slot="sidebar"] > div > div[data-window-drag]:has([data-slot="sidebar.brand.name"]) {
  display: none !important;
}
/* 2. 新会话按钮:sidebar 根容器唯一的直接子 ,
      保留但改画成 nav 里 .panelRow 的同款(见下) */
[data-slot="sidebar"] > div > button {
  height: 32px;
  min-height: 32px;
  margin: 0 0 4px;            /* 左右 0 与面板行同边距;4px = 面板行行距 */
  padding: 5px 8px;
  border: none;
  border-radius: var(--dsw-radius-md);
  background: transparent !important;
  color: var(--dsw-alias-label-primary);
  font-weight: 400;
}
[data-slot="sidebar"] > div > button:hover {
  background: var(--dsw-alias-interactive-bg-hover) !important;
}
[data-slot="sidebar"] > div > button:focus-visible {
  outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
  outline-offset: -2px;
}
/* 内容左对齐 + 图标 16px::has(> span) 只在宽态成立(收起态不渲染文字 span) */
[data-slot="sidebar"] > div > button > span:first-child > span:has(> span) {
  justify-content: flex-start;
  width: auto;
  gap: 8px;
}
[data-slot="sidebar"] > div > button > span:first-child > span:has(> span) > svg {
  width: 16px;
  height: 16px;
}
/* 2b. 折叠开关(面板图标):展开态也钉到官方浮层的落点(红绿灯右侧)。
       全屏必须排除 —— 那时没有红绿灯,浮层与 topStrip 本来就都在 left:12px。 */
html[data-platform="darwin"]:not([data-fullscreen]) [data-slot="sidebar"] > div > :first-child {
  --dsh-sidebar-toggle-left: 88px;   /* ← 与官方 .leadingSeat 的 left 同值;上游若改要同步 */
  justify-content: flex-start;
  padding-left: var(--dsh-sidebar-toggle-left);
}
/* 3. 全局面板行(插件 / 自动化任务 / …):pill 与列表 pill 同边距 */
[data-slot="sidebar"] > div > nav > button {
  margin-left: 0;
  margin-right: 0;
  gap: 8px;
}
/* 4. 工作区行(DSH UI Lab / Pico / …) */
[data-slot="sidebar"] [data-row-key^="workspace:"] {
  gap: 8px;
}
/* 5. 会话行:官方这里不是 flex gap(行 gap:0 + 标题 margin-left:4px),
      所以改标题自己的左外边距;标题恒为行的第 2 个子元素 */
[data-slot="sidebar"] [data-row-key^="session:"] > span:nth-child(2) {
  margin-left: 8px;
}
/* 6. 整体左右内边距 12px → 8px(一处决定三件事,见下) */
[data-slot="sidebar"] > div {
  --dsh-sidebar-inline-padding: 8px;
}
/* 7. 「展开其余 N 个会话」按钮:与上方会话行同款
      —— 高 32px(规则 9 统一)/ 14px 字 / 圆角 12px / hover 同款底色 / 文字起点 40px
      —— 文案:隐藏官方文字,用 ::after 显示,aria-expanded 区分两态 */
[data-slot="sidebar"] button[data-row-key^="overflow:"] {
  margin-top: 2px;
  padding-left: calc(32px + var(--dsh-workspace-indent, 0px));
  border-radius: var(--dsw-radius-md);
  font-size: 0;
}
[data-slot="sidebar"] button[data-row-key^="overflow:"]::after {
  content: "更多会话";
  font-size: 14px;
}
[data-slot="sidebar"] button[data-row-key^="overflow:"][aria-expanded="true"]::after {
  content: "收起";
}
[data-slot="sidebar"] button[data-row-key^="overflow:"]:hover {
  background: var(--dsw-alias-interactive-bg-hover);
}
/* 8. 「工作区」区段标题:左内边距 4px → 8px,让标题与下方图标同一条 16px 垂线;
      收起态复原官方值(轨道里只剩图标按钮,不能推右 8px) */
[data-slot="sidebar.workspaces"] > div > :first-child {
  padding-left: 8px;
}
[data-sidebar-collapsed] [data-slot="sidebar.workspaces"] > div > :first-child {
  padding-left: 0;
}
/* 12. 去掉侧栏的渐变染色,只保留半透明基色(逐态复刻官方的基色算法,
       不透明度取规则 10 的旋钮;含 prefers-reduced-transparency 分支,
       避免顶掉无障碍偏好) */
[data-platform="darwin"] div:has(> [data-slot="sidebar"]) {
  background: color-mix(in srgb, color-mix(in srgb, var(--dsw-specific-sidebar-fill) 97%, #7a9bf0) var(--dsh-sidebar-alpha-light), transparent);
}
[data-platform="darwin"] [data-ds-dark-theme] div:has(> [data-slot="sidebar"]) {
  background: color-mix(in srgb, var(--dsw-specific-sidebar-fill) var(--dsh-sidebar-alpha-dark), transparent);
}
@media (prefers-reduced-transparency: reduce) {
  [data-platform="darwin"] div:has(> [data-slot="sidebar"]) {
    background: color-mix(in srgb, var(--dsw-specific-sidebar-fill) 90%, transparent);
  }
}
/* 11. 激活工作区的文件夹图标:去掉蓝色强调,与文字同色 */
[data-slot="sidebar"] [class*="folderActive"] {
  color: inherit;
}
/* 13. 无状态(idle)的会话行:左侧 16px 槽位补一个灰点
      —— 只在座位锚点存在且为空时命中(= 官方判定为 idle 的那一类行)
      —— 6px 可见圆 = 官方彩色实心点(10px 盒 / ::after{inset:20%})的同一尺寸 */
[data-slot="sidebar"] [data-row-key^="session:"] > span:has(> [data-slot="sidebar.session.row.leading"]:empty)::after {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--dsw-alias-state-idle-primary);
}
/* 15. 工作区与工作区之间:4px → 8px
      —— 官方只用一个类的类名分组(_7514NG_groupSection),所以用后缀匹配;
         选择器带三个属性段,压过官方那条两类的规则,不需要 !important */
[data-slot="sidebar"] [class*="groupSection"] + [class*="groupSection"] {
  margin-top: 8px;
}
/* 10. 侧边栏底色旋钮:一态两个(基色 + 不透明度),想微调只动这四行 */
div:has(> [data-slot="sidebar"]) {
  --dsh-sidebar-fill-dark: #151517;   /* 暗色基色 = 对话区 --dsw-alias-bg-base(官方原值 #1b1b1c) */
  --dsh-sidebar-fill-light: #ffffff;  /* 亮色基色 = 对话区 --dsw-alias-bg-base(官方原值 #f9fafb) */
  --dsh-sidebar-alpha-dark: 50%;      /* 暗色不透明度(官方值) */
  --dsh-sidebar-alpha-light: 90%;     /* 亮色不透明度(官方 40%;提到 90% 才压得住窗口材质) */
  --dsw-specific-sidebar-fill: var(--dsh-sidebar-fill-light);
}
body[data-ds-dark-theme] div:has(> [data-slot="sidebar"]) {
  --dsw-specific-sidebar-fill: var(--dsh-sidebar-fill-dark);
}
/* 9. 行高统一为 32px(面板行 / 新会话行 / 区段标题行 / 工作区行 / 会话行 / 更多会话) */
[data-slot="sidebar"] [data-row-key^="workspace:"],
[data-slot="sidebar"] [data-row-key^="session:"],
[data-slot="sidebar"] button[data-row-key^="overflow:"],
[data-slot="sidebar.workspaces"] > div > :first-child {
  height: 32px;
}
/* 面板行与新会话行官方是靠 min-height:36px + padding:7px 8px 撑出来的(行高 22px),
   上下内边距收到 5px 才是 22 + 5 + 5 = 32px */
[data-slot="sidebar"] > div > nav > button,
[data-slot="sidebar"] > div > button {
  min-height: 32px;
  height: 32px;
  padding-top: 5px;
  padding-bottom: 5px;
}
/* 14. 设置行右侧的设置入口:一个真实按钮(注册在 sidebar.footer.action 座位里)。
       脚区从「竖排两行」改成「一行两列」,设置行占左列、footerActions 占右列,
       两个热区因此不重叠;按钮 28×28 与「新建工作区」按钮同款,齿轮用遮罩画。 */
div:has(> [data-slot="sidebar"]) [data-slot="sidebar"] > div > div:has(> div > [data-slot="sidebar.settings"]) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 4px;
}
div:has(> [data-slot="sidebar"]) [data-slot="sidebar"] > div > div:has(> div > [data-slot="sidebar.settings"]) > :first-child {
  grid-area: 1 / 2;   /* footerActions:设置入口 */
}
div:has(> [data-slot="sidebar"]) [data-slot="sidebar"] > div > div:has(> div > [data-slot="sidebar.settings"]) > :last-child {
  grid-area: 1 / 1;   /* settingsArea:账号行 */
}
.dsh-settings-entry {
  width: 28px;
  height: 28px;
  padding: 0;
  border: none;
  border-radius: var(--dsw-radius-sm);
  background: transparent;
  color: var(--dsw-alias-label-secondary);
  cursor: pointer;
  position: relative;
}
.dsh-settings-entry::after {
  content: "";
  position: absolute;
  inset: 6px;
  background-color: currentColor;
  mask: var(--dsh-settings-gear) center / 16px 16px no-repeat;
}
.dsh-settings-entry:hover { background: var(--dsw-alias-interactive-bg-hover); }
/* 收起轨道:脚区复位成官方的竖排,入口不显示 */
[data-sidebar-collapsed] div:has(> [data-slot="sidebar"]) [data-slot="sidebar"] > div > div:has(> div > [data-slot="sidebar.settings"]) {
  display: flex;
  flex-direction: column;
  align-items: center;
  column-gap: 0;
}
[data-sidebar-collapsed] .dsh-settings-entry { display: none; }

这几条规则各修了什么:

  • 规则 2b — 折叠开关(面板图标)固定到红绿灯右侧:这是本次新增的一条,也是唯一 一条改变展开态布局位置的规则。

    官方的开关在 macOS 桌面端有两个落点:展开时由侧栏自己的 topStrip 承载,官方给它 justify-content: flex-end,于是被推到侧栏最右边;收起时侧栏整列宽度归 0 (AppFrame 里 collapsedWidth = darwin ? 0 : 56 —— macOS 上「收起 = 整列隐藏,连轨道都没有」), 开关改由侧栏之外的官方浮层接管:HeaderLeadingControls 渲染在 .leadingSeat{position:absolute; top:11px; left:88px} 里,落在红绿灯右侧。

    同一个按钮、两个落点,展开/收起时会横向跳 152px。这条规则把展开态也钉到浮层那一格:

    官方展开态官方折叠态(基准)现在(两态)
    按钮 x240..268(侧栏最右)88..116(红绿灯右侧)88..116
    按钮 y11..3911..3911..39
    实测图标中心(253.75, 24.75)(101.75, 24.75)(101.75, 24.75)

    垂直方向本来就相等,所以只动横向:主轴改成 flex-start,左内边距取 88px 旋钮。 88px 与官方 .leadingSeat 的 left 是同一个数(上游若改要同步);顶部 top:11px 对得上是因为 topStrip 高 52px、下内边距 2px、align-items: center 天然给出 y = 11..39。

折叠开关:官方两态横跳 152px vs 现在两态同一位

这张图是真实窗口截图(screencapture -l,2x),不是 DOM 副本 —— 三行分别是 「关掉本规则」「开着本规则」「侧栏收起(基准)」,三态在同一台机器、同一次会话里连拍。 逐帧验证:连拍 40 帧(约 90ms 一帧),期间状态来回切换了两次(展开 → 收起 → 展开), 图标包围盒恒为 x 190..217 / y 36..63@2x(= CSS x 95..108.5 / y 18..31.5), 过场帧与静止帧的像素个数也完全相同(244)—— 没有位移、没有闪烁。

必须排除全屏(html:not([data-fullscreen])):全屏下没有红绿灯,官方把浮层挪到 left:12px、topStrip 也改成 flex-start,开关在两态本来就都落在 x = 12..40, 不排除反而会被这条规则推到 88px。

选择器用「sidebar 根容器的第一个子元素」定位 topStrip:它只在 darwinDesktop 下渲染, 而 isDarwinDesktop() 就是读 [data-platform="darwin"](同一个属性),两者同义, 所以 Web 端永远不会命中这条(那里第一个子元素是品牌行)。

  • 规则 2 — 新会话按钮:保留,但画成列表行:「新会话」是外壳自己渲染的按钮 (SidebarRoot 里 sidebar 根容器唯一的直接子 ``),官方把它做成一张独立卡片: 38px 高、.5px 描边、elevated 半透明底、内容居中、下外边距 12px; 而紧挨着它的 nav.panelList 面板行是 32px 无底色胶囊、图标与文字左对齐。 品牌行(规则 1)去掉后两者上下相邻 —— 一张卡片压在一份列表上,看起来是两种东西。

    规则 2 把它改画成面板行的同款,实测(真实 Chrome,tools/verify-new-session.mjs):

    官方 .newSession.panelRow(nav)本插件
    高度38px32px32px(规则 9 统一)
    左右外边距14px(margin: 0 2px + 12px 内边距)8px8px
    到下一行的间距12px4px4px
    描边 / 底色.5px 描边 + elevated 半透明底无 / transparent无 / transparent
    内容对齐居中(图标 109..123、文字 129)左对齐左对齐
    图标14px16px16px(都落在 16px 垂线)
    图标→文字6px8px8px
    文字 x129px40px40px
    字重500400(继承根)400
    hover--dsw-alias-button-floating-hover(卡片更亮)--dsw-alias-interactive-bg-hover列表行同款

    几个不显然的地方:

    1. 为什么下外边距是 4px:它就是 nav.panelList 的行间距。设成 4px 后,「新会话」 与面板行之间、面板行彼此之间的间距完全一样,读起来是同一份列表(否则会多出 8px 的断口,又变回「一个按钮 + 一份列表」)。
    2. 为什么底色要用 !important:官方在 macOS 上给这张卡片叠了四层底色 ([data-platform=darwin] .newSession 亮/暗两态 + 各自的 hover),选择器都是 2~4 层,普通规则压不过。作用域只有这一个按钮,而且展开态与收起态要的都是 「无底色 + hover 用 interactive-bg-hover」,所以收起态不需要再写复位。
    3. 为什么内容对齐用 :has(> span) 守卫:官方把内容做成 .newSessionContent{justify-content:center; width:100cqw},要改成左对齐就得改它; 而文字 span 只在宽态渲染,于是 button > span:first-child > span:has(> span) 恰好等于「这一列是展开的」。收起态的 56px 轨道(以及 Windows 的 36×36 圆形按钮) 自动不命中,轨道里的图标仍然是官方值(18px、居中)—— 已由 tools/verify-new-session.mjs 断言(:has() 守卫一旦失效,这条断言会红)。
    4. ⌘N 键帽保留:官方的 ShortcutKeys(12px / label-tertiary)只在 hover 显示, 静止态与列表行完全一样;宽态下 Tooltip 是关掉的,删掉它就再没有快捷键提示了。
    5. margin-left/right: 0 与规则 3 同源:面板行被规则 3 归零了 margin: 0 2px, 两边的 pill 左边缘因此都落在规则 6 的 8px 内边距上。

新会话按钮:官方 38px 卡片 vs 与面板行同款的一行(含 hover)

上面那张是 DOM 副本(真实产物 CSS + 真实外壳 JSX)。下面这张是真实窗口截图 (screencapture -l,2x,亮色外观)。对它做像素扫描:五行的文字左边缘都在 2x 图的 第 81/82 像素(= CSS 40.5/41px,多出的 0.5~1px 是字形自身的左留白), 行间距也一律 40px —— 与面板行完全同一条线、同一个节奏。

真实窗口截图:新会话作为列表第一行,与插件/Skill-MCP/自动化任务/乔木 RSS 同款

  • 规则 3 — 面板 pill 比列表 pill 多缩 2px:官方给面板行写了 margin: 0 2px, 而列表行没有。归零后两类 pill 的左右边距相等(绝对值由规则 5 决定), 图标也随之内缩对齐。

  • 规则 3/4/5 — 文字落在三条不同的线上:面板行 gap: 8px → 46px、工作区行 gap: 6px → 42px、 会话行 margin-left: 4px → 40px。三者统一到 8px 后,文字自然同线(40px) (规则 2 把「新会话」也一并拉上这条线 —— 它官方是居中的,没有自己的左对齐线)。 会话行之所以单独用 margin-left 而不是 gap:给它加 gap 会把标题与时间戳之间也一起撑开。

  • 规则 6 — 收紧整体内边距:官方把 --dsh-sidebar-inline-padding: 12px 写在根元素自己身上, 所以必须命中同一个元素才能覆盖([data-slot] 属性的特异性高于单个 class)。 它一处决定:

    • 列表行 pill 的左右外边距(12px → 8px)
    • 面板行 pill 的左右外边距(同为 12px → 8px)
    • 工作区的 edge-inset —— 也就是右侧「padding + scrollbar-gutter 预留 + margin」那套对称算法

    图标随之外移:20px →