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
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ unic-langid = "0.9"
x25519-dalek = { version = "2.0", features = ["static_secrets"] }
aes-gcm = "0.10"
sha2 = "0.10"
minisign-verify = "0.2"
sha1 = "0.10"
argon2 = "0.5"
rand = "0.8"
Expand Down
4 changes: 2 additions & 2 deletions docs/interactive-capabilities/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ OpenBitFun Playbook currently contains **22 features**, **21 settings pages**, a
- Generated per-item interaction audit: `docs/interactive-capabilities/technical/product-control-open-audit.json`
- Generated low-level audit map: `docs/interactive-capabilities/technical/tauri-command-map.json`

说明书、网站、搜索和 Agent 只看“功能 + 设置 + 子能力”。每项子能力都必须引用已注册 Tauri Command 或可解析的源码标记;这些证据不会进入公开目录。当前 **662** 个 Tauri 命令只用于实现覆盖审计。产品 UI 交互源码会在生成和检查时扫描并校验,但不会保存成随普通 UI 改动频繁变化的版本化快照。
说明书、网站、搜索和 Agent 只看“功能 + 设置 + 子能力”。每项子能力都必须引用已注册 Tauri Command 或可解析的源码标记;这些证据不会进入公开目录。当前 **665** 个 Tauri 命令只用于实现覆盖审计。产品 UI 交互源码会在生成和检查时扫描并校验,但不会保存成随普通 UI 改动频繁变化的版本化快照。

Docs, website, search, and agents see only features, settings, and documented sub-capabilities. Every sub-capability must reference a registered Tauri command or a resolvable source marker; evidence is stripped from public projections. The **662** Tauri commands remain implementation-audit evidence only. Product UI interaction sources are scanned and validated during generation and checks, but are not stored as a versioned snapshot that churns with ordinary UI changes.
Docs, website, search, and agents see only features, settings, and documented sub-capabilities. Every sub-capability must reference a registered Tauri command or a resolvable source marker; evidence is stripped from public projections. The **665** Tauri commands remain implementation-audit evidence only. Product UI interaction sources are scanned and validated during generation and checks, but are not stored as a versioned snapshot that churns with ordinary UI changes.

## 控制边界 / Control boundary

