mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-30 04:40:18 +08:00
feat(hermes): Batch 2 §I + Batch 3 §M - 流恢复 + Kanban 看板
## Batch 2 §I 流恢复(chat 在切页/刷新后能接上 run)
校对稿:用 run_id 持久化到 localStorage,新页面挂载时查询 status 决定是否重连。
### 后端
- 新 Tauri 命令 hermes_run_status(run_id):
· GET /v1/runs/{run_id} 返回 { run_id, status, last_event, output?, ... }
· status: running / stopping / completed / failed / cancelled / waiting_for_approval
· 404 友好返回 status='not_found' 而不是抛错
### 前端 chat-store
- 新 STORAGE_ACTIVE_RUN 持久化 { runId, sessionId, profile, t }
- hermes-run-started 监听里 safeSet 持久化
- cleanupAfterRun 里 safeRemove 清理
- 新方法 recoverIfRunning():
· 跨 profile / 1 小时过期 → 直接清
· status=running/stopping/waiting_for_approval → attachStreamListeners + 恢复 streaming
· status=已结束 → 拉最新 messages
· 404 → 静默清
### chat.js
- 页面挂载时 store.recoverIfRunning() — 切页/刷新后无缝接上流
## Batch 3 §M Kanban 看板(Hermes 已内置)
校对稿:「Hermes 已内置 kanban 系统,直接调 /api/plugins/kanban/* 即可」。
设计稿原本是「自建本地存储」(~800 行),复用 Hermes 内置后大幅缩减。
### 新页面 /h/kanban
- 全部走 hermesDashboardApi(复用 §H 的基础设施)
- 顶部 board 切换器 + 「+ 新任务」按钮
- 渲染 board.columns(按状态分列:todo / in_progress / blocked / done / archived)
- 任务卡片:title + summary(2 行截断)+ priority badge + assignee + 评论数
- 点卡片 → showContentModal 显示详情 + 「修改状态」按钮
- 修改状态 → PATCH /api/plugins/kanban/tasks/{id} { status }
- board 切换 → POST /api/plugins/kanban/boards/{slug}/switch
### sidebar
- 「管理」section 加 Kanban 入口(inbox 图标)
- /h/kanban 路由注册
### CSS (.hm-kanban-*)
- 水平滚动 board 容器
- 280px 固定宽度列 + 内部滚动
- 卡片 hover 边框变 accent 色 + 轻阴影
- 优先级 badge(琥珀色)/ assignee(accent 色)
### i18n
- 27 个新键 × 3 语言(zh-CN/en/zh-TW)
## 累计
- Rust: 1 个新命令(hermes_run_status ~30 行)
- 前端: chat-store 流恢复(~40 行)+ kanban 新页面(~230 行)
- i18n: 27 个新键 × 3 语言
- CSS: ~100 行
- cargo check ✓ + npm build ✓
This commit is contained in:
@@ -3795,6 +3795,44 @@ 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 2 §I: hermes_run_status — 查 run 当前状态(流恢复用)
|
||||
//
|
||||
// GET /v1/runs/{run_id} 返回 { run_id, status, last_event, output?, ... }
|
||||
// status 取值:running / stopping / completed / failed / cancelled / waiting_for_approval
|
||||
// 切页 / 刷新后用这个判断是否还需要重连 SSE 事件流
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn hermes_run_status(run_id: String) -> Result<Value, String> {
|
||||
if run_id.is_empty() {
|
||||
return Err("run_id 不能为空".to_string());
|
||||
}
|
||||
let gw_url = hermes_gateway_url();
|
||||
let url = format!("{gw_url}/v1/runs/{run_id}");
|
||||
let api_key = read_hermes_api_key();
|
||||
let client = hermes_gateway_http_client(std::time::Duration::from_secs(5))
|
||||
.map_err(|e| format!("HTTP 客户端创建失败: {e}"))?;
|
||||
let mut req = client.get(&url);
|
||||
if !api_key.is_empty() {
|
||||
req = req.header("Authorization", format!("Bearer {api_key}"));
|
||||
}
|
||||
let resp = req
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| format!("status 请求失败: {}", reqwest_error_detail(&e)))?;
|
||||
let status = resp.status();
|
||||
if status.as_u16() == 404 {
|
||||
// run 已过期或不存在 — 返回明确状态而不是错
|
||||
return Ok(serde_json::json!({ "run_id": run_id, "status": "not_found" }));
|
||||
}
|
||||
if !status.is_success() {
|
||||
let body = resp.text().await.unwrap_or_default();
|
||||
return Err(format!("status 失败 HTTP {}: {}", status.as_u16(), body));
|
||||
}
|
||||
resp.json::<Value>().await.map_err(|e| format!("解析 JSON 失败: {e}"))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Batch 1 §E: hermes_session_export — 导出会话消息(走 dashboard 9119)
|
||||
//
|
||||
|
||||
@@ -241,6 +241,7 @@ pub fn run() {
|
||||
hermes::hermes_agent_run,
|
||||
hermes::hermes_run_stop,
|
||||
hermes::hermes_run_approval,
|
||||
hermes::hermes_run_status,
|
||||
hermes::hermes_session_export,
|
||||
hermes::hermes_dashboard_api_proxy,
|
||||
hermes::hermes_read_config,
|
||||
|
||||
Reference in New Issue
Block a user