Files
opsxshell/AGENTS.md
T

7.2 KiB
Raw Blame History

OpsXShell 开发指南

OpsXShell 是基于 Tauri 2、Rust、React 和 TypeScript 的轻量运维终端。产品强调便捷、人性化、操作简单实用,不加入审计、审批或堡垒机功能。

架构

  • src/:React 界面、Zustand 状态和 XTerm.js 终端。
  • src/i18n/:界面文案(zh-CN / zh-TW / en / ja / ko / vi / ru);新增可见字符串必须同步全部语种,并用 test/i18n/localeKeys.test.ts 校验 key 对齐。
  • src/platform/:唯一的 Tauri 命令与事件适配入口。
  • src/platform/sftp.ts:固定 localPath/remotePath 方向,区分远程文本读写与文件传输。
  • src/platform/rdp.ts / src/platform/vnc.ts:远程桌面会话适配;运行态只在原生侧内存中。
  • src/utils/terminalPipeline.ts:终端输入、UTF-8 输出、背压和错误边界。
  • src-tauri/src/commands/:精简命令边界和统一响应。
  • src-tauri/src/services/:SSH、SFTP、隧道、PTY、串口、桌面、存储和凭据服务。转发 Listener 必须由 TunnelManager 统一持有和取消。
  • src-tauri/src/services/ssh/:认证、known_hosts、代理/跳板、路径和 SFTP,禁止重新堆回 ssh.rs。
  • src-tauri/src/services/tunnel/:运行模型、SOCKS5 协议和 Relay;运行态只能由 TunnelManager 持有。
  • src-tauri/src/services/desktop/:RDP(IronRDP)与 VNC(vnc-rs);帧、输入、剪贴板经 Tauri 事件交给 Canvas,断开即取消 worker。RDP 批量压缩优先 RDP5(MPPC/K64),避免 XCRUSH 在分辨率切换后解压失败。
  • shared/types/:渲染层共享 TypeScript 契约。
  • test/:Vitest 单元/组件测试与基础巡检(test/patrol/:SSH / SFTP / RDP / VNC);改功能后优先 npm run test:patrol。
  • scripts/:本地启动、验收、版本同步与原生安装包构建/发布脚本(入口 ./run.sh、./scripts/build.sh)。
  • docs/:使用、架构、验收与发布文档;路线图与任务见根目录 ROADMAP.md / TASKS.md / TDD_PLAN.md。

