diff --git a/.github/RELEASE_TEMPLATE.md b/.github/RELEASE_TEMPLATE.md index e34fefc..c1973e5 100644 --- a/.github/RELEASE_TEMPLATE.md +++ b/.github/RELEASE_TEMPLATE.md @@ -7,7 +7,8 @@ - 设置页新增「自动更新」和「测试计划」:默认自动检查正式版,开启测试计划后可接收 RC,关闭自动更新时仍可手动检查正式版。 - 按已保存的通道选择已发布 Release,并核对版本和更新资产;正式版通道不会提示 RC。 - 下载和安装仍需在版本提示中由用户点击「确认更新」,检查时只获取版本清单。 -- 已安装旧版使用固定的正式版地址,需从 Releases 手动安装本版一次,之后才能选择测试计划。 +- RC 发布列表扫描设置总超时;模型添加、测试、预览、应用与恢复经过隔离验收。 +- `rc.2` 及更早版本使用固定的正式版地址,需从 Releases 手动安装支持测试计划的版本;已开启测试计划的 `rc.3` 可在应用内升级到本版。 ### 下载选择 @@ -28,7 +29,7 @@ - 当前安装包未使用开发者证书签名或 Apple 公证,系统可能提示未知发布者或阻止首次打开。请先确认下载来源并核对校验值。 - Windows 需要 WebView2 Runtime;MSI 可引导安装,ZIP 需要预先安装。ZIP 仍将数据保存在当前用户应用目录,不能视为数据随身携带的便携版,也不保证注册 `power-switch://` 协议。 - Linux AppImage 需赋予执行权限;部分发行版还需要 FUSE。DEB/RPM 会声明所需的系统依赖。 -- 此 RC 预发布不会进入正式版 Latest 更新通道。支持「测试计划」的客户端启用该选项后可收到 RC 提示;旧版客户端仍需从 Releases 手动安装一次。 +- 此 RC 预发布不会进入正式版 Latest 更新通道。支持「测试计划」的客户端启用该选项后可收到 RC 提示;`rc.2` 及更早版本需从 Releases 手动安装一次。 - 检查更新只读取版本清单,下载安装需要在应用内再次确认。 - 云端构建与测试通过不代表所有平台均完成真实机器安装验收。 diff --git a/README.md b/README.md index a2a99f8..c7bfaa3 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,9 @@ WorkBuddy 写入成功后可以打开新建任务页,请在 WorkBuddy 中手 恢复前会再次备份当前配置,避免误操作后无法返回。 -## 设置配置文件位置 +## 设置配置位置 -在“设置”中可以修改各 Agent 的配置文件位置。默认位置如下: +在“设置”中可以修改 WorkBuddy、Claude Code 的配置文件位置和 Codex 的配置目录。默认位置如下: | Agent | 默认位置 | | ----------- | ------------------------------------- | diff --git a/docs/new-api.md b/docs/new-api.md index 78d0038..72cd262 100644 --- a/docs/new-api.md +++ b/docs/new-api.md @@ -6,7 +6,7 @@ power-switch 内置 New API 接入模块,默认地址为 `https://new-api.banm 1. 可先点击应用顶栏的 **新手指引**,通过三步动画了解申请密钥、模型入库和应用到 Agent 的流程。随后在模型库点击橙色 **从 New API 添加**。实例地址应为 HTTPS 根地址,不包含 `/v1`,且与 New API 的 `ServerAddress` 一致。 2. 点击 **钉钉 / Keycloak 登录**,在独立窗口完成授权。应用不会读取或保存钉钉密码。 -3. 选择目前客户端、平台名称和模型。接口固定使用 `default` 分组,无需在页面选择。列表只显示该分组可用的模型,并按服务端元数据筛选;对 Codex,`openai` 模型也会作为 Responses 候选,是否真正兼容由保存前的调用确认。默认优先选中 `auto`;没有兼容的 `auto` 时选择第一个可用模型。平台名称默认为 `winwin`,可自行修改,切换模型时保留。 +3. 选择目标客户端、平台名称和模型。接口固定使用 `default` 分组,无需在页面选择。列表只显示该分组可用的模型,并按服务端元数据筛选;对 Codex,`openai` 模型也会作为 Responses 候选,是否真正兼容由保存前的调用确认。默认优先选中 `auto`;没有兼容的 `auto` 时选择第一个可用模型。平台名称默认为 `winwin`,可自行修改,切换模型时保留。 4. 按上游实际能力设置图像、工具调用和推理档位,不能从模型别名推断。 5. 点击 **创建并添加**。同一实例、同一账号创建或复用一把 power-switch 专属密钥,不设置模型限制;首次创建使用 `default` 分组决定密钥的实际访问范围。应用先检查所选模型是否可访问,再发送一次模型调用;只有收到所选协议的有效文本回复才保存到模型库。调用可能消耗账户额度;失败时密钥可能已创建,重试会复用。 6. 可主动显示或复制密钥。保存后按需点击 **测试连接** 可再次调用模型;测试只确认基本文本调用及响应格式,不证明工具调用、图像、流式或上下文能力。应用到 Agent 时只预览并写入配置,不重复调用模型。 diff --git a/package.json b/package.json index b584c36..dbc4d4c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "power-switch", "private": true, - "version": "0.1.6-rc.3", + "version": "0.1.6-rc.4", "type": "module", "packageManager": "pnpm@10.18.3", "pnpm": { diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 59ac7fe..d85da55 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2976,7 +2976,7 @@ dependencies = [ [[package]] name = "power-switch" -version = "0.1.6-rc.3" +version = "0.1.6-rc.4" dependencies = [ "base64 0.22.1", "dirs", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 33d6137..0bc3246 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "power-switch" -version = "0.1.6-rc.3" +version = "0.1.6-rc.4" description = "Local model configuration switcher for coding agents" edition = "2021" rust-version = "1.92" diff --git a/src-tauri/src/update_desktop.rs b/src-tauri/src/update_desktop.rs index 25bee93..f8df23c 100644 --- a/src-tauri/src/update_desktop.rs +++ b/src-tauri/src/update_desktop.rs @@ -106,32 +106,36 @@ fn manifest_url(release: &GithubRelease) -> AppResult { Url::parse(&manifest.browser_download_url).map_err(|_| "更新清单地址无效".into()) } -/// List published releases through the official API so RC builds can be found without changing the stable feed. +/// Bound the complete GitHub release scan so pagination cannot leave update checks hanging. async fn github_releases() -> AppResult> { let client = reqwest::Client::builder() - .timeout(Duration::from_secs(30)) + .timeout(Duration::from_secs(15)) .user_agent("power-switch-updater") .build() .map_err(|error| format!("无法初始化更新检查:{error}"))?; - let mut releases = Vec::new(); - for page in 1..=10 { - let batch: Vec = client - .get(format!("{RELEASES_API}?per_page=100&page={page}")) - .header("Accept", "application/vnd.github+json") - .send() - .await - .and_then(reqwest::Response::error_for_status) - .map_err(|error| format!("无法获取 GitHub 发布列表:{error}"))? - .json() - .await - .map_err(|error| format!("无法解析 GitHub 发布列表:{error}"))?; - let count = batch.len(); - releases.extend(batch); - if count < 100 { - return Ok(releases); + tokio::time::timeout(Duration::from_secs(30), async { + let mut releases = Vec::new(); + for page in 1..=10 { + let batch: Vec = client + .get(format!("{RELEASES_API}?per_page=100&page={page}")) + .header("Accept", "application/vnd.github+json") + .send() + .await + .and_then(reqwest::Response::error_for_status) + .map_err(|error| format!("无法获取 GitHub 发布列表:{error}"))? + .json() + .await + .map_err(|error| format!("无法解析 GitHub 发布列表:{error}"))?; + let count = batch.len(); + releases.extend(batch); + if count < 100 { + return Ok(releases); + } } - } - Err("发布列表过长,无法安全判断最新版本".into()) + Err("发布列表过长,无法安全判断最新版本".into()) + }) + .await + .map_err(|_| "获取 GitHub 发布列表超时,请稍后重试".to_string())? } /// Let Tauri parse the signed manifest and compare it with this installed app version. diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index ee58997..0649c1e 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "power-switch", - "version": "0.1.6-rc.3", + "version": "0.1.6-rc.4", "identifier": "com.powerswitch.desktop", "build": { "beforeDevCommand": "pnpm dev:web", @@ -30,7 +30,7 @@ "targets": "all", "windows": { "wix": { - "version": "0.1.6.3" + "version": "0.1.6.4" } }, "shortDescription": "模型随心切换", diff --git a/src/App.tsx b/src/App.tsx index bd968f1..fc1206b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -562,26 +562,6 @@ export default function App() { )} - {notice && ( -
- {notice.kind === "success" ? ( - - ) : ( - - )} - {notice.text} - -
- )} {!data ? (
@@ -1037,6 +1017,26 @@ export default function App() {
+ {notice && ( +
+ {notice.kind === "success" ? ( + + ) : ( + + )} + {notice.text} + +
+ )} {modal?.kind === "guide" && (