Что такое репозиторий

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/. Именно они превращают push в релиз, который 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, и так далее по всей таблице выше.

Проверьте до публикации

Пак в репозитории остаётся тем же самым файлом, который можно открыть вручную, так что сперва проверьте коротким путём: отправьте его на телефон через AirDrop или положите в «Файлы» и откройте в 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, а не дополняет его, поэтому последний push это всегда то, что получают остальные.

Откройте эту вкладку после того, как репозиторий опубликует релиз.

Добавьте его в Clink

  1. Откройте «Общие», затем «Репозитории», и добавьте владелец/репозиторий.
  2. Откройте вкладку своего вида и потяните вниз для обновления. Ваши паки появятся под теми именами, которые дал им манифест.
  3. Нажмите на любой, чтобы скачать. Clink проверит его и установит, как любой другой пак.

Для пакетов с данными достаточно добавить репозиторий: темы, раскладки, профили, звуки, шрифты и языки. Панели, действия и плагины несут логику, поэтому каждому репозиторию нужен собственный переключатель, прежде чем Clink установит любой из них, и приложение спрашивает в первый раз.

Панели содержат ограниченную интерактивную логику. Разрешайте только репозитории, которым доверяете.

Что проверяет Clink

  1. Адрес использует HTTPS на github.com и ведёт в релизы того репозитория, который вы добавили.
  2. Размер загрузки в точности совпадает с манифестом, а её хеш SHA-256 из 64 символов сходится.
  3. У файла правильное расширение, и он разбирается как тот тип пака, за который себя выдаёт.
  4. Панели, действия и плагины проходят политику исходного кода перед сохранением.

Если загрузка отклонена, причина будет одной из этих пяти. Сообщение в приложении намеренно короткое, поэтому проверяйте их по порядку.

ПроверкаОтклоняется, если
github.comАдрес не HTTPS на github.com и не ведёт в релизы добавленного вами репозитория. Манифест не может указывать куда-то ещё, даже на другой ваш репозиторий.
byteCountРазмер файла не совпадает с заявленным в манифесте или превышает предел для своего вида. Пересборка манифеста после каждой правки решает почти все такие случаи.
sha256Хеш не сходится с байтами. Обычно манифест записали до последнего изменения файла.
pathИмя файла не оканчивается расширением, которого требует вид, или пытается выбраться из релиза двумя точками.
sourceПанель, действие или плагин не прошли политику исходного кода: слишком длинные или содержат фрагмент, который политика отвергает.

Обновление и отзыв

Идентификатором служит имя файла без расширения, и именно он делает публикацию обновлением. Сохраните имя, и новый релиз заменит копию, которая у людей уже есть. Переименуйте файл, и вы опубликовали второй пак рядом с первым.

Удаление пака из репозитория прекращает новые загрузки. До телефонов, где он уже стоит, это не доходит, поэтому неудачный релиз стоит заменять, а не удалять.

Официальные репозитории

Сделайте форк любого из них, чтобы начать. Каждый собирает собственный манифест и публикует себя через GitHub Actions.

Загрузить в App Store