Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/RELEASE_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

### 本次更新

- Codex 模型配置支持经验证的 Responses 协议写入;复制模型后可直接测试并保存。
- 设置页提供「自动更新」和「测试计划」:默认检查正式版;开启测试计划后可接收 RC,关闭自动检查后仍可手动检查正式版。
- 更新提示显示在侧边栏版本号旁;检查只读取清单,下载和安装仍需用户确认。
- 优化模型、主题与界面细节,并补充跨平台自动化检查。
- 应用本地数据统一保存到用户目录的 `.power-switch`,包括模型、API Key、New API 登录会话与备份;所有凭据按当前设计明文保存。旧数据目录和系统凭据库不会自动读取或迁移,升级后需要重新添加模型并登录 New API。
- 下载更新清单与安装包时优先使用 `ghfast.top`,加速源不可用时回退 GitHub 原地址;更新包继续验签。
- 优化添加模型弹窗的固定标题栏、设置界面与交互细节。
- 覆盖模型保存、New API 会话持久化和跨平台构建的自动化检查。
- Microsoft Store MSIX 打包流程已经准备好,但商店包须在产品名称预留、包标识配置及商店审核后另行提供;此处下载的是 GitHub 分发版。

### 下载选择
Expand All @@ -27,7 +27,7 @@
### 安装须知

- 当前安装包未使用开发者证书签名或 Apple 公证,系统可能提示未知发布者或阻止首次打开。请先确认下载来源并核对校验值。
- Windows 需要 WebView2 Runtime;MSI 可引导安装,ZIP 需要预先安装。ZIP 仍将数据保存在当前用户应用目录,不能视为数据随身携带的便携版,也不保证注册 `power-switch://` 协议。
- Windows 需要 WebView2 Runtime;MSI 可引导安装,ZIP 需要预先安装。ZIP 仍将数据保存在当前用户的 `.power-switch` 目录,不能视为数据随身携带的便携版,也不保证注册 `power-switch://` 协议。
- Linux AppImage 需赋予执行权限;部分发行版还需要 FUSE。DEB/RPM 会声明所需的系统依赖。
- 流水线先将本版发布为预发布;完成验证并提升为正式版后,才会进入 Latest 更新通道。已安装的正式版客户端届时可检查到本版。
- 检查更新只读取版本清单,下载安装需要在应用内再次确认。
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ WorkBuddy 写入成功后可以打开新建任务页,请在 WorkBuddy 中手

恢复前会再次备份当前配置,避免误操作后无法返回。

## 本地数据目录

macOS、Linux 使用 `$HOME/.power-switch`,Windows 使用 `%USERPROFILE%\.power-switch`。设置页会显示实际路径。目录中的 `models.json` 保存模型、API Key 和应用设置;`new-api.json` 保存密钥创建恢复记录;`new-api/sessions/` 保存 New API 登录会话;`backups/` 保存应用配置前的原始快照。`skill-staging/` 只用于技能安装期间的临时文件,`.lock` 用于防止多个进程同时写入。

以上凭据和快照均为**明文**,请按敏感数据保护整个目录。应用只读写这个新目录,不会读取、迁移或删除旧应用数据目录与旧系统凭据库条目;升级后需要重新添加旧模型并登录 New API。应用到 Agent 时,仍会写入各 Agent 自己的配置文件。

## 设置配置位置

在“设置”中可以修改 WorkBuddy、Claude Code 的配置文件位置和 Codex 的配置目录。默认位置如下:
Expand All @@ -81,7 +87,7 @@ Codex 使用 OpenAI Responses 协议。手动添加时,所选模型必须由

## 安全说明

