feat: 兼容 OpenClaw v2026.3.7 (SecretRef token, caps tool-events, 认证错误处理, Gateway 可见终端)

This commit is contained in:
晴天
2026-03-09 00:23:44 +08:00
parent b904fb2398
commit 69160c06f4
6 changed files with 96 additions and 51 deletions

View File

@@ -126,7 +126,7 @@ pub fn create_connect_frame(nonce: String, gateway_token: String) -> Result<Valu
},
"role": "operator",
"scopes": SCOPES,
"caps": [],
"caps": ["tool-events"],
"auth": { "token": gateway_token },
"device": {
"id": device_id,

View File

@@ -357,7 +357,9 @@ mod platform {
}
}
/// 以前台模式 spawn Gateway(不需要管理员权限)
const GATEWAY_WINDOW_TITLE: &str = "OpenClaw Gateway";
/// 在可见终端窗口中启动 Gateway用户可直接看到输出
pub async fn start_service_impl(_label: &str) -> Result<(), String> {
if !is_cli_installed() {
return Err(
@@ -369,29 +371,20 @@ mod platform {
return Ok(());
}
let log_dir = dirs::home_dir()
.unwrap_or_default()
.join(".openclaw")
.join("logs");
std::fs::create_dir_all(&log_dir).ok();
let enhanced = crate::commands::enhanced_path();
let stdout_log = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(log_dir.join("gateway.log"))
.map_err(|e| format!("创建日志文件失败: {e}"))?;
// 用 cmd /c start 打开新的可见终端窗口运行 Gateway
// 父 cmd 用 CREATE_NO_WINDOW 避免自身闪窗,子窗口由 start 创建
const CREATE_NO_WINDOW: u32 = 0x08000000;
let start_cmd = format!(
"start \"{}\" cmd /k openclaw gateway",
GATEWAY_WINDOW_TITLE
);
let stderr_log = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(log_dir.join("gateway.err.log"))
.map_err(|e| format!("创建错误日志文件失败: {e}"))?;
crate::utils::openclaw_command_async()
.arg("gateway")
.stdin(std::process::Stdio::null())
.stdout(stdout_log)
.stderr(stderr_log)
std::process::Command::new("cmd")
.args(["/c", &start_cmd])
.env("PATH", &enhanced)
.creation_flags(CREATE_NO_WINDOW)
.spawn()
.map_err(|e| format!("启动 Gateway 失败: {e}"))?;
@@ -401,30 +394,39 @@ mod platform {
return Ok(());
}
}
Err("Gateway 启动超时,请检查日志".into())
Err("Gateway 启动超时,请检查终端窗口中的错误信息".into())
}
/// 关闭 Gateway 终端窗口
pub async fn stop_service_impl(_label: &str) -> Result<(), String> {
const CREATE_NO_WINDOW: u32 = 0x08000000;
// 先尝试优雅停止
let _ = crate::utils::openclaw_command_async()
.args(["gateway", "stop"])
.output()
.await;
if check_service_status(0, "").0 {
const CREATE_NO_WINDOW: u32 = 0x08000000;
let _ = TokioCommand::new("cmd")
.args([
"/c",
"taskkill",
"/f",
"/im",
"node.exe",
"/fi",
"WINDOWTITLE eq openclaw*",
])
.creation_flags(CREATE_NO_WINDOW)
.output()
.await;
// 等一下看是否停了
for _ in 0..5 {
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
if !check_service_status(0, "").0 {
// 关闭残留终端窗口
let _ = TokioCommand::new("cmd")
.args(["/c", "taskkill", "/fi", &format!("WINDOWTITLE eq {}", GATEWAY_WINDOW_TITLE)])
.creation_flags(CREATE_NO_WINDOW)
.output()
.await;
return Ok(());
}
}
// 强制关闭终端窗口(会同时杀掉其中的 node 进程)
let _ = TokioCommand::new("cmd")
.args(["/c", "taskkill", "/f", "/fi", &format!("WINDOWTITLE eq {}", GATEWAY_WINDOW_TITLE)])
.creation_flags(CREATE_NO_WINDOW)
.output()
.await;
Ok(())
}

View File

@@ -152,6 +152,20 @@ pub fn run() {
update::rollback_frontend_update,
update::get_update_status,
])
.run(tauri::generate_context!())
.expect("启动 ClawPanel 失败");
.build(tauri::generate_context!())
.expect("启动 ClawPanel 失败")
.run(|_app, event| {
if let tauri::RunEvent::Exit = event {
#[cfg(target_os = "windows")]
{
// 退出时关闭 Gateway 终端窗口
use std::os::windows::process::CommandExt;
const CREATE_NO_WINDOW: u32 = 0x08000000;
let _ = std::process::Command::new("cmd")
.args(["/c", "taskkill", "/fi", "WINDOWTITLE eq OpenClaw Gateway"])
.creation_flags(CREATE_NO_WINDOW)
.output();
}
}
});
}