仓库是什么

Clink 从公开的 GitHub 仓库读取包。你按名称添加一个,Clink 读它最新的发行版,每个文件都会在安装前完成校验。没有任何内容被上传,你的东西也不会在服务器上运行。

请输入 owner/repository、github.com/owner/repository 或完整的 HTTPS URL。在下载任何内容之前,Clink 都会验证每个发布清单和文件。

先挑一种

每一种包都有自己的文件扩展名和自己在清单里的集合名,Clink 也分别给它们各自的大小上限。挑好你要发布的那一行,并照着来:一个被归到面板底下的主题,根本读不出来。

种类文件集合单个文件上限(字节)官方仓库
主题.clinkthemethemes128,000anti-ltd/clink-themes
布局.clinklayoutlayouts512,000anti-ltd/clink-layouts
配置文件.clinkprofileprofiles256,000anti-ltd/clink-profiles
声音.clinkpacksounds512,000anti-ltd/clink-sounds
字体.otf .ttffonts32,000,000anti-ltd/clink-fonts
面板.clinkpanelpanels50,000anti-ltd/clink-panels
操作.clinkextactions48,000anti-ltd/clink-actions
插件.clinkpluginplugins66,000anti-ltd/clink-plugins

语言包是例外。那里的一个包是一组词库和模型文件,而不是一个文档,官方仓库里带着构建它们的整套工具。请从那边的 README 开始,而不是这一页。

从官方仓库起步

最快的路子是分叉。包目录、清单生成脚本和发布工作流都已经接好,还附带能直接照抄的可用示例。

# Everything a repository needs is already wired together in the official one.
gh repo fork anti-ltd/clink-panels --clone
cd clink-panels

