DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

dongasai /

dongasai/running-sessions-float

Verified

This plugin has no description yet.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@8adf6c85

@dongasai/running-sessions-float

在 DSH Web GUI 左侧栏底部的动作区里放一块「进行中」坞:把正在跑、卡在等你处理和刚跑完还没看过的会话收成一张小列表,点一行就把主视图切过去;没有这类会话时收成一行细字,只留「暂无进行中」。坞是布局里的真实一块,排在这排动作的最上面,不浮在会话列表上。

官方侧栏本来就会在会话行上标运行状态点(StateDot)和待处理状态,但那些行分散在各个工作区分组里 —— 组一折叠就看不见,要判断「现在有几个会话在等我」得逐个展开找。

这个坞不新增数据源,只做聚合:复用同一套标准 Hook(useSessions / useSessionStatus),筛出 running、pending 或 completionUnread 的会话,按最近更新时间排,固定在侧栏底部动作区。它不轮询、不落盘、没有 Host 状态,也不改任何会话。

想知道 看
怎么装、怎么用、怎么排错 本文件
为什么这么实现(槽位取舍、过滤规则、空态、locale 降级) IMPLEMENTATION.md
给 agent 的约束、命令、改动连带项 AGENTS.md

本仓库是 DSH 独立插件仓库,当前只有这一个插件;仓库根就是插件包 —— package.json、index.js、client.js、cordis.patch.yml、locale/ 都在根目录,装哪个 profile 都指到仓库根。

功能列表

能力 说明
进行中聚合 running === true 的会话进坞,行尾「运行中」
待处理聚合 有 pendingInteraction 的会话进坞,按类型显示「等待审批 / 计划待审 / 等待回答」;待处理优先于运行中
完成未读聚合 completionUnread === true(主视图之外停了运行、结果还没看过)的会话进坞,行尾灰字「已完成」;打开该会话后官方清掉这个标记,行随之消失
一键切换 点行调用 uiWorkspace.openSession,主视图切到该会话
计数徽标 坞头右侧显示当前行数
头部状态点 只要还有会话在跑或在等你处理,绿点就脉冲;只剩「已完成」提醒时切成静止的 6px 成功色圆点,不再假装有任务在跑
空态细行 无进行中会话时收成一行无边框细字,灰点静止,不显示计数
中英双语 内置 zh / en 两套文案,跟随界面语言;locale 服务缺失时回落中文
仅 Web 客户端 dsh.client.platform: web;headless 等没有 Web 客户端的 profile 不加载它
占位不遮挡 注册在 sidebar.footer.action(侧栏底部动作区),是布局里的真实一块,不盖住会话列表
与官方入口共存 坞独占动作区最上面一行,用量统计 会话管理 等原有入口照旧排在它下面,一个都不少
键盘可达 每行是 <button>,可 Tab 聚焦,Enter / Space 触发,:focus-visible 有品牌色描边

不提供:停止运行、回答提问 / 批准审批、归档过滤、设置项 / 开关。那些动作属于官方浮层,坞刻意不复制第二套交互。

快速开始

四步:装 → 确认装配行 → 用 → 卸载。

1. 装插件

target 就是仓库根(package.json、index.js、client.js、cordis.patch.yml、locale/ 都在根目录)。 2026-10-25 之前包体塞在同名子目录 running-sessions-float/ 里,github: 直装和 #tag 钉版本全都装不出来 (pnpm 把没有 package.json 的根当空壳,依赖名落成 running-sessions-float#0.1、版本 0.0.0,随后 dsh plugin add 报 cannot resolve profile bundle);那层子目录已经删掉,现在三种装法都指仓库根。

方式一:Web 界面(推荐)

DSH Web → 左侧栏 插件 → 添加插件 → 填仓库根的绝对路径(在仓库根执行 realpath .)→ 安装 → 装完点 立即启用。

仓库地址(clone 用):https://github.com/dongasai/running-sessions-float.git

  • 「添加插件」接受:包名(可带版本)、Git 地址、压缩包、本地绝对路径。
  • 装完不点 立即启用,就只是「装着但没启用」。
  • 侧栏这个「插件」页才能装和开关;设置 → 内置插件 里的清单是只读的。

方式二:命令行 · git 源(分发)

