Files
Netcatty/ET_INTEGRATION_CHECKLIST.md
T
陈大猫 01e7edc006 feat(mosh): integrate MoshCatty pure Rust client (no Cygwin legacy) (#2085)
* feat(mosh): default bundled client to MoshCatty releases

Wire Netcatty packaging and npm run dev to pull pure Rust mosh-client
binaries from binaricat/MoshCatty (moshcatty-* tags), document the cutover,
and mark the old Cygwin Windows fetch path as legacy-only.

* fix(mosh): accept pure MoshCatty packages (exe-only, no dlls/terminfo)

Align fetch/packaging with MoshCatty pure-Rust releases: require only
mosh-client[.exe], treat Cygwin dll bags and terminfo as optional legacy
layout. Document moshcatty-0.1.1 (ConPTY Ctrl+C + static MSVC CRT).

* refactor(mosh): drop Cygwin legacy; MoshCatty-only pipeline

Remove FluentTerminal/mosh-bin fallbacks, build-mosh C++ CI, and
dll/terminfo runtime helpers. Fetch accepts only moshcatty-* pure
binaries; packaging ships a single mosh-client per platform.

* docs: align ET checklist and et README with MoshCatty-only mosh

Update mosh template references after removing Cygwin build pipeline and
legacy fallbacks. Point ET packaging notes at fetch-mosh / MoshCatty
instead of deleted build-mosh-binaries workflow.

* docs(mosh): require MoshCatty 0.1.2+ for Linux glibc floors

Codex review vs main: defaulting to MoshCatty Linux binaries built on
ubuntu-latest required GLIBC 2.34, above Netcatty's package floors
(x64 2.28 / arm64 2.31). Document the floors, prefer moshcatty-0.1.2+,
and drop trailing whitespace in the design note. Upstream MoshCatty
release CI now builds in almalinux:8 / debian:bullseye with assert.

* fix(mosh): reject MoshCatty releases below 0.1.2

Codex re-review: docs alone still allowed MOSH_BIN_RELEASE=moshcatty-0.1.0/0.1.1,
which produce packages that fail to start on Netcatty's Linux glibc floors.
Validate the minimum tag in resolve and fetch, skip pre-0.1.2 when picking
latest, and cover the reject path in unit tests.

* fix(mosh): pin MoshCatty owner and reject floor prereleases

Codex review vs main (P2):
- Always default MOSH_BIN owner/repo to binaricat/MoshCatty; do not
  inherit fork owner from GITHUB_REPOSITORY in resolve or fetch.
- Treat moshcatty-X.Y.Z-rcN as below final X.Y.Z so pins like
  moshcatty-0.1.2-rc1 cannot bypass the glibc floor.

* fix(mosh): accept build metadata in MoshCatty release tags

TAG_RE rejected '+' so moshcatty-0.1.2+build.1 failed validation even
though the version parser and isAtLeastMinRelease accepted it. Align
the regex and require a successful semver parse.
2026-07-10 20:24:24 +08:00

15 KiB
Raw Blame History

EternalTerminal (ET) 集成清单 — 按 Mosh 方式重做

目标:在上游最新架构(分支 feat/et-history-reapply,基于 031bf0ee)上, 完全照搬 Mosh 的方式重新集成 EternalTerminal:

  1. 打包客户端 —— 像 mosh-client 那样,把 et 客户端二进制构建 + 下载 + 捆绑进安装包,运行时只用捆绑的二进制(不依赖系统安装的 et)。
  2. 接入协议 —— 把旧分支 feat/eternal-terminal(tip 67e81616)里的 ET 后端 + UI 重新落到上游重构后的目录结构上,并让它启动捆绑的 et。

旧实现参考:git show 67e81616(共 7 个 ET 提交,见 feat/eternal-terminal)。 Mosh 模板参考(仅 MoshCatty 纯二进制路径):resources/mosh/README.md、 scripts/fetch-mosh-binaries.cjs、scripts/resolve-mosh-bin-release.cjs、 scripts/mosh-extra-resources.cjs、electron/bridges/terminalBridge/moshSession.cjs。 客户端本体在独立仓库 binaricat/MoshCatty (moshcatty-* releases);Netcatty 内已无 Cygwin 构建流水线 / FluentTerminal 回退。

关键设计差异(ET vs Mosh)

  • 协议:Mosh 需要 Node 做 SSH bootstrap + 抓 MOSH CONNECT + 换 PTY (moshHandshake + moshSession)。ET 不需要 —— et 客户端自己完成 SSH 引导 + 协议握手,我们只要把 et 当作普通 PTY 进程 pty.spawn 即可。所以没有 etHandshake.cjs。
  • 凭证注入:Mosh 自己驱动 ssh、直接往 PTY 里敲密码;ET 内部驱动 ssh,需用 SSH_ASKPASS + 临时 ~/.ssh 环境把保存的密码/密钥/跳板/算法喂给 et 内部的 ssh (旧实现 prepareEtSshEnvironment 已完整实现,直接搬运)。
  • 纯二进制:MoshCatty 与理想 ET 打包都是「每平台一个客户端文件」。Mosh 侧已 无 terminfo / Cygwin DLL 袋;et 同样本地不渲染终端。Windows 若动态链 CRT 才考虑可选 DLL 目录,否则只放 et[.exe]。
  • 构建系统:Mosh 客户端在 MoshCatty 仓库用 Rust 构建并发布;Netcatty 只 fetch。ET 用 CMake + Ninja + vcpkg (cmake -DDISABLE_TELEMETRY=ON -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo), 产物是单个 et(Windows et.exe),由 scripts/build-et/ + build-et-binaries.yml 发布。

命名约定(镜像 Mosh / MoshCatty)

Mosh (MoshCatty) ET
resources/mosh/<plat-arch>/mosh-client[.exe] resources/et/<plat-arch>/et[.exe]
打包后 <Resources>/mosh/mosh-client 打包后 <Resources>/et/et
上游构建:binaricat/MoshCatty CI releases scripts/build-et/ + build-et-binaries.yml
scripts/fetch-mosh-binaries.cjs scripts/fetch-et-binaries.cjs
scripts/resolve-mosh-bin-release.cjs scripts/resolve-et-bin-release.cjs
scripts/mosh-extra-resources.cjs scripts/et-extra-resources.cjs
env MOSH_BIN_RELEASE / 仓库 MoshCatty / tag moshcatty-* env ET_BIN_RELEASE / 仓库 Netcatty-et-bin / tag et-bin-*
npm run fetch:mosh[:dev] npm run fetch:et[:dev]
bundledMoshClient() / resolveBareMoshClient() bundledEtClient() / resolveBareEtClient()

Phase 1 — 打包基础设施(构建/下载/捆绑)

  • 1.1 resources/et/README.md —— 镜像 resources/mosh/README.md:说明 二进制来源、Netcatty-et-bin 发布仓库、et-bin-* tag、许可证(ET 为 Apache-2.0,与 GPL-3.0 兼容)、可复现构建命令。
  • 1.2 .gitignore —— 追加 ET 段(镜像 mosh 段): /resources/et/*/et、/resources/et/*/et.exe、/resources/et/*/*.dll、 /resources/et/*/et-win32-*-dlls/。保留 resources/et/README.md。
  • 1.3 scripts/build-et/build-linux.sh —— manylinux2014 + vcpkg 静态三元组 构建 et(x64/arm64),产物 et-linux-<arch>.tar.gz(+.sha256),内含单个 et。 校验非系统动态库(ldd 白名单)。
  • 1.4 scripts/build-et/build-macos.sh —— arm64 + x86_64 分别构建后 lipo 成 universal,MACOSX_DEPLOYMENT_TARGET=11.0,产物 et-darwin-universal.tar.gz。
  • 1.5 scripts/build-et/build-windows.ps1(或 .sh)—— MSVC + vcpkg x64-windows-static,产物 et-win32-x64.tar.gz(含 et.exe;若动态链接 CRT 则随附 DLL 目录 et-win32-x64-dlls/,否则纯静态无 DLL)。
  • 1.6 scripts/et-extra-resources.cjs —— 镜像 mosh-extra-resources.cjs: 按平台/arch 仅当 resources/et/<plat-arch>/et[.exe] 存在时才产出 extraResources 指令(to: "et/");Windows 额外处理可选 DLL 目录。纯客户端文件为主。
  • 1.7 scripts/resolve-et-bin-release.cjs —— 镜像 resolve-mosh-bin-release.cjs: TAG_RE=/^et-bin-.../,默认仓库 Netcatty-et-bin,env ET_BIN_RELEASE 优先。
  • 1.8 scripts/fetch-et-binaries.cjs —— 镜像 fetch-mosh-binaries.cjs: TARGETS 四项(linux-x64/arm64、darwin-universal、win32-x64),全部 tar.gz; SHA256SUMS 校验;解包到 resources/et/<plat-arch>/。Windows 用自建产物。
  • 1.9 单元测试:scripts/fetch-et-binaries.test.cjs、 scripts/resolve-et-bin-release.test.cjs、scripts/et-extra-resources.test.cjs (镜像对应 mosh 测试,改名/改路径)。
  • 1.10 package.json scripts:新增 "fetch:et": "node scripts/fetch-et-binaries.cjs"、 "fetch:et:dev": "node scripts/fetch-et-binaries.cjs --host --resolve-release"; 把 dev 脚本改成先 fetch:mosh:dev && fetch:et:dev;test glob 已覆盖 scripts/*.test.cjs(确认即可)。
  • 1.11 electron-builder.config.cjs:引入 etExtraResources,在 darwin/win32/ linux 三处把 etExtraResources(plat) 合并进 extraResources(与 mosh 数组拼接)。
  • 1.12 .github/workflows/build-et-binaries.yml —— 四个构建 job + 一个 release job(dispatch 且 release_tag 非空时发布到 Netcatty-et-bin,附 SHA256SUMS)。paths 过滤指向 scripts/build-et/**、scripts/fetch-et-binaries.cjs、 scripts/et-extra-resources.cjs。env 用 ET_REF(默认 ET release tag,如 et-v6.2.x)。 > 注:实际二进制由用户手动 workflow_dispatch 触发产出;本地/CI 未设 > ET_BIN_RELEASE 时 fetch 步骤安静跳过(同 mosh 的 MOSH_BIN_RELEASE)。

Phase 2 — 运行时定位捆绑客户端

  • 2.1 electron/bridges/terminalBridge.cjs 新增 bundledEtClient(opts) —— 镜像 bundledMoshClient:打包路径 <Resources>/et/et[.exe];dev 回退 <projectRoot>/resources/et/<plat-arch>/et[.exe];导出到 module.exports。

Phase 3 — ET 协议后端(搬运旧实现到新架构)

  • 3.1 新建 electron/bridges/terminalBridge/etSession.cjs —— 用上游 moshSession.cjs 的 createXxxSessionApi(ctx) + with(ctx) 工厂模式,封装: ET_ASKPASS_SCRIPT、writeSecureFile、prepareEtSshEnvironment、 createEtAskpassArtifacts、cleanupStaleEtTempDirs、 cleanupSessionExternalAuthArtifacts、execOnEtSession、startEtSession。 改动点:etCmd 由 findExecutable('et') 改为 resolveBareEtClient() (取捆绑二进制);找不到时抛错(同 mosh:提示跑 npm run fetch:et:dev)。 Windows 若有动态链接 DLL 目录,可把该目录加进 PATH(MoshCatty 路径已无此需求)。
  • 3.2 terminalBridge.cjs 接线 createEtSessionApi(ctx)(镜像 moshSessionApi 的 ctx),传入 bundledEtClient、tempDirBridge、execFile/execFileSync 等; 解构出 startEtSession、execOnEtSession、cleanupStaleEtTempDirs、 cleanupSessionExternalAuthArtifacts、resolveBareEtClient。
  • 3.3 init() 调 cleanupStaleEtTempDirs();registerHandlers 加 ipcMain.handle("netcatty:et:start", startEtSession);closeSession 与 cleanupAllSessions 调 cleanupSessionExternalAuthArtifacts(session); module.exports 导出 startEtSession、execOnEtSession、bundledEtClient。
  • 3.4 测试:terminalBridge.bundledEt.test.cjs(路径解析)+ terminalBridge/etSession.test.cjs(prepareEtSshEnvironment 的端口/密钥/ askpass/跳板/legacy 算法分支)。可参考旧分支是否已有 ET 测试并搬运。

Phase 4 — domain / 类型 / preload 接口面

  • 4.1 domain/models.ts:HostProtocol 加 'et';ProtocolConfig.etPort?; Host/GroupConfig 加 etEnabled?/etPort?/etTerminalPath?; TerminalSession.etEnabled?;ConnectionLog.protocol 加 'et'。 (照搬 git show 794eecdf -- domain/models.ts)
  • 4.2 domain/groupConfig.ts:加 etEnabled 默认项(照搬旧 diff)。
  • 4.3 global.d.ts:NetcattyBridge 加 startEtSession?(options): Promise<...> 及相关 options 类型(照搬 git show 794eecdf -- global.d.ts,并补齐后续 ET 提交 新增的 etPort/terminalPath/jumpHosts/legacyAlgorithms 字段)。
  • 4.4 electron/preload/api.cjs:加 startEtSession(镜像第 26 行的 startMoshSession)→ ipcRenderer.invoke("netcatty:et:start", options)。 注意:上游已把 preload 重构成 createPreloadApi,落点在 preload/api.cjs, 不是旧的 preload.cjs 内联对象。

Phase 5 — 渲染层 + UI + i18n

  • 5.1 application/state/useTerminalBackend.ts:加 etAvailable(查 bridge?.startEtSession)+ startEtSession,并在返回对象/依赖数组里登记 (镜像 mosh 的第 10/42/198/205 行处)。
  • 5.2 application/state/useSessionState.ts:路由 ET 会话(照搬旧 diff,+6 行)。
  • 5.3 components/terminal/runtime/createTerminalSessionStarters.ts:加 startEt(term)(镜像 startMosh,组装 options:etPort/terminalPath/ jumpHosts/legacyAlgorithms/凭证/identityFilePaths)。 注意:上游把它从旧的 infrastructure/runtime/ 移到了 components/terminal/runtime/ —— 落点以上游为准。
  • 5.4 UI 组件(照搬 git show b1a306f8 6c0d5bf3 55caa268 的相应文件, 映射到上游同名组件): - [ ] components/ProtocolSelectDialog.tsx —— 新增 ET 选项 - [ ] components/QuickConnectWizard.tsx - [ ] components/HostDetailsPanel.tsx —— ET 设置(启用、ET 端口、etterminal 路径) - [ ] components/GroupDetailsPanel.tsx - [ ] components/VaultView.tsx - [ ] components/Terminal.tsx / components/TerminalLayer.tsx - [ ] components/terminal/TerminalConnectionDialog.tsx / TerminalToolbar.tsx - [ ] App.tsx
  • 5.5 i18n:application/i18n/locales/en.ts 与 zh-CN.ts 加 ET 文案 (照搬旧 diff,键名对齐上游现有 mosh 文案结构)。

Phase 6 — 校验

  • 6.1 npm run lint(确保新 .cjs 在 scripts/ 下不受 ESLint 限制, 或按需加 eslint-disable,与 mosh 脚本一致)。
  • 6.2 npm test(新增的 fetch/resolve/extra-resources/etSession 测试全绿)。
  • 6.3 npm run build(渲染层 TS 编译通过,无类型错误)。
  • 6.4 手动冒烟(需先有发布的二进制): ET_BIN_RELEASE=et-bin-... npm run fetch:et → npm run start → 新建 ET 会话连一台装了 etserver 的主机,验证连接/输入/退出/凭证注入。

进度记录

  • 状态:Phase 1–5 已完成并通过校验(仅余 1 个可选项 + CI 产二进制)
  • 验证结果:
    • npx eslint <所有改动文件> → 干净(0 错 0 警)
    • npx tsc --noEmit → 我的改动 0 个新增类型错误 (TerminalConnectionDialog 里 case 'mosh' 的 TS2678 是既有问题,行号因我插入 ET 早返回从 60→64,非新增)
    • node --test(ET 相关)→ etSession/bundledEt/3 个脚本测试 全绿
    • npm test → 1383 通过 / 16 失败,16 个全是既有的 Windows 环境失败 (mosh 打包测试的 GNU-tar C: 问题、isExecutableFile 无 x 位、ACP execPath、SKILL.md 权限、Comware DH 等;均在我未改动的文件里)
    • npm run build(Vite)→ 构建成功(8.55s),渲染层打包通过

已完成

  • Phase 1:scripts/et-extra-resources.cjs / resolve-et-bin-release.cjs / fetch-et-binaries.cjs(+3 测试,27 通过)、scripts/build-et/{build-linux.sh, build-macos.sh,build-windows.ps1}、.github/workflows/build-et-binaries.yml、 resources/et/README.md、.gitignore、package.json、electron-builder.config.cjs。
  • Phase 2:terminalBridge.cjs 新增并导出 bundledEtClient。
  • Phase 3:terminalBridge/etSession.cjs(startEtSession + prepareEtSshEnvironment + SSH_ASKPASS 机制 + execOnEtSession + 清理),接线进 terminalBridge.cjs(ctx/IPC netcatty:et:start/init 清理/close/quit 清理/导出),+2 测试(13 通过)。 et 指向捆绑二进制(resolveBareEtClient→bundledEtClient),找不到则报错。
  • Phase 4:domain connection.ts/history.ts/terminal.ts、groupConfig.ts、 types/global/netcatty-bridge-session.d.ts(startEtSession + NetcattyJumpHost[])、 electron/preload/api.cjs、domain/vaultImport.ts(排除 'et' 导入协议)。
  • Phase 5:
    • 启动派发:useTerminalEffects.ts、Terminal.tsx(×3) → startEt
    • 运行时 starter:createTerminalSessionStarters.ts 新增 startEt(含单跳板/凭证/ legacy 算法/askpass 路径),.types.ts 加 etAvailable/startEtSession
    • 后端 hook:useTerminalBackend.ts(etAvailable + startEtSession)
    • 会话透传 etEnabled:sessionFactories.ts、useSessionState.ts(×6)、 TerminalLayer.tsx(×3)、TerminalLayerSupport.tsx、AppHandlers.ts(协议解析/日志/选择)
    • UI:HostDetailsAdvancedSections.tsx(ET 开关+端口+etterminal 路径,与 Mosh 互斥)、 HostDetailsPanel.tsx、ProtocolSelectDialog.tsx(ET 选项)、 TerminalConnectionDialog.tsx(ET 标签)、TerminalToolbar.tsx(编码菜单门控)、 GroupSshSettingsSection.tsx + GroupDetailsPanel.tsx(组级 ET)、VaultView.tsx
    • i18n:en/zh-CN 的 hostDetails.section.et、hostDetails.et.*、 terminal.connection.protocol.et、terminal.et.*

剩余(可选 / 非阻塞)

  • QuickConnectWizard.tsx:把 ET 加为“快速连接”协议按钮(type/端口/建主机映射 + UI 按钮)。当前快速连接未列 ET;保存主机后开启 ET 再连即可,故仅为便利项。

  • 产出二进制:手动 workflow_dispatch 跑 build-et-binaries.yml(带 release_tag=et-bin-<ver>-1)发布到 Netcatty-et-bin,并配 ET_BIN_RELEASE_TOKEN secret。之后 ET_BIN_RELEASE=... npm run fetch:et 即可本地/打包捆绑 et。 build-et 脚本本机无法编译 C++,需在 CI 验证。

  • 端到端冒烟:有二进制后 npm run dev,对装有 etserver 的主机建 ET 会话验证。

  • 当前分支:feat/et-history-reapply(基于上游 031bf0ee)

  • 旧 ET 实现参考分支:feat/eternal-terminal(tip 67e81616,7 个 ET 提交)