feat: 版本更新

This commit is contained in:
chaoszhu
2026-08-15 12:01:43 +08:00
parent 7eb80329d4
commit 71ab95c53e
6 changed files with 184 additions and 11 deletions
+11
View File
@@ -6,6 +6,17 @@
* 支持csv模板特定格式导入 * 支持csv模板特定格式导入
* AI功能增强 * AI功能增强
## [3.7.3](https://github.com/chaos-zhu/easynode/releases) (2026-08-15)
* 兼容 移动端 AI Agent 功能
* 其他功能优化与bug修复
## [native-v1.2.0](https://github.com/chaos-zhu/easynode/releases) (2026-07-05)
* AI Agent 功能支持
* ssh&sfpt状态共享优化
* 终端页拖动选择滚动优化
* 支持更多更多主题
* 其他功能优化与bug修复
## [3.7.2](https://github.com/chaos-zhu/easynode/releases) (2026-08-02) ## [3.7.2](https://github.com/chaos-zhu/easynode/releases) (2026-08-02)
* AI Chat 功能重构为 AI Agent 功能上线 * AI Chat 功能重构为 AI Agent 功能上线
* web 端布局调整 * web 端布局调整
+149 -8
View File
@@ -4,12 +4,14 @@ EasyNode 的 Flutter Native App,复用现有后端 (`/api/v1`),在原生端
## 技术栈 ## 技术栈
- Flutter `^3.11.5` - Flutter `^3.11.0`
- Riverpod (`flutter_riverpod`) 状态管理 - Riverpod (`flutter_riverpod`) 状态管理
- Dio + dio_cookie_manager + flutter_secure_storage 网络与持久化 - Dio + dio_cookie_manager + flutter_secure_storage 网络与持久化
- dartssh2 + xterm 终端 - dartssh2 + xterm 终端
- Socket.IO (`socket_io_client`) AI 助手实时通信
- pointycastle + basic_utils RSA / AES-GCM 加密 - pointycastle + basic_utils RSA / AES-GCM 加密
- re_editor / photo_view 文件预览与编辑 - re_editor / photo_view 文件预览与编辑
- flutter_markdown_plus Markdown 渲染
## 目录结构 ## 目录结构
@@ -17,23 +19,25 @@ EasyNode 的 Flutter Native App,复用现有后端 (`/api/v1`),在原生端
native/ native/
├── lib/ ├── lib/
│ ├── main.dart # 入口,调用 EasyNodeApp.bootstrap() │ ├── main.dart # 入口,调用 EasyNodeApp.bootstrap()
│ ├── app.dart # 启动装配、ProviderScope override、登录态路由 │ ├── app.dart # 启动装配、ProviderScope override、登录态路由、AI Agent overlay
│ ├── core/ │ ├── core/
│ │ ├── api/ # ApiClient / Cookie / 通用错误 │ │ ├── api/ # ApiClient / Cookie / 通用错误
│ │ ├── crypto/ # RSA、AES-GCM、CryptoJS 兼容 │ │ ├── crypto/ # RSA、AES-GCM、CryptoJS 兼容
│ │ ├── storage/ # SharedPreferences + SecureStorage + deviceId │ │ ├── storage/ # SharedPreferences + SecureStorage + deviceId
│ │ ├── i18n/ # 多语言资源
│ │ ├── ui/ # 主题色板 │ │ ├── ui/ # 主题色板
│ │ └── utils/ # JWT、表单校验 │ │ └── utils/ # JWT、表单校验
│ ├── features/ │ ├── features/
│ │ ├── auth/ # 登录页、登录控制器、AuthSession │ │ ├── auth/ # 登录页、登录控制器、AuthSession
│ │ ├── servers/ # 服务器列表、表单、Repository、模型 │ │ ├── servers/ # 服务器列表、表单、Repository、模型
│ │ ├── terminal/ # SSH 通道、xterm 控制器、会话管理、工具栏 │ │ ├── terminal/ # SSH 通道、xterm 控制器、会话管理、工具栏
│ │ ├── ai_agent/ # AI 助手:Socket.IO 客户端、消息流、工具调用审批
│ │ ├── scripts/ # 脚本库与脚本分组 │ │ ├── scripts/ # 脚本库与脚本分组
│ │ ├── settings/ # 账户安全、凭据、代理、登录日志、Plus │ │ ├── settings/ # 账户安全、凭据、代理、登录日志、Plus
│ │ └── shell/ # MainShell / SFTP / 编辑器 / 媒体预览 │ │ └── shell/ # MainShell / SFTP / 编辑器 / 媒体预览
│ ├── state/ # Riverpod providers (auth、host list、terminal …) │ │ ├── editor/ # 文件编辑器(re_editor)
│ └── l10n/ # 多语言入口 │ │ └── media/ # 媒体预览(photo_view)
│ ├── state/ # Riverpod providers (auth、host list、terminal、agent …)
│ └── l10n/ # 多语言入口:AppLocalizations、strings_zh/en
├── android/ # Android 工程,含 key.properties.example ├── android/ # Android 工程,含 key.properties.example
├── ios/ # iOS 工程 ├── ios/ # iOS 工程
├── assets/ # 图标 / 图片资源 ├── assets/ # 图标 / 图片资源
@@ -80,13 +84,15 @@ native/
### 主壳 ### 主壳
`features/shell/main_shell_page.dart` 是四个 tab 的 IndexedStack 保活容器: `features/shell/main_shell_page.dart` 是四个 tab 的 IndexedStack 保活容器 + AI Agent 全局浮窗:
- `ServersTab`:服务器列表,点击连接走 `ApiServerRepository.fetchSshConfig(hostId)` → `TerminalSessionManager.openSession()` 在本地起 dartssh2 session。 - `ServersTab`:服务器列表,点击连接走 `ApiServerRepository.fetchSshConfig(hostId)` → `TerminalSessionManager.openSession()` 在本地起 dartssh2 session。
- `SftpTab`:SFTP 文件操作。 - `SftpTab`:SFTP 文件操作。
- `ScriptsTab`:脚本库与脚本分组。 - `ScriptsTab`:脚本库与脚本分组。
- `SettingsTab`:账户安全 / 凭据 / 代理 / 登录日志 / Plus。 - `SettingsTab`:账户安全 / 凭据 / 代理 / 登录日志 / Plus。
AI Agent 通过 `AgentOverlay` 浮窗全局可用,支持多种 AI 提供商(OpenAI、Anthropic、Google),实时 Socket.IO 通信,工具调用需用户审批。
登出由 `authProvider` 状态变更触发 `_AppRoot` 回到 `LoginPage`,不需要手动 pop。 登出由 `authProvider` 状态变更触发 `_AppRoot` 回到 `LoginPage`,不需要手动 pop。
### 终端 / SSH ### 终端 / SSH
@@ -96,6 +102,14 @@ native/
- `ssh_connection_config.dart`:与服务端 native SSH payload 对齐的纯数据类。 - `ssh_connection_config.dart`:与服务端 native SSH payload 对齐的纯数据类。
- `http_proxy_connector.dart` / `socks5_connector.dart` / `ssh_transport.dart`:代理与跳板机连接通道。 - `http_proxy_connector.dart` / `socks5_connector.dart` / `ssh_transport.dart`:代理与跳板机连接通道。
### AI Agent
- `features/ai_agent/agent_socket_client.dart`:Socket.IO 客户端,连接 `/agent` 命名空间,处理 `message` / `tool-call` / `stream-end` 事件。
- `agent_controller.dart` + `agent_reducer.dart`:消息流状态机,处理用户输入、工具审批、历史会话。
- `agent_overlay.dart` + `agent_window.dart`:全局可拖拽浮窗,支持最小化 / 展开,跨 tab 保持状态。
- `agent_repository.dart`:`GET /api/v1/agent/provider-config` 获取 AI 配置,`POST /agent/history` 保存会话。
- 工具调用(如执行 SSH 命令、读文件)需要用户在 `agent_approval_card.dart` 中点击批准,未批准的调用自动拒绝。
### 存储分层 ### 存储分层
- `AppStorage`(SharedPreferences):普通偏好,例如 server address、username、save password 开关。 - `AppStorage`(SharedPreferences):普通偏好,例如 server address、username、save password 开关。
@@ -117,10 +131,137 @@ flutter test # 单元测试(仅在显式需要时执行)
## 打包步骤 ## 打包步骤
打包 / 发布操作(Android 本地构建、Android CI、iOS 构建、发布前自检)见 `docs/native-packaging.md`;纯 Android 从零环境搭建见 `docs/native-android-build-from-zero.md`。 ### Android
1. **准备签名密钥**(仅首次)
```bash
keytool -genkeypair -v -keystore easynode-release.jks \
-alias easynode -keyalg RSA -keysize 2048 -validity 10000
```
把生成的 `easynode-release.jks` 放到 `native/android/` 下。
2. **创建 `native/android/key.properties`**
参考 `key.properties.example`:
```properties
storePassword=<your-store-password>
keyPassword=<your-key-password>
keyAlias=easynode
storeFile=easynode-release.jks
```
该文件已被 `.gitignore` 忽略,**不要提交**。如果不提供,`build.gradle.kts` 会回退到 debug keystore,仅供本地 `flutter run --release` 使用,正式产物必须有 release keystore。
3. **更新版本号**
编辑 `native/pubspec.yaml` 顶部的 `version: x.y.z+build`,`+` 之前是 `versionName`,之后是 `versionCode`。
4. **构建产物**
```bash
flutter pub get
flutter clean # 可选,更新插件后建议执行
flutter build apk --release # 通用 APK
flutter build apk --release --split-per-abi # 按 ABI 拆分(推荐用于分发)
flutter build appbundle --release # Google Play 上架用 AAB
```
产物位置:
- APK: `native/build/app/outputs/flutter-apk/`
- AAB: `native/build/app/outputs/bundle/release/`
### Android CI 构建
GitHub Actions 使用 `.github/workflows/native-android-release.yml` 构建 Android 产物。
触发方式:
- 推送 `native-v*` 标签,例如 `native-v0.1.0-beta.1`(会构建并上传到对应 GitHub Release)
- 在 Actions 页面手动运行 `Build Native Android`(只产出 artifact,不写 Release)
需要在仓库配置以下 GitHub Secrets(`Settings → Secrets and variables → Actions`):
- `ANDROID_KEYSTORE_BASE64`:`native/android/easynode-release.jks` 的 base64 内容
- `ANDROID_STORE_PASSWORD`:keystore store password
- `ANDROID_KEY_PASSWORD`:key password
- `ANDROID_KEY_ALIAS`:默认 `easynode`
生成 keystore 的 base64(任选其一):
```powershell
# Windows PowerShell
[Convert]::ToBase64String([IO.File]::ReadAllBytes("native/android/easynode-release.jks"))
```
```bash
# Linux
base64 -w 0 native/android/easynode-release.jks
# macOS
base64 -i native/android/easynode-release.jks
```
workflow 会在还原签名后校验上述 Secret 非空,并在构建后用 `apksigner` 校验产物证书不是 debug keystore,任一不满足直接失败。
CI 产物:
- APK: `native/build/app/outputs/flutter-apk/*.apk`(APK 可直接安装/侧载,当前分发方式)
> AAB(Google Play 上架格式)默认不构建,workflow 里 `Build app bundle` 步骤已注释。需要上架 Google Play 时取消注释,并恢复两个上传步骤里的 `*.aab` 路径。
发布版本时需要同步更新:
- `native/pubspec.yaml` 的 `version: x.y.z+build`(`+build`/versionCode 必须单调递增,否则无法上架 Google Play)
- `server/version.json` 的 `nativeVersion: native-vx.y.z`
> 提示:发布 `native-v*` 的 GitHub Release 不会触发服务端 Docker 构建(`docker-builder.yml` 已对 `native-`/`client` 前缀加了跳过守卫),Web 端更新检测也已忽略 `native-v*` 标签。
### iOS
iOS 构建需要 macOS + Xcode。
1. **首次准备**
```bash
cd native/ios
pod install
```
2. **在 Xcode 配置签名**
用 Xcode 打开 `native/ios/Runner.xcworkspace`,在 `Runner` → `Signing & Capabilities` 配置 Team / Bundle Identifier / Provisioning Profile。
3. **构建归档**
```bash
flutter build ipa --release
```
或在 Xcode 中选择 `Product → Archive`,再通过 Organizer 上传到 App Store Connect / 导出 Ad-hoc IPA。
产物位置:`native/build/ios/archive/` 与 `native/build/ios/ipa/`。
### HarmonyOS
参见 `OHOS_PATCH.md` 获取完整的 HarmonyOS 构建说明。
### 发布前自检
- `flutter analyze` 通过。
- 在真机 release 模式运行一次(`flutter run --release`)。
- 确认登录页能输入服务器地址、HTTP 地址有风险提示、HTTPS 不提示。
- 确认终端、SFTP、脚本三个 tab 能正常访问后端。
- 确认登出后 token / cookie / deviceId 已清空。
## 后端约定 ## 后端约定
- Native 端复用 `/api/v1` 全部接口,鉴权与 Web 端一致:`token` header + `session` cookie。 - Native 端复用 `/api/v1` 全部接口,鉴权与 Web 端一致:`token` header + `session` cookie。
- 专属端点:`POST /api/v1/native/ssh-connection`,返回 AES-GCM 加密后的 SSH 连接参数。修改时同步更新 `server/app/controller/native.js` 与 `native/lib/features/servers/server_repository.dart`、`native/lib/core/crypto/aes_gcm_crypto.dart`。 - 专属端点:
- `POST /api/v1/native/ssh-connection`:返回 AES-GCM 加密后的 SSH 连接参数。修改时同步更新 `server/app/controller/native.js` 与 `native/lib/features/servers/server_repository.dart`、`native/lib/core/crypto/aes_gcm_crypto.dart`。
- `GET /api/v1/agent/provider-config`:返回 AI Agent 配置(提供商、模型列表、上下文限制)。
- WebSocket 命名空间:
- `/agent`:AI Agent 实时通信,事件包括 `message`(流式文本)、`tool-call`(工具调用请求)、`stream-end`(会话结束)。
- 解密后的 SSH 凭据**不得写入磁盘或日志**。 - 解密后的 SSH 凭据**不得写入磁盘或日志**。
+1 -1
View File
@@ -1,7 +1,7 @@
name: easynode_native name: easynode_native
description: "EasyNode native app." description: "EasyNode native app."
publish_to: 'none' publish_to: 'none'
version: 1.1.0+3 version: 1.2.0+1
environment: environment:
sdk: ^3.11.0 sdk: ^3.11.0
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "server", "name": "server",
"version": "3.7.2", "version": "3.7.3",
"description": "easynode-server", "description": "easynode-server",
"type": "module", "type": "module",
"bin": "./bin/www", "bin": "./bin/www",
+21
View File
@@ -1,4 +1,25 @@
[ [
{
"version": "v3.7.3",
"date": "2026-08-15",
"nativeVersion": "native-v1.2.0",
"nativeReleaseUrl": "https://github.com/chaos-zhu/easynode/releases",
"iosReleaseUrl": "",
"ohosReleaseUrl": "",
"features": [
"移动端 AI Agent 功能支持",
"优化首页加载逻辑",
"其他功能优化与bug修复"
],
"nativeFeatures": [
"移动端AI助手功能上线",
"ssh & sfpt状态共享优化",
"终端页拖动选择滚动优化",
"支持更多主题",
"proxyList 延迟加载修复",
"其他功能优化与bug修复"
]
},
{ {
"version": "v3.7.2", "version": "v3.7.2",
"date": "2026-08-02", "date": "2026-08-02",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "web", "name": "web",
"version": "3.7.2", "version": "3.7.3",
"description": "easynode-web", "description": "easynode-web",
"private": true, "private": true,
"scripts": { "scripts": {