docs: PRD §13 乐高式工作区框架设计定稿(tiling + PaneProvider,M1-M3)

This commit is contained in:
Aisland
2026-08-17 00:28:30 +08:00
parent 999f860084
commit e419ee83f0
2 changed files with 120 additions and 5 deletions
+84 -5
View File
@@ -1,6 +1,6 @@
# dsh-worktable(工作台)PRD
> 版本:v0.2 草案 · 日期:2026-08-16 · 状态:v2 已实现并验收;§12 多项目分栏框架(v3)设计定案、待新项目开工时实现
> 版本:v0.2 草案 · 日期:2026-08-16 · 状态:v2 已实现并验收;§12 多项目分栏框架(v3)与 §13 乐高式工作区框架(v4)设计定案、待实现
> 关联项目:dsh-travelatlas(第一个入驻项目)、上游参考 dsh-reminder(文件夹结构)
## 1. 项目定位
@@ -229,7 +229,8 @@ ctx.slots.register({
| 服务端健康路由 | ✅ 已实现 | `01_content/src/index.ts` |
| 视图菜单去分组、编辑模式、添加面板、快捷方式、埋点、i18n | ✅ 本窗口(v2)已实现并验收 | `01_content/src/client/`(§5.3–§5.7) |
| travelatlas 卡片协议 v2 | ✅ 本窗口已实现并构建(并行重写覆盖后已重新应用) | `dsh-travelatlas/src/client/index.tsx` |
| 多项目分栏框架(openSplit 声明式多栏) | 📝 设计定案(§12),代码待新项目开工时实现 | PRD §12 |
| 多项目分栏框架(openSplit 声明式多栏) | 📝 设计定案(§12),并入 §13 框架引擎 | PRD §12 |
| 乐高式工作区框架(tiling + 内容插件) | 📝 设计定案(§13),M1–M3 待实现 | PRD §13 |
## 12. 多项目分栏框架(v3 设计,已定案、待实现)
@@ -274,9 +275,13 @@ type SplitPane = {
### 12.4 框架职责
- 几何:查找会话根(`[data-phase]` 探测 + 结构化甄别,与 travelatlas 现行 hack 一致,
集中一处维护)、marginLeft 右挤对话区、分隔线拖宽(逐栏 width 约束)、Esc/✕ 退出、
会话关闭或结构变化自动退出;
- 对话栏:固定最右,宽度 240–480 可拖;
集中一处维护)、marginLeft 右挤对话区、分隔线拖宽(逐栏 width 约束)、Esc/✕ 退出;
- **会话切换行为(2026-08-16 用户需求定案)**:切换不同对话时分栏与左侧内容**保持不关闭**——
会话根变化时重新锚定(重算几何、改观察新根),iframe 组件保持挂载不卸载不刷新;
新会话过渡态(phase 非 active)短暂保持等待、不误关;关闭条件仅:✕ / 再次点击工作台卡片 /
Esc / 无任何活动会话;
- 对话栏:固定最右,可拖宽范围 = 240 起、上限为「列宽 − 左侧内容最小宽」(参考实现取 160px,
与 travelatlas 现行语义一致;不再设固定 480 上限);
- 持久化:`dsh.worktable.split.v1` = `{ [projectId]: { [paneId]: width, chat: width } }`;
- iframe 内容:同源路由约定 `/<project>/site/`(项目服务端自行托管,travelatlas 模式),
URL 校验 http/https,新标签打开入口同 travelatlas;
@@ -287,3 +292,77 @@ type SplitPane = {
- 待第一个新项目开工时在本窗口实现;travelatlas 迁入(改为声明式)作为验证用例;
- 实现不改动 §5.3 卡片协议既有字段,仅新增 openSplit;v2 卡片与老项目不受影响。
## 13. 乐高式工作区框架(v4 设计,路线已定案、待实现)
> 状态:设计定稿(2026-08-16 与用户讨论确认);里程碑 M1–M3 分阶段实现。
> 定位:官方工作区只承载「对话与 Agent 内容」,工作台补上「项目工作区」——一个基座,
> 用户可在其上拼装 2/3/4 窗拓扑与任意内容窗,把项目视窗变成自己想要的样子。
### 13.1 目标与非目标
- 目标:
- 「+」新建工作区:拓扑预设选择(2/3/4 窗)→ 各窗内容指派 → 命名保存为布局;
- 其中一窗恒为聊天窗(继承工作区全部会话;切会话不关闭——§12.4 已实现重锚定);
- 其余窗为内容窗:浏览器 / 资源管理器 / 终端 / 任务管理 / 源代码管理 / 自定义(vibe 生成);
- 拖分隔线、布局持久化、Esc 退出;所有状态存 localStorage。
- 非目标:不搬动/替换官方会话组件;不支持聊天窗出现在非边缘位置(见 13.2 硬约束)。
### 13.2 硬约束:聊天窗必须贴右边缘或下边缘
- 聊天窗 = 官方会话视图区整体,插件仅能以 margin-left / margin-top 将其挤到右/下角,
无法把官方组件拆出来放进中间位置;
- 因此拓扑预设仅提供聊天窗位于右边缘或下边缘(含角)的形态:左右、上下、
3 横排(聊天最右)、上一下二(聊天右下)、井字 2×2(聊天右下)、3+1(聊天右列或下列);
- 上一下二与井字 = margin-left + margin-top 组合挤法(已推演可行);
- 长期观察项:若宿主未来提供「可嵌入的会话组件」,聊天窗即可任意摆位。
### 13.3 布局模型(分割树)
- 布局 = 二叉分割树:叶 = 内容窗(含聊天窗);内部节点 = 分割方向(水平/垂直)+ 比例;
- 预设拓扑均为分割树实例:上一下二 = 水平切 → 下区再垂直切;井字 = 横切 + 每区纵切;
- 状态结构 `LayoutSpec = { id, title, tree: SplitNode }`;叶 = `{ id, title, min/max, content }`;
- 渲染:递归渲染分割树;拖分隔线改比例;聊天窗叶走 margin 挤法 + §12.4 重锚定。
### 13.4 内容插件协议 PaneProvider
- 内容三态:`iframe`(同源 URL,主推)/ `component`(插件打包 React 组件)/ `builtin`(工作台内置);
- builtin 注册表:工作台内置「浏览器」;资源管理器 / 终端 / 任务管理作为后续内容插件逐个接入;
- 内容插件 = 独立 DSH 插件包,经专用座位或注册表挂载,不硬编码进工作台本体。
### 13.5 「+」面板改版
- 「+」展开后两个入口:
1. **新建工作区**:拓扑预设选择(可视化缩略图)→ 各窗内容指派 → 命名保存;
2. **接入项目 / 快捷方式**:现有接入指引 + 本地条目功能保留(§5.6);
- 保存的布局以「布局条目」形式出现在项目区(布局 = 一种工作台项目),点击打开 tiling 工作区,
再次点击 / ✕ / Esc 关闭。
### 13.6 持久化
- `dsh.worktable.layouts.v1` = `{ [layoutId]: LayoutSpec + 分隔线比例 }`;
- 聊天窗宽度语义同 §12.4:240 起、上限 = 行/列尺寸 − 相邻内容窗最小宽。
### 13.7 内容窗可行性记录(2026-08-16)
| 内容窗 | 可行性 | 依据 |
| --- | --- | --- |
| 浏览器 | ✅ 现成 | iframe + 同源路由(travelatlas 已验证) |
| 资源管理器 | 🔶 待调研 | workspaces/directory 服务与官方目录选择器可作基底 |
| 终端 | 🔶 待调研 | 宿主依赖含 xterm + dsh-terminal 包,接入方式需逆向确认 |
| 任务管理 | 🔶 待调研 | todo/目标状态投影服务,需找对 API |
| 源代码管理 | ⚠️ 受限 | 宿主无内置 git 服务;先以「终端里跑 git」替代 |
| 自定义 vibe | ✅ 可闭环 | 描述需求 → agent 生成新项目(插件/站点)→ 注册进工作台 |
### 13.8 里程碑
- **M1 布局引擎**:分割树 + 拓扑预设选择器 + 聊天重锚定(§12.4 已有参考实现)+ 浏览器窗 + 布局持久化;
- **M2 内容插件协议**:PaneProvider 三态接口;travelatlas 图鉴作为第一个内容窗迁入验证;
- **M3 内容插件库**:资源管理器 / 终端 / 任务管理逐个接入;SCM 视 API 情况;自定义 vibe 闭环。
### 13.9 与既有协议的关系
- §5.3 卡片协议 v2 不变:项目插件仍注册卡片(reportMeta/reportUsed/openSplit);
- §12 的 openSplit 声明式多栏并入本框架:项目预设布局 = 一份固定 LayoutSpec,
用户自建布局 = 同一引擎的运行时产物,共用 tiling 引擎与持久化;
- 本地快捷方式、接入指引保留于「+」面板第二入口。
@@ -176,3 +176,39 @@
为主、component 预留位);路线 A(项目自带 overlay)作为逃生舱并存。
- 落地:PRD §12 写入设计规格(SplitSpec/框架职责/实施时机),代码待第一个新项目开工时实现;
§11 状态表同步;本窗口暂不写代码(用户选择「先落设计」)。
## 补记(travelatlas 分栏「切会话不关闭」补丁)
- 需求(用户):分栏模式下切换不同对话时,左侧旅行网页保持不消失;仅 ✕ / 再点工作台卡片 /
Esc / 无任何活动会话时关闭。
- 实现(travelatlas src/client/index.tsx,store 层):
① 新增 syncAnchor:会话根失效时找新根重新锚定(恢复旧视图区 margin、更新 root/header/viewArea、
RO 改观察新根、几何重算),左侧 iframe 组件保持挂载不卸载不刷新;
② findConversationRoot 优先 phase=active(避免过渡期命中旧根);
③ 新增 body 级 MutationObserver 兜底(attributeFilter data-phase + childList),
覆盖「旧根被替换后 RO 不再回调」与 phase 过渡态;close 时一并断开;
④ 关闭条件收敛为:无任何会话根 / 结构无法识别 / ✕ / Esc / 再点卡片。
- 验证:构建 + node --check 通过;服务端实时下发(served len=17083,含 syncAnchor/MutationObserver);
待用户刷新后实测「切会话左侧保持、点 ✕/卡片才关闭」。
- 该行为已同步写入 PRD §12.4 框架规格(所有未来项目默认继承)。
## 补记(分隔线向左范围放开)
- 需求(用户):分栏分隔线向右可移、向左有上限(聊天栏最大 480px 且图鉴保留 260px),
希望对话框更大、分隔线能再往左。
- 实现(travelatlas):删除 MAX_CHAT_W=480 固定上限;新增 MIN_ATLAS_W=160,
聊天栏钳制改为 [240, max(240, 列宽−160)]——左侧图鉴最小保留 160px,其余全给聊天栏。
- 验证:构建 + node --check 通过;服务端实时下发(served len=17070,含 MIN_ATLAS_W)。
- PRD §12.4 对话栏宽度语义同步(上限=列宽−内容最小宽,不再固定 480)。
## 补记(乐高式工作区构想 → PRD §13 设计定稿)
- 用户构想:把工作台做成「乐高基座」——「+」新建工作区时提供 2/3/4 窗拓扑预设
(左右/上下/3 横排/上一下二/井字/3+1),其中一窗恒为聊天窗(继承全部会话、切会话不消失),
其余窗放置内容插件(浏览器/资源管理器/源代码管理/任务管理/终端/自定义 vibe 生成)。
- 评估结论(已与用户确认):可行;核心 = 分割树 tiling 引擎 + PaneProvider 内容插件协议;
硬约束 = 聊天窗必须贴右/下边缘(margin 挤法的能力边界);内容窗可行性分级记录(浏览器✅、
资源管理器/终端/任务管理🔶待调研、SCM⚠️受限、自定义✅闭环)。
- 落地:PRD §13 设计定稿(13.1–13.9:目标/硬约束/分割树/内容协议/+面板改版/持久化/
可行性记录/里程碑 M1-M3/协议关系);§12 并入 §13 引擎;§11 状态表同步;
代码按用户选择暂不实现。