From 0e0d5a4e9b32ed8751835ab1fbcba6388ff3ceb2 Mon Sep 17 00:00:00 2001
From: try2love <1929706911@qq.com>
Date: Sun, 11 Oct 2026 19:30:45 +0800
Subject: [PATCH 1/2] release: integrate PR24 compatibility and chat list
improvements for v2.0.2
Adapt PR #24 to current workspace and authentication boundaries, extend login startup and mobile system colors across platforms, and improve automatic chat-list pagination and pull-to-refresh.
Co-authored-by: heiqiu47 <64836651+heiqiu47@users.noreply.github.com>
---
ARCHITECTURE.md | 6 +-
README.md | 28 +++----
README_EN.md | 28 +++----
RELEASE_NOTES.md | 24 ++++++
bridge/api/httpd.py | 6 +-
bridge/app/service.py | 8 +-
bridge/features/workspace/files.py | 40 +++++++--
desktop/index.html | 2 +-
desktop/login-startup.cjs | 78 ++++++++++++++++++
desktop/main.cjs | 32 +++++---
desktop/shell/renderer.js | 11 ++-
docs/desktop-updates.md | 2 +-
mobile/README.md | 4 +-
mobile/android-push/AndroidManifest.xml | 6 +-
mobile/android-push/build.gradle | 2 +-
mobile/android/AndroidManifest.xml | 4 +-
.../try2love/codexbridge/DownloadCard.java | 18 +++--
.../codexbridge/DownloadProvider.java | 60 ++++++++++++++
.../try2love/codexbridge/MainActivity.java | 32 ++++++--
.../try2love/codexbridge/MobileStrings.java | 4 +
.../codexbridge/MobileWebScripts.java | 2 +-
.../try2love/codexbridge/SystemBars.java | 54 +++++++++++++
mobile/ios/BridgeActivity/Info.plist | 4 +-
mobile/ios/BridgeNotifications/Info.plist | 4 +-
.../BridgePreview.xcodeproj/project.pbxproj | 5 +-
mobile/ios/BridgePreview/App.swift | 69 ++++++++++++++--
mobile/ios/BridgePreview/Info.plist | 6 +-
mobile/ios/BridgePreview/WebScripts.swift | 2 +
mobile/shared/AGENTS.md | 2 +-
mobile/shared/web/mobile-system-bars.js | 48 +++++++++++
mobile/tests/resources.test.cjs | 11 ++-
mobile/tests/system-bars.test.cjs | 28 +++++++
package-lock.json | 4 +-
package.json | 2 +-
scripts/build-mobile-android.py | 6 +-
scripts/build-mobile-ios.py | 3 +-
scripts/smoke-windows.cjs | 31 ++++++-
site/index.html | 20 ++---
site/setup.html | 2 +-
tests/browser/list-sync-ui.browser.js | 9 ++-
tests/browser/markdown.browser.js | 16 ++++
tests/desktop.test.cjs | 71 +++++++++++++++-
tests/list-sync.test.cjs | 61 ++++++++++++++
tests/login-startup.test.cjs | 49 +++++++++++
tests/notifications-ui.test.cjs | 81 +++++++++++++++++--
tests/test_artifact_compatibility.py | 59 ++++++++++++++
tests/test_download_ranges.py | 21 +++++
tests/test_mobile_ios_build.py | 2 +-
web/features/chat/list-sync.js | 52 +++++++++---
web/features/workspace/workbench.css | 7 +-
web/index.html | 2 +-
web/shared/i18n.js | 7 ++
web/shared/markdown.js | 16 +++-
web/shell/app.js | 31 +++++--
54 files changed, 1028 insertions(+), 154 deletions(-)
create mode 100644 desktop/login-startup.cjs
create mode 100644 mobile/android/src/io/github/try2love/codexbridge/DownloadProvider.java
create mode 100644 mobile/android/src/io/github/try2love/codexbridge/SystemBars.java
create mode 100644 mobile/shared/web/mobile-system-bars.js
create mode 100644 mobile/tests/system-bars.test.cjs
create mode 100644 tests/list-sync.test.cjs
create mode 100644 tests/login-startup.test.cjs
create mode 100644 tests/test_artifact_compatibility.py
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index 0a2a844f..4cee6f99 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -30,7 +30,9 @@ HTTP 阅读请求先返回,保存历史和实时连接在后台加载,通过
SSH 参数包含非交互认证、严格主机指纹检查和禁用额外转发。远端模型/Skill 目录由远端 Codex 运行时读取,不复用 本机文件路径。
-本地与远端列表在合并后按最近交互时间排序、分页。项目优先采用显式归属,其次按最长工作目录前缀匹配。项目键带主机 ID,避免同名项目相互混淆。
+本地与远端列表在合并后按最近交互时间排序、分页。Codex 聊天列表每批读取 100 条,接近底部时自动续载;失败保留已加载内容,再次向下滚动可重试。项目优先采用显式归属,其次按最长工作目录前缀匹配。项目键带主机 ID,避免同名项目相互混淆。
+
+Codex 列表下拉刷新使用浮层提示与按动画帧更新的位移,不改变滚动区域高度;拖动期间暂停自动刷新。成功提示停留 500 毫秒后淡出,失败保留点击重试。列表展示内容未变化时保留已有聊天节点。
## 新建聊天
@@ -98,7 +100,7 @@ Windows 自动发现用户目录中的 App 运行时、常见安装目录、MSIX
桌面控制器通过白名单 Electron IPC 调用 `desktop.py` 的独立 JSON 工作进程;网关启停、更新和网络配置管理不监听网络。PushPlus 全局配置与测试允许通过手机 HTTP 操作,必须经过 Host、Origin、登录及写入 CSRF 校验,仅接受 PushPlus 字段,不返回 Token。该配置影响整个网关的关注聊天,不按登录设备隔离。打包版本执行随包提供的 PyInstaller 运行时,网关以独立后台进程运行,退出控制器不会停止网关。Windows 使用 NSIS 安装包或完整 ZIP 目录,避免临时自解压目录随控制器退出被删除而破坏后台运行时。
-Windows `desktop/shell/tray.cjs` 管理托盘状态、手机地址和两种退出动作;仅显式停止才调用网关的协作停止协议。主窗口关闭时隐藏,第二次启动恢复原窗口;退出前销毁托盘并允许窗口关闭。状态请求合并,菜单操作避免重复提交;停止失败保留控制器并显示错误。macOS 不创建此托盘,保留原窗口生命周期。
+Windows `desktop/shell/tray.cjs` 管理托盘状态、手机地址和两种退出动作;仅显式停止才调用网关的协作停止协议。主窗口关闭时隐藏,第二次启动恢复原窗口;退出前销毁托盘并允许窗口关闭。状态请求合并,菜单操作避免重复提交;停止失败保留控制器并显示错误。macOS 使用同一菜单提供菜单栏入口,关闭控制面板后仍可从菜单栏或 Dock 重新打开。登录自启动由用户在高级设置中启用:Windows/macOS 使用系统登录项,Linux 已安装的桌面包使用用户 XDG autostart;AppImage 注册原始文件路径,不注册临时挂载目录。Windows/macOS 登录启动隐藏控制面板,Linux 保持窗口可见。启用登录自启动同时启用网关自动启动;关闭登录项保留后者。
网关停止使用带随机实例令牌的本地控制文件,由服务主动调用 `shutdown`,再关闭隧道、IPC 和 HTTP。`stop.py --config` 与启动配置对应,不依赖 Unix 信号或 Windows PID 强制终止。文件统一使用 UTF-8;Windows 权限继承目录 ACL。
diff --git a/README.md b/README.md
index 176f8d15..ad4e6b4e 100644
--- a/README.md
+++ b/README.md
@@ -5,11 +5,11 @@
# Codex Mobile Bridge · 多客户端远程工作台
-> **v2.0.0 正式版**:[发布与下载](https://github.com/try2love/codex-mobile-bridge/releases/tag/v2.0.0) · [完整更新说明](RELEASE_NOTES.md) · [手机安装说明](mobile/README.md)。从 v1.4.0 的 Codex 手机网关,扩展为 Codex、Claude Desktop 与 DeepSeek Harness 的统一远程入口。
+> **v2.0.2 正式版**:[发布与下载](https://github.com/try2love/codex-mobile-bridge/releases/tag/v2.0.2) · [完整更新说明](RELEASE_NOTES.md) · [手机安装说明](mobile/README.md)。本版改善文件链接、手机文件打开、登录自启与聊天列表滚动刷新,保留 Codex、Claude Desktop 与 DeepSeek Harness 的统一远程入口。
[简体中文](README.md) · [English](README_EN.md)
-**[双语介绍与使用演示 ↗](https://try2love.github.io/codex-mobile-bridge/?lang=zh)** · **[下载桌面与手机 App](https://github.com/try2love/codex-mobile-bridge/releases/tag/v2.0.0)**
+**[双语介绍与使用演示 ↗](https://try2love.github.io/codex-mobile-bridge/?lang=zh)** · **[下载桌面与手机 App](https://github.com/try2love/codex-mobile-bridge/releases/tag/v2.0.2)**
[](https://try2love.github.io/codex-mobile-bridge/?lang=zh)
@@ -47,18 +47,18 @@
## 下载与快速开始(推荐)
-日常使用直接下载桌面 App,**无需 Agent 帮忙部署,也无需安装 Python、Node.js 或打开终端**。当前版本为 **v2.0.0 正式版**。
+日常使用直接下载桌面 App,**无需 Agent 帮忙部署,也无需安装 Python、Node.js 或打开终端**。当前版本为 **v2.0.2 正式版**。
| 系统 | 下载 | 打开方式 |
| --- | --- | --- |
-| Windows x64(推荐安装包) | [下载 Setup.exe](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/Codex-Mobile-Bridge-2.0.0-Windows-x64-Setup.exe) | 运行安装包,从快捷方式打开 |
-| Windows x64(免安装) | [下载完整 ZIP](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/Codex-Mobile-Bridge-2.0.0-Windows-x64.zip) | 完整解压后运行 `Codex Mobile Bridge.exe`,不要单独移动 exe |
-| macOS Apple Silicon(M 系列) | [下载 arm64 DMG](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/Codex-Mobile-Bridge-2.0.0-macOS-arm64.dmg) | 打开 DMG,将 App 拖入“应用程序” |
-| macOS Intel(英特尔) | [下载 x64 DMG](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/Codex-Mobile-Bridge-2.0.0-macOS-x64.dmg) | 打开 DMG,将 App 拖入“应用程序” |
-| Ubuntu x64(实验性) | [下载 .deb](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/Codex-Mobile-Bridge-2.0.0-Linux-amd64.deb) | Ubuntu 22.04;安装后以普通用户启动 |
-| Ubuntu ARM64(实验性) | [下载 .deb](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/Codex-Mobile-Bridge-2.0.0-Linux-arm64.deb) | Ubuntu 22.04 ARM64;不含 32 位 ARM |
+| Windows x64(推荐安装包) | [下载 Setup.exe](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/Codex-Mobile-Bridge-2.0.2-Windows-x64-Setup.exe) | 运行安装包,从快捷方式打开 |
+| Windows x64(免安装) | [下载完整 ZIP](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/Codex-Mobile-Bridge-2.0.2-Windows-x64.zip) | 完整解压后运行 `Codex Mobile Bridge.exe`,不要单独移动 exe |
+| macOS Apple Silicon(M 系列) | [下载 arm64 DMG](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/Codex-Mobile-Bridge-2.0.2-macOS-arm64.dmg) | 打开 DMG,将 App 拖入“应用程序” |
+| macOS Intel(英特尔) | [下载 x64 DMG](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/Codex-Mobile-Bridge-2.0.2-macOS-x64.dmg) | 打开 DMG,将 App 拖入“应用程序” |
+| Ubuntu x64(实验性) | [下载 .deb](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/Codex-Mobile-Bridge-2.0.2-Linux-amd64.deb) | Ubuntu 22.04;安装后以普通用户启动 |
+| Ubuntu ARM64(实验性) | [下载 .deb](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/Codex-Mobile-Bridge-2.0.2-Linux-arm64.deb) | Ubuntu 22.04 ARM64;不含 32 位 ARM |
-[查看所有版本与更新说明](https://github.com/try2love/codex-mobile-bridge/releases) · [下载 SHA256 校验文件](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/SHA256SUMS.txt)。两种 Mac 同时提供 ZIP,供应用内更新或手动替换使用。Windows ARM 暂无专用安装包。Mac 版采用本地完整性签名但未公证,首次打开可能需要手动允许;Windows 版未做证书签名。详见下方 macOS 首次打开说明。
+[查看所有版本与更新说明](https://github.com/try2love/codex-mobile-bridge/releases) · [下载 SHA256 校验文件](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/SHA256SUMS.txt)。两种 Mac 同时提供 ZIP,供应用内更新或手动替换使用。Windows ARM 暂无专用安装包。Mac 版采用本地完整性签名但未公证,首次打开可能需要手动允许;Windows 版未做证书签名。详见下方 macOS 首次打开说明。
1. 安装并登录要使用的桌面客户端,打开 **Codex Mobile Bridge**。在 **客户端与接入** 检查扫描结果,完成需要的授权,并启用配置就绪的客户端。
2. 在 **网络访问** 保留局域网访问或添加 HTTPS 入口,保存后从概览或客户端页点击 **启动网关**。已有配置时沿用原端口。
@@ -67,7 +67,7 @@
需要外网访问时,可选 [Tailscale 固定 HTTPS](docs/tailscale.md)、内置 Cloudflare 临时 HTTPS、[固定 Cloudflare Tunnel](docs/fixed-domain.md)、[自有服务器 + SSH](docs/server-ssh.md) 或 NAS 反代。详细要求见[连接方式说明](#connections)。固定地址不保证国内直连速度,首次配置请用实际蜂窝网络测试。
-Android APK、iOS 未签名 IPA 与 Xcode 源码包见同一 [v2.0.0 Release](https://github.com/try2love/codex-mobile-bridge/releases/tag/v2.0.0)。Android 覆盖安装以保留数据;iOS 需自行签名,暂无 App Store/TestFlight 分发。源码运行与自定义部署见后面的[部署 Agent 执行说明](#agent-deployment)。
+Android APK、iOS 未签名 IPA 与 Xcode 源码包见同一 [v2.0.2 Release](https://github.com/try2love/codex-mobile-bridge/releases/tag/v2.0.2)。Android 覆盖安装以保留数据;iOS 需自行签名,暂无 App Store/TestFlight 分发。源码运行与自定义部署见后面的[部署 Agent 执行说明](#agent-deployment)。
@@ -77,7 +77,7 @@ Android APK、iOS 未签名 IPA 与 Xcode 源码包见同一 [v2.0.0 Release](ht
从 `v0.2.0-beta.5` 起,可在桌面 App 的「应用更新」中检查新版、查看说明并点击「更新并重启」。下载与校验完成后短暂重启网关,保留登录、网络、通知和关注聊天配置;失败时尝试恢复原版本。此前版本需要先手动安装一次支持更新的版本。使用临时 HTTPS 时,重启后请打开最新地址。发布与恢复说明见 [桌面更新文档](docs/desktop-updates.md)。
-**Windows beta.7 / 1.0.0 用户:**旧更新器可能因目录占用报 `WinError 32` 并回退。请先在托盘选择“停止网关并退出”,再用 **2.0.0 Setup.exe** 安装到原位置;无需卸载或删除数据。1.1.0 修复后续更新的目录占用问题。
+**Windows beta.7 / 1.0.0 用户:**旧更新器可能因目录占用报 `WinError 32` 并回退。请先在托盘选择“停止网关并退出”,再用 **2.0.2 Setup.exe** 安装到原位置;无需卸载或删除数据。1.1.0 修复后续更新的目录占用问题。
### 手机阅读与显示设置
@@ -120,10 +120,10 @@ v2.0.0 在线查询订阅周期日期,显示剩余时间和具体日期;接
当前 Mac 版具有本地完整性签名(ad-hoc),**没有 Apple Developer ID 签名和公证**,首次打开仍可能被 macOS 拦截。旧版 `v0.2.0-beta.1` 还存在包签名缺陷,请优先下载 `v1.1.0` 或后续版本。
-1. 从本仓库的 Release 下载对应芯片的 DMG 或 ZIP,以及 `SHA256SUMS.txt`。计算下载文件的 SHA-256,与校验文件中同名文件的一行比较;不一致时重新下载,不要放行。以下以 2.0.0 的 M 系列 Mac DMG 为例,其他文件请替换文件名:
+1. 从本仓库的 Release 下载对应芯片的 DMG 或 ZIP,以及 `SHA256SUMS.txt`。计算下载文件的 SHA-256,与校验文件中同名文件的一行比较;不一致时重新下载,不要放行。以下以 2.0.2 的 M 系列 Mac DMG 为例,其他文件请替换文件名:
```sh
- shasum -a 256 "$HOME/Downloads/Codex-Mobile-Bridge-2.0.0-macOS-arm64.dmg"
+ shasum -a 256 "$HOME/Downloads/Codex-Mobile-Bridge-2.0.2-macOS-arm64.dmg"
```
2. 打开 DMG,将 `Codex Mobile Bridge.app` 拖入“应用程序”,再推出磁盘映像;ZIP 则先解压并移动 App。尝试从“应用程序”打开后,前往 **系统设置 → 隐私与安全性 → 仍要打开**,按系统提示确认。
diff --git a/README_EN.md b/README_EN.md
index ccf4cc19..a7911e58 100644
--- a/README_EN.md
+++ b/README_EN.md
@@ -5,11 +5,11 @@
# Codex Mobile Bridge · A remote workbench for desktop agents
-> **v2.0.0 stable**: [Release and downloads](https://github.com/try2love/codex-mobile-bridge/releases/tag/v2.0.0) · [Full release notes](RELEASE_NOTES.md) · [Mobile installation](mobile/README.md). The v1.4.0 Codex gateway grows into one remote entry for Codex, Claude Desktop and DeepSeek Harness.
+> **v2.0.2 stable**: [Release and downloads](https://github.com/try2love/codex-mobile-bridge/releases/tag/v2.0.2) · [Full release notes](RELEASE_NOTES.md) · [Mobile installation](mobile/README.md). This release improves file links, mobile file opening, login startup and chat-list scrolling and refresh for the shared Codex, Claude Desktop and DeepSeek Harness gateway.
[简体中文](README.md) · [English](README_EN.md)
-**[Product guide and interactive demos ↗](https://try2love.github.io/codex-mobile-bridge/?lang=en)** · **[Download desktop and mobile apps](https://github.com/try2love/codex-mobile-bridge/releases/tag/v2.0.0)**
+**[Product guide and interactive demos ↗](https://try2love.github.io/codex-mobile-bridge/?lang=en)** · **[Download desktop and mobile apps](https://github.com/try2love/codex-mobile-bridge/releases/tag/v2.0.2)**
[](https://try2love.github.io/codex-mobile-bridge/?lang=en)
@@ -47,18 +47,18 @@ Supports macOS, Windows and experimental Ubuntu x64/ARM64. See the [Linux guide]
## Download and quick start (recommended)
-Download the desktop App for everyday use. **No deployment Agent, Python, Node.js or terminal is required.** The current release is **v2.0.0 (stable)**.
+Download the desktop App for everyday use. **No deployment Agent, Python, Node.js or terminal is required.** The current release is **v2.0.2 (stable)**.
| Platform | Download | Open |
| --- | --- | --- |
-| Windows x64 (recommended installer) | [Download Setup.exe](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/Codex-Mobile-Bridge-2.0.0-Windows-x64-Setup.exe) | Run the installer and launch from the shortcut |
-| Windows x64 (no installation) | [Download full ZIP](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/Codex-Mobile-Bridge-2.0.0-Windows-x64.zip) | Extract the entire ZIP and run `Codex Mobile Bridge.exe`; do not move just the exe |
-| macOS Apple Silicon (M series) | [Download arm64 DMG](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/Codex-Mobile-Bridge-2.0.0-macOS-arm64.dmg) | Open the DMG and drag the App to Applications |
-| macOS Intel | [Download x64 DMG](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/Codex-Mobile-Bridge-2.0.0-macOS-x64.dmg) | Open the DMG and drag the App to Applications |
-| Ubuntu x64 (experimental) | [Download .deb](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/Codex-Mobile-Bridge-2.0.0-Linux-amd64.deb) | Ubuntu 22.04; launch as a regular user |
-| Ubuntu ARM64 (experimental) | [Download .deb](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/Codex-Mobile-Bridge-2.0.0-Linux-arm64.deb) | Ubuntu 22.04 ARM64; no 32-bit ARM build |
+| Windows x64 (recommended installer) | [Download Setup.exe](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/Codex-Mobile-Bridge-2.0.2-Windows-x64-Setup.exe) | Run the installer and launch from the shortcut |
+| Windows x64 (no installation) | [Download full ZIP](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/Codex-Mobile-Bridge-2.0.2-Windows-x64.zip) | Extract the entire ZIP and run `Codex Mobile Bridge.exe`; do not move just the exe |
+| macOS Apple Silicon (M series) | [Download arm64 DMG](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/Codex-Mobile-Bridge-2.0.2-macOS-arm64.dmg) | Open the DMG and drag the App to Applications |
+| macOS Intel | [Download x64 DMG](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/Codex-Mobile-Bridge-2.0.2-macOS-x64.dmg) | Open the DMG and drag the App to Applications |
+| Ubuntu x64 (experimental) | [Download .deb](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/Codex-Mobile-Bridge-2.0.2-Linux-amd64.deb) | Ubuntu 22.04; launch as a regular user |
+| Ubuntu ARM64 (experimental) | [Download .deb](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/Codex-Mobile-Bridge-2.0.2-Linux-arm64.deb) | Ubuntu 22.04 ARM64; no 32-bit ARM build |
-[All releases and release notes](https://github.com/try2love/codex-mobile-bridge/releases) · [Download SHA256 checksums](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.0/SHA256SUMS.txt). Both Mac architectures also include ZIPs for in-app updates or manual replacement. Windows ARM packages are not available. The Mac build is ad-hoc signed but not notarized and may require manual approval; Windows builds have no certificate signature. See the macOS first-launch instructions below.
+[All releases and release notes](https://github.com/try2love/codex-mobile-bridge/releases) · [Download SHA256 checksums](https://github.com/try2love/codex-mobile-bridge/releases/download/v2.0.2/SHA256SUMS.txt). Both Mac architectures also include ZIPs for in-app updates or manual replacement. Windows ARM packages are not available. The Mac build is ad-hoc signed but not notarized and may require manual approval; Windows builds have no certificate signature. See the macOS first-launch instructions below.
1. Install and sign in to the desktop clients you need. Open **Codex Mobile Bridge**, inspect **Clients and access**, complete required permissions and enable configured clients.
2. Keep LAN access or add an HTTPS entry under **Network access**, save, and select **Start gateway** from Overview or Clients. Preserve your configured port.
@@ -67,7 +67,7 @@ Download the desktop App for everyday use. **No deployment Agent, Python, Node.j
For remote access, choose [Tailscale HTTPS](docs/tailscale.md), bundled temporary Cloudflare HTTPS, a [fixed Cloudflare tunnel](docs/fixed-domain.md), [your own SSH server](docs/server-ssh.md) or a NAS proxy. See [Parallel connections](#parallel-connections). Fixed addresses do not guarantee mainland China performance; test the actual cellular network.
-Android APK, unsigned iOS IPA and Xcode source downloads are in the same [v2.0.0 Release](https://github.com/try2love/codex-mobile-bridge/releases/tag/v2.0.0). Install Android over the existing app; iOS requires your own signing, with no App Store/TestFlight distribution. Source/custom setups are covered by the [Deployment Agent instructions](#deployment-agent-instructions).
+Android APK, unsigned iOS IPA and Xcode source downloads are in the same [v2.0.2 Release](https://github.com/try2love/codex-mobile-bridge/releases/tag/v2.0.2). Install Android over the existing app; iOS requires your own signing, with no App Store/TestFlight distribution. Source/custom setups are covered by the [Deployment Agent instructions](#deployment-agent-instructions).
### In-app updates
@@ -75,7 +75,7 @@ Android APK, unsigned iOS IPA and Xcode source downloads are in the same [v2.0.0
Starting with `v0.2.0-beta.5`, use **App updates** to check for a release, read its notes, and select **Update and restart**. The app verifies the signed manifest and package before replacing itself, preserves login, network, notification and watched-chat settings, and restores a previously running gateway. Installation failures attempt to restore the previous app. Older versions need one manual upgrade to a version with this feature. Temporary HTTPS addresses change when the gateway restarts.
-**Windows beta.7 / 1.0.0 users:** the old updater may roll back with `WinError 32` because its working directory is locked. Choose **Stop gateway and quit** in the tray, then install **2.0.0 Setup.exe** to the same location. Do not uninstall or delete your data. Version 1.1.0 fixes this working-directory issue for subsequent updates.
+**Windows beta.7 / 1.0.0 users:** the old updater may roll back with `WinError 32` because its working directory is locked. Choose **Stop gateway and quit** in the tray, then install **2.0.2 Setup.exe** to the same location. Do not uninstall or delete your data. Version 1.1.0 fixes this working-directory issue for subsequent updates.
### Phone reading and display settings
@@ -115,10 +115,10 @@ View remaining percentages, reset times and available usage resets. In v2.0.0, r
The Mac build has an **ad-hoc integrity signature**, but **no Apple Developer ID signature or notarization**. macOS can still block the first launch. The older `v0.2.0-beta.1` also has a bundle-signing defect; use `v1.1.0` or later.
-1. Download the DMG or ZIP for your Mac's chip and `SHA256SUMS.txt` from this repository's Release. Calculate the downloaded file's hash and compare it with the matching filename in the checksum file. If they differ, download again instead of allowing the app. The example below uses the 2.0.0 Apple Silicon DMG; replace the filename for other downloads.
+1. Download the DMG or ZIP for your Mac's chip and `SHA256SUMS.txt` from this repository's Release. Calculate the downloaded file's hash and compare it with the matching filename in the checksum file. If they differ, download again instead of allowing the app. The example below uses the 2.0.2 Apple Silicon DMG; replace the filename for other downloads.
```sh
- shasum -a 256 "$HOME/Downloads/Codex-Mobile-Bridge-2.0.0-macOS-arm64.dmg"
+ shasum -a 256 "$HOME/Downloads/Codex-Mobile-Bridge-2.0.2-macOS-arm64.dmg"
```
2. Open the DMG, drag `Codex Mobile Bridge.app` to Applications, then eject the disk image. For a ZIP, extract it and move the App instead. Try opening it from Applications, then go to **System Settings → Privacy & Security → Open Anyway** and confirm.
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 8c69d096..58e1cbdf 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,3 +1,27 @@
+## v2.0.2 · 文件兼容与聊天列表体验优化
+
+- **聊天列表更连贯**:Codex 列表滚动接近底部时自动加载后续聊天,移除常驻“加载更多”按钮。下拉刷新提示不再挤压列表,手势跟随与回弹更顺滑,成功提示更快收起;内容未变化时保留已有列表节点和阅读位置。
+- **Windows 文件链接更可靠**:兼容盘符、反斜杠、file URL 和长路径前缀;同一文件的不同引用共用下载入口。继续使用现有工作区授权与可配置下载上限。
+- **手机下载后直接打开**:Android 和 iOS 可通过系统支持的应用打开已下载文件,同时保留保存入口;系统区域颜色随当前页面变化。
+- **跨平台登录自启**:Windows、macOS 和已安装的 Linux 桌面包可在高级设置中启用。Windows/macOS 登录后收起控制面板,macOS 可从菜单栏或 Dock 恢复;Linux 保持窗口可见,AppImage 使用原文件路径。
+- 保留 v2.0.1 的 macOS 异常应用 plist 扫描修复。
+
+感谢 [@heiqiu47](https://github.com/heiqiu47) 在 [PR #24](https://github.com/try2love/codex-mobile-bridge/pull/24) 中贡献的文件兼容、手机文件打开、系统栏与登录自启改进。本版按现有 main 的文件与认证边界整合,并扩展跨平台适配。
+
+**升级**:建议网关与手机 App 一起更新至 v2.0.2,以使用完整改进。聊天列表优化由网关提供,升级后重新加载页面即可。Android 覆盖安装以保留已保存电脑与登录;iOS IPA 仍需自行签名,另附 Xcode 源码包。Linux 仍为实验性支持,请保留数据目录后手动安装。下载文件可用 `SHA256SUMS.txt` 校验。
+
+### English
+
+- Load more Codex chats automatically near the bottom, remove the persistent load-more button, and make pull-to-refresh smoother with a shorter success notice. Keep unchanged list nodes and reading position.
+- Improve Windows drive paths, backslashes, file URLs and long-path aliases while retaining workspace authorization and configurable download limits.
+- Open downloaded files through supported system apps on Android and iOS, retain Save, and match system-area colors to the current page.
+- Add opt-in login startup for Windows, macOS and installed Linux desktop packages. Windows/macOS hide the control panel on login; Linux keeps it visible. macOS provides a menu-bar entry, and AppImage startup uses its original file path.
+- Retain the v2.0.1 macOS malformed-plist discovery fix.
+
+Thanks to [@heiqiu47](https://github.com/heiqiu47) for [PR #24](https://github.com/try2love/codex-mobile-bridge/pull/24). Update both the gateway and mobile app for all improvements. Install Android over the existing app; the unsigned iOS IPA requires your own signing. Linux remains experimental. Verify downloads with `SHA256SUMS.txt`.
+
+---
+
## v2.0.1 · 修复 macOS 客户端扫描中断
- 修复 macOS 扫描应用时,某个应用的 `Info.plist` 存在 XML 格式错误,导致整轮客户端发现中断、已启用客户端无法继续自动接入的问题。
diff --git a/bridge/api/httpd.py b/bridge/api/httpd.py
index 8295f5aa..8e3ac82f 100644
--- a/bridge/api/httpd.py
+++ b/bridge/api/httpd.py
@@ -18,6 +18,7 @@
from bridge.features.workspace.uploads import MAX_FILE
from bridge.features.workspace.workspace import MAX_TRANSFER, Workspace
from bridge.features.workspace.preferences import transfer_settings
+from bridge.features.workspace.files import workspace_relative_path
from bridge.features.notifications.channels import settings as notification_settings, save_settings as save_notification_settings, publish_pushplus
from socketserver import TCPServer
from urllib.parse import parse_qs, urlsplit, quote
@@ -790,9 +791,8 @@ def download(self, bridge, thread_id, artifact_id, info=False):
if info:
result = workspace.info(relative)
cwd = bridge.store.get(thread_id).get('cwd')
- root = Path(cwd).resolve() if cwd else None
- result['locatable'] = root is not None and root in path.parents
- result['path'] = path.relative_to(root).as_posix() if result['locatable'] else None
+ result['path'] = workspace_relative_path(path, cwd)
+ result['locatable'] = result['path'] is not None
return self.output(200, {**result, **policy})
# Walk the authorized absolute path without following replaced parent
# symlinks. Inline images retain their independent preview size bound.
diff --git a/bridge/app/service.py b/bridge/app/service.py
index e1a95972..de571b87 100644
--- a/bridge/app/service.py
+++ b/bridge/app/service.py
@@ -1198,7 +1198,7 @@ def view(self, thread_id, attach=True, background=False, force=False):
view["goalActivationIds"] = sorted(self._goal_activation_ids(thread_id))
with session.condition:
artifacts = artifact_paths(session.state or {}, self.store.home) if self.host == "local" else {}
- view["files"] = [{"id": k, "name": v["name"], "reference": v["reference"], "image": v["image"]} for k, v in artifacts.items()]
+ view["files"] = [{"id": k, "name": v["name"], "reference": v["reference"], "references": v["references"], "image": v["image"]} for k, v in artifacts.items()]
self._overlay_native_goal(session, thread_id, view)
self._submission_meta(session, view)
view["forkedFrom"] = self._fork_origin(thread_id)
@@ -1504,14 +1504,14 @@ def timeline_read(self, thread_id, mode='page', **options):
cwd = (session.state or {}).get('cwd')
media_items = [item for turn in ordered_turns(session.state or {})
for item in items_array(turn.get('items')) if item.get('type') in ('ImageView', 'imageView')]
- # Resolve links in the delivered page, plus ImageView evidence needed by
- # embedded model screenshots that can live outside workspace roots.
+ # Resolve links in the delivered page, plus runtime ImageView evidence
+ # retained separately from the paged message text.
file_state = {'cwd': cwd, 'turns': [
{'items': [{'type': 'agentMessage', 'text': text} for text in texts]},
{'items': media_items},
]}
artifacts = artifact_paths(file_state, self.store.home) if self.host == 'local' else {}
- result['files'] = [{'id': k, 'name': v['name'], 'reference': v['reference'], 'image': v['image']} for k, v in artifacts.items()]
+ result['files'] = [{'id': k, 'name': v['name'], 'reference': v['reference'], 'references': v['references'], 'image': v['image']} for k, v in artifacts.items()]
if mode != 'detail':
self._submission_meta(session, result['meta'])
result['meta']['forkedFrom'] = self._fork_origin(thread_id)
diff --git a/bridge/features/workspace/files.py b/bridge/features/workspace/files.py
index 17648bb2..94ee602b 100644
--- a/bridge/features/workspace/files.py
+++ b/bridge/features/workspace/files.py
@@ -19,15 +19,36 @@ def path_identity(value):
"""Return the host-normalized identity used to link duplicate references."""
path = value if isinstance(value, Path) else Path(value)
try:
- return Path(os.path.normcase(str(path.resolve(strict=False))))
+ return Path(os.path.normcase(_without_windows_prefix(str(path.resolve(strict=False)))))
except (OSError, RuntimeError):
- return Path(os.path.normcase(os.path.abspath(str(path))))
+ return Path(os.path.normcase(_without_windows_prefix(os.path.abspath(str(path)))))
+
+
+def _without_windows_prefix(value):
+ if os.name == 'nt':
+ if value.startswith('\\\\?\\UNC\\'):
+ return '\\\\' + value[8:]
+ if value.startswith('\\\\?\\') and re.match(r'[A-Za-z]:\\', value[4:]):
+ return value[4:]
+ return value
+
+
+def workspace_relative_path(path, cwd):
+ """Locate an artifact inside the resolved workspace, including Windows aliases."""
+ if not cwd:
+ return None
+ path = Path(_without_windows_prefix(str(Path(path).resolve())))
+ root = Path(_without_windows_prefix(str(Path(cwd).resolve())))
+ return path.relative_to(root).as_posix() if root in path.parents else None
def reference_path(value, allow_relative=False):
"""Resolve a local file reference without allowing remote URL access."""
if not isinstance(value, str) or not value:
return None
+ # Chat links may prefix Windows drive paths with a URL-style slash.
+ if os.name == 'nt' and re.fullmatch(r'/[A-Za-z]:[\\/].*', value):
+ value = value[1:]
try:
parsed = urlsplit(value)
if parsed.scheme == 'file':
@@ -122,7 +143,7 @@ def artifact_paths(state, codex_home):
candidates.add(value)
result = {}
model_images, trusted_views = _model_image_references(state)
- for raw in candidates:
+ for raw in sorted(candidates):
# Model-authored Markdown and response attachments remain bound to the
# workspace/visualization roots even when they name an image suffix.
value = re.sub(r':\d+$', '', raw)
@@ -131,14 +152,15 @@ def artifact_paths(state, codex_home):
continue
try:
path = ((Path(state['cwd']) / path) if not path.is_absolute() and state.get('cwd') else path).resolve(strict=True)
- if not any(root in path.parents for root in roots) or not (path.is_file() or path.is_dir()):
+ if not any(workspace_relative_path(path, root) is not None for root in roots) or not (path.is_file() or path.is_dir()):
continue
except OSError:
continue
key = hashlib.sha256(str(path_identity(path)).encode()).hexdigest()
- result[key] = {'path': path, 'reference': raw, 'name': path.name,
+ artifact = result.setdefault(key, {'path': path, 'reference': raw, 'references': [], 'name': path.name,
'kind': 'directory' if path.is_dir() else 'file',
- 'image': path.is_file() and path.suffix.lower() in IMAGE_SUFFIXES}
+ 'image': path.is_file() and path.suffix.lower() in IMAGE_SUFFIXES})
+ artifact['references'].append(raw)
# A path can be shown once as ImageView and embedded later with another text
# form (usually a plain absolute path versus file://). Only the runtime view
# grants the outside-workspace exception; collect all references so Markdown
@@ -158,7 +180,8 @@ def artifact_paths(state, codex_home):
file_refs = sorted(ref for ref in references if urlsplit(ref).scheme == 'file')
reference = plain[0] if plain else (file_refs[0] if file_refs else next(iter(references)))
key = hashlib.sha256(str(path).encode()).hexdigest()
- result[key] = {'path': path, 'reference': reference, 'name': path.name,
+ references.update(result.get(key, {}).get('references', []))
+ result[key] = {'path': path, 'reference': reference, 'references': sorted(references), 'name': path.name,
'kind': 'directory' if path.is_dir() else 'file',
'image': path.is_file() and path.suffix.lower() in IMAGE_SUFFIXES}
return result
@@ -171,5 +194,6 @@ def workspace_references(messages, cwd):
for row in messages if row.get('role') == 'assistant']} ]}
root = Path(cwd).resolve()
return [{'id': key, 'name': value['name'], 'reference': value['reference'],
- 'path': value['path'].relative_to(root).as_posix(), 'kind': value['kind'], 'image': False}
+ 'references': value['references'], 'path': workspace_relative_path(value['path'], root),
+ 'kind': value['kind'], 'image': False}
for key, value in artifact_paths(state, None).items()]
diff --git a/desktop/index.html b/desktop/index.html
index c6a674d9..d429029c 100644
--- a/desktop/index.html
+++ b/desktop/index.html
@@ -35,7 +35,7 @@