# Your packs replace the examples. Keep tools/ and .github/.
rm Panels/*.clinkpanel
cp ~/Downloads/my-panel.clinkpanel Panels/kaomoji-plus.clinkpanel

保留 tools/ 和 .github/workflows/。正是这两样把一次推送变成 Clink 读得懂的发行版;缺了它们的分叉什么也发布不出来。

或者用三个文件从头搭

仓库并不神秘。它需要一个放包的目录、一个写清单的脚本,以及一个切发行版的工作流。

my-panels/
├── Panels/
   └── kaomoji.clinkpanel        # one file per pack, the name is the id
├── tools/
   └── build-manifest.py         # writes manifest.json from that folder
└── .github/workflows/
    └── release.yml               # turns a push into a release

工作流做三件事:重建清单、删掉上一个发行版、再发布一个标记为 latest 的新发行版,把包文件和清单一并附上。就这些。

name: Release panels
on:
  push:
    branches: [main]
    paths: ["Panels/**", "tools/**", ".github/workflows/release.yml"]
permissions: { contents: write }
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: python3 tools/build-manifest.py
      - run: gh release delete latest --yes || true
        env: { GH_TOKEN: "${{ github.token }}" }
      - run: gh release create latest Panels/*.clinkpanel manifest.json --title "Latest panels" --latest
        env: { GH_TOKEN: "${{ github.token }}" }
.github/workflows/release.yml

生成脚本遍历目录,为每个文件写一条记录。哈希和字节数只从这里产生,所以它跑在工作流里,而不是靠手动执行。

#!/usr/bin/env python3
import hashlib, json, os, pathlib

root = pathlib.Path(__file__).resolve().parents[1]
repository = os.environ.get("GITHUB_REPOSITORY", "<owner>/<repository>")
packs = []
for path in sorted((root / "Panels").glob("*.clinkpanel")):
    data = path.read_bytes()
    pack = json.loads(data)
    packs.append({
        "id": path.stem,
        "name": pack["name"],
        "version": "latest",
        "asset": {
            "path": path.name,
            "url": f"https://github.com/{repository}/releases/download/latest/{path.name}",
            "sha256": hashlib.sha256(data).hexdigest(),
            "byteCount": len(data),
        },
    })
(root / "manifest.json").write_text(json.dumps({"version": "latest", "panels": packs}, indent=2))
tools/build-manifest.py。换一种包时,把目录、扩展名和集合名改成你挑的那一行。

清单

每个发行版都会把 manifest.json 与包文件一起发布,Clink 从最新发行版的 https://github.com/<owner>/<repository>/releases/latest/download/manifest.json 读取它。每条记录写明文件名、它在同一发行版中的地址、SHA-256 哈希和精确的字节数。

{
  "version": "latest",
  "panels": [
    {
      "id": "kaomoji",
      "name": "Kaomoji",
      "version": "latest",
      "asset": {
        "path": "kaomoji.clinkpanel",
        "url": "https://github.com/<owner>/<repository>/releases/download/latest/kaomoji.clinkpanel",
        "sha256": "8f14e45fce…",
        "byteCount": 2048
      }
    }
  ]
}
面板仓库清单里的一条记录。

集合名必须和种类对上。面板放在 panels 下,主题放在 themes 下,上面那张表依此类推。

发布前先试一遍

仓库里的包,就是你能直接打开的那个文件,所以先走捷径试:用隔空投送发到手机上,或者放进“文件”再用 Clink 打开。之后再检查脚本写出的清单。

python3 tools/build-manifest.py
cat manifest.json
  1. 运行生成脚本。它会按目录里此刻的内容重写 manifest.json。
  2. 读一遍它写出的东西。每条记录都应指向一个真实存在的文件,字节数也要对得上。
  3. 在 Clink 里打开包文件本身用一用。面板或操作会落进各自的编辑器,可以就地运行。

发布

git add Panels manifest.json
git commit -m "Add my first panel"
git push

推送到 main,剩下的交给工作流。它是替换 latest 发行版而不是往上追加,所以最新一次推送永远就是别人拿到的东西。

仓库发布版本后,再打开此标签页。

在 Clink 里添加

  1. 打开“通用”,进入“仓库”,添加 owner/repository。
  2. 打开你这一类的标签页并下拉刷新。你的包会按清单里给的名字列出来。
  3. 点一个开始下载。Clink 校验之后,像装其他包一样装上。

数据包只需添加仓库即可:主题、布局、配置文件、声音、字体和语言。面板、动作和插件带有逻辑,所以每个仓库都需要单独的开关,Clink 才会安装其中任何一种,应用会在第一次时询问。

面板包含受约束的交互逻辑。只允许你信任的仓库。

Clink 会检查什么

  1. 地址是 github.com 上的 HTTPS,且位于你添加的那个仓库的发行版之下。
  2. 下载的字节数与清单完全一致,64 位的 SHA-256 哈希也对得上。
  3. 文件带着正确的扩展名,并且能按它自称的包类型解析。
  4. 面板、动作和插件在存储前都要通过源代码策略。

下载被拒绝时,无非这五种原因。应用里的提示故意写得很短,所以按顺序排查。

检查项拒绝条件
github.com地址不是 github.com 上的 HTTPS,或者不在你添加的那个仓库的发行版之下。清单不能指向别处,哪怕是你自己的另一个仓库。
byteCount文件大小和清单声明的不完全一致,或者超过了该种类的上限。每次改完就重建清单,能解决其中绝大多数。
sha256哈希和字节对不上。通常是清单写在文件最后一次改动之前。
path文件名没有以该种类要求的扩展名结尾,或者用两个点试图爬出发行版。
source某个面板、动作或插件未通过源代码策略:过长,或含有策略拒绝的片段。

更新,以及收回

id 就是去掉扩展名的文件名,它决定了一次发布算不算更新。保持文件名不变,新发行版就会替换掉别人手上的那一份。改了名字,你就是在第一个旁边又发布了第二个包。

把包从仓库里撤下来只会停掉新的下载。它触及不到已经装好的手机,所以一个糟糕的发行版应该去替换,而不是删掉。

官方仓库

分叉其中任意一个就能开始。每个仓库都会生成自己的清单,并用 GitHub Actions 自行发布。

在 App Store 下载