feat: add web deployment support
This commit is contained in:
1 parent
15922a5605
commit
5d1df9e237
238 files changed
+23777
-8879
No files matched your search
@@ -0,0 +1,115 @@
|
||||
# Web / Desktop 实现与验收报告
|
||||
|
||||
## 源码审查与边界
|
||||
|
||||
实际入口为 `src/main.tsx`,主窗口复用 `AppProvider`、`PluginProvider` 和 `App.tsx`,子页面复用 `ChildAppProvider` / `ChildWindowRouter`。原来的 `src/lib/invoke.ts` 是主要业务调用入口,但会话工厂、日志、事件、窗口、文件和设置代码也存在直接 Tauri 调用。本次将这些调用转到 `src/lib/backend`;没有新增第二套 React 应用或替换现有 workspace/state 模型。
|
||||
|
||||
Desktop 的 `cmd/session.rs` 在进入 `core/ssh/session.rs` 前处理连接解析、认证提示、录制和 ownership。`core/ssh/{client,auth,io}.rs` 包含 Tauri state/event 依赖,以及 OSC、录制、Zmodem、命令捕获等原生逻辑,继续留在 Desktop。SFTP 使用同一 russh 连接和 vendored russh-sftp。配置/存储/加密中的 AppHandle 原来主要是接口参数,适合抽到共享库。AI provider、模型选择、流式解析、prompt/redaction/history 同样抽到共享库;Desktop 的 Agent 执行、审批和原生集成保留。
|
||||
|
||||
参考了 `temp/dbx/crates/dbx-web` 的 Core/HTTP/SSE/静态资源分离、限额和 base path 设计;没有复制 DBX 源码或引入其依赖。
|
||||
|
||||
## 已实现架构
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
UI[现有 React / xterm / Providers] --> API[backend API / capability / platform]
|
||||
API --> D[Tauri invoke / event]
|
||||
API --> W[HTTP JSON / WS / SSE]
|
||||
D --> DC[原有 Tauri commands / SessionManager]
|
||||
W --> WC[Axum routes / owned WebSession]
|
||||
DC --> C[nyaterm-core]
|
||||
WC --> C
|
||||
C --> P[共享 config / redb / crypto / SSH协议 / SFTP工具 / AI]
|
||||
DC --> N[Desktop 原生 I/O / PTY / 录制 / Zmodem等]
|
||||
```
|
||||
|
||||
Core 和 Web 是两个独立 Cargo crate;Desktop 以 path dependency 引用 Core。没有把 vendored russh 纳入新的顶层 workspace,避免其已有 workspace dependency 解析冲突。
|
||||
|
||||
共享范围包括配置类型与迁移、redb 文档、AES-GCM/主密码密钥层次、历史工具、SSH 算法/连接/密码和交互认证/通道回复/输入/resize、SFTP 初始化及原有文件属性/文本冲突工具、私钥校验和公钥派生、AI provider/model/catalog/prompt/redaction/parser/stream/history。Web 专属的会话 ownership、cookie、认证提示、HTTP 文件流和生命周期留在 Web crate。Desktop 和 Web 的会话调度循环不同,因为 Desktop 仍提供原生附加能力;没有复制原生 SSH/SFTP 全栈。
|
||||
|
||||
## 新增与修改文件
|
||||
|
||||
| 文件/目录 | 实际作用 |
|
||||
| -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
||||
| `src/lib/backend/{api,tauri,http,runtime,events}.ts` | 同类型 invoke/listen/emit,运行时选择、集中能力、同源 URL、WS 和 SSE。 |
|
||||
| `src/lib/backend/platform/{app,window,webviewWindow,webview,path,dialog,opener}.ts` | Desktop 转发原 API;浏览器替代或拒绝原生操作。 |
|
||||
| `src/lib/backend/{BrowserGate.tsx,files.ts,web.test.tsx}` | 登录入口、浏览器 File 上传/下载和边界测试。 |
|
||||
| `src/main.tsx`、`src/lib/{invoke,windowManager,appSessionFactory,appWorkspace,...}` | 接入边界,复用现有页面、状态和子窗口流程。 |
|
||||
| 现有 providers/hooks、terminal/SFTP/AI/设置/连接/插件组件 | 替换原生 imports,依据集中 capability 隐藏/禁用能力。四种 locale 增加 Web 登录文本。 |
|
||||
| `src-tauri/crates/nyaterm-core/src/{config,storage,utils,core/ai,core/history,ssh,services.rs}` | 从原有文件移动共享逻辑,新增通用协议与服务边界。 |
|
||||
| `src-tauri/src/{config,storage,utils,core/ai,core/history,core/sftp/util.rs,...}` | 原位置使用 re-export/wrapper,保留 Desktop 调用兼容性。文件删除对应迁入 Core,非删除桌面功能。 |
|
||||
| `src-tauri/src/{cmd/connection.rs,cmd/ai.rs,core/ssh,core/sftp/sftp_backend/session.rs}` | 调用共享服务与协议;原生管理器继续保留。 |
|
||||
| `src-tauri/crates/nyaterm-web/src/{main,lib,auth,state,session,commands,sftp,ai,plugins,error}.rs` | 独立服务、显式命令 allowlist、会话和资源清理。 |
|
||||
| `src-tauri/crates/nyaterm-web/tests/{transport,bootstrap}.rs` | 真正 russh/SFTP fixture 与进程启动测试。 |
|
||||
| 各 crate Cargo.toml/Cargo.lock、`package.json`、`vite.config.ts` | 依赖、构建入口和 base path。 |
|
||||
| `Dockerfile`、`.dockerignore`、`compose.web.yml`、`.gitignore` | 三阶段非 root 容器、持久 volume、构建上下文/秘密排除。 |
|
||||
| `docs/web-deployment.md`、本文 | 操作步骤、能力、安全边界和验证报告。 |
|
||||
|
||||
原生 imports 只在 transport/platform 边界及被 capability 隔离的 RDP/VNC Channel、updater 和 native PluginPanel 资源转换中保留。不会在 Web startup 创建原生 Channel 或加载原生插件。
|
||||
|
||||
## 调用链
|
||||
|
||||
**Desktop terminal**:现有会话工厂 → typed invoke → Tauri adapter → `cmd/session.rs` → 原 SessionManager/SSH session → 共享 protocol/algorithm/input/resize → 原生 I/O loop → Tauri output event → 原 XTerminal。
|
||||
|
||||
**Web terminal**:同一会话工厂 → HTTP adapter → `POST /api/sessions` → WebSession + Core protocol/russh → `WS /api/sessions/{id}/terminal` → 二进制输出 / JSON 或二进制输入 / JSON resize/control → 同一 XTerminal。SSH host-key/password/passphrase/keyboard-interactive 提示通过 owner 的 SSE 到现有对话框,HTTP 响应按 requestId 返回。
|
||||
|
||||
**SFTP**:同一 FileExplorer → HTTP command → owner session 检查 → 同一 russh handle 的 SFTP subsystem → 共享初始化/文件工具。上传使用浏览器 File 作为原始流式 request body,远端同目录 `.part` 成功后 rename;下载使用 HTTP body stream 和 Content-Disposition/Content-Length。进度通过 SSE 的现有 transfer-event 格式送入 TransferContext。Desktop 继续使用本地 picker/path/拖拽、原有原生传输管理器。
|
||||
|
||||
**AI**:同一 AI panel → HTTP command → Web Ask/ownership/强制 redaction → Core model/provider/stream → owner SSE → panel。模型发现、测试、历史、清除/重绑共享 Core。Agent/MCP/原生附件在 Web 拒绝。
|
||||
|
||||
**设置与凭据**:HTTP allowlist / Tauri commands → shared config/services → redb/AES-GCM;Web 显式 secret getters 仅供已认证管理员主动读取,列表不返回明文。Web 会合并 masked AI/settings 字段,并拒绝通过 settings save 关闭或替换现有主密码。
|
||||
|
||||
## 生命周期与资源上限
|
||||
|
||||
1. 先建立 SSE,再创建 SSH;创建立即返回不透明 ID,后台连接有 120 秒总超时,提示有 90 秒超时。
|
||||
2. 每个登录最多 16 个会话、4 个 AI 请求;全局最多 128 个会话和 128 个登录;每个 session 最多 4 个 SFTP 操作。
|
||||
3. 每个会话最多一个 WS attachment;SSH output queue 为 32 × 64 KiB(2 MiB),WS write buffer 最多 256 KiB。输出按序 backpressure,最终 close 在 final bytes 后;socket send 有超时。输入 queue 为 128 条、WS 单帧/消息最大 64 KiB,浏览器发送缓冲超过 1 MiB 拒绝继续输入。
|
||||
4. WS 每 15 秒 heartbeat,45 秒没有 peer 活动断开。断线保留 30 秒 attachment lease 和有界输出;浏览器自动尝试同 session 重附着,明确 SSH reconnect 则创建新连接。lease 到期取消连接。
|
||||
5. 显式 close、创建取消、logout、8 小时登录到期和 shutdown 通过 CancellationToken 终止等待、SSH、SFTP 和 AI。SSH disconnect 有超时,registry 清除后发 session change。
|
||||
6. 上传中断/失败或响应被丢弃时,RAII cleanup 清除 `.part` 并关闭 SFTP;上传/下载和文件操作均受 owner 与 cancel 约束。Web 无传输暂停/重试服务。
|
||||
7. SIGTERM/Ctrl-C 取消共享 shutdown,HTTP graceful drain 最多 5 秒,再等待会话清理最多 5 秒。重启不会恢复活跃 SSH。
|
||||
|
||||
## 能力矩阵
|
||||
|
||||
| 能力 | Web MVP |
|
||||
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| 保存/临时 SSH、终端输入输出/resize/关闭 | 支持标准 profile,UTF-8;应用终端类型,解析全局编码。 |
|
||||
| 密码/私钥、主机指纹与手工交互认证 | 支持;不绕过 known_hosts;可提示私钥 passphrase。 |
|
||||
| 保存连接/组、基础凭据、设置 | 共享持久化。保存数据为实例共享;活动会话按登录隔离。 |
|
||||
| SFTP 浏览、单文件上传/下载、文本编辑 | 流式传输;应用 enabled/pipeline depth;UTF-8 文件名;不支持 compatibility mode/递归或原生工作流。 |
|
||||
| AI Assistant | provider API/Ask streaming、脱敏、历史;无 Agent、MCP 或本地附件。 |
|
||||
| 插件 | Web target/capability/permission 检查框架;只允许 UI 类权限,未提供安装或执行器。 |
|
||||
| 本地文件、剪贴板、外部链接、子窗口 | 浏览器 File/download、Clipboard、受限链接、同源 iframe 页面替代;浏览器权限仍适用。 |
|
||||
| Local Shell/PTY、Serial、Telnet、RDP/VNC | 不支持;创建入口与服务均 gate。 |
|
||||
| tray、原生窗口、全局快捷键、桌面通知、OS credential manager、自动更新 | 不支持;Web 采用服务端加密存储和浏览器页面。 |
|
||||
| SCP/Zmodem、watcher、复杂本地文件集成、录制、远程监控、传输控制、同步备份 | 不支持,集中 capability/panel/settings gate。 |
|
||||
| SSH proxy/jump、agent/X11/证书、启动命令、network_device、非 UTF-8 | 拒绝连接;不能静默改成直接连接或忽略这些配置。 |
|
||||
| OSC/CWD 自动跟踪、动态标题 | Web 暂不提供;Desktop 原逻辑保留。 |
|
||||
|
||||
## 安全边界
|
||||
|
||||
这是单管理员实例,不是多租户 ACL 服务。共享保存配置和历史应只对可信管理员开放。高熵登录密码与独立 32 字节外部数据密钥必须配置;启动不能回退到 OS credential manager 或路径派生密钥。既有主密码层次保留,错误数据密钥启动失败。redb 的元数据/AI 历史不等于整个数据库加密。
|
||||
|
||||
cookie 为随机 256 bit、HttpOnly、SameSite=Strict,HTTPS 下 Secure,Path 绑定 base path,8 小时有效。登录校验 Origin 与自定义请求头;mutation 校验 CSRF;WS 校验 cookie 和 Origin;所有静态/API/事件/传输入口校验配置的 Host 与存在的 Origin。没有 wildcard CORS,也不把 forwarded headers 当作认证依据。非回环 public URL 必须 HTTPS。登录尝试限额为全局每分钟 20 次。
|
||||
|
||||
session/prompt/AI cancellation 隔离于登录 owner,跨 owner 的 session 返回 404、prompt 返回 403。WS URL 不含 token。SSH unknown/changed key 均要求明确确认后才保存。secret 不进入日志/列表,响应使用 no-store,并设置 CSP/nosniff/referrer policy。Web command 显式 allowlist,不能反射调用任意 Tauri command、访问服务端任意本地路径或执行本地程序。浏览器插件框架不提供服务端文件/进程权限。
|
||||
|
||||
## 验证结果
|
||||
|
||||
已完成的验证:
|
||||
|
||||
- 共享 Core:248 个单元测试通过,覆盖原有配置、迁移、存储、加密、SFTP helper、AI provider/catalog。
|
||||
- 前端全量:157 个文件、990 个测试通过;Web adapter 的 5 个测试覆盖同源/base URL、CSRF、UTF-8 WS/输入/resize、native 拒绝、有界发送、既有设置 iframe 和登录 gate。
|
||||
- Web integration:真实 russh fixture、SFTP subsystem、mock OpenAI-compatible provider;认证/CSRF/Host/CSP/SPA、owner prompts、known-host 首次确认及变更拒绝、UTF-8 input/resize、断开重附着、3 MiB 输出及 final-tail、5 MiB 上传下载、上传中断清理、凭据加密、AI stream/redaction/history、错误加密密钥拒绝。
|
||||
- Desktop `cargo check --lib` 通过。原生 Rust 测试已成功编译,但测试 exe 在运行前以 `0xc0000139` / `STATUS_ENTRYPOINT_NOT_FOUND` 退出,无法验证 Desktop 原生 SSH/SFTP 运行测试;共享部分已由 Core 和 Web 测试验证。
|
||||
|
||||
- Web 进程启动测试通过:外部 `_FILE` 秘密、真实 HTTP 登录/API、子路径首页,以及更换数据密钥后拒绝重启。Axum 子路由使用带 `/` 的挂载点,裸路径重定向到目录 URL。
|
||||
- 追加的 Web 安全/兼容断言通过:跨 owner / 错 Origin 的 WS upgrade 拒绝、全局编码、保存连接的加密认证、SFTP disabled、AI target-context ownership/redaction、清除历史、HTTP logout,以及等待 host-key prompt 时取消创建后的 session/prompt 清理。
|
||||
- TypeScript、`pnpm lint`、Rust formatting、Desktop `cargo check --lib --locked` 通过。lint 保留未修改 CommandSuggestions 中一个既有 dependency warning;Vite 有既有 chunk-size/Browserslist 提示。
|
||||
- `pnpm build` 和 `/nyaterm/` base path 的 `pnpm build:web` 已通过;输出资源和图标使用构建 base path;最后一轮两种构建均通过。
|
||||
|
||||
本机没有 Docker CLI/engine 或可用浏览器。因此未执行 Docker image build、Linux 容器运行和浏览器视觉/手工交互验收;不能把 HTTP fixture/DOM 测试称为这些验证。部署步骤见 [web-deployment.md](web-deployment.md)。
|
||||
|
||||
## 后续扩展
|
||||
|
||||
优先在 Linux CI 构建和启动 Docker 镜像,加入 Playwright 登录→保存 SSH→指纹确认→xterm→SFTP 的完整浏览器验收,并在三平台 native runner 验证 Desktop。再把更多 SSH auth/session policy 抽为注入 event sink 的服务,减少两端调度差异。随后实现更细的能力描述与本地化不可用提示、Web 插件 sandbox/runtime、SFTP overwrite/递归/取消控制、OSC/CWD 与 SSH proxy/jump。若需要多人使用,先增加用户、保存资源 ACL、AI history 隔离和审计,再放开多用户入口。
|
||||
@@ -0,0 +1,120 @@
|
||||
# Web / Docker 部署
|
||||
|
||||
Web 模式复用现有 React 界面,由 `nyaterm-web` 同时提供静态资源和 HTTP / WebSocket / SSE API。此 MVP 面向一个可信管理员:不同登录的终端、认证提示和运行中的 AI 请求隔离,但保存的连接、凭据、设置、known_hosts 和 AI 历史在同一实例内共享。
|
||||
|
||||
## 本地运行
|
||||
|
||||
需要 Node 24、pnpm 11.10 和 Rust 1.97.1(本次实际验证的版本)。
|
||||
|
||||
```powershell
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm build:web
|
||||
pnpm web:build:server
|
||||
```
|
||||
|
||||
生成两个独立随机秘密并写入工作区外的受限目录。以下命令不打印秘密;登录密码可通过密码管理器读取保存。目录和文件的访问权限应限制为服务运行用户。
|
||||
|
||||
```powershell
|
||||
$secretDir = Join-Path $env:LOCALAPPDATA 'NyaTermWebSecrets'
|
||||
New-Item -ItemType Directory -Force -Path $secretDir | Out-Null
|
||||
$loginBytes = [System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32)
|
||||
$keyBytes = [System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32)
|
||||
[System.IO.File]::WriteAllText((Join-Path $secretDir 'login'), [Convert]::ToBase64String($loginBytes))
|
||||
[System.IO.File]::WriteAllText((Join-Path $secretDir 'encryption'), [Convert]::ToBase64String($keyBytes))
|
||||
$env:NYATERM_WEB_PASSWORD_FILE = Join-Path $secretDir 'login'
|
||||
$env:NYATERM_WEB_ENCRYPTION_KEY_FILE = Join-Path $secretDir 'encryption'
|
||||
$env:NYATERM_WEB_PUBLIC_URL = 'http://localhost:8080/'
|
||||
$env:NYATERM_WEB_BIND = '127.0.0.1:8080'
|
||||
$env:NYATERM_WEB_DATA_DIR = Join-Path $env:LOCALAPPDATA 'NyaTermWebData'
|
||||
pnpm web:serve
|
||||
```
|
||||
|
||||
访问 `http://localhost:8080/`,使用生成的登录密码。PowerShell 示例要求 PowerShell 7 / .NET 的 `GetBytes(int)` API。Linux 可用 `umask 077` 后分别执行 `openssl rand -base64 32 > login` 和 `openssl rand -base64 32 > encryption`,然后配置相应 `_FILE` 变量。
|
||||
|
||||
## 环境变量
|
||||
|
||||
| 变量 | 含义 |
|
||||
| ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `NYATERM_WEB_PASSWORD` / `NYATERM_WEB_PASSWORD_FILE` | 登录密码,至少 32 字符;推荐随机生成。指定 `_FILE` 时优先读取文件。 |
|
||||
| `NYATERM_WEB_ENCRYPTION_KEY` / `NYATERM_WEB_ENCRYPTION_KEY_FILE` | 标准 Base64 编码的 32 字节随机密钥,必须持久保存,禁止重新生成后直接复用旧数据。 |
|
||||
| `NYATERM_WEB_PUBLIC_URL` | 浏览器实际访问地址,含端口和 base path;默认 `http://localhost:8080/`。非回环地址必须为 HTTPS。 |
|
||||
| `NYATERM_WEB_BIND` | 服务监听地址,默认 `127.0.0.1:8080`,容器为 `0.0.0.0:8080`。 |
|
||||
| `NYATERM_WEB_DATA_DIR` | redb 数据目录,默认 `./nyaterm-web-data`,容器为 `/data`。 |
|
||||
| `NYATERM_WEB_DIST` | 已构建 React 资源目录,默认 `dist`,容器为 `/app/dist`。 |
|
||||
| `NYATERM_WEB_BASE_PATH` | **前端构建时**使用的路径,默认 `/`,必须与 PUBLIC_URL 的路径一致并以 `/` 结尾。 |
|
||||
|
||||
服务启动会验证数据密钥;错误密钥会阻止启动。文件方式会去掉末尾换行。登录密码可独立替换,服务器重启使所有旧登录失效;加密密钥目前没有在线轮换 API。
|
||||
|
||||
## Docker
|
||||
|
||||
```sh
|
||||
docker build -t nyaterm-web .
|
||||
docker volume create nyaterm-data
|
||||
docker run -d --name nyaterm-web --init \
|
||||
-p 127.0.0.1:8080:8080 \
|
||||
-e NYATERM_WEB_PUBLIC_URL=http://localhost:8080/ \
|
||||
-e NYATERM_WEB_PASSWORD_FILE=/run/secrets/login \
|
||||
-e NYATERM_WEB_ENCRYPTION_KEY_FILE=/run/secrets/encryption \
|
||||
--mount type=bind,src=/absolute/private/secrets,dst=/run/secrets,readonly \
|
||||
--mount type=volume,src=nyaterm-data,dst=/data \
|
||||
--read-only --tmpfs /tmp --cap-drop ALL \
|
||||
--security-opt no-new-privileges:true \
|
||||
nyaterm-web
|
||||
```
|
||||
|
||||
容器使用 UID / GID `10001:10001`。绑定目录时,确保该用户可以读取秘密文件和写入数据目录;新 named volume 会继承镜像中 `/data` 的所有权。默认端口映射仅暴露本机。如需远程访问,使用下面的 HTTPS 反向代理配置。
|
||||
|
||||
仓库还提供 `compose.web.yml`,它通过外部环境变量注入密码和密钥:
|
||||
|
||||
```sh
|
||||
docker compose -f compose.web.yml up --build -d
|
||||
```
|
||||
|
||||
提前在当前 shell 或受限 `.env` 中设置两个必填秘密。`.env*` 已排除在 Git 和 Docker build context 外。生产环境优先将 Compose 改为 `secrets` 挂载和 `_FILE` 变量,避免把秘密写入镜像。Dockerfile 使用 Node、Rust、Debian 三阶段构建,最终镜像只含 dist、服务程序和运行依赖。
|
||||
|
||||
## HTTPS 和子路径
|
||||
|
||||
例如部署到 `https://terminal.example.com/nyaterm/`:
|
||||
|
||||
```sh
|
||||
docker build --build-arg NYATERM_WEB_BASE_PATH=/nyaterm/ -t nyaterm-web .
|
||||
```
|
||||
|
||||
运行时设置 `NYATERM_WEB_PUBLIC_URL=https://terminal.example.com/nyaterm/`。前端和后端必须使用相同的 origin 和路径;后端会校验原始 Host / Origin,不使用转发头放宽校验。代理应保留完整路径,不能剥掉 `/nyaterm`。
|
||||
|
||||
Nginx 示例(TLS 证书配置按已有站点设置):
|
||||
|
||||
```nginx
|
||||
# http 块
|
||||
map $http_upgrade $nyaterm_connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
# 已配置 TLS 的 server 块
|
||||
location = /nyaterm { return 308 /nyaterm/; }
|
||||
location /nyaterm/ {
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Origin $http_origin;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $nyaterm_connection_upgrade;
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_read_timeout 650s;
|
||||
client_max_body_size 0;
|
||||
}
|
||||
```
|
||||
|
||||
关闭响应缓冲以支持 SSE / 下载,关闭请求缓冲以支持流式上传。可根据部署需求调整上传大小和代理超时。Web 不提供跨源 API 或 Vite 开发代理;验证运行模式应使用构建后的 dist。
|
||||
|
||||
## 数据与能力范围
|
||||
|
||||
停服后备份整个数据目录,并单独备份加密密钥与登录密码。密钥丢失将无法解密凭据。不要让多个进程同时写同一个 redb volume,也不要把桌面用户数据目录直接作为服务器 volume。保存的私人密钥、密码和 AI provider 密钥使用原有 AES-GCM 存储。AI 历史和连接元数据属于实例共享数据,未作为整个数据库加密。
|
||||
|
||||
支持保存/临时 SSH、密码/私钥与手工交互认证、主机指纹确认、终端输入/输出/resize、SFTP 浏览与单文件流式上传/下载、文本编辑、基础 AI Ask 和设置持久化。插件部分提供兼容性及权限检查框架,当前没有浏览器插件安装/执行器。
|
||||
|
||||
Web 当前不支持本地 Shell、Serial、Telnet、RDP/VNC、代理/跳板、SSH agent/X11/证书登录、启动命令、非标准 SSH profile、非 UTF-8 终端/文件名、SFTP compatibility mode、CWD 自动跟踪、远程监控、录制、SCP/Zmodem、本地文件 watcher、传输暂停/重试、同步备份和 AI Agent/MCP/本地附件。系统托盘、原生窗口、OS credential manager、系统全局快捷键、桌面通知、自动更新也不提供。浏览器文件、剪贴板、链接和 iframe 页面代替相应原生入口,仍受浏览器权限约束。
|
||||
|
||||
测试与架构见 [web-architecture.md](web-architecture.md)。当前环境没有 Docker 和浏览器,因此镜像实构建和浏览器视觉验收仍需在部署环境执行。
|
||||
Reference in new issue
Block a user