React 不直接访问 SSH、文件系统或加密实现。数据流:UI → Zustand → src/platform/* → Tauri command → src-tauri 服务。新增原生能力时先定义 Rust command,再更新 src/desktop.d.ts、对应 src/platform/*.ts 和 test/setup.ts。

怎么扩展

  1. 领域契约:先改 shared/types/ 或 Rust domain,再改 command。
  2. 原生实现:能力放 src-tauri/src/services/,command 只做参数边界和统一响应。
  3. 渲染适配:只经 src/platform/;组件和 store 不直接 invoke。
  4. 界面:Zustand 持有资源 ID 与 UI 状态;可见文案同步七语种。
  5. 测试:功能改动优先 npm run test:patrol,再补对应单测。

IPC 响应约定

  • 业务失败(SSH / SFTP / 转发 / 会话 CRUD / 本地文件)使用信封 { success, error, errorCode? }。errorCode 是稳定点分路径(如 native.taskJoin),前端用 translateIpcError 映射 errors:*。
  • RDP / VNC 运行态(connect / input / clipboard)走 throw;在桌面视图 catch。
  • 禁止第三种失败形态。组件和 store 不直接 invoke,只经 src/platform/(invokeNative / invokeEnvelope)。
  • 同步对话框 command(show_open_dialog / show_save_dialog)必须在主线程调用,不得 spawn_blocking(macOS 保存框依赖主线程)。磁盘 I/O 走 spawn_blocking。

规则

  • 未由 Rust 后端实现的能力不能在界面中显示为可用。
  • 会话密码、私钥口令和代理密码必须由 Rust 加密后落盘。
  • 不保存终端命令历史;批量命令结果仅保留在当前窗口。
  • 主机密钥使用 ~/.ssh/known_hosts 校验。
  • 主密钥位于 ~/.opsxshell/master.key,Unix 目录权限 0700、文件权限 0600。
  • 保持常用流程简短,高级配置默认收起。
  • 端口转发规则可持久化,运行中状态不得持久化;界面的停止操作必须关闭真实原生 Listener。
  • 复制转发规则不得复制运行态;运行中的规则修改前必须先停止 Listener。
  • SSH 断开 / keepalive 失败 / 空闲挂起 / 同窗重连:未点「停止」的转发 Listener 应保留;按 user@host:port 指纹 orphan-adopt;同窗用进程内 forwardIntent 自动恢复;关标签不得自动再启。空闲挂起应先断开原生会话并 retainForwards,避免僵尸 TCP。
  • SSH 标签还开着时:协议心跳保链路(不写入 Shell,不对抗 TMOUT);意外断开有限次自动重连(新 PTY)。远端空闲退出只提示重开该分屏。不要默认向 Shell 发送回车/空格。长任务用远端 tmux/screen。
  • 活跃 SFTP 标签同样有限次自动重连并恢复上次远程目录。
  • RDP/VNC 标签还开着时意外断开有限次自动重连;不发送假鼠标对抗空闲 GPO。断开即取消本地 worker,重连是新会话。
  • 动态转发(SOCKS5)默认仅本机 127.0.0.1:1080;流量经当前 SSH 服务器出口 IP 访问外网。每台 SSH 主机仅保留一条动态规则。状态栏「转发」打开抽屉管理,右键复制 socks5://127.0.0.1:1080。
  • 本地转发监听默认本机端口;远程转发监听默认远端 127.0.0.1。远程 0.0.0.0 需 sshd GatewayPorts,未开启时常静默只绑 loopback。
  • SFTP read/write 不得作为 upload/download 的别名,本地路径与远程路径不得使用位置含糊的调用。
  • RDP / VNC 仅在 Tauri 原生应用中可用;会话运行态不落盘,断开即清理。批量命令排除桌面会话。
  • 大模型新配置必须先用临时凭据完成真实测试,测试期间不得写 settings 或 secrets;连接字段变化后保存必须重新锁定。
  • AI 远程执行只能复用当前活跃 SSH connection;按 strict/relaxed(严格/宽松)模式决定确认阈值,critical 始终硬拒绝;不建立独立 podexec/Kubernetes 凭据边界,也不保存命令或工具输出。
  • ssh:// 禁止携带密码或静默直连;冷启动与运行中唤起都必须通过原生有界队列交付给快速连接确认。

命令

./run.sh                 # 开发启动(scripts/run.sh)
npm run test:patrol
npm run acceptance:quick
npm run acceptance:full
./scripts/build.sh       # 当前平台安装包(macOS → Tauri .app + .dmg)
./scripts/macos-notarize.sh  # 新 DMG 的 Apple 公证 + staple

平台安装包必须在目标系统实机验收。没有签名凭据时不得宣称完成签名、公证或自动更新发布。macOS 有 Developer ID 时:仓库默认 signingIdentity 仍是 "-";本机把身份写进 gitignore 的 src-tauri/tauri.signing.conf.json,build.sh 会自动带上,并走 bundle.macOS.dmg 的 Tauri 窗口布局。新打的 DMG 必须再跑 macos-notarize.sh 才能给别人直接打开。

评审边界

  • src/platform/ 与 Tauri command 是本应用内部边界,不是给第三方调用的公共 API。
  • 结账与在线授权由独立的 opsx-licence 服务承担;不要把结账/签发逻辑堆回桌面进程。桌面端只验 LIC-(在线)和 LICOFF-(离线 Ed25519)。
  • 不把 CLI、MCP、插件宿主或堡垒机审批做成默认能力。
  • 转发 Listener、SSH 会话、RDP/VNC worker 的运行态只在原生侧内存;评审时以「停止是否关掉真实资源」为准。