dsh plugin --profile web add github:dongasai/running-sessions-float
# 或
dsh plugin --profile web add git+https://github.com/dongasai/running-sessions-float.git
# 钉版本(URL 后加 #<tag>,锁到某个发布版本来复现问题 / 稳定使用)
dsh plugin --profile web add github:dongasai/running-sessions-float#0.3

dsh plugin --profile <name> <pnpm args> 把参数转发给该 profile 目录里的 pnpm。装进来的是副本:之后改本仓库代码不影响已装的副本(想边改边用就走方式三)。

  • --profile 必填(不写直接报 required option '--profile <name> not specified')。
  • 必须带 git+ 或 github: 前缀。git@github.com:owner/repo.git 这种 scp 写法不会被认成 git spec,pnpm 会把它当路径,装出一条指向不存在目录的 link: 死链。
  • 钉版本:URL 后加 #(上面第三条就是钉 0.3),tag / 分支 / commit 都行。本仓库当前 tag 是 0.3,对应 package.json 的 0.3.0 —— 不带 # 则跟 main 走,每次装到的都可能是新代码。0.2 及更早的 tag 是「包在子目录」的旧布局(0.1 还是旧包名 @local/running-sessions-float),钉它们装不出当前这套,只能走「克隆 + checkout」。
  • pnpm 默认会拦 prepare 等依赖构建脚本;本包没有任何构建步骤(client.js 是手写的浏览器 bundle,由 Host 直接读盘发出),不会遇到。

本机实测(0.3,临时 DSH_HOME):github:dongasai/running-sessions-float#0.3 装完依赖名是 @dongasai/running-sessions-float github:dongasai/running-sessions-float#0.3(不是旧布局那种 running-sessions-float#0.1 0.0.0),副本 package.json 版本 0.3.0,dsh.profile.bundles 自动登记,--dump-config 能查到装配行(见下面「装完确认」)。

方式三:命令行 · 本地目录(link,开发)

# 在仓库根执行;--profile 必填,web 换成你要装进的 profile
dsh plugin --profile web add "link:$(pwd)"

dsh plugin --profile <name> <pnpm args> 把参数转发给该 profile 目录里的 pnpm。link: 装的是软链:改仓库里的 client.js,客户端半边会在一两秒内换新(见「生效条件」)。

这条命令要写 profile 目录,在宿主 shell 里跑;受限的 Agent 沙箱通常写不了 ~/.dsh。

