docs: M6/M7 delivered — roadmap + state snapshot (release v0.7.0 published)

This commit is contained in:
954801926@qq.com committed 2026-09-06 21:03:20 +08:00
1 parent 2a32ee910a
commit 54c803091c
2 files changed
+53 -34

No files matched your search

+13 -13
View File
@@ -12,8 +12,8 @@
| M3 | SSH 产品化:Terminal/SSH 分离 + 服务器硬件监控(Wave 风格) | ✅ 已完成(v0.3) |
| M4 | SFTP 文件管理 + 传输面板 + 权限/属主/chmod | ✅ 已完成(v0.4) |
| M5 | 命令历史/命令库/补全 + 会话日志 | ✅ 已完成(v0.5) |
| M6 | 广播输入 + ZMODEM + 快捷输入面板 + 快捷键系统 | 📋 下一步 |
| M7 | 打包分发(electron-builder + 自动更新) | |
| M6 | 广播输入 + ZMODEM + 快捷输入面板 + 快捷键系统 | ✅ 已完成(v0.6) |
| M7 | 打包分发(MSI + NSIS + 自动更新) | ✅ 已完成(v0.7,Release 已发布) |
## M2 — SSH 远程会话 ✅
@@ -68,20 +68,20 @@
- [x] ~~关键词高亮~~(✅ 已提前完成:highlightEngine 流式 ANSI 注入 + 11 条预设 + 设置页管理,见 M2.5)
- 验收:补全 ↑↓/Tab/Esc 交互与 XTerminal 一致
## M6 — 多终端协同
## M6 — 多终端协同 ✅
- [ ] 广播输入(toggleBroadcast):选中多个会话同步键入
- [ ] 快捷输入面板(Quick Input):右下角浮层 = 命令输入 + 快捷命令 + 最近命令
- [ ] ZMODEM(rz/sz):渲染层检测 ZRQINIT/ZRINIT 序列,触发文件选择
- [ ] 快捷键系统:增减字号、切换上下个终端、全局快捷键(globalShortcut)
- 验收:3 个分屏同步执行命令;rz 传输成功
- [x] 广播输入(broadcastStore):选中 ≥2 个会话同步键入;标签广播标记 + 按钮计数徽标;目标 <2 自动关闭
- [x] 快捷输入面板(Quick Input):右下角浮层 = 命令输入 + 自动执行(\r) + 快捷命令 + 最近命令;广播感知发送
- [x] ZMODEM(rz/sz):主进程引擎(zmodem.js,仅 SSH 会话;本地 ConPTY 不支持二进制),文件选择/保存目录对话框 + 传输面板进度 + 看门狗超时;双向 e2e(tests/zmodem-e2e.mjs)
- [x] 快捷键系统:Ctrl+=/-/0 字号(持久化)、Ctrl+PgUp/PgDn 切换终端、全局唤起/隐藏(设置页可配 globalShowHide)
- 验收:3 个分屏同步执行命令 ✅(活体验证:终端 3 键入扇出到终端 4);rz 传输 ✅(e2e 双向内容一致;真实服务器 rz/sz 待用户复测)
## M7 — 打包与分发
## M7 — 打包与分发 ✅
- [ ] electron-builder:nsis 安装包(Windows 优先,x64/arm64)
- [ ] 原生模块处理:node-pty 已用 @lydell 预编译版,无需 rebuild
- [ ] 自动更新(electron-updater + generic provider 或 GitHub Releases)
- [ ] 代码签名(可选)
- [x] electron-builder:**MSI**(固定 upgradeCode,手动/企业部署)+ NSIS(x64),`npm run dist` / `dist:dir`
- [x] 原生模块:@lydell/node-pty 预编译 + asarUnpack(node-pty/ssh2),npmRebuild=false,win-unpacked 冒烟通过
- [x] 自动更新(electron-updater,generic feed = Gitea generic package 稳定地址,公网可读;仅 packaged 启用,OT_UPDATE_URL/OT_UPDATE_TOKEN 可覆盖)
- [ ] 代码签名(可选,未做);应用图标(默认 Electron 图标,MSI 快捷方式暂禁用待图标补齐)
## 工程约定(贯穿各阶段)
+40 -21
View File
@@ -4,8 +4,9 @@
## 当前版本与仓库
- v0.5(提交 90058eb+),远程 `git.codingplan.site/admin/OpenTerminal.git`(令牌已存于 .git/config)
- 技术栈:Electron + electron-vite + React 19 + TS strict + antd 6(全局深色)+ zustand + dockview-react 8 + @xterm/xterm 6 + @lydell/node-pty + ssh2 + font-list
- v0.7.0(tag v0.7.0 = 2a32ee9),远程 `git.codingplan.site/admin/OpenTerminal.git`(令牌已存于 .git/config)
- Release v0.7.0:MSI + NSIS 安装包 + latest.yml 已上传附件;更新通道 = `https://git.codingplan.site/api/packages/admin/generic/openterminal-update/stable/`(公网可读,含 latest.yml/exe/blockmap)
- 技术栈:Electron + electron-vite + React 19 + TS strict + antd 6(全局深色)+ zustand + dockview-react 8 + @xterm/xterm 6 + @lydell/node-pty + ssh2 + zmodem.js + electron-updater + electron-builder
- 契约先行约定:所有跨进程接口定义在 `src/shared/`,主/预载/渲染各自实现;新功能先改 shared 再派两端
## 里程碑状态(详见 ROADMAP.md)
@@ -18,12 +19,25 @@
| M3 Terminal/SSH 分离+服务器监控(Wave 风格) | ✅(真实服务器验收通过) |
| M4 SFTP 文件管理+传输+权限/chmod/chown+监控图表化 | ✅(真实服务器验收通过) |
| M5 命令历史/命令库/补全+会话日志 | ✅ |
| M6 广播输入+ZMODEM+快捷输入面板+快捷键系统 | 📋 下一步 |
| M7 打包分发(electron-builder+自动更新) | |
| M6 广播输入+ZMODEM+快捷输入面板+快捷键系统 | ✅(v0.6.0,UI 活体验收;ZMODEM 双向 e2e) |
| M7 打包分发(MSI+NSIS+自动更新) | ✅(v0.7.0 已发布 Release) |
M6 实施要点(已定):广播输入=多会话同步键入(选中会话集合,输入写全部);ZMODEM=渲染层检测 ZRQINIT/ZRINIT 触发文件对话框+rz/sz 命令注入;快捷输入面板=右下浮层(命令输入+快捷命令+最近命令);快捷键=globalShortcut+窗口内(Ctrl+加减字号、Ctrl+PgUp/PgDn 切换终端)。
## M6/M7 实现要点(已落地)
M7 实施要点:electron-builder nsis;node-pty 用 @lydell 预编译免 rebuild;自动更新 electron-updater。
- **广播输入**:渲染层 zustand(broadcastStore)维护 enabled/targets/sessions;TerminalView 全部写路径(onData/补全/粘贴/Workspace runCommand)走 writeBroadcast 扇出;目标 <2 自动禁用;tab 目标圆点 + 按钮计数徽标
- **ZMODEM**:主进程引擎(src/main/zmodem.ts,仅 SSH 会话;本地 pty 走 ConPTY 只给 UTF-8 字符串,二进制会损坏——不支持,注释已说明);Sentry 常驻分流非 zmodem 字节;offer→渲染层选文件/目录→respond;传输期抑制 PTY_DATA/replay/日志并丢弃用户键入;offer 120s/传输 90s 看门狗;进度复用 TransferPanel(kind=zmodem-upload/download);测试 tests/zmodem-e2e.mjs 用第二个 zmodem.js Sentry 模拟远端,双向内容一致性断言
- **快捷输入面板**:QuickInputPanel 右下 fixed 浮层(bottom:44 避让 TransferPanel),发送经 writeBroadcast(广播感知),列表打开沿刷新
- **快捷键**:Ctrl+=/-/0 字号(main.tsx capture 监听,xterm-helper-textarea 放行——隐藏 textarea 曾被误判为输入框导致终端聚焦时失效,已修);globalShowHide accelerator(globalShortcuts.ts,设置页系统分区可配,注册失败仅 warn);Ctrl+PgUp/PgDn 面板循环(Workspace capture 监听)
- **打包**:electron-builder.yml(msi 固定 upgradeCode 5ab9f79e-e4eb-4052-9df6-3af3a301ab0a + nsis;asarUnpack @lydell/node-pty + ssh2;npmRebuild false);updater.ts(仅 packaged 启用,OT_UPDATE_URL/OT_UPDATE_TOKEN env,默认 feed=上述 generic package 地址)
## 发布流程(下一版本照抄)
1. package.json version 升位 → `npm run dist`(env:ELECTRON_MIRROR + ELECTRON_BUILDER_BINARIES_MIRROR=npmmirror;dist:dir 后先删 release/win-unpacked 避免占用 EPERM)
2. `git tag vX.Y.Z && git push origin main vX.Y.Z`
3. Gitea API 建发布:POST /api/v1/repos/admin/OpenTerminal/releases(中文 body 必须走 UTF-8 文件 --data-binary @file,shell 内联会坏)
4. 附件:POST .../releases/{id}/assets?name=(msi/exe/blockmap/latest.yml,实测 141MB 可传)
5. 更新通道:DELETE .../api/packages/admin/generic/openterminal-update/stable(旧版)→ PUT 同 URL 依次上传 latest.yml / exe.blockmap / exe
6. 校验:curl 无 token 拉 latest.yml 应 200 且 version 正确
## 测试(全部通过,改动后必跑)
@@ -35,28 +49,33 @@ npx esbuild src/main/pty.ts --bundle --platform=node --format=cjs --outfile=test
node tests/sysinfo-e2e.mjs
npx esbuild tests/hl-split-smoke.mjs --bundle --platform=node --format=cjs --outfile=tests/.hl-split-smoke.cjs && node tests/.hl-split-smoke.cjs
node tests/commands-store.mjs
# 真实服务器测试(需 JD 环境变量凭据):
node tests/zmodem-e2e.mjs
# 真实服务器测试(需 JD 环境变量凭据,旧凭据已过期):
# JD_HOST=... JD_USER=root JD_PASS=... node tests/sftp-real.mjs / tests/sftp-chmod.mjs
# 打包:npm run dist(产物 release/)
```
## 关键架构与已踩坑(勿重蹈)
1. **主进程 = NestJS 式注入**:pty.ts 的 sessions Map(local/ssh 统一数据面);sysinfo/sftp/日志均经 provider/configure 注入,保持 ssh.ts/commands.ts 无 electron 依赖
2. **JD 云服务器三个怪癖**:① SFTP SETSTAT 被静默忽略 → chmod/chown 走 SSH exec;② SFTP 写 ACK 惰性 → 传输用窗口化流水线 + close 兜底(见 sftp.ts 注释);③ 每连接仅允许一个 SFTP 子系统通道(第二个 open 永不响应)→ 传输复用缓存的元数据通道
3. **esbuild CJS bundle 会让 ssh2 fastPut 完成回调不触发**(数据实际完整到达)→ 测试用 ESM bundle 或 stat 轮询完成检测;真实应用是 rollup,未复现
4. **antd Modal 必须包在 `<App>`+`<ConfigProvider darkAlgorithm>` 内**(App.useApp 上下文),且 `.ant-app` 需显式 height:100%(高度链曾断裂)
5. **xterm 清理**:onData/onSelectionChange 返回 IDisposable 对象不可当函数调用(曾致整窗崩溃);终端卸载必须 dispose
6. **高亮引擎**:写入前 ANSI 注入;跨块用 HighlightStream carry-over(转义序列从不参与匹配);完成检测见 src/main/sftp.ts
7. **JD 服务器测试凭据**:用户临时提供过(36.151.147.123 root)——已过期勿用,凭据一律走环境变量且不落盘
1. **主进程 = 注入式**:pty.ts 的 sessions Map(local/ssh 统一数据面);sysinfo/sftp/zmodem/日志均经 provider/configure 注入,保持 ssh.ts/commands.ts/zmodem.ts 无 electron 依赖
2. **JD 云服务器三个怪癖**:① SFTP SETSTAT 被静默忽略 → chmod/chown 走 SSH exec;② SFTP 写 ACK 惰性 → 窗口化流水线 + close 兜底;③ 每连接仅一个 SFTP 子系统通道 → 传输复用缓存通道
3. **esbuild CJS bundle 会让 ssh2 fastPut 回调不触发**(数据实际到达)→ 测试用 stat 轮询;真实应用 rollup 未复现
4. **antd Modal 必须包在 `<App>`+darkAlgorithm 内**,`.ant-app` 需 height:100%(高度链)
5. **xterm 清理**:IDisposable 只能 .dispose(),不可当函数调用
6. **zmodem.js 0.1.10**:Node 可 require 核心(Sentry/Session);`on_input` 交付的是普通 Array 非 Uint8Array(需防御转换);send_files 在 zmodem_browser.js:58(FileReader 版,已移植 fs 版)
7. **MSI 无图标会链接失败**(WiX LGHT0094:Shortcut 引用不存在的 Icon)→ electron-builder.yml 已设 msi createDesktop/StartMenuShortcut:false;补 build/icon.ico 后可恢复
8. **electron-updater 不支持 MSI 自动更新** → 更新通道走 NSIS exe;MSI 仅分发
9. **命令库测试时间戳竞态**:saveLibraryItem 连续保存同一毫秒 createdAt 相同排序不稳 → 测试保存间 wait(2)
10. **JD 服务器测试凭据已过期**;凭据一律环境变量且不落盘
## 编排约定(本会话确立)
## 编排约定
- 主代理:契约先行 → 并行派遣子代理(每个带自审清单)→ 集成验收(typecheck/build/测试/UI 截图)→ 提交推送
- **新增:code-review 专用子代理**——后续每个里程碑在"子代理自审"与"主代理集成验收"之间插入 code-review 代理审查环节
- 主代理额度紧张时:契约与验收保持主代理,实现全部下沉子代理
- 主代理:契约先行 → 并行派遣子代理(每个带自审清单)→ **code-review 子代理** → 主代理集成验收(typecheck/build/测试/真实打包/UI 活体验证)→ 提交推送 + tag
- 主代理额度紧张时:契约与验收保持主代理,实现全部下沉子代理;GUI 验收(computer-use)必须主代理亲自做
- 自动化差异备忘:antd Popover 触发按钮与 portal 内按钮对 AXPress 不响应(真实鼠标点击正常)——验收一律用 event 策略坐标点击 + 精确 bounds
## 待办(按优先级)
1. M6 里程碑(见上要点)
2. M7 打包
3. 小项:autoWrap=false 固定列宽、OSC 标题跟随、内置 OFL 字体打包、WebGL 终端数上限降级、i18n(中英切换,需文案抽取重构)
1. 应用图标(build/icon.ico)——MSI 快捷方式随图标恢复
2. 用户实测项:Ctrl+PgUp/PgDn 真实键盘(合成键盘无法验证修饰键)、真实服务器 rz/sz 一轮、全局唤起快捷键
3. 小项:autoWrap=false 固定列宽、OSC 标题跟随、内置 OFL 字体打包、WebGL 终端数上限降级、i18n(中英切换)、最近命令历史出现两条命令拼接的记录(广播键入时行捕获合并,低优先级修)