- 模型和 API Key 只保存在本机。
- 模型、API Key、New API 登录会话和备份均以明文保存在本机用户目录。
- API Key 以本地配置形式保存,请不要分享模型文件、备份文件或带密钥的分享链接。
- 保存模型不会自动修改 Agent;必须经过“应用到 Agent”并确认后才会写入。
- 删除模型库记录不会撤销服务商上的密钥,需要时请到服务商控制台操作。
Expand Down
6 changes: 3 additions & 3 deletions docs/new-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ Codex 只接受 OpenAI Responses。当前 New API 实例的 `/api/pricing` 对 `

## 存储与恢复

- macOS 登录会话只保存在系统钥匙串的 `com.powerswitch.desktop.new-api` 服务内,按实例地址隔离;Windows 使用系统凭证存储。其他平台暂不支持持久登录,绝不降级为明文会话文件。旧 Cookie 记录在验证身份后迁移到新存储格式,不按其中的版本号拒绝。
- macOS、Windows、Linux 均将登录会话明文保存在用户目录的 `.power-switch/new-api/sessions/`。每个规范化实例地址对应一个以 SHA-256 命名的 JSON 文件,文件内记录格式版本、实例地址和会话;读取时校验实例。系统钥匙串及旧应用数据目录中的记录不再读取或迁移,升级后需要重新登录。
- 本机会话最长保留 30 天;新流程也受服务端会话到期时间约束。启动恢复时核对身份,Bearer 临近到期时使用仅限 `/api/user/auth` 路径的刷新 Cookie 续期。会话失效后重新登录,已创建的模型密钥独立有效。
- API Key 沿用 `models.json` 的本机私有存储。管理会话、授权码和完整远端响应不写日志、分享链接或错误提示。
- `new-api.json` 只保存账号 ID、实例、首次创建分组、令牌名称与 ID、创建前同名令牌的 ID,以及每个关联模型的模型 ID、协议和稳定本地 ID。Unix 文件权限为 `0600`。**请保留此文件**,它负责识别已有密钥并恢复未完成操作。
- API Key 明文保存在 `.power-switch/models.json`,应用设置也在此文件中;配置快照明文保存在 `.power-switch/backups/`。这些文件和会话文件都包含敏感信息,复制或备份整个目录时应按凭据处理。管理会话、授权码和完整远端响应不写日志、分享链接或错误提示。
- `.power-switch/new-api.json` 只保存账号 ID、实例、首次创建分组、令牌名称与 ID、创建前同名令牌的 ID,以及每个关联模型的模型 ID、协议和稳定本地 ID。Unix 目录权限为 `0700`、文件权限为 `0600`;Windows 使用仅当前用户和 SYSTEM 可访问的受保护 ACL。**请保留此文件**,它负责识别已有密钥并恢复未完成操作。
- 同一用户的不同令牌允许使用相同的姓名拼音名称。创建前记录已存在的同名令牌 ID,再写入 `submitted` 记录;恢复时排除旧 ID,核对账号、首次分组及无限制设置,已有绑定按令牌 ID 识别。旧版恢复记录可读,升级后保留为迁移来源。
- 崩溃、断网或响应丢失后先恢复查询,不自动重发无法确认结果的创建请求。可先点击 **重新检查并继续**;只有用户核对服务端列表并勾选允许重新创建时,才启动新的创建操作。
- 重复导入复用密钥和本地模型 ID;同一实例、同一账号的模型与协议共用一把密钥。其他分组的模型若不在共享密钥的 `/v1/models` 清单中,导入会停止并提示调整分组权限。用户主动更换失效密钥时,同步更新本机仍指向原接口的关联模型;已写入 Agent 的配置需重新预览应用。
Expand Down
9 changes: 5 additions & 4 deletions docs/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Store 版与 GitHub MSI/ZIP 版是两个分发渠道。Store 版使用 MSIX,

这些是公开包标识,不是签名私钥。Store 工作流在缺少任何值或使用 RC 标签时提前失败。仅在正式版标签已进入 `master` 历史后,手动运行 Actions 中的 **Microsoft Store MSIX**,输入例如 `v0.1.6`。工作流执行现有质量检查,分别产出 x64、ARM64 的 `store-windows-*` 工件。`MakeAppx` 生成的包未签名,只供 Partner Center 提交。应用版本 `0.1.6` 映射为 Store 包版本 `1.1.6.0`;映射固定为 `(major + 1).minor.patch.0`,确保 Store 要求的首段非零、末段为零,并保持跨版本递增。

上传前检查两个包的清单身份与架构,使用 Windows App Certification Kit 检验。在 Partner Center 审核和重新签名完成后,通过 **Microsoft Store 页面**安装到干净的 Windows 11 x64、ARM64 机器,测试启动、模型添加与应用、`power-switch://` 导入、本地数据和商店升级。商店版不会检查或安装 GitHub MSI;设置中会显示商店更新说明。现有 GitHub 安装用户改装商店版时,还要核对模型与密钥能否从原 AppData 路径读取,因为 MSIX 可能虚拟化新建文件。确认产品页可用后再把 README 的 Windows 首选入口改为商店链接。
上传前检查两个包的清单身份与架构,使用 Windows App Certification Kit 检验。在 Partner Center 审核和重新签名完成后,通过 **Microsoft Store 页面**安装到干净的 Windows 11 x64、ARM64 机器,测试启动、模型添加与应用、`power-switch://` 导入、本地数据和商店升级。商店版不会检查或安装 GitHub MSI;设置中会显示商店更新说明。现有 GitHub 安装用户改装商店版时,应确认模型与密钥从 `%USERPROFILE%\.power-switch` 读取;旧 AppData 目录不会被读取或迁移。还应在 MSIX 包中实测新目录的写入与 ACL,因为 MSIX 可能虚拟化新建文件。确认产品页可用后再把 README 的 Windows 首选入口改为商店链接。

