# dsh-side-workspace **中文** | [English](README.md) > DeepSeek Harness (DSH) 插件:对齐 ChatGPT / Codex 三件套的设计—— > **side conversations(侧会话)· integrated workspace(右侧集成工作区)· pinned notes(置顶摘要小黑板)** - 仓库名:`dsh-side-workspace` - 插件 ID / npm 包名:`@dsh-external/dsh-side`(不变) ![dsh-side-workspace 实机界面](assets/screenshot-workspace.png) > **免责声明**:本项目是独立开源项目,与 OpenAI、DeepSeek 无关联,未获其背书或赞助。 > "ChatGPT"、"Codex" 均为各自权利人商标,此处仅用于描述功能对齐关系。 官方术语对照(起名依据): | 本插件功能 | 官方叫法 | 出处 | | --- | --- | --- | | `/side` 侧会话 | Codex **side conversations** | [openai/codex#18190](https://github.com/openai/codex/pull/18190) | | 右侧集成工作区 | ChatGPT **Workspace**(工作区) | OpenAI 工作区代理 | | 置顶摘要小黑板 | ChatGPT **Notes**(消息笔记置顶) | [Pin a Note to Any Message](https://www.getaiworkspace.com/chatgpt-message-notes) | --- ## 功能 ### 1. 侧会话 `/side` — Codex side conversations `/side <问题>` 把当前会话的完整历史以「边界上下文」方式 fork 到一条**后台侧会话**,主对话继续聚焦,两者互不阻塞;`/btw <问题>` 是一次性侧问(只读)。子会话是普通顶层会话(`ctx.agents.create`),继承父会话的 agent preset / model / cwd,并走部署自身的审批与沙箱策略——侧会话产出的内容**永不回流**到主对话日志。 - 默认 `ephemeral`:创建即归档,永不进入普通会话列表;空闲超过 TTL(默认 60 分钟)由主机侧定时清扫,运行中/等待审批的子会话永不过期;新的 `/side` 替换同父会话空闲的旧 `/side`。 - 清理是小型状态机(active → expiring → removed / cleanup-failed + 有界退避重试),失败的 dispose 不会丢失管理记录。 - **裸 `/side` 打开空侧会话**:不注入任何问题,子会话以「等待输入」状态待命,直接在面板输入框提问;问完后状态恢复正常的运行/完成流转。 - **侧会话可选模型与思考强度**:详情页顶部的「模型」行展开后按供应商分组列出模型,选中模型后出现该模型的思考强度(reasoning effort)选项;走宿主 `session.selectModel`,选择持久化在该子会话上、作用于其下一步。 ### 2. 右侧集成工作区 — ChatGPT Workspace 会话头部开关打开壳的右列(details 列,主对话被挤压),内置分组列表 + 详情页: - **Side**:该会话的侧会话列表(运行状态、活动行、失败/清理失败标记),点击进详情页(完整转录 + 可追问输入框;`/btw` 只读)。 - **Subagents**:会话的子代理目录(引用计数托管实时目录),运行徽标与面板同源。 - **Goal**:会话目标(暂停/继续/完成/清除,走 goal RPC)。 - 点击任意条目在**同一右栏**内打开详情页,左栏与主对话不动;Escape 逐级回退(详情 → 列表 → 关面板)。 - **新状态提醒**:侧会话从运行中变为已完成/失败/清理失败时,主对话上方的面板小按钮会出现警示小圆点(未读数进 title 提示),打开面板即标记已读;打开会话时的既有历史是基线,不会重放成提醒。 ### 3. 置顶摘要小黑板 — ChatGPT Notes 右侧工作区顶部的小黑板(自己的图钉按钮开关):收起是细条,展开编辑 标题 / 目标 / 一句话状态 / 下一步(可勾选)/ 决定 等分区。 - **用户编辑优先**:本阶段 AI 不写黑板;每次编辑走与服务器**同一个** CAS 领域函数(乐观本地应用 + 串行 PATCH 补丁)。 - **冲突处理**:版本冲突自动回同步并暂存编辑,横幅 + 重试;补丁 ID 保证重试幂等;「响应丢失但已应用」按内容比对自动识别,不会重复写入。 - 持久化在 `$DSH_HOME/dsh-side-boards.json`(原子写、坏文件容忍降级),路由 `/plugins/dsh-side/board`(GET/PATCH/DELETE,同源、遵循部署既有访问规则)。 - **默认只是记录,绝不自动动 /goal**:目标区的手动按钮才同步——无会话目标时 `goals.create`,已有时按投影 CAS 修订 `goals.edit`;下一步非空时以「下一步」清单附在目标文本后一起提交。 ### 4. 边栏折叠热区(best-effort) 左侧边栏右缘内侧的拖拽条:向左拖过阈值 → 完全折叠到 56px 轨道,从轨道向右拖 → 展开。全部走主机自己的 `toggleSidebar()`,几何发现是结构性的(不遮蔽 `sidebar` 槽、不碰主机手柄与内部 store)。 --- ## 安装(DSH web profile) 插件以 `link:` 方式挂进 web profile,**改完需要你手动重启 `dsh web`**(本插件不提供 HMR): ```powershell # 1. profile package.json 添加依赖,并把客户端 bundle 注册到 profile 的 # dsh.profile.bundles 列表 "@dsh-external/dsh-side": "link:<本仓库绝对路径>" # 2. profile cordis.patch.yml 添加 insert 行(本仓库 cordis.patch.yml 即该行) # 3. 在 profile 目录 pnpm install pnpm install --config.confirmModulesPurge=false ``` ## 配置 | 键 | 默认 | 说明 | | --- | --- | --- | | `retention` | `ephemeral` | `ephemeral`(归档 + TTL 过期)/ `persistent`(普通持久顶层会话) | | `idleTtlMinutes` | `60` | 侧会话空闲过期分钟(1–1440) | ## 用法 ``` /side <问题> 启动可追问的侧会话(后台运行,完成后右侧面板揭示) /side 打开一条空侧会话,在面板里直接提问 /btw <问题> 一次性侧问(只读,不能追问) /side list 列出当前会话的侧会话 ``` ## 示意图 **UI 布局(三列网格 + 右栏工作区 + 小黑板 + 提醒点)** ![workspace-layout](assets/workspace-layout.svg) **架构与数据流(浏览器/主机半部 + 壳服务 + 生命周期)** ![architecture](assets/architecture.svg) > 实机截图(README 首图)存于 `assets/screenshot-workspace.png`;如需换图, > 可在主对话开 1 个运行中的 `/side`、右栏展开小黑板时重新截一张全窗口图覆盖它。 ## 架构 ``` src/ index.ts node 半部:创建/归档/清理状态机 + TTL 清扫 + web 路由 (/plugins/dsh-side/list、/last、/board)+ 命令接线 side.ts fork 截断(宿主 fork RPC 契约)、模型继承、消息形状 prompts.ts 边界提示 / 人设 / 模式行(自写 /side 等价物) registry.ts 父→子注册表 + 清理生命周期 + 纯 TTL/重试决策 board.ts 小黑板纯领域:分区、条目、CAS 补丁引擎、锁定保护、大小上限 board-persistence.ts BoardStore:DSH_HOME 下单个原子 JSON 文件、每板保存链、补丁幂等 client/ 浏览器半部:右栏工作区(Side/Subagents/Goal + 小黑板)、 转录数据层(分页历史读取 + 流式合并 + FIFO 缓存)、目录引用计数、 动作准入闸、会话围栏轮询、边栏折叠热区 tests/ 165 个单元测试(领域 / 持久化 / 客户端 store / 注册表 / 转录 …) ``` ## 开发 ```powershell pnpm install --config.confirmModulesPurge=false # 见下方 link 说明 pnpm check # typecheck(node + client)&& vitest && build ``` `pnpm build` 产出 `lib/index.js`(ESM node 半部)+ `lib/index.d.ts` + `lib/client.js`(CJS 浏览器半部,`window.__ModuleLoader__.load` 包装;react/cordis/dsh-client-* 外部化,lucide 按图标单文件引入,包体约 195kB / gzip 43kB)。 **依赖说明**:devDependencies 是对本地 DSH 安装的相对 `link:./dsh-dev/*` 引用(官方包由 profile 的 pnpm 闭包注入,禁止用 npm 上的裸 `cordis`/`schemastery` 冒充)。`dsh-dev/` 是 gitignored 的 junction 目录,克隆后先建好再 `pnpm install`: ```powershell # 仓库根目录执行;先确认 `npm root -g` 里有 @deepseek-ai/dsh $dsh = (npm root -g) + '\@deepseek-ai\dsh\node_modules' New-Item -ItemType Junction -Path dsh-dev/ai -Target "$dsh\@deepseek-ai" New-Item -ItemType Junction -Path dsh-dev/react -Target "$dsh\react" New-Item -ItemType Junction -Path dsh-dev/react-dom -Target "$dsh\react-dom" ``` `pnpm-lock.yaml` 含绝对路径、不入库(每台机器重新生成)。 ## 已知限制(诚实声明) - **单 details 轨道**:壳只有一条右列,小黑板与工作区纵向共用(无「双倍挤压」);真正的双挤压需要主机提供第二列。 - **无宽度 setter**:`ctx.layout` 只暴露 `toggleSidebar/openDetails/closeDetails`,边栏手柄被主机钳制 264–420px——「自由拖拽任意宽度 + 低于阈值全折叠」是 best-effort,已向主机建议 `ctx.layout.setSidebar(widthPx)` 与零宽折叠模式。 - 侧会话注册表是**进程内**的:`dsh web` 重启后侧会话不再出现在面板(默认语义如此,见「保留契约」)。 ## Roadmap - 可选把黑板内容注入侧会话边界上下文(让侧会话照着目标/下一步工作); - 黑板 AI 提案(owner: assistant-proposal 的数据模型与锁定保护已就绪,等提案入口); - 边栏真自由拖拽(等宿主 `ctx.layout.setSidebar`); - 提醒扩展:子代理/目标阶段变化进同一未读队列。 ## 保留契约(改动前必读) **默认 `ephemeral`(对齐 ChatGPT 临时侧线程):** 创建即归档(不进左侧会话列表)、注册表进程内(重启即忘)、空闲超 TTL 由主机清扫(运行中不扫)、清理失败可见重试。设 `retention: persistent` 恢复 0.2 之前的持久顶层会话行为。 ## 许可 MIT,第三方声明见 [licenses/THIRD-PARTY-NOTICES.md](licenses/THIRD-PARTY-NOTICES.md)。