---
title: "更新"
description: "ThinkTerm 如何检查和安装更新，为什么安装方式决定了由谁替换文件，以及远端 server 如何在不中断会话的情况下更新。"
url: "https://docs.closex.org/zh/thinkterm/updates.html"
markdown_url: "https://docs.closex.org/zh/thinkterm/updates.md"
site: "CloseX Docs"
product: "ThinkTerm"
language: "zh-Hans"
last_updated: "2026-11-08T12:04:16.000Z"
alternates:
  en: "https://docs.closex.org/thinkterm/updates.md"
  zh-Hans: "https://docs.closex.org/zh/thinkterm/updates.md"
  ja: "https://docs.closex.org/ja/thinkterm/updates.md"
---

# 更新

ThinkTerm 不会自行安装更新。它只负责检查、告诉你，然后等你决定。

## 检查更新

桌面应用运行期间，会自己去 GitHub 检查有没有新版本：启动后大约十秒，如果记录里的上一次检查已经早于检查频率，就检查一次；之后每过一个这么长的时间再检查一次。命令行工具、TUI 和会话 server 从不自行检查。

`设置 › 软件更新` 里有两行控制这件事。`自动检查更新` 是一个开关，`检查频率` 提供 `每 12 小时`（默认）、`每天` 和 `每周`，开关关闭时它是灰的。改动在一分钟内生效。在你动用这两行之前，它们跟随配置文件里的 `check_for_updates` 和 `check_for_updates_interval_seconds`；两者怎么配合、一次检查何时到点，见配置页的[更新检查](https://docs.closex.org/zh/thinkterm/configuration.md#更新检查)。

`设置 › 软件更新` 显示的是检查的结果：当前运行的版本、是否已知有更新的版本，以及这个副本是怎么安装的。

- 顶部那个按钮，在已知有新版本、且这个副本是 ThinkTerm 可以替换的那种时，是 `安装更新`，下面叠着一个 `检查更新`；其余情况下只有 `检查更新`。`检查更新` 会当场去问 GitHub，不论 `自动检查更新` 开着与否：请求进行期间按钮显示 `正在检查…`，之后短暂显示 `已检查`，上方的卡片显示返回的结果。请求失败时，卡片显示 `无法检查更新。`，原因打印在它下方。下面的 `thinkterm update --check` 在终端里做同样的事。
- `上次检查` 是只读的。它显示记录里最近一次检查是什么时候做的，不论是应用自己做的，还是用 `检查更新` 做的。
- `更新内容` 会在浏览器里打开待安装版本的发布说明。没有待安装的版本时，显示的是 `查看全部版本`，打开完整列表。
- `下载来源` 决定更新从哪里下载安装包，本机和远端 server 都用它。默认的 `自动` 先走 GitHub，GitHub 慢或连不上时改用镜像；`直连 GitHub` 从不使用镜像；也可以指定某一个镜像。不管从哪里下载，都要和 GitHub 记录的校验值一致才会安装。

检查到新版本时，窗口的角落里会浮出一枚胶囊，而不是弹窗抢占屏幕，见 [更新胶囊](#the-update-capsule)。如果找到它的是自动检查，还会同时发一条通知 —— *ThinkTerm 有新版本* —— 点击后会在浏览器里打开这个版本在 GitHub 上的页面。`Check for Updates...`（在 macOS 的 ThinkTerm 菜单和命令面板里，名称不翻译）会打开 `设置 › 软件更新`，绑定到按键上的 `CheckForUpdates` 动作也一样。

判断一个发布版是否更新，看版本号；唯一的例外是版本号相同。在 macOS 上，从源码检出自己打包的 `ThinkTerm.app`，可能带着一个后来才发布的版本号，而那个发布版是用更新的代码做的。遇到这种情况，ThinkTerm 会比较这个应用所基于的提交的时间和发布版所基于的提交的时间，用更新的代码做成的发布版会以 `有新构建` 提示出来。此时通知写的是 *ThinkTerm 有新构建*，`设置 › 软件更新` 写的是 `ThinkTerm x.y.z 有比你这份更新的构建`。查出发布版的提交时间要多发一个请求，发给 GitHub 的提交列表，只发一次，并和保存的检查结果存在一起。正式发布包从不这样比较，所以它不会被告知它自己就是的那个发布版。

除了上面那次查询，一次检查就是向 GitHub 的 release API 发一个请求，不带任何凭据。如果你自己设了 `THINKTERM_UPDATE_TOKEN`，它会被读取 —— 这能解除 GitHub 对匿名请求的限流，私有 fork 也需要它。它与安装脚本接受的 `GITHUB_TOKEN` 是两个变量，这是刻意的：ThinkTerm 自己的代码从不读取 `GITHUB_TOKEN`，所以你为别的工具导出的 token 不会被检查发出去。更新所运行的安装脚本会读取它，但只在必须自己下载归档时才会用到；见 [安装更新](#installing)。ThinkTerm 还会发送哪些东西，见 [隐私与安全](https://docs.closex.org/zh/thinkterm/privacy.md)。

## 安装更新 {#installing}

`安装更新` 会原地替换文件。替换期间你面前的窗口可以继续使用，而 ThinkTerm 仍然运行着启动时的那个版本。

最后这点最容易被误解，所以确认信息把话说明白了：*ThinkTerm x.y.z 已安装。重启后开始使用新版本。* 运行中的会话底下不会被偷偷换掉。

在找到眼前这个新版本之后，也许又发布了更新的版本，装旧的只会紧接着再更新一次。所以设置里的 `安装更新` 和更新胶囊会先向 GitHub 再问一次最新的发布版，装那一个，卡片和胶囊随后写的也是它。如果这第二次问不通 GitHub，就装原来提供的那个版本。

页面顶部的卡片会跟着安装进度变化。先是 `正在准备安装 ThinkTerm x.y.z…`，此时 ThinkTerm 在准备安装脚本；然后是 `正在下载 ThinkTerm x.y.z…`，带一条进度条和类似 `63.1 MB / 80.0 MB · 79%` 的一行，下载持续一秒之后会再加上 `约 12 秒`；接着是 `正在安装 ThinkTerm x.y.z…`。出了问题，卡片显示 `更新安装失败。`，原因出现在它下方；如果已经走到安装器那一步，还会附上安装器打印的内容。

ThinkTerm 会自己下载归档，并在安装脚本看到它之前，用 GitHub 在文件上传时记录的 SHA-256 核对。对不上的下载会被删除，什么都不会安装。如果 GitHub 没有这个归档的校验和，就由脚本自己获取并判断，和手动运行时一样，也没有进度条。

桌面应用通过系统代理下载，或者环境里指定的代理，SOCKS 也行。`thinkterm update` 用系统的 `curl` 下载，它读取环境里指定的代理。

安装完成后，卡片上会出现 `重启 ThinkTerm`，但只在重启不会结束任何终端时才有。由 ThinkTerm 自己运行的 shell —— 在应用自己的进程里的，或者经直接 SSH 连接的 —— 会随它一起结束，而放在会话 server 里的终端不会。只要还开着第一种 pane，就没有这个按钮，你可以在方便的时候自己退出再重新打开 ThinkTerm。Windows 也一样：安装器不会关掉 ThinkTerm，卡片会等安装器结束，然后给出同样的重启按钮。

更新前就在运行的会话 server，会在 ThinkTerm 下次启动时被移到新版本：运行中的 server 把 pane 交给新构建，里面的终端继续运行。如果 server 比正在启动的应用还新 —— 比如更新 server 时留在原地的旧应用 —— 它就不会被动，这个窗口先用自己的终端。server 里的那些终端还在；更新 ThinkTerm 后它们就回来了，要是改在设置里停掉会话 server，它们则会结束。

## 更新胶囊 {#the-update-capsule}

已知有新版本时，每个窗口终端区域的右下角都会浮着一枚圆角胶囊，写着 `有新版本` 和版本号。如果这个副本是 ThinkTerm 可以替换的，点一下就和 `安装更新` 做同样的事；其他副本则会打开 `设置 › 软件更新`，那里写明文件归谁管。胶囊会避开菜单、命令面板和对话框。

接着它代替卡片跟着安装走。先是 `正在下载` 和百分比，图标外转着一圈进度环，然后是 `正在安装`。装完之后，在重启不会结束任何终端时它写 `重启以完成更新`，点一下就重启 ThinkTerm。重启会结束终端时，它写 `更新已安装`，点一下打开设置页面。安装失败时写 `更新失败` 和 `重试`，点一下再试一次。更新下载或安装期间，点击没有任何作用。

指针停在胶囊上时，会展开一个关闭按钮。关掉后，胶囊收拢，飞进侧边栏设置按钮上的一个小圆点，一直留到下次启动；安装失败时圆点是红色的，这时点设置按钮打开的是 `设置 › 软件更新`，而不是设置。更新下载期间关掉胶囊，不会中止安装。

## 谁有权替换这些文件

ThinkTerm 只更新它自己装的副本，也就是通过安装脚本装的那种。其他每一种安装方式都有各自的归属方：系统包管理器、Homebrew、Nix、AppImage 自己的更新器，或者那个运行了 `cargo build` 的人。对这些情况，ThinkTerm 会指出归属方，而不是覆盖它的文件。

| 这个副本的安装方式 | ThinkTerm 的处理 |
|---|---|
| 安装脚本 | 安装更新，并保持原来的变体 |
| 手动放置的 `ThinkTerm.app` | 在原位置替换，并把命令行工具放到 `~/.local/bin` |
| AppImage | 提示用 AppImageUpdate，或从发布页下载新的 AppImage |
| Homebrew | 提示运行 `brew upgrade thinkterm`。Homebrew 的 cask 不算在这里：它把 `ThinkTerm.app` 放进 `/Applications`，所以应用会把它当作手动放置的，在原位置替换 |
| Nix | 提示通过你的 Nix 配置更新 |
| 系统包管理器 | 提示用 `apt`、`dnf` 或原来的方式安装新包 |
| Windows 安装器 | 下载适合这台机器架构的新安装器并运行 |
| 从源码构建 | 提示拉取仓库后重新构建 |
| 无法识别 | 拒绝替换，并提示按原来的安装方式更新 |

在它不会替换文件的那些情况下，`thinkterm update` 做的不止是指出归属方：在 macOS 和 Linux 上，它还会打印一条出路 —— 跑一次安装脚本，就把这台机器纳入脚本管理的安装，之后每一次更新都回到按钮或那条命令。而如果安装器跑起来了却拒绝这台机器（glibc 太旧、musl、没有对应架构的构建），它会直说，并给出从源码构建这个版本的命令，而不是报一个没有原因的失败。

## 命令行

`thinkterm update` 遵循与设置里那个按钮完全相同的规则。

```bash
thinkterm update              # 检查，安装前询问
thinkterm update --check      # 只报告是否有新版本，不安装
thinkterm update -y           # 不询问直接安装
thinkterm update --version X  # 安装指定版本 X 而不是最新版，允许降级
```

两条路径都没有重新实现安装器，而是先下载发布归档，按 [安装更新](#installing) 里描述的方式核对，再把活交给 `install.sh`——只有这个脚本了解归档布局，以及桌面版和服务器版之间的切换。ThinkTerm 下载好的归档通过 `--from` 交给它，同时带上 `--version` 和这次安装所用的 `--prefix`。脚本是从默认分支拉取的，不是从要安装的那个 release 里取的：这样对安装器的修复能一次性覆盖所有已装机器，而不用等下一个版本发布。Windows 没有安装脚本，在那里两条路径都是下载新的安装器并运行它。

`thinkterm update` 让脚本直接写到你的终端，所以在服务器版安装上，脚本自己的交接会生效：运行中的 mux 服务端把会话交给新构建，见[升级与卸载](https://docs.closex.org/zh/thinkterm/install.md#升级与卸载)。设置里的 `安装更新` 则会捕获脚本的输出，桌面应用在下次启动时自己把会话 server 交接过去。

## 更新远端 server

客户端和 server 在协议发生变化后就无法通信。最常见的触发方式是：你的桌面端升级了，而某台主机上的 server 还跑着上个月的构建。

ThinkTerm 手上已经有到那台主机的 SSH 会话，所以它可以自己修复这个不匹配，而不是把你打发去手动登录。attach 时发现版本不匹配，它会先说明两边各运行哪个版本，接下来怎么做取决于那台主机。

有些不匹配它修不了，会在提问之前就说明。其中两种它从你自己的配置里就能知道：这个域被配置成从固定路径运行 ThinkTerm，以及客户端本身就是开发构建，没有对应的发布版。第三种是 server 比这个客户端还新：它会原样保留，因为它不会把会话交给更旧的构建，提示里会让你改为在这一端更新 ThinkTerm。

否则，ThinkTerm 会打开到该主机的 SSH 会话，读取那里装了什么。此时还没有向 GitHub 请求任何东西，主机上也没有任何改动。主机的 glibc 对要装的那个版本来说太旧（服务器版低于 2.31，桌面版低于 2.35）、主机用的是 musl、或者它的架构没有发布版，会在这一步、任何提问之前就被指出，并附上从源码构建的办法。glibc 为 2.31 到 2.33 的主机会装上内置 OpenSSL 的服务器构建。装哪个变体取决于主机上已有的东西：那里的桌面版安装会保留 GUI，在 Linux 上，发行版包装的桌面应用（它不写安装记录）也一样：它会得到装在 `~/.local` 下的桌面版，启动器移到新的安装上，应用和服务器保持同一个版本。如果主机的 glibc 对桌面版来说太旧，提问里会说明只更新服务器，应用保持自己的版本。主机上的 macOS 应用包不动，因为它会自己更新。

然后它只问一次。这个问题会说明哪个版本、以哪个变体装到主机上，是以 SSH 用户的身份装到 `~/.local` 下、不需要 root，通过 SSH 会发送什么，以及随带的东西，比如桌面应用。带有未提交源码改动的客户端不会因此被拒绝；提问里会带一条警告，说明发布版仍可能与它不匹配。回答 `n`，则哪里都没有改动：ThinkTerm 会打印出命令，供你自己在主机上运行。

只有回答 yes 之后，ThinkTerm 才会去 GitHub 查这个发布版。这是这个客户端正在运行的版本，不一定是最新版。查询失败时，它会说 `Could not resolve release x.y.z`，给出原因，然后停下。否则它通过这条 SSH 会话把安装脚本和这个发布版的校验值发给主机，由主机自己下载归档；下载不经过 ThinkTerm。脚本是联网取得的已签名副本（四秒内能验证就用它），不然用 ThinkTerm 内置的那一份，所以不会运行任何未经验证的东西。`下载来源` 同样适用，GitHub 慢时会让位给镜像，见[安装](https://docs.closex.org/zh/thinkterm/install.md#安装脚本)。安装器的输出，以及下载的字节数和速率，会转发到连接窗口里。

之后运行中的会话会怎样，取决于一个设置，它同样在 `设置 › 软件更新` 页面上，默认开启：

**`更新远端 server 时保留会话`** —— *运行中的 server 把 pane 交给新版本而不是停掉，里面跑的程序不会中断。*

交接中途失败会重试，最多三次。太旧、无法交出 pane 的 server，会退回到下面这个询问。关闭该设置时，ThinkTerm 会在停止旧 server 前询问，因为停止它会结束它持有的所有会话。这件事从不会在未经询问的情况下执行；如果你拒绝，旧 server 会继续运行，直到你自己停掉它并重新连接。

交接本身用的就是 [远程](https://docs.closex.org/zh/thinkterm/remote.md) 里描述的那套机制——运行中的 server 把 pane 传给新的二进制，会话本身察觉不到。

## 相关

- [远程](https://docs.closex.org/zh/thinkterm/remote.md) —— 会话如何在断开、重启和升级后存活
- [命令行](https://docs.closex.org/zh/thinkterm/cli.md) —— `thinkterm` 的其余子命令
- [安装](https://docs.closex.org/zh/thinkterm/install.md) —— 每次更新实际运行的安装脚本
