feat(hermes): Batch 1 §E - Sessions 导出(走 dashboard /api/sessions/{id}/messages)

校对稿订正:不走 CLI `hermes sessions export`,直接调 dashboard 9119 HTTP API。

## 后端
- 新 Tauri 命令 hermes_session_export(session_id):
  · GET http://127.0.0.1:{dashboard_port}/api/sessions/{id}/messages
  · 拿原始 JSON 返回前端
  · 错误提示「请先启动 Dashboard」(dashboard server 必须运行)

## 前端
- tauri-api.js: hermesSessionExport wrapper
- sessions.js: 详情面板「打开会话 / Pin / 导出 / 删除」并列布局
  · 点导出 → Blob + URL.createObjectURL + a.download 浏览器下载 hermes-session-{id}.json
  · toast 成功/失败
- dev-api.js: Web 模式 handler 同步调 dashboard 端口

## i18n
- sessionsExport / sessionsExportSuccess / sessionsExportFailed × 3 语言
This commit is contained in:
晴天
2026-05-14 04:54:25 +08:00
parent 832bb9a6ef
commit 112963b2b7
6 changed files with 83 additions and 0 deletions

View File

@@ -3795,6 +3795,43 @@ pub async fn hermes_run_approval(run_id: String, choice: String) -> Result<Value
Ok(resp.json::<Value>().await.unwrap_or(serde_json::json!({ "ok": true })))
}
// ---------------------------------------------------------------------------
// Batch 1 §E: hermes_session_export — 导出会话消息(走 dashboard 9119
//
// 校对稿订正:不走 CLI `hermes sessions export`,直接调
// `GET http://127.0.0.1:{dashboard_port}/api/sessions/{session_id}/messages`
// 拿 JSON 后由前端打包下载(避免 CLI 子进程开销 + Web 模式不可达)。
//
// 注意dashboard server 需要先启动(用户没启的话调 hermes_dashboard_start
// ---------------------------------------------------------------------------
#[tauri::command]
pub async fn hermes_session_export(session_id: String) -> Result<Value, String> {
if session_id.is_empty() {
return Err("session_id 不能为空".to_string());
}
let port = hermes_dashboard_port();
let url = format!("http://127.0.0.1:{port}/api/sessions/{session_id}/messages");
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(30))
.build()
.map_err(|e| format!("HTTP 客户端创建失败: {e}"))?;
let resp = client
.get(&url)
.send()
.await
.map_err(|e| format!("export 请求失败: {}(提示:请先启动 Dashboard", reqwest_error_detail(&e)))?;
let status = resp.status();
if !status.is_success() {
let body = resp.text().await.unwrap_or_default();
return Err(format!("export 失败 HTTP {}: {}", status.as_u16(), body));
}
// 让前端拿原始 JSON 自己打包下载(保留完整结构)
resp.json::<Value>().await.map_err(|e| format!("解析 JSON 失败: {e}"))
}
#[tauri::command]
pub async fn hermes_agent_run(
app: tauri::AppHandle,

View File

@@ -241,6 +241,7 @@ pub fn run() {
hermes::hermes_agent_run,
hermes::hermes_run_stop,
hermes::hermes_run_approval,
hermes::hermes_session_export,
hermes::hermes_read_config,
hermes::hermes_read_config_full,
hermes::hermes_lazy_deps_features,