diff --git a/.changeset/fair-bears-tell.md b/.changeset/fair-bears-tell.md new file mode 100644 index 000000000..767f223a4 --- /dev/null +++ b/.changeset/fair-bears-tell.md @@ -0,0 +1,5 @@ +--- +"@spencer-kit/coder-studio": patch +--- + +Refresh workspace and runtime flows with canvas support, terminal profile improvements, skill management updates, and follow-up Windows and UI fixes. diff --git a/README.md b/README.md index 8b7470e19..cd48685dc 100644 --- a/README.md +++ b/README.md @@ -111,9 +111,9 @@ The same workspace URL works across all devices — interface adapts automatical ![Desktop Workspace](docs/help/assets/screenshot-pc.png) -**Mobile Interface** +**Phone Layout** -![Mobile Workspace](docs/help/assets/screenshot-mobile.png) +The current phone layout is not a bottom dock UI. It uses a top bar for workspace, files, terminal, and more actions, a main active-session stage, fullscreen sheets for files and terminal, and a bottom status bar. --- @@ -200,7 +200,7 @@ pnpm dev ### Development Docs -- [PRD](docs/PRD.zh-CN.md) +- [Product Spec Index (zh-CN)](docs/product-spec/README.zh-CN.md) - [Design Spec](docs/superpowers/specs/2026-04-13-coder-studio-design.md) - [More Docs](docs/) diff --git a/README.zh-CN.md b/README.zh-CN.md index 67a94bf5a..953b59787 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -111,9 +111,9 @@ coder-studio open ![桌面端工作区](docs/help/assets/screenshot-pc.png) -**移动端界面** +**手机端布局** -![移动端工作区](docs/help/assets/screenshot-mobile.png) +当前手机端不是底部 Dock 导航,而是顶部栏、当前会话主区、文件/终端全屏 Sheet,以及底部状态栏的组合。 --- @@ -201,7 +201,7 @@ pnpm dev ### 开发文档 -- [PRD](docs/PRD.zh-CN.md) +- [产品规格索引](docs/product-spec/README.zh-CN.md) - [设计规范](docs/superpowers/specs/2026-04-13-coder-studio-design.md) - [更多文档](docs/) diff --git a/docs/PRD.zh-CN.md b/docs/PRD.zh-CN.md index fb31dac10..daf9cc3ee 100644 --- a/docs/PRD.zh-CN.md +++ b/docs/PRD.zh-CN.md @@ -1,1621 +1,8 @@ -# 产品需求文档:Coder Studio(产品评审版,代码现状基线) +# Coder Studio PRD(迁移说明) -> **文档更新时间:** 2026-05-06 -> **代码基线:** 当前仓库 `packages/web`、`packages/server` 实现 -> **适用范围:** Web UI、内置 Server、WebSocket 命令层 -> **阅读说明:** -> - 第 `1 ~ 7` 章按产品评审视角描述当前可见能力、页面结构与用户交互。 -> - 第 `8` 章保留实现边界与未纳入范围,避免把未接线能力写成已上线功能。 -> - 一切以当前代码为准,不沿用旧版 PRD、README 或历史规划中的未落地项。 +当前中文版产品现状基线已迁移到 [docs/product-spec/current-baseline.zh-CN.md](./product-spec/current-baseline.zh-CN.md)。 ---- - -## 1. 文档说明 - -### 1.1 适用范围 - -本文档只描述**当前代码中已接线、可达、可交互**的产品能力,覆盖: - -- 欢迎页、登录页、工作区页、设置页、404 页 -- 桌面端与移动端两套工作区体验 -- 文件、Git、会话、终端、通知、配置等核心能力 - -### 1.2 编写原则 - -- **以代码现状为准:** 组件存在、测试存在,不等于页面已上线。 -- **以页面为主线:** 先描述页面目标与交互,再描述状态、边界与错误反馈。 -- **以用户可见能力为主:** 正文尽量使用产品语言;必要的实现事实统一收敛到附录。 - -### 1.3 阅读方式 - -- 若是做**产品评审**,重点阅读第 `2 ~ 7` 章。 -- 若要判断某项能力是否**真实接线**、是否只是 UI 或是否仍有实现边界,重点阅读第 `8` 章。 - ---- - -## 2. 产品概览 - -### 2.1 产品定位 - -Coder Studio 是一款**面向自部署环境、以 Deploy once, coding everywhere 为核心承诺的 AI 编码工作台**。 -用户可以把它部署在个人电脑、开发机、家用服务器或云主机上,并通过浏览器在桌面端或手机端访问同一套工作区、会话、终端与 Git 能力。根据部署方式不同,这种访问既可以发生在本机,也可以发生在局域网内,或通过外网持续访问。当前实现把以下能力整合到同一个工作区体系中: - -- 打开并切换多个本地 workspace -- 在同一 workspace 中创建多个 AI 会话(Claude / Codex) -- 以终端形态查看和继续输入 Agent 会话 -- 浏览文件树、编辑文本文件、预览图片文件 -- 查看 Git 状态、Diff、提交、Push / Pull、分支切换 -- 管理 Provider、通知、外观与部分快捷键配置 - -### 2.2 当前核心价值 - -从产品能力上看,当前版本的核心价值有三点: - -1. **Deploy once, coding everywhere:一次部署,在任意可访问设备上继续编码。** -2. **把 AI 会话、文件、Git、终端集中到同一工作区工作流里。** -3. **同时提供桌面与移动两套真实独立的访问体验。** - -### 2.3 端形态 - -| 端 | 形态 | 核心特征 | -| --- | --- | --- | -| Desktop | 宽屏多栏工作台 | 顶栏 + 左侧栏 + 主区 + 底部终端 | -| Mobile | Sheet / Dock 驱动工作台 | 顶部栏 + 单会话主区 + 底部 Dock + 多个全屏 Sheet | - -> **说明:** -> 移动端不是桌面布局的简单缩放,而是另一套以 `Dock + Sheet` 为中心的交互结构。 - ---- - -## 3. 信息架构与主流程 - -### 3.1 页面地图 - -| 路由 | 页面 | 说明 | -| --- | --- | --- | -| `/` | 欢迎页 | 当没有可进入的 workspace 时作为默认入口;也承接打开工作区与进入设置 | -| `/login` | 登录页 | 前端登录页路由 | -| `/workspace` | 工作区页 | 主工作区;桌面与移动端为两套不同体验 | -| `/settings` | 设置页 | 桌面与移动端共用同一页能力,但导航结构不同 | -| `*` | 404 页面 | 展示未命中路径并提供返回首页操作 | - -### 3.2 壳层选择 - -| 条件 | 壳层 | 页面骨架 | -| --- | --- | --- | -| 视口宽度 `> 899px` | Desktop Shell | 顶栏、左栏、主区、底部终端 | -| 视口宽度 `<= 899px` | Mobile Shell | 顶部栏、主会话区、Dock、全屏 Sheet | - -两套壳层共享: - -- 同一路由体系 -- 同一组 workspace / session / terminal 数据 -- 同一组全局能力,如命令面板、分支切换、Toast 等 - -### 3.3 启动与进入流程 - -应用启动后的真实主流程如下: - -1. 先调用认证状态接口,确认当前是否需要登录。 -2. 若服务端开启认证且当前未通过认证: - - 页面停留在登录流 - - 不继续恢复 workspace 视图 -3. 若当前已认证: - - 建立或恢复 WebSocket 连接 - - 连接可用后拉取 workspace 列表 -4. 根据 workspace 列表决定默认去向: - - 当前在首页且已存在 workspace:自动进入工作区 - - 当前在工作区页但已无 workspace:自动回到首页 -5. 在工作区页内,如果当前 active workspace 仍未解析完成: - - 显示加载占位 - - 若失败则显示错误占位 - -### 3.4 全局连接状态 - -所有页面共享同一套连接状态反馈: - -- `connected`:不显示连接横幅 -- `connecting`:不显示横幅,等待连接完成 -- `reconnecting`:显示“正在重新连接...” -- `disconnected`:显示“连接已断开” -- `rejected`:显示“另一个标签页已激活” - -桌面顶栏和移动顶栏在**未连接**时还会显示轻量连接状态指示器。 - ---- - -## 4. 页面规格 - -## 4.1 欢迎页 `/` - -### 4.1.1 页面目标 - -欢迎页是“当前没有可进入 workspace”时的默认入口页,承担三件事: - -- 打开本地 workspace -- 进入设置页 -- 以简洁方式说明产品核心能力 - -### 4.1.2 页面结构 - -页面主体是一张居中的欢迎卡片,移动端只调整样式,不改变信息结构。卡片固定包含: - -- 产品 kicker -- 标题 -- 描述文案 -- 主按钮“打开工作区” -- 次按钮“设置” -- 分隔线 -- 三个功能亮点卡片 - -### 4.1.3 功能与详细交互 - -| 区域 | 功能 | 交互规则 | -| --- | --- | --- | -| 打开工作区按钮 | 打开 workspace 启动器 | 点击后打开项目内的目录浏览器;**不是**系统原生文件选择器 | -| 设置按钮 | 进入设置页 | 点击后跳转到 `/settings` | -| 功能亮点区 | 展示核心能力 | 当前固定为三项:Agent-first、Git 工具、终端能力 | - -### 4.1.4 状态与边界 - -- 欢迎页自身没有复杂错误态。 -- 若应用已经解析出至少一个 workspace,启动流程通常会直接把用户送往 `/workspace`,因此欢迎页不会长期停留。 - ---- - -## 4.2 登录页 `/login` - -### 4.2.1 页面目标 - -登录页用于处理“服务端启用了密码保护”的场景。 - -### 4.2.2 页面结构 - -登录页沿用欢迎页的居中卡片式布局,包含: - -- 产品 kicker -- 应用标题 -- 状态 / 说明文案 -- 状态面板 -- 密码输入框 -- 提交按钮 - -### 4.2.3 状态探测 - -页面挂载后会根据认证状态检查结果决定显示内容: - -| 状态 | 页面行为 | -| --- | --- | -| 正在检查认证状态 | 展示“连接中”状态 | -| 服务端未启用认证 | 直接把前端鉴权态设为已通过,后续退出登录页 | -| 已存在有效会话 | 直接把前端鉴权态设为已通过 | -| 服务不可用 / 请求失败 | 状态面板显示“不可用 / 无法获取状态” | -| 需要登录 | 保持在当前页,等待用户输入密码 | - -### 4.2.4 提交与错误反馈 - -| 场景 | 交互规则 | -| --- | --- | -| 输入为空 | 提交按钮禁用 | -| 正在检查状态 / 正在提交 | 提交按钮禁用,按钮文案切换为连接中 | -| 提交成功 | 登录成功后把前端鉴权态设为已通过 | -| 密码错误 | 直接展示服务端错误文案;当前典型文案为 `Invalid password` | -| 触发临时封禁 | 若服务端返回封禁截止时间,页面按当前语言格式化显示具体时间 | -| 网络错误 | 显示网络错误文案 | - -### 4.2.5 边界说明 - -- 输入框类型固定为 `password`。 -- 当前没有“忘记密码”“切换账号”“退出登录”等额外流程。 -- 登录页本身没有额外快捷键设计。 - ---- - -## 4.3 工作区页 `/workspace`(桌面) - -### 4.3.1 页面目标与整体结构 - -桌面工作区是当前产品最完整的工作台形态,目标是让用户在同一屏内完成: - -- 切换 workspace -- 创建 / 关闭 AI 会话 -- 浏览和编辑代码 -- 查看与处理 Git 变更 -- 使用 shell terminal - -页面整体分为四个区域: - -| 区域 | 内容 | -| --- | --- | -| 顶部 | Workspace 顶栏 | -| 左侧 | Files / Git 面板 | -| 中央 | Agent / 编辑器 / Diff 主区 | -| 底部 | Terminal 面板 | - -### 4.3.2 进入条件与页面状态 - -| 状态 | 页面表现 | -| --- | --- | -| 当前 active workspace 解析中 | 显示加载占位卡片 | -| workspace 列表加载失败 | 显示错误卡片 | -| 当前 active workspace 为空 | 显示“无 workspace”空态,不渲染完整工作台 | -| 存在有效 workspace | 渲染完整桌面工作区 | - -### 4.3.3 顶部工作区栏 - -#### 4.3.3.1 Workspace 标签区 - -| 功能点 | 交互 / 规则 | -| --- | --- | -| Workspace 标签列表 | 按当前 workspace 顺序渲染 | -| 标签主文案 | 优先显示 workspace 名称;否则显示路径最后一段;再退化为完整路径或 id | -| 状态点 | active workspace 显示激活样式,其他显示 idle 样式 | -| 未读徽标 | `unreadCount > 0` 时显示;大于 `9` 时显示 `9+` | -| 点击标签 | 切换当前 active workspace | -| 键盘 Enter / Space | 聚焦标签时也可触发切换 | -| 关闭按钮 | 关闭该 workspace,并同步从本地列表中移除 | -| 新增按钮 `+` | 打开 workspace 启动器 | - -#### 4.3.3.2 动作区 - -| 按钮 / 区域 | 行为 | -| --- | --- | -| 连接状态 | 仅在非 `connected` 时显示 | -| Quick Actions | 打开 / 关闭命令面板 | -| Terminal | 显示 / 隐藏底部终端面板 | -| Files | 显示 / 隐藏左侧栏 | -| Settings | 跳转 `/settings` | -| Fullscreen | 浏览器支持时显示;切换工作区根节点全屏 | - -#### 4.3.3.3 关闭最后一个 workspace 的返回 - -- 若关闭的是最后一个 workspace,前端状态会变为空。 -- 随后启动逻辑会检测到 `/workspace` 下无可用 workspace,并自动回到 `/`。 - -### 4.3.4 布局、尺寸与专注模式 - -#### 4.3.4.1 页面布局 - -桌面工作区固定由三块核心内容组成: - -- 左侧栏:文件 / Git -- 中央主区:会话 / 编辑器 / Diff -- 底部面板:终端 - -#### 4.3.4.2 拖拽尺寸 - -| 区域 | 默认值 / 范围 | -| --- | --- | -| 左侧栏宽度 | 默认 `280px`,范围 `220px ~ 480px` | -| 底部终端高度 | 范围 `120px ~ 400px` | - -#### 4.3.4.3 布局记忆 - -当前 workspace 会记住以下 UI 状态: - -- 左侧栏宽度 -- 底部终端高度 -- 专注模式开关状态 -- 当前 active session -- 会话分屏布局 - -#### 4.3.4.4 专注模式 - -专注模式当前已接线,打开后会: - -- 隐藏左侧栏 -- 隐藏底部终端 - -关闭后恢复显示。 - -> **当前产品边界:** -> 当前用户可见的专注模式入口只确认来自命令面板;不要把独立全局 `F` 快捷键写成当前已上线能力。 - -### 4.3.5 左侧栏:Files / Git - -#### 4.3.5.1 共用框架 - -左侧栏顶部固定包含: - -- 当前面板名称 -- 当前分支按钮 -- Files / Git 切换 Tab -- 内联 Git 状态栏 - -##### 分支按钮 - -点击分支按钮会: - -1. 把左侧栏切到 Git Tab -2. 打开分支快速切换弹层 - -按钮文案优先显示当前分支名;无值时显示 `—`。 - -##### Tab 切换 - -| Tab | 内容 | -| --- | --- | -| Files | 文件树与文件操作工具栏 | -| Git | Git 面板 | - -切到 Files 时显示文件工具栏;切到 Git 时不显示 Files 工具栏。 - -#### 4.3.5.2 Files 视图 - -##### 顶部工具栏 - -| 按钮 | 行为 | -| --- | --- | -| 新建文件 | 打开创建弹窗,模式为 file | -| 新建文件夹 | 打开创建弹窗,模式为 folder | -| 刷新 | 重新拉取文件树 | - -##### 文件树加载方式 - -- 首次进入时拉取根目录文件树。 -- 子目录为懒加载:展开目录时,如果子节点尚未加载,则按该目录路径再次请求。 -- 顶层目录中,`app`、`packages`、`src` 会默认展开。 - -##### 文件搜索 - -| 功能点 | 规则 | -| --- | --- | -| 搜索框 | 输入关键字后触发文件搜索 | -| 触发时机 | 输入停止约 `150ms` 后发起 | -| 返回条数 | 默认上限 `10` 条 | -| 搜索结果项 | 展示文件名、所在目录、删除按钮 | -| 点击搜索结果 | 直接打开文件到编辑器 | - -##### 树节点交互 - -| 节点类型 | 点击行为 | 行内操作 | -| --- | --- | --- | -| 文件夹 | 展开 / 收起;首次展开时拉取子节点 | 新建文件、新建文件夹、删除 | -| 文件 | 设为当前 active file,并在主区打开 | 删除 | - -##### 创建文件 / 文件夹 - -创建弹窗的真实规则如下: - -- 以 modal 形式展示 -- 若从文件夹行内入口发起,输入框默认预填 `目录路径/` -- 若从左侧工具栏发起,输入框默认为空 -- 路径为空时报错 -- 新建文件且路径以 `/` 结尾时报错 -- 提交成功后: - - 重新拉取文件树 - - 若创建的是文件,自动打开该文件 - -##### 删除文件 / 文件夹 - -- 删除通过确认弹窗执行 -- 确认后发起删除 -- 删除成功后: - - 重新拉取文件树 - - 如果删掉的是当前打开文件,则关闭该文件并清空 active file - -#### 4.3.5.3 Git 视图 - -##### 面板结构 - -Git 面板从上到下包含: - -- 工具栏 -- Commit message 输入框 -- Latest commit 摘要 -- 变更分组列表 -- 丢弃确认弹窗(条件出现) - -##### 顶部工具栏 - -| 按钮 | 出现条件 | 行为 | -| --- | --- | --- | -| 刷新 | 始终显示 | 重新拉取 Git 状态 | -| Stage All | 有变更时显示 | 暂存 modified / deleted / untracked | -| Unstage All | 有变更时显示 | 取消暂存全部 staged | -| Discard All | 有变更时显示 | 打开全部丢弃确认 | -| Commit | 有变更时显示 | 仅当 commit message 非空且 staged 非空时可点 | - -##### Commit 输入 - -- 使用单行自动扩展风格文本域 -- 点击 Commit 后发起提交 -- 提交成功后清空 commit message,并刷新 Git 状态 - -##### Latest commit 摘要 - -若当前状态中存在最新提交摘要,面板会展示: - -- “Latest commit” 标签 -- 短 SHA -- 提交标题 - -##### 变更分组 - -当前按以下顺序分组展示: - -1. `staged` -2. `changes`(modified) -3. `deleted` -4. `untracked` - -每组都展示标题、数量与文件列表。 - -##### 文件级交互 - -| 操作 | 行为 | -| --- | --- | -| 点击文件行 | 请求该文件 Diff,并在主区打开 Diff 视图 | -| Stage / Unstage | 单文件切换暂存状态 | -| Discard | 打开单文件丢弃确认 | - -##### Diff 自动预览规则 - -Git 面板存在真实的“首项自动预览”行为: - -- 当 Git 状态加载完成且当前未 dismiss Diff 预览时: - - 若已有当前预览且该文件仍存在,则保持当前预览 - - 否则自动选中第一条变更并请求 Diff -- 用户主动关闭 Diff 后,会把“预览已 dismiss”标记设为 true,避免继续自动弹出 - -#### 4.3.5.4 Git 状态栏 - -状态栏显示三类数字: - -- 变更总数 -- Ahead 数 -- Behind 数 - -##### Push / Pull 触发 - -- 点击 Ahead 数:打开 Push 确认弹窗 -- 点击 Behind 数:打开 Pull 确认弹窗 -- 若对应数字 `<= 0`,按钮禁用 - -##### 确认弹窗 - -确认弹窗固定包含: - -- 标题 -- 文案 -- 取消按钮 -- 主操作按钮 - -##### HTTP 认证失败时的二次流程 - -当 Push / Pull 遇到 HTTP 认证失败,且后端表明可以继续询问账号密码时: - -- 弹窗内容切换为认证表单 -- 用户名输入框优先预填服务端给出的 `usernameHint` -- 需要同时输入用户名和密码才能继续提交 - -若后端标记为“不支持交互式认证”,弹窗仅展示提示,不给出可提交表单。 - -### 4.3.6 中央主区:会话 / 编辑器 / Diff - -#### 4.3.6.1 显示优先级 - -桌面主区的显示优先级是固定的: - -1. 若当前左侧栏在 Git Tab,且存在 Diff 预览:显示 Diff -2. 否则若存在当前 active file:显示编辑器 -3. 否则:显示 Agent 会话区 - -这意味着: - -- Git Diff 与 Git Tab 绑定 -- 只要切回 Files Tab,主区就会从 Diff 返回到编辑器或会话区 - -#### 4.3.6.2 Agent 会话区 - -##### Pane 布局 - -会话区支持: - -- 单 pane -- 横向 split -- 纵向 split -- 叶子节点为真实 session 或新建会话草稿卡 - -每个 split 容器的 ratio 会持久化到当前 workspace 的 UI 状态中。 - -##### 新会话草稿卡 - -当当前 pane 没有真实 session 时,主区显示一个新会话草稿卡,支持: - -- 选择 Claude / Codex -- 在当前 pane 内创建会话 -- 横向 split 新草稿 pane -- 纵向 split 新草稿 pane -- 关闭草稿 pane - -##### Provider 启动流程 - -桌面端草稿卡与移动端创建会话共用同一套 provider 启动流程: - -1. 先检查 provider runtime 是否可用 -2. 若 runtime 可用: - - 直接创建 session -3. 若 runtime 不可用但支持自动安装: - - 先启动安装 - - 之后每 `1.5s` 轮询安装状态 - - 安装成功后再创建 session -4. 若 runtime 不可用且不支持自动安装: - - 在卡片上展示手动安装说明 - - 若存在文档地址,则展示跳转链接 - -桌面端额外规则: - -- 只要任一 provider 处于启动或安装中,两个 provider 卡片都会整体禁用,防止重复发起。 - -##### Session Card - -每个已创建 session 以卡片形式渲染,包含: - -- 顶部进度条 -- Header:状态点、标题、provider badge、state badge、右侧操作区 -- 条件性的 Supervisor 卡片 -- 会话终端 - -###### 标题与状态显示规则 - -- 标题优先使用 `session.title` -- 无标题时退化为 `SESSION-XX` -- Provider badge 显示 `Claude` / `Codex` -- State badge 直接把 `starting / running / idle / ended / draft` 转为 Title Case - -###### Header 操作 - -| 操作 | 出现条件 | 行为 | -| --- | --- | --- | -| Stop | 仅 `running` 时显示 | 停止当前 session | -| Split Horizontal | 始终显示 | 以当前 session 为锚点横向分屏 | -| Split Vertical | 始终显示 | 以当前 session 为锚点纵向分屏 | -| Close | 始终显示 | 先从 pane 布局移除,再执行关闭会话流程 | - -###### 点击卡片本体 - -- 点击卡片空白区域时,会把该 session 设为当前 workspace 的 active session -- 点击按钮、链接、输入控件不会触发该行为 - -###### 关闭会话的真实流程 - -| 会话状态 | 行为 | -| --- | --- | -| `ended` | 直接删除 | -| 其他状态 | 先停止,再轮询等待 `ended`,最后删除 | - -##### 桌面内联 Supervisor - -当且仅当满足以下条件时,会在 Session Card 内联显示 Supervisor 卡片: - -- 当前 session 具备 full capability -- session 不是 `draft` -- session 不是 `ended` - -内联区域支持: - -- 启用目标 -- 编辑目标 -- 暂停 / 恢复 -- 手动触发一次评估 -- 禁用目标 - -桌面端的启用、编辑、禁用都通过 modal 对话框完成。 - -#### 4.3.6.3 编辑器与文件预览 - -##### 文件打开规则 - -选择文件后,页面按文件类型进入两种模式: - -| 文件类型 | 页面表现 | -| --- | --- | -| 文本文件 | 打开 Monaco 编辑器 | -| 图片文件 | 打开图片预览 | - -##### 文本文件编辑 - -| 功能点 | 交互规则 | -| --- | --- | -| 编辑器 | 使用 Monaco;按文件扩展名自动切换语言模式 | -| 脏状态 | 内容变更后标记未保存 | -| 保存按钮 | 仅文本文件且有未保存变更时可用 | -| 快捷键保存 | Monaco 内真实注册 `Ctrl/Cmd + S` | -| 关闭按钮 | 关闭当前文件并清空 active file | - -保存时会带上 `baseHash` 做冲突检测。 - -##### 图片文件预览 - -- 图片文件通过 `/api/file` 预览 -- 该接口只服务于图片预览,不是通用文件下载接口 - -##### SVG / 文本型图片切换 - -若图片文件本身是“文本型图片”(当前实际主要是 SVG): - -- 页面显示“图像 / 文本”模式切换按钮 -- 从图像切到文本时: - - 再次抓取文本内容 - - 以文本文件模式进入 Monaco -- 从文本切回图像时: - - 重新按图片模式加载 - -##### 外部变更检测 - -编辑器会响应文件系统或 Git 变更引起的刷新: - -| 场景 | 行为 | -| --- | --- | -| 文件在磁盘上被修改,且当前文件**没有未保存变更** | 自动刷新为磁盘最新内容 | -| 文件在磁盘上被修改,且当前文件**有未保存变更** | 保留本地内容,并显示“文件已在磁盘上被修改”警告 | -| 文件在磁盘上被删除 | 显示“文件已在磁盘上被删除”警告 | -| 图片文件资源变化 | 刷新图片 URL / size | - -##### 错误与空态 - -| 场景 | 页面表现 | -| --- | --- | -| 打开文件失败 | 在主区显示错误信息 | -| 已有 active path,但文件尚未加载完成 | 显示 loading 占位 | -| 未选择文件 | 显示编辑器空态提示 | - -#### 4.3.6.4 Diff Viewer - -Diff Viewer 是只读视图,包含: - -- 顶部文件路径 -- 关闭按钮 -- 逐行渲染的 diff 内容 -- 行号 -- added / removed / meta / context 的不同视觉样式 - -关闭 Diff 后,当前行为是: - -- 清空当前 diff 预览 -- 清空 `activeFilePath` -- 主区回到 Agent 视图 - -### 4.3.7 底部终端面板 - -#### 4.3.7.1 面板结构 - -终端面板包含: - -- 顶部工具栏 -- 可选 terminal tabs -- 当前 terminal 的 xterm 渲染区 - -#### 4.3.7.2 工具栏 - -| 功能点 | 行为 | -| --- | --- | -| 当前 terminal 标题 | 按当前 meta / title 格式化展示 | -| 关闭当前 terminal | 关闭当前选中 terminal | -| 新建 terminal | 创建新的 shell terminal | -| terminal selector | 多 terminal 时可切换 | - -#### 4.3.7.3 多 terminal 行为 - -| 场景 | 页面表现 | -| --- | --- | -| 0 个 terminal | 显示空态与“新建终端”CTA | -| 1 个 terminal | 直接显示 xterm | -| `> 1` 个 terminal | 同时显示 tabs,并提供 selector 下拉选择 | - -#### 4.3.7.4 shell terminal 创建规则 - -新建 shell terminal 时: - -- 工作目录固定为当前 workspace 路径 -- Unix-like 环境默认使用 `$SHELL -i` -- Windows 默认使用 `cmd.exe` - -#### 4.3.7.5 终端恢复与渲染 - -桌面终端与 Agent 终端共用同一套 xterm 宿主能力,具备以下真实行为: - -- 首次进入时优先尝试 replay / snapshot 恢复历史输出 -- 恢复未完成前显示 restoring overlay -- 若 replay 数据过旧、终端已关闭或恢复失败,显示 degraded overlay -- 对非活跃终端存在 hydration 队列,占位阶段显示 placeholder - -#### 4.3.7.6 交互能力 - -| 功能点 | 行为 | -| --- | --- | -| 普通输入 | 直接发送到 terminal 或 session | -| 只读保护 | 非交互态会话终端不可输入 | -| 粘贴 / 拖拽上传文件 | 可先把文件上传到当前 workspace,再把 shell-safe 路径文本注入输入框 | -| 上传中 | 在 xterm 上方显示 `Uploading…` 遮罩,并临时禁用输入 | - -上传成功后,终端实际收到的是: - -- 每个路径按 shell-safe 方式单引号转义 -- 多个文件以空格拼接 -- 末尾补一个空格,方便用户继续输入命令 - ---- - -## 4.4 工作区页 `/workspace`(移动) - -### 4.4.1 页面目标与整体结构 - -移动端工作区不是桌面缩放版,而是围绕“当前会话 + Dock + 多个全屏 Sheet”组织的移动工作流。 - -整体结构为: - -- 顶部栏 -- 当前单会话主区 -- 底部 Dock -- Agent / Files / Terminal / Supervisor 等全屏 Sheet - -### 4.4.2 进入条件与页面状态 - -移动端与桌面端共用相同的 workspace 启动与路由守卫逻辑: - -- 解析中:显示 loading 占位 -- 加载失败:显示错误占位 -- 有有效 workspace:进入移动工作区 - -### 4.4.3 顶部栏 - -| 功能点 | 行为 | -| --- | --- | -| Workspace 按钮 | 展示当前 workspace 名称;点击打开 Workspace Drawer | -| Settings 按钮 | 跳转 `/settings` | -| Fullscreen 按钮 | 浏览器支持时显示;切换工作区视图全屏 | - -workspace 标题显示规则与桌面一致:优先名称,其次路径最后一段,再其次完整路径。 - -### 4.4.4 页面内 Banner - -移动工作区页顶部会内嵌显示配置漂移 Banner。 -它位于工作区内容内部,不是壳层级横跨所有页面的全局条。 - -### 4.4.5 主会话区 - -#### 4.4.5.1 有 session 时 - -主区只展示**当前激活的一个 session**。 - -当前主卡片行为: - -- 使用同一套 Session Card 核心内容 -- 不展示桌面端那组 header 操作 -- 通过顶部角标入口提供 Supervisor 打开能力 - -因此,移动主卡片默认**不直接展开**: - -- Stop -- Split -- Close - -#### 4.4.5.2 无 session 时 - -页面显示空态与 CTA: - -- 文案 1:提示用户开始一个 session -- 文案 2:提示文件与终端能力可在 Dock 中继续访问 -- CTA:打开 Agent Sheet,并直接进入创建模式 - -#### 4.4.5.3 焦点联动 - -若外部动作(如通知点击)请求聚焦某个 session: - -- 只要该 session 属于当前 workspace -- 移动端会自动把它切换为当前可见 session - -### 4.4.6 底部 Dock - -底部固定三个入口: - -- `Agent` -- `Files` -- `Terminal` - -交互规则如下: - -| Dock 项 | 行为 | -| --- | --- | -| Agent | 打开 / 关闭 Agent Sheet | -| Files | 打开 Files 全屏 Sheet | -| Terminal | 打开 Terminal 全屏 Sheet | - -当前激活态规则: - -- Agent Sheet 打开时,高亮 Agent -- Files / Terminal Sheet 打开时,高亮对应项 - -### 4.4.7 Agent Sheet - -#### 4.4.7.1 模式 - -Agent Sheet 有两个模式: - -- `sessions`:会话列表 -- `providers`:创建新会话 - -默认规则: - -- 当前已有 session:默认进入 `sessions` -- 当前没有 session:默认进入 `providers` - -#### 4.4.7.2 会话列表模式 - -内容包含: - -- “创建 session”动作项 -- 当前 workspace 下的 session 列表 - -每个 session 行提供: - -- 主点击:切换到该 session 并关闭 Sheet -- 行尾关闭按钮:关闭该 session,然后关闭 Sheet - -#### 4.4.7.3 Provider 模式 - -当前固定展示两个 provider: - -- Claude -- Codex - -交互规则: - -- 选择 provider 后,复用与桌面相同的 runtime / auto-install / create 流程 -- 成功创建后: - - 写入 session 数据 - - 追加到布局 - - 切换为移动端当前会话 - - 关闭 Sheet - -与桌面不同的是: - -- 移动端按 provider 逐项展示 busy 状态并只禁用忙碌项 -- 桌面端则在任一 provider 忙碌时整体锁定全部 provider 卡片 - -### 4.4.8 Files Sheet - -Files Sheet 是一个全屏 Sheet,包含三种 route 状态: - -- `root` -- `editor` -- `diff` - -#### 4.4.8.1 Root 状态 - -Root 状态顶部包含: - -- 当前分支按钮 -- Files / Git Tab -- 内联 Git 状态栏 - -##### 分支按钮 - -- 点击打开分支快速切换 -- 文案显示当前分支名;无值时显示 no branch 文案 - -##### Tab 行为 - -| Tab | 内容 | -| --- | --- | -| Files | 文件树 | -| Git | Git 面板 | - -#### 4.4.8.2 Editor 状态 - -- 进入方式:在 Files Tab 中点选文件 -- 主体:代码编辑器 / 文件预览 -- 页面级返回:通过 Sheet Header 的 Back 回到 root -- Header 右侧动作: - - 文本型图片可切换图像 / 文本 - - 文本文件可保存 - -#### 4.4.8.3 Diff 状态 - -- 进入方式:在 Git Tab 中点选某个变更 -- 主体:Diff Viewer -- 页面级返回:通过 Sheet Header 的 Back 回到 root -- 关闭整个 Sheet:直接退出 Files Sheet - -### 4.4.9 Terminal Sheet - -移动端 Terminal 通过全屏 Sheet 打开,内部复用同一套终端能力。 - -#### 4.4.9.1 工具栏差异 - -与桌面相比: - -- 仅在存在 terminal 时展示当前 terminal selector -- 多 terminal 时通过 `MobileSelectSheet` 选择 -- 不展示桌面 tabs - -#### 4.4.9.2 移动端软按键栏 - -移动端 xterm 上方会显示一条真实可用的软按键栏,包含: - -- `Ctrl` -- `Shift` -- `Esc` -- `Tab` -- `↑` -- `←` -- `↓` -- `→` -- `Enter` - -交互规则: - -| 按键 | 行为 | -| --- | --- | -| Ctrl 点击 | 在 off / armed 之间切换 | -| Ctrl 长按 | 锁定为 locked | -| Shift 点击 | 切到 armed;下一个软键输入后自动消耗 | -| 方向 / Esc / Tab / Enter | 直接写入对应控制序列 | - -软按键栏在以下情况下禁用: - -- 当前 terminal 不可交互 -- 正在上传文件 -- WebSocket 未连接 - -### 4.4.10 Supervisor Sheet - -移动端 Supervisor 分为两层: - -#### 4.4.10.1 Root 层 - -| 场景 | 页面表现 | -| --- | --- | -| 当前 session 已启用 supervisor | 展示状态卡片与“编辑目标” / “禁用”按钮 | -| 当前 session 未启用 supervisor | 展示空态与“启用目标”按钮 | - -#### 4.4.10.2 Detail 层 - -启用、编辑、禁用都会进入 detail 层,支持: - -- 展示 mode 对应标题、副标题、图标 -- 编辑 objective -- 选择 evaluator provider -- 底部固定 Cancel / Confirm 按钮 - -选择 evaluator provider 时,会再打开一个选择 Sheet。 - -### 4.4.11 Workspace Drawer - -#### 4.4.11.1 列表项 - -每个 workspace 行包含: - -- 主区域:切换到该 workspace,并导航到 `/workspace` -- 关闭按钮:关闭该 workspace - -#### 4.4.11.2 底部动作 - -抽屉底部固定一个按钮: - -- 打开 workspace 启动器 - -#### 4.4.11.3 关闭最后一个 workspace - -从移动端抽屉关闭最后一个 workspace 时,会显式要求“若为空则返回首页”,因此会回到欢迎页。 - ---- - -## 4.5 设置页 `/settings` - -### 4.5.1 页面目标与导航结构 - -设置页用于管理: - -- 通知 -- Provider 启动参数与配置文件 -- 外观 -- 部分快捷键配置 - -桌面与移动共用同一页能力,但导航结构不同: - -| 端 | 导航结构 | -| --- | --- | -| 桌面 | 左侧 Section 导航 + 右侧内容区 | -| 移动 | Root 列表页 + Detail 子页 | - -当前 section 可见范围如下: - -| 端 | 可见 section | -| --- | --- | -| 桌面 | General / Providers / Appearance / Shortcuts | -| 移动 | General / Providers / Appearance | - -> **说明:** -> 移动端当前没有 Shortcuts 入口。 - -### 4.5.2 通用规则 - -#### 4.5.2.1 返回逻辑 - -| 场景 | Back 行为 | -| --- | --- | -| 移动端 detail 页 | 先返回移动 root 列表 | -| 其他情况 | 优先走浏览器 history;否则回 `/workspace`;再否则回 `/` | - -#### 4.5.2.2 加载逻辑 - -连接可用后,设置页会加载设置数据,并同步以下内容到页面状态: - -- 通知总开关 -- 通知声音开关 -- 终端 renderer -- 语言 -- provider additional args -- external config audit - -若加载失败: - -- 内容区顶部出现 error notice -- 用户可点击 Refresh 重新拉取 - -#### 4.5.2.3 通用页脚 - -设置页底部固定显示: - -- autosave 提示 -- 版本字符串 `v0.2.6` - -#### 4.5.2.4 页面内 Banner - -设置内容区顶部嵌入配置漂移 Banner,用于处理 Codex 配置漂移问题。 - -### 4.5.3 General - -General 当前只包含通知相关设置。 - -#### 4.5.3.1 开关项 - -| 设置项 | 交互规则 | -| --- | --- | -| Notifications Enabled | 开关即时保存 | -| Notification Sound | 开关即时保存;当 Notifications Enabled 关闭时,该项禁用 | - -前端同时会把两项值同步到本地通知偏好。 - -#### 4.5.3.2 浏览器能力状态 - -页面会检测浏览器通知能力,并显示三种状态之一: - -- `available` -- `limited` -- `unsupported` - -移动端判断规则: - -- 若是移动设备且不是 standalone web app,则记为 `limited` - -#### 4.5.3.3 权限状态 - -页面会显示浏览器通知权限状态: - -- `granted` -- `denied` -- `default` -- `unavailable` - -其中: - -- 当状态为 `default` 且 capability 为 `available` 时,显示“请求权限”按钮 -- 当状态为 `denied` / `limited` / `unavailable` 时,显示对应说明文字 - -### 4.5.4 Providers - -Providers 是设置页中最复杂的一组内容,分为两个层次: - -1. 启动参数层 -2. 配置文件编辑层 - -#### 4.5.4.1 Provider 切换 - -当前固定两个 Provider: - -- Claude -- Codex - -#### 4.5.4.2 启动参数层(Base) - -桌面端有二级切换: - -- Base -- Config File - -移动端默认先进入 Base,再通过单独入口进入 Config File。 - -Base 层当前包含: - -| 功能点 | 交互规则 | -| --- | --- | -| Additional Args 文本域 | 一行一个参数;变更即自动保存 | -| Command Preview | 实时刷新命令预览 | - -#### 4.5.4.3 配置文件编辑层(Config File) - -配置文件编辑器的实际行为如下: - -| 功能点 | 交互规则 | -| --- | --- | -| 加载 | 进入后读取真实配置文件内容与绝对路径 | -| 文件不存在 | 显示空态与提示,但仍保留卡片结构 | -| 展开 / 收起 | 卡片可折叠;展开状态持久化到本地存储 | -| 编辑器 | 使用 Monaco | -| 状态显示 | `saved / dirty / saving / error` | -| Save | 保存到真实配置文件;若产生备份路径,会通过 Toast 告知 | -| Reset | 恢复成最近一次加载 / 保存后的内容 | -| Format | 仅 `claude` 配置支持;本质是 JSON pretty-print | - -#### 4.5.4.4 布局差异 - -| 端 | 行为 | -| --- | --- | -| 桌面 | Provider Tab + Base / Config File 二级切换;Config File 可占满剩余高度 | -| 移动 | Base 页展示“打开配置文件编辑器”入口;点击后进入配置文件子层,并提供返回 Base 的按钮 | - -### 4.5.5 Appearance - -Appearance 当前包含三项: - -- Theme -- Terminal Renderer -- Language - -#### 4.5.5.1 Theme - -| 功能点 | 交互规则 | -| --- | --- | -| Dark / Light 切换 | 点击后立即切换前端主题 | -| 本地持久化 | 主题选择会写入本地存储 | -| 服务端保存 | 页面会尝试同步保存到设置 | - -> **当前实现边界:** -> 主题的即时生效是完整的; -> 但服务端持久化仍有边界,详见第 `8.2` 章。 - -#### 4.5.5.2 Terminal Renderer - -支持两种 renderer: - -- `standard` -- `compatibility` - -点击后立即保存。 - -#### 4.5.5.3 Language - -支持: - -- 中文 `zh` -- 英文 `en` - -点击后会立即切换前端语言并保存配置。 - -### 4.5.6 Shortcuts(仅桌面) - -Shortcuts 页面当前提供的是**快捷键配置 UI**,分四类: - -- Global -- Workspace -- Editor -- Terminal - -#### 4.5.6.1 配置交互 - -| 功能点 | 行为 | -| --- | --- | -| 点击某一快捷键绑定 | 进入捕获态 | -| 捕获输入 | 记录 `Mod / Shift / Alt + Key` | -| `Escape` | 取消当前捕获 | -| Reset 单项 | 删除该项自定义绑定 | -| Reset All | 清空全部自定义绑定 | - -所有修改都会: - -- 写入本地快捷键配置 -- 同步保存到设置 - -#### 4.5.6.2 当前能力边界 - -这个页面当前的真实能力应定义为: - -- 查看默认绑定 -- 录入 / 重置自定义绑定 -- 保存配置 - -而**不是**“全局快捷键立即生效系统”。 -更具体的运行时边界见第 `8.3` 章。 - ---- - -## 4.6 404 页面 `*` - -404 页面沿用欢迎页的视觉壳体,包含: - -- kicker -- 标题 -- 描述 -- 一个状态面板,展示当前未命中的路径 -- 返回首页按钮 - -交互规则非常简单: - -- 点击按钮后返回 `/` - ---- - -## 5. 跨页面系统 - -## 5.1 命令面板(Quick Actions) - -命令面板在桌面与移动端都已接线。 - -### 5.1.1 打开方式 - -当前**真实已接线的全局热键**只有一个: - -- `Ctrl/Cmd + K`:打开 / 关闭命令面板 - -### 5.1.2 展现形态 - -| 端 | 形态 | -| --- | --- | -| 桌面 | 居中 overlay modal | -| 移动 | 全屏 Sheet | - -### 5.1.3 打开后的通用行为 - -- 自动聚焦搜索框 -- 清空上次搜索词 -- 选中索引重置为第一项 - -### 5.1.4 键盘交互 - -| 按键 | 行为 | -| --- | --- | -| `ArrowDown` | 下移选中项 | -| `ArrowUp` | 上移选中项 | -| `Enter` | 执行当前选中命令并关闭面板 | -| `Escape` | 关闭面板 | - -### 5.1.5 当前命令集合 - -#### 全端通用 - -- 打开 workspace 启动器 -- 返回首页 -- 打开设置页 -- 切换到某个已打开 workspace -- 当存在 active workspace 时,额外提供“返回首页并清空 active workspace”命令 - -#### 桌面专属 - -- 切换 Focus Mode -- 显式打开 Focus Mode -- 显式关闭 Focus Mode -- 切换左侧栏显示 -- 切换终端显示 -- 显式打开终端 -- 显式关闭终端 - -### 5.1.6 展示文案与真实监听的边界 - -面板列表中当前可能会展示如下 shortcut 文案: - -- `Ctrl+N` -- `Ctrl+,` -- `F` - -这些当前只是**列表文案**,不等于对应全局快捷键已经真实接线。 - -## 5.2 Workspace 启动器 - -欢迎页、桌面顶栏与移动抽屉共用同一个 workspace 启动器。 - -### 5.2.1 打开形态 - -| 端 | 形态 | -| --- | --- | -| 桌面 | Modal | -| 移动 | 全屏 Sheet | - -### 5.2.2 目录浏览 - -| 功能点 | 行为 | -| --- | --- | -| Home 按钮 | 跳到 `~` | -| Go Up 按钮 | 跳到上级目录;根目录 `/` 时不显示 | -| 预设根路径 chips | 当前固定显示 `/`、`~`、`/home/spencer` 三个入口 | -| 当前路径 chip | 若当前路径不在预设 chips 中,额外追加一个当前路径 chip | -| 单击目录行 | 选中目录 | -| 双击目录行 | 进入该目录 | -| 选中目录后的行内动作 | 出现“进入目录”动作按钮 | - -### 5.2.3 启动规则 - -- Start 按钮在未选择目录时禁用 -- 点击 Start 后打开该目录为 workspace -- 成功后: - - 把 workspace 加入本地列表 - - 更新 workspace 顺序 - - 设置为当前 active workspace - - 若当前不在 `/workspace`,自动导航到 `/workspace` - - 关闭启动器 - -### 5.2.4 快捷关闭 - -桌面版启动器会监听: - -- `Escape`:关闭弹窗 - -## 5.3 分支快速切换 - -### 5.3.1 触发入口 - -- 桌面左侧栏分支按钮 -- 移动 Files Sheet 的分支按钮 - -### 5.3.2 展现形态 - -| 端 | 形态 | -| --- | --- | -| 桌面 | Overlay 弹层 | -| 移动 | 选择 Sheet | - -### 5.3.3 搜索与切换 - -| 功能点 | 行为 | -| --- | --- | -| 搜索框 | 按名称过滤 branch 列表 | -| 当前分支 | 带勾选标记 | -| 远端分支 | 带 `Remote` badge | -| 选择已有分支 | 直接切换到该分支 | - -### 5.3.4 新建分支 - -当前实现不是“一次点击直接创建”,而是**二次确认**: - -1. 输入一个不存在的分支名时,列表出现“Create xxx” -2. 选择一次后,变成“Confirm create xxx” -3. 再确认一次,才真正创建并切换 - -### 5.3.5 键盘交互 - -| 按键 | 行为 | -| --- | --- | -| `ArrowDown / ArrowUp` | 移动选中项 | -| `Enter` | 选中分支 / 发起创建 / 确认创建 | -| `Escape` | 关闭 | - -## 5.4 连接状态横幅 - -全局连接横幅统一处理以下状态: - -- `reconnecting`:显示“正在重新连接...” -- `rejected`:显示“另一个标签页已激活” -- 其他非连接态:显示“连接已断开” - -## 5.5 Toast 与通知 - -### 5.5.1 Toast 容器 - -Toast 容器支持: - -- 最多同时保留最近 `5` 条 -- `success / error / warning / info` 四种类型 -- 自动消失(默认 `5s`,`duration = 0` 可改为手动) - -### 5.5.2 Toast 点击行为 - -| Toast 附带数据 | 点击结果 | -| --- | --- | -| `workspaceId + sessionId` | 跳到对应 workspace,并让 session 获得聚焦 / 滚动到视野 / 高亮脉冲 | -| 仅 `workspaceId` | 切换到对应 workspace,并在必要时导航到 `/workspace` | -| 无跳转数据 | 仅关闭 Toast | - -### 5.5.3 Session 完成通知 - -当前只针对“Agent 一轮工作完成”发通知,触发规则非常明确: - -- 主触发:`running -> idle` -- 兜底触发:`running -> ended` - -并且: - -- 小于 `4s` 的短轮次不会通知 -- 当前页可见时: - - 如果桌面端当前 active workspace 已是该 session 所属 workspace - - 或移动端正在看对应 session - - 则抑制通知 -- 当前页可见但用户不在对应 workspace / session: - - 发 in-app toast -- 当前页隐藏: - - 发浏览器系统通知 - -若开启 sound: - -- 优先播放 `/task-complete.wav` -- 播放失败时回退到 Web Audio 合成提示音 - -## 5.6 Supervisor 编辑容器 - -Supervisor 的编辑类交互由两种容器承载: - -| 端 | 容器 | -| --- | --- | -| 桌面 | Modal 对话框 | -| 移动 | 全屏 Sheet + 可选选择 Sheet | - -支持的 mode: - -- enable -- edit -- disable - -可编辑字段: - -- Objective 文本 -- Evaluator Provider - ---- - -## 6. 已接线快捷键与输入基线 - -本章只列出**当前确认已接线**的交互,不列历史 PRD 中曾规划但当前没有统一监听的内容。 - -### 6.1 全局级 - -| 交互 | 状态 | -| --- | --- | -| `Ctrl/Cmd + K` | 已接线:打开 / 关闭命令面板 | - -### 6.2 浮层内部 - -| 浮层 | 已接线交互 | -| --- | --- | -| 命令面板 | `ArrowUp / ArrowDown / Enter / Escape` | -| 分支快速切换 | `ArrowUp / ArrowDown / Enter / Escape` | -| Workspace 启动器(桌面) | `Escape` 关闭 | - -### 6.3 编辑器内部 - -| 交互 | 状态 | -| --- | --- | -| Monaco `Ctrl/Cmd + S` | 已接线:保存当前文本文件 | - -### 6.4 移动终端 - -已接线软按键: - -- Ctrl / Shift -- Esc / Tab / Enter -- 上下左右方向键 - -### 6.5 当前不要写成“已上线快捷键”的项 - -以下项**不要在当前产品能力里写成已上线全局快捷键**: - -- `Ctrl/Cmd + N` -- `Ctrl/Cmd + ,` -- `F` -- 任何 pane split 快捷键 -- Settings 页面里录入的自定义快捷键绑定 - -它们当前最多只是: - -- 命令面板中的展示文案 -- 或仅存在于未挂载组件 / 未统一消费的代码中 - ---- - -## 7. 系统边界与异常处理 - -## 7.1 文件 / Git 变更联动 - -服务端会推送文件与 Git 脏变更事件。前端收到后会按提示做这些刷新: - -- 刷新 Git 状态 -- 刷新分支列表 -- 标记文件树 stale 并按需重载 -- 刷新已打开编辑器 buffer - -## 7.2 认证边界 - -当前前端没有显式“退出登录”入口,尽管服务端存在对应接口。 - -登录相关异常主要包括: - -- 密码错误 -- 登录接口不可达 -- 因过多失败而进入临时封禁 - -## 7.3 上传边界 - -终端粘贴 / 拖拽上传存在以下边界: - -- 请求必须带 `workspaceId` -- 当前批次必须至少包含一个文件 -- 工作区不存在时返回 `workspace_not_found` -- 文件过大、解析失败、写入失败时返回对应错误 -- 失败时前端通过 error toast 告知 - -## 7.4 图片预览边界 - -`/api/file` 当前只服务于图片预览: - -- 非图片类型会返回 `not_an_image` -- 路径越界会返回 `path_escape` -- 不是通用文件下载接口 - ---- - -## 8. 实现附录与未纳入范围 - -本章只处理两类问题: - -1. 正文里不适合展开、但必须保留的实现事实 -2. 仓库中虽然存在,但当前不能写成已上线能力的项 - -### 8.1 认证路由实现备注 - -前端登录页挂载在 `/login`。 - -后端鉴权接口仍然位于 `/auth/*`,例如: - -- `/auth/status` -- `/auth/login` -- `/auth/logout` - -`/auth` 不是前端页面路由,产品流程文档不应再把它描述成登录页。 - -### 8.2 Theme 持久化边界 - -当前前端 UI 真实支持浅色 / 深色即时切换; -但服务端设置 schema 仅完整接受 `appearance.theme = "dark"` 这一路径。 - -因此: - -- 主题**即时生效**是成立的 -- 主题**服务端持久化完整一致**当前并不完整 - -产品文档不应把它写成“前后端完全一致持久化的主题系统”。 - -### 8.3 当前不要纳入“已上线能力”的项 - -以下能力虽然在仓库里能看到组件、测试或片段实现,但**当前不应写成用户已可达功能**: - -#### 8.3.1 `WorktreeModal` - -- 组件存在 -- 但当前没有在实际页面中挂载为可达入口 - -#### 8.3.2 独立 `FocusMode` 组件 - -- 组件存在 -- 内部定义了 `F` / `Escape` 等逻辑 -- 但当前未发现它被壳层或工作区页面挂载 - -当前用户真正可见的 focus mode 入口,仅确认来自**命令面板对专注模式状态的切换**。 - -#### 8.3.3 Shortcuts 运行时替换 - -- Shortcuts 设置页已存在 -- 自定义绑定已能保存 -- 但运行时没有统一用这些绑定驱动全局热键 - -因此,不应把“自定义快捷键会全局即时生效”写入当前 PRD。 - ---- - -## 9. 本版 PRD 的维护原则 - -后续继续维护本 PRD 时,应遵循三条原则: - -1. **正文按页面与用户流程写,不按技术模块堆叠。** -2. **先写真实可达交互,再写状态、错误、边界。** -3. **组件存在不等于功能上线;没有挂载或没有统一监听的能力,不写成当前产品能力。** +说明: +- `docs/product-spec/` 是当前产品规格文档的维护目录。 +- 现状功能、页面、路由和模块描述以 `current-baseline.zh-CN.md` 及其后续同步的模块文档为准。 +- 若旧 `docs/PRD*.md` 与 `product-spec` 内容冲突,以 `product-spec` 为准。 diff --git a/docs/help/README.md b/docs/help/README.md index f22eee7d6..242f0f50f 100644 --- a/docs/help/README.md +++ b/docs/help/README.md @@ -17,12 +17,12 @@ ## 我主要在手机上使用 -- [移动端与远程访问指南](mobile-guide.md) — 手机端界面、局域网访问、Tailscale/ngrok/Cloudflare Tunnel +- [移动端与远程访问指南](mobile-guide.md) — 手机端当前布局、局域网访问、Tailscale/ngrok/Cloudflare Tunnel ## 我想了解产品结构 - [App 功能总览](app-overview.md) — 核心概念与能力说明 -- [工作分析](work-analysis.md) — 多工作区、多时间范围的基础分析与深入分析 +- [工作分析](work-analysis.md) — 当前 dashboard 式工作分析、目录/时间筛选与刷新机制 --- diff --git a/docs/help/app-overview.md b/docs/help/app-overview.md index 994a2e035..4f73b4020 100644 --- a/docs/help/app-overview.md +++ b/docs/help/app-overview.md @@ -21,7 +21,7 @@ Coder Studio 是一款**本地优先**的 AI 编码工作台。它将 AI Agent - 独立的终端会话 - Git 状态信息 -你可以同时打开多个工作区,通过顶栏的工作区标签切换。 +你可以同时打开多个工作区。桌面端通过顶栏标签切换,移动端通过工作区抽屉切换。 ### Session(会话) @@ -62,21 +62,20 @@ Provider 需要在本地独立安装。Coder Studio 会在启动会话时调用 - 让 Agent 通过 `coder-studio capabilities --json` 查看可用的只读验证命令清单 - 让 Agent 读取终端输出、Git 状态和指定文件 diff,辅助最终检查 -### Settings(设置) +### More(更多) -设置页面提供以下配置: +桌面端和移动端都通过顶栏的 **More / 更多** 按钮进入统一的 `/more` 页面。当前没有顶级 `/settings` 路由。`/more` 当前分为三组内容: -- **General**:通知开关、语言设置 -- **Providers**:查看和配置每个 Provider 的启动参数 -- **Appearance**:主题切换、终端渲染方式 -- **Shortcuts**:查看和自定义快捷键 +- **Settings**:`General`、`Providers`、`Terminal`、`Appearance`、`Shortcuts` +- **Analysis**:`Work Analysis`、`Monitoring`、`Diagnostics` +- **About**:`Product`、`Update Status`、`Auto Update` ## 桌面端 vs 移动端 Coder Studio 使用响应式界面,同一服务同时支持: -- **桌面端**:多面板布局、快捷键、专注模式([桌面端使用指南](desktop-guide.md)) -- **移动端**:底部 Dock 导航、全屏面板([移动端使用指南](mobile-guide.md)) +- **桌面端**:多面板布局、快捷键、专注模式和顶栏快速操作([桌面端使用指南](desktop-guide.md)) +- **移动端**:顶部栏、当前会话主区、Sheet/Drawer 和底部状态栏([移动端使用指南](mobile-guide.md)) ## 适合的使用场景 @@ -92,4 +91,4 @@ Coder Studio 使用响应式界面,同一服务同时支持: 可以。你可以在同一工作区内同时运行多个 Provider 会话。 **Q:可以打开多个项目吗?** -可以。通过顶栏的工作区标签切换,每个工作区独立管理自己的会话、文件和终端。 +可以。桌面端通过顶栏标签切换,移动端通过工作区抽屉切换;每个工作区独立管理自己的会话、文件和终端。 diff --git a/docs/help/desktop-guide.md b/docs/help/desktop-guide.md index 8b98b2dd8..c7f8826a5 100644 --- a/docs/help/desktop-guide.md +++ b/docs/help/desktop-guide.md @@ -98,7 +98,7 @@ 高级设置键 `git.autofetchPeriodSec` 控制活动工作区的周期性远程 fetch,默认值是 `180` 秒;设为 `0` 会关闭周期性 fetch,但不会影响打开工作区时的自动 fetch,也不会影响手动点击 **Fetch**。 -当前设置页还没有这个高级键的图形化入口。如需手动调整,可以直接编辑本地状态目录里的 `settings.json`。默认路径通常是 `~/.coder-studio/data/state/settings.json`;如果你通过 `coder-studio config --state-dir ...` 改过状态目录,请使用你自己的路径。 +当前 `/more/settings/*` 相关页面还没有这个高级键的图形化入口。如需手动调整,可以直接编辑本地状态目录里的 `settings.json`。默认路径通常是 `~/.coder-studio/data/state/settings.json`;如果你通过 `coder-studio config --state-dir ...` 改过状态目录,请使用你自己的路径。 ```bash node -e ' diff --git a/docs/help/mobile-guide.md b/docs/help/mobile-guide.md index 6c850c066..6d6df6676 100644 --- a/docs/help/mobile-guide.md +++ b/docs/help/mobile-guide.md @@ -189,54 +189,68 @@ https://coder.example.com -> http://localhost:<端口> ## 移动端界面结构 -![移动端界面结构](assets/screenshot-mobile-layout.png) +当前移动端不是底部 Dock 驱动布局,而是 `顶部栏 + 当前会话主区 + Sheet/Drawer + 底部状态栏`。 ### 顶部栏 -- 工作区名称(点击打开工作区抽屉,可切换工作区) -- 设置入口 -- 全屏入口(仅在浏览器支持原生全屏时显示) +- 工作区按钮(点击打开工作区抽屉,可切换工作区、切换会话、打开新工作区) +- Files 按钮(打开文件 Sheet) +- Terminal 按钮(打开终端 Sheet) +- More 按钮(进入 `/more`,包含 settings、analysis、about) +- 全屏按钮(仅在浏览器支持原生全屏时显示) -### 当前 Agent 区域 +### 当前会话主区 -显示当前活跃会话的状态和输出。没有会话时会显示提示信息。 +- 显示当前活跃会话的状态、输出和可用的 Supervisor 内联信息 +- 没有会话时会显示空状态和 **创建会话** 按钮 -### 底部 Dock +### 抽屉与全屏面板 -底部有三个入口: +- **工作区抽屉**:从顶部栏左侧工作区按钮打开,包含工作区列表、当前工作区的创建会话按钮、会话列表和打开新工作区入口 +- **Files Sheet**:从顶部栏 Files 打开,支持文件树、搜索、Git/Source Control 和文件详情 +- **Terminal Sheet**:从顶部栏 Terminal 打开,显示该工作区的终端面板 +- **Supervisor Sheet**:当当前会话存在活跃 Supervisor 时,可打开详情面板 -- **Agent**:打开 Agent 面板,管理会话 -- **Files**:打开文件面板 -- **Terminal**:打开终端面板 +> 注:仓库里虽然存在 `MobileDock` 组件,但当前实现并未挂载,移动端文档不应再把它写成正式入口。 + +### 底部状态栏 + +- 显示工作区状态和 Git/分支相关信息 +- 在终端全屏 Sheet 中也会保留状态栏 ## 操作步骤 ### 切换或打开工作区 -点击顶部栏的工作区名称,打开工作区抽屉。在抽屉中可以: +点击顶部栏左侧的工作区按钮,打开工作区抽屉。在抽屉中可以: - 切换到其他已打开的工作区 -- 点击按钮打开新的工作区 +- 展开某个工作区查看其会话列表 +- 点击入口打开新的工作区 ### 创建第一个 Agent 会话 -点击底部 Dock 的 **Agent** 按钮,打开 Agent 面板。如果没有活跃会话,面板默认处于创建模式。点击创建会话并选择 Provider。 +- 如果当前工作区还没有会话,直接点击主区空状态里的 **创建会话** +- 或者先打开工作区抽屉,再点击当前工作区右侧的创建会话按钮 +- 之后选择一个已检测到的 Provider,创建会话 ### 切换当前会话 -在 Agent 面板中可以看到所有会话列表。点击任意会话即可将其设为当前活跃会话。 +打开工作区抽屉,展开当前工作区,点击任意会话即可将其切换为当前活跃会话。 ### 查看文件 -点击底部 Dock 的 Files 按钮,打开文件面板。文件面板包含: +点击顶部栏的 Files 按钮,打开文件 Sheet。当前支持: - 文件树浏览 +- 搜索视图 +- Git / Source Control 视图 - 点击文件可查看内容 -- Git 视图(查看分支和变更列表) +- 查看 diff 明细 ### 查看终端 -点击底部 Dock 的 Terminal 按钮,打开终端面板。包含: +点击顶部栏的 Terminal 按钮,打开终端 Sheet。包含: - 该工作区的所有终端 - 新建终端的入口 @@ -252,7 +266,7 @@ https://coder.example.com -> http://localhost:<端口> ## 使用建议 - 移动端适合"查看"为主,复杂的文件编辑和 Agent 管理建议在桌面端完成 -- 手机键盘弹出时会压缩底部 Dock 区域,操作时注意布局变化 +- 手机键盘弹出时会影响底部状态区域和全屏 Sheet 的可视高度,操作时注意布局变化 - 终端操作在小屏幕上可能不便,建议仅在需要时查看 - 如果浏览器支持原生全屏,可点击顶部栏右侧的全屏按钮进入;再次点击同一位置的按钮可退出 - 某些移动端浏览器不支持原生全屏,此时不会显示该按钮 diff --git a/docs/help/providers.md b/docs/help/providers.md index 8b8fe0897..e79a1f51b 100644 --- a/docs/help/providers.md +++ b/docs/help/providers.md @@ -129,9 +129,9 @@ Aider 不属于当前内置 Provider 列表。它适合通过 preset/custom-prov 自定义 Provider 主要是交互式命令集成,不一定支持内置 Provider 的 supervisor、idle detection、Agent instructions 或自动安装能力。 -## 在设置页中配置 Provider +## 通过 More > Settings > Providers 配置 Provider -进入设置 → Providers 页面,你可以针对每个 Provider 配置 `additionalArgs`。 +从工作区顶栏进入 **More / 更多 > Settings > Providers**,对应路由为 `/more/settings/providers`。在这里你可以针对每个 Provider 配置 `additionalArgs`。 ### additionalArgs 是什么 @@ -147,7 +147,7 @@ Aider 不属于当前内置 Provider 列表。它适合通过 preset/custom-prov ### 修改后如何验证 -保存设置后,设置页面会显示 **Command Preview**,你可以看到最终有效的完整命令。 +保存设置后,Providers 区域会显示 **Command Preview**,你可以看到最终有效的完整命令。 ## 常见问题 diff --git a/docs/help/quick-start.md b/docs/help/quick-start.md index a18616617..7b0d1d0dd 100644 --- a/docs/help/quick-start.md +++ b/docs/help/quick-start.md @@ -64,23 +64,24 @@ coder-studio open ### 2. 创建第一个 Agent 会话 -打开工作区后,你会看到 Agent 工作区。点击 **"创建会话"**,选择已检测到的 Provider 即可开始。首次试跑建议选择 Claude 或 Codex。 +打开工作区后,你会看到 Agent 工作区。桌面端点击 **"创建会话"**;移动端点击空状态里的 **"创建会话"**,或从工作区抽屉里发起创建。选择已检测到的 Provider 即可开始。首次试跑建议选择 Claude 或 Codex。 如果 Provider 未安装,界面上会显示安装提示和指引。 ### 3. 查看终端和文件 -- 底部面板显示终端,你可以看到 Agent 的输出,也可以自己打开 Shell 终端运行命令 -- 左侧面板显示文件树,可以浏览项目结构 +- 桌面端:底部面板显示终端,左侧面板显示文件树 +- 移动端:通过顶部栏的 Files 和 Terminal 按钮打开对应 Sheet -### 4. 进入设置 +### 4. 进入 More 与设置相关页面 -点击顶栏右侧的齿轮图标进入设置页,这里可以: +点击工作区顶栏右侧的 **More / 更多** 按钮,进入统一的 `/more` 页面。这里可以: - 切换语言(中文/英文) - 切换主题(浅色/深色) - 查看 Provider 状态和配置 - 自定义快捷键 +- 打开工作分析、监控和诊断页面 ## 常见问题 diff --git a/docs/help/work-analysis.md b/docs/help/work-analysis.md index 63712c091..cb237eeaf 100644 --- a/docs/help/work-analysis.md +++ b/docs/help/work-analysis.md @@ -2,54 +2,47 @@ ## 这篇文档解决什么问题 -帮助你理解 `工作分析` 能看什么、怎么筛选,以及 `基础分析` 和 `深入分析` 的区别。 +帮助你理解当前 `工作分析` 页面的入口、筛选方式、刷新机制,以及它能提供哪些 dashboard 信息。 ## 前置条件 -- 至少打开一个工作区,让 Coder Studio 知道要分析哪个 workspace path -- 该 workspace 在所选时间范围内最好有 provider 本地日志 +- 至少有一个工作区在所选时间范围内产生过 Provider 本地日志 - 不要求当前有打开中的 Coder Studio session -## 怎么用 - -1. 打开设置页,进入 `工作分析` -2. 选择一个或多个工作区 -3. 选择时间范围 -4. 先运行 `基础分析` -5. 如需更高维度结论,再运行 `深入分析` +## 入口 -## 基础分析会给出什么 +- 从顶栏进入 **More / 更多 > Analysis > 工作分析** +- 或直接访问独立页面 `/analytics` +- 在 `/more/analysis/analytics` 中也可以进入嵌入版入口 -- 覆盖范围:命中的工作区数、provider 本地会话数、provider 数 -- 活动统计:总时长、平均会话时长、用户/助手/工具调用信号 -- 工作时间:provider 本地会话主要发生在哪些小时段 -- Provider 结构:常用 provider 分布,以及每个 provider 的日志状态 -- Skill 资产:已安装、已挂载、未挂载的 skill 数量 - -这部分会扫描 provider 保存在本机的日志或缓存数据,目前覆盖 5 个内置 provider:`claude`、`codex`、`gemini`、`cursor`、`opencode`。 +## 怎么用 -不同 provider 的数据质量可能不同: +1. 打开页面后,系统会自动读取现有 dashboard,并在需要时补齐缺失或落后的小时索引 +2. 使用 `时间` 筛选器选择 `24h`、`7d`、`30d`、`90d` 或自定义区间 +3. 使用 `目录` 筛选器选择一个或多个工作区路径 +4. 查看 KPI、Token 趋势、Agent/模型/项目贡献、任务/工具/Skill 归因和工作时段热力图 +5. 如需获取当前查询范围的最新结果,点击 `立即刷新` +6. 如索引明显落后或需要彻底重扫,使用 `强制刷新` -- 有些 workspace 在选定时间范围内没有匹配日志 -- 有些 provider 只能返回部分数据 -- 有些会话缺少明确时间戳,只能回退到文件修改时间 +## 当前页面会给出什么 -## 深入分析会给出什么 +- KPI:会话、活跃时长、Token 等汇总指标 +- 趋势图:按时间范围聚合的 Token 趋势 +- 贡献排行:Agent、模型、项目维度的主要贡献者 +- 归因分布:任务类型、工具调用、Skill 调用 +- 热力图:工作主要发生在哪些小时段 -- 工作内容总结 -- 重复出现的工作模式 -- 主要瓶颈 -- 流程改进建议 -- 可沉淀为 skill 的候选项 +## 刷新和重建有什么区别 -这部分会把基础分析结果和从 provider 日志中采样出来的代表性证据交给 headless agent,所以成本更高,也依赖 provider 的 headless 能力。 +- `立即刷新`:针对当前查询手动刷新 dashboard 数据 +- `强制刷新`:清空工作分析小时索引并重新扫描历史日志,但不会删除原始日志 ## 当前限制 -- skill 使用次数不是 v1 的强保证,目前主要是 inventory 视角 -- 不同 provider 可读到的数据并不完全对称 +- 当前主界面是 dashboard 流,不再把旧版 `基础分析 / 深入分析` 作为主要操作入口 +- Skill 调用归因目前只统计 Claude 日志中可识别的调用次数 +- 不同 Provider 可读到的数据并不完全对称 - 本地 provider 日志可能缺失、部分损坏,或者因时间戳缺失而回退到文件修改时间 -- 深入分析失败不会影响基础分析结果 ## 下一步 diff --git a/docs/help/workflows.md b/docs/help/workflows.md index dd26e3f63..4cf886b87 100644 --- a/docs/help/workflows.md +++ b/docs/help/workflows.md @@ -16,13 +16,13 @@ 1. 启动服务:`coder-studio open` 2. 浏览器中点击"打开工作区" 3. 在目录选择器中找到你的项目目录并确认 -4. 项目加载后,点击"创建会话"选择 Provider +4. 项目加载后,桌面端点击"创建会话";移动端使用空状态里的创建会话按钮,或从工作区抽屉里创建会话 5. Agent 会话启动后,你就可以通过终端输入指令开始协作 ## 启动一个新的 Agent 会话 - **桌面端**:在 Agent 面板中点击创建会话,选择 Provider -- **移动端**:点击底部 Dock 的 Agent,然后点击创建会话 +- **移动端**:点击当前会话空状态里的创建会话,或先打开工作区抽屉,再点击当前工作区右侧的创建会话按钮 每个会话是独立的,可以在同一工作区内并行运行多个会话。 @@ -30,21 +30,21 @@ Agent 工作期间,你可以: -- 通过左侧文件树查看被修改的文件 -- 通过底部终端面板中的 Agent 终端观察 Agent 输出 +- 桌面端通过左侧文件树查看被修改的文件,并通过底部终端面板观察 Agent 输出 +- 移动端通过顶部栏的 Files 和 Terminal 按钮打开对应 Sheet - 同时创建 Shell 终端来独立验证 Agent 的成果 ## 查看 Git 变更 -1. 在左侧面板切换到 Git 标签 +1. 桌面端在左侧面板切换到 Git 标签;移动端在 Files Sheet 中切到 Git / Source Control 视图 2. 查看当前分支名称和变更列表 3. 点击某个文件可以查看差异内容 -4. 差异视图支持在中央区域查看具体变更 +4. 差异视图会在中央区域或移动端详情页中显示具体变更 ## 修改 Provider 启动参数 -1. 点击顶栏的设置按钮 -2. 进入 Providers 页面 +1. 点击顶栏的 **More / 更多** 按钮 +2. 进入 `Settings > Providers`(对应路由 `/more/settings/providers`) 3. 选择对应的 Provider 4. 在文本框中添加每行一个额外参数 5. 通过 Command Preview 确认最终命令 diff --git a/docs/product-spec/README.zh-CN.md b/docs/product-spec/README.zh-CN.md index c2dbbf435..5ef37ce63 100644 --- a/docs/product-spec/README.zh-CN.md +++ b/docs/product-spec/README.zh-CN.md @@ -2,6 +2,11 @@ 本文档定义 Coder Studio 的产品功能规格体系。它不是 PRD,也不是历史设计记录,而是面向开发、测试和后续 AI agent 的功能事实与验收契约。 +## 0. 当前代码基线入口 + +- 当前产品总览见 [current-baseline.zh-CN.md](./current-baseline.zh-CN.md)。 +- 当模块文档与总览存在冲突时,以总览中的当前代码基线描述为准,直到对应模块完成同步。 + ## 1. 文档目标 Product Spec 只回答四类问题: @@ -40,6 +45,7 @@ Product Spec 不承担以下职责: ```text docs/product-spec/ README.zh-CN.md + current-baseline.zh-CN.md modules/ app-shell.zh-CN.md @@ -103,10 +109,10 @@ docs/product-spec/ | --- | --- | --- | | App Shell | 启动、路由壳层、连接态、桌面/移动壳层选择 | `packages/web/src/app`、`packages/web/src/shells` | | Auth | 登录、会话门禁、认证状态 | `packages/web/src/features/auth`、`packages/server/src/auth` | -| Welcome | 欢迎页、打开工作区入口、设置入口 | `packages/web/src/features/welcome` | +| Welcome | 欢迎页、打开工作区入口、两步首屏引导 | `packages/web/src/features/welcome` | | Workspace | 工作区总入口、active workspace、加载/错误/空态 | `packages/web/src/features/workspace`、`packages/server/src/commands/workspace.ts` | | Workspace Desktop | 桌面工作区布局、侧栏、主区、底部终端 | `packages/web/src/features/workspace/views/desktop` | -| Workspace Mobile | 移动端 Dock、Sheet、Drawer、移动端工作区状态 | `packages/web/src/features/workspace/views/mobile` | +| Workspace Mobile | 移动端工作区主区、Sheet、Drawer、顶部栏和底部状态栏 | `packages/web/src/features/workspace/views/mobile` | | Workspace Tabs / Layout | workspace tab、布局持久化、focus/fullscreen、最后查看目标 | `packages/web/src/features/workspace/actions/use-workspace-ui-state-persistence.ts`、`packages/web/src/features/workspace/actions/use-workspace-layout-actions.ts` | | Agent Sessions | Agent 会话创建、运行态、历史、metadata | `packages/web/src/features/agent-panes`、`packages/server/src/commands/session.ts` | | Agent Panes | Agent pane 布局、pane card、draft launcher、pane navigation | `packages/web/src/features/agent-panes` | @@ -119,10 +125,10 @@ docs/product-spec/ | Git | Git 状态、Diff、commit、branch、push/pull | `packages/web/src/features/workspace/actions/use-git-actions.ts`、`packages/server/src/commands/git.ts` | | Worktrees | Worktree 列表、详情、管理入口 | `packages/web/src/features/workspace/views/shared/worktree-*`、`packages/server/src/commands/worktree.ts` | | Terminal | shell terminal、agent terminal、多终端、恢复、上传 | `packages/web/src/features/terminal-panel`、`packages/server/src/terminal` | -| Settings | 设置页、provider 设置、外观、快捷键、监控设置、关于 | `packages/web/src/features/settings`、`packages/server/src/commands/settings.ts` | +| Settings | `/more` 下的设置、分析、关于入口,以及 settings 读写与嵌入式设置分区 | `packages/web/src/features/more`、`packages/web/src/features/settings`、`packages/server/src/commands/settings.ts` | | Diagnostics | 系统依赖、诊断页、安装流程 | `packages/web/src/features/diagnostics`、`packages/server/src/commands/diagnostics.ts` | | Monitoring | 运行监控、指标展示、监控设置 | `packages/web/src/features/monitoring`、`packages/server/src/monitoring` | -| Work Analysis | 工作分析、时间范围、归因、趋势、导出 | `packages/web/src/features/work-analysis`、`packages/server/src/work-analysis` | +| Work Analysis | 工作分析、时间范围、归因、趋势与仪表盘刷新/重建 | `packages/web/src/features/work-analysis`、`packages/server/src/work-analysis` | | Skills | skills 面板、挂载目录、归因和管理 | `packages/web/src/features/workspace/actions/use-skills-panel.ts`、`packages/server/src/skills` | | Updates | 更新检查、更新提示、footer update rail | `packages/web/src/features/updates`、`packages/server/src/update` | | Notifications | Toast、系统通知、会话完成通知 | `packages/web/src/features/notifications`、`packages/web/src/components/ui/toast` | diff --git a/docs/product-spec/acceptance/mobile.zh-CN.md b/docs/product-spec/acceptance/mobile.zh-CN.md index 7f4944535..83617aabe 100644 --- a/docs/product-spec/acceptance/mobile.zh-CN.md +++ b/docs/product-spec/acceptance/mobile.zh-CN.md @@ -4,7 +4,7 @@ ## 1. 目标 -验证移动端 Dock / Sheet / Drawer 工作区体验和移动端终端输入能力。 +验证移动端工作区主区、Sheet / Drawer、状态栏和移动端终端输入能力。 ## 2. 验收清单 @@ -12,10 +12,10 @@ | --- | --- | --- | --- | | MOBILE-001 | 移动 shell 渲染 | `APP-004` | 组件测试 / e2e | | MOBILE-002 | 移动工作区整体渲染 | `WSM-001` | 组件测试 / e2e | -| MOBILE-003 | Mobile Dock 切换 | `WSM-003` | 组件测试 / 手工 | +| MOBILE-003 | 移动端当前会话主区与状态栏 | `WSM-003` | 组件测试 / 手工 | | MOBILE-004 | Agent Sheet | `WSM-004` | 组件测试 | | MOBILE-005 | Files Sheet | `WSM-005` | 组件测试 | -| MOBILE-006 | Workspace Drawer | `WSM-006` | 组件测试 | +| MOBILE-006 | Workspace Drawer | `WSM-008` | 组件测试 | | MOBILE-007 | Mobile Terminal soft keys | `TERM-009` | 组件测试 / 手工 | | MOBILE-008 | Mobile long press copy line | `TERM-010` | 单测 / 手工 | | MOBILE-009 | Mobile Supervisor Sheet | `SUP-008` | 组件测试 | diff --git a/docs/product-spec/current-baseline.zh-CN.md b/docs/product-spec/current-baseline.zh-CN.md new file mode 100644 index 000000000..7d6a47a9d --- /dev/null +++ b/docs/product-spec/current-baseline.zh-CN.md @@ -0,0 +1,1064 @@ +# Coder Studio 当前代码基线总览 + +> **文档更新时间:** 2026-06-26 +> **代码基线:** 当前仓库 `packages/web`、`packages/server`、`packages/core`、`packages/providers` +> **文档目的:** 以当前代码实现为唯一事实来源,重整产品需求描述,纠正旧版 PRD 中与实际实现不一致的页面、路由、入口和功能表述。 +> **重要原则:** +> - 本文只描述当前代码中已经接线、可达、可交互的能力。 +> - 历史设计、旧版 README、过期 PRD、未挂载组件不计入“当前功能”。 +> - 本文是“现状基线文档”,不是未来路线图。 + +--- + +## 1. 文档范围 + +本文覆盖以下产品面: + +- Web 前端桌面壳层与移动壳层 +- 工作区、会话、文件、Git、终端、通知、设置、监控、分析、诊断 +- 嵌入式 Canvas 页面 +- 与前端直接对应的 Server 命令面和 API 面 + +本文不覆盖: + +- 未来规划或未接线入口 +- 样式实现细节与 CSS 规范 +- Provider 内部执行细节的逐行实现说明 + +--- + +## 2. 产品概览 + +### 2.1 产品定位 + +Coder Studio 是一个以浏览器为入口的 AI 编码工作台。当前实现把以下能力聚合到同一套工作区模型中: + +- 打开并管理多个本地 workspace +- 在同一 workspace 中创建和切换多个 Agent 会话 +- 使用文件树、搜索、Git、终端完成开发操作 +- 在桌面端和移动端访问同一套工作区数据 +- 配置 Provider、终端、外观、快捷键、通知、监控和更新行为 + +### 2.2 当前核心价值 + +当前代码体现出的核心价值是: + +1. **一次部署,多端继续编码。** +2. **把 AI 会话、文件、Git、终端和诊断能力放进同一个工作流。** +3. **桌面端和移动端都有独立且真实的工作区体验,而不是单纯缩放同一套布局。** + +### 2.3 当前端形态 + +| 端形态 | 入口条件 | 当前骨架 | +| --- | --- | --- | +| Desktop | 视口宽度 `> 899px` | 顶栏 + 左侧活动栏/侧栏 + 主工作区 + 底部终端 + 状态栏 | +| Mobile | 视口宽度 `<= 899px` | 顶栏 + 当前会话主区 + 抽屉/Sheet + 底部状态栏 | + +> 说明:当前移动端不是桌面端的压缩版,交互模型不同。 + +--- + +## 3. 信息架构与应用生命周期 + +### 3.1 当前真实路由 + +| 路由 | 页面/壳层 | 当前状态 | +| --- | --- | --- | +| `/embedded/canvas/:workspaceId` | 独立嵌入 Canvas 页面 | 已接线 | +| `/` | 欢迎页 | 已接线 | +| `/login` | 登录页 | 已接线 | +| `/session-gate` | 激活门禁页 | 已接线 | +| `/workspace` | 主工作区 | 已接线 | +| `/analytics` | 工作分析页 | 已接线 | +| `/monitoring` | 性能监控页 | 已接线 | +| `/diagnostics` | 诊断页 | 已接线 | +| `/more/*` | More 页 / 设置与二级能力入口 | 已接线 | +| `*` | 404 页面 | 已接线 | + +**当前没有顶级 `/settings` 路由。** +设置相关内容实际通过 `/more/settings/*`、`/more/analysis/*`、`/more/about/*` 提供。 + +### 3.2 壳层选择 + +- `App` 先处理 `/embedded/canvas/:workspaceId`。 +- 其余路径进入桌面或移动壳层: + - `DesktopShell` + - `MobileShell` + +两套壳层共享: + +- 路由体系 +- workspace / session / terminal 数据模型 +- 通知、连接状态、命令面板等全局能力 + +### 3.3 启动、认证与激活流程 + +当前启动流程由 `useBootstrap` 驱动,真实规则如下: + +1. 若服务端开启认证且当前未认证: + - `/login` 之外的页面一律重定向到 `/login` +2. 若已认证,或服务端未开启认证: + - 停留在 `/login` 会被重定向到 `/` +3. 若激活状态为 `gated`: + - 重定向到 `/session-gate` +4. workspace 启动引导只在 `/` 和 `/workspace` 发生: + - 拉取 `workspace.list` + - 拉取 `workspace.lastViewedTarget.get` +5. 引导完成后按 workspace 数量路由: + - `/` 且 workspace 数量大于 0 时,重定向到 `/workspace` + - `/workspace` 且 workspace 数量为 0 时,重定向到 `/` + +### 3.4 工作区入口解析状态 + +`/workspace` 页面在进入真实工作区前,会经过 `WorkspaceRouteGate`: + +- workspace 仍在解析中:显示加载壳 +- workspace 拉取失败:显示错误空态 +- workspace 已就绪:进入桌面或移动工作区视图 + +### 3.5 连接状态反馈 + +全局连接状态当前通过横幅和局部指示共同表达: + +- `connected`:不显示主横幅 +- `reconnecting`:显示正在重连提示 +- `disconnected`:显示连接断开提示 +- `rejected`:显示“另一个标签页已激活”提示 + +桌面顶栏和移动顶栏还会展示轻量连接状态指示。 + +--- + +## 4. 页面规格 + +### 4.1 欢迎页 `/` + +#### 页面目标 + +欢迎页只承担“当前没有已进入 workspace 时的首屏入口”职责,不再承担旧版 PRD 中描述的设置入口职责。 + +#### 当前结构 + +欢迎页为两步式落地页: + +1. 第一步:打开工作区 +2. 第二步:开始编码 / 进入会话流 + +页面包含: + +- 产品 kicker +- 标题与描述 +- 两步工作流卡片 +- 主按钮“打开工作区” +- 支撑性能力说明区 + +#### 当前功能 + +- “打开工作区”按钮打开 `WorkspaceLaunchModal` +- 支撑性能力说明当前只有两项: + - Git tools + - terminals + +#### 明确不应再写入 PRD 的旧描述 + +- 欢迎页**没有**当前可达的设置按钮 +- 欢迎页**不是**“三张功能卡 + 设置次按钮”的旧结构 + +### 4.2 登录页 `/login` + +#### 页面目标 + +登录页用于处理服务端启用认证的场景。 + +#### 当前行为 + +- 页面会主动探测 `/auth/status` +- 若认证未开启: + - 直接将前端鉴权态设为已通过 +- 若已存在有效认证: + - 直接将前端鉴权态设为已通过 +- 若探测失败: + - 展示状态不可用 +- 若需要密码: + - 保持在当前页等待提交 + +#### 当前交互 + +- 输入框类型固定为 `password` +- 提交接口为 `/auth/login` +- 提交中与状态探测中,提交按钮禁用 +- 密码错误时直接展示服务端错误 +- 若服务端返回封禁截止时间: + - 页面会按当前语言格式化显示具体时间 + +#### 当前未提供的流程 + +- 忘记密码 +- 切换账号 +- 多账户管理 + +### 4.3 Session Gate `/session-gate` + +#### 页面目标 + +当应用激活状态为 `gated` 时,当前页面作为阻断页展示。 + +#### 当前结构与交互 + +- 复用欢迎页风格外壳 +- 展示门禁标题、说明和错误态状态面板 +- 主操作为“重新进入” +- 点击后通过 `window.location.replace("/")` 回到首页重新进入流程 + +### 4.4 工作区页 `/workspace`(桌面) + +#### 页面目标 + +桌面工作区是当前最完整的主工作台。用户可以在同一屏中完成: + +- workspace 切换 +- Agent 会话创建与继续 +- 文件浏览、搜索、编辑和预览 +- Git 提交、差异查看、分支切换、worktree 管理 +- 终端操作 +- Agent 指令、Memory、Skills 管理 + +#### 当前整体布局 + +页面结构为: + +- 顶栏 `TopBar` +- 左侧活动栏 + 侧边内容区 +- 主工作区舞台 +- 可展开底部终端面板 +- 底部状态栏 + +在 `focus mode` 或侧栏折叠时,左侧栏会收起。终端面板也可以单独隐藏。 + +#### 顶栏能力 + +当前顶栏包含: + +- workspace tabs +- 新建/打开 workspace 按钮 +- 连接状态指示 +- Quick Actions 按钮 +- 终端显示/隐藏切换 +- 侧栏显示/隐藏切换 +- 打开 `/more` +- 全屏切换 + +> 旧版“顶栏设置按钮跳到 `/settings`”的描述已不成立。 +> 当前入口是 `/more`。 + +#### 左侧栏:真实视图集合 + +当前桌面侧栏不再只有 Files / Git 两项,而是 6 个真实视图: + +1. `explorer` +2. `search` +3. `source-control` +4. `agent-instructions` +5. `memory` +6. `skills` + +##### Explorer + +Explorer 当前包含: + +- 新建文件 +- 新建文件夹 +- 全部折叠 +- 文件树 + +文件树当前支持: + +- 目录懒加载 +- 默认展开常见根目录(如 `app`、`packages`、`src`) +- 桌面拖拽路径 +- 重命名、删除、创建等上下文动作 +- 双击目录进入、单击选中 + +##### Search + +Search 当前支持: + +- 搜索 +- 替换 +- 大小写匹配 +- 整词匹配 +- 正则 +- include files / exclude files +- ignore / exclude 规则开关 +- 单文件替换 +- 单匹配替换 +- 结果预览与定位 + +##### Source Control + +Git 侧栏当前包含: + +- Commit 区 +- Worktree 区 +- Staged / Changes / Merge Changes 等变更分组 +- Git 历史列表 +- 历史分页增量加载 +- 校验任务提示与重跑 verify +- Diff 预览打开 + +Worktree 区当前支持: + +- 查看工作树列表 +- 打开工作树 +- 新建工作树 +- 删除工作树 + +##### Agent Instructions + +Agent Instructions 视图当前由两部分组成: + +- Token trend 区块 +- Agent Instructions 区块 + +当前已接线能力包括: + +- 项目级 instructions 状态展示 +- 生成 / 重新生成 / 编辑自定义 instructions +- 各 provider 的 system instructions 状态展示 +- 对可编辑 system instructions 进行编辑 + +##### Memory + +Memory 面板当前支持: + +- 列表查看 +- 关键字搜索 +- 按 memory type 过滤 +- 新建 memory +- 编辑 memory +- 删除 memory +- 对可行动类型维护状态 + +##### Skills + +Skills 面板当前支持: + +- 查看 custom / installed / builtin / recommendations +- 安装 skill +- 卸载 skill +- 针对 provider target 挂载 / 卸载 +- 创建自定义 skill +- 查看来源、版本、origin、library path 等信息 + +#### 主工作区舞台 + +主舞台当前由两套内容叠加组成: + +- `AgentPanes` +- `CodeEditorHost` + +当前存在两种主模式: + +- `agent` 模式:以会话为主 +- `editor` 模式:以编辑器为主 + +编辑器当前支持: + +- 固定(pinned) +- 浮动(floating) +- 浮动状态下拖拽移动 +- 浮动状态下四角 resize +- 在 agent 模式下通过“恢复编辑器”按钮重新打开 + +#### 文件打开规则 + +当前文件打开行为不是单一文本编辑: + +- 普通文件:进入编辑器文件 tab +- 预览式打开:可使用 preview tab +- 图片文件:由编辑器宿主进入预览模式 +- `.csc` 文件: + - 若是导航式打开,则默认以 Canvas tab 打开 + - 若带显式定位信息(如行列号)或指定草稿 pane,则按源码文件处理 + +#### 底部终端面板 + +当前终端面板: + +- 可显示/隐藏 +- 可拖动调整高度 +- 位于主工作区底部 + +#### 状态栏 + +当前状态栏由两部分组成: + +- 左侧:Git 状态条 +- 右侧:更新轨 `FooterUpdateRail` + +Git 状态条当前支持: + +- 当前分支展示 +- ahead / behind 摘要 +- 打开分支快速切换 +- 刷新 Git 状态 + +更新轨当前支持: + +- 发现可更新版本 +- 准备安装 +- 安装中 / 重启中 +- 失败 / 需要手动处理 +- 成功提示 +- 若系统中仍有活动工作,会先弹确认框 + +#### 桌面快捷键 + +当前桌面工作区内,至少存在以下已接线快捷键: + +- `Ctrl/Cmd + B`:切换侧栏 +- `Ctrl/Cmd + 1`:Explorer +- `Ctrl/Cmd + 2`:Search +- `Ctrl/Cmd + 3`:Source Control +- `Ctrl/Cmd + 4`:Agent Instructions +- `Ctrl/Cmd + 5`:Memory +- `Ctrl/Cmd + 6`:Skills + +### 4.5 工作区页 `/workspace`(移动) + +#### 页面目标 + +移动端工作区以“当前会话 + 顶部入口 + 全屏 Sheet / 抽屉”为主,不复用桌面端的多栏结构。 + +#### 当前整体结构 + +当前移动工作区由以下部分组成: + +- 顶栏 `MobileTopBar` +- 当前会话主区 +- 底部状态栏 +- Agent Sheet +- Files Sheet +- Terminal 全屏 Sheet +- Supervisor Sheet +- Workspace Drawer + +#### 顶栏能力 + +当前移动顶栏包含: + +- workspace 抽屉开关 +- 当前 workspace 名称 +- 文件入口 +- 终端入口 +- `/more` 入口 +- 全屏入口 + +#### 当前会话主区 + +若存在会话: + +- 主区展示当前激活 `SessionCard` + +若不存在会话: + +- 展示空态 +- 主按钮为“创建会话” + +#### Session 恢复规则 + +移动端当前会根据以下优先级恢复会话: + +- `lastViewedTarget` +- workspace UI state 中的 `activeSessionId` +- 最近活跃会话 + +#### Agent Sheet + +Agent Sheet 当前有两种模式: + +- `sessions` +- `providers` + +当前能力包括: + +- 切换当前会话 +- 关闭会话 +- 创建新会话 +- 选择 provider 启动会话 +- 当 provider 不可直接启动时,进入 diagnostics 深链 + +#### Files Sheet + +Files Sheet 当前分两层: + +- `root`:面板模式 +- `detail`:编辑器/预览明细模式 + +`root` 层当前包含 3 个视图: + +- `explorer` +- `search` +- `source-control` + +`detail` 层当前由 `CodeEditorHost` 承接,用于: + +- 文件编辑 +- 文件预览 +- Git Diff 详情 + +#### Terminal Sheet + +移动端终端当前以全屏 Sheet 展示: + +- 主体为 `TerminalPanel` +- 底部附带工作区状态栏 + +#### Supervisor Sheet + +当当前会话触发 supervisor 相关交互时: + +- 自动切换到 `MobileSupervisorSheet` + +#### Workspace Drawer + +当前 Drawer 支持: + +- 浏览所有 workspace +- 展开/折叠单个 workspace +- 查看该 workspace 下的会话列表 +- 切换 workspace +- 切换 session +- 在当前 workspace 下新建 session +- 关闭 workspace +- 关闭 session +- 打开 workspace 启动器 + +#### 当前不应误写的点 + +- 代码中存在 `MobileDock` 组件和样式资源 +- 但当前 `WorkspaceMobileView` **没有挂载该组件** +- 因此“底部 Dock 为当前主入口”**不应写成已上线能力** + +### 4.6 More 页 `/more/*` + +#### 页面定位 + +`/more/*` 是当前真实的“设置与二级能力中心”,不是边缘页面。 + +#### 当前一级分类 + +当前分类固定为 3 组: + +| 分类 | 当前 section | +| --- | --- | +| `settings` | `general`、`providers`、`terminal`、`appearance`、`shortcuts` | +| `analysis` | `analytics`、`monitoring`、`diagnostics` | +| `about` | `product`、`update-status`、`auto-update` | + +#### 桌面端表现 + +桌面端 `MoreFeaturesPage` 当前结构为: + +- 页头 +- 顶部 category tabs +- 左侧 section 导航 +- 右侧内容区 + +访问规则: + +- 会自动规范化到 `/more//
` +- 非法或缺失 section 会回落到该分类默认 section + +#### 移动端表现 + +移动端当前是三层流转: + +1. `/more`:分类列表 +2. `/more/`:section 列表 +3. `/more//
`:具体内容 + +#### 当前内容映射 + +- `/more/settings/*`:嵌入 `SettingsPage` +- `/more/analysis/analytics`:嵌入 `WorkAnalyticsSettingsSection` +- `/more/analysis/monitoring`:嵌入监控设置与监控看板 +- `/more/analysis/diagnostics`:嵌入 `DiagnosticsPage` +- `/more/about/*`:嵌入 About / Update / Auto Update 视图 + +### 4.7 工作分析页 `/analytics` + +#### 页面定位 + +`/analytics` 是当前独立的分析页面,不是“设置页下的一个旧子页壳”。 + +#### 当前能力 + +- 时间范围选择 +- 预设范围切换 +- 刷新分析看板 +- 扫描状态展示 +- provider 数据来源质量摘要 +- KPI 网格 +- token trend +- agent / model / project 排行 +- skill 归因拆分 +- 小时热力图 +- 刷新失败和警告态反馈 + +### 4.8 监控页 `/monitoring` + +#### 页面定位 + +`/monitoring` 是当前独立监控页面,也可在 `/more/analysis/monitoring` 中以内嵌形态出现。 + +#### 当前能力 + +- 刷新监控快照 +- 时间窗口切换:`5m` / `15m` / `30m` +- Host Overview +- Runtime Summary +- Attribution Tree +- Subprocess Drilldown +- Background Runtime +- Entity Detail 面板 +- disabled / degraded / waiting / empty 等多类状态 + +### 4.9 诊断页 `/diagnostics` + +#### 页面定位 + +`/diagnostics` 既是独立页面,也能作为 More 页内嵌内容使用。 + +#### 当前上下文类型 + +当前诊断流至少覆盖: + +- `manual_check` +- `workspace_open` +- `session_start` +- `mobile_continue` + +#### 当前能力 + +- 拉取诊断报告 +- 手动 recheck +- 按上下文继续后续动作 +- 复制诊断详情 +- 安装系统依赖 +- 展示 LSP 服务状态 +- 展示 workspace / git / nodejs / provider runtime / server auth / mobile host 等检查项 + +#### 当前继续动作 + +- `workspace_open`:通过 `workspace.open` 继续打开工作区 +- `session_start`:在通过诊断后创建会话并返回工作区 +- `mobile_continue`:在通过诊断后生成并复制手机访问入口 + +### 4.10 嵌入 Canvas `/embedded/canvas/:workspaceId` + +#### 页面定位 + +该路由是工作区外部的独立 Canvas 渲染页面。 + +#### 当前参数要求 + +- 路径参数:`workspaceId` +- 查询参数:`sourcePath` +- 可选查询参数:`refresh` + +#### 当前行为 + +- 通过 `/api/canvas/:workspaceId/data?sourcePath=...` 拉取数据 +- 支持 `architecture_canvas` 与 `report_canvas` +- 缺少 `sourcePath`、workspace 不存在、路径越界、画布不存在时会进入错误态 + +#### 与工作区内 Canvas 的关系 + +- 工作区内打开 `.csc` 文件时,也可作为 Canvas tab 呈现 +- `/embedded/canvas/:workspaceId` 是独立页面形态,不依赖工作区壳层 + +### 4.11 404 页面 `*` + +当前 404 页面展示: + +- 标题与说明 +- 当前未命中路径 +- 返回首页按钮 + +--- + +## 5. 跨页面共享系统 + +### 5.1 Workspace 启动器 + +当前 workspace 启动器可从以下入口打开: + +- 欢迎页主按钮 +- 桌面顶栏新增 workspace 按钮 +- 命令面板中的“打开工作区” +- 移动端 workspace drawer 底部入口 + +#### 当前形态 + +- 桌面:WorkbenchLayer 弹层 +- 移动:Sheet + +#### 当前能力 + +- 浏览目录 +- 返回上级目录 +- 快速回到 Home +- root path 切换 +- 新建文件夹 +- 选择目录并打开 workspace +- 最近 workspace 列表 +- 打开最近 workspace +- 删除单条最近记录 +- 清空最近记录 + +#### 当前约束 + +它是**应用内目录浏览器**,不是系统原生文件选择器。 + +### 5.2 命令面板(Quick Actions) + +#### 当前入口 + +- 全局快捷键 `Ctrl/Cmd + K` +- 桌面顶栏 Quick Actions 按钮 +- 移动壳层命令面板 Sheet + +#### 当前命令集合 + +当前代码已接线的命令包括: + +- 打开 workspace +- 返回首页 +- 打开 `/more/settings/general` +- 打开 `/monitoring` +- 打开 Quick Open(桌面且有活动 workspace 时) +- 开关 focus mode(桌面) +- 开关侧栏(桌面) +- 开关终端(桌面) +- 切换到指定 workspace +- 从工作区返回欢迎页 + +#### 当前更正 + +- “Settings” 命令当前跳转的是 `/more/settings/general` +- 不是 `/settings` + +### 5.3 Quick Open + +#### 当前入口 + +- 仅桌面壳层挂载 +- 全局快捷键 `Ctrl/Cmd + P` + +#### 当前能力 + +- 搜索当前 workspace 中文件 +- 键盘上下选择 +- 回车打开 +- 支持鼠标悬停与点击 + +#### 当前打开规则 + +- 通过 `file.search` 获取结果 +- 常规导航打开文件 +- `.csc` 文件在导航式打开时默认进入 Canvas tab + +### 5.4 分支快速切换 + +#### 当前形态 + +- 桌面:状态栏分支按钮上的 Popover +- 移动:独立移动选择 Sheet + +#### 当前能力 + +- 搜索分支 +- 选择分支并切换 +- 创建分支 +- 标记当前分支 +- 标记远程分支 +- 标记已被 worktree 占用的分支 + +### 5.5 通知与 Toast + +#### In-app Toast + +当前 Toast 系统: + +- 最多保留 5 条 +- 支持自动消失 +- 点击后可跳到对应 workspace / session + +#### Session 完成通知 + +当前通知引擎会在长任务完成时发送提示,真实规则包括: + +- 主触发:`running -> idle` +- 回退触发:`running -> ended` +- 过短任务不会提示(当前阈值为 4 秒) +- 页面可见且用户已在同一 workspace / 会话时,会被抑制 +- 页面不可见时,优先使用浏览器系统通知 +- 声音提示受独立开关控制 + +### 5.6 连接反馈 + +当前全局连接反馈由两层组成: + +- 页面顶部的连接状态横幅 +- 顶栏/移动顶栏中的轻量连接状态点 + +### 5.7 状态栏与更新轨 + +当前状态栏提供: + +- Git 分支摘要 +- Git ahead / behind / refresh +- 分支快速切换入口 +- 更新状态轨 + +更新轨当前覆盖: + +- update available +- installing +- restarting +- failed +- manual required +- succeeded + +--- + +## 6. 当前设置架构与配置模型 + +### 6.1 设置入口架构 + +当前设置并非独立顶层页面,而是通过 `/more` 组织: + +- `/more/settings/*` +- `/more/analysis/*` +- `/more/about/*` + +`SettingsPage` 当前可见 section 为: + +- `general` +- `providers` +- `terminal` +- `appearance` +- `shortcuts` + +`SettingsPage` 当前还支持嵌入式 section: + +- `monitoring` +- `analysis` +- `diagnostics` +- `about` + +### 6.2 General + +当前 General section 已接线项包括: + +- 完成通知开关 +- 通知声音开关 +- 浏览器通知能力状态 +- 浏览器通知权限状态 +- LSP runtime mode:`auto` / `off` +- supervisor evaluation timeout +- supervisor retry 开关 +- supervisor retry 最大次数 +- supervisor retry 延迟 +- retry on timeout +- retry on evaluator error +- 语言切换:`zh` / `en` + +### 6.3 Providers + +当前 Providers section 已接线项包括: + +- provider 列表 +- provider badge / capability / stability 信息 +- provider runtime status +- additional args 文本编辑 +- 命令预览 +- 配置编辑器(当前仅 `claude`、`codex`) +- diagnostics 深链 + +### 6.4 Terminal + +当前 Terminal section 已接线项包括: + +- terminal renderer:`standard` / `compatibility` +- copy on select +- 终端 profile 配置 +- 默认 terminal profile +- 自定义 terminal profile +- 桌面终端字号 +- 移动终端字号 + +### 6.5 Appearance + +当前 Appearance section 已接线项包括: + +- 主题选择 +- 背景模式:无背景 / 图片背景 +- 背景适配方式 +- 背景资源上传 +- 背景资源删除 +- 玻璃与材质参数 +- surface opacity / blur 等个性化设置 +- 桌面端与移动端覆盖配置 + +### 6.6 Shortcuts + +当前 Shortcuts section 已接线项包括: + +- 分类展示: + - `global` + - `workspace` + - `editor` + - `terminal` +- 编辑快捷键绑定 +- 重置快捷键 + +### 6.7 Monitoring(嵌入设置) + +当前嵌入监控设置页已接线项包括: + +- 启用/禁用 monitoring +- 预设模式:`light` / `standard` / `deep` / `custom` +- 采样间隔 +- 时间窗口预览 +- 高级能力开关: + - host metrics + - runtime summary + - workspace attribution + - subprocess drilldown +- 内嵌监控看板 + +### 6.8 About / Update / Auto Update + +当前 About 相关 section 已接线项包括: + +- 产品信息 +- 当前版本 +- server instance id +- 当前安装支持情况 +- 最新版本 +- 上次检查时间 +- 更新可用性 +- 更新状态 +- 立即检查更新 +- 准备安装更新 +- 自动检查开关 +- 自动检查间隔 +- 需要手动处理时的提示与命令展示 + +--- + +## 7. 后端能力附录(当前命令面) + +当前 Server 已注册的命令家族包括: + +- `workspace` +- `workspace-activity` +- `automation` +- `ui-actions` +- `canvas` +- `activation` +- `connection` +- `recovery` +- `session` +- `session-metadata` +- `session-review` +- `terminal` +- `task` +- `file` +- `git` +- `agent-instructions` +- `skills` +- `agent-context` +- `settings` +- `diagnostics` +- `provider` +- `custom-provider` +- `system-deps` +- `supervisor` +- `worktree` +- `fencing` +- `lsp` +- `updates` +- `monitoring` +- `work-analysis` +- `memory` + +这些命令家族说明当前产品面已经不仅限于早期版本中的文件、Git 和会话基础能力。 + +### 7.1 Canvas API + +当前独立 Canvas 页面依赖的服务端 API 为: + +- `GET /api/canvas/:workspaceId/data?sourcePath=...` + +当前约束: + +- workspace 不存在返回 `404` +- 缺少 `sourcePath` 返回 `400` +- 路径逃逸会被拒绝 +- 找不到 canvas 返回 `404` + +--- + +## 8. 实现边界与禁止误写项 + +以下内容在今后维护 PRD 时,**不要再写成当前已上线能力**: + +### 8.1 顶级 `/settings` + +- 当前产品路由中没有顶级 `/settings` +- 设置中心的真实入口是 `/more/*` + +### 8.2 欢迎页设置按钮 + +- 当前欢迎页没有设置次按钮 +- 欢迎页的主动作只有“打开工作区” + +### 8.3 桌面侧栏只有 Files / Git + +- 当前桌面侧栏真实视图是 6 项 +- Files / Git 只是其中两项视图能力的一部分 + +### 8.4 移动端底部 Dock 为当前主入口 + +- 当前代码里虽然有 `MobileDock` 组件 +- 但主工作区视图没有挂载该组件 +- 因此不应把“底部 Dock 导航”写成当前产品入口 + +### 8.5 分析/监控/诊断只是设置子面板 + +- `/analytics` +- `/monitoring` +- `/diagnostics` + +以上 3 个当前都是真实独立页面,同时也可以在 `/more` 中以内嵌内容出现。 + +### 8.6 Embedded Canvas 是工作区内私有能力 + +- `.csc` 文件可在工作区内作为 Canvas tab 打开 +- 但当前还存在独立路由 `/embedded/canvas/:workspaceId` +- 不能只按“工作区内部预览”描述 + +--- + +## 9. 维护原则 + +后续维护本文时,应遵守以下规则: + +1. 路由图以 `App` 与 Shell 注册结果为准。 +2. 页面能力以当前真实挂载组件为准,不以“存在组件文件”作为已上线依据。 +3. 设置项以 `/more` 下的真实 section 和 `SettingsPage` 可见/嵌入 section 为准。 +4. 工作区能力以桌面与移动两套视图分别核对,不做互相投射。 +5. 若独立页面和内嵌页面同时存在,应在 PRD 中明确写出“双入口”。 diff --git a/docs/product-spec/modules/settings.zh-CN.md b/docs/product-spec/modules/settings.zh-CN.md index 07864b2fc..e5131e80f 100644 --- a/docs/product-spec/modules/settings.zh-CN.md +++ b/docs/product-spec/modules/settings.zh-CN.md @@ -1,342 +1,200 @@ # Settings -> 第一轮模块索引。本文只记录代码可见的功能点、状态、代码入口和验收入口。 +> 当前代码基线。本文描述当前用户真实可达的设置与二级功能入口,以及其对应的 settings 读写能力。 ## 1. 模块范围 覆盖: -- 设置页导航和分区。 -- Provider 设置、配置文件读写、命令预览。 -- 外观、快捷键、监控设置、关于。 +- `/more` 页面及其路由归一化。 +- `/more/settings/*` 下的嵌入式设置分区。 +- `/more/analysis/*` 与 `/more/about/*` 下的二级入口。 +- settings 读取、更新、配置文件编辑与命令预览。 不覆盖: -- Provider runtime 实际执行。 +- 独立顶级页面 `/analytics`、`/monitoring`、`/diagnostics` 的完整页面行为。 +- provider runtime 的具体执行逻辑。 ## 2. 用户入口 | 入口 | 端 | 说明 | | --- | --- | --- | -| `/settings` | Both | 设置页入口。 | -| Settings navigation | Both | 切换设置分区或子页。 | -| Provider Settings | Both | 编辑 provider 配置。 | -| Monitoring Settings | Both | 配置监控相关选项。 | +| 顶栏 `/more` 按钮 | Desktop | 打开 More 页面。 | +| `/more` | Both | More 页面入口。 | +| `/more/settings/*` | Both | 常规设置入口。 | +| `/more/analysis/*` | Both | 工作分析、监控、诊断的嵌入入口。 | +| `/more/about/*` | Both | 产品、更新状态、自动更新入口。 | ## 3. 功能点清单 | ID | 功能点 | 状态 | 代码入口 | 验收入口 | | --- | --- | --- | --- | --- | -| SETTINGS-001 | 设置页渲染 | Implemented | `packages/web/src/features/settings/components/settings-page.tsx` | `settings-page.test.tsx` | -| SETTINGS-002 | 设置页导航 | Implemented | `settings-navigation.ts` | `settings-navigation.test.ts` | -| SETTINGS-003 | settings.get/update | Implemented | `packages/server/src/commands/settings.ts` | `packages/server/src/commands/settings.test.ts` | -| SETTINGS-004 | 读取/写入配置文件 | Implemented | `settings.readConfigFile`、`settings.writeConfigFile`、`config-editor.tsx` | `config-editor.test.tsx` | -| SETTINGS-005 | 命令预览 | Implemented | `settings.previewCommand` | `packages/server/src/commands/settings.test.ts` | -| SETTINGS-006 | Provider settings UI | Implemented | `provider-settings.tsx` | `provider-settings.test.tsx` | -| SETTINGS-007 | Shortcuts settings UI | Implemented | `shortcuts-settings.tsx` | `shortcuts-settings.test.tsx` | -| SETTINGS-008 | Monitoring settings UI | Implemented | `monitoring-settings-card.tsx`、`monitoring-settings-subpage.tsx` | `monitoring-settings-subpage.test.tsx` | -| SETTINGS-009 | About settings | Implemented | `about-settings.tsx` | `about-settings.test.tsx` | -| SETTINGS-010 | Session gate dispatch | Internal | `use-session-gate-dispatch.ts` | 设置页手工验收 | - -## 4. 模块级验收线索 - -- 进入设置页后能切换主要设置分区。 -- 修改设置后刷新应保留持久化结果。 -- 配置文件编辑失败时应展示错误。 +| SETTINGS-001 | More 页面路由解析与归一化 | Implemented | `packages/web/src/features/more/routes.ts`、`packages/web/src/features/more/page.tsx` | `packages/web/src/features/more/page.test.tsx` | +| SETTINGS-002 | 常规设置分区嵌入渲染 | Implemented | `packages/web/src/features/more/page.tsx`、`packages/web/src/features/settings/components/settings-page.tsx` | `packages/web/src/features/more/page.test.tsx` | +| SETTINGS-003 | settings.get / settings.update | Implemented | `packages/server/src/commands/settings.ts` | `packages/server/src/commands/settings.test.ts` | +| SETTINGS-004 | 配置文件读取与写入 | Implemented | `settings.readConfigFile`、`settings.writeConfigFile`、`packages/web/src/features/settings/components/config-editor.tsx` | `packages/web/src/features/settings/components/config-editor.test.tsx` | +| SETTINGS-005 | Provider 启动命令预览 | Implemented | `settings.previewCommand`、`packages/web/src/features/settings/components/provider-settings.tsx` | `packages/server/src/commands/settings.test.ts` | +| SETTINGS-006 | Providers 分区 | Implemented | `packages/web/src/features/settings/components/provider-settings.tsx` | `packages/web/src/features/settings/components/provider-settings.test.tsx` | +| SETTINGS-007 | Terminal 分区 | Implemented | `packages/web/src/features/settings/components/terminal-settings-section.tsx` | `packages/web/src/features/settings/components/settings-page.test.tsx` | +| SETTINGS-008 | Appearance 分区 | Implemented | `packages/web/src/features/settings/components/settings-page.tsx` | `packages/web/src/features/settings/components/settings-page.test.tsx` | +| SETTINGS-009 | Shortcuts 分区 | Implemented | `packages/web/src/features/settings/components/shortcuts-settings.tsx` | `packages/web/src/features/settings/components/shortcuts-settings.test.tsx` | +| SETTINGS-010 | Monitoring 嵌入分区 | Implemented | `packages/web/src/features/settings/components/monitoring-settings-subpage.tsx` | `packages/web/src/features/settings/components/monitoring-settings-subpage.test.tsx` | +| SETTINGS-011 | Analysis / Diagnostics 嵌入入口 | Implemented | `packages/web/src/features/more/page.tsx`、`packages/web/src/features/work-analysis/page.tsx`、`packages/web/src/features/diagnostics/page.tsx` | `packages/web/src/features/more/page.test.tsx` | +| SETTINGS-012 | About / Update Status / Auto Update 分区 | Implemented | `packages/web/src/features/settings/components/about-settings.tsx` | `packages/web/src/features/settings/components/about-settings.test.tsx` | + +## 4. 当前页面事实 + +- 当前没有顶级 `/settings` 路由;用户真实入口是 `/more`。 +- `More` 页面按 3 个 category 组织: + - `settings` + - `analysis` + - `about` +- 当前 `/more/settings/*` 的可见设置分区是: + - `general` + - `providers` + - `terminal` + - `appearance` + - `shortcuts` +- `monitoring` 不是设置首页可见分区,而是通过 `/more/analysis/monitoring` 嵌入进入。 +- `analytics` 与 `diagnostics` 也通过 `/more/analysis/*` 嵌入显示,同时仍保留独立顶级页面。 +- `product`、`update-status`、`auto-update` 通过 `/more/about/*` 嵌入显示。 ## 5. 功能点规格 -### SETTINGS-001 设置页渲染 +### SETTINGS-001 More 页面路由解析与归一化 状态:`Implemented` 用户行为: -- 用户进入 `/settings`,在桌面或移动端查看设置页面。 +- 用户进入 `/more`、`/more/settings`、`/more/analysis` 或任意子路径。 系统响应: -- 设置页加载 server settings、provider 列表、runtime 状态、监控数据和更新状态等上下文。 -- 根据当前 section 渲染 General、Providers、Appearance、Shortcuts、Monitoring、Analysis、Diagnostics、About。 -- 移动端使用同一 section 定义,但布局适配移动视口。 +- 桌面端会把空 category 或空 section 归一化到默认 section。 +- 移动端可以停留在 category 列表页,再进入具体 section。 +- 非法路径会回退到可解析的合法路径。 状态与边界: -- Loading:设置数据未准备好时部分控件使用默认值或禁用态。 -- Session gate:部分 dispatch 遇到 `activation_required` 会导航到 `/session-gate`。 -- Section fallback:未知 section 应回落到默认 section。 +- Desktop fallback:默认落到 `/more/settings/general`。 +- Mobile fallback:默认落到 `/more` 或对应 category 首页。 +- Invalid section:未知 section 不会导致页面崩溃,而是回退到默认 section。 验收标准: -- Given 用户访问 `/settings` -- When settings 数据加载完成 -- Then 页面显示设置导航 -- And 默认 section 可渲染对应内容 +- Given 用户访问 `/more/settings` +- When 桌面壳层完成路由归一化 +- Then URL 应变为 `/more/settings/general` 代码索引: -- `packages/web/src/features/settings/components/settings-page.tsx` -- `packages/web/src/features/settings/components/settings-sections.tsx` +- `packages/web/src/features/more/routes.ts` +- `packages/web/src/features/more/page.tsx` -### SETTINGS-002 设置页导航 +### SETTINGS-002 常规设置分区嵌入渲染 状态:`Implemented` 用户行为: -- 用户点击设置导航中的分区或通过 URL 进入某个分区。 +- 用户从 `/more/settings/*` 进入某个设置分区。 系统响应: -- `SETTINGS_SECTIONS` 定义所有分区 id、i18n label 和 icon semantic。 -- navigation 工具解析和生成设置路径。 -- 页面根据 section id 切换内容。 +- `More` 页面通过 `SettingsPage embeddedSection=...` 渲染分区内容。 +- 嵌入模式下保留分区内容,不渲染独立设置页的整页 chrome。 状态与边界: -- Sections:当前分区包括 `general`、`providers`、`appearance`、`shortcuts`、`monitoring`、`analysis`、`diagnostics`、`about`。 -- Mobile:移动端 section 集合与桌面相同。 -- Unknown:未知 id 不应导致页面崩溃。 +- Embedded sections:当前只接受 `general`、`providers`、`terminal`、`appearance`、`shortcuts`、`monitoring`。 +- Unknown section:未知 section 返回空内容并由路由层回退。 +- Workspace mode:嵌入分区会根据当前 workspace / session 状态切换布局模式。 验收标准: -- Given 用户在 Settings 页面 -- When 点击 Providers 分区 -- Then URL 和内容切换到 providers -- And Provider Settings 被渲染 +- Given 用户进入 `/more/settings/terminal` +- When 页面渲染完成 +- Then 应显示嵌入式终端设置内容 +- And 不应要求存在顶级 `/settings` 页面入口 代码索引: -- `packages/web/src/features/settings/components/settings-sections.tsx` -- `packages/web/src/features/settings/components/settings-navigation.ts` +- `packages/web/src/features/more/page.tsx` - `packages/web/src/features/settings/components/settings-page.tsx` -### SETTINGS-003 settings.get/update +### SETTINGS-003 settings.get / settings.update 状态:`Implemented` 用户行为: -- 用户修改设置项,例如默认 provider、通知、外观、LSP、更新、监控、Supervisor 或 provider 配置。 +- 用户修改设置项,例如默认 provider、通知、外观、终端、监控或 Supervisor 相关设置。 系统响应: -- `settings.get` 从 settings repo 读取非 provider 设置,并从 provider config repo 合并 provider 配置。 -- provider config 会按 provider schema sanitize,非法配置回退到默认值。 -- Supervisor 设置通过 resolver 归一化默认值和范围。 -- `settings.update` 校验 schema、flatten 非 provider 设置、合并 provider config,并写入 repo。 -- 更新 updates 或 monitoring 设置时触发对应服务 reload。 +- `settings.get` 读取非 provider 设置,并与 provider 配置合并返回。 +- `settings.update` 校验并写回设置;更新 monitoring 或 updates 相关设置时会触发对应服务 reload。 +- provider 配置按 schema 清洗,未知 provider 更新会返回错误。 状态与边界: -- Provider keys:`settings.get` 不直接暴露原始 `providers.*` settingsRepo 条目,而是来自 providerConfigRepo。 -- Unknown provider:更新未知 provider 配置返回 `unknown_provider`。 -- Personalization snapshot:完整 personalization snapshot 中缺失的 override 字段会删除旧 override key。 -- Validation:数值范围由 zod schema 和 core validator 限制。 +- Validation:数值范围与结构由 schema 校验。 +- Unknown provider:返回 `unknown_provider`。 +- Personalization snapshot:完整覆盖式更新会清理缺失的 override 字段。 验收标准: -- Given settings 中已配置 monitoring.enabled 为 false -- When 调用 `settings.update` 设置 monitoring.enabled 为 true -- Then settings repo 写入该值 -- And monitoring service reload 被触发 +- Given 当前 `monitoring.enabled` 为 `false` +- When 调用 `settings.update` 将其改为 `true` +- Then settings repo 应写入新值 +- And monitoring service 应重新加载 代码索引: - `packages/server/src/commands/settings.ts` - `packages/server/src/storage/settings-repo.ts` -### SETTINGS-004 读取/写入配置文件 +### SETTINGS-004 配置文件读取与写入 状态:`Implemented` 用户行为: -- 用户在 Provider Settings 中打开 Claude 或 Codex 配置文件编辑器,编辑内容、格式化、保存或重置。 +- 用户在 Providers 分区打开 Claude 或 Codex 配置文件编辑器,读取、修改、保存或重置配置。 系统响应: -- `settings.readConfigFile` 读取 `codex` 或 `claude` 配置文件,返回 configPath、content、exists。 -- 编辑器显示文件路径、存在状态、Monaco 编辑区和保存状态。 -- Claude 配置支持 JSON 格式化;Codex TOML 格式化当前不实现。 -- `settings.writeConfigFile` 写入内容,并在可能时返回 backupPath。 -- 保存成功后 toast 展示成功,带 backup 信息;失败后展示错误状态和 error toast。 +- `settings.readConfigFile` 返回配置路径、内容和文件存在状态。 +- `settings.writeConfigFile` 保存内容,并在可用时返回备份路径。 +- 前端在保存成功或失败后展示对应 toast。 状态与边界: -- File missing:文件不存在时显示空态提示,但仍允许编辑保存。 -- Dirty:content 与 originalContent 不同即为 dirty,启用保存和重置。 -- Saving:保存中禁用重复保存。 -- Load error:读取失败且没有 configPath 时只显示错误卡片。 +- File missing:文件不存在时仍允许用户新建并保存。 +- Dirty:内容有改动时才允许保存。 +- Formatting:Claude 配置支持 JSON 格式化;Codex TOML 当前不提供格式化。 验收标准: - Given Claude 配置文件存在 -- When 用户修改内容并点击保存 -- Then 前端调用 `settings.writeConfigFile` -- And 保存成功后 dirty 状态清除 -- And 如果有 backupPath,toast 中展示备份路径 +- When 用户修改后点击保存 +- Then 前端应调用 `settings.writeConfigFile` +- And 保存成功后清除 dirty 状态 代码索引: - `packages/server/src/commands/settings.ts` - `packages/server/src/config/config-io.ts` - `packages/web/src/features/settings/components/config-editor.tsx` -### SETTINGS-005 命令预览 +### SETTINGS-005 Provider 启动命令预览 状态:`Implemented` 用户行为: -- 用户在 Provider Settings 中编辑 provider 启动参数并查看命令预览。 +- 用户在 Providers 分区调整 provider 启动参数并查看命令预览。 系统响应: -- 前端调用 `settings.previewCommand`,传入 providerId、临时 config 和可选 workspacePath。 -- 服务端将临时 config 与默认/现有 provider config 合并,通过 provider `buildCommand` 生成 argv、cwd、env 和 preview 字符串。 -- UI 展示 preview 字符串。 +- 前端调用 `settings.previewCommand`。 +- 服务端按 provider 定义构造 argv、cwd、env 和 preview 字符串。 +- UI 展示最终命令预览。 状态与边界: -- Unknown provider:providerId 不存在时返回 `unknown_provider`。 -- Workspace fallback:workspacePath 未传时使用当前进程 cwd。 -- Preview failure:前端展示 `Error loading preview`。 +- Unknown provider:返回 `unknown_provider`。 +- Workspace fallback:未传 `workspacePath` 时使用当前进程 `cwd`。 +- Preview failure:前端展示错误提示,不写入配置。 验收标准: -- Given 用户在 Codex 启动参数输入 `--model gpt-5` -- When preview 请求完成 -- Then UI 展示包含该参数的启动命令预览 +- Given 用户为 Codex 输入 `--model gpt-5` +- When preview 请求成功 +- Then UI 应展示包含该参数的启动命令 代码索引: - `packages/server/src/commands/settings.ts` - `packages/web/src/features/settings/components/provider-settings.tsx` -### SETTINGS-006 Provider settings UI - -状态:`Implemented` - -用户行为: -- 用户在 Providers 分区查看 provider 概览、能力、runtime 状态、启动参数和配置文件入口。 - -系统响应: -- Provider tabs 来自 provider 列表。 -- provider badge、capability、stability 和 supported capabilities 作为摘要展示。 -- runtime 状态可用时显示 success,不可用时显示 warning、手工说明、文档和诊断入口。 -- 启动参数保存到 provider config。 -- Claude/Codex 允许切换到 config file 子视图。 - -状态与边界: -- Runtime loading:runtime 未返回时不展示状态块。 -- Mobile:移动端使用单独入口进入 config file 编辑器,再返回 base。 -- Unsupported config:非 Claude/Codex provider 不显示 config file 入口。 - -验收标准: -- Given Provider Settings 打开并选中不可用的 Claude -- When runtime status 返回 missing CLI -- Then 页面显示 warning -- And 用户可以跳转诊断页 - -代码索引: -- `packages/web/src/features/settings/components/provider-settings.tsx` - -### SETTINGS-007 Shortcuts settings UI - -状态:`Implemented` - -用户行为: -- 用户查看快捷键分类、点击某个快捷键进入录制、按键设置自定义绑定,或重置单个/全部快捷键。 - -系统响应: -- UI 按 global、workspace、editor、terminal 分类展示默认快捷键。 -- 进入编辑后输入框捕获 keydown,生成 binding 字符串。 -- 保存自定义 binding 到 `customShortcutsAtom`,并调用 `settings.update` 写入 `shortcuts.`。 -- Escape 取消录制。 -- 重置单个快捷键写入 null;重置全部写入空 shortcuts 对象。 - -状态与边界: -- Platform:Mac 上 Meta 映射为 Mod,非 Mac 上 Ctrl 映射为 Mod。 -- Arrow:Ctrl+Arrow 会保留 Ctrl。 -- UI state:失焦退出编辑态。 - -验收标准: -- Given 用户打开 Shortcuts 的 editor 分类 -- When 点击某个快捷键并按 `Mod+Shift+P` -- Then 该快捷键显示新绑定 -- And 前端调用 `settings.update` - -代码索引: -- `packages/web/src/features/settings/components/shortcuts-settings.tsx` -- `packages/web/src/lib/shortcuts.ts` - -### SETTINGS-008 Monitoring settings UI - -状态:`Implemented` - -用户行为: -- 用户在 Monitoring 分区启用/关闭监控,调整监控设置,并查看主机和 runtime 指标。 - -系统响应: -- Monitoring subpage 渲染 hero、状态卡、设置卡、KPI 和 MonitoringDashboard。 -- 启用开关调用 `onChange` 更新 settings。 -- 设置卡可刷新监控数据并切换 time window。 -- 如果 optimistic settings 已启用但最新监控 response 仍是 disabled,页面用空 response 合成等待态。 - -状态与边界: -- Disabled:监控关闭时显示 disabled 摘要和空 KPI。 -- Degraded/error:telemetry degraded 或 error 时状态显示 attention。 -- Not ready:monitoring settings 未 ready 时开关禁用。 -- Mobile:subpage 根据 viewport 添加移动/桌面 class。 - -验收标准: -- Given monitoring settings ready 且 enabled 为 false -- When 用户打开开关 -- Then onChange 收到 enabled 为 true 的 settings -- And 页面状态进入 enabled 或 waiting 展示 - -代码索引: -- `packages/web/src/features/settings/components/monitoring-settings-subpage.tsx` -- `packages/web/src/features/settings/components/monitoring-settings-card.tsx` -- `packages/server/src/commands/settings.ts` - -### SETTINGS-009 About settings - -状态:`Implemented` - -用户行为: -- 用户查看版本、server instance、安装支持、更新状态,并手动检查或安装更新。 - -系统响应: -- About 展示产品名、当前版本、serverInstanceId、安装支持状态、最新版本、上次检查时间、可用性和更新状态。 -- 用户可开关自动检查,并选择更新检查间隔。 -- 手动检查调用 `updates.check`。 -- 准备安装调用 `updates.prepareInstall`;如果存在 active work,显示确认框。 -- 安装调用 `updates.startInstall`,可传 force。 - -状态与边界: -- Unsupported:不支持安装时展示 unsupported reason。 -- Manual required:更新状态为 manual_required 时显示 manual command。 -- Failure:检查或安装失败时推送 error toast。 -- Confirmation:有 active work 时必须确认后才 force install。 - -验收标准: -- Given updateState 表示有新版本且支持安装 -- When 用户点击更新并 prepareInstall 返回 active work -- Then About 显示确认对话框 -- When 用户确认 -- Then 前端调用 `updates.startInstall` 且 force 为 true - -代码索引: -- `packages/web/src/features/settings/components/about-settings.tsx` - -### SETTINGS-010 外观和终端偏好 - -状态:`Implemented` - -用户行为: -- 用户在 Appearance 或 General 中切换主题、语言、LSP runtime mode、终端 renderer、复制选择、终端字号,以及背景/玻璃个性化设置。 - -系统响应: -- 主题切换立即更新 document `data-theme`,并保存 `appearance.themeId`。 -- 语言写入 `appearance.locale`。 -- LSP mode 写入 `lsp.mode`。 -- 终端 renderer/copy/font size 写入 `appearance` 对应字段。 -- 背景图片上传后保存 assetId;删除时先删除 asset,再清空 personalization 字段。 -- personalization 支持 common、desktop override、mobile override。 - -状态与边界: -- Terminal font:字号必须在 10-18,保存节流。 -- Bounded personalization:dimness 0-100,blur 0-40,glass/surface 0-100。 -- Override clearing:关闭 desktop/mobile override 时保存空 override。 -- Asset failure:上传或删除失败时显示 appearance asset 错误。 - -验收标准: -- Given 当前桌面终端字号为 13 -- When 用户输入 20 并提交 -- Then UI 恢复为 13 -- And 显示字号范围错误 -- When 用户输入 14 -- Then 调用 `settings.update` 保存 desktopTerminalFontSize 为 14 - -代码索引: -- `packages/web/src/features/settings/components/settings-page.tsx` -- `packages/server/src/commands/settings.ts` - -## 6. 未确认项 +## 6. 模块级验收线索 -- Diagnostics 分区在本模块只记录入口,详细诊断流程放到 Diagnostics 模块展开。 +- 桌面端访问 `/more` 时应自动归一化到 `/more/settings/general`。 +- 移动端访问 `/more` 时应先看到 category 列表,再进入具体 section。 +- 当前文档不得把 `/settings` 写成用户真实入口。 diff --git a/docs/product-spec/modules/welcome.zh-CN.md b/docs/product-spec/modules/welcome.zh-CN.md index 9a3042adc..9b6da56a4 100644 --- a/docs/product-spec/modules/welcome.zh-CN.md +++ b/docs/product-spec/modules/welcome.zh-CN.md @@ -1,39 +1,44 @@ # Welcome -> 第一轮模块索引。本文只记录代码可见的功能点、状态、代码入口和验收入口。 +> 当前代码基线。本文只记录当前已接线、用户可达的欢迎页能力。 ## 1. 模块范围 覆盖: -- 欢迎页。 -- 打开工作区入口。 -- 设置入口。 +- 欢迎页首屏内容。 +- 从欢迎页打开 workspace 启动器。 +- 两步式工作流说明与支撑能力列表。 不覆盖: -- 工作区目录浏览和打开后的状态更新,写入 Workspace 模块。 +- 登录与 session gate。 +- workspace 启动器内部的目录浏览、创建目录和打开目录流程。 ## 2. 用户入口 | 入口 | 端 | 说明 | | --- | --- | --- | -| `/` | Both | 默认欢迎入口或无 workspace 时的回退页面。 | -| 欢迎页打开工作区按钮 | Both | 打开 workspace launch modal。 | -| 欢迎页设置按钮 | Both | 进入设置页。 | +| `/` | Both | 没有可进入 workspace 时的默认首屏入口。 | +| 欢迎页“打开工作区”按钮 | Both | 打开 `WorkspaceLaunchModal`。 | ## 3. 功能点清单 | ID | 功能点 | 状态 | 代码入口 | 验收入口 | | --- | --- | --- | --- | --- | | WELCOME-001 | 欢迎页渲染 | Implemented | `packages/web/src/features/welcome/index.tsx` | `packages/web/src/features/welcome/index.test.tsx` | -| WELCOME-002 | 从欢迎页打开工作区启动器 | Implemented | `packages/web/src/features/welcome/index.tsx`、`packages/web/src/features/workspace/views/shared/workspace-launch-modal.tsx` | `packages/web/src/features/workspace/views/shared/workspace-launch-modal.test.tsx` | -| WELCOME-003 | 从欢迎页进入设置页 | Implemented | `packages/web/src/features/welcome/index.tsx` | `packages/web/src/features/welcome/index.test.tsx` | +| WELCOME-002 | 从欢迎页打开 workspace 启动器 | Implemented | `packages/web/src/features/welcome/index.tsx`、`packages/web/src/features/workspace/views/shared/workspace-launch-modal.tsx` | `packages/web/src/features/workspace/views/shared/workspace-launch-modal.test.tsx` | +| WELCOME-003 | 两步式工作流与支撑能力说明 | Implemented | `packages/web/src/features/welcome/index.tsx` | `packages/web/src/features/welcome/index.test.tsx` | -## 4. 模块级验收线索 +## 4. 当前页面事实 -- 无 workspace 时访问首页能看到欢迎页。 -- 点击打开工作区应显示目录浏览入口。 -- 点击设置应进入设置页。 +- 欢迎页当前是两步式落地页,不是旧版“三张功能卡 + 设置次按钮”结构。 +- 首屏当前只有一个主要交互入口:`打开工作区`。 +- 支撑能力说明当前只有两项: + - `Git tools` + - `terminals` +- 当前欢迎页没有可达的设置按钮,也不会直接跳转 `/settings`。 -## 5. 未确认项 +## 5. 模块级验收线索 -- 欢迎页文案和视觉信息不在第一轮索引中验收,后续可在 UI/文案规格中细化。 +- 当 workspace 列表为空时访问 `/`,页面应渲染欢迎页。 +- 点击“打开工作区”后应打开 workspace 启动器,而不是跳转到系统文件选择器。 +- 页面下方的支撑能力列表应只显示 Git 与终端两项。 diff --git a/docs/product-spec/modules/work-analysis.zh-CN.md b/docs/product-spec/modules/work-analysis.zh-CN.md index 98f602f08..f8f087fcb 100644 --- a/docs/product-spec/modules/work-analysis.zh-CN.md +++ b/docs/product-spec/modules/work-analysis.zh-CN.md @@ -31,7 +31,7 @@ | WA-006 | log collector 和 source adapters | Internal | `packages/server/src/work-analysis/log-sources` | `work-analysis-log-collector.test.ts`、`work-analysis-log-sources-file-adapters.test.ts` | | WA-007 | task classifier | Internal | `work-analysis/classification` | `work-analysis-task-classifier.test.ts` | | WA-008 | efficiency/retry metrics | Internal | `work-analysis/metrics` | `work-analysis-efficiency-metrics.test.ts`、`work-analysis-retry-metrics.test.ts` | -| WA-009 | optimize/exporters | Internal | `work-analysis/optimize`、`exporters` | `work-analysis-efficiency-and-optimize.test.ts` | +| WA-009 | optimize findings | Internal | `packages/server/src/work-analysis/optimize` | `work-analysis-efficiency-and-optimize.test.ts` | ## 4. 模块级验收线索 @@ -262,4 +262,4 @@ ## 6. 未确认项 -- 导出功能是否有稳定 UI 入口需在第二轮确认。 +- WA-004 与 WA-005 覆盖了当前真实用户入口;其余分析能力主要作为服务层与 dashboard 投影能力存在。 diff --git a/docs/product-spec/modules/workspace-mobile.zh-CN.md b/docs/product-spec/modules/workspace-mobile.zh-CN.md index 10110d48d..6fab95e0d 100644 --- a/docs/product-spec/modules/workspace-mobile.zh-CN.md +++ b/docs/product-spec/modules/workspace-mobile.zh-CN.md @@ -1,25 +1,30 @@ # Workspace Mobile -> 第一轮模块索引。本文只记录代码可见的功能点、状态、代码入口和验收入口。 +> 当前代码基线。本文只记录当前移动端工作区中真实挂载、真实可达的能力。 ## 1. 模块范围 覆盖: -- 移动端工作区视图。 -- Dock、Sheet、Drawer、移动端顶部栏。 -- 移动端文件、agent、terminal、supervisor 入口编排。 +- 移动端工作区整体布局。 +- 顶部栏、当前会话主区、底部状态栏。 +- Agent / Files / Terminal / Supervisor Sheet。 +- Workspace Drawer。 不覆盖: -- 每个 Sheet 内部业务细节。 +- 各 Sheet 内部的业务细节。 +- 未挂载组件或仅代码存在但无入口的移动端 UI。 ## 2. 用户入口 | 入口 | 端 | 说明 | | --- | --- | --- | | `/workspace` 移动视口 | Mobile | 渲染移动工作区布局。 | -| Mobile Dock | Mobile | 打开 agent、files、terminal、supervisor 等区域。 | -| Workspace Drawer | Mobile | 查看和切换 workspace。 | -| Mobile Topbar | Mobile | 移动端顶栏状态和 workspace 入口。 | +| Mobile Top Bar | Mobile | 打开 workspace drawer、文件、终端或 agent 相关入口。 | +| Agent Sheet | Mobile | 创建会话或切换当前 workspace 内的会话。 | +| Files Sheet | Mobile | 浏览文件、搜索、Source Control 和文件详情。 | +| Terminal Sheet | Mobile | 进入全屏终端视图。 | +| Supervisor Sheet | Mobile | 查看当前会话的 supervisor 详情。 | +| Workspace Drawer | Mobile | 查看和切换 workspace,以及切换其他 workspace 的会话。 | ## 3. 功能点清单 @@ -27,19 +32,28 @@ | --- | --- | --- | --- | --- | | WSM-001 | 移动工作区整体渲染 | Implemented | `packages/web/src/features/workspace/views/mobile/workspace-mobile-view.tsx` | `packages/web/src/features/workspace/views/mobile/workspace-mobile-view.test.tsx` | | WSM-002 | 移动端顶部栏 | Implemented | `packages/web/src/features/workspace/views/mobile/mobile-topbar.tsx` | `packages/web/src/features/workspace/views/mobile/workspace-mobile-view.test.tsx` | -| WSM-003 | 移动端 Dock | Implemented | `packages/web/src/features/workspace/views/mobile/mobile-dock.tsx` | `packages/web/src/features/workspace/views/mobile/workspace-mobile-view.test.tsx` | +| WSM-003 | 当前会话主区与底部状态栏 | Implemented | `packages/web/src/features/workspace/views/mobile/workspace-mobile-view.tsx`、`packages/web/src/features/workspace/views/shared/workspace-status-bar.tsx` | `packages/web/src/features/workspace/views/mobile/workspace-mobile-view.test.tsx` | | WSM-004 | Agent Sheet | Implemented | `packages/web/src/features/workspace/views/mobile/mobile-agent-sheet.tsx` | `packages/web/src/features/workspace/views/mobile/mobile-agent-sheet.test.tsx` | | WSM-005 | Files Sheet | Implemented | `packages/web/src/features/workspace/views/mobile/mobile-files-sheet.tsx` | `packages/web/src/features/workspace/views/mobile/mobile-files-sheet.test.tsx` | -| WSM-006 | Workspace Drawer | Implemented | `packages/web/src/features/workspace/views/mobile/mobile-workspace-drawer.tsx` | `packages/web/src/features/workspace/views/mobile/mobile-workspace-drawer.test.tsx` | -| WSM-007 | Mobile explorer panel | Implemented | `packages/web/src/features/workspace/views/mobile/mobile-explorer-panel.tsx` | `packages/web/src/features/workspace/views/mobile/mobile-explorer-panel.test.tsx` | -| WSM-008 | 移动布局/动效模式 hook | Internal | `packages/web/src/features/workspace/views/mobile/hooks` | 手工验收:移动视口布局与键盘视口变化 | - -## 4. 模块级验收线索 - -- 移动视口进入工作区时应显示 Dock 驱动布局。 -- Dock 打开不同 Sheet 后应保持当前 workspace 上下文。 -- Workspace Drawer 能展示 workspace 列表并切换 active workspace。 - -## 5. 未确认项 - -- 视觉视口 inset 在不同移动浏览器的边界需后续人工设备验收。 +| WSM-006 | Terminal Sheet | Implemented | `packages/web/src/features/workspace/views/mobile/workspace-mobile-view.tsx`、`packages/web/src/features/terminal-panel` | `packages/web/src/features/workspace/views/mobile/workspace-mobile-view.test.tsx` | +| WSM-007 | Supervisor Sheet | Implemented | `packages/web/src/features/supervisor/views/mobile/mobile-supervisor-sheet.tsx` | `packages/web/src/features/workspace/views/mobile/workspace-mobile-view.test.tsx` | +| WSM-008 | Workspace Drawer | Implemented | `packages/web/src/features/workspace/views/mobile/mobile-workspace-drawer.tsx` | `packages/web/src/features/workspace/views/mobile/mobile-workspace-drawer.test.tsx` | +| WSM-009 | Mobile Dock 组件 | Internal | `packages/web/src/features/workspace/views/mobile/mobile-dock.tsx` | 代码存在,但当前 `WorkspaceMobileView` 未挂载 | + +## 4. 当前页面事实 + +- 当前移动端不是 Dock 驱动布局;真实布局是“顶部栏 + 当前会话主区 + Sheet/Drawer + 底部状态栏”。 +- `MobileDock` 组件当前仅存在于代码中,未被 `WorkspaceMobileView` 挂载,不能写成已上线功能。 +- Files Sheet 当前承担多种视图: + - `explorer` + - `search` + - `source-control` + - 文件详情 / 编辑器详情 +- Terminal 以全屏 Sheet 打开,底部仍可附带 workspace 状态栏。 +- Workspace Drawer 会按需 hydrate 非当前 workspace 的会话列表。 + +## 5. 模块级验收线索 + +- 移动视口进入 `/workspace` 后,应直接看到当前会话主区,而不是底部 Dock。 +- 从顶部栏或其他移动入口打开 Files / Terminal / Supervisor 时,应进入对应 Sheet。 +- 打开 Workspace Drawer 后,应能切换 workspace,并查看其他 workspace 的会话列表。 diff --git a/docs/promotion/releases/v0.5.5.md b/docs/promotion/releases/v0.5.5.md new file mode 100644 index 000000000..3f11779da --- /dev/null +++ b/docs/promotion/releases/v0.5.5.md @@ -0,0 +1,83 @@ +# Coder Studio v0.5.5 + +## 中文 + +### 这个版本为什么重要 + +`v0.5.5` 把最近一轮 workspace 与 runtime 的大改动整理成一个可发布版本。它把 canvas、技能管理、terminal profile、automation entry 和一批 workspace 交互改进合到同一个交付里,同时补上了 Windows WSL 编码识别和 pane divider 可见性这类会直接影响日常使用的修复。 + +实际体验上,这个版本意味着: + +- workspace 现在可以直接承载 canvas 文件与架构/报告视图,不再只能停留在普通文本编辑 +- 技能管理、技能文件编辑和内置能力桥接更完整,workspace 内的技能工作流更顺手 +- terminal profile 与 runtime 装配能力更成熟,尤其是 Windows/WSL 环境下的终端识别更可靠 +- 桌面端和移动端的 workspace、skills、settings、open editors 与 terminal 相关交互更一致 + +### 这个版本包含哪些变化 + +- 新增 canvas 数据模型、服务端路由、渲染组件和嵌入式 canvas 路径,支持架构图和报告画布 +- 扩展技能管理能力,补齐技能文件读写、挂载、推荐与内置 automation bridge 相关流程 +- 引入 terminal profile 注册与检测链路,并修复 Windows 下 `wsl.exe -l -q` 的 UTF-16 输出解码 +- 更新 automation entry、runtime 装配、host/runtime router 与 session 相关能力,提升运行时组织方式 +- 打磨 workspace、skills panel、code editor tabs、mobile drawer、settings terminal section 等 UI 细节 +- 修复 agent pane split divider 不可见问题,并补强相关主题测试 +- 同步更新文档、预览场景、测试与发布辅助脚本 + +### 谁最受益 + +- 需要在 workspace 内查看或维护架构图、报告画布的用户 +- 重度依赖技能管理、自定义技能与自动化桥接能力的用户 +- 在 Windows 或 WSL 环境中运行 Coder Studio 的开发者 +- 希望桌面端和移动端 workspace 体验更完整、更稳定的日常使用者 + +### 安装或升级 + +```bash +npm install -g @spencer-kit/coder-studio@latest +coder-studio open +``` + +### 完整变更 + +- [Compare `v0.5.4...v0.5.5`](https://github.com/spencerkit/coder-studio/compare/v0.5.4...v0.5.5) + +## English + +### Why this release matters + +`v0.5.5` packages the latest workspace and runtime refresh into a releasable build. It brings canvas support, skill-management improvements, terminal profile handling, automation entry updates, and a broad set of workspace refinements into one delivery, while also fixing daily-use issues like Windows WSL label decoding and invisible pane dividers. + +In practice, this release means: + +- the workspace can now handle canvas files and architecture/report views instead of treating everything as plain text +- skill management, skill-file editing, and builtin automation bridging are more complete inside the workspace +- terminal profile detection and runtime assembly are more mature, especially for Windows and WSL environments +- desktop and mobile flows across workspace, skills, settings, open editors, and terminal interactions behave more consistently + +### Included in v0.5.5 + +- add canvas domain models, server routes, rendering components, and embedded canvas paths for architecture and report canvases +- expand skill-management workflows with skill-file read/write flows, mounting improvements, recommendations, and a builtin automation bridge +- introduce terminal profile registry and detection flows, and fix UTF-16 decoding for `wsl.exe -l -q` on Windows +- update automation entry, runtime assembly, host/runtime routing, and session plumbing for a cleaner runtime structure +- refine workspace, skills panel, code editor tabs, mobile drawer, and terminal settings UI surfaces +- restore visible agent pane split dividers and strengthen the related theme tests +- sync docs, preview scenes, tests, and release-supporting scripts with the new behavior + +### Who benefits most + +- users who need to view or maintain architecture diagrams and report canvases inside the workspace +- users who rely heavily on skill management, custom skills, and automation bridge flows +- developers running Coder Studio in Windows or WSL environments +- daily users who want a fuller, more stable workspace experience across desktop and mobile + +### Install or upgrade + +```bash +npm install -g @spencer-kit/coder-studio@latest +coder-studio open +``` + +### Full changelog + +- [Compare `v0.5.4...v0.5.5`](https://github.com/spencerkit/coder-studio/compare/v0.5.4...v0.5.5) diff --git a/docs/wiki/Quick-Start.md b/docs/wiki/Quick-Start.md index 6862f8e6a..388dbb8c4 100644 --- a/docs/wiki/Quick-Start.md +++ b/docs/wiki/Quick-Start.md @@ -33,7 +33,7 @@ After Coder Studio opens, continue with [First Agent Run](First-Agent-Run.md) to ## Open A Project -1. Click the workspace picker. +1. On the welcome screen, click **Open Workspace**. 2. Select your project folder. 3. Wait for the file tree, Git panel, and terminal area to load. diff --git a/packages/cli/src/automation-command-client.test.ts b/packages/cli/src/automation-command-client.test.ts index 4e7d78095..357bed676 100644 --- a/packages/cli/src/automation-command-client.test.ts +++ b/packages/cli/src/automation-command-client.test.ts @@ -64,6 +64,7 @@ describe("automation command client", () => { beforeEach(() => { socketInstances.length = 0; vi.stubEnv("CODER_STUDIO_API_URL", ""); + vi.stubEnv("CODER_STUDIO_SESSION_TOKEN", ""); getServerStatus.mockResolvedValue({ status: "running", pid: 1, diff --git a/packages/server/src/terminal-profiles/__tests__/wsl.test.ts b/packages/server/src/terminal-profiles/__tests__/wsl.test.ts new file mode 100644 index 000000000..c65b827d0 --- /dev/null +++ b/packages/server/src/terminal-profiles/__tests__/wsl.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it } from "vitest"; +import { decodeWindowsConsoleOutput } from "../wsl.js"; + +describe("decodeWindowsConsoleOutput", () => { + it("decodes UTF-16 LE wsl distro list output without BOM", () => { + const buffer = Buffer.from("Ubuntu-24.04\r\n", "utf16le"); + + expect(decodeWindowsConsoleOutput(buffer)).toBe("Ubuntu-24.04\r\n"); + }); + + it("decodes UTF-16 LE output with BOM", () => { + const body = Buffer.from("Ubuntu-24.04\r\n", "utf16le"); + const buffer = Buffer.concat([Buffer.from([0xff, 0xfe]), body]); + + expect(decodeWindowsConsoleOutput(buffer)).toBe("Ubuntu-24.04\r\n"); + }); + + it("keeps UTF-8 output unchanged", () => { + const buffer = Buffer.from("Ubuntu-24.04\r\n", "utf8"); + + expect(decodeWindowsConsoleOutput(buffer)).toBe("Ubuntu-24.04\r\n"); + }); +}); diff --git a/packages/server/src/terminal-profiles/detect.ts b/packages/server/src/terminal-profiles/detect.ts index 4a972b5df..b71b06d16 100644 --- a/packages/server/src/terminal-profiles/detect.ts +++ b/packages/server/src/terminal-profiles/detect.ts @@ -1,3 +1,4 @@ +import { spawn } from "node:child_process"; import { existsSync as fsExistsSync } from "node:fs"; import path from "node:path"; import type { TerminalProfile } from "@coder-studio/core"; @@ -7,7 +8,7 @@ import { getCommandLookupExecutable, } from "../provider-runtime/command-check.js"; import { type CommandRunner, runCommandAsString } from "../provider-runtime/command-runner.js"; -import { formatWslLabel } from "./wsl.js"; +import { decodeWindowsConsoleOutput, formatWslLabel } from "./wsl.js"; export interface DetectedTerminalProfile extends TerminalProfile { source: "detected"; @@ -200,19 +201,47 @@ function pushIfUnique( } async function listWslDistros(runCommand?: CommandRunner): Promise { - const runner = runCommand ?? runCommandAsString; - try { - const { stdout } = await runner("wsl.exe", ["-l", "-q"], { windowsHide: true }); - return stdout - .split(/\r?\n/) - .map((line) => line.trim()) - .filter((line) => line.length > 0); + const stdout = runCommand + ? (await runCommand("wsl.exe", ["-l", "-q"], { windowsHide: true })).stdout + : await runWslListStdout(); + return parseWslDistroLines(stdout); } catch { return []; } } +function parseWslDistroLines(stdout: string): string[] { + return stdout + .split(/\r?\n/) + .map((line) => line.trim()) + .filter((line) => line.length > 0); +} + +function runWslListStdout(): Promise { + return new Promise((resolve, reject) => { + const child = spawn("wsl.exe", ["-l", "-q"], { + windowsHide: true, + stdio: ["ignore", "pipe", "pipe"], + }); + const stdoutChunks: Buffer[] = []; + + child.stdout?.on("data", (chunk: string | Buffer) => { + stdoutChunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk); + }); + + child.on("error", reject); + child.on("close", (code) => { + if (code !== 0) { + reject(new Error(`wsl.exe exited with code ${code ?? "unknown"}`)); + return; + } + + resolve(decodeWindowsConsoleOutput(Buffer.concat(stdoutChunks))); + }); + }); +} + async function resolveWindowsCommandPath( command: string, runCommand?: CommandRunner diff --git a/packages/server/src/terminal-profiles/wsl.ts b/packages/server/src/terminal-profiles/wsl.ts index 09537d568..b281868bb 100644 --- a/packages/server/src/terminal-profiles/wsl.ts +++ b/packages/server/src/terminal-profiles/wsl.ts @@ -1,5 +1,22 @@ import path from "node:path"; +export function decodeWindowsConsoleOutput(buffer: Buffer): string { + if (buffer.length === 0) { + return ""; + } + + if (buffer[0] === 0xff && buffer[1] === 0xfe) { + return buffer.toString("utf16le", 2); + } + + const nullBytes = buffer.reduce((count, byte) => count + (byte === 0 ? 1 : 0), 0); + if (nullBytes > 0) { + return buffer.toString("utf16le"); + } + + return buffer.toString("utf8"); +} + export function toWslPath(windowsPath: string): string | null { const parsed = path.win32.parse(windowsPath); if (!parsed.root || !/^[A-Za-z]:\\$/.test(parsed.root)) { diff --git a/packages/web/src/styles/components.css b/packages/web/src/styles/components.css index a369d0ce8..b080bb98c 100644 --- a/packages/web/src/styles/components.css +++ b/packages/web/src/styles/components.css @@ -11010,7 +11010,7 @@ body.is-resizing-floating-editor--nesw * { position: absolute; pointer-events: none; border-radius: var(--radius-pill); - background: transparent; + background: var(--component-mix-border-default-62pct-transparent); } .pane-layout-horizontal-divider::after { @@ -11026,12 +11026,12 @@ body.is-resizing-floating-editor--nesw * { right: 0; top: 50%; height: 1px; - background: transparent; + background: var(--component-mix-border-default-78pct-status-info-fg-22pct); transform: translateY(-50%); } .pane-layout-divider:hover::after { - background: transparent; + background: var(--component-mix-border-focus-58pct-transparent); } .pane-layout-divider:hover { diff --git a/packages/web/src/styles/components.theme.test.ts b/packages/web/src/styles/components.theme.test.ts index 85c142628..8e1a2f655 100644 --- a/packages/web/src/styles/components.theme.test.ts +++ b/packages/web/src/styles/components.theme.test.ts @@ -1482,7 +1482,9 @@ describe("components.css theme-sensitive surfaces", () => { expect(paneDividerBaseRules).toContain("z-index: var(--z-inline)"); expect(paneDividerBaseRules).not.toContain("z-index: var(--z-inline-raised)"); expect(paneDividerBaseRules).toContain("background: transparent"); - expect(paneDividerLineRules).toContain("background: transparent"); + expect(paneDividerLineRules).toContain( + "background: var(--component-mix-border-default-62pct-transparent)" + ); expect(paneDividerLineRules).toContain("border-radius: var(--radius-pill)"); expect(paneDividerHoverRules).toContain("background: transparent"); expect(paneDividerHorizontalRules).toContain("width: 10px"); diff --git a/packages/web/src/styles/pane-layout-divider.theme.test.ts b/packages/web/src/styles/pane-layout-divider.theme.test.ts index e1900cfb4..96005f8e7 100644 --- a/packages/web/src/styles/pane-layout-divider.theme.test.ts +++ b/packages/web/src/styles/pane-layout-divider.theme.test.ts @@ -46,7 +46,11 @@ describe("pane-layout vertical divider styles", () => { expect(divider).toContain("margin-top: -5px"); expect(divider).toContain("margin-bottom: -5px"); expect(divider).toContain("background: transparent"); - expect(dividerLine).toContain("background: transparent"); - expect(hoverDividerLine).toContain("background: transparent"); + expect(dividerLine).toContain( + "background: var(--component-mix-border-default-78pct-status-info-fg-22pct)" + ); + expect(hoverDividerLine).toContain( + "background: var(--component-mix-border-focus-58pct-transparent)" + ); }); });