让 Agent 装(等价路径,不是命令行):action: install_bundle、target: link:<仓库绝对路径>(或 github:dongasai/running-sessions-float#0.3)。这个动作需要 danger-full-access 批准(它会改 profile、装包、可能跑安装脚本);返回 application: applied 才算当场生效,restart-required 表示要重启 Harness。

钉版本:克隆 + checkout tag

tag 0.3 真实存在,对应 package.json 的 0.3.0。想连 git 历史一起钉住时这样装:

git clone https://github.com/dongasai/running-sessions-float.git
cd running-sessions-float
git checkout 0.3
dsh plugin --profile web add "link:$(pwd)"

0.2 及更早的 tag 里包还在子目录,realpath 要指到 <clone>/running-sessions-float(那一层已在新版删掉)。

包名与旧版本

包名是 @dongasai/running-sessions-float(2026-10-23 从 @local/running-sessions-float 改过来,与本机其它自研插件同一 scope)。改名是破坏性的:

  • 0.1 及更早的 tag 与 main 上 2026-10-23 之前的提交里,package.json、cordis.patch.yml、client.js 的 client id 都还是 @local/...;装那些版本得到的插件页条目与装配 id 都是旧名。
  • 已装旧名的 profile 不会自动迁移:依赖名、dsh.profile.bundles 选中项、node_modules/@local/running-sessions-float 软链都指向旧名。按下面「换包名时怎么升」重装一次即可。

换包名时怎么升(本机实测流程):

# 1) 移除旧名(先卸再装,避免两个名字同时被装配)
dsh plugin --profile web remove @local/running-sessions-float
# 2) 用当前仓库装新名
dsh plugin --profile web add "link:$(pwd)"
# 3) 确认依赖名、bundles 选中项、软链三处都换了
grep -n running-sessions-float ~/.dsh/profiles/web/package.json
ls -l ~/.dsh/profiles/web/node_modules/@dongasai/running-sessions-float
# 4) 确认装配行(应显示 @dongasai/running-sessions-float)
dsh --profile web --dump-config | grep -A2 running-sessions-float
# 5) 重启正在跑的实例(插件行在启动时合成)

pnpm 移除链接包时不一定会清掉旧 node_modules/@local/... 软链 —— 那条孤立软链不在 loader entries 里、不会被加载,但要留意将来 pnpm install 的歧义。确认它指向本仓库这个包再删(realpath 核验后再 rm,别删成别的插件的链接)。

装完确认

命令行可以直接看合成后的 profile 树(只读,不启动服务):

dsh --profile web --dump-config | grep -A2 running-sessions-float

期望输出(本机实测):

# == @dongasai/running-sessions-float
- id: running-sessions-float
  name: '@dongasai/running-sessions-float'

运行中的实例要重启才会加载它(插件行在启动时合成)。

五条通用坑:

  1. --profile 必填 —— 不写直接报 error: required option '--profile <name>' not specified。
  2. 只加依赖、没登记 dsh.profile.bundles = 装了不挂载 —— 命令行的 dsh plugin add 写的是依赖,挂载还取决于 bundles;实测清空 bundles 后 --dump-config 输出为空,所以装完必须用上面的命令验一遍。
  3. git spec 必须带 github: / git+ 前缀 —— git@github.com:owner/repo.git 这种 scp 写法会被 pnpm 当成本地路径,装出一条指向不存在目录的 link: 死链。
  4. 钉版本的 tag 必须真实存在 —— 本仓库是 0.3(对应 0.3.0)。0.2 及更早的 tag 是「包在子目录」的旧布局、0.1 还是旧包名 @local/running-sessions-float,钉它们装不出当前这套;那些版本只能「克隆 + checkout + link 子目录」。
  5. 不要在仓库根下再套一层同名子目录 —— 根没有 package.json 时 pnpm 会把仓库当空壳(依赖名落成 running-sessions-float#0.3、版本 0.0.0),dsh plugin add 随后报 cannot resolve profile bundle。2026-10-25 已按这条把结构改回「根即包」。

本仓库 private: true、未发布 npm,没有 registry 装法;package.json 里没有声明任何 DSH peer 依赖,不会触发版本兼容闸。

2. 用起来

装完等一两秒 —— 客户端半边在启动时加载,Web 组合会通过 client-hmr 把新模块推给页面;没出现就刷新一次页面。侧栏底部、设置行上方出现坞:

  1. 有进行中 / 待处理 / 刚跑完未读的会话时,坞头是「进行中」+ 计数徽标,下面一行一个会话:左边标题、右边状态。
  2. 行按会话的 updatedAt 从新到旧排;刚发过消息的会话在最上面。
  3. 点一行:主视图切到那个会话(不是开新页签)。悬停有提示「打开这个会话 — 标题」。
  4. 没有这样的会话时:坞收成一行无边框细字,文字「暂无进行中」,绿点变灰点、停止脉冲。
  5. 行多了列表在坞内滚动(坞最高 min(28vh, 200px),给下面的官方入口和设置行留位置)。

3. 确认它真的在工作

  • 插件页「已安装」列表里出现 进行中会话坞(英文界面:Running Sessions Dock)。
  • 装配层认得它:--dump-config 里能查到装配行(命令与期望输出见「快速开始 → 装完确认」)。
  • 在另一个会话发一条要跑一会儿的消息,回到当前会话:坞里应多出一行「运行中」,计数 +1。
  • 点那一行:主视图切过去。
  • 让某个会话卡在审批上(例如让它执行一条需要确认的命令):行尾应变成「等待审批」。
  • 让一个会话在你的另一个页签 / 主视图之外跑完:它的行尾应变成灰字「已完成」,而且不会从坞里掉出去。
  • 点那行「已完成」进去看一眼再回来:官方清掉 completionUnread,这行应当消失。
  • 把所有会话停下来且都看过:坞应收成一行「暂无进行中」细字。

看不到坞时按「排错」表逐条对。

4. 卸载

Web 插件页:停用这个插件 → 移除。或让 Agent 执行:

action: remove_bundle
target: @dongasai/running-sessions-float

remove_bundle 会先取消 bundle 选中、再删包。不要只跑 pnpm remove:依赖没了、dsh.profile.bundles 里的选中项还在,下次装配会解析不到这个包。

界面长什么样

侧栏(默认 280px,最窄 264px)
┌────────────────────────────┐
│ 工作区 A                   │
│  · 会话 1                  │
│ 工作区 B                   │
│  · 会话 2                  │
│  · 会话 3                  │
│                            │
│  ┌──────────────────────┐  │ ← 坞:侧栏底部动作区顶部
│  │ 进行中             3 │  │    独占一行,排在官方动作之上
│  │ 会话 2        运行中 │  │    最高 min(28vh, 200px)
│  │ 会话 3      等待审批 │  │    列表在坞内滚动
│  │ 会话 1        已完成 │  │    跑完但还没看过的也在这里
│  └──────────────────────┘  │
│  用量统计                  │ ← 原有入口照旧,排在坞下面
│  会话管理                  │
│  [设置]                    │
└────────────────────────────┘

逐块说明:

  • 坞头:状态点 + 标题 + 计数。只要还有会话在跑或在等你处理,绿点就脉冲(1.8s 循环);只剩「已完成」提醒时换成 6px 静止成功色圆点;空态灰点静止。
  • 行:整行是一个按钮。标题单行省略,状态文字不换行、右对齐。
  • 状态色:运行中用 --dsw-alias-state-success-primary;待处理用 --dsw-alias-state-warn-primary;已完成用次级文字色 --dsw-alias-label-tertiary(它是提醒,不是告警,不抢眼);其余文字 / 边框 / 背景都走主题 token,明暗主题都跟随。
  • 空态:不画边框、背景透明,收成 padding: 2px 6px 的一行 11px 次级色文字。
  • 位置:挂在 sidebar.footer.action 槽位,order: -10,排在所有官方底部动作之前;width: 100%,高度由内容决定,最高 min(28vh, 200px)。它占真实布局:坞变高时上方会话列表相应变矮,而不是被盖住。
  • 独占一行:宿主把这一行排成不换行的 flex-direction: row,而这条生态里的底部入口(用量统计 / 会话管理 / 搜索)都写着 flex: 0 0 100%,意思都是「我要占满一整行」。不换行时第一个就把别人挤出可视区。坞挂载时给那一行加 flex-wrap: wrap(promoteFooterContainer,另有一条等价 :has() 规则管首帧),于是每个入口各占一行、都在坞下面。
  • 为什么不是改成列:试过 flex-direction: column —— 列里 100% 会按高度算,搜索插件那个入口直接涨成整块 140px,把别人顶出屏幕。只有「可换行的行」同时满足它们的 100% 宽度语义。
  • 窄栏:侧栏折叠成 56px 窄栏时,槽位只给 wide: false,坞换成 36px 圆点 + 计数的圆片(rsf-rail),不摊开列表。
  • 点击范围:坞是普通文档流元素,没有浮层吃掉点击的问题;坞外的内容照常可点。

它怎么判断「进行中」

会话目录与运行状态都来自框架标准 Hook,插件自己不做任何请求:

条件 是否进坞 行尾状态
有 pendingInteraction 是 按 kind 归类(见下表),优先于运行中与已完成
running === true 且无待处理 是 运行中
completionUnread === true 且已停下 是 已完成(灰字)
blank === true(新建但还没发消息) 否 —
origin === 'subagent' 否 —
其余空闲会话(含已看过结果的结束会话) 否 —

三个保留条件之间是并集,显示优先级是 待处理 > 运行中 > 已完成:一个会话既在跑又有待审批时显示「等待审批」,刚跑完但还没看过时显示「已完成」。

  • running 优先取状态快照;状态里没有这个字段(或没有该会话的状态)时,退回列表快照的 summary.running。
  • completionUnread 只从状态快照读,缺字段就当作「已读过」:列表快照里没有对应事实,猜一个会让坞凭空多出一行「已完成」。官方在主视图里停下运行时不会置这个标记,所以坞里出现的每一条「已完成」都是你没在当前视图里看过的。
  • kind 是各域自己定的字符串,插件只做大小写无关的包含匹配:
kind 实际值 坞里显示
approval 等待审批
permission(当前没有发布者,兼容用) 等待审批
plan-review 计划待审
question 等待回答
其它 / 未知 等待回答

官方目前会发布 approval、plan-review、question 三种;未知 kind 不会让会话消失,统一落到「等待回答」。

生效条件(客户端半边)

本插件 Host 半边是空的(index.js 只有一个空 apply()),没有 Host 状态、路由或配置,所以不存在「Host 改了要重启」的问题;所有行为都在浏览器半边。

  • 装的是 link:,改 client.js:Web 组合里的 client-hmr 每 500ms 轮询 bundle 文件的 mtime / ctime / size,变了就换新 revision 并通过 /plugins/events 推给浏览器;通常一两秒内自动换新,不用刷新。没换再刷新页面。
  • 部署没挂 client-hmr:Host 内存里还是旧字节,刷新页面也不够 —— 重新安装或重启 Harness 才会重读。
  • 装的是副本(git / tarball / npm):改仓库代码不影响已装副本 → 重新安装。
  • 改 package.json 的 dsh.client / dsh.bundle 字段:需要重新装配(重新安装或重启对应 profile)。

结构

running-sessions-float/                 ← 仓库根 == 插件包(安装 target)
├─ package.json                        # name / version / exports / files / dsh.bundle + dsh.client
├─ cordis.patch.yml                    # insert 一行插件入口
├─ index.js                            # Host 半边:export function apply() {}(8 行)
├─ client.js                           # 浏览器半边:CSS + 组件 + sidebar.footer.action 注册(477 行)
├─ locale/en.json                      # 插件页元数据(meta.title / meta.description)
├─ locale/zh.json                      # 同上,中文
├─ icon.svg                            # 插件图标
├─ README.md
├─ IMPLEMENTATION.md
├─ AGENTS.md
├─ test/smoke.mjs                      ← 无 DOM 冒烟 + 包契约(42 项)
└─ .agents/index.json                  ← 架构扫描状态:模块清单 / 覆盖率 / 缺口

README.md / IMPLEMENTATION.md / AGENTS.md / test/ / .agents/ 靠 package.json 的 files 白名单挡在包外,只进 git。

文件 行数 作用
package.json 32 包声明:dsh.bundle.patch 指向 patch,dsh.client 声明 web 平台、启动即加载、依赖 session UI 包
cordis.patch.yml 3 insert 一行 running-sessions-float → @dongasai/running-sessions-float
index.js 8 Host 半边,空 apply();不提供服务、不注册工具、不挂路由
client.js 477 浏览器半边:样式、组件、locale 注册、sidebar.footer.action 注册
locale/*.json 6 × 2 只给插件页的标题 / 描述;界面文案在 client.js 的 DICTS 里
icon.svg 11 插件图标
AGENTS.md — 给 agent 的命令、硬约束与改动连带项
test/smoke.mjs 324 无 DOM 组件冒烟 + 包契约(42 项)

两侧注入

  • Host:无 inject。index.js 只导出 apply(),不依赖任何 Host 服务。
  • Client(client.js 模块返回):inject: ['slots'];apply(ctx) 里 ctx.get('locale') 与 ctx.slots.inject('sidebar.footer.action', ...);uiWorkspace 不在这里取,而是每次点击时现取(它由启动更晚的 workspace 插件补挂)。
  • 加载顺序(package.json → dsh.client.inject):@deepseek-ai/dsh-client-ui-session —— 它提供 useSessions / useSessionStatus 这两个全局标准 props,必须排在它之后激活。
  • 启动加载:immediately: true,启动时就加载,不等打开某个面板。

扩展点占用表

扩展点 类型 id / 命名空间 order priority patterns 条件 说明
sidebar.footer.action list 槽位 running-sessions-float -10 未设 无(该槽没有 patterns) 无条件 唯一 UI 注册;list 槽按 order 升序渲染,负值排在官方动作(默认 0)之前
locale 字典命名空间 local.runningSessions — — — locale 服务存在时 注册 en / zh 各 8 个 key(title running approval plan answer done empty openHint);不在时用内置中文
uiWorkspace 可选服务 — — — — 每次点击 点击时才 ctx.get('uiWorkspace') 并调 openSession;不要在 apply 时缓存 —— 它由启动更晚的插件提供,缓存到的是 undefined;缺失则点击无动作

不占 sidebar / sidebar.workspaces.* / composer.* 等其它槽位;sidebar.footer.action 是本插件唯一的 UI 注册。

安全模型

  • 没有 Host 路由、没有工具、没有文件读写、没有网络请求;只订阅两个官方 Hook 并读它们的快照。
  • 没有 npm 依赖(package.json 无 dependencies),不加载外部资源;样式、文案、图标都在包内。
  • 没有持久化:不写 localStorage、不写状态文件,坞的内容全部来自官方快照。
  • 安装动作本身要写 profile(plugin_manager 路径需要 danger-full-access 批准);插件运行时不要求额外权限。

边界说明:这不是权限隔离。坞只是把当前用户本来就能在侧栏看到的会话状态聚合到一块;能打开这个 Web GUI 的本机用户,本来就能看到同样的信息。插件没有扩大任何能力,也没有新增数据出口。

与 Agent 的关系

  • 不注册工具、不注入提示,Agent 侧看不到这个坞,也不会因为装了它改变行为。
  • 坞里显示的就是 Agent 的运行状态(running / pendingInteraction),只读展示,不参与调度。
  • 点行只切换视图,不会向会话发消息、不会批准审批、不会回答提问 —— 那些动作仍在官方浮层里由人完成。

排错

现象 原因 处理
插件页装不上,报 not-bundle 或找不到 manifest target 没指到仓库根(或指到了已删除的旧子目录) 指到仓库根;package.json 就在根目录
装完界面没变化 只装没启用 / profile 启动时装配 插件页点「立即启用」;application: restart-required 时重启 Harness
坞没出现,插件却是启用状态 页面还是旧模块代次 / 推送还没到 等一两秒;刷新页面;仍无则重启 Harness(无 client-hmr 的部署)
坞一直「暂无进行中」 没有 running / pending / 完成未读的会话;或它们都是空白 / subagent 会话(被过滤) 去另一个会话发一条消息;确认不是刚建的空会话
会话跑完了坞里却没有「已完成」行 那个会话当时是主视图(官方会把 completionUnread 清掉),或它已归档 / 被删 属预期:主视图里跑完不算「未读」
「已完成」行点了也不消失 点击只切视图,官方在会话成为主视图后才清标记;状态快照可能滞后一拍 等一拍;仍不消失就刷新页面确认是不是旧 bundle
点行没反应 部署里没有 uiWorkspace(无工作区 UI),或会话已删 属于降级行为;换有工作区的部署
所有行都点不动、但坞数据显示正常 旧版把 uiWorkspace 缓存在 apply 里,而它由启动更晚的插件补挂 → 缓存永远是 undefined 已修:改成点击时现取;更新到含该修复的版本
改了 client.js 没变化 装的是副本,或部署没挂 client-hmr link: 装等推送,没挂就重启 Harness;副本重新安装
文案不跟随界面语言 locale 服务不可用,回落中文 检查界面语言设置;locale 服务由官方加载
坞把上方会话列表挤短了 坞在底部动作区里占的是真实布局,不是浮层 预期行为:坞展开时列表相应变短;行多时坞内滚动,最高 200px
用量统计 / 会话管理 不见了 坞没能给那行加 flex-wrap: wrap,不换行时全宽坞把兄弟入口挤出可视区 看控制台有没有 closest 报错;宿主改过 data-slot 锚点时改选择器
卸载后仍被装配 只跑了 pnpm remove,没取消 bundle 选中 从插件页卸载,或用 plugin_manager 的 remove_bundle(先取消选中再删包)
按 #0.2 或更早的 tag 装不出来 那些 tag 里包还在子目录,URL 钉版本要求仓库根就是包 克隆后 git checkout <tag>,再 link: 到 <clone>/running-sessions-float(见「装法五条坑」第 4 条)
#0.3 装不出来,或跑出 cannot resolve profile bundle 仓库根没有 package.json(有人又把包塞回子目录了) 恢复「根即包」结构:package.json / index.js / client.js / patch / locale 必须在根(见「装法五条坑」第 5 条)
坞里的行数比侧栏会话少 空白会话与 subagent 会话被刻意过滤 预期行为;去侧栏对应工作区看它们
改了 locale/*.json 文案没变 那两份只放插件页 meta,坞内文案在 client.js 的 DICTS 改 DICTS 后重新装;插件页 meta 要重新装配才刷新

怎么验证

命令行能覆盖的部分

# 1) 语法
node --check client.js
node --check index.js

# 2) 包声明与 patch
node -e '
const fs = require("fs");
const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
console.log(pkg.name, pkg.version);
console.log(pkg.dsh.bundle.patch, pkg.dsh.client.inject);
'
# 预期:@dongasai/running-sessions-float 0.3.0
#       ./cordis.patch.yml [ '@deepseek-ai/dsh-client-ui-session' ]

# 3) 组件行为 + 包契约(无 DOM,42 项)
node test/smoke.mjs
# 预期:42 行 PASS + ALL PASS

test/smoke.mjs 用 Node 的 vm 加载 client.js,用 React 桩渲染组件,覆盖 34 项行为:过滤(blank / subagent / 空闲)、排序、五种行状态(运行中 / 等待审批 / 计划待审 / 等待回答 / 已完成)、计数徽标、点击转发(含「已完成」行、含走 inject face 的包装函数:注入的 openSession 必须真能经 uiWorkspace 跳转、apply 时不许缓存它、晚到的 uiWorkspace 仍可用、缺失时不抛异常)、头部状态点(活跃脉冲 / 只剩已完成时静止 / 空态灰点)、空态、locale 回落、无 openSession 时不抛异常、en 字典注册、窄栏圆点(有 / 无计数 / 只剩已完成时静止)、CSS 里没有 position: fixed(坞不再浮层)、「已完成」配色只用主题 token、挂载时把底部动作行改成可换行(锚点是该行唯一子元素时也要改)、卸载时还原;另加 8 项包契约:client id 与包名一致、注册在 sidebar.footer.action、order 为负(排在官方动作之前)、patch 行指向本包、files 含运行文件、zh / en 字典键完全一致、源码里每个 t('key') 两本字典都有、client bundle 只 require('react')。34 + 8 = 42,与 node test/smoke.mjs 的 PASS 行数一致。样式与真实布局只能在浏览器看,见下一节。

只能在浏览器里看的(逐条打勾)

  • 侧栏底部、设置行上方出现坞;有进行中会话时标题「进行中」,右侧有数字徽标。
  • 行按最近更新时间排,刚发过消息的在最上面。
  • 行标题过长显示省略号,不换行、不撑宽坞。
  • 「已完成」行尾是灰字(不抢眼、不是橙色告警),和「运行中」的绿色、待处理的橙色区分得开。
  • 运行中行尾是绿色「运行中」;待处理是橙色。
  • 点一行,主视图切到该会话;悬停提示「打开这个会话 — 标题」。
  • 没有进行中会话时收成一行细字,文字「暂无进行中」,点为灰色且不动,没有边框。
  • 切换界面语言(中 / 英):标题、状态、空态文案都跟着变。
  • 切明暗主题:边框、背景、文字都跟随,没有写死颜色。
  • Tab 能聚焦到行,聚焦时有品牌色描边,Enter / Space 能打开。
  • 侧栏拖宽 / 收窄:坞跟着侧栏宽度走(width: 100%),不再固定 252px。
  • 坞展开时上方列表相应变短,没有被坞盖住、点不到的行。
  • 侧栏折叠成 56px 窄栏:坞变成 36px 圆点 + 计数,不摊开列表、不压主内容。
  • 让一个会话停在审批 / 计划审阅 / 提问上:行尾分别显示「等待审批 / 计划待审 / 等待回答」。
  • 新建一个空白会话(不发消息):它不出现在坞里。
  • 启动一个 subagent:它不出现在坞里。
  • 行数很多时:列表在坞内滚动,坞不超过 200px / 28vh。
  • 坞下面「用量统计」「会话管理」这些原有入口都还在,且各占一行。
  • 在别的页签 / 主视图之外让一个会话跑完:坞里多出一行灰字「已完成」,头部绿点变成静止的小圆点(不再脉冲)。
  • 点那行「已完成」进去看,再回来:该行消失,计数 -1。
  • 任何一行(运行中 / 待处理 / 已完成)点下去都能切到对应会话 —— 三种状态走的是同一个点击路径。
  • 窄栏(56px)时只剩「已完成」会话:圆片里仍是计数,圆点静止、不脉冲。

已知边界

每条都带原因与代价;没解决之前不要从文档里删。

  • 坞在侧栏最底部,只看得见「进行中」的一屏:坞最高 min(28vh, 200px),行再多要在坞内滚动。代价:会话特别多时,坞和上方列表抢高度 —— 这是「不遮挡 + 不挤掉官方入口」换来的(浮层不占高度,但会盖住行)。
  • 窄栏只剩计数:折叠成 56px 窄栏时只有圆点 + 数字,看不到标题、也点不开行。代价:想看列表得先展开侧栏。
  • 靠负 order 抢位:order: -10 保证坞排在官方底部动作(默认 0)之前。代价:官方若也发负 order,顺序会变;这是槽位顺序契约,不是坞能单方面决定的。
  • 改宿主布局的代价:宿主给的槽位内容是 display: contents 锚点,本身没有「独占一行」的契约。坞挂载时用 closest('[data-slot="sidebar.footer.action"]') 找到锚点、给它父元素加 flex-wrap: wrap(另有一条等价 :has() 规则管首帧),这样每个入口各占一行、官方入口排在坞下面。代价:宿主改这个 data-slot 锚点、或换掉这一层容器时,坞会和官方动作挤在同一行,需要回来改选择器。
  • 只做导航:点行只切换会话,不能停止运行、不能回答提问 / 审批。那些动作在官方浮层里;坞刻意不复制第二套交互。
  • 「已完成」只覆盖主视图之外的结束:completionUnread 由官方置位,而官方在会话是主视图(retainedBy.mainView > 0)时会清掉它。代价:你正盯着某个会话看它跑完时,它不会以「已完成」留在坞里 —— 那是「你已经看过」的正常情况,坞不去猜「其实没仔细看」。
  • 「已完成」没有单独清除按钮:唯一清除方式是打开该会话(官方随即清标记),或等下一轮 reconcile。代价:不想看的提醒也得点进去一次才消失;补一个「全部标记已读」需要 Host 或官方接口,超出本插件的只读边界。
  • 不显示 subagent:origin === 'subagent' 被过滤。代价:子代理在跑什么,得进主会话看;换来的是一个任务不会在坞里裂成多行。
  • 不显示空白会话:blank === true 被过滤。代价:刚新建、还没发消息的会话不出现在坞里(它本来也不算「进行中」)。
  • 排序只看 updatedAt:不跟随侧栏的固定 / 手动排序。代价:长时间不写消息的旧会话可能排在刚启动的会话后面。
  • 待处理文案是归类,不是官方原文:kind 做包含匹配,未知 kind 落到「等待回答」。代价:将来新增的交互类型会显示成「等待回答」,需要回来补映射。
  • 没有设置项:没有开关、位置、透明度、快捷键。装了就一直在;不想看只能卸载。改这些要改 client.js 的 CSS 常量。
  • 界面文案在代码里:locale/*.json 只管插件页标题 / 描述;坞里的 8 个 key 在 client.js 的 DICTS。代价:加语言要改代码并重新装。
  • 不读归档 / 固定状态:只按 running / pending / completionUnread 筛。代价:若某会话归档后仍带运行状态,坞不会隐藏它 —— 这时它会和侧栏的归档视图不一致。

相关文件

文件 关系
README.md 本文件:怎么装、怎么用、怎么排错、怎么验证
IMPLEMENTATION.md 为什么这么实现:槽位取舍、过滤规则、空态、locale 降级、生效路径
AGENTS.md 给 agent 的:命令、硬约束、改动连带项、接口契约、数据形状、FAQ
client.js 浏览器半边:样式、组件、slot 注册
index.js Host 半边(空 apply())
package.json 包声明:bundle patch + client 声明
cordis.patch.yml 装配行
test/smoke.mjs 无 DOM 冒烟 + 包契约(42 项)
—/ 5

No ratings yet

Verified DSH bundle

Commit 8adf6c852c5d

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout