dsh-better-workspace 0.38.2 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -39,7 +39,7 @@
39
39
 
40
40
  **重启后标题不回退**:DSH 重启后的冷列表只为命中投影缓存的会话携带标题——分叉出的会话与从未写过检查点的会话会暂时没有标题,真实的标题其实还在会话日志里。本插件把每个会话**最近一次的真实标题**持久化在浏览器里(带防抖的本地缓存,变更合并整写一次),回退窗口内直接用记忆标题渲染,`/` 分级分组照常成立;打开会话后官方数据到位即自动纠正。**从未有过标题的会话**(例如只写了头部、零轮次的空会话)不再回退成「工作区名」,而是显示官方语义的「未命名」(v0.36.14,issue #16)。
41
41
 
42
- **跨端手动同步(Web ↔ 桌面客户端)**:外观自定义、默认外观与开关默认保存在各设备自己的浏览器里;设置卡片新增「跨端同步」区——Web 上点「从客户端获取」、客户端上点「从 Web 获取」,可选**覆盖本设备**或**合并两端**(并集保留各自独有项),另一端的数据经宿主设置存储(~/.dsh/settings.yaml,两端共享)送达;旁边有「发送本设备数据」按钮,旧版本的历史数据首次同步推一次即可,之后每次修改都会自动写入宿主、对端随手可取。折叠状态仍保持每端独立。
42
+ **设置与外观**:外观自定义、默认外观与开关保存在当前设备,并随当前 DSH profile 持久化;折叠状态与会话本地序仍保持每端独立。
43
43
 
44
44
  <table>
45
45
  <tr>
@@ -55,14 +55,14 @@
55
55
  <table>
56
56
  <tr>
57
57
  <td align="center" width="58%"><img src="docs/screenshots/5-context-menu.png" alt="右键菜单"/></td>
58
- <td valign="top"><b>右键菜单</b><br/>操作都收进右键:工作区行——重命名 / 删除 / 分叉 / 归档 / 自定义外观 / <b>修改工作区默认预设</b>(v0.32.0 起,改写该工作区常驻新会话所用的 agent 预设,走官方同一通道;内置预设显示官方本地化名——标准模式 / PTC 模式 / 极简模式 / 创造模式,v0.33.0 起;工作区暂无待命新会话时,确认后会预备一个带所选预设的新会话作为该工作区默认);工作区分组行——重命名分组(同步更新组内所有工作区名称)/ 自定义外观;会话与会话分组行——重命名 / 分叉 / 归档 / 自定义外观;会话行另有<b>复制 Session ID</b>(v0.30.0 起,对齐 dsh 0.2.1-alpha.5 官方会话菜单第五项——写剪贴板走宿主原语,复制成功与否均有提示)。<br/><b>v0.38.0 起接入官方统一右键菜单</b>:会话/工作区行由宿主共享菜单渲染,官方条目与插件补充项(移动到分组 / 移出分组 / 自定义外观 / 修改默认预设,排在分隔线之后)同席,官方新增条目会自动出现;分组行仍用插件菜单,旧宿主回退原菜单。</td>
58
+ <td valign="top"><b>右键菜单</b><br/>操作都收进右键:工作区行——重命名 / 删除 / 分叉 / 归档 / 自定义外观 / <b>修改工作区默认预设</b>(v0.32.0 起,改写该工作区常驻新会话所用的 agent 预设,走官方同一通道;内置预设显示官方本地化名——标准模式 / PTC 模式 / 极简模式 / 创造模式,v0.33.0 起;工作区暂无待命新会话时,确认后会预备一个带所选预设的新会话作为该工作区默认);工作区分组行——重命名分组(同步更新组内所有工作区名称)/ 自定义外观;会话与会话分组行——重命名 / 分叉 / 归档 / 自定义外观;会话行另有<b>复制 Session ID</b>(v0.30.0 起,对齐 dsh 0.2.1-alpha.5 官方会话菜单第五项——写剪贴板走宿主原语,复制成功与否均有提示)。<br/><b>v0.38.0 起接入官方统一右键菜单</b>:会话/工作区行由宿主共享菜单渲染,官方条目与插件补充项(移动到分组 / 移出分组 / 自定义外观 / 修改默认预设,排在分隔线之后)同席,官方新增条目会自动出现;分组行仍用插件菜单。</td>
59
59
  </tr>
60
60
  </table>
61
61
 
62
62
  <table>
63
63
  <tr>
64
64
  <td align="center" width="58%"><img src="docs/screenshots/4-settings-card.png" alt="插件设置卡片"/></td>
65
- <td valign="top"><b>设置卡片</b><br/>设置 → 插件 → 插件配置 里新增「更好的工作区」卡片(官方折叠卡片样式),提供<b>单链分组合并</b>开关(如 测试层1 下只有 AI交易 一个工作区时,合并显示为一行 测试层1/AI交易)、<b>状态呼吸灯</b>开关(被折叠藏起的状态灯沿层级向外冒泡呼吸发光,默认开)、<b>行密度</b>三档(紧凑 / 标准 / 宽松,默认=官方行高,v0.34.0 起)与<b>显示会话数</b>开关(行尾会话数角标,默认关=官方,v0.34.0 起);另有<b>默认外观</b>区——颜色 / 发光 / 字体粗细 / 字体阴影 / 字体描边开关 / 描边粗细一次配好,没有单独自定义过的行全部继承(描边新装默认关,其余同「无自定义」),并随宿主设置存储跨端同步。展开状态与外观自定义经 dsh 客户端 store 持久化在当前浏览器。</td>
65
+ <td valign="top"><b>设置卡片</b><br/>设置 → 插件 → 插件配置 里新增「更好的工作区」卡片(官方折叠卡片样式),提供<b>单链分组合并</b>开关(如 测试层1 下只有 AI交易 一个工作区时,合并显示为一行 测试层1/AI交易)、<b>状态呼吸灯</b>开关(被折叠藏起的状态灯沿层级向外冒泡呼吸发光,默认开)、<b>行密度</b>三档(紧凑 / 标准 / 宽松,默认=官方行高,v0.34.0 起)与<b>显示会话数</b>开关(行尾会话数角标,默认关=官方,v0.34.0 起);另有<b>默认外观</b>区——颜色 / 发光 / 字体粗细 / 字体阴影 / 字体描边开关 / 描边粗细一次配好,没有单独自定义过的行全部继承(描边新装默认关,其余同「无自定义」)。设置随当前 DSH profile 持久化;展开状态与外观自定义另经 dsh 客户端 store 持久化在当前浏览器。</td>
66
66
  </tr>
67
67
  </table>
68
68
 
@@ -72,7 +72,7 @@
72
72
  - **拖拽还原原版能力**:工作区行可拖拽——拖到另一工作区行上/下半即调整顺序(写回宿主 registry 序),拖到分组行中带则移动进该分组(改写名称前缀);**工作区分组行同样可拖拽(v0.36.0 起,三带悬停)**——拖到分组行时行分三个落区:上下 **30% 边带**=与该组**排序**(拖完立即重排、刷新后保留),**中带**=整组移入(组成员逐个改写名称前缀,与「重命名分组」同一语义;拖到自身/自己的子孙组上会被拒绝);**组行与工作区行同处一条混合序列(v0.36.5 起)**:一个层级里的行顺序只有一份(组行与裸工作区行交错),工作区可以拖到分组行的边带插到该组前面/后面,分组也可以拖到工作区行前面/后面——不再有「组永远排在裸工作区之前」的限制;拖到**另一层**的边带是**放置**(v0.36.6):工作区离开原组(或进入目标层)并插到落点,「插到第一个」画哪落哪(跨磁盘层不放行——磁盘层是文件系统事实);**拖入黑框统一(v0.36.7)**:工作区行拖到分组行中带 = 改名前缀进组(黑框反馈);组行拖到**它所属的磁盘层工作区行 / 直接父级分组行**中带 = 整组「放入」该容器、排到该层末尾(标题与磁盘位置都不动,同一套黑框视觉)——排序走边带、放入走中带,两类操作视觉上彻底分开;**容器防环(v0.36.9)**:磁盘层的容器工作区不能被拖进它自己的名称组或子工作区——那会把容器改名成自己的子孙(如「工作/用户目录」甚至「<id>/用户目录」),现在整行拒绝、不留任何落点反馈,排序与放入父容器(v0.36.7)不受影响;**平级组嵌套与提升(v0.36.10)**:组行拖到平级组行的**中带**=变成它的**子组**(成员标题落到新组之下,`工作/平行帮` → `工作/Fis管理后台/平行帮`,天然不撞名——旧的并入语义会在双方都有同名子工作区时报 name-conflict、整树不动);组行拖到**另一层工作区行的边带**(同磁盘、不在自己子树内)=**整组提升**到那行所在层并锚定在落点旁(「把平行帮拖到和用户目录、工作平级」);已打开的排序槽不再锁死判定——指针推回行**中带**即可翻成放入黑框,嵌套与排序随时互切;**静止松手兜底**:Chromium 把指针静止约一秒后的松手吞成 dragend 时,按最后悬停的落点补提交(Esc 取消不受影响),不再「松手没反应」;**撑开让位(v0.36.4)**:进入排序边带立刻把目标行撑开一行(工作区行与分组行同一套视觉),判定按**行未撑开时的原始位置**算——指针停在槽空出的新区里保持当前方向不闪烁;槽已打开的行只按原始中线二选一(上半=插在前,下半=插在后,**不会翻成「移入」**),三带里的中带 INTO 只在首次进入时决定,随时可改主意;会话行可拖拽——同组内拖到另一会话上/下即调整顺序,拖到**别组的会话行**会把名字前缀改写到那个组(拖到根层的行 = 移出分组),拖到会话子分组行即移动进该分组,拖到**自己的工作区行**或**树里任何组外的地方**(含空白区域)同样移出分组 —— 拖拽期间工作区行整行高亮、树底部有一条淡虚线提示这个出口;带分组前缀的会话行右键还多一项「移出分组」。显示顺序 = 宿主手动序(分组行 = 父容器下的持久化组序),拖拽结果立即生效。**磁盘层是文件系统事实,不随拖拽改变**:跨磁盘层不放行(边带不接管光标、不画落点线),同磁盘层内按落点锚定。拖拽期间树形保持不变(v0.36.4):单链合并行不再临时展开、归组成功也不自动展开目标组——指针下的行不会突然换人,展开状态只在点击时改变。
73
73
  - **不丢原生能力**:会话行(打开/重命名/分叉/归档;**双击标题**重命名,v0.34.0 起;**右键是唯一菜单入口**——行内「⋯」已退役,悬停只留快捷钮,工作区行同样只留新会话钮,v0.35.1 起)、**官方行样式逐项对齐**(v0.34.0 起:恒定 16px 状态槽——运行转圈不再挤动标题、悬停 800ms 弹官方 HoverCard(标题/路径/时间/状态,可复制)、超长标题悬停匀速滚动、活动链工作区文件夹图标着蓝、拖放指示用官方斜纹图案)、每工作区「新会话」(点 + 总是先展开该工作区,让新会话立刻可见)、当前会话高亮、官方状态灯(蓝色运行环 / 琥珀待交互 / 绿色完成提醒)、**状态呼吸灯**(折叠藏起的状态灯向外冒泡:工作区/分组行图标按状态色呼吸发光——琥珀待交互/绿完成,自定义过发光的标题一起呼吸;运行中只在会话行本层蓝色呼吸,不外渗;可在设置关闭)、**活跃定时任务角标**(有活动 Schedule 的会话显示闹钟图标;v0.23.0 起直接渲染官方 `sidebar.session.row.leading` 座位的占用者,与官方行同源)、未分组会话兜底、界面文案跟随 DSH 的语言设置(内置 21 种语言,含简繁中文)。
74
74
  - **新增项自动配色 + 图标(v0.25.0,默认关闭)**:设置卡里一个开关,打开后**新创建的会话**自动分到一个内置色、**新工作区**再额外分到一个图标,懒得逐个设置的人直接开箱即用。颜色来自**定死的 13 个槽位**,每个槽位配**两色**——浅色主题用深色系、深色主题用亮色系——按「洗牌袋 + 近期回避窗口」抽取:一轮之内绝不重复,跨轮也不会立刻撞上刚出过的 3 个,连续新建几项肉眼可辨。**可读性是真达标**:每个色在**对应主题**背景下的对比度都 **≥4.5**,即 WCAG **正文级 AA**(对比度是脚本真算的,测试逐色断言;浅色主题按比纯白更暗的悬停面、深色主题按最亮的面这种保守取值)。行里存的是**槽位 id(`auto:3`)而不是色值**,所以**切换深浅主题时颜色自动换成同色系的另一套**,既不用重新设置,也不会失配。**只影响打开开关之后新建的项**:你手动设置过外观的行(存的是 hex)永不被覆盖,关闭开关也不回收已分配的样式,同一项不会被二次随机。图标从既有图标候选集里取、按宿主实际导出过滤;**图标只给工作区**——会话行的那个位置是官方状态灯与日程角标,没有图标位。
75
- - **官方新语义与快捷键都接上(v0.23.0,对齐 dsh 0.1.7-rc.2)**:① 归档筛选是官方新版三态直选(**隐藏已归档** / **全部对话(显示已归档)** / **仅显示已归档**);选「仅显示已归档」时**没有归档会话的工作区整行隐藏**,空列表显示「暂无已归档会话」+「查看其他会话」一键回退;② 官方快捷键 **⌥⌘K 搜索 / ⌥⌘O 添加工作区 / ⌥⌘N 新会话**(桌面端为 ⌘K / ⌘O / ⌘N)在本插件的自绘侧栏里**真的生效**——搜索键打开并聚焦本插件的搜索框、添加键走同一个官方目录流(原生宿主弹系统选择器,browse 宿主弹应用内入口提示),按钮文案还会带上宿主当前的键位;③ 首次使用的工作区显示为本地化的「默认工作区」,不再露出磁盘目录名。
75
+ - **官方新语义与快捷键都接上(v0.23.0,对齐 dsh 0.1.7-rc.2)**:① 归档筛选是官方新版三态直选(**隐藏已归档** / **全部对话(显示已归档)** / **仅显示已归档**);选「仅显示已归档」时**没有归档会话的工作区整行隐藏**,空列表显示「暂无已归档会话」+「查看其他会话」一键回退;② 官方快捷键 **⌥⌘K 搜索 / ⌥⌘O 添加工作区 / ⌥⌘N 新会话**(桌面端为 ⌘K / ⌘O / ⌘N)在本插件的自绘侧栏里**真的生效**——搜索键打开并聚焦本插件的搜索框、添加键走同一个官方目录流(原生宿主弹系统选择器,browse 宿主直接弹出官方应用内目录浏览器),按钮文案还会带上宿主当前的键位;③ 首次使用的工作区显示为本地化的「默认工作区」,不再露出磁盘目录名。
76
76
  - **URL/斜杠标题不拆层**:宿主自动生成的会话标题落地时若含 `/`(如复述了 URL),整串自动包上 `“”` 原样显示,绝不解析成层级——只对本次启动后**新建的会话**生效,并等命名稳定(约 20 秒,让原生 AI 命名先落地)才处理;存量会话与你手动命名的 `/` 分组标题永不被改动。引号内(含手动添加)的 `/` 永不切分,孤立引号只当普通字符;无引号但含 URL 的旧标题也有平铺兜底。**v0.37.2 起再加一道路径保护(issue #17)**:标题里引用绝对路径(`/Users/...`、`C:/...` 这类含至少两个 `/` 的路径 token)时,整条标题作为一个会话行显示,绝不拆成伪目录——存量会话与首条消息回显的标题同样生效,`web/前端` 这类正常的名称分组不受影响。**v0.37.3 起路径标题不再被 20 秒稳定期改成带引号的用户标题**:显示层已经平铺,原逻辑反而会把回显路径钉死并取消尚未落地的 AI 命名;现在直接放过,等 AI 总结名替换。会话分组仍默认开启,不需要的话可在视图菜单关掉。
77
77
  - **新会话页的工作区选择器 = 侧栏那棵树(v0.22.0)**:会话空态页「工作区」按钮的弹层原本是官方的一层平铺标题列表(连磁盘目录嵌套都没有);本插件接管该座位后,弹层绘制与侧栏**同一棵**树——磁盘目录嵌套、「/」名称分组三态、单链合并全部读同一个视图 store,所以侧栏的视图选项一改,**这边立刻跟着变**;当前工作区带勾选标记,分组行可开合(选择器内本地记忆,默认全展开),标题按侧栏的层级叶子显示。底部「添加工作区」仍由**官方目录拾取占用者**承载(原生选择器 / 官方应用内浏览器),不是仿制品。
78
78
 
@@ -107,9 +107,9 @@ dsh plugin --profile web add dsh-better-workspace # npm 公开包
107
107
 
108
108
  ## 工作原理
109
109
 
110
- DSH 的侧边栏浏览区是一个公开插槽 `sidebar.workspaces`(single),官方工作区浏览器是它的占用者;本插件以更低优先级注册同一插槽,**整区替换**为层级树版本。数据全部来自插槽标准注入(`useWorkspaces` / `useSessions` 快照钩子),动作(打开会话、重命名/删除工作区、归档等)也走注入的宿主动作——不碰任何私有 API。
110
+ DSH 的侧边栏浏览区是一个公开插槽 `sidebar.workspaces`(single),官方工作区浏览器是它的占用者;本插件以更低优先级注册同一插槽,**整区替换**为层级树版本。数据全部来自插槽标准注入(`useWorkspaces` / `useSessions` 快照钩子),动作(打开会话、重命名/删除工作区、归档等)也走注入的宿主动作。唯一例外是**关闭历史会话的重命名**:rc.1 公开面只有 `sessions.binding` / `sessions.using`(`using` 会打开历史),不打开历史的快速路径仍要读 `sessions.manager`,代码里标为 **PRIVATE BRIDGE**;官方把这条路径公开后应立即删除该桥。
111
111
 
112
- 「添加工作区」完全交给官方:官方组合占用者(原生选择器 / 应用内浏览器)承载全部拾取交互;本插件作为 owner 只负责选完目录后的创建与新会话。**两个 directoryFlow 子洞自 v0.16.0 起都不由本插件声明**——子洞声明是独占的,接管座位的一方永远拿不到 `renderSlot` 授权(相关事故见 CHANGELOG)。侧栏的添加动作因此改为直接驱动官方目录服务(native → 官方 OS 选择器;browse → 提示指向空态页),而**空态页的添加动作直接渲染官方占用者组件本身**:从 slot ledger 读出该洞的占用项(组件 + 它自己的注入面),由本插件补上 owner 对话(open / busy / onPicked / onCancel / onError)。原生与 browse 宿主各自保留出厂交互;ledger 读不到占用项时,少的只是「添加工作区」这一项,选择器照常工作。该机制 0.1.2+ 宿主即可用,升级先后都收敛。
112
+ 「添加工作区」完全交给官方:官方组合占用者(原生选择器 / 应用内浏览器)承载全部拾取交互;本插件作为 owner 只负责选完目录后的创建与新会话。**两个 directoryFlow 子洞自 v0.16.0 起都不由本插件声明**——子洞声明是独占的,接管座位的一方永远拿不到 `renderSlot` 授权(相关事故见 CHANGELOG)。侧栏添加动作先探测后端:native 直接调官方 `pickDirectory()`;browse 从 slot ledger 读出官方占用者组件(连同它自己的注入面),由本插件补上 owner 对话(open / busy / onPicked / onCancel / onError)后直接渲染。**空态页的添加动作使用同一套读法**。原生与 browse 宿主各自保留出厂交互;ledger 读不到占用项时,少的只是「添加工作区」这一项,选择器照常工作。该机制要求 dsh >= 0.2.2-rc.1。
113
113
 
114
114
  会话空态页的工作区座位(`conversation.hero.workspace`)与侧栏同理:本插件以更低优先级注册同一座位,弹层换成侧栏同源的树;该座位**不声明任何子洞**,所以官方 picker entry 的所有权不受影响。
115
115
 
@@ -121,12 +121,10 @@ DSH 的侧边栏浏览区是一个公开插槽 `sidebar.workspaces`(single),官
121
121
 
122
122
  ## 版本兼容
123
123
 
124
- - **dsh 0.1.6-alpha.1**:图标集与浏览器注入面都变了,本插件 **0.10.2 起自动适配**——图标网格只列本宿主真正导出的字形(退役的 `IconSendOutline16` 自动落到等价的 `IconSendOutline14`,已保存的旧选择不会变成空图标位),会话拖拽排序在宿主不再注入 `insertSessionBefore` 时改用浏览器本地顺序,**功能不丢**。升级 dsh 与升级插件谁先谁后都收敛。
125
- - **dsh 0.1.6-alpha.2**:设置页重组——本插件 **0.12.0 起双座位**注册设置卡片(旧宿主的 设置→插件 卡片 + 新宿主 插件面板 bundle 页,按包名挂载);工作区树新增**磁盘目录嵌套层**(官方 workspace-tree 语义),添加工作区回归官方目录流(原生选择器 / 官方应用内浏览器)。
126
- - **dsh 0.2.2-alpha.2**:自绘会话行渲染官方 `sidebar.session.row.trailing` 行尾座位(时间之后、置顶角标之前;空会话不渲染),官方实验性 worktree / PR 图标因此在插件接管侧栏后仍能出现;同时接受官方的空白会话复用语义(不传 `agentPreset` 时会复用同工作区任意 preset 的空白会话)。该座位按能力探测:老宿主没有它时行尾照常渲染,不会因此报错。兼容下限保持 `>=0.1.6-alpha.2`。
127
- - **dsh 0.2.2-alpha.3**:会话/工作区行接入官方统一右键菜单(`contextMenus`)——官方条目与插件补充项同席,插件条目 order 700、排在其后并以分隔线隔开,官方今后新增的条目会自动出现。工作区分组 / 会话分组行是插件私有虚拟对象,仍用插件菜单;没有该服务的旧宿主整体回退本地菜单,兼容下限保持 `>=0.1.6-alpha.2`。
128
- - **dsh 0.2.2-rc.1**:客户端 ModuleLoader / package-local chunk、官方 `contextMenus` 与侧栏座位均按原契约工作;自绘侧栏复刻的官方行内座位补上 rc.1 新增的全局 `useSessionAccess` 标准 hook,首条会话渲染时 pin/archive 按钮不再抛错拖垮整栏(旧宿主没有该 hook 时自动省略)。`ui-settings` 新增的可选 `settings.section.icon` 未被本插件使用。真机验证侧栏树、右键菜单、外观与 chunk 加载正常,兼容下限保持 `>=0.1.6-alpha.2`。
129
- - **跨端**:web 与桌面共用同一套客户端资产;外观 / 开关可经设置卡片手动跨端同步,**折叠状态与会话本地序每端本地**(设计如此)。
124
+ - **运行时下限:dsh >= 0.2.2-rc.1,Node.js >= 24.9.0**。本插件自 v0.39.0 起只维护这一代宿主,不再为 0.1.x / 0.2.0 / 0.2.1 / 0.2.2-rc.1 之前的预发布保留探测或回退。
125
+ - **rc.1 契约**:全局标准 hook 使用 `useSessionStatus` / `useSessionAccess`;会话/工作区行接入官方 `contextMenus`;会话行渲染官方 `sidebar.session.row.trailing` 与 `sidebar.session.row.leading` 座位;设置只注册官方插件面板的 `plugins.bundle.config` 座位。
126
+ - **设置持久化**:插件 Config 只公开 `compactChains` / `statusPulse` / `styling` / `appearance` 四个 volatile 字段;其余视图偏好留在浏览器本地 store,不再尝试写宿主。跨端手动同步已随共享 `settings.yaml` 时代一起移除。
127
+ - **用户数据迁移**:旧快照的 `workspaceTitleSlash` / 缺省 `stroke` 键 / 旧图标名仍按读时分代解析,升级不会改变既有外观与分组;这类兼容只针对**本插件自己的旧数据**,不针对旧宿主。
130
128
 
131
129
  ## 限制与路线图
132
130
 
package/README_EN.md CHANGED
@@ -39,7 +39,7 @@ Session titles nest on `/` too (e.g. `test1/plugin maintenance`). Session groups
39
39
 
40
40
  **No title regression after a restart**: the cold list right after a DSH restart only carries titles for sessions that hit the persisted projection cache — fork-born and never-checkpointed sessions temporarily fall back to the workspace *basename*, even though the real title still lives in the session log. This plugin remembers each session's **last real wire title** in the browser (a debounced local cache: real changes coalesce into one write) and renders from memory during that window, so `/` grouping keeps working; the moment a session opens, the official data takes over and self-heals.
41
41
 
42
- **Manual cross-device sync (web ↔ desktop app)**: appearance, the default appearance, and toggles live in each device's own browser by default. The settings card adds a "Cross-device sync" section — "Pull from desktop app" on the web / "Pull from web" in the desktop app, with an **overwrite-this-device** or **merge-both-sides** mode (the union keeps each side's unique entries); the other surface's data travels through the host settings store (~/.dsh/settings.yaml, shared by both surfaces). A "Send this device's data" button next to it covers history created before this version — push once, and afterwards every edit is written to the host automatically for the other surface to pull. Expansion state stays per-device.
42
+ **Settings and appearance**: appearance, the default appearance, and toggles persist for the current DSH profile; collapse state and the local session order stay per-browser.
43
43
 
44
44
  <table>
45
45
  <tr>
@@ -55,14 +55,14 @@ Session titles nest on `/` too (e.g. `test1/plugin maintenance`). Session groups
55
55
  <table>
56
56
  <tr>
57
57
  <td align="center" width="58%"><img src="docs/screenshots/5-context-menu.png" alt="Context menu"/></td>
58
- <td valign="top"><b>Context menu everywhere</b><br/>Actions live in the right-click menu: workspace rows — rename / delete / fork / archive / customize; folder rows — rename group (updates all descendant workspaces) / customize; session &amp; session-group rows — rename / fork / archive / customize; session rows also get <b>Copy Session ID</b> (v0.30.0, mirroring dsh 0.2.1-alpha.5's fifth official menu entry — the clipboard write rides the host primitive, with a notice either way).<br/><b>Since v0.38.0 the shared host context menu owns session/workspace rows</b>: official entries and this plugin's extras (move to group / move out / customize / default preset, after a separator) share one popup, and future official entries appear automatically; group rows keep the plugin menu and older hosts fall back to it.</td>
58
+ <td valign="top"><b>Context menu everywhere</b><br/>Actions live in the right-click menu: workspace rows — rename / delete / fork / archive / customize; folder rows — rename group (updates all descendant workspaces) / customize; session &amp; session-group rows — rename / fork / archive / customize; session rows also get <b>Copy Session ID</b> (v0.30.0, mirroring dsh 0.2.1-alpha.5's fifth official menu entry — the clipboard write rides the host primitive, with a notice either way).<br/><b>Since v0.38.0 the shared host context menu owns session/workspace rows</b>: official entries and this plugin's extras (move to group / move out / customize / default preset, after a separator) share one popup, and future official entries appear automatically; group rows keep the plugin menu.</td>
59
59
  </tr>
60
60
  </table>
61
61
 
62
62
  <table>
63
63
  <tr>
64
64
  <td align="center" width="58%"><img src="docs/screenshots/4-settings-card.png" alt="Settings card"/></td>
65
- <td valign="top"><b>Settings card</b><br/>Settings → Plugins → Configuration adds a “Better Workspaces” card (official accordion style) with a <b>single-child-chain merge</b> toggle (e.g. level1 containing only AI trade renders as one row level1/AI trade) and a <b>status breathing light</b> toggle (status dots hidden by collapse bubble outward as breathing glows; on by default); a <b>default appearance</b> section configures color / glow / weight / shadow / outline toggle / outline width once for every row that was never customized (the outline ships off on fresh installs, the rest matches “no customization”) and syncs across surfaces through the host settings store. Expansion state and styling persist via the dsh client store in the browser.</td>
65
+ <td valign="top"><b>Settings card</b><br/>Settings → Plugins → Configuration adds a “Better Workspaces” card (official accordion style) with a <b>single-child-chain merge</b> toggle (e.g. level1 containing only AI trade renders as one row level1/AI trade) and a <b>status breathing light</b> toggle (status dots hidden by collapse bubble outward as breathing glows; on by default); a <b>default appearance</b> section configures color / glow / weight / shadow / outline toggle / outline width once for every row that was never customized (the outline ships off on fresh installs, the rest matches “no customization”). Settings persist for the current DSH profile; expansion state and styling additionally persist via the dsh client store in the browser.</td>
66
66
  </tr>
67
67
  </table>
68
68
 
@@ -86,9 +86,9 @@ Plain JavaScript, zero build, zero npm dependencies (dsh client baseline modules
86
86
 
87
87
  ## How it works
88
88
 
89
- The sidebar browsing region is the public `sidebar.workspaces` slot; this plugin registers the same slot with a lower priority and replaces the shipped browser with the tree. All data flows through the slot’s standard snapshot hooks and injected host actions — no private APIs.
89
+ The sidebar browsing region is the public `sidebar.workspaces` slot; this plugin registers the same slot with a lower priority and replaces the shipped browser with the tree. All data flows through the slot’s standard snapshot hooks and injected host actions. The one exception is **renaming a closed session without opening its history**: rc.1 only exposes `sessions.binding` / `sessions.using` (`using` opens history), so the fast path still reads `sessions.manager`. The code marks it **PRIVATE BRIDGE**; remove it as soon as the host makes that path public.
90
90
 
91
- The add flow is entirely official: this plugin's `sidebar.workspaces` registration **declares** the directory-flow child hole and consumes it through `renderSlot` (the same children pattern the official WorkspaceBrowser uses); the official composed occupant (native chooser / in-app browser) owns the whole picking interaction. This plugin, as the owner, just creates the workspace and starts a session after the pick. The mechanism works on dsh 0.1.2+ hosts — either upgrade order converges.
91
+ The add flow is entirely official. This plugin **does not declare** either directory-flow child hole (child-hole declaration is exclusive, and the entry that shadows the seat cannot receive `renderSlot` authorization). The sidebar probes the backend: `native` calls the official `pickDirectory()`; `browse` reads the official occupant from the slot ledger (component plus its own inject face), supplies the owner callback contract (open / busy / onPicked / onCancel / onError), and renders it directly. The conversation empty-state picker uses the same reading. The official composed occupant (native chooser / in-app browser) owns the whole picking interaction; this plugin, as the owner, just creates the workspace and starts a session after the pick. Requires dsh >= 0.2.2-rc.1.
92
92
 
93
93
  View state (folder collapse, session expansion), custom styling and plugin settings persist browser-side via the dsh client store (`dsh.betterWorkspace.view.v1`).
94
94
 
@@ -98,11 +98,10 @@ Same `dsh-better-*` family, zero overlap: [dsh-better-sidebar](https://github.co
98
98
 
99
99
  ## Version compatibility
100
100
 
101
- - **dsh 0.1.6-alpha.1**: both the primitives icon set and the browser injection face changed; this plugin **adapts automatically since 0.10.2**. The icon grid only lists glyphs this host actually exports (the retired `IconSendOutline16` resolves to the equivalent `IconSendOutline14`, so a previously saved choice never turns into an empty icon slot), and session drag-to-reorder falls back to a browser-local order when the host no longer injects `insertSessionBefore` — **no feature is lost**. Either upgrade order (plugin first or dsh first) converges.
102
- - **dsh 0.1.6-alpha.2**: the settings pages were reworked — since **0.12.0** this plugin registers its settings card on **both seats** (the pre-alpha.2 Settings → Plugins card and the alpha.2+ Plugins panel's bundle page, keyed by package name); the tree gains the **disk-nesting layer** (official workspace-tree semantics) and add-workspace rides the official directory flow (native chooser / official in-app browser).
103
- - **dsh 0.2.2-alpha.2**: the hand-drawn session rows now render the shipped `sidebar.session.row.trailing` seat (after the time, before the pin badge; blank rows skip it), so the official experimental worktree / PR icons still appear after this plugin takes over the sidebar. The plugin also accepts the host's blank-session reuse semantics (without `agentPreset`, a blank from any preset in the same workspace may be reused). The seat is capability-probed: hosts without it keep rendering the row tail and never error. The compatibility floor stays `>=0.1.6-alpha.2`.
104
- - **dsh 0.2.2-alpha.3**: session/workspace rows join the shipped unified context menu (`contextMenus`) — official entries and this plugin's extras share one popup, the extras sit at order 700 after a separator, and future official entries appear automatically. Workspace-group / session-group rows are plugin-private virtual objects and keep the plugin menu; older hosts without the service fall back to the local menu, and the compatibility floor stays `>=0.1.6-alpha.2`.
105
- - **Across surfaces**: web and desktop share one set of client assets; appearance / switches sync manually through the settings card, while **collapse state and the local session order stay per-browser** by design.
101
+ - **Runtime floor: dsh >= 0.2.2-rc.1, Node.js >= 24.9.0.** Since v0.39.0 this plugin maintains only this host generation; it keeps no probes or fallbacks for 0.1.x / 0.2.0 / 0.2.1 / pre-rc.1 0.2.2 prereleases.
102
+ - **rc.1 contract**: the global standard hooks are `useSessionStatus` / `useSessionAccess`; session/workspace rows use the shipped `contextMenus`; session rows render the shipped `sidebar.session.row.trailing` and `sidebar.session.row.leading` seats; settings register only the official `plugins.bundle.config` seat.
103
+ - **Settings persistence**: the plugin Config exposes only four volatile fields — `compactChains` / `statusPulse` / `styling` / `appearance`; other view preferences stay in the browser-local store and are never written to the host. Manual cross-device sync is gone with the shared `settings.yaml` era.
104
+ - **User-data migration**: old snapshots with `workspaceTitleSlash`, a missing `stroke` key, or retired icon names are still read with per-era defaults, so upgrading never changes existing grouping or appearance. This compatibility covers **this plugin's own old data only**, not old hosts.
106
105
 
107
106
  ## Limitations / roadmap
108
107
 
package/dsh.plugin.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-better-workspace",
3
- "version": "0.38.2",
3
+ "version": "0.39.0",
4
4
  "main": "./src/index.js",
5
5
  "description": "侧边栏工作区树:按官方磁盘目录嵌套(官方 workspace-tree 语义),可选按名称中的 / 分组(默认关闭,设置里开启);新会话页的工作区选择器同树。Workspace tree for the DSH sidebar workspace list, nested by official disk folders with optional \"/\"-name grouping; the New Session workspace picker shows the same tree.",
6
6
  "engines": {
7
- "dsh": ">=0.1.6-alpha.2"
7
+ "dsh": ">=0.2.2-rc.1"
8
8
  },
9
9
  "contributes": {
10
10
  "tools": [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-better-workspace",
3
- "version": "0.38.2",
3
+ "version": "0.39.0",
4
4
  "description": "侧边栏工作区树:按官方磁盘目录嵌套(官方 workspace-tree 语义),可选按名称中的 / 分组(默认关闭,设置里开启);新会话页的工作区选择器同树(同一份视图选项即时同步);添加工作区走官方目录流。Workspace tree for the DSH sidebar: disk-path nesting (official workspace-tree semantics), with optional \"/\"-name grouping (off by default), and the same tree in the New Session workspace picker; add-workspace rides the official directory flow.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -18,8 +18,8 @@
18
18
  "./package.json": "./package.json"
19
19
  },
20
20
  "engines": {
21
- "node": ">=18",
22
- "dsh": ">=0.1.6-alpha.2"
21
+ "node": ">=24.9.0",
22
+ "dsh": ">=0.2.2-rc.1"
23
23
  },
24
24
  "dsh": {
25
25
  "bundle": {
@@ -65,16 +65,12 @@
65
65
  "license": "MIT",
66
66
  "peerDependencies": {
67
67
  "@deepseek-ai/cordis": "^4.0.1",
68
- "@deepseek-ai/dsh": ">=0.1.6-alpha.2",
69
- "@deepseek-ai/dsh-settings": ">=0.1.0-rc.7",
70
- "@deepseek-ai/schemastery": "^3.18.1"
68
+ "@deepseek-ai/dsh": ">=0.2.2-rc.1",
69
+ "@deepseek-ai/schemastery": "^3.19.0"
71
70
  },
72
71
  "peerDependenciesMeta": {
73
72
  "@deepseek-ai/dsh": {
74
73
  "optional": true
75
- },
76
- "@deepseek-ai/dsh-settings": {
77
- "optional": true
78
74
  }
79
75
  },
80
76
  "homepage": "https://github.com/KannaKuron/dsh-better-workspace",
@@ -83,6 +79,6 @@
83
79
  },
84
80
  "icon": "./icon.svg",
85
81
  "devDependencies": {
86
- "@deepseek-ai/schemastery": "^3.18.1"
82
+ "@deepseek-ai/schemastery": "^3.19.0"
87
83
  }
88
84
  }