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
99 changes: 30 additions & 69 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,103 +2,64 @@

**[English](README.md) | [中文](README.zh-CN.md)**

The Homebrew cask for [ThinkWatch Lite](https://thinkwat.ch/lite/), the
desktop app for a local AI API gateway. The cask installs the macOS build,
which runs on Apple silicon with macOS 12 or later.
The Homebrew cask for [ThinkWatch Lite](https://thinkwat.ch/lite/), a desktop
app that runs a local gateway for Claude Code, Codex and other AI clients. It
requires macOS 12 or later on Apple silicon; the cask refuses to install on an
Intel Mac.

```bash
brew install --cask thinkwatchproject/tap/thinkwatch-lite
```

Installing by the full name taps this repository automatically; a separate
`brew tap` is not required.
Installing by the full name taps this repository; no separate `brew tap` is
needed. Windows and Linux builds and the macOS disk image are on the
[download page](https://thinkwat.ch/lite/#install).

The Windows and Linux builds, and the disk image for a manual installation on
macOS, are available on the [ThinkWatch Lite page](https://thinkwat.ch/lite/#install)
and on the [releases page](https://github.com/ThinkWatchProject/ThinkWatch-Lite/releases/latest).
## Unsigned app and the quarantine attribute

## What the cask installs

`ThinkWatch Lite.app` in `/Applications`. The gateway, ThinkWatch Core, is
part of the app bundle, so no second package or background service has to be
installed.

The app is built for Apple silicon only. There is no universal binary, so the
cask requires an arm64 Mac and refuses to install on an Intel Mac instead of
installing an app that cannot run there.

## Code signing and the quarantine attribute

The app is signed with the project's self-signed certificate, not with an
Apple Developer ID. The certificate does not satisfy Gatekeeper. It gives
every release the same signer, so that `brew upgrade` recognizes a new version
as coming from the same source as the installed one and does not report a
changed signer.

macOS quarantines files downloaded from the internet and does not open an app
that is not signed by a registered Apple developer. Since macOS 15, opening
the app with a Control-click no longer bypasses this check; the remaining
options are System Settings › Privacy & Security › Open Anyway, once per
installation, or removing the quarantine attribute. The cask's `postflight`
step removes the attribute:
The app is signed with the project's self-signed certificate, not an Apple
Developer ID, so Gatekeeper does not accept it. The certificate keeps the
signer the same across releases, so `brew upgrade` does not report a changed
signer. The cask's `postflight` step removes the quarantine attribute, which
is the only action it takes besides copying the app:

```bash
xattr -dr com.apple.quarantine "/Applications/ThinkWatch Lite.app"
```

Apart from copying the app out of its disk image, this is the only action the
cask performs. To install without it, download
`ThinkWatch-Lite-<version>-arm64.dmg` from the
[releases page](https://github.com/ThinkWatchProject/ThinkWatch-Lite/releases/latest),
compare it with the SHA-256 checksum published beside it, and run the command
above.

The checksum in the cask is not copied from that published file. It is
computed from the disk image that the update job downloads, and the update
fails if the two checksums differ: a checksum published next to the file it
describes does not verify that file on its own.
To do this step by hand instead, download `ThinkWatch-Lite-<version>-arm64.dmg`
from the [releases page](https://github.com/ThinkWatchProject/ThinkWatch-Lite/releases/latest),
check it against the published SHA-256 checksum and run the command above.
Otherwise, System Settings › Privacy & Security › Open Anyway is required once
per installation; since macOS 15, Control-click no longer bypasses the check.

## Updates

```bash
brew update && brew upgrade --cask thinkwatch-lite
```

An app installed with Homebrew does not update itself. Homebrew records the
version it placed in `/Applications`; if the app replaced its own bundle, that
record would point to a version that is no longer on disk, and the next
`brew upgrade` would install the older version over the newer one.

The app checks this tap instead of the release page, so a new version is
reported only after the cask here carries it. The app reports it in a
notification, in its menu and in Settings; each of these opens a window with
the command above and a button that copies it. Every ThinkWatch Lite release
updates the cask as soon as it is published; an hourly job in this repository
serves as the fallback.

`brew update` is part of the command because `brew upgrade` refreshes taps on
its own at most once a day (`HOMEBREW_AUTO_UPDATE_SECS`). Without it, an
outdated copy of this tap would report that the latest version is already
installed.
An app installed with Homebrew does not update itself, so that Homebrew's
record of the installed version stays correct. The app announces a new version
once this cask carries it, and offers the command above to copy. Each release
updates the cask when it is published, with an hourly job here as a fallback.
`brew update` is included because `brew upgrade` refreshes taps at most once a
day.

## Uninstallation

Before the cask is uninstalled, Settings › Full uninstall in the app restores every
connected client and turns off launch at login. Removing the app alone does
neither, which leaves connected clients pointed at a port where nothing is
listening.
First use Settings › Full uninstall in the app: it restores every connected
client and turns off launch at login. Removing the app alone leaves clients
pointed at a port where nothing is listening.

```bash
brew uninstall --cask thinkwatch-lite
```

This quits and removes the app, and keeps `~/.thinkwatch`, which holds the
configuration with the upstream keys, the request history and the keys of
remote connections. To remove that directory and the app's other files as
well:
This keeps `~/.thinkwatch`, which holds the configuration with upstream keys,
the request history and the keys of remote connections. To move that directory
and the app's other files to the Trash as well:

```bash
brew uninstall --zap --cask thinkwatch-lite
```

`--zap` moves those files to the Trash rather than deleting them.
71 changes: 21 additions & 50 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,84 +3,55 @@
**[English](README.md) | [中文](README.zh-CN.md)**

[ThinkWatch Lite](https://thinkwat.ch/zh-CN/lite/) 的 Homebrew cask。ThinkWatch
Lite 是在本机运行 AI API 网关的桌面应用。此 cask 安装 macOS 版本,适用于
macOS 12 及以上版本的 Apple silicon 机型。
Lite 是为 Claude Code、Codex 等 AI 客户端在本机运行网关的桌面应用,要求
macOS 12 及以上版本的 Apple silicon 机型;在 Intel 机型上 cask 会拒绝安装。

```bash
brew install --cask thinkwatchproject/tap/thinkwatch-lite
```

按完整名称安装时会自动添加此 tap,无需先执行 `brew tap`。
按完整名称安装时会自动添加此 tap,无需先执行 `brew tap`。Windows 与 Linux
版本以及 macOS 磁盘映像见[下载页面](https://thinkwat.ch/zh-CN/lite/#install)。

Windows 与 Linux 版本,以及在 macOS 上手动安装所用的磁盘映像,见
[ThinkWatch Lite 页面](https://thinkwat.ch/zh-CN/lite/#install)和
[发布页面](https://github.com/ThinkWatchProject/ThinkWatch-Lite/releases/latest)。
## 未签名的应用与隔离属性

## 安装内容

`/Applications` 中的 `ThinkWatch Lite.app`。网关 ThinkWatch Core 包含在应用包
内,无需另外安装软件包或后台服务。

应用仅为 Apple silicon 构建,没有通用二进制,因此 cask 要求 arm64 机型:在
Intel 机型上直接拒绝安装,而不是装上一个无法运行的应用。

## 代码签名与隔离属性

应用使用项目自有的自签名证书签名,而非 Apple Developer ID。该证书不能使应用
通过 Gatekeeper,其作用是让每个版本的签名者保持一致,使 `brew upgrade` 能确认
新版本与已安装的版本来源相同,不提示签名者已变更。

macOS 会为从互联网下载的文件添加隔离属性,并拒绝打开未经注册开发者签名的
应用。自 macOS 15 起,按住 Control 键点按打开已无法绕过这项检查;其余方式是每次
安装后在「系统设置 › 隐私与安全性」中选择「仍要打开」,或移除隔离属性。cask 的
`postflight` 步骤会移除该属性:
应用使用项目自有的自签名证书签名,而非 Apple Developer ID,因此无法通过
Gatekeeper。该证书使各版本的签名者保持一致,`brew upgrade` 不会提示签名者已
变更。cask 的 `postflight` 步骤会移除隔离属性,这是它在复制应用之外执行的唯一
操作:

```bash
xattr -dr com.apple.quarantine "/Applications/ThinkWatch Lite.app"
```

除从磁盘映像中复制应用外,这是 cask 执行的唯一操作。如不希望由 cask 执行,可从
[发布页面](https://github.com/ThinkWatchProject/ThinkWatch-Lite/releases/latest)
下载 `ThinkWatch-Lite-<版本>-arm64.dmg`,与旁边发布的 SHA-256 校验和核对后,
执行上面的命令。

cask 中的校验和并非抄自那份文件,而是根据更新任务实际下载的磁盘映像计算得出;
两者不一致时,更新失败。与所描述的文件发布在同一处的校验和,本身不能证明该文件
未被替换。
如需手动完成这一步,可从[发布页面](https://github.com/ThinkWatchProject/ThinkWatch-Lite/releases/latest)
下载 `ThinkWatch-Lite-<版本>-arm64.dmg`,与发布的 SHA-256 校验和核对后执行上面
的命令。否则每次安装后需在「系统设置 › 隐私与安全性」中选择「仍要打开」;自
macOS 15 起,按住 Control 键点按打开已无法绕过这项检查。

## 更新

```bash
brew update && brew upgrade --cask thinkwatch-lite
```

通过 Homebrew 安装的应用不会自行更新。Homebrew 会记录它放入 `/Applications`
的版本;如果应用自行替换了应用包,这条记录将指向一个已不在磁盘上的版本,下一次
`brew upgrade` 会用旧版本覆盖新版本。

应用查询的是此 tap,而不是发布页面,因此只有这里的 cask 更新到新版本之后,应用
才会提示新版本。提示出现在系统通知、应用的菜单和设置中,均可打开一个窗口,其中
给出上面的命令和复制按钮。ThinkWatch Lite 每次发布时都会立即更新 cask;此仓库中
每小时运行一次的任务作为补充。

命令中包含 `brew update`,是因为 `brew upgrade` 自身最多每天刷新一次 tap
(`HOMEBREW_AUTO_UPDATE_SECS`)。不先刷新时,过时的 tap 会报告已是最新版本。
通过 Homebrew 安装的应用不会自行更新,以免 Homebrew 记录的已安装版本失准。此
cask 更新到新版本后,应用会提示新版本并给出上面的命令供复制。每次发布时 cask
随即更新,此仓库每小时运行一次的任务作为补充。命令中包含 `brew update`,是因为
`brew upgrade` 自身最多每天刷新一次 tap。

## 卸载

卸载 cask 之前,应先在应用的「设置 › 完全卸载」中执行卸载:该操作会还原所有已接管
的客户端,并取消开机启动。仅删除应用不会执行这两项,已接管的客户端会继续向一个
无人监听的端口发送请求。
应先在应用的「设置 › 完全卸载」中执行卸载:该操作会还原所有已接管的客户端,并
取消开机启动。仅删除应用时,已接管的客户端会继续向一个无人监听的端口发送请求。

```bash
brew uninstall --cask thinkwatch-lite
```

此命令退出并删除应用,保留 `~/.thinkwatch`:其中包括含上游密钥的配置、请求记录
以及远程连接的密钥。如需一并删除该目录和应用的其他文件:
此命令保留 `~/.thinkwatch`,其中包括含上游密钥的配置、请求记录以及远程连接的
密钥。如需将该目录和应用的其他文件一并移到废纸篓:

```bash
brew uninstall --zap --cask thinkwatch-lite
```

`--zap` 会将这些文件移到废纸篓,而不是直接删除。
Loading