Expand Down
14 changes: 7 additions & 7 deletions docs/interactive-capabilities/capabilities.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"title": "OpenBitFun Playbook",
"origin": "https://playbook.openbitfun.com",
"source": "src/shared/interactive-capabilities/catalog.json",
"digest": "c21d28e130de07890a2ebd6793cf78905c7749f577d8b8e547d9fe12a6e26a95",
"digest": "9973af8307e72206bb5c4af5dfb3249fef2def6a27925a13aca9a25ac62ef8a3",
"ownerDigest": "c0e5c187cf62bc6ed06196ce8520b3eb427bf268cf24659b72d2552fb1d99c54",
"searchAcceptance": [
{
Expand Down Expand Up @@ -24810,13 +24810,13 @@
},
{
"id": "manual-update",
"titleZh": "手动检查、下载并安装可用更新,然后按需重启",
"titleEn": "Check for, download, and install an available update manually, then restart when needed",
"titleZh": "手动检查并后台下载更新,确认后安装并重启,或稍后从关于页面安装",
"titleEn": "Check and download updates in the background, then confirm installation and restart or install later from About",
"control": {
"kind": "open",
"reasonCode": "unstructuredInteraction",
"reasonZh": "“手动检查、下载并安装可用更新,然后按需重启”由多个实时状态相关步骤组成,目前没有一个能确定完成整个流程的单一结构化 Command;Agent 会打开精确入口,并把后续交互保留在用户可见界面。",
"reasonEn": "“Check for, download, and install an available update manually, then restart when needed” spans multiple live-state-dependent steps and currently has no single structured Command that can deterministically complete the whole workflow; the Agent opens the exact entry and keeps the remaining interaction visible to the user."
"reasonZh": "“手动检查并后台下载更新,确认后安装并重启,或稍后从关于页面安装”需要下载后由用户确认安装与重启;Agent 会打开精确入口,并把后续交互保留在用户可见界面。",
"reasonEn": "“Check and download updates in the background, then confirm installation and restart or install later from About” requires user confirmation after downloading, before installation and restart; the Agent opens the exact entry and keeps the remaining interaction visible to the user."
}
},
{
Expand Down Expand Up @@ -25020,8 +25020,8 @@
"Completion, permission, and startup-tip notifications",
"启用或停用自动检查更新",
"Enable or disable automatic update checks",
"手动检查、下载并安装可用更新,然后按需重启",
"Check for, download, and install an available update manually, then restart when needed",
"手动检查并后台下载更新,确认后安装并重启,或稍后从关于页面安装",
"Check and download updates in the background, then confirm installation and restart or install later from About",
"控制 OpenBitFun 是否在登录系统后自动启动",
"Choose whether OpenBitFun launches automatically after system sign-in",
"控制 OpenBitFun 运行期间是否阻止电脑自动睡眠",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ Manage app-level preferences for startup, updates, close behavior, notifications

- **Agent 可直接控制 / Direct Agent control** · 启用或停用自动检查更新
- Enable or disable automatic update checks
- **Agent 可定位入口,需交互完成 / Agent opens; interaction required** · 手动检查、下载并安装可用更新,然后按需重启
- Check for, download, and install an available update manually, then restart when needed
- **Agent 可定位入口,需交互完成 / Agent opens; interaction required** · 手动检查并后台下载更新,确认后安装并重启,或稍后从关于页面安装
- Check and download updates in the background, then confirm installation and restart or install later from About
- **Agent 可直接控制 / Direct Agent control** · 控制 OpenBitFun 是否在登录系统后自动启动
- Choose whether OpenBitFun launches automatically after system sign-in
- **Agent 可直接控制 / Direct Agent control** · 控制 OpenBitFun 运行期间是否阻止电脑自动睡眠
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"schemaVersion": 1,
"generatedFrom": "src/shared/interactive-capabilities/catalog.json",
"catalogDigest": "c21d28e130de07890a2ebd6793cf78905c7749f577d8b8e547d9fe12a6e26a95",
"catalogDigest": "9973af8307e72206bb5c4af5dfb3249fef2def6a27925a13aca9a25ac62ef8a3",
"count": 211,
"reasonCounts": {
"externalAuth": 4,
Expand Down Expand Up @@ -2471,19 +2471,20 @@
{
"capabilityId": "setting.application.general",
"itemId": "manual-update",
"titleZh": "手动检查、下载并安装可用更新,然后按需重启",
"titleEn": "Check for, download, and install an available update manually, then restart when needed",
"titleZh": "手动检查并后台下载更新,确认后安装并重启,或稍后从关于页面安装",
"titleEn": "Check and download updates in the background, then confirm installation and restart or install later from About",
"reasonCode": "unstructuredInteraction",
"reasonZh": "“手动检查、下载并安装可用更新,然后按需重启”由多个实时状态相关步骤组成,目前没有一个能确定完成整个流程的单一结构化 Command;Agent 会打开精确入口,并把后续交互保留在用户可见界面。",
"reasonEn": "“Check for, download, and install an available update manually, then restart when needed” spans multiple live-state-dependent steps and currently has no single structured Command that can deterministically complete the whole workflow; the Agent opens the exact entry and keeps the remaining interaction visible to the user.",
"reasonZh": "“手动检查并后台下载更新,确认后安装并重启,或稍后从关于页面安装”需要下载后由用户确认安装与重启;Agent 会打开精确入口,并把后续交互保留在用户可见界面。",
"reasonEn": "“Check and download updates in the background, then confirm installation and restart or install later from About” requires user confirmation after downloading, before installation and restart; the Agent opens the exact entry and keeps the remaining interaction visible to the user.",
"presentationTarget": {
"kind": "settings",
"pageId": "application.general"
},
"evidence": [
"command:check_for_updates",
"command:install_update",
"command:restart_app",
"command:download_update",
"command:get_pending_update",
"command:install_pending_update",
"command:get_app_version"
]
},
Expand Down
68 changes: 56 additions & 12 deletions docs/interactive-capabilities/technical/tauri-command-map.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"schemaVersion": 2,
"generatedFrom": "src/shared/interactive-capabilities/catalog.json",
"catalogDigest": "c21d28e130de07890a2ebd6793cf78905c7749f577d8b8e547d9fe12a6e26a95",
"commandCount": 662,
"catalogDigest": "9973af8307e72206bb5c4af5dfb3249fef2def6a27925a13aca9a25ac62ef8a3",
"commandCount": 665,
"coverage": {
"commandCount": 662,
"documentedCommandCount": 631,
"implementationCommandCount": 31,
"implementationDigest": "859a3a3cb1e4e27ca38cd9003cef14e8758483ce85417a2c22c6ab92df9dd2c3"
"commandCount": 665,
"documentedCommandCount": 632,
"implementationCommandCount": 33,
"implementationDigest": "35539d9c1510287cb47f4a68fe35859b78f93bb06cd66b86e58d878a48d8c509"
},
"commands": [
{
Expand Down Expand Up @@ -2290,6 +2290,22 @@
"signature": "fn download_skill_market( _state: State<'_, AppState>, request: SkillMarketDownloadRequest, ) -> Result<SkillMarketDownloadResponse, String>",
"remoteWorkspacePolicy": "LegacyUnaudited"
},
{
"id": "download_update",
"moduleId": "update",
"capabilityId": "setting.application.general",
"capabilityIds": [
"setting.application.general"
],
"documentedItemIds": [
"setting.application.general:manual-update"
],
"visibility": "documented",
"rustPath": "api::update_api::download_update",
"sourceFile": "src/apps/desktop/src/api/update_api.rs",
"signature": "fn download_update( app: AppHandle, request: PendingUpdateRequest, ) -> Result<PendingUpdateResponse, String>",
"remoteWorkspacePolicy": "WorkspaceAgnostic"
},
{
"id": "editor_ai_cancel",
"moduleId": "editor_ai",
Expand Down Expand Up @@ -3509,6 +3525,22 @@
"signature": "fn get_pending_announcements( state: State<'_, AppState>, ) -> Result<Vec<AnnouncementCard>, String>",
"remoteWorkspacePolicy": "WorkspaceAgnostic"
},
{
"id": "get_pending_update",
"moduleId": "update",
"capabilityId": "setting.application.general",
"capabilityIds": [
"setting.application.general"
],
"documentedItemIds": [
"setting.application.general:manual-update"
],
"visibility": "documented",
"rustPath": "api::update_api::get_pending_update",
"sourceFile": "src/apps/desktop/src/api/update_api.rs",
"signature": "fn get_pending_update( app: AppHandle, request: PendingUpdateRequest, ) -> Result<Option<PendingUpdateResponse>, String>",
"remoteWorkspacePolicy": "WorkspaceAgnostic"
},
{
"id": "get_prevent_sleep_enabled",
"moduleId": "sleep_prevention",
Expand Down Expand Up @@ -4780,8 +4812,8 @@
"remoteWorkspacePolicy": "LegacyUnaudited"
},
{
"id": "install_update",
"moduleId": "system",
"id": "install_pending_update",
"moduleId": "update",
"capabilityId": "setting.application.general",
"capabilityIds": [
"setting.application.general"
Expand All @@ -4790,6 +4822,20 @@
"setting.application.general:manual-update"
],
"visibility": "documented",
"rustPath": "api::update_api::install_pending_update",
"sourceFile": "src/apps/desktop/src/api/update_api.rs",
"signature": "fn install_pending_update( app: AppHandle, request: InstallPendingUpdateRequest, ) -> Result<(), String>",
"remoteWorkspacePolicy": "WorkspaceAgnostic"
},
{
"id": "install_update",
"moduleId": "system",
"capabilityId": "setting.application.general",
"capabilityIds": [
"setting.application.general"
],
"documentedItemIds": [],
"visibility": "implementation",
"rustPath": "install_update",
"sourceFile": "src/apps/desktop/src/api/system_api.rs",
"signature": "fn install_update(app: AppHandle, request: InstallUpdateRequest) -> Result<(), String>",
Expand Down Expand Up @@ -7790,10 +7836,8 @@
"capabilityIds": [
"setting.application.general"
],
"documentedItemIds": [
"setting.application.general:manual-update"
],
"visibility": "documented",
"documentedItemIds": [],
"visibility": "implementation",
"rustPath": "restart_app",
"sourceFile": "src/apps/desktop/src/api/system_api.rs",
"signature": "fn restart_app(app: AppHandle, request: RestartAppRequest) -> Result<(), String>",
Expand Down
5 changes: 5 additions & 0 deletions src/apps/desktop/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ The `devtools` Cargo feature exists for debugging UI/UX in the desktop app. When
cargo check -p openbitfun-desktop && cargo test -p openbitfun-desktop
```

For staged application-update cache and signature behavior, use
`cargo test -p openbitfun-desktop --lib api::update_api::tests`.
After changing updater command registration, also run
`cargo test -p openbitfun-desktop --lib remote_workspace_policy`.

If the change affects startup, WebDriver, browser/computer-use, or packaged behavior, also run:

```bash
Expand Down
1 change: 1 addition & 0 deletions src/apps/desktop/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ axum = { workspace = true }
tower-http = { workspace = true, features = ["fs"] }
sha1 = { workspace = true }
sha2 = { workspace = true }
minisign-verify = { workspace = true }
screenshots = { workspace = true }
enigo = { workspace = true }
image = { workspace = true, features = ["jpeg", "png"] }
Expand Down
27 changes: 27 additions & 0 deletions src/apps/desktop/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# OpenBitFun Desktop

For development commands, see [AGENTS.md](AGENTS.md) and the repository
[contribution guide](../../../CONTRIBUTING.md).

## Application updates

Choose **Background download** in the new-version dialog to download and verify
an update while continuing to use OpenBitFun. Downloading does not install the
update or restart the application.

When the download finishes, OpenBitFun offers **Install and restart** or
**Later**. Installation restarts OpenBitFun on this device and interrupts its
active sessions. Choosing Later, or closing the dialog, keeps the downloaded
update. Open **About → Install and restart** whenever you are ready; the same
confirmation appears before installation.

Downloaded updates remain available after closing and reopening OpenBitFun.
After reopening, the current updater requires access to the update server to
restore installer metadata, but does not download the package again. If this
step or installation fails, the pending update remains available to retry.
Use **Download again** in the error dialog if the cached package is damaged.

Application updates always belong to the local desktop, including while viewing
a peer device or a remote workspace. They do not install software on the peer or
cancel independently running detached jobs on another host. Connections through
the restarting desktop are interrupted.
1 change: 1 addition & 0 deletions src/apps/desktop/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub mod system_api;
pub mod terminal_api;
pub mod token_usage_api;
pub mod tool_api;
pub mod update_api;
pub mod workspace_activation;
pub mod worktree_api;

Expand Down
17 changes: 12 additions & 5 deletions src/apps/desktop/src/api/system_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,9 @@ async fn probe_endpoint_throughput(client: &reqwest::Client, url: &str) -> u64 {

/// Build an updater whose endpoints are ordered by measured throughput.
/// Falls back to the bundled configuration if the builder rejects them.
async fn ranked_updater(app: &AppHandle) -> Result<tauri_plugin_updater::Updater, String> {
pub(super) async fn ranked_updater(
app: &AppHandle,
) -> Result<tauri_plugin_updater::Updater, String> {
let endpoints = updater_endpoints_by_policy().await;
let builder = app.updater_builder();
let builder = match builder.endpoints(endpoints) {
Expand All @@ -218,7 +220,9 @@ async fn ranked_updater(app: &AppHandle) -> Result<tauri_plugin_updater::Updater
app.updater_builder()
}
};
builder.build().map_err(|error| error.to_string())
crate::api::update_api::with_update_exit_cleanup(builder, app)
.build()
.map_err(|error| error.to_string())
}

#[derive(Clone, serde::Serialize)]
Expand Down Expand Up @@ -319,8 +323,8 @@ pub async fn install_update(app: AppHandle, request: InstallUpdateRequest) -> Re
let progress = Arc::new(Mutex::new((0u64, None::<u64>)));
let progress_chunk = Arc::clone(&progress);
let app_chunk = app_handle.clone();
update
.download_and_install(
let bytes = update
.download(
move |chunk_len, content_len| {
let (downloaded, total) = {
let mut g = progress_chunk
Expand Down Expand Up @@ -353,7 +357,10 @@ pub async fn install_update(app: AppHandle, request: InstallUpdateRequest) -> Re
},
)
.await
.map_err(|e| e.to_string())
.map_err(|e| e.to_string())?;
tokio::task::spawn_blocking(move || update.install(bytes).map_err(|e| e.to_string()))
.await
.map_err(|e| e.to_string())?
}

#[derive(Debug, Deserialize)]
Expand Down
Loading
Loading