TermDock 第一版要解决的是“桌面端远程工作台”的核心闭环,而不是协议大而全。
核心体验:
- 一个连接列表
- 一个多标签工作区
- SSH 会话中终端与 SFTP 文件联动
- FTP 会话中只呈现文件管理
- 上传下载任务全局可见
当前仓库已经具备 MVP 雏形,主要能力包括:
- Monorepo workspace 基础结构
- Electron 主窗口启动
- 独立连接管理器窗口
- React 工作台主界面
- 标签页工作区模型
- SSH / FTP 连接配置的新增、编辑、删除、持久化
- 基于文件的 profile 存储(
profiles.json) - 本地目录浏览
- 本地文件读写
- SSH 会话连接
- SSH shell 输出接入
- 终端写入与 resize IPC
- SFTP 远程目录浏览
- 远程文件读取与写回
- FTP 会话连接与远程文件能力
- 上传下载任务队列与进度状态
- 工作区快照广播到多个窗口
- 预览态数据与桌面运行态双模式
- SSH 主机系统信息页与轮询刷新
当前主题系统也已经开始成形,主要落点包括:
apps/desktop/src/renderer/styles/themes/tokens.css- 基础视觉 token,供半径、阴影、间距等全局样式复用。
apps/desktop/src/renderer/styles/themes/default-dark.cssapps/desktop/src/renderer/styles/themes/default-light.css- 明暗主题变量与组件覆盖层。
apps/desktop/src/renderer/hooks/useThemeMode.ts- 通过
document.documentElement.dataset.theme切换主题。
- 通过
apps/desktop/src/renderer/components/TerminalView.tsx- 从 CSS 变量读取终端主题色,确保终端外观和全局主题联动。
当前已安装、已接入的第三方项目和维护边界见 integration-inventory.md。本节包含部分阶段规划项,精确现状以该集成总表和 package.json 为准。
- Electron
- React
- TypeScript
- Vite
- xterm.js
- Monaco Editor
- OpenCC
ssh2basic-ftpelectron-builder- 文件型 profile 存储
- Tailwind CSS:已放弃迁移。TermDock 需要大量覆盖 xterm、Monaco、Electron 桌面壳和表格/文件面板细节,继续使用
token -> theme vars -> component skins的 CSS 分层更可控。 - Radix UI / shadcn/ui:暂不引入。当前自有组件和桌面式密集布局更贴近产品形态,避免再叠一层组件体系。
- react-resizable-panels:暂不引入。现阶段文件面板和侧栏 resize 已由本地组件处理。
- Zustand:暂不引入。当前状态主要由 React state、workspace service snapshot 和 IPC 广播驱动;等
App.tsx拆分后再评估是否需要 store。 - zod:暂不引入。类型先收敛到
packages/core,运行时校验如果变复杂再单独评估。 - SQLite / Drizzle ORM:暂缓。当前连接配置使用文件型 profile 存储;等 profile、设置、传输历史的查询需求明确后再迁移。
- 系统钥匙串:暂缓。敏感信息存储策略需要单独做安全设计,不混在 UI 或协议改动里。
Renderer UI
-> Application Stores
-> IPC Bridge
-> Desktop Services
-> Session Controllers
-> Protocol Adapters
-> Remote Servers分层职责:
Renderer UI- 界面渲染
- 用户交互
- 布局与组件状态
Application Stores- 标签状态
- 当前工作区状态
- 连接列表
- 传输任务
IPC Bridge- 暴露类型安全的前后端调用接口
Desktop Services- 配置存储
- 密钥管理
- 会话创建与销毁
- 文件传输调度
- 系统信息采集调度与快照广播
Session Controllers- 会话生命周期管理
- 状态机
- 通道复用
- 面向协议与平台的原始系统指标采集
Protocol Adapters- SSH
- SFTP
- FTP
当前系统信息页先服务于 SSH 会话,但边界需要按“可扩展到多平台”来建立:
packages/core- 只定义原始指标结构与 renderer 需要的通用字段,不承载中文或英文展示字符串。
main/services/sessions/*- 负责按远端平台探测并采集原始指标,例如 Linux
/proc、BusyBox 兼容命令、未来的 Windows PowerShell。
- 负责按远端平台探测并采集原始指标,例如 Linux
workspace-session-runtime- 负责轮询、节流、网络历史合并、快照广播。
renderer/features/system/*- 只做展示、本地化、布局与表格格式化,不承担平台分支判断。
现阶段的实现仍然偏 Linux over SSH,但后续扩展应保持:
platform probe
-> raw metrics collection
-> normalized core shape
-> snapshot/runtime merge
-> localized renderer presentationtermdock/
AGENTS.md
README.md
package.json
tsconfig.base.json
docs/
architecture.md
roadmap.md
plans/
active/
completed/
decisions/
quality/
.agents/
README.md
extensions/
README.md
apps/
desktop/
index.html
package.json
tsconfig.json
tsconfig.node.json
vite.config.ts
src/
main/
main.ts
ipc.ts
services/
file-profile-repository.ts
local-files-service.ts
session-controllers.ts
workspace-service.ts
preload/
preload.cts
renderer/
App.tsx
i18n.ts
main.tsx
vite-env.d.ts
components/
TerminalView.tsx
styles/
app.css
themes/
packages/
core/
src/
index.ts
shared/
src/
index.ts
storage/
src/
index.ts当前仓库采用 npm workspaces 的 monorepo 结构。协议 controller 仍放在 desktop main service 内,暂不拆成独立 protocol-* package:
termdock/
apps/
desktop/
src/
main/
preload/
renderer/
packages/
core/
storage/
shared/apps/desktop- Electron 主工程
- 桌面窗口
- preload
- React 渲染层入口
packages/core- 领域模型
- Session interface
- 文件操作统一抽象
- 状态定义
apps/desktop/src/main/services/sessions- SSH 连接
- shell channel
- SFTP client adapter
- FTP 连接与文件操作 adapter
packages/storage- profile repository
- settings repository 预留
apps/desktop/src/main/services- 文件型 profile 存储
- profile repository
packages/shared- types
- constants
- 轻量共享工具
apps/desktop/src/renderer- 可复用 UI 组件
- 终端、文件管理、连接管理、系统信息等 feature UI
type SessionType = 'ssh' | 'ftp'interface BaseProfile {
id: string
name: string
host: string
port: number
}
interface SshProfile extends BaseProfile {
type: 'ssh'
username: string
authType: 'password' | 'privateKey'
password?: string
privateKeyPath?: string
passphrase?: string
sftpEnabled: boolean
}
interface FtpProfile extends BaseProfile {
type: 'ftp'
username: string
password?: string
secure: boolean
}
type ConnectionProfile = SshProfile | FtpProfileinterface SshSession {
id: string
type: 'ssh'
shell: ShellChannel
sftp: SftpClient
}
interface FtpSession {
id: string
type: 'ftp'
ftpClient: FtpClient
}SSH 终端与远程文件区通过真实 shell cwd 联动,不解析用户输入的 cd 文本:
shell integration
-> OSC 7 cwd
-> SSH controller cwd changed
-> workspace runtime follow policy
-> SessionSnapshot
-> rendererSessionSnapshot 中三个字段语义保持独立:
shellCwd:远端交互式 shell 当前工作目录。remotePath:远程文件面板当前展示目录。followShellCwd:该 tab 是否允许 cwd 变化驱动文件面板。
shell 注入按 bash、zsh、fish、POSIX 风格策略选择;探测或注入失败时只降级目录跟随,不影响 SSH、SFTP 和终端输入输出。
interface WorkspaceTab {
id: string
sessionType: 'ssh' | 'ftp'
profileId: string
title: string
layout: 'terminal-file' | 'file-only'
status: 'idle' | 'connecting' | 'connected' | 'error' | 'closed'
}这是第一版最重要的建模约束。
- 同一个认证上下文
- 同一个目标主机
- 终端与文件面板天然联动
- 未来可扩展端口转发、远端命令、路径跟随
- 独立协议
- 无 shell
- 文件操作是完整主路径
- 未来即使支持 FTPS,也仍属于 FTP 家族,不应嫁接到 SSH 模型中
如果一开始为了“统一文件协议”硬揉成一个大 RemoteSession,后面会很快出现:
- 一堆条件分支
- 一堆无意义空能力
- 布局逻辑混乱
- 状态类型失真
所以这里必须拆。
前端不要直接接触协议客户端,所有能力都走服务边界。
profile- 创建连接配置
- 更新连接配置
- 删除连接配置
- 查询连接配置
session- 打开会话
- 关闭会话
- 重连
- 查询会话状态
terminal- 输入
- resize
- 粘贴
- 订阅输出
remoteFile- list
- stat
- mkdir
- rename
- delete
- upload
- download
transfer- 查询任务
- 取消任务
- 重试任务
- 左侧:连接列表 / 收藏 / 分组
- 顶部:标签栏
- 主区:工作区视图
- 底部:传输任务面板
- 上部:终端
- 下部:远程文件面板
- 支持拖动调整比例
- 支持切换终端全屏或文件全屏
- 仅文件面板
- 主区域全高使用
主题系统需要保持一条清晰链路:
tokens -> theme vars -> component skins -> terminal colors约束:
- 新视觉能力优先进入
styles/themes/的 token 和主题层。 - 终端、标签页、按钮、表格、面板这类共用外观,先判断是否需要补 theme vars。
- 不要把颜色、阴影、圆角散落在业务组件里。
- 终端配色从 CSS 变量读取,避免和全局主题脱节。
- 连接配置
- 分组
- 最近连接
- UI 设置
- 终端设置
- 传输历史
当前策略:
- 连接配置使用文件型 profile 存储。
- 密码、私钥和系统钥匙串接入仍属于后续安全专项。
后续如果迁移存储,再评估:
- 连接元数据存 SQLite
- 密码与私钥密文单独存储
- 优先使用 Electron
safeStorage - 后续可接系统钥匙串
当前状态主要由 React state、workspace service snapshot 与 IPC 广播驱动。后续优先拆 App.tsx 和 workspace service 的领域边界,再决定是否需要引入 store 库。
如果未来引入 store,建议按领域拆 store,而不是一个全局超级 store:
useWorkspaceStoreuseProfilesStoreuseSessionStoreuseTransferStoreuseSettingsStore
避免重走旧桌面项目常见的“大 store 全塞”路线。
当前最重的实现集中在:
apps/desktop/src/main/services/workspace-service.ts- 工作区状态中心,已经承担了 profile、tab、session、transfer 的主要调度职责。
apps/desktop/src/main/services/session-controllers.ts- SSH / FTP 的运行时协议接入。
apps/desktop/src/renderer/App.tsx- UI 逻辑较重,承接了较多页面状态与交互。
建议优先小步拆分这些热点,而不是一边加功能一边继续堆。
这些能力在设计时可以预留接口,但不进入首轮交付:
- Telnet
- Serial
- RDP
- VNC
- 自动化脚本
- 团队同步
- 云备份
- AI 助手
- 手机端正式布局适配
- 所有新功能先落抽象,再接 UI
- IPC 必须有类型定义
- 不允许 renderer 直接操作协议客户端
- 文件传输必须走统一任务中心
- 错误处理必须以用户可读提示为目标
- 优先把 macOS 与 Windows 体验做顺
- 视觉样式优先遵循主题系统链路