维护者本机需要 Git SSH 推送权限。查看私有仓库 Actions、修改默认分支及管理 Release 时,还需 GitHub CLI 登录:

Expand All @@ -54,7 +54,7 @@ gh repo edit winwin-inc/power-switch --default-branch master

CI 使用 Node.js 22、pnpm 10.18.3、Rust 1.92.0。前端依赖采用 `--frozen-lockfile`,Rust 检查、测试和发布构建采用 `--locked`。

Windows Installer 只比较 MSI `ProductVersion` 的前三段,[第四段不参与升级比较](https://learn.microsoft.com/en-us/windows/win32/msi/productversion)。已发布的 `v0.1.6-rc.4` 安装包设置为 `0.1.6.4`,因此正式版 `v0.1.6` 的 WiX 版本使用 `0.1.7.0`,确保 MSI 升级序列实际递增;应用本身仍显示 `0.1.6`。后续 Windows 版本必须使前三段高于 `0.1.7`,不能只增加第四段。发布前应在 Windows 上验证从上一版 MSI 升级。
Windows Installer 只比较 MSI `ProductVersion` 的前三段,[第四段不参与升级比较](https://learn.microsoft.com/en-us/windows/win32/msi/productversion)。已发布的 `v0.1.6-rc.4` 安装包设置为 `0.1.6.4`,正式版 `v0.1.6` 使用 `0.1.7.0`;`v0.1.7` 的 WiX 版本使用 `0.1.8.0`,确保 MSI 升级序列实际递增,应用本身仍显示 `0.1.7`。后续 Windows 版本必须使前三段高于 `0.1.8`,不能只增加第四段。发布前应在 Windows 上验证从上一版 MSI 升级。

## 准备一个版本

Expand Down Expand Up @@ -151,9 +151,10 @@ shasum -a 256 -c SHA256SUMS
Windows 可执行 `Get-FileHash .\power-switch-v0.1.0-windows-x64.msi -Algorithm SHA256`,将结果与 `SHA256SUMS` 同名记录比较。

- macOS DMG 和 ZIP 中的应用均为通用二进制,构建时通过 `lipo` 校验 Intel 与 ARM64 架构。首版没有 Apple 开发者签名和公证;可能只有构建工具所需的临时签名。确认来源与校验值后,可在系统“隐私与安全性”查看允许打开的选项,不要关闭系统的全局安全检查。
- Windows MSI 可引导安装 WebView2 并完成安装注册。ZIP 只包含应用可执行文件,需预装 WebView2;数据仍保存在用户应用目录,不保证注册 `power-switch://` 导入协议。系统可能显示未知发布者提示。
- Linux AppImage 使用前需 `chmod +x`,部分发行版需要 FUSE;DEB/RPM 由系统包管理器安装。当前 New API 登录的系统凭证持久化仅实现 macOS/Windows,Linux 的此功能限制不因打包而改变。
- Windows MSI 可引导安装 WebView2 并完成安装注册。ZIP 只包含应用可执行文件,需预装 WebView2;数据仍保存在 `%USERPROFILE%\.power-switch`,不保证注册 `power-switch://` 导入协议。系统可能显示未知发布者提示。
- Linux AppImage 使用前需 `chmod +x`,部分发行版需要 FUSE;DEB/RPM 由系统包管理器安装。New API 登录会话在三个桌面系统中均明文保存在用户目录的 `.power-switch/new-api/sessions/`。
- 默认在启动时检查 GitHub 最新正式版;「测试计划」开启后还会检查已发布的 RC。关闭「自动更新」则跳过启动检查,设置页的「检查更新」仍可使用正式版通道。检查只读取清单,用户确认后才下载。安装后 macOS/Linux 可点击重启;Windows 安装器会自动关闭应用,安装完成后重新打开应用。
- 更新清单与安装包优先通过 `https://ghfast.top/` 加速读取;加速源请求、解析或安装包验签失败时,客户端重试原始 GitHub Release 地址。发布清单仍记录原始 GitHub URL,更新包始终按内置公钥验签。
- 已安装的旧版客户端仍使用固定的 Latest 正式版地址,无法从远端获得新的通道设置;需要手动安装一次支持「测试计划」的版本,之后才可选择接收 RC。

## 重跑、正式发布与故障处理
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "power-switch",
"private": true,
"version": "0.1.6",
"version": "0.1.7",
"type": "module",
"packageManager": "pnpm@10.18.3",
"pnpm": {
Expand Down
35 changes: 4 additions & 31 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "power-switch"
version = "0.1.6"
version = "0.1.7"
description = "Local model configuration switcher for coding agents"
edition = "2021"
rust-version = "1.92"
Expand Down Expand Up @@ -52,11 +52,8 @@ tauri-plugin-process = { version = "2.3.1", optional = true }
[dev-dependencies]
wiremock = "0.6"

[target.'cfg(target_os = "macos")'.dependencies]
keyring = { version = "3", features = ["apple-native"] }

[target.'cfg(target_os = "windows")'.dependencies]
keyring = { version = "3", features = ["windows-native"] }
windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_Security", "Win32_Security_Authorization", "Win32_System_Threading"] }

[profile.release]
lto = "thin"
Expand Down
9 changes: 8 additions & 1 deletion src-tauri/src/desktop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ fn delete_model(state: Shared<'_>, id: String) -> AppResult<()> {
fn save_settings(state: Shared<'_>, settings: Settings) -> AppResult<()> {
with_engine(state, |e| e.settings(settings))
}
/// Update only the last checked New API address, keeping other settings intact.
#[tauri::command]
fn save_new_api_url(state: Shared<'_>, url: String) -> AppResult<()> {
with_engine(state, |e| e.new_api_url(url))
}
/// Prepare a model application for user review.
#[tauri::command]
fn preview_apply(
Expand Down Expand Up @@ -287,8 +292,9 @@ pub fn run() {
.plugin(tauri_plugin_process::init())
.setup(|app| {
let paths = Paths::discover().map_err(std::io::Error::other)?;
crate::new_api_desktop::setup(app.handle(), paths.data.clone());
let data = paths.data.clone();
let engine = Engine::open(paths).map_err(std::io::Error::other)?;
crate::new_api_desktop::setup(app.handle(), data);
app.manage(Mutex::new(engine));
app.manage(Mutex::new(VerifiedModels::default()));
app.manage(Mutex::new(crate::skills::SkillManager::default()));
Expand Down Expand Up @@ -316,6 +322,7 @@ pub fn run() {
list_models,
delete_model,
save_settings,
save_new_api_url,
preview_apply,
apply_preview,
cancel_preview,
Expand Down
Loading
Loading