新增: 应用内版本更新与自动升级全链路

后端 update.rs: app_check_update(拉 latest.json+ed25519 签名校验) /
app_download_install_update / prefs 读写 / mark_checked / mark_notified 五命令,
lib.rs 注册;tauri.conf updater 段(endpoints=app.1216.top/download/devflow/latest.json
+ pubkey + createUpdaterArtifacts) + tauri-plugin-updater 依赖 + capabilities 权限。

前端 UpdateBadge.vue(顶栏徽章+下拉) / useUpdateCheck.ts(检查/下载/安装状态机) /
AboutPanel.vue(设置页关于面板) + AppLayout 接线 + SettingsNav/searchIndex 索引 +
i18n zh/en settings 键。

运维 scripts/publish-release.ps1(发版) + swap-install.ps1(换装校验) +
设计文档 版本更新与自动升级-设计-2026-10-09.md。

验收: cargo check -p devflow EXIT 0 + vue-tsc EXIT 0 + build EXIT 0。
This commit is contained in:
lxy
2026-10-09 22:53:14 +08:00
parent c70faa7bb8
commit a8c92e9619
27 changed files with 2021 additions and 24 deletions
+7 -3
View File
@@ -70,10 +70,12 @@ impl Node for HumanNode {
// 3. select! 循环:Response / 超时 / 取消
let deadline = tokio::time::Instant::now() + Duration::from_secs(timeout_secs);
let mut cancel_tick = tokio::time::interval(Duration::from_millis(500));
cancel_tick.tick().await; // 丢弃首个立即触发的 tick
// FR-P4:取消检测由 500ms interval 轮询改为 Notify 被动唤醒(set_cancelled 触发)。
// 先建 notified future 再进 loop,避免 notify 早于 await 的竞态窗口;
// 每轮 select! 后重建(Notified 单次消费),配合 is_cancelled 复查兜底。
loop {
let cancel_wait = ctx.node_status.cancel_notified();
tokio::select! {
recv = rx.recv() => match recv {
Ok(WorkflowEvent::HumanApprovalResponse {
@@ -154,7 +156,9 @@ impl Node for HumanNode {
_ = tokio::time::sleep_until(deadline) => {
return Err(anyhow::anyhow!("人工审批超时({}s)", timeout_secs));
}
_ = cancel_tick.tick() => {
_ = cancel_wait => {
// FR-P4:Notify 唤醒后复查 is_cancelled(Notify 无状态,
// 可能因其他节点取消而误唤醒,须确认本节点确被取消)。
if ctx.node_status.is_cancelled(&ctx.node_id) {
return Err(anyhow::anyhow!("人工审批被取消"));
}