目标:在上游最新架构(分支
feat/et-history-reapply,基于031bf0ee)上, 完全照搬 Mosh 的方式重新集成 EternalTerminal:
- 打包客户端 —— 像
mosh-client那样,把et客户端二进制构建 + 下载 + 捆绑进安装包,运行时只用捆绑的二进制(不依赖系统安装的 et)。- 接入协议 —— 把旧分支
feat/eternal-terminal(tip67e81616)里的 ET 后端 + UI 重新落到上游重构后的目录结构上,并让它启动捆绑的et。旧实现参考:
git show 67e81616(共 7 个 ET 提交,见feat/eternal-terminal)。 Mosh 模板参考:resources/mosh/README.md、scripts/*mosh*、electron/bridges/terminalBridge/moshSession.cjs、.github/workflows/build-mosh-binaries.yml。
- 协议:Mosh 需要 Node 重写 Perl 包装器(SSH bootstrap + 抓
MOSH CONNECT+ 换 PTY)。ET 不需要 ——et客户端自己完成 SSH 引导 + 协议握手,我们只要 把et当作普通 PTY 进程pty.spawn即可。所以没有etHandshake.cjs。 - 凭证注入:Mosh 自己驱动 ssh、直接往 PTY 里敲密码;ET 内部驱动 ssh,需用
SSH_ASKPASS + 临时 ~/.ssh 环境把保存的密码/密钥/跳板/算法喂给 et 内部的 ssh
(旧实现
prepareEtSshEnvironment已完整实现,直接搬运)。 - terminfo:
et是纯传输客户端、本地不渲染终端,无需 捆绑 terminfo (Mosh 因静态 ncurses 才需要)。打包目录里只放et[.exe](+ Windows DLL)。 - 构建系统:Mosh 用 autotools;ET 用 CMake + Ninja + vcpkg
(
cmake -DDISABLE_TELEMETRY=ON -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo), 产物是单个et(Windowset.exe)。
| Mosh | ET |
|---|---|
resources/mosh/<plat-arch>/mosh-client[.exe] |
resources/et/<plat-arch>/et[.exe] |
打包后 <Resources>/mosh/mosh-client |
打包后 <Resources>/et/et |
scripts/build-mosh/ |
scripts/build-et/ |
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 / 仓库 Netcatty-mosh-bin / tag mosh-bin-* |
env ET_BIN_RELEASE / 仓库 Netcatty-et-bin / tag et-bin-* |
npm run fetch:mosh[:dev] |
npm run fetch:et[:dev] |
bundledMoshClient() / resolveBareMoshClient() |
bundledEtClient() / resolveBareEtClient() |
.github/workflows/build-mosh-binaries.yml |
.github/workflows/build-et-binaries.yml |
- 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。 校验非系统动态库(同 mosh 的 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 + vcpkgx64-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 目录。去掉 terminfo 分支。 - 1.7
scripts/resolve-et-bin-release.cjs—— 镜像resolve-mosh-bin-release.cjs:TAG_RE=/^et-bin-.../,默认仓库Netcatty-et-bin,envET_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 用自建产物 (ET 官方有 Windows 构建,无需 FluentTerminal 那种 fallback)。去掉 terminfo 校验。 - 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.jsonscripts:新增"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;testglob 已覆盖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—— 镜像build-mosh-binaries.yml:四个构建 job + 一个releasejob(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)。
- 2.1
electron/bridges/terminalBridge.cjs新增bundledEtClient(opts)—— 镜像bundledMoshClient:打包路径<Resources>/et/et[.exe];dev 回退<projectRoot>/resources/et/<plat-arch>/et[.exe];导出到 module.exports。
- 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 目录,复用prependEnvPath思路把 DLL 目录加进 PATH。 - 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 测试并搬运。
- 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内联对象。
- 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 文案结构)。
- 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-tarC:问题、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/IPCnetcatty: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_TOKENsecret。之后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(tip67e81616,7 个 ET 提交)