Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bce7b5345 | ||
|
|
18bef94a96 | ||
|
|
7b8347aee9 | ||
|
|
73f99ad8dc | ||
|
|
59c5942572 | ||
|
|
0e0e474b72 | ||
|
|
73b5e87e95 | ||
|
|
6401c42a91 | ||
|
|
3fdc6a608a | ||
|
|
9833b202f9 | ||
|
|
d3b2abecdd | ||
|
|
b9e2887b2f | ||
|
|
f33ec4b124 | ||
|
|
c0929c030a | ||
|
|
f02fc98097 | ||
|
|
08104de30c | ||
|
|
91fe77b794 | ||
|
|
5dc78222f6 | ||
|
|
71d6f41d92 | ||
|
|
a68fb112d7 | ||
|
|
84a1bbea8a | ||
|
|
8564f84ed5 | ||
|
|
07d13aca64 | ||
|
|
c34650a941 | ||
|
|
fdb4a492ef | ||
|
|
3cc4217790 | ||
|
|
f3af93802f | ||
|
|
1801be3549 |
@@ -2,6 +2,70 @@
|
||||
|
||||
В файле фиксируются значимые изменения Nivora.
|
||||
|
||||
## 2026-07-25 — Vintner
|
||||
|
||||
### Изменено
|
||||
|
||||
- Пакет `msvc-go-wine` переименован в `vintner` вслед за ребрендингом
|
||||
апстрима (github.com/Cheviiot/vintner); `replaces` обновлён для чистого
|
||||
перехода при обновлении.
|
||||
- Версия поднята до `0.2.0`: добавлена поддержка сборки KMDF/UMDF-драйверов
|
||||
через Windows Driver Kit (`download --with-wdk`), короткие алиасы команд
|
||||
и локализация CLI на английский и русский (`VINTNER_LANG`).
|
||||
- Версия поднята до `0.3.0`: пакет теперь сам регистрирует автодополнение
|
||||
для bash (`/usr/share/bash-completion/completions/vintner`) и zsh
|
||||
(`/usr/share/zsh/site-functions/_vintner`) через хелпер Stapler
|
||||
`install-completion` — работает сразу после `stplr install`, без
|
||||
ручного `source <(vintner completion bash)`. Также добавлена корректная
|
||||
остановка процессов Wine при завершении `vintner` по PID.
|
||||
- Версия поднята до `0.3.1`: исправлен реальный баг в `toolrelay.exe` —
|
||||
определение `mt.exe` по имени файла никогда не срабатывало (путь
|
||||
приходил с прямыми слэшами, а проверка искала обратный), из-за чего
|
||||
перевод кода возврата `mt.exe` для совместимости с CMake фактически не
|
||||
работал ни разу. Найдено и исправлено при реальной сборке движка Ogre3D
|
||||
через CMake+Ninja+cl.exe.
|
||||
- Версия поднята до `0.4.0`: добавлена поддержка DirectX SDK (июнь 2010)
|
||||
для сборки устаревшего кода на D3DX9 (`download --with-dxsdk`), и
|
||||
алиасинг старых имён PlatformToolset (v90–v143) на единственный
|
||||
установленный компилятор — теперь старые `.vcxproj`, закреплённые за
|
||||
давними версиями тулсета, тоже собираются. В зависимости добавлен
|
||||
`cabextract` (нужен рантайму для `--with-dxsdk`).
|
||||
- Версия поднята до `0.5.0`: инструменты MSVC теперь можно вызывать без
|
||||
добавления `<dest>/bin/<arch>` в PATH — напрямую как `vintner cl ...`,
|
||||
`vintner msbuild ...` и т.д. Добавлена команда `vintner doctor`,
|
||||
диагностирующая неисправную настройку wine/toolchain. `download` теперь
|
||||
докачивает прерванные загрузки вместо перезапуска с нуля, а
|
||||
`download`/`install` берут файловую блокировку на каталог назначения,
|
||||
чтобы два параллельных запуска не повредили дерево файлов. Ошибка
|
||||
«wine не найден» теперь называет конкретный пакет для установки.
|
||||
Wine-процессы больше не зависают навечно при обрыве сборки (принудительно
|
||||
отключён node reuse MSBuild, добавлена поддержка таймаута через
|
||||
`VINTNER_TIMEOUT`).
|
||||
|
||||
## 2026-07-25 — Telegram Desktop
|
||||
|
||||
### Добавлено
|
||||
|
||||
- В каталог добавлен Telegram Desktop 7.0.5 для `amd64` из официального
|
||||
статически собранного Linux-архива `tsetup.<version>.tar.xz`.
|
||||
- Сохранены официальные desktop-id `org.telegram.desktop` и WM-класс
|
||||
`TelegramDesktop`; иконка взята из официального репозитория
|
||||
`telegramdesktop/tdesktop` для закреплённого тега релиза.
|
||||
- Пакет добавляет команду `telegram-desktop`; сборка распространяется под
|
||||
GPL-3.0-only с отдельным разрешением на линковку с OpenSSL.
|
||||
|
||||
## 2026-07-25 — Nivora CLI
|
||||
|
||||
### Изменено
|
||||
|
||||
- Пакет `nivora-stplr` полностью переработан и переименован в `nivora-cli`.
|
||||
- Новая команда `nv` получила компактное интерактивное меню, русскую и
|
||||
английскую локализацию, диагностику, dry-run и генерацию автодополнения.
|
||||
- Повседневные операции доступны отдельными командами в стиле eepm:
|
||||
`nvi`, `nve`, `nvu`, `nvs`, `nvqi`, `nvqa`, `nvr`, `nvrl`, `nvf`, `nvd`
|
||||
и `nvc`.
|
||||
- Прежние команды семейства `sl*` удалены без слоя совместимости.
|
||||
|
||||
## 2026-07-24 — GitHub Desktop
|
||||
|
||||
### Добавлено
|
||||
|
||||
@@ -11,7 +11,7 @@ Nivora предлагает открытые рецепты упаковки д
|
||||
официальный репозиторий Stapler и не официальные пакеты upstream-проектов.
|
||||
|
||||
<!-- package-count -->
|
||||
**19 пакетов** · **6 категорий** · `amd64`, `arm64` и `all`
|
||||
**24 пакета** · **6 категорий** · `amd64`, `arm64` и `all`
|
||||
|
||||
[](https://github.com/Cheviiot/Nivora/actions/workflows/quality.yml)
|
||||
|
||||
@@ -47,9 +47,12 @@ stplr info nivora/codex
|
||||
|:--|:--:|:--:|:--|
|
||||
| [Clash Verge Rev](https://github.com/clash-verge-rev/clash-verge-rev) | `2.5.2` | `amd64`, `arm64` | `stplr install nivora/clash-verge-rev` |
|
||||
| [Happ](https://happ.su/) | `3.3.6` | `amd64`, `arm64` | `stplr install nivora/happ` |
|
||||
| [NetBird](https://netbird.io/) | `0.75.0` | `amd64`, `arm64` | `stplr install nivora/netbird` |
|
||||
| [Tailscale](https://tailscale.com/) | `1.98.9` | `amd64`, `arm64` | `stplr install nivora/tailscale` |
|
||||
| [Яндекс Браузер](https://browser.yandex.ru/) | `26.4.1.1110` | `amd64` | `stplr install nivora/yandex-browser-stable` |
|
||||
| [MAX](https://max.ru/) (в песочнице Firejail) | `26.24.0~75261` | `amd64` | `stplr install nivora/max` |
|
||||
| [NetBird](https://netbird.io/) | `0.76.0` | `amd64`, `arm64` | `stplr install nivora/netbird` |
|
||||
| [Tailscale](https://tailscale.com/) | `1.98.10` | `amd64`, `arm64` | `stplr install nivora/tailscale` |
|
||||
| [Telegram](https://desktop.telegram.org/) | `7.0.6` | `amd64` | `stplr install nivora/telegram` |
|
||||
| [VK Messenger](https://vk.me/app) | `6.0.57` | `amd64` | `stplr install nivora/vk-messenger` |
|
||||
| [Яндекс Браузер](https://browser.yandex.ru/) | `26.6.1.1003` | `amd64` | `stplr install nivora/yandex-browser-stable` |
|
||||
|
||||
### Удалённый доступ
|
||||
|
||||
@@ -62,10 +65,12 @@ stplr info nivora/codex
|
||||
| Приложение | Версия | Архитектуры | Установка |
|
||||
|:--|:--:|:--:|:--|
|
||||
| [Chatbox](https://chatboxai.app/ru) | `1.20.3` | `amd64`, `arm64` | `stplr install nivora/chatbox` |
|
||||
| [Claude](https://code.claude.com/docs/en/desktop-quickstart) | `1.24012.0` | `amd64`, `arm64` | `stplr install nivora/claude-desktop` |
|
||||
| [Codex](docs/packages/codex.md) | `26.721.31836` | `amd64` | `stplr install nivora/codex` |
|
||||
| [Claude](docs/packages/claude.md) | `1.24012.0` | `amd64`, `arm64` | `stplr install nivora/claude` |
|
||||
| [ClaudeAlt](docs/packages/claude-alt.md) | `1.24012.0` | `amd64`, `arm64` | `stplr install nivora/claude-alt` |
|
||||
| [Codex](docs/packages/codex.md) | `26.721.81911` | `amd64` | `stplr install nivora/codex` |
|
||||
| [GitHub Desktop](docs/packages/github-desktop.md) | `3.6.3` | `amd64`, `arm64` | `stplr install nivora/github-desktop` |
|
||||
| [OpenCode](https://opencode.ai/) | `1.18.4` | `amd64`, `arm64` | `stplr install nivora/opencode` |
|
||||
| [OpenCode](https://opencode.ai/) | `1.18.10` | `amd64`, `arm64` | `stplr install nivora/opencode` |
|
||||
| [Vintner](https://github.com/Cheviiot/vintner) | `0.5.0` | `amd64`, `arm64` | `stplr install nivora/vintner` |
|
||||
|
||||
### Рабочий стол
|
||||
|
||||
@@ -87,7 +92,7 @@ stplr info nivora/codex
|
||||
|:--|:--:|:--:|:--|
|
||||
| [balenaEtcher](https://etcher.balena.io/) | `2.1.6` | `amd64` | `stplr install nivora/balena-etcher` |
|
||||
| [Fisher](https://github.com/jorgebucaran/fisher) | `4.4.8` | `all` | `stplr install nivora/fisher` |
|
||||
| [Nivora Stapler Helper](docs/packages/nivora-stplr.md) | `0.3.0` | `all` | `stplr install nivora/nivora-stplr` |
|
||||
| [Nivora CLI](docs/packages/nivora-cli.md) | `1.0.0` | `all` | `stplr install nivora/nivora-cli` |
|
||||
| [Ventoy](docs/packages/ventoy.md) | `1.1.17` | `amd64`, `arm64` | `stplr install nivora/ventoy` |
|
||||
|
||||
## Обновление
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
exec "${root}/tools/package_updates.sh" check claude-alt
|
||||
@@ -0,0 +1,134 @@
|
||||
name='claude-alt'
|
||||
version=1.24012.0
|
||||
release=1
|
||||
summary='Independent secondary Claude desktop application'
|
||||
summary_ru='Независимое второе приложение Claude'
|
||||
group='Development/Tools'
|
||||
desc='A fully independent secondary Claude Desktop installation with its own runtime, profile, desktop identity and Nivora icons.'
|
||||
desc_ru='Полностью независимая вторая установка Claude Desktop с собственным runtime, профилем, desktop-идентичностью и иконками Nivora.'
|
||||
homepage='https://github.com/Cheviiot/Nivora'
|
||||
maintainer='Nivora <https://github.com/Cheviiot/Nivora>'
|
||||
architectures=('amd64' 'arm64')
|
||||
license=('Custom')
|
||||
nonfree=1
|
||||
nonfree_msg='ClaudeAlt использует проприетарный Claude Desktop и условия Anthropic.'
|
||||
nonfree_url='https://www.anthropic.com/legal/consumer-terms'
|
||||
provides=()
|
||||
replaces=('claude-alt')
|
||||
conflicts=()
|
||||
auto_reqprov_method="dirty"
|
||||
auto_req=0
|
||||
auto_prov=0
|
||||
|
||||
deps=()
|
||||
deps_debian=('libgtk-3-0' 'libnotify4' 'libnss3' 'xdg-utils' 'libatspi2.0-0' 'libdrm2' 'libgbm1' 'libxcb-dri3-0' 'libsecret-1-0' 'libc6' 'libxtst6' 'libuuid1' 'xdg-desktop-portal')
|
||||
deps_ubuntu=("${deps_debian[@]}")
|
||||
deps_fedora=('gtk3' 'libnotify' 'nss' 'xdg-utils' 'at-spi2-core' 'libdrm' 'mesa-libgbm' 'libxcb' 'libsecret' 'glibc' 'libXtst' 'libuuid' 'xdg-desktop-portal')
|
||||
deps_arch=('gtk3' 'libnotify' 'nss' 'xdg-utils' 'at-spi2-core' 'libdrm' 'libgbm' 'libxcb' 'libsecret' 'glibc' 'libxtst' 'libutil-linux' 'xdg-desktop-portal')
|
||||
deps_opensuse=('gtk3' 'libnotify4' 'mozilla-nss' 'xdg-utils' 'at-spi2-core' 'libdrm2' 'libgbm1' 'libxcb-dri3-0' 'libsecret-1-0' 'glibc' 'libXtst6' 'libuuid1' 'xdg-desktop-portal')
|
||||
deps_altlinux=('libgtk+3' 'libnotify' 'libnss' 'xdg-utils' 'libat-spi2-core' 'libdrm' 'libgbm' 'libxcb' 'libsecret' 'glibc' 'libXtst' 'libuuid' 'xdg-desktop-portal')
|
||||
|
||||
build_deps=('binutils')
|
||||
build_deps_debian=('binutils' 'python3')
|
||||
build_deps_ubuntu=("${build_deps_debian[@]}")
|
||||
build_deps_fedora=('binutils' 'python3')
|
||||
build_deps_arch=('binutils' 'python')
|
||||
build_deps_opensuse=('binutils' 'python3')
|
||||
build_deps_altlinux=('binutils' 'python3')
|
||||
|
||||
sources=(
|
||||
"https://downloads.claude.ai/claude-desktop/apt/stable/pool/main/c/claude-desktop/claude-desktop_${version}_amd64.deb?~archive=false&~name=claude-desktop.deb"
|
||||
"local:///claude-alt"
|
||||
"https://raw.githubusercontent.com/Cheviiot/Nivora/main/claude/claude-alt.png?~archive=false&~name=claude-alt.png"
|
||||
"https://raw.githubusercontent.com/Cheviiot/Nivora/main/claude/claude-alt-tray-turquoise.png?~archive=false&~name=claude-alt-tray.png"
|
||||
"local:///patch-asar.py"
|
||||
)
|
||||
sources_arm64=(
|
||||
"https://downloads.claude.ai/claude-desktop/apt/stable/pool/main/c/claude-desktop/claude-desktop_${version}_arm64.deb?~archive=false&~name=claude-desktop.deb"
|
||||
"local:///claude-alt"
|
||||
"https://raw.githubusercontent.com/Cheviiot/Nivora/main/claude/claude-alt.png?~archive=false&~name=claude-alt.png"
|
||||
"https://raw.githubusercontent.com/Cheviiot/Nivora/main/claude/claude-alt-tray-turquoise.png?~archive=false&~name=claude-alt-tray.png"
|
||||
"local:///patch-asar.py"
|
||||
)
|
||||
checksums=(
|
||||
'sha256:1096a8063956f8430fdbe504bb1c5e02985f31d0f45d082e4966e5d30ea7e3ac'
|
||||
'sha256:b5264918d7cc3436bde057057e5790f617e42ccfcd1237d9170d26aea12799b8'
|
||||
'sha256:f23de36a74c3f6ddae92511fc0dc659816853bf1d28520a6e0232fe2606fd0b4'
|
||||
'sha256:21d1db80c30921346252ed405fa36cb5c48c287afdd8ebe474073389fd88e85e'
|
||||
'sha256:14e0a5ce4da6afb25b13b3cee0b0264fbd896430dae85ade1f3394d8ca999e7d'
|
||||
)
|
||||
checksums_arm64=(
|
||||
'sha256:37dd5dc1b0bfcb3192561acbd33cb59037806fe9b95221a3ddf38244203196f1'
|
||||
'sha256:b5264918d7cc3436bde057057e5790f617e42ccfcd1237d9170d26aea12799b8'
|
||||
'sha256:f23de36a74c3f6ddae92511fc0dc659816853bf1d28520a6e0232fe2606fd0b4'
|
||||
'sha256:21d1db80c30921346252ed405fa36cb5c48c287afdd8ebe474073389fd88e85e'
|
||||
'sha256:14e0a5ce4da6afb25b13b3cee0b0264fbd896430dae85ade1f3394d8ca999e7d'
|
||||
)
|
||||
|
||||
scripts=(
|
||||
['postinstall']='postinstall.sh'
|
||||
['postremove']='postremove.sh'
|
||||
)
|
||||
|
||||
package() {
|
||||
cd "${srcdir}"
|
||||
mkdir -p extracted
|
||||
ar x claude-desktop.deb
|
||||
tar -xf data.tar.* -C extracted
|
||||
install -dm755 "${pkgdir}/usr/lib"
|
||||
cp -a extracted/usr/lib/claude-desktop "${pkgdir}/usr/lib/claude-alt"
|
||||
mv "${pkgdir}/usr/lib/claude-alt/claude-desktop" \
|
||||
"${pkgdir}/usr/lib/claude-alt/claude-alt-bin"
|
||||
chmod 0755 "${pkgdir}/usr/lib/claude-alt/claude-alt-bin" \
|
||||
"${pkgdir}/usr/lib/claude-alt/chrome-sandbox"
|
||||
python3 patch-asar.py "${pkgdir}/usr/lib/claude-alt/resources/app.asar"
|
||||
install -Dm755 claude-alt "${pkgdir}/usr/lib/claude-alt/claude-alt"
|
||||
install -Dm644 claude-alt.png "${pkgdir}/usr/lib/claude-alt/resources/icon.png"
|
||||
for icon in TrayIconLinux.png TrayIconLinux-Dark.png; do
|
||||
install -Dm644 claude-alt-tray.png \
|
||||
"${pkgdir}/usr/lib/claude-alt/resources/${icon}"
|
||||
done
|
||||
install -dm755 "${pkgdir}/usr/bin"
|
||||
ln -s /usr/lib/claude-alt/claude-alt "${pkgdir}/usr/bin/claude-alt"
|
||||
ln -s claude-alt "${pkgdir}/usr/bin/claude-code-alt"
|
||||
install -Dm644 claude-alt.png \
|
||||
"${pkgdir}/usr/share/icons/hicolor/512x512/apps/claude-alt.png"
|
||||
install -Dm644 /dev/stdin \
|
||||
"${pkgdir}/usr/share/applications/com.anthropic.ClaudeAlt.desktop" <<'EOF'
|
||||
[Desktop Entry]
|
||||
Name=ClaudeAlt
|
||||
Name[ru]=ClaudeAlt
|
||||
Comment=Independent secondary Claude desktop application
|
||||
Comment[ru]=Независимое второе приложение Claude
|
||||
GenericName=AI Assistant
|
||||
Keywords=AI;Chat;Assistant;Claude;Code;LLM;
|
||||
Exec=/usr/bin/claude-alt %U
|
||||
Icon=claude-alt
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
StartupWMClass=com.anthropic.ClaudeAlt
|
||||
SingleMainWindow=true
|
||||
Categories=Development;
|
||||
Actions=NewChat;NewCode;
|
||||
|
||||
[Desktop Action NewChat]
|
||||
Name=New chat
|
||||
Name[ru]=Новый чат
|
||||
Exec=/usr/bin/claude-alt claude://claude.ai/new
|
||||
|
||||
[Desktop Action NewCode]
|
||||
Name=New Claude Code session
|
||||
Name[ru]=Новая сессия Claude Code
|
||||
Exec=/usr/bin/claude-alt claude://code/new
|
||||
EOF
|
||||
install-license extracted/usr/share/doc/claude-desktop/copyright \
|
||||
"claude-alt/copyright"
|
||||
}
|
||||
|
||||
files() {
|
||||
files-find "/usr/lib/claude-alt/**/*"
|
||||
files-find-binary
|
||||
files-find-desktop
|
||||
files-find-license
|
||||
files-find "/usr/share/icons/hicolor/*/apps/claude-alt.png"
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
if [ -z "${HOME:-}" ] && [ -z "${XDG_CONFIG_HOME:-}" ]; then
|
||||
echo "claude-alt: HOME or XDG_CONFIG_HOME is required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
config_home="${XDG_CONFIG_HOME:-${HOME}/.config}"
|
||||
default_data_dir="${config_home}/ClaudeAlt"
|
||||
legacy_data_dir="${CLAUDE_DESKTOP_ACCOUNT2_DIR:-${config_home}/Claude-Account-2}"
|
||||
claude_alt_executable="${CLAUDE_ALT_EXECUTABLE:-/usr/lib/claude-alt/claude-alt-bin}"
|
||||
|
||||
if [ -n "${CLAUDE_ALT_DATA_DIR:-}" ]; then
|
||||
data_dir="${CLAUDE_ALT_DATA_DIR}"
|
||||
elif [ -d "${default_data_dir}" ]; then
|
||||
data_dir="${default_data_dir}"
|
||||
elif [ -d "${legacy_data_dir}" ]; then
|
||||
data_dir="${legacy_data_dir}"
|
||||
else
|
||||
data_dir="${default_data_dir}"
|
||||
fi
|
||||
|
||||
if [ ! -x "${claude_alt_executable}" ]; then
|
||||
echo "claude-alt: executable not found: ${claude_alt_executable}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${data_dir}"
|
||||
CHROME_DESKTOP='com.anthropic.ClaudeAlt.desktop'
|
||||
export CHROME_DESKTOP
|
||||
|
||||
exec "${claude_alt_executable}" \
|
||||
--user-data-dir="${data_dir}" \
|
||||
--class=com.anthropic.ClaudeAlt \
|
||||
"$@"
|
||||
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Give ClaudeAlt an independent Electron identity without changing its protocol."""
|
||||
|
||||
import copy
|
||||
import hashlib
|
||||
import json
|
||||
import struct
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
path = Path(sys.argv[1])
|
||||
data = path.read_bytes()
|
||||
if len(data) < 16:
|
||||
raise SystemExit("ClaudeAlt app.asar is too small")
|
||||
|
||||
_, _, _, header_size = struct.unpack("<IIII", data[:16])
|
||||
header = json.loads(data[16 : 16 + header_size])
|
||||
base_offset = 16 + ((header_size + 3) & ~3)
|
||||
output = bytearray()
|
||||
counts = {"package": 0, "socket": 0, "user_agent": 0}
|
||||
|
||||
|
||||
def integrity(content: bytes, block_size: int) -> dict:
|
||||
blocks = [
|
||||
hashlib.sha256(content[index : index + block_size]).hexdigest()
|
||||
for index in range(0, len(content), block_size)
|
||||
] or [hashlib.sha256(b"").hexdigest()]
|
||||
return {
|
||||
"algorithm": "SHA256",
|
||||
"hash": hashlib.sha256(content).hexdigest(),
|
||||
"blockSize": block_size,
|
||||
"blocks": blocks,
|
||||
}
|
||||
|
||||
|
||||
def rebuild(node: dict, prefix: str = "") -> dict:
|
||||
result = {}
|
||||
for name, child in node.get("files", {}).items():
|
||||
item_path = f"{prefix}/{name}" if prefix else name
|
||||
if "files" in child:
|
||||
result[name] = {
|
||||
**{key: value for key, value in child.items() if key != "files"},
|
||||
"files": rebuild(child, item_path),
|
||||
}
|
||||
continue
|
||||
|
||||
entry = copy.deepcopy(child)
|
||||
if entry.get("unpacked"):
|
||||
result[name] = entry
|
||||
continue
|
||||
|
||||
offset, size = int(entry["offset"]), int(entry["size"])
|
||||
content = data[base_offset + offset : base_offset + offset + size]
|
||||
changed = False
|
||||
|
||||
if item_path == "package.json":
|
||||
package = json.loads(content)
|
||||
expected = {
|
||||
"productName": "Claude",
|
||||
"desktopName": "com.anthropic.Claude.desktop",
|
||||
}
|
||||
for field, value in expected.items():
|
||||
if package.get(field) != value:
|
||||
raise SystemExit(
|
||||
f"unexpected Claude package.json {field}: "
|
||||
f"{package.get(field)!r} != {value!r}"
|
||||
)
|
||||
package["productName"] = "ClaudeAlt"
|
||||
package["desktopName"] = "com.anthropic.ClaudeAlt.desktop"
|
||||
content = (json.dumps(package, indent=2) + "\n").encode()
|
||||
counts["package"] += 1
|
||||
changed = True
|
||||
|
||||
old_socket = b"claude-cowork-vm.sock"
|
||||
socket_count = content.count(old_socket)
|
||||
if socket_count:
|
||||
content = content.replace(old_socket, b"claude-alt-cowork-vm.sock")
|
||||
counts["socket"] += socket_count
|
||||
changed = True
|
||||
|
||||
marker = b'P.app.isPackaged||P.app.setName("Claude");RRn();'
|
||||
marker_count = content.count(marker)
|
||||
if marker_count:
|
||||
content = content.replace(
|
||||
marker,
|
||||
b'P.app.isPackaged||P.app.setName("Claude");'
|
||||
b'P.app.userAgentFallback=P.app.userAgentFallback'
|
||||
b'.replaceAll("ClaudeAlt","Claude");RRn();',
|
||||
)
|
||||
counts["user_agent"] += marker_count
|
||||
changed = True
|
||||
|
||||
entry["offset"] = str(len(output))
|
||||
if changed:
|
||||
entry["size"] = len(content)
|
||||
block_size = entry.get("integrity", {}).get("blockSize", 4194304)
|
||||
entry["integrity"] = integrity(content, block_size)
|
||||
output.extend(content)
|
||||
result[name] = entry
|
||||
return result
|
||||
|
||||
|
||||
rebuilt_header = {"files": rebuild(header)}
|
||||
if counts != {"package": 1, "socket": 1, "user_agent": 1}:
|
||||
raise SystemExit(f"unexpected ClaudeAlt patch counts: {counts}")
|
||||
|
||||
header_bytes = json.dumps(rebuilt_header, separators=(",", ":")).encode()
|
||||
padded_size = (len(header_bytes) + 3) & ~3
|
||||
patched = (
|
||||
struct.pack("<IIII", 4, padded_size + 8, padded_size + 4, len(header_bytes))
|
||||
+ header_bytes
|
||||
+ b"\0" * (padded_size - len(header_bytes))
|
||||
+ bytes(output)
|
||||
)
|
||||
required = (
|
||||
b"com.anthropic.ClaudeAlt.desktop",
|
||||
b'"productName": "ClaudeAlt"',
|
||||
b'.replaceAll("ClaudeAlt","Claude")',
|
||||
b"claude-alt-cowork-vm.sock",
|
||||
)
|
||||
if any(patched.count(value) != 1 for value in required):
|
||||
raise SystemExit("ClaudeAlt identity verification failed")
|
||||
path.write_bytes(patched)
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
sandbox=/usr/lib/claude-alt/chrome-sandbox
|
||||
if [[ ! -f "$sandbox" ]]; then
|
||||
echo "Ошибка: не найден Electron sandbox: ${sandbox}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -L /proc/self/ns/user ]] && command -v unshare >/dev/null 2>&1 \
|
||||
&& unshare --user true 2>/dev/null; then
|
||||
chmod 0755 "$sandbox"
|
||||
else
|
||||
chmod 4755 "$sandbox"
|
||||
fi
|
||||
|
||||
if command -v update-desktop-database >/dev/null 2>&1; then
|
||||
update-desktop-database -q /usr/share/applications || true
|
||||
fi
|
||||
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
|
||||
gtk-update-icon-cache -f -q /usr/share/icons/hicolor || true
|
||||
fi
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
if command -v update-desktop-database >/dev/null 2>&1; then
|
||||
update-desktop-database -q /usr/share/applications || true
|
||||
fi
|
||||
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
|
||||
gtk-update-icon-cache -f -q /usr/share/icons/hicolor || true
|
||||
fi
|
||||
@@ -1,388 +0,0 @@
|
||||
name='claude-desktop'
|
||||
version=1.24012.0
|
||||
release=4
|
||||
summary='Claude desktop application'
|
||||
summary_ru='Десктопное приложение Claude'
|
||||
group='Development/Tools'
|
||||
desc='Claude is the Anthropic desktop application for Claude and Claude Code workflows with chat, project context, integrated terminal, editor and visual diff review.'
|
||||
desc_ru='Claude — десктопное приложение Anthropic для Claude и сценариев Claude Code: чат, контекст проекта, встроенный терминал, редактор и визуальный просмотр diff.'
|
||||
homepage='https://code.claude.com/docs/en/desktop-quickstart'
|
||||
maintainer='Anthropic PBC <support@anthropic.com>'
|
||||
|
||||
architectures=('amd64' 'arm64')
|
||||
|
||||
license=('Custom')
|
||||
nonfree=1
|
||||
nonfree_msg='Claude Desktop является проприетарным приложением Anthropic. Использование Claude, Claude Code, учетной записи, подписки, сетевых функций и моделей регулируется условиями Anthropic.'
|
||||
nonfree_url='https://www.anthropic.com/legal/consumer-terms'
|
||||
|
||||
provides=()
|
||||
replaces=('claude-desktop')
|
||||
conflicts=()
|
||||
|
||||
auto_reqprov_method="dirty"
|
||||
auto_req=0
|
||||
auto_prov=0
|
||||
|
||||
deps=()
|
||||
deps_debian=('libgtk-3-0' 'libnotify4' 'libnss3' 'xdg-utils' 'libatspi2.0-0' 'libdrm2' 'libgbm1' 'libxcb-dri3-0' 'libsecret-1-0' 'libc6' 'libxtst6' 'libuuid1' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk | xdg-desktop-portal-gnome | xdg-desktop-portal-kde')
|
||||
deps_ubuntu=("${deps_debian[@]}")
|
||||
deps_fedora=('gtk3' 'libnotify' 'nss' 'xdg-utils' 'at-spi2-core' 'libdrm' 'mesa-libgbm' 'libxcb' 'libsecret' 'glibc' 'libXtst' 'libuuid' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk')
|
||||
deps_arch=('gtk3' 'libnotify' 'nss' 'xdg-utils' 'at-spi2-core' 'libdrm' 'libgbm' 'libxcb' 'libsecret' 'glibc' 'libxtst' 'libutil-linux' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk')
|
||||
deps_opensuse=('gtk3' 'libnotify4' 'mozilla-nss' 'xdg-utils' 'at-spi2-core' 'libdrm2' 'libgbm1' 'libxcb-dri3-0' 'libsecret-1-0' 'glibc' 'libXtst6' 'libuuid1' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk')
|
||||
deps_altlinux=('libgtk+3' 'libnotify' 'libnss' 'xdg-utils' 'libat-spi2-core' 'libdrm' 'libgbm' 'libxcb' 'libsecret' 'glibc' 'libXtst' 'libuuid' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk')
|
||||
|
||||
opt_deps=()
|
||||
opt_deps_debian=('libasound2t64 | libasound2 | pulseaudio' 'libayatana-appindicator3-1 | libappindicator3-1' 'ca-certificates' 'gnome-keyring | kwalletd6 | kwalletd5' 'qemu-system-x86' 'ovmf' 'virtiofsd')
|
||||
opt_deps_ubuntu=("${opt_deps_debian[@]}")
|
||||
opt_deps_fedora=('alsa-lib' 'pulseaudio-libs' 'libappindicator-gtk3' 'ca-certificates' 'gnome-keyring' 'kwallet' 'qemu-system-x86' 'edk2-ovmf' 'virtiofsd')
|
||||
opt_deps_arch=('alsa-lib' 'pulseaudio' 'libappindicator-gtk3' 'ca-certificates' 'gnome-keyring' 'kwallet' 'qemu-system-x86' 'edk2-ovmf' 'virtiofsd')
|
||||
opt_deps_opensuse=('libasound2' 'libpulse0' 'libappindicator3-1' 'ca-certificates' 'gnome-keyring' 'kwallet6' 'qemu-x86' 'ovmf' 'virtiofsd')
|
||||
opt_deps_altlinux=('libalsa' 'libappindicator-gtk3' 'ca-certificates' 'gnome-keyring' 'qemu-system-x86' 'virtiofsd')
|
||||
|
||||
build_deps=('binutils')
|
||||
build_deps_debian=('binutils' 'python3')
|
||||
build_deps_ubuntu=("${build_deps_debian[@]}")
|
||||
build_deps_fedora=('binutils' 'python3')
|
||||
build_deps_arch=('binutils' 'python')
|
||||
build_deps_opensuse=('binutils' 'python3')
|
||||
build_deps_altlinux=('binutils' 'python3')
|
||||
|
||||
sources=(
|
||||
"https://downloads.claude.ai/claude-desktop/apt/stable/pool/main/c/claude-desktop/claude-desktop_${version}_amd64.deb?~archive=false&~name=claude-desktop.deb"
|
||||
"local:///claude-alt"
|
||||
"local:///claude-alt.png"
|
||||
"local:///claude-tray-orange.png"
|
||||
"local:///claude-alt-tray-turquoise.png"
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
sources_arm64=(
|
||||
"https://downloads.claude.ai/claude-desktop/apt/stable/pool/main/c/claude-desktop/claude-desktop_${version}_arm64.deb?~archive=false&~name=claude-desktop.deb"
|
||||
"local:///claude-alt"
|
||||
"local:///claude-alt.png"
|
||||
"local:///claude-tray-orange.png"
|
||||
"local:///claude-alt-tray-turquoise.png"
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:1096a8063956f8430fdbe504bb1c5e02985f31d0f45d082e4966e5d30ea7e3ac'
|
||||
'sha256:00d9fe6549d82f564a99c6e8ec54d1380fdf8f0a20c99bb9b3cda1f689adf57d'
|
||||
'sha256:f23de36a74c3f6ddae92511fc0dc659816853bf1d28520a6e0232fe2606fd0b4'
|
||||
'sha256:be51081c0e0b2eec3489c25da38194dccf68fe7445928b32c30e1b8051eb557b'
|
||||
'sha256:21d1db80c30921346252ed405fa36cb5c48c287afdd8ebe474073389fd88e85e'
|
||||
'sha256:40efe7a2755d02c9fe13f98cae18705e2d31e5bbb24816ebbd4951c5e3a56b3f'
|
||||
)
|
||||
|
||||
checksums_arm64=(
|
||||
'sha256:37dd5dc1b0bfcb3192561acbd33cb59037806fe9b95221a3ddf38244203196f1'
|
||||
'sha256:00d9fe6549d82f564a99c6e8ec54d1380fdf8f0a20c99bb9b3cda1f689adf57d'
|
||||
'sha256:f23de36a74c3f6ddae92511fc0dc659816853bf1d28520a6e0232fe2606fd0b4'
|
||||
'sha256:be51081c0e0b2eec3489c25da38194dccf68fe7445928b32c30e1b8051eb557b'
|
||||
'sha256:21d1db80c30921346252ed405fa36cb5c48c287afdd8ebe474073389fd88e85e'
|
||||
'sha256:40efe7a2755d02c9fe13f98cae18705e2d31e5bbb24816ebbd4951c5e3a56b3f'
|
||||
)
|
||||
|
||||
scripts=(
|
||||
['postinstall']='postinstall.sh'
|
||||
['postremove']='postremove.sh'
|
||||
)
|
||||
|
||||
package() {
|
||||
cd "${srcdir}"
|
||||
|
||||
mkdir -p "${srcdir}/extracted"
|
||||
ar x claude-desktop.deb
|
||||
tar -xf data.tar.* -C "${srcdir}/extracted"
|
||||
|
||||
install -dm755 "${pkgdir}/usr/lib"
|
||||
cp -a "${srcdir}/extracted/usr/lib/claude-desktop" "${pkgdir}/usr/lib/"
|
||||
chmod 0755 "${pkgdir}/usr/lib/claude-desktop/chrome-sandbox"
|
||||
chmod 755 \
|
||||
"${pkgdir}/usr/lib/claude-desktop/claude-desktop" \
|
||||
"${pkgdir}/usr/lib/claude-desktop/resources/chrome-native-host" \
|
||||
"${pkgdir}/usr/lib/claude-desktop/resources/cowork-linux-helper" \
|
||||
"${pkgdir}/usr/lib/claude-desktop/resources/virtiofsd"
|
||||
|
||||
# Сохраняем штатный tray-глиф Claude, меняя только его цвет.
|
||||
for icon_name in TrayIconLinux.png TrayIconLinux-Dark.png; do
|
||||
install -Dm644 "${srcdir}/claude-tray-orange.png" \
|
||||
"${pkgdir}/usr/lib/claude-desktop/resources/${icon_name}"
|
||||
done
|
||||
|
||||
# ClaudeAlt получает отдельные executable и app.asar. Остальные неизменяемые
|
||||
# Electron-файлы подключаются к основной копии относительными symlink-ами.
|
||||
# Это сохраняет отдельный resourcesPath, но не удваивает пакет целиком.
|
||||
install -dm755 \
|
||||
"${pkgdir}/usr/lib/claude-alt" \
|
||||
"${pkgdir}/usr/lib/claude-alt/resources"
|
||||
cp -p "${pkgdir}/usr/lib/claude-desktop/claude-desktop" \
|
||||
"${pkgdir}/usr/lib/claude-alt/claude-alt-bin"
|
||||
|
||||
for entry in "${pkgdir}/usr/lib/claude-desktop"/*; do
|
||||
entry_name="${entry##*/}"
|
||||
case "${entry_name}" in
|
||||
claude-desktop | resources) continue ;;
|
||||
esac
|
||||
ln -s "../claude-desktop/${entry_name}" \
|
||||
"${pkgdir}/usr/lib/claude-alt/${entry_name}"
|
||||
done
|
||||
|
||||
for entry in "${pkgdir}/usr/lib/claude-desktop/resources"/*; do
|
||||
entry_name="${entry##*/}"
|
||||
case "${entry_name}" in
|
||||
app.asar)
|
||||
cp -p "${entry}" "${pkgdir}/usr/lib/claude-alt/resources/app.asar"
|
||||
;;
|
||||
icon.png | TrayIconLinux.png | TrayIconLinux-Dark.png)
|
||||
# Эти ресурсы ниже заменяются иконкой ClaudeAlt.
|
||||
;;
|
||||
*)
|
||||
ln -s "../../claude-desktop/resources/${entry_name}" \
|
||||
"${pkgdir}/usr/lib/claude-alt/resources/${entry_name}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Большая иконка ClaudeAlt используется окном, а в tray устанавливается
|
||||
# отдельный бирюзовый вариант штатного глифа Claude.
|
||||
install -Dm644 "${srcdir}/claude-alt.png" \
|
||||
"${pkgdir}/usr/lib/claude-alt/resources/icon.png"
|
||||
for icon_name in TrayIconLinux.png TrayIconLinux-Dark.png; do
|
||||
install -Dm644 "${srcdir}/claude-alt-tray-turquoise.png" \
|
||||
"${pkgdir}/usr/lib/claude-alt/resources/${icon_name}"
|
||||
done
|
||||
|
||||
alt_asar="${pkgdir}/usr/lib/claude-alt/resources/app.asar"
|
||||
|
||||
python3 - "${alt_asar}" <<'PY'
|
||||
import copy
|
||||
import hashlib
|
||||
import json
|
||||
import struct
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
asar_path = Path(sys.argv[1])
|
||||
data = asar_path.read_bytes()
|
||||
if len(data) < 16:
|
||||
raise SystemExit("ClaudeAlt app.asar is too small")
|
||||
|
||||
_, _, _, header_size = struct.unpack("<IIII", data[:16])
|
||||
header = json.loads(data[16 : 16 + header_size])
|
||||
base_offset = 16 + ((header_size + 3) & ~3)
|
||||
output = bytearray()
|
||||
patched_package_json = 0
|
||||
patched_cowork_socket = 0
|
||||
patched_user_agent = 0
|
||||
|
||||
|
||||
def integrity_for(content: bytes, block_size: int = 4194304) -> dict:
|
||||
blocks = [
|
||||
hashlib.sha256(content[index : index + block_size]).hexdigest()
|
||||
for index in range(0, len(content), block_size)
|
||||
]
|
||||
if not blocks:
|
||||
blocks = [hashlib.sha256(b"").hexdigest()]
|
||||
return {
|
||||
"algorithm": "SHA256",
|
||||
"hash": hashlib.sha256(content).hexdigest(),
|
||||
"blockSize": block_size,
|
||||
"blocks": blocks,
|
||||
}
|
||||
|
||||
|
||||
def rebuild_node(node: dict, prefix: str = "") -> dict:
|
||||
global patched_cowork_socket, patched_package_json, patched_user_agent
|
||||
|
||||
rebuilt = {}
|
||||
for name, child in node.get("files", {}).items():
|
||||
path = f"{prefix}/{name}" if prefix else name
|
||||
if "files" in child:
|
||||
rebuilt[name] = {
|
||||
**{key: value for key, value in child.items() if key != "files"},
|
||||
"files": rebuild_node(child, path),
|
||||
}
|
||||
continue
|
||||
|
||||
entry = copy.deepcopy(child)
|
||||
if entry.get("unpacked"):
|
||||
rebuilt[name] = entry
|
||||
continue
|
||||
|
||||
offset = int(entry["offset"])
|
||||
size = int(entry["size"])
|
||||
content = data[base_offset + offset : base_offset + offset + size]
|
||||
content_changed = False
|
||||
|
||||
if path == "package.json":
|
||||
package_json = json.loads(content)
|
||||
expected = {
|
||||
"productName": "Claude",
|
||||
"desktopName": "com.anthropic.Claude.desktop",
|
||||
}
|
||||
for field, expected_value in expected.items():
|
||||
if package_json.get(field) != expected_value:
|
||||
raise SystemExit(
|
||||
f"unexpected Claude package.json {field}: "
|
||||
f"{package_json.get(field)!r} != {expected_value!r}"
|
||||
)
|
||||
# Отдельный productName нужен Electron для независимого instance
|
||||
# lock. Официальный User-Agent восстанавливается ниже отдельно.
|
||||
package_json["productName"] = "ClaudeAlt"
|
||||
package_json["desktopName"] = "com.anthropic.ClaudeAlt.desktop"
|
||||
content = (json.dumps(package_json, indent=2) + "\n").encode("utf-8")
|
||||
patched_package_json += 1
|
||||
content_changed = True
|
||||
|
||||
socket_name = b"claude-cowork-vm.sock"
|
||||
socket_matches = content.count(socket_name)
|
||||
if socket_matches:
|
||||
content = content.replace(socket_name, b"claude-alt-cowork-vm.sock")
|
||||
patched_cowork_socket += socket_matches
|
||||
content_changed = True
|
||||
|
||||
user_agent_marker = (
|
||||
b'P.app.isPackaged||P.app.setName("Claude");RRn();'
|
||||
)
|
||||
user_agent_matches = content.count(user_agent_marker)
|
||||
if user_agent_matches:
|
||||
content = content.replace(
|
||||
user_agent_marker,
|
||||
b'P.app.isPackaged||P.app.setName("Claude");'
|
||||
b'P.app.userAgentFallback=P.app.userAgentFallback'
|
||||
b'.replaceAll("ClaudeAlt","Claude");RRn();',
|
||||
)
|
||||
patched_user_agent += user_agent_matches
|
||||
content_changed = True
|
||||
|
||||
entry["offset"] = str(len(output))
|
||||
if content_changed:
|
||||
entry["size"] = len(content)
|
||||
entry["integrity"] = integrity_for(
|
||||
content,
|
||||
entry.get("integrity", {}).get("blockSize", 4194304),
|
||||
)
|
||||
output.extend(content)
|
||||
rebuilt[name] = entry
|
||||
|
||||
return rebuilt
|
||||
|
||||
|
||||
rebuilt_header = {"files": rebuild_node(header)}
|
||||
if patched_package_json != 1:
|
||||
raise SystemExit(
|
||||
f"expected one ClaudeAlt package.json, got {patched_package_json}"
|
||||
)
|
||||
if patched_cowork_socket != 1:
|
||||
raise SystemExit(
|
||||
f"expected one ClaudeAlt Cowork socket, got {patched_cowork_socket}"
|
||||
)
|
||||
if patched_user_agent != 1:
|
||||
raise SystemExit(
|
||||
f"expected one ClaudeAlt User-Agent patch, got {patched_user_agent}"
|
||||
)
|
||||
|
||||
header_bytes = json.dumps(rebuilt_header, separators=(",", ":")).encode("utf-8")
|
||||
header_padded_size = (len(header_bytes) + 3) & ~3
|
||||
patched_data = (
|
||||
struct.pack(
|
||||
"<IIII",
|
||||
4,
|
||||
header_padded_size + 8,
|
||||
header_padded_size + 4,
|
||||
len(header_bytes),
|
||||
)
|
||||
+ header_bytes
|
||||
+ (b"\0" * (header_padded_size - len(header_bytes)))
|
||||
+ bytes(output)
|
||||
)
|
||||
if patched_data.count(b"com.anthropic.ClaudeAlt.desktop") != 1:
|
||||
raise SystemExit("ClaudeAlt desktopName was not written exactly once")
|
||||
if patched_data.count(b'"productName": "ClaudeAlt"') != 1:
|
||||
raise SystemExit("ClaudeAlt productName was not written exactly once")
|
||||
if patched_data.count(b'.replaceAll("ClaudeAlt","Claude")') != 1:
|
||||
raise SystemExit("ClaudeAlt official User-Agent patch is missing")
|
||||
if patched_data.count(b"claude-alt-cowork-vm.sock") != 1:
|
||||
raise SystemExit("ClaudeAlt Cowork socket was not written exactly once")
|
||||
asar_path.write_bytes(patched_data)
|
||||
PY
|
||||
|
||||
chmod 755 "${pkgdir}/usr/lib/claude-alt/claude-alt-bin"
|
||||
install -Dm755 "${srcdir}/claude-alt" \
|
||||
"${pkgdir}/usr/lib/claude-alt/claude-alt"
|
||||
|
||||
install -dm755 "${pkgdir}/usr/share"
|
||||
cp -a "${srcdir}/extracted/usr/share/applications" "${pkgdir}/usr/share/"
|
||||
cp -a "${srcdir}/extracted/usr/share/icons" "${pkgdir}/usr/share/"
|
||||
|
||||
desktop_file="$(find "${pkgdir}/usr/share/applications" -maxdepth 1 -type f -name "*.desktop" | head -1)"
|
||||
[[ -n "${desktop_file}" ]] || {
|
||||
echo "Claude desktop file not found" >&2
|
||||
return 1
|
||||
}
|
||||
sed -i \
|
||||
-e '0,/^Name=/{s/^Name=.*/Name=Claude\nName[ru]=Claude/}' \
|
||||
-e 's/^Categories=.*/Categories=Development;/' \
|
||||
"${desktop_file}"
|
||||
|
||||
install -Dm644 "${srcdir}/claude-alt.png" \
|
||||
"${pkgdir}/usr/share/icons/hicolor/512x512/apps/claude-alt.png"
|
||||
|
||||
install -Dm644 /dev/stdin "${pkgdir}/usr/share/applications/com.anthropic.ClaudeAlt.desktop" <<'EOF'
|
||||
[Desktop Entry]
|
||||
Name=ClaudeAlt
|
||||
Name[ru]=ClaudeAlt
|
||||
Comment=Independent secondary Claude desktop application
|
||||
Comment[ru]=Независимое второе приложение Claude
|
||||
GenericName=AI Assistant
|
||||
Keywords=AI;Chat;Assistant;Claude;Code;LLM;
|
||||
Exec=claude-alt %U
|
||||
Icon=claude-alt
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
StartupWMClass=com.anthropic.ClaudeAlt
|
||||
SingleMainWindow=true
|
||||
Categories=Development;
|
||||
Actions=NewChat;NewCode;
|
||||
|
||||
[Desktop Action NewChat]
|
||||
Name=New chat
|
||||
Name[ru]=Новый чат
|
||||
Exec=claude-alt claude://claude.ai/new
|
||||
|
||||
[Desktop Action NewCode]
|
||||
Name=New Claude Code session
|
||||
Name[ru]=Новая сессия Claude Code
|
||||
Exec=claude-alt claude://code/new
|
||||
EOF
|
||||
|
||||
install -dm755 "${pkgdir}/usr/bin"
|
||||
ln -sfn /usr/lib/claude-desktop/claude-desktop "${pkgdir}/usr/bin/claude-desktop"
|
||||
ln -sfn /usr/lib/claude-alt/claude-alt "${pkgdir}/usr/bin/claude-alt"
|
||||
ln -sfn /usr/lib/claude-alt/claude-alt "${pkgdir}/usr/bin/claude-code-alt"
|
||||
ln -sfn /usr/lib/claude-alt/claude-alt "${pkgdir}/usr/bin/claude-desktop-account2"
|
||||
|
||||
install -dm755 "${pkgdir}/usr/share/licenses/claude-desktop"
|
||||
install-license "${srcdir}/LICENSE" "claude-desktop/LICENSE.nivora"
|
||||
install -Dm644 "${srcdir}/extracted/usr/share/doc/claude-desktop/copyright" \
|
||||
"${pkgdir}/usr/share/licenses/claude-desktop/copyright"
|
||||
install -Dm644 "${srcdir}/extracted/usr/lib/claude-desktop/LICENSES.chromium.html" \
|
||||
"${pkgdir}/usr/share/licenses/claude-desktop/LICENSES.chromium.html"
|
||||
install -Dm644 "${srcdir}/extracted/usr/lib/claude-desktop/resources/virtiofsd.LICENSE-APACHE" \
|
||||
"${pkgdir}/usr/share/licenses/claude-desktop/virtiofsd.LICENSE-APACHE"
|
||||
install -Dm644 "${srcdir}/extracted/usr/lib/claude-desktop/resources/virtiofsd.LICENSE-BSD-3-Clause" \
|
||||
"${pkgdir}/usr/share/licenses/claude-desktop/virtiofsd.LICENSE-BSD-3-Clause"
|
||||
}
|
||||
|
||||
files() {
|
||||
files-find-binary
|
||||
files-find-desktop
|
||||
files-find-license
|
||||
files-find \
|
||||
"/usr/lib/claude-desktop/**/*" \
|
||||
"/usr/lib/claude-alt/**/*" \
|
||||
"/usr/share/icons/hicolor/*/apps/claude-desktop.png" \
|
||||
"/usr/share/icons/hicolor/*/apps/claude-alt.png"
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
name='claude'
|
||||
version=1.24012.0
|
||||
release=1
|
||||
summary='Claude desktop application'
|
||||
summary_ru='Десктопное приложение Claude'
|
||||
group='Development/Tools'
|
||||
desc='Claude is the Anthropic desktop application for Claude and Claude Code workflows with chat, project context, integrated terminal, editor and visual diff review.'
|
||||
desc_ru='Claude — десктопное приложение Anthropic для Claude и сценариев Claude Code: чат, контекст проекта, встроенный терминал, редактор и визуальный просмотр diff.'
|
||||
homepage='https://code.claude.com/docs/en/desktop-quickstart'
|
||||
maintainer='Anthropic PBC <support@anthropic.com>'
|
||||
|
||||
architectures=('amd64' 'arm64')
|
||||
|
||||
license=('Custom')
|
||||
nonfree=1
|
||||
nonfree_msg='Claude Desktop является проприетарным приложением Anthropic. Использование Claude, Claude Code, учетной записи, подписки, сетевых функций и моделей регулируется условиями Anthropic.'
|
||||
nonfree_url='https://www.anthropic.com/legal/consumer-terms'
|
||||
|
||||
provides=()
|
||||
replaces=('claude' 'claude-desktop')
|
||||
conflicts=()
|
||||
|
||||
auto_reqprov_method="dirty"
|
||||
auto_req=0
|
||||
auto_prov=0
|
||||
|
||||
deps=()
|
||||
deps_debian=('libgtk-3-0' 'libnotify4' 'libnss3' 'xdg-utils' 'libatspi2.0-0' 'libdrm2' 'libgbm1' 'libxcb-dri3-0' 'libsecret-1-0' 'libc6' 'libxtst6' 'libuuid1' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk | xdg-desktop-portal-gnome | xdg-desktop-portal-kde')
|
||||
deps_ubuntu=("${deps_debian[@]}")
|
||||
deps_fedora=('gtk3' 'libnotify' 'nss' 'xdg-utils' 'at-spi2-core' 'libdrm' 'mesa-libgbm' 'libxcb' 'libsecret' 'glibc' 'libXtst' 'libuuid' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk')
|
||||
deps_arch=('gtk3' 'libnotify' 'nss' 'xdg-utils' 'at-spi2-core' 'libdrm' 'libgbm' 'libxcb' 'libsecret' 'glibc' 'libxtst' 'libutil-linux' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk')
|
||||
deps_opensuse=('gtk3' 'libnotify4' 'mozilla-nss' 'xdg-utils' 'at-spi2-core' 'libdrm2' 'libgbm1' 'libxcb-dri3-0' 'libsecret-1-0' 'glibc' 'libXtst6' 'libuuid1' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk')
|
||||
deps_altlinux=('libgtk+3' 'libnotify' 'libnss' 'xdg-utils' 'libat-spi2-core' 'libdrm' 'libgbm' 'libxcb' 'libsecret' 'glibc' 'libXtst' 'libuuid' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk')
|
||||
|
||||
opt_deps=()
|
||||
opt_deps_debian=('libasound2t64 | libasound2 | pulseaudio' 'libayatana-appindicator3-1 | libappindicator3-1' 'ca-certificates' 'gnome-keyring | kwalletd6 | kwalletd5' 'qemu-system-x86' 'ovmf' 'virtiofsd')
|
||||
opt_deps_ubuntu=("${opt_deps_debian[@]}")
|
||||
opt_deps_fedora=('alsa-lib' 'pulseaudio-libs' 'libappindicator-gtk3' 'ca-certificates' 'gnome-keyring' 'kwallet' 'qemu-system-x86' 'edk2-ovmf' 'virtiofsd')
|
||||
opt_deps_arch=('alsa-lib' 'pulseaudio' 'libappindicator-gtk3' 'ca-certificates' 'gnome-keyring' 'kwallet' 'qemu-system-x86' 'edk2-ovmf' 'virtiofsd')
|
||||
opt_deps_opensuse=('libasound2' 'libpulse0' 'libappindicator3-1' 'ca-certificates' 'gnome-keyring' 'kwallet6' 'qemu-x86' 'ovmf' 'virtiofsd')
|
||||
opt_deps_altlinux=('libalsa' 'libappindicator-gtk3' 'ca-certificates' 'gnome-keyring' 'qemu-system-x86' 'virtiofsd')
|
||||
|
||||
build_deps=('binutils')
|
||||
build_deps_debian=('binutils' 'python3')
|
||||
build_deps_ubuntu=("${build_deps_debian[@]}")
|
||||
build_deps_fedora=('binutils' 'python3')
|
||||
build_deps_arch=('binutils' 'python')
|
||||
build_deps_opensuse=('binutils' 'python3')
|
||||
build_deps_altlinux=('binutils' 'python3')
|
||||
|
||||
sources=(
|
||||
"https://downloads.claude.ai/claude-desktop/apt/stable/pool/main/c/claude-desktop/claude-desktop_${version}_amd64.deb?~archive=false&~name=claude-desktop.deb"
|
||||
"local:///claude-tray-orange.png"
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
sources_arm64=(
|
||||
"https://downloads.claude.ai/claude-desktop/apt/stable/pool/main/c/claude-desktop/claude-desktop_${version}_arm64.deb?~archive=false&~name=claude-desktop.deb"
|
||||
"local:///claude-tray-orange.png"
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:1096a8063956f8430fdbe504bb1c5e02985f31d0f45d082e4966e5d30ea7e3ac'
|
||||
'sha256:be51081c0e0b2eec3489c25da38194dccf68fe7445928b32c30e1b8051eb557b'
|
||||
'sha256:40efe7a2755d02c9fe13f98cae18705e2d31e5bbb24816ebbd4951c5e3a56b3f'
|
||||
)
|
||||
|
||||
checksums_arm64=(
|
||||
'sha256:37dd5dc1b0bfcb3192561acbd33cb59037806fe9b95221a3ddf38244203196f1'
|
||||
'sha256:be51081c0e0b2eec3489c25da38194dccf68fe7445928b32c30e1b8051eb557b'
|
||||
'sha256:40efe7a2755d02c9fe13f98cae18705e2d31e5bbb24816ebbd4951c5e3a56b3f'
|
||||
)
|
||||
|
||||
scripts=(
|
||||
['postinstall']='postinstall.sh'
|
||||
['postremove']='postremove.sh'
|
||||
)
|
||||
|
||||
package() {
|
||||
cd "${srcdir}"
|
||||
|
||||
mkdir -p "${srcdir}/extracted"
|
||||
ar x claude-desktop.deb
|
||||
tar -xf data.tar.* -C "${srcdir}/extracted"
|
||||
|
||||
install -dm755 "${pkgdir}/usr/lib"
|
||||
cp -a "${srcdir}/extracted/usr/lib/claude-desktop" "${pkgdir}/usr/lib/"
|
||||
chmod 0755 "${pkgdir}/usr/lib/claude-desktop/chrome-sandbox"
|
||||
chmod 755 \
|
||||
"${pkgdir}/usr/lib/claude-desktop/claude-desktop" \
|
||||
"${pkgdir}/usr/lib/claude-desktop/resources/chrome-native-host" \
|
||||
"${pkgdir}/usr/lib/claude-desktop/resources/cowork-linux-helper" \
|
||||
"${pkgdir}/usr/lib/claude-desktop/resources/virtiofsd"
|
||||
|
||||
# Сохраняем штатный tray-глиф Claude, меняя только его цвет.
|
||||
for icon_name in TrayIconLinux.png TrayIconLinux-Dark.png; do
|
||||
install -Dm644 "${srcdir}/claude-tray-orange.png" \
|
||||
"${pkgdir}/usr/lib/claude-desktop/resources/${icon_name}"
|
||||
done
|
||||
|
||||
install -dm755 "${pkgdir}/usr/share"
|
||||
cp -a "${srcdir}/extracted/usr/share/applications" "${pkgdir}/usr/share/"
|
||||
cp -a "${srcdir}/extracted/usr/share/icons" "${pkgdir}/usr/share/"
|
||||
|
||||
desktop_file="$(find "${pkgdir}/usr/share/applications" -maxdepth 1 -type f -name "*.desktop" | head -1)"
|
||||
[[ -n "${desktop_file}" ]] || {
|
||||
echo "Claude desktop file not found" >&2
|
||||
return 1
|
||||
}
|
||||
sed -i \
|
||||
-e '0,/^Name=/{s/^Name=.*/Name=Claude\nName[ru]=Claude/}' \
|
||||
-e 's/^Categories=.*/Categories=Development;/' \
|
||||
"${desktop_file}"
|
||||
|
||||
install -dm755 "${pkgdir}/usr/bin"
|
||||
ln -sfn /usr/lib/claude-desktop/claude-desktop "${pkgdir}/usr/bin/claude-desktop"
|
||||
|
||||
install -dm755 "${pkgdir}/usr/share/licenses/claude-desktop"
|
||||
install-license "${srcdir}/LICENSE" "claude-desktop/LICENSE.nivora"
|
||||
install -Dm644 "${srcdir}/extracted/usr/share/doc/claude-desktop/copyright" \
|
||||
"${pkgdir}/usr/share/licenses/claude-desktop/copyright"
|
||||
install -Dm644 "${srcdir}/extracted/usr/lib/claude-desktop/LICENSES.chromium.html" \
|
||||
"${pkgdir}/usr/share/licenses/claude-desktop/LICENSES.chromium.html"
|
||||
install -Dm644 "${srcdir}/extracted/usr/lib/claude-desktop/resources/virtiofsd.LICENSE-APACHE" \
|
||||
"${pkgdir}/usr/share/licenses/claude-desktop/virtiofsd.LICENSE-APACHE"
|
||||
install -Dm644 "${srcdir}/extracted/usr/lib/claude-desktop/resources/virtiofsd.LICENSE-BSD-3-Clause" \
|
||||
"${pkgdir}/usr/share/licenses/claude-desktop/virtiofsd.LICENSE-BSD-3-Clause"
|
||||
}
|
||||
|
||||
files() {
|
||||
files-find-binary
|
||||
files-find-desktop
|
||||
files-find-license
|
||||
files-find \
|
||||
"/usr/lib/claude-desktop/**/*" \
|
||||
"/usr/share/icons/hicolor/*/apps/claude-desktop.png"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
@@ -1,5 +1,5 @@
|
||||
name='codex'
|
||||
version=26.721.31836
|
||||
version=26.721.81911
|
||||
release=1
|
||||
summary='Unofficial Linux repack of the Codex desktop app'
|
||||
summary_ru='Неофициальная Linux-перепаковка десктопного приложения Codex'
|
||||
@@ -51,7 +51,7 @@ sources=(
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:f48c0ae3fca556d66525b863dd009a0bd0702115517f83c39f8a44cf4d128eb3'
|
||||
'sha256:87798af5884c55a1faab57c8fef818a827a9f0243241c94d19a467d8216aef31'
|
||||
'sha256:8cde2dac642947cdfab23d302056ef81b574cc7f5684f25f7116f80411ec551c'
|
||||
'sha256:fab36489be4f1e92591d2ebcd28a96a95f788b5d1ba87824985623ab7df5e3f4'
|
||||
'sha256:9259dc4b9ae217855d55414b2266db08d9b40c5b0cdbca20a183234ff55ba006'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Инварианты
|
||||
|
||||
- В репозитории ровно 19 каталогов с `Staplerfile`.
|
||||
- В репозитории ровно 24 каталога с `Staplerfile`.
|
||||
- Каталог совпадает с `name` и командой в README.
|
||||
- Upstream-версия не меняется из-за патча рецепта; для этого повышается `release`.
|
||||
- Desktop-id, AppStream component-id, units и пути данных не меняются без отдельной миграции.
|
||||
@@ -17,10 +17,12 @@ Stapler сам добавляет текущее `name` в generated `Provides`
|
||||
| Package ID | Основание |
|
||||
|:--|:--|
|
||||
| `clash-verge-rev` | Upstream-репозиторий и release title: Clash Verge Rev |
|
||||
| `claude-desktop` | Upstream DEB: `Package: claude-desktop`; desktop-id `com.anthropic.Claude` сохранён |
|
||||
| `claude` | Upstream DEB: `Package: claude-desktop`; desktop-id `com.anthropic.Claude` сохранён; старое имя пакета `claude-desktop` заменяется |
|
||||
| `codex` | Отображаемое имя `Codex`; команда и desktop-id `codex-app` сохранены |
|
||||
| `github-desktop` | Официальный upstream `desktop/desktop`; Linux-сборка без стороннего форка |
|
||||
| `nivora-stplr` | Собственный helper Nivora |
|
||||
| `max` | Upstream package name `max`; версия хранится как `VERSION~BUILD` (совпадает с номером сборки в имени deb-файла, как у ALT eepm) для воспроизводимости; пакет всегда запускает бинарник через Firejail (`/etc/firejail/max.profile`), `/usr/bin/max` — не симлинк, а обёртка с `exec firejail` |
|
||||
| `nivora-cli` | Многоязычная оболочка Nivora для Stapler |
|
||||
| `telegram` | Upstream-тарбол не даёт своего package ID; desktop-id `org.telegram.desktop` сохранён; каталог и package ID переименованы с `telegram-desktop`. В отличие от `claude`/`claude-desktop`, `replaces` не включает старое имя (это разрешено только для `claude` в `validate_repo.py`) — у кого установлен `telegram-desktop`, нужно вручную `stplr install telegram` и `stplr remove telegram-desktop` |
|
||||
|
||||
## Локальные проверки
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# ClaudeAlt
|
||||
|
||||
Самостоятельная вторая установка Claude, не входящая в пакет
|
||||
`claude`:
|
||||
|
||||
```bash
|
||||
sudo stplr install nivora/claude-alt
|
||||
```
|
||||
|
||||
Использует собственные runtime, профиль и desktop-идентичность. Иконки Nivora
|
||||
переносятся без изменений. `claude` и `claude-alt` можно устанавливать,
|
||||
обновлять и удалять независимо друг от друга.
|
||||
@@ -1,20 +1,20 @@
|
||||
# Claude Desktop
|
||||
# Claude
|
||||
|
||||
Пакет `claude-desktop` переупаковывает DEB из APT-источника Anthropic и сохраняет upstream
|
||||
Пакет `claude` переупаковывает DEB из APT-источника Anthropic и сохраняет upstream
|
||||
desktop-id `com.anthropic.Claude`.
|
||||
|
||||
```bash
|
||||
sudo stplr install nivora/claude-desktop
|
||||
sudo stplr install nivora/claude
|
||||
```
|
||||
|
||||
## Два независимых приложения
|
||||
При установке новый пакет заменяет прежнее имя `nivora/claude-desktop`.
|
||||
Исполняемая команда `/usr/bin/claude-desktop` сохраняется, чтобы не
|
||||
конфликтовать с Claude Code CLI, использующим команду `claude`.
|
||||
|
||||
- `claude-desktop` запускает основное приложение Claude.
|
||||
- `claude-alt` и `claude-code-alt` запускают отдельное приложение ClaudeAlt.
|
||||
- `claude-desktop-account2` — дополнительное имя запуска ClaudeAlt.
|
||||
- Команда `claude` не создаётся, чтобы не конфликтовать с Claude Code CLI.
|
||||
## Два независимых пакета
|
||||
|
||||
ClaudeAlt имеет отдельные executable/resources tree, Electron `productName`, Wayland `app_id`,
|
||||
`claude-alt` устанавливается отдельной командой и имеет собственные
|
||||
executable/resources tree, Electron `productName`, Wayland `app_id`,
|
||||
X11 `WM_CLASS`, desktop-файл, Chromium-профиль, Cowork VM socket, оконную и
|
||||
tray-иконки. В системном лотке используется штатный глиф Claude: оранжевый у
|
||||
основного приложения и бирюзовый у ClaudeAlt. Большие app-иконки окон при этом
|
||||
@@ -0,0 +1,112 @@
|
||||
# Nivora CLI
|
||||
|
||||
Nivora CLI — компактная многоязычная оболочка для Stapler. Она упрощает
|
||||
установку, удаление, обновление и поиск пакетов, управление репозиториями и
|
||||
диагностику системы.
|
||||
|
||||
```bash
|
||||
sudo stplr install nivora/nivora-cli
|
||||
```
|
||||
|
||||
## Интерактивный режим
|
||||
|
||||
Команда `nv` без аргументов открывает компактное меню:
|
||||
|
||||
```text
|
||||
╭─ NIVORA ─────────────────────────────╮
|
||||
│ Простое управление пакетами Stapler │
|
||||
╰──────────────────────────────────────╯
|
||||
|
||||
Пакеты
|
||||
[i] Установить nvi
|
||||
[e] Удалить nve
|
||||
[u] Обновить nvu
|
||||
[s] Найти nvs
|
||||
[q] Информация nvqi
|
||||
[a] Все пакеты nvqa
|
||||
|
||||
Система
|
||||
[r] Обновить репозитории nvr
|
||||
[l] Репозитории nvrl
|
||||
[f] Исправить nvf
|
||||
[d] Диагностика nvd
|
||||
```
|
||||
|
||||
В конвейере или другом неинтерактивном окружении `nv` выводит обычную справку.
|
||||
|
||||
## Короткие команды
|
||||
|
||||
| Команда | Операция Stapler |
|
||||
|:--|:--|
|
||||
| `nvi package` | установить `nivora/package` |
|
||||
| `nve package` | удалить `nivora/package` |
|
||||
| `nvu` | обновить установленные пакеты |
|
||||
| `nvs query` | найти пакет |
|
||||
| `nvqi package` | показать информацию о пакете |
|
||||
| `nvqa` | показать каталог пакетов |
|
||||
| `nvr` | обновить индексы репозиториев |
|
||||
| `nvrl` | показать подключённые репозитории |
|
||||
| `nvf` | исправить состояние Stapler |
|
||||
| `nvd` | проверить окружение |
|
||||
| `nvc` | показать или изменить конфигурацию Stapler |
|
||||
|
||||
Основная команда принимает и полные названия операций:
|
||||
|
||||
```bash
|
||||
nv install codex
|
||||
nv search editor
|
||||
nv info codex
|
||||
nv repo list
|
||||
```
|
||||
|
||||
## Репозитории
|
||||
|
||||
Короткое имя автоматически получает префикс `nivora`:
|
||||
|
||||
```bash
|
||||
nvi codex # stplr install nivora/codex
|
||||
nvi other/package # stplr install other/package
|
||||
```
|
||||
|
||||
Репозиторий можно изменить или отключить:
|
||||
|
||||
```bash
|
||||
nvi --repo other package
|
||||
nvi --repo none package
|
||||
NIVORA_REPO=other nvi package
|
||||
```
|
||||
|
||||
Локальные пути и файлы пакетов никогда не получают префикс.
|
||||
|
||||
## Язык и оформление
|
||||
|
||||
Русский или английский язык выбирается по системной локали. Явное
|
||||
переопределение:
|
||||
|
||||
```bash
|
||||
nv --lang en help
|
||||
NIVORA_LANG=ru nvd
|
||||
```
|
||||
|
||||
Цветной вывод включается только для терминала. Его можно отключить стандартной
|
||||
переменной `NO_COLOR`, параметром `--no-color` или значением
|
||||
`NIVORA_COLOR=never`.
|
||||
|
||||
## Безопасность
|
||||
|
||||
Изменяющие систему операции запускаются через `sudo`. Другую команду повышения
|
||||
привилегий можно задать в `NIVORA_SUDO`. Аргументы передаются массивом без
|
||||
вычисления shell-строк. Параметр `--dry-run` показывает итоговую команду без её
|
||||
выполнения.
|
||||
|
||||
| Переменная | Назначение |
|
||||
|:--|:--|
|
||||
| `NIVORA_LANG` | язык интерфейса: `ru` или `en` |
|
||||
| `NIVORA_REPO` | репозиторий коротких имён |
|
||||
| `NIVORA_SUDO` | команда повышения привилегий |
|
||||
| `NIVORA_COLOR` | режим цвета; `never` отключает цвет |
|
||||
| `NIVORA_QUIET=1` | не печатать запускаемую команду |
|
||||
| `NO_COLOR` | стандартное отключение цвета |
|
||||
|
||||
Автодополнение для Bash, Fish или Zsh генерируется командой
|
||||
`nv completion <shell>`.
|
||||
@@ -1,43 +0,0 @@
|
||||
# Nivora Stapler Helper
|
||||
|
||||
`nivora-stplr` добавляет короткие команды для Stapler.
|
||||
|
||||
```bash
|
||||
sudo stplr install nivora/nivora-stplr
|
||||
```
|
||||
|
||||
## Команды
|
||||
|
||||
| Alias | Вызов Stapler |
|
||||
|:--|:--|
|
||||
| `sli` | `sudo stplr install` |
|
||||
| `slr` | `sudo stplr remove` |
|
||||
| `slu` | `sudo stplr up` |
|
||||
| `slf` | `sudo stplr fix` |
|
||||
| `slref` | `sudo stplr refresh` |
|
||||
| `sls` | `stplr search` |
|
||||
| `slii` | `stplr info` |
|
||||
| `sll` | `stplr list` |
|
||||
| `sl` | Диспетчер тех же команд |
|
||||
|
||||
Примеры:
|
||||
|
||||
```bash
|
||||
sli --repo nivora parsec
|
||||
slii nivora/codex
|
||||
slu --clean
|
||||
```
|
||||
|
||||
Короткое имя пакета не привязывается к Nivora по умолчанию. Префикс задаётся явно:
|
||||
|
||||
```bash
|
||||
export NIVORA_STPLR_REPO=nivora
|
||||
```
|
||||
|
||||
| Переменная | Назначение |
|
||||
|:--|:--|
|
||||
| `NIVORA_STPLR_REPO` | Префикс для коротких package names |
|
||||
| `NIVORA_STPLR_SUDO` | Команда повышения привилегий, по умолчанию `sudo` |
|
||||
| `NIVORA_STPLR_QUIET=1` | Не печатать команду перед запуском |
|
||||
|
||||
Helper не передаёт произвольные shell-строки через `sudo`.
|
||||
@@ -0,0 +1,33 @@
|
||||
Сведения о лицензии пакета max
|
||||
|
||||
Лицензия: Custom (проприетарная).
|
||||
Исходный продукт: https://max.ru/
|
||||
Официальный deb-репозиторий: https://download.max.ru/linux/deb/
|
||||
|
||||
Нюансы пакета:
|
||||
- Пакет перепаковывает официальный Linux deb-артефакт MAX Messenger Client
|
||||
из deb-репозитория max.ru; отдельного публичного репозитория исходников
|
||||
или GitHub-релиза у продукта нет.
|
||||
- Приложение собрано на Qt6 и распространяется полностью самодостаточным
|
||||
бандлом (собственные библиотеки Qt в `lib64/`).
|
||||
- Пакет запускает приложение только через Firejail-песочницу (профиль
|
||||
`/etc/firejail/max.profile`): домашний каталог пользователя виден
|
||||
приложению только через отдельные `~/.config/max`, `~/.cache/max`,
|
||||
`~/.local/share/max`; capabilities сброшены, seccomp включён,
|
||||
системная D-Bus недоступна. Отдельный процесс `crashpad_handler`
|
||||
(сбор и отправка крэш-дампов) заблокирован явным `blacklist`, чтобы
|
||||
ограничить исходящую телеметрию, не относящуюся к функциям обмена
|
||||
сообщениями.
|
||||
- Полная гарантия отсутствия любой сетевой телеметрии невозможна:
|
||||
трафик самого мессенджера к серверам max.ru неотличим от служебного
|
||||
на уровне песочницы. Firejail ограничивает доступ к системе и файлам,
|
||||
а не содержимое протокола приложения.
|
||||
- Для полноценной работы требуется учетная запись, привязанная к
|
||||
российскому номеру телефона.
|
||||
- Использование мессенджера, учетной записи и сетевых функций
|
||||
регулируется условиями MAX.
|
||||
- Пакет помечен как несвободный через `nonfree=1`.
|
||||
|
||||
Официальные условия:
|
||||
https://legal.max.ru/ps
|
||||
https://legal.max.ru/pp
|
||||
@@ -0,0 +1,105 @@
|
||||
name='max'
|
||||
version='26.24.0~75261'
|
||||
release=1
|
||||
summary='MAX messenger client, sandboxed with Firejail'
|
||||
summary_ru='Клиент мессенджера MAX в песочнице Firejail'
|
||||
group='Networking/Instant messaging'
|
||||
desc='MAX is the Russian state-affiliated instant messaging client. This package always launches it inside a Firejail sandbox that hides the rest of the home directory and blocks the standalone crash-report uploader, since the app has no independent security track record and no reason to see the whole system.'
|
||||
desc_ru='MAX — российский государственно-аффилированный клиент мгновенных сообщений. Пакет всегда запускает его в песочнице Firejail, которая скрывает остальной домашний каталог и блокирует отдельный процесс отправки крэш-дампов — у приложения нет независимой истории аудита безопасности и нет причин видеть всю систему.'
|
||||
homepage='https://max.ru/'
|
||||
maintainer='max.ru <https://max.ru/>'
|
||||
|
||||
architectures=('amd64')
|
||||
|
||||
license=('Custom')
|
||||
nonfree=1
|
||||
nonfree_msg='MAX является проприетарным приложением. Использование мессенджера, учетной записи и сетевых функций регулируется условиями MAX.'
|
||||
nonfree_url='https://legal.max.ru/ps'
|
||||
|
||||
provides=()
|
||||
replaces=('max')
|
||||
conflicts=()
|
||||
|
||||
auto_reqprov_method="dirty"
|
||||
auto_req=0
|
||||
auto_prov=0
|
||||
|
||||
deps=('firejail')
|
||||
deps_debian=('firejail' 'libxcb-xinerama0' 'libxcb-composite0' 'libxcb-ewmh2' 'libva-x11-2' 'libva-drm2' 'libvdpau1' 'libnotify4' 'libxcb-dri2-0' 'libopengl0' 'libxcb-cursor0' 'libxkbcommon-x11-0' 'libxcb-icccm4' 'libxcb-keysyms1' 'libxss1' 'libglib2.0-0' 'gsettings-desktop-schemas' 'ca-certificates')
|
||||
deps_ubuntu=("${deps_debian[@]}")
|
||||
deps_fedora=('firejail' 'libxcb' 'libva' 'libvdpau' 'libnotify' 'libglvnd-opengl' 'xcb-util-cursor' 'libxkbcommon-x11' 'xcb-util-wm' 'xcb-util-keysyms' 'libXScrnSaver' 'glib2' 'gsettings-desktop-schemas' 'ca-certificates')
|
||||
deps_arch=('firejail' 'libxcb' 'libva' 'libvdpau' 'libnotify' 'libglvnd' 'xcb-util-cursor' 'libxkbcommon-x11' 'xcb-util-wm' 'xcb-util-keysyms' 'libxss' 'glib2' 'gsettings-desktop-schemas' 'ca-certificates')
|
||||
deps_opensuse=('firejail' 'libxcb1' 'libva2' 'libvdpau1' 'libnotify4' 'libxcb-cursor0' 'libxkbcommon-x11-0' 'xcb-util-wm0' 'xcb-util-keysyms0' 'libXss1' 'libglib-2_0-0' 'gsettings-desktop-schemas' 'ca-certificates')
|
||||
deps_altlinux=('firejail' 'libxcb' 'libxcbutil-cursor' 'libxcbutil-icccm' 'libxcbutil-keysyms' 'libXScrnSaver' 'libva' 'libvdpau' 'libnotify' 'libOpenGL' 'libxkbcommon-x11' 'glib2' 'gsettings-desktop-schemas' 'ca-certificates')
|
||||
|
||||
opt_deps=()
|
||||
opt_deps_debian=('desktop-file-utils' 'hicolor-icon-theme' 'pipewire')
|
||||
opt_deps_ubuntu=("${opt_deps_debian[@]}")
|
||||
opt_deps_fedora=('desktop-file-utils' 'hicolor-icon-theme' 'pipewire')
|
||||
opt_deps_arch=('desktop-file-utils' 'hicolor-icon-theme' 'pipewire')
|
||||
opt_deps_opensuse=('desktop-file-utils' 'hicolor-icon-theme' 'pipewire')
|
||||
opt_deps_altlinux=('desktop-file-utils' 'icon-theme-hicolor' 'pipewire')
|
||||
|
||||
build_deps=('binutils')
|
||||
|
||||
sources=(
|
||||
"https://download.max.ru/linux/deb/pool/main/m/max/MAX-26.24.0.75261.deb?~archive=false&~name=max.deb"
|
||||
'local:///max.desktop'
|
||||
'local:///max.profile'
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:7151aa2559e5fe22dd4dd6cf037b5d5cd38d302f84e49d4c4be94e1c4fe1f7d5'
|
||||
'sha256:80ec5c0f4777ab00c433c25ffa70ef23d1752785e6584288d189518b8b43d613'
|
||||
'sha256:cf8c986f7f1a9841be33b43cfd8e34e6c75dac6ffea07aad07869177fc7768c7'
|
||||
'sha256:ddfcad273084c8b5690f6276fb29d8990ff4a7114db8a89b3f46255f8675e6b6'
|
||||
)
|
||||
|
||||
scripts=(
|
||||
['postinstall']='postinstall.sh'
|
||||
['postremove']='postremove.sh'
|
||||
)
|
||||
|
||||
package() {
|
||||
cd "${srcdir}"
|
||||
|
||||
mkdir -p "${srcdir}/extracted"
|
||||
ar x max.deb
|
||||
tar -xf data.tar.* -C "${srcdir}/extracted"
|
||||
|
||||
install -dm755 "${pkgdir}/usr/share"
|
||||
cp -a "${srcdir}/extracted/usr/share/max" "${pkgdir}/usr/share/max"
|
||||
install -Dm644 "${srcdir}/extracted/usr/share/pixmaps/max.png" \
|
||||
"${pkgdir}/usr/share/pixmaps/max.png"
|
||||
|
||||
for icon in "${srcdir}"/extracted/usr/share/icons/hicolor/*/apps/max.png; do
|
||||
size="$(basename "$(dirname "$(dirname "$icon")")")"
|
||||
install -Dm644 "$icon" \
|
||||
"${pkgdir}/usr/share/icons/hicolor/${size}/apps/max.png"
|
||||
done
|
||||
|
||||
install -Dm644 max.profile "${pkgdir}/etc/firejail/max.profile"
|
||||
|
||||
# The desktop file and every other launch path go through this wrapper —
|
||||
# MAX never runs unsandboxed regardless of how it's started.
|
||||
install -Dm755 /dev/stdin "${pkgdir}/usr/bin/max" <<'EOF'
|
||||
#!/bin/sh
|
||||
exec firejail --profile=max -- /usr/share/max/bin/max "$@"
|
||||
EOF
|
||||
|
||||
install -Dm644 max.desktop "${pkgdir}/usr/share/applications/max.desktop"
|
||||
|
||||
install-license "${srcdir}/LICENSE" "max/LICENSE.nivora"
|
||||
}
|
||||
|
||||
files() {
|
||||
files-find-binary
|
||||
files-find-desktop
|
||||
files-find-license
|
||||
files-find \
|
||||
"/etc/firejail/max.profile" \
|
||||
"/usr/share/max/**/*" \
|
||||
"/usr/share/pixmaps/max.png" \
|
||||
"/usr/share/icons/hicolor/*/apps/max.png"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Terminal=false
|
||||
Name=MAX
|
||||
Exec=/usr/bin/max %U
|
||||
Icon=max
|
||||
MimeType=x-scheme-handler/max;
|
||||
Comment=MAX Messenger Client Application
|
||||
Comment[ru]=Клиентское приложение мессенджера MAX
|
||||
StartupWMClass=max
|
||||
Categories=Chat;Network;InstantMessaging;Qt;
|
||||
Keywords=max;chat;im;messaging;messenger;sms;
|
||||
DBusActivatable=false
|
||||
SingleMainWindow=true
|
||||
X-GNOME-UsesNotifications=true
|
||||
X-GNOME-SingleWindow=true
|
||||
@@ -0,0 +1,53 @@
|
||||
# Firejail profile for MAX Messenger (Nivora package)
|
||||
# MAX is a proprietary Russian messenger; this profile keeps it away from
|
||||
# the rest of the user's files and system, and blocks its standalone
|
||||
# crash-report uploader.
|
||||
|
||||
include max.local
|
||||
include globals.local
|
||||
|
||||
noblacklist ${HOME}/.config/max
|
||||
noblacklist ${HOME}/.cache/max
|
||||
noblacklist ${HOME}/.local/share/max
|
||||
|
||||
include disable-common.inc
|
||||
include disable-devel.inc
|
||||
include disable-exec.inc
|
||||
include disable-interpreters.inc
|
||||
include disable-programs.inc
|
||||
include landlock-common.inc
|
||||
|
||||
mkdir ${HOME}/.config/max
|
||||
mkdir ${HOME}/.cache/max
|
||||
mkdir ${HOME}/.local/share/max
|
||||
whitelist ${HOME}/.config/max
|
||||
whitelist ${HOME}/.cache/max
|
||||
whitelist ${HOME}/.local/share/max
|
||||
include whitelist-common.inc
|
||||
include whitelist-run-common.inc
|
||||
include whitelist-usr-share-common.inc
|
||||
include whitelist-var-common.inc
|
||||
|
||||
caps.drop all
|
||||
netfilter
|
||||
nodvd
|
||||
nogroups
|
||||
nonewprivs
|
||||
noroot
|
||||
notv
|
||||
nou2f
|
||||
protocol unix,inet,inet6
|
||||
seccomp
|
||||
restrict-namespaces
|
||||
|
||||
disable-mnt
|
||||
private-dev
|
||||
private-tmp
|
||||
|
||||
# Chromium/Qt-style standalone crash uploader: no messaging function, only
|
||||
# phones home with crash dumps. Block it outright rather than trust a
|
||||
# network-level filter.
|
||||
blacklist /usr/share/max/bin/crashpad_handler
|
||||
blacklist /usr/share/max/bin/max-service/bin/crashpad_handler
|
||||
|
||||
dbus-system none
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
optional_refresh() {
|
||||
local label=$1
|
||||
shift
|
||||
if ! "$@"; then
|
||||
echo "Предупреждение: не удалось обновить ${label}." >&2
|
||||
fi
|
||||
}
|
||||
|
||||
if command -v update-desktop-database >/dev/null 2>&1; then
|
||||
optional_refresh "desktop-базу" update-desktop-database -q /usr/share/applications
|
||||
fi
|
||||
|
||||
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
|
||||
optional_refresh "кэш иконок" gtk-update-icon-cache -f -q /usr/share/icons/hicolor
|
||||
fi
|
||||
|
||||
if command -v kbuildsycoca6 >/dev/null 2>&1; then
|
||||
optional_refresh "кэш KDE" kbuildsycoca6 --noincremental
|
||||
elif command -v kbuildsycoca5 >/dev/null 2>&1; then
|
||||
optional_refresh "кэш KDE" kbuildsycoca5 --noincremental
|
||||
fi
|
||||
|
||||
if ! command -v firejail >/dev/null 2>&1; then
|
||||
echo "Предупреждение: firejail не найден в PATH — MAX запускается только через firejail, пакет firejail должен быть установлен." >&2
|
||||
fi
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
optional_refresh() {
|
||||
local label=$1
|
||||
shift
|
||||
if ! "$@"; then
|
||||
echo "Предупреждение: не удалось обновить ${label}." >&2
|
||||
fi
|
||||
}
|
||||
|
||||
if command -v update-desktop-database >/dev/null 2>&1; then
|
||||
optional_refresh "desktop-базу" update-desktop-database -q /usr/share/applications
|
||||
fi
|
||||
|
||||
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
|
||||
optional_refresh "кэш иконок" gtk-update-icon-cache -f -q /usr/share/icons/hicolor
|
||||
fi
|
||||
|
||||
if command -v kbuildsycoca6 >/dev/null 2>&1; then
|
||||
optional_refresh "кэш KDE" kbuildsycoca6 --noincremental
|
||||
elif command -v kbuildsycoca5 >/dev/null 2>&1; then
|
||||
optional_refresh "кэш KDE" kbuildsycoca5 --noincremental
|
||||
fi
|
||||
@@ -0,0 +1 @@
|
||||
include = "../stapler-repo.toml"
|
||||
@@ -1,5 +1,5 @@
|
||||
name='netbird'
|
||||
version=0.75.0
|
||||
version=0.76.0
|
||||
release=1
|
||||
summary='WireGuard-based mesh VPN client'
|
||||
summary_ru='Mesh VPN-клиент на базе WireGuard'
|
||||
@@ -48,7 +48,7 @@ sources_arm64=(
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:b65f65d7f32831639ebdd44c241e7a2310287723b64dbc03c93292853042ee6f'
|
||||
'sha256:0fdc5ee0336c71d58223c5ea92019b062d8bc2d5a73dbc4692c6d2313307a0f4'
|
||||
'sha256:71b133636e91eb67f221f64592f64fa04a3b2337f4d616be36492efae0cff643'
|
||||
'sha256:abd8064281462a4ce12c2fdf2e9436d9ae6932ff3b366668a175f2a556169012'
|
||||
'sha256:bb5c44ab330db0d63a82b582f2c508681a6922ea65f3bf2becaeed87693215b1'
|
||||
@@ -56,7 +56,7 @@ checksums=(
|
||||
)
|
||||
|
||||
checksums_arm64=(
|
||||
'sha256:9e57e854da0bbaf392cc6f99e37db75809e21c3effde0fca9f3bc9dc90245c02'
|
||||
'sha256:b8f0f8cb47df28f9ec0061c38eba5c96af43b25f49f4f28c544919f34f34cbe8'
|
||||
'sha256:71b133636e91eb67f221f64592f64fa04a3b2337f4d616be36492efae0cff643'
|
||||
'sha256:abd8064281462a4ce12c2fdf2e9436d9ae6932ff3b366668a175f2a556169012'
|
||||
'sha256:bb5c44ab330db0d63a82b582f2c508681a6922ea65f3bf2becaeed87693215b1'
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
package_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
repo_root="$(cd "${package_dir}/.." && pwd)"
|
||||
exec "${repo_root}/tools/package_updates.sh" check "$(basename "$package_dir")"
|
||||
@@ -0,0 +1,16 @@
|
||||
Сведения о лицензии пакета Nivora CLI
|
||||
|
||||
Лицензия: MIT.
|
||||
Исходный проект: https://github.com/Cheviiot/Nivora
|
||||
|
||||
Нюансы пакета:
|
||||
- Пакет устанавливает оболочку Stapler с командами `nv`, `nvi`, `nve`, `nvu`, `nvs`, `nvqi`, `nvqa`, `nvr`, `nvrl`, `nvf`, `nvd` и `nvc`.
|
||||
- Nivora CLI не заменяет Stapler: все операции выполняются через системную команду `stplr`.
|
||||
- Через команду повышения привилегий запускаются только `install`, `remove`, `up`, `fix` и `refresh`.
|
||||
- Команды чтения `search`, `info` и `list` выполняются без повышения привилегий.
|
||||
- Префикс репозитория задается через `--repo <name>` или `NIVORA_REPO`; по умолчанию используется репозиторий `nivora`.
|
||||
- Пути вида `repo/package` не изменяются.
|
||||
- Nivora CLI не исполняет произвольные shell-строки через `sudo`.
|
||||
|
||||
Полный официальный текст MIT:
|
||||
https://opensource.org/licenses/MIT
|
||||
@@ -0,0 +1,55 @@
|
||||
name='nivora-cli'
|
||||
version='1.0.0'
|
||||
release=1
|
||||
summary='Friendly multilingual command shell for Stapler'
|
||||
summary_ru='Удобная многоязычная оболочка для Stapler'
|
||||
desc='Nivora CLI is a compact bilingual command shell for everyday Stapler package management, repository administration, diagnostics, interactive navigation and shell completion.'
|
||||
desc_ru='Nivora CLI — компактная двуязычная оболочка для управления пакетами и репозиториями Stapler, диагностики, интерактивной навигации и автодополнения.'
|
||||
group='System/Configuration/Packaging'
|
||||
homepage='https://github.com/Cheviiot/Nivora'
|
||||
maintainer='Cheviiot <https://github.com/Cheviiot>'
|
||||
|
||||
architectures=('all')
|
||||
license=('MIT')
|
||||
|
||||
provides=()
|
||||
replaces=('nivora-cli')
|
||||
conflicts=()
|
||||
|
||||
auto_reqprov_method='dirty'
|
||||
auto_req=0
|
||||
auto_prov=0
|
||||
|
||||
deps=()
|
||||
deps_debian=('bash' 'sudo')
|
||||
deps_ubuntu=("${deps_debian[@]}")
|
||||
deps_fedora=('bash' 'sudo')
|
||||
deps_arch=('bash' 'sudo')
|
||||
deps_altlinux=('bash' 'sudo')
|
||||
deps_opensuse=('bash' 'sudo')
|
||||
|
||||
sources=(
|
||||
'local:///nivora'
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:438a5b3b73cd8f69108174b25e647b0f8013b3c16f4fcd5ca9e9769fd19f98b7'
|
||||
'sha256:16f1438f500706ac85b363c2549b392daef3a920b24139fca6b30f5648a7801a'
|
||||
)
|
||||
|
||||
package() {
|
||||
install -Dm755 "${srcdir}/nivora" "${pkgdir}/usr/bin/nv"
|
||||
|
||||
shortcut=''
|
||||
for shortcut in nvi nve nvu nvs nvqi nvqa nvr nvrl nvf nvd nvc; do
|
||||
ln -sfn nv "${pkgdir}/usr/bin/${shortcut}"
|
||||
done
|
||||
|
||||
install-license "${srcdir}/LICENSE" 'nivora-cli/LICENSE.nivora'
|
||||
}
|
||||
|
||||
files() {
|
||||
files-find-binary
|
||||
files-find-license
|
||||
}
|
||||
@@ -0,0 +1,546 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
readonly NIVORA_VERSION='1.0.0'
|
||||
readonly DEFAULT_REPOSITORY='nivora'
|
||||
|
||||
language="${NIVORA_LANG:-}"
|
||||
repository="${NIVORA_REPO:-${DEFAULT_REPOSITORY}}"
|
||||
dry_run=0
|
||||
color_mode="${NIVORA_COLOR:-auto}"
|
||||
|
||||
detect_language() {
|
||||
[[ -n "$language" ]] && return
|
||||
case "${LC_ALL:-${LC_MESSAGES:-${LANG:-en}}}" in
|
||||
ru* | RU*) language='ru' ;;
|
||||
*) language='en' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
message() {
|
||||
local key="$1"
|
||||
case "${language}:${key}" in
|
||||
ru:title) printf 'Простое управление пакетами Stapler' ;;
|
||||
ru:usage) printf 'Использование' ;;
|
||||
ru:packages) printf 'Пакеты' ;;
|
||||
ru:system) printf 'Система' ;;
|
||||
ru:install) printf 'Установить' ;;
|
||||
ru:remove) printf 'Удалить' ;;
|
||||
ru:upgrade) printf 'Обновить' ;;
|
||||
ru:search) printf 'Найти' ;;
|
||||
ru:info) printf 'Информация' ;;
|
||||
ru:all_packages) printf 'Все пакеты' ;;
|
||||
ru:refresh) printf 'Обновить репозитории' ;;
|
||||
ru:repositories) printf 'Репозитории' ;;
|
||||
ru:fix) printf 'Исправить' ;;
|
||||
ru:doctor) printf 'Диагностика' ;;
|
||||
ru:config) printf 'Конфигурация' ;;
|
||||
ru:help) printf 'Справка' ;;
|
||||
ru:exit) printf 'Выход' ;;
|
||||
ru:choose) printf 'Выберите действие' ;;
|
||||
ru:package_prompt) printf 'Имя пакета' ;;
|
||||
ru:query_prompt) printf 'Поисковый запрос' ;;
|
||||
ru:unknown_command) printf 'неизвестная команда' ;;
|
||||
ru:unknown_choice) printf 'нет такого пункта' ;;
|
||||
ru:missing_argument) printf 'необходим аргумент' ;;
|
||||
ru:invalid_language) printf 'поддерживаются языки ru и en' ;;
|
||||
ru:invalid_repository) printf 'некорректное имя репозитория' ;;
|
||||
ru:stapler_missing) printf 'команда stplr не найдена' ;;
|
||||
ru:privilege_missing) printf 'команда повышения привилегий не найдена' ;;
|
||||
ru:running) printf 'Выполняется' ;;
|
||||
ru:preview) printf 'Предпросмотр' ;;
|
||||
ru:diagnostics) printf 'Диагностика окружения' ;;
|
||||
ru:ready) printf 'Система готова к работе' ;;
|
||||
ru:problems) printf 'Обнаружены проблемы' ;;
|
||||
ru:available) printf 'доступен' ;;
|
||||
ru:missing) printf 'не найден' ;;
|
||||
ru:language) printf 'Язык' ;;
|
||||
ru:repository) printf 'Репозиторий' ;;
|
||||
ru:privileges) printf 'Привилегии' ;;
|
||||
ru:commands) printf 'Короткие команды' ;;
|
||||
ru:options) printf 'Параметры' ;;
|
||||
ru:examples) printf 'Примеры' ;;
|
||||
en:title) printf 'Simple Stapler package management' ;;
|
||||
en:usage) printf 'Usage' ;;
|
||||
en:packages) printf 'Packages' ;;
|
||||
en:system) printf 'System' ;;
|
||||
en:install) printf 'Install' ;;
|
||||
en:remove) printf 'Remove' ;;
|
||||
en:upgrade) printf 'Upgrade' ;;
|
||||
en:search) printf 'Search' ;;
|
||||
en:info) printf 'Information' ;;
|
||||
en:all_packages) printf 'All packages' ;;
|
||||
en:refresh) printf 'Refresh repositories' ;;
|
||||
en:repositories) printf 'Repositories' ;;
|
||||
en:fix) printf 'Repair' ;;
|
||||
en:doctor) printf 'Diagnostics' ;;
|
||||
en:config) printf 'Configuration' ;;
|
||||
en:help) printf 'Help' ;;
|
||||
en:exit) printf 'Exit' ;;
|
||||
en:choose) printf 'Choose an action' ;;
|
||||
en:package_prompt) printf 'Package name' ;;
|
||||
en:query_prompt) printf 'Search query' ;;
|
||||
en:unknown_command) printf 'unknown command' ;;
|
||||
en:unknown_choice) printf 'unknown choice' ;;
|
||||
en:missing_argument) printf 'an argument is required' ;;
|
||||
en:invalid_language) printf 'supported languages are ru and en' ;;
|
||||
en:invalid_repository) printf 'invalid repository name' ;;
|
||||
en:stapler_missing) printf 'stplr command was not found' ;;
|
||||
en:privilege_missing) printf 'privilege command was not found' ;;
|
||||
en:running) printf 'Running' ;;
|
||||
en:preview) printf 'Preview' ;;
|
||||
en:diagnostics) printf 'Environment diagnostics' ;;
|
||||
en:ready) printf 'The system is ready' ;;
|
||||
en:problems) printf 'Problems found' ;;
|
||||
en:available) printf 'available' ;;
|
||||
en:missing) printf 'missing' ;;
|
||||
en:language) printf 'Language' ;;
|
||||
en:repository) printf 'Repository' ;;
|
||||
en:privileges) printf 'Privileges' ;;
|
||||
en:commands) printf 'Short commands' ;;
|
||||
en:options) printf 'Options' ;;
|
||||
en:examples) printf 'Examples' ;;
|
||||
*) printf '%s' "$key" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
setup_style() {
|
||||
if [[ "$color_mode" == 'never' || -n "${NO_COLOR:-}" || ! -t 1 ]]; then
|
||||
bold=''; dim=''; cyan=''; blue=''; green=''; red=''; reset=''
|
||||
return
|
||||
fi
|
||||
bold=$'\033[1m'
|
||||
dim=$'\033[2m'
|
||||
cyan=$'\033[38;5;44m'
|
||||
blue=$'\033[38;5;75m'
|
||||
green=$'\033[38;5;78m'
|
||||
red=$'\033[38;5;203m'
|
||||
reset=$'\033[0m'
|
||||
}
|
||||
|
||||
fail() {
|
||||
printf '%s%sNivora:%s %s\n' "$bold" "$red" "$reset" "$*" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
validate_settings() {
|
||||
case "$language" in
|
||||
ru | en) ;;
|
||||
*)
|
||||
local invalid_language="$language"
|
||||
language='en'
|
||||
fail "$(message invalid_language): ${invalid_language}"
|
||||
;;
|
||||
esac
|
||||
if [[ "$repository" != 'none' &&
|
||||
! "$repository" =~ ^[[:alnum:]_.-]+$ ]]; then
|
||||
fail "$(message invalid_repository): ${repository}"
|
||||
fi
|
||||
}
|
||||
|
||||
parse_options() {
|
||||
arguments=()
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--lang)
|
||||
[[ "$#" -ge 2 ]] || fail "$(message missing_argument): --lang"
|
||||
language="$2"
|
||||
shift 2
|
||||
;;
|
||||
--lang=*)
|
||||
language="${1#--lang=}"
|
||||
shift
|
||||
;;
|
||||
--repo)
|
||||
[[ "$#" -ge 2 ]] || fail "$(message missing_argument): --repo"
|
||||
repository="$2"
|
||||
shift 2
|
||||
;;
|
||||
--repo=*)
|
||||
repository="${1#--repo=}"
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
dry_run=1
|
||||
shift
|
||||
;;
|
||||
--no-color)
|
||||
color_mode='never'
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
arguments+=("$@")
|
||||
break
|
||||
;;
|
||||
*)
|
||||
arguments+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
setup_style
|
||||
validate_settings
|
||||
}
|
||||
|
||||
print_header() {
|
||||
printf '%s%s╭─ NIVORA ─────────────────────────────╮%s\n' "$bold" "$cyan" "$reset"
|
||||
if [[ "$language" == 'ru' ]]; then
|
||||
printf '%s%s│%s Простое управление пакетами Stapler %s%s│%s\n' \
|
||||
"$cyan" "$bold" "$reset" "$bold" "$cyan" "$reset"
|
||||
else
|
||||
printf '%s%s│%s Simple Stapler package management %s%s│%s\n' \
|
||||
"$cyan" "$bold" "$reset" "$bold" "$cyan" "$reset"
|
||||
fi
|
||||
printf '%s%s╰──────────────────────────────────────╯%s\n' "$bold" "$cyan" "$reset"
|
||||
}
|
||||
|
||||
menu_row() {
|
||||
local key="$1"
|
||||
local label="$2"
|
||||
local shortcut="$3"
|
||||
local padding=$((23 - ${#label}))
|
||||
[[ "$padding" -lt 1 ]] && padding=1
|
||||
printf ' %s[%s]%s %s' "$cyan" "$key" "$reset" "$label"
|
||||
printf '%*s' "$padding" ''
|
||||
printf '%s%s%s\n' "$dim" "$shortcut" "$reset"
|
||||
}
|
||||
|
||||
interactive_menu() {
|
||||
if [[ ! -t 0 || ! -t 1 ]]; then
|
||||
show_help
|
||||
return
|
||||
fi
|
||||
|
||||
print_header
|
||||
printf '\n %s%s%s\n' "$bold" "$(message packages)" "$reset"
|
||||
menu_row i "$(message install)" nvi
|
||||
menu_row e "$(message remove)" nve
|
||||
menu_row u "$(message upgrade)" nvu
|
||||
menu_row s "$(message search)" nvs
|
||||
menu_row q "$(message info)" nvqi
|
||||
menu_row a "$(message all_packages)" nvqa
|
||||
printf '\n %s%s%s\n' "$bold" "$(message system)" "$reset"
|
||||
menu_row r "$(message refresh)" nvr
|
||||
menu_row l "$(message repositories)" nvrl
|
||||
menu_row f "$(message fix)" nvf
|
||||
menu_row d "$(message doctor)" nvd
|
||||
local help_label
|
||||
help_label="$(message help)"
|
||||
printf '\n %s[h]%s %s' "$cyan" "$reset" "$help_label"
|
||||
printf '%*s' "$((23 - ${#help_label}))" ''
|
||||
printf '%s[x]%s %s\n\n' "$cyan" "$reset" "$(message exit)"
|
||||
printf '%s › ' "$(message choose)"
|
||||
read -r choice
|
||||
case "$choice" in
|
||||
i) prompt_and_dispatch install package ;;
|
||||
e) prompt_and_dispatch remove package ;;
|
||||
u) dispatch upgrade ;;
|
||||
s) prompt_and_dispatch search query ;;
|
||||
q) prompt_and_dispatch info package ;;
|
||||
a) dispatch list ;;
|
||||
r) dispatch refresh ;;
|
||||
l) dispatch repo-list ;;
|
||||
f) dispatch fix ;;
|
||||
d) doctor ;;
|
||||
h) show_help ;;
|
||||
x | q!) return ;;
|
||||
*) fail "$(message unknown_choice): ${choice}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
prompt_and_dispatch() {
|
||||
local command_name="$1"
|
||||
local prompt_type="$2"
|
||||
local value
|
||||
if [[ "$prompt_type" == 'package' ]]; then
|
||||
printf '%s › ' "$(message package_prompt)"
|
||||
else
|
||||
printf '%s › ' "$(message query_prompt)"
|
||||
fi
|
||||
read -r value
|
||||
[[ -n "$value" ]] || fail "$(message missing_argument): ${command_name}"
|
||||
dispatch "$command_name" "$value"
|
||||
}
|
||||
|
||||
show_help() {
|
||||
print_header
|
||||
if [[ "$language" == 'ru' ]]; then
|
||||
cat <<EOF
|
||||
|
||||
${bold}$(message usage)${reset}
|
||||
nv интерактивное меню
|
||||
nv <команда> [аргументы] выполнить команду
|
||||
|
||||
${bold}$(message commands)${reset}
|
||||
${cyan}nvi${reset} <пакет...> установить ${cyan}nvr${reset} обновить репозитории
|
||||
${cyan}nve${reset} <пакет...> удалить ${cyan}nvrl${reset} показать репозитории
|
||||
${cyan}nvu${reset} обновить пакеты ${cyan}nvf${reset} исправить Stapler
|
||||
${cyan}nvs${reset} <запрос> найти ${cyan}nvd${reset} запустить диагностику
|
||||
${cyan}nvqi${reset} <пакет> информация ${cyan}nvc${reset} конфигурация Stapler
|
||||
${cyan}nvqa${reset} каталог пакетов
|
||||
|
||||
${bold}$(message options)${reset}
|
||||
--repo <имя|none> репозиторий коротких имён (по умолчанию: nivora)
|
||||
--lang <ru|en> язык интерфейса
|
||||
--dry-run показать команду без выполнения
|
||||
--no-color отключить цвета
|
||||
|
||||
${bold}$(message examples)${reset}
|
||||
nvi codex
|
||||
nvs editor
|
||||
nvqi codex
|
||||
nv --repo none install other/package
|
||||
EOF
|
||||
else
|
||||
cat <<EOF
|
||||
|
||||
${bold}$(message usage)${reset}
|
||||
nv interactive menu
|
||||
nv <command> [arguments] run a command
|
||||
|
||||
${bold}$(message commands)${reset}
|
||||
${cyan}nvi${reset} <package...> install ${cyan}nvr${reset} refresh repositories
|
||||
${cyan}nve${reset} <package...> remove ${cyan}nvrl${reset} list repositories
|
||||
${cyan}nvu${reset} upgrade packages ${cyan}nvf${reset} repair Stapler
|
||||
${cyan}nvs${reset} <query> search ${cyan}nvd${reset} run diagnostics
|
||||
${cyan}nvqi${reset} <package> information ${cyan}nvc${reset} configure Stapler
|
||||
${cyan}nvqa${reset} package catalog
|
||||
|
||||
${bold}$(message options)${reset}
|
||||
--repo <name|none> repository for short names (default: nivora)
|
||||
--lang <ru|en> interface language
|
||||
--dry-run print the command without running it
|
||||
--no-color disable colors
|
||||
|
||||
${bold}$(message examples)${reset}
|
||||
nvi codex
|
||||
nvs editor
|
||||
nvqi codex
|
||||
nv --repo none install other/package
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
need_stapler() {
|
||||
command -v stplr >/dev/null 2>&1 || fail "$(message stapler_missing)"
|
||||
}
|
||||
|
||||
privilege_command() {
|
||||
[[ "$EUID" -eq 0 ]] && return
|
||||
local command_name="${NIVORA_SUDO:-sudo}"
|
||||
command -v "$command_name" >/dev/null 2>&1 ||
|
||||
fail "$(message privilege_missing): ${command_name}"
|
||||
printf '%s\n' "$command_name"
|
||||
}
|
||||
|
||||
is_package_name() {
|
||||
local value="$1"
|
||||
[[ -n "$value" &&
|
||||
"$value" != -* &&
|
||||
"$value" != */* &&
|
||||
"$value" != ./* &&
|
||||
"$value" != ../* &&
|
||||
"$value" != /* &&
|
||||
"$value" != *.rpm &&
|
||||
"$value" != *.deb &&
|
||||
"$value" != *.pkg.tar.* ]]
|
||||
}
|
||||
|
||||
normalize_packages() {
|
||||
local argument
|
||||
for argument in "$@"; do
|
||||
if [[ "$repository" != 'none' ]] && is_package_name "$argument"; then
|
||||
printf '%s/%s\n' "$repository" "$argument"
|
||||
else
|
||||
printf '%s\n' "$argument"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
print_command() {
|
||||
local label
|
||||
if [[ "$dry_run" -eq 1 ]]; then
|
||||
label="$(message preview)"
|
||||
else
|
||||
label="$(message running)"
|
||||
fi
|
||||
printf '%s%s%s%s %s›%s' "$bold" "$blue" "$label" "$reset" "$cyan" "$reset" >&2
|
||||
printf ' %q' "$@" >&2
|
||||
printf '\n' >&2
|
||||
}
|
||||
|
||||
run_stapler() {
|
||||
local access="$1"
|
||||
shift
|
||||
need_stapler
|
||||
|
||||
local -a command=()
|
||||
local privilege
|
||||
if [[ "$access" == 'privileged' ]]; then
|
||||
privilege="$(privilege_command)"
|
||||
[[ -n "$privilege" ]] && command+=("$privilege")
|
||||
fi
|
||||
command+=(stplr "$@")
|
||||
|
||||
[[ "${NIVORA_QUIET:-0}" == '1' ]] || print_command "${command[@]}"
|
||||
[[ "$dry_run" -eq 1 ]] && return
|
||||
exec "${command[@]}"
|
||||
}
|
||||
|
||||
require_arguments() {
|
||||
local command_name="$1"
|
||||
local count="$2"
|
||||
[[ "$count" -gt 0 ]] || fail "$(message missing_argument): ${command_name}"
|
||||
}
|
||||
|
||||
doctor() {
|
||||
local failures=0
|
||||
local privilege="${NIVORA_SUDO:-sudo}"
|
||||
printf '%s%s%s\n\n' "$bold" "$(message diagnostics)" "$reset"
|
||||
|
||||
if command -v stplr >/dev/null 2>&1; then
|
||||
printf ' %s●%s %-14s %s\n' "$green" "$reset" 'Stapler' "$(message available)"
|
||||
else
|
||||
printf ' %s●%s %-14s %s\n' "$red" "$reset" 'Stapler' "$(message missing)"
|
||||
failures=1
|
||||
fi
|
||||
|
||||
if [[ "$EUID" -eq 0 ]] || command -v "$privilege" >/dev/null 2>&1; then
|
||||
printf ' %s●%s %-14s %s\n' \
|
||||
"$green" "$reset" "$(message privileges)" \
|
||||
"$([[ "$EUID" -eq 0 ]] && printf 'root' || printf '%s' "$privilege")"
|
||||
else
|
||||
printf ' %s●%s %-14s %s\n' \
|
||||
"$red" "$reset" "$(message privileges)" "$(message missing)"
|
||||
failures=1
|
||||
fi
|
||||
|
||||
printf ' %s●%s %-14s %s\n' "$green" "$reset" "$(message language)" "$language"
|
||||
printf ' %s●%s %-14s %s\n\n' \
|
||||
"$green" "$reset" "$(message repository)" "$repository"
|
||||
|
||||
if [[ "$failures" -eq 0 ]]; then
|
||||
printf '%s✓ %s%s\n' "$green" "$(message ready)" "$reset"
|
||||
else
|
||||
printf '%s✗ %s%s\n' "$red" "$(message problems)" "$reset"
|
||||
fi
|
||||
return "$failures"
|
||||
}
|
||||
|
||||
completion() {
|
||||
local shell="${1:-}"
|
||||
case "$shell" in
|
||||
bash)
|
||||
cat <<'EOF'
|
||||
_nivora() {
|
||||
local commands='install remove upgrade search info list refresh repo-list fix doctor config completion version help'
|
||||
if (( COMP_CWORD == 1 )); then
|
||||
COMPREPLY=($(compgen -W "$commands" -- "${COMP_WORDS[COMP_CWORD]}"))
|
||||
fi
|
||||
}
|
||||
complete -F _nivora nv
|
||||
EOF
|
||||
;;
|
||||
fish)
|
||||
cat <<'EOF'
|
||||
complete -c nv -f -n '__fish_use_subcommand' -a 'install remove upgrade search info list refresh repo-list fix doctor config completion version help'
|
||||
EOF
|
||||
;;
|
||||
zsh)
|
||||
cat <<'EOF'
|
||||
#compdef nv
|
||||
_arguments '1:command:(install remove upgrade search info list refresh repo-list fix doctor config completion version help)' '*::argument:->arguments'
|
||||
EOF
|
||||
;;
|
||||
*) fail "$(message missing_argument): completion <bash|fish|zsh>" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
dispatch() {
|
||||
local command_name="${1:-help}"
|
||||
[[ "$#" -gt 0 ]] && shift
|
||||
|
||||
case "$command_name" in
|
||||
install | i)
|
||||
require_arguments "$command_name" "$#"
|
||||
local -a packages=()
|
||||
mapfile -t packages < <(normalize_packages "$@")
|
||||
run_stapler privileged install "${packages[@]}"
|
||||
;;
|
||||
remove | erase | e)
|
||||
require_arguments "$command_name" "$#"
|
||||
local -a packages=()
|
||||
mapfile -t packages < <(normalize_packages "$@")
|
||||
run_stapler privileged remove "${packages[@]}"
|
||||
;;
|
||||
upgrade | update | u) run_stapler privileged up "$@" ;;
|
||||
search | s)
|
||||
require_arguments "$command_name" "$#"
|
||||
run_stapler user search "$@"
|
||||
;;
|
||||
info | query-info | qi)
|
||||
require_arguments "$command_name" "$#"
|
||||
local -a packages=()
|
||||
mapfile -t packages < <(normalize_packages "$@")
|
||||
run_stapler user info "${packages[@]}"
|
||||
;;
|
||||
list | packages | query-all | qa) run_stapler user list "$@" ;;
|
||||
refresh | r) run_stapler privileged refresh "$@" ;;
|
||||
repo-list | rl) run_stapler user repo list "$@" ;;
|
||||
repo)
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
run_stapler user repo list
|
||||
elif [[ "${1:-}" == 'list' || "${1:-}" == 'ls' ]]; then
|
||||
run_stapler user repo "$@"
|
||||
else
|
||||
run_stapler privileged repo "$@"
|
||||
fi
|
||||
;;
|
||||
fix | f) run_stapler privileged fix "$@" ;;
|
||||
doctor | d) doctor ;;
|
||||
config | c)
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
run_stapler user config show
|
||||
else
|
||||
run_stapler user config "$@"
|
||||
fi
|
||||
;;
|
||||
completion) completion "$@" ;;
|
||||
support) run_stapler user support "$@" ;;
|
||||
version | v | --version)
|
||||
printf 'Nivora CLI %s\n' "$NIVORA_VERSION"
|
||||
command -v stplr >/dev/null 2>&1 && stplr version
|
||||
;;
|
||||
help | h | -h | --help) show_help ;;
|
||||
*) fail "$(message unknown_command): ${command_name}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
main() {
|
||||
detect_language
|
||||
setup_style
|
||||
parse_options "$@"
|
||||
set -- "${arguments[@]}"
|
||||
|
||||
case "$(basename "$0")" in
|
||||
nv)
|
||||
if [[ "$#" -eq 0 ]]; then interactive_menu; else dispatch "$@"; fi
|
||||
;;
|
||||
nvi) dispatch install "$@" ;;
|
||||
nve) dispatch remove "$@" ;;
|
||||
nvu) dispatch upgrade "$@" ;;
|
||||
nvs) dispatch search "$@" ;;
|
||||
nvqi) dispatch info "$@" ;;
|
||||
nvqa) dispatch list "$@" ;;
|
||||
nvr) dispatch refresh "$@" ;;
|
||||
nvrl) dispatch repo-list "$@" ;;
|
||||
nvf) dispatch fix "$@" ;;
|
||||
nvd) doctor ;;
|
||||
nvc) dispatch config "$@" ;;
|
||||
nivora) dispatch "$@" ;;
|
||||
*) fail "$(message unknown_command): $(basename "$0")" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1 @@
|
||||
include = "../stapler-repo.toml"
|
||||
@@ -1,16 +0,0 @@
|
||||
Сведения о лицензии пакета Nivora Stapler Helper
|
||||
|
||||
Лицензия: MIT.
|
||||
Исходный проект: https://github.com/Cheviiot/Nivora
|
||||
|
||||
Нюансы пакета:
|
||||
- Пакет устанавливает CLI-helper для Stapler с командами `sl`, `sli`, `slr`, `slu`, `slf`, `slref`, `sls`, `slii` и `sll`.
|
||||
- Helper не заменяет Stapler: все операции выполняются через системную команду `stplr`.
|
||||
- Через команду повышения привилегий запускаются только `install`, `remove`, `up`, `fix` и `refresh`.
|
||||
- Команды чтения `search`, `info` и `list` выполняются без повышения привилегий.
|
||||
- Префикс репозитория задается через `--repo <name>` или `NIVORA_STPLR_REPO`; по умолчанию короткие имена не привязаны к одному репозиторию.
|
||||
- Пути вида `repo/package` не изменяются.
|
||||
- Helper не исполняет произвольные shell-строки через `sudo`.
|
||||
|
||||
Полный официальный текст MIT:
|
||||
https://opensource.org/licenses/MIT
|
||||
@@ -1,55 +0,0 @@
|
||||
name='nivora-stplr'
|
||||
version='0.3.0'
|
||||
release=1
|
||||
summary='Short command helper for Stapler'
|
||||
summary_ru='Короткие команды для Stapler'
|
||||
desc='Nivora Stapler Helper provides short commands for common Stapler operations across configured repositories and elevates only operations that modify packages or caches.'
|
||||
desc_ru='Nivora Stapler Helper добавляет короткие команды для типовых операций Stapler и повышает привилегии только для изменения пакетов и кэша.'
|
||||
group='System/Configuration/Packaging'
|
||||
homepage='https://github.com/Cheviiot/Nivora'
|
||||
maintainer='Cheviiot <https://github.com/Cheviiot>'
|
||||
|
||||
architectures=('all')
|
||||
license=('MIT')
|
||||
|
||||
provides=()
|
||||
replaces=('nivora-stplr')
|
||||
conflicts=()
|
||||
|
||||
auto_reqprov_method='dirty'
|
||||
auto_req=0
|
||||
auto_prov=0
|
||||
|
||||
deps=()
|
||||
deps_debian=('bash' 'sudo')
|
||||
deps_ubuntu=("${deps_debian[@]}")
|
||||
deps_fedora=('bash' 'sudo')
|
||||
deps_arch=('bash' 'sudo')
|
||||
deps_altlinux=('bash' 'sudo')
|
||||
deps_opensuse=('bash' 'sudo')
|
||||
|
||||
sources=(
|
||||
'local:///nivora-stplr'
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:7b0c2a69aed30bc39ac5546aabd0cb82d45b857a52408b4326ad1fd667684ecb'
|
||||
'sha256:c5674e6873211a8ea0f08ee3a950f809c9145c60750746dafff9aee7e1c21cf1'
|
||||
)
|
||||
|
||||
package() {
|
||||
install -Dm755 "${srcdir}/nivora-stplr" "${pkgdir}/usr/bin/sl"
|
||||
|
||||
shortcut=''
|
||||
for shortcut in sli slr slu slf slref sls slii sll; do
|
||||
ln -sfn sl "${pkgdir}/usr/bin/${shortcut}"
|
||||
done
|
||||
|
||||
install-license "${srcdir}/LICENSE" 'nivora-stplr/LICENSE.nivora'
|
||||
}
|
||||
|
||||
files() {
|
||||
files-find-binary
|
||||
files-find-license
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_prefix="${NIVORA_STPLR_REPO:-}"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Nivora Stapler Helper
|
||||
|
||||
Usage:
|
||||
sl <command> [args...]
|
||||
sli <package> [stplr args...] sudo stplr install <package>
|
||||
slr <package> [stplr args...] sudo stplr remove <package>
|
||||
slu [stplr args...] sudo stplr up
|
||||
slf [stplr args...] sudo stplr fix
|
||||
slref [stplr args...] sudo stplr refresh
|
||||
sls <query> [stplr args...] stplr search <query>
|
||||
slii <package> [stplr args...] stplr info <package>
|
||||
sll [stplr args...] stplr list
|
||||
|
||||
Commands:
|
||||
install, in, i install package with sudo
|
||||
remove, rm, r remove package with sudo
|
||||
up, upgrade, u upgrade installed packages with sudo
|
||||
fix, f run stplr fix with sudo
|
||||
refresh, ref refresh repositories with sudo
|
||||
search, s search packages
|
||||
info, show show package info
|
||||
list, ls list repository packages
|
||||
help show this help
|
||||
|
||||
Options:
|
||||
--repo <name> prefix short package names with repository, e.g. sli --repo nivora parsec
|
||||
|
||||
Environment:
|
||||
NIVORA_STPLR_REPO optional repository prefix for short names, default: disabled
|
||||
NIVORA_STPLR_SUDO privilege command, default: sudo
|
||||
NIVORA_STPLR_QUIET=1 do not print command before execution
|
||||
EOF
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "nivora-stplr: $*" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
need_stplr() {
|
||||
command -v stplr >/dev/null 2>&1 || die "команда stplr не найдена"
|
||||
}
|
||||
|
||||
sudo_cmd() {
|
||||
if [[ "${EUID}" -eq 0 ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local command_name="${NIVORA_STPLR_SUDO:-sudo}"
|
||||
command -v "${command_name}" >/dev/null 2>&1 || die "команда ${command_name} не найдена"
|
||||
printf '%s\n' "${command_name}"
|
||||
}
|
||||
|
||||
is_package_token() {
|
||||
local value="$1"
|
||||
|
||||
[[ -n "${value}" ]] || return 1
|
||||
[[ "${value}" == -* ]] && return 1
|
||||
[[ "${value}" == */* ]] && return 1
|
||||
[[ "${value}" == ./* || "${value}" == ../* || "${value}" == /* ]] && return 1
|
||||
[[ "${value}" == *.rpm || "${value}" == *.deb || "${value}" == *.pkg.tar.* ]] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
normalize_package() {
|
||||
local value="$1"
|
||||
|
||||
if [[ -n "${repo_prefix}" ]] && is_package_token "${value}"; then
|
||||
printf '%s/%s\n' "${repo_prefix}" "${value}"
|
||||
else
|
||||
printf '%s\n' "${value}"
|
||||
fi
|
||||
}
|
||||
|
||||
normalize_package_args() {
|
||||
local arg
|
||||
|
||||
for arg in "$@"; do
|
||||
normalize_package "${arg}"
|
||||
done
|
||||
}
|
||||
|
||||
extract_repo_option() {
|
||||
local -n output_ref="$1"
|
||||
shift
|
||||
|
||||
output_ref=()
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--repo)
|
||||
[[ "$#" -ge 2 ]] || die "для --repo нужно имя репозитория"
|
||||
repo_prefix="$2"
|
||||
shift 2
|
||||
;;
|
||||
--repo=*)
|
||||
repo_prefix="${1#--repo=}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
output_ref+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
print_and_exec() {
|
||||
local -a command=("$@")
|
||||
|
||||
if [[ "${NIVORA_STPLR_QUIET:-0}" != "1" ]]; then
|
||||
printf '=>'
|
||||
printf ' %q' "${command[@]}"
|
||||
printf '\n'
|
||||
fi
|
||||
|
||||
exec "${command[@]}"
|
||||
}
|
||||
|
||||
run_stplr() {
|
||||
local mode="$1"
|
||||
shift
|
||||
|
||||
need_stplr
|
||||
|
||||
local -a command=()
|
||||
if [[ "${mode}" == "sudo" ]]; then
|
||||
local privilege
|
||||
privilege="$(sudo_cmd)"
|
||||
if [[ -n "${privilege}" ]]; then
|
||||
command+=("${privilege}")
|
||||
fi
|
||||
fi
|
||||
|
||||
command+=(stplr "$@")
|
||||
print_and_exec "${command[@]}"
|
||||
}
|
||||
|
||||
require_args() {
|
||||
local command_name="$1"
|
||||
local count="$2"
|
||||
|
||||
if [[ "${count}" -eq 0 ]]; then
|
||||
die "для команды ${command_name} нужен аргумент"
|
||||
fi
|
||||
}
|
||||
|
||||
dispatch() {
|
||||
local command_name="$1"
|
||||
shift
|
||||
|
||||
case "${command_name}" in
|
||||
install | in | i)
|
||||
require_args "${command_name}" "$#"
|
||||
local -a args=()
|
||||
extract_repo_option args "$@"
|
||||
require_args "${command_name}" "${#args[@]}"
|
||||
mapfile -t normalized < <(normalize_package_args "${args[@]}")
|
||||
run_stplr sudo install "${normalized[@]}"
|
||||
;;
|
||||
remove | rm | r | erase | delete | del)
|
||||
require_args "${command_name}" "$#"
|
||||
local -a args=()
|
||||
extract_repo_option args "$@"
|
||||
require_args "${command_name}" "${#args[@]}"
|
||||
mapfile -t normalized < <(normalize_package_args "${args[@]}")
|
||||
run_stplr sudo remove "${normalized[@]}"
|
||||
;;
|
||||
up | upgrade | u)
|
||||
run_stplr sudo up "$@"
|
||||
;;
|
||||
fix | f)
|
||||
run_stplr sudo fix "$@"
|
||||
;;
|
||||
refresh | ref)
|
||||
run_stplr sudo refresh "$@"
|
||||
;;
|
||||
search | s)
|
||||
require_args "${command_name}" "$#"
|
||||
run_stplr user search "$@"
|
||||
;;
|
||||
info | show)
|
||||
require_args "${command_name}" "$#"
|
||||
local -a args=()
|
||||
extract_repo_option args "$@"
|
||||
require_args "${command_name}" "${#args[@]}"
|
||||
mapfile -t normalized < <(normalize_package_args "${args[@]}")
|
||||
run_stplr user info "${normalized[@]}"
|
||||
;;
|
||||
list | ls | l)
|
||||
run_stplr user list "$@"
|
||||
;;
|
||||
version | support)
|
||||
run_stplr user "${command_name}" "$@"
|
||||
;;
|
||||
help | -h | --help | "")
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
die "неизвестная команда: ${command_name}. Запустите: sl help"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main() {
|
||||
local invoked
|
||||
invoked="$(basename "$0")"
|
||||
|
||||
case "${invoked}" in
|
||||
sli) dispatch install "$@" ;;
|
||||
slr) dispatch remove "$@" ;;
|
||||
slu) dispatch up "$@" ;;
|
||||
slf) dispatch fix "$@" ;;
|
||||
slref) dispatch refresh "$@" ;;
|
||||
sls) dispatch search "$@" ;;
|
||||
slii) dispatch info "$@" ;;
|
||||
sll) dispatch list "$@" ;;
|
||||
sl)
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
usage
|
||||
return 0
|
||||
fi
|
||||
local command_name="$1"
|
||||
shift
|
||||
dispatch "${command_name}" "$@"
|
||||
;;
|
||||
*)
|
||||
die "неизвестное имя запуска: ${invoked}"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -1,5 +1,5 @@
|
||||
name='opencode'
|
||||
version=1.18.4
|
||||
version=1.18.10
|
||||
release=1
|
||||
summary='Open source AI coding agent desktop app'
|
||||
summary_ru='Десктопное приложение AI-агента OpenCode'
|
||||
@@ -50,12 +50,12 @@ sources_arm64=(
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:a67bc47a98ded10275e7a8f32fa3e16480b55996cd52232da91450432b4d6599'
|
||||
'sha256:ebc1f7650eb132ee8cb3cfc29bd2ae4d64d9d69ec85b799201602417c31e3f00'
|
||||
'sha256:5c888de95824a9a5752d1ee3de95e80200eb057eec4078df892a95ac34333888'
|
||||
)
|
||||
|
||||
checksums_arm64=(
|
||||
'sha256:09bd2be9951ba5a7a333db818de49524edc6c98fedcca20d13a4a0f1c6c5b9e1'
|
||||
'sha256:d7ee7a8c28989c858e2beffcf32cedc12610500fbfb72aa419436e1682475ce1'
|
||||
'sha256:5c888de95824a9a5752d1ee3de95e80200eb057eec4078df892a95ac34333888'
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name='tailscale'
|
||||
version='1.98.9'
|
||||
release=3
|
||||
version=1.98.10
|
||||
release=1
|
||||
summary='Mesh VPN built on WireGuard'
|
||||
summary_ru='Mesh VPN на базе WireGuard'
|
||||
group='Networking/Other'
|
||||
@@ -44,15 +44,15 @@ sources_arm64=(
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'11be30ad301d48f84ff52fec34f8a2f78eb3e3dee1be4e9624d19fccc8df5540'
|
||||
'fc0e166481e2f97c21dca773ad4bfe673842268935ce1628c14b96af98e70555'
|
||||
'3c7a7d6d7f09890d5e682901acaeb12bda9542fc6450a709c9dc296a91e726a5'
|
||||
'sha256:52490ce0832b245857e2afef7426d6ae5a4b49fb391412833cc95729bd23f7de'
|
||||
'sha256:fc0e166481e2f97c21dca773ad4bfe673842268935ce1628c14b96af98e70555'
|
||||
'sha256:3c7a7d6d7f09890d5e682901acaeb12bda9542fc6450a709c9dc296a91e726a5'
|
||||
)
|
||||
|
||||
checksums_arm64=(
|
||||
'fa554ee808d7d07ee8e3ebbc0215ea087157e2a0abbf408e6e18ea7532554db6'
|
||||
'fc0e166481e2f97c21dca773ad4bfe673842268935ce1628c14b96af98e70555'
|
||||
'3c7a7d6d7f09890d5e682901acaeb12bda9542fc6450a709c9dc296a91e726a5'
|
||||
'sha256:d74a84e07cb1948d9f09a23ae161417c6127e562949773705c95d0762be2809d'
|
||||
'sha256:fc0e166481e2f97c21dca773ad4bfe673842268935ce1628c14b96af98e70555'
|
||||
'sha256:3c7a7d6d7f09890d5e682901acaeb12bda9542fc6450a709c9dc296a91e726a5'
|
||||
)
|
||||
|
||||
scripts=(
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
package_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
repo_root="$(cd "${package_dir}/.." && pwd)"
|
||||
exec "${repo_root}/tools/package_updates.sh" check "$(basename "$package_dir")"
|
||||
@@ -0,0 +1,24 @@
|
||||
Сведения о лицензии пакета Telegram Desktop
|
||||
|
||||
Лицензия: GPL-3.0-only (с отдельным разрешением на линковку с OpenSSL).
|
||||
Исходный проект: https://github.com/telegramdesktop/tdesktop
|
||||
Официальный сайт: https://desktop.telegram.org/
|
||||
Условия использования сервиса: https://telegram.org/tos
|
||||
|
||||
Нюансы пакета:
|
||||
- Пакет перепаковывает официальный статически собранный Linux-архив
|
||||
Telegram Desktop (`tsetup.<version>.tar.xz`), публикуемый Telegram напрямую
|
||||
и через официальные релизы `telegramdesktop/tdesktop` на GitHub.
|
||||
- Собственный код Telegram Desktop распространяется на условиях GNU GPL
|
||||
версии 3 с отдельным разрешением на линковку с OpenSSL; часть bundled-
|
||||
зависимостей (Qt, ffmpeg и другие) распространяется на собственных
|
||||
условиях соответствующих проектов.
|
||||
- Учетные записи, серверы, боты, Premium-подписка и прочие сетевые функции
|
||||
Telegram в пакет не входят и регулируются условиями Telegram.
|
||||
- Локальные данные, кэш и сессии создаются приложением в домашнем каталоге
|
||||
пользователя после запуска и не поставляются внутри пакета.
|
||||
- Пакет добавляет команду `telegram-desktop` и использует официальные
|
||||
desktop-id `org.telegram.desktop`.
|
||||
|
||||
Полный официальный текст GPL-3.0:
|
||||
https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
@@ -0,0 +1,101 @@
|
||||
name='telegram'
|
||||
version=7.0.6
|
||||
release=1
|
||||
summary='Official Telegram messaging client'
|
||||
summary_ru='Официальный клиент мессенджера Telegram'
|
||||
group='Networking/Instant messaging'
|
||||
desc='Telegram Desktop is the official Telegram messaging client with cloud-synced chats, voice and video calls, and no limits on file size or media history.'
|
||||
desc_ru='Telegram Desktop — официальный клиент мессенджера Telegram с облачной синхронизацией чатов, голосовыми и видеозвонками и без ограничений на размер файлов и историю медиа.'
|
||||
homepage='https://desktop.telegram.org/'
|
||||
maintainer='Telegram Messenger LLP <https://github.com/telegramdesktop/tdesktop>'
|
||||
|
||||
architectures=('amd64')
|
||||
|
||||
license=('GPL-3.0-only')
|
||||
|
||||
provides=()
|
||||
replaces=('telegram')
|
||||
conflicts=()
|
||||
|
||||
auto_reqprov_method="dirty"
|
||||
auto_req=0
|
||||
auto_prov=0
|
||||
|
||||
deps=()
|
||||
deps_debian=('libc6' 'libglib2.0-0t64 | libglib2.0-0' 'libfontconfig1' 'libfreetype6' 'libharfbuzz0b' 'libpng16-16' 'libpcre2-8-0' 'libbrotli1' 'libbz2-1.0' 'libblkid1' 'libmount1' 'libselinux1' 'libffi8' 'libexpat1' 'libgraphite2-3' 'zlib1g' 'libx11-6' 'hicolor-icon-theme')
|
||||
deps_ubuntu=("${deps_debian[@]}")
|
||||
deps_fedora=('glibc' 'glib2' 'fontconfig' 'freetype' 'harfbuzz' 'libpng' 'pcre2' 'brotli' 'bzip2-libs' 'libblkid' 'libmount' 'libselinux' 'libffi' 'expat' 'graphite2' 'zlib' 'libX11' 'hicolor-icon-theme')
|
||||
deps_arch=('glibc' 'glib2' 'fontconfig' 'freetype2' 'harfbuzz' 'libpng' 'pcre2' 'brotli' 'bzip2' 'util-linux-libs' 'libselinux' 'libffi' 'expat' 'graphite' 'zlib' 'libx11' 'hicolor-icon-theme')
|
||||
deps_opensuse=('glibc' 'libglib-2_0-0' 'libfontconfig1' 'libfreetype6' 'libharfbuzz0' 'libpng16-16' 'libpcre2-8-0' 'libbrotli1' 'libbz2-1' 'libblkid1' 'libmount1' 'libselinux1' 'libffi8' 'libexpat1' 'libgraphite2-3' 'libz1' 'libX11-6' 'hicolor-icon-theme')
|
||||
deps_altlinux=('glibc' 'glib2' 'libfontconfig1' 'libfreetype' 'libharfbuzz' 'libpng16' 'libpcre2' 'libbrotlicommon' 'libbrotlidec' 'bzlib' 'libblkid' 'libmount' 'libselinux' 'libffi8' 'libexpat' 'libgraphite2' 'zlib' 'libX11' 'icon-theme-hicolor')
|
||||
|
||||
opt_deps=()
|
||||
opt_deps_debian=('xdg-utils' 'libayatana-appindicator3-1 | libappindicator3-1' 'ca-certificates' 'libasound2t64 | libasound2 | pulseaudio' 'libgl1' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk | xdg-desktop-portal-gnome | xdg-desktop-portal-kde' 'pipewire')
|
||||
opt_deps_ubuntu=("${opt_deps_debian[@]}")
|
||||
opt_deps_fedora=('xdg-utils' 'libappindicator-gtk3' 'ca-certificates' 'alsa-lib' 'pulseaudio-libs' 'mesa-libGL' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk' 'pipewire')
|
||||
opt_deps_arch=('xdg-utils' 'libappindicator-gtk3' 'ca-certificates' 'alsa-lib' 'pulseaudio' 'libglvnd' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk' 'pipewire')
|
||||
opt_deps_opensuse=('xdg-utils' 'libappindicator3-1' 'ca-certificates' 'libasound2' 'libpulse0' 'Mesa-libGL1' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk' 'pipewire')
|
||||
opt_deps_altlinux=('xdg-utils' 'libappindicator-gtk3' 'ca-certificates' 'libalsa' 'libGL' 'xdg-desktop-portal' 'xdg-desktop-portal-gtk' 'pipewire')
|
||||
|
||||
sources=(
|
||||
"https://td.telegram.org/tlinux/tsetup.${version}.tar.xz?~archive=false&~name=tsetup.tar.xz"
|
||||
'local:///org.telegram.desktop.desktop'
|
||||
'local:///telegram-desktop.png'
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:a9463f13c5f479e1dd951629ab9aa3686386cade4eb61138e0141db2efcfad6d'
|
||||
'sha256:8ceb3f6aea1003f84f1b5757cd857f8237b294bb18456e5e0e54d96e6fff04ba'
|
||||
'sha256:3fb1400c7dc9bbc3b5cb3ffedcbf4a9b09c53e28b57a7ff33a8a6b9048864090'
|
||||
'sha256:f3ad1b5ecdc1c9e5ab3719a0b084a3e0b4fc87ad424fbf81043df9637be3d1f5'
|
||||
)
|
||||
|
||||
scripts=(
|
||||
['postinstall']='postinstall.sh'
|
||||
['postremove']='postremove.sh'
|
||||
)
|
||||
|
||||
package() {
|
||||
cd "${srcdir}"
|
||||
|
||||
tar --no-same-owner --no-same-permissions -xJf tsetup.tar.xz
|
||||
|
||||
install -dm755 "${pkgdir}/opt/telegram-desktop"
|
||||
install -Dm755 "Telegram/Telegram" "${pkgdir}/opt/telegram-desktop/Telegram"
|
||||
|
||||
install -dm755 "${pkgdir}/usr/bin"
|
||||
ln -sfn /opt/telegram-desktop/Telegram "${pkgdir}/usr/bin/telegram-desktop"
|
||||
|
||||
# Telegram's own Launcher::ComputeExternalUpdater() (SourceFiles/core/
|
||||
# launcher.cpp) looks for a file under <exe-dir>/externalupdater.d/ that
|
||||
# contains a line matching its own full executable path; if found, it
|
||||
# calls SetUpdaterDisabledAtStartup(), which is the *documented* way for
|
||||
# distro/repo packagers to tell Telegram "I manage updates, not you".
|
||||
# This one flag fixes two things at once: it makes InstallLauncher() skip
|
||||
# self-writing a shadow ~/.local/share/applications/*.desktop and D-Bus
|
||||
# .service file on every launch, and it makes QGuiApplication's
|
||||
# desktopFileName() (the Wayland app_id used to match the running window
|
||||
# to an icon) use the plain "org.telegram.desktop" id instead of a
|
||||
# per-install-path hashed one — which is what was breaking the
|
||||
# taskbar/window icon even after the shadow-file duplicate was silenced.
|
||||
install -Dm644 /dev/stdin \
|
||||
"${pkgdir}/opt/telegram-desktop/externalupdater.d/nivora" <<'EOF'
|
||||
/opt/telegram-desktop/Telegram
|
||||
EOF
|
||||
|
||||
install-desktop org.telegram.desktop.desktop
|
||||
install -Dm644 telegram-desktop.png \
|
||||
"${pkgdir}/usr/share/icons/hicolor/256x256/apps/org.telegram.desktop.png"
|
||||
|
||||
install-license LICENSE "telegram/LICENSE.nivora"
|
||||
}
|
||||
|
||||
files() {
|
||||
files-find-binary
|
||||
files-find-desktop
|
||||
files-find-license
|
||||
files-find \
|
||||
"/opt/telegram-desktop/**/*" \
|
||||
"/usr/share/icons/hicolor/256x256/apps/org.telegram.desktop.png"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
[Desktop Entry]
|
||||
Name=Telegram
|
||||
Comment=New era of messaging
|
||||
TryExec=telegram-desktop
|
||||
Exec=telegram-desktop -- %U
|
||||
Icon=org.telegram.desktop
|
||||
Terminal=false
|
||||
StartupWMClass=TelegramDesktop
|
||||
Type=Application
|
||||
Categories=Chat;Network;InstantMessaging;Qt;
|
||||
MimeType=x-scheme-handler/tg;x-scheme-handler/tonsite;
|
||||
Keywords=tg;chat;im;messaging;messenger;sms;tdesktop;
|
||||
Actions=quit;
|
||||
DBusActivatable=false
|
||||
SingleMainWindow=true
|
||||
X-GNOME-UsesNotifications=true
|
||||
X-GNOME-SingleWindow=true
|
||||
|
||||
[Desktop Action quit]
|
||||
Exec=telegram-desktop -quit
|
||||
Name=Quit Telegram
|
||||
Icon=application-exit
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
optional_refresh() {
|
||||
local label=$1
|
||||
shift
|
||||
if ! "$@"; then
|
||||
echo "Предупреждение: не удалось обновить ${label}." >&2
|
||||
fi
|
||||
}
|
||||
|
||||
if command -v update-desktop-database >/dev/null 2>&1; then
|
||||
optional_refresh "desktop-базу" update-desktop-database -q /usr/share/applications
|
||||
fi
|
||||
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
|
||||
optional_refresh "кэш иконок" \
|
||||
gtk-update-icon-cache -q -t -f /usr/share/icons/hicolor
|
||||
fi
|
||||
if command -v kbuildsycoca6 >/dev/null 2>&1; then
|
||||
optional_refresh "кэш KDE" kbuildsycoca6 --noincremental
|
||||
elif command -v kbuildsycoca5 >/dev/null 2>&1; then
|
||||
optional_refresh "кэш KDE" kbuildsycoca5 --noincremental
|
||||
fi
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
optional_refresh() {
|
||||
local label=$1
|
||||
shift
|
||||
if ! "$@"; then
|
||||
echo "Предупреждение: не удалось обновить ${label}." >&2
|
||||
fi
|
||||
}
|
||||
|
||||
if command -v update-desktop-database >/dev/null 2>&1; then
|
||||
optional_refresh "desktop-базу" update-desktop-database -q /usr/share/applications
|
||||
fi
|
||||
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
|
||||
optional_refresh "кэш иконок" \
|
||||
gtk-update-icon-cache -q -t -f /usr/share/icons/hicolor
|
||||
fi
|
||||
if command -v kbuildsycoca6 >/dev/null 2>&1; then
|
||||
optional_refresh "кэш KDE" kbuildsycoca6 --noincremental
|
||||
elif command -v kbuildsycoca5 >/dev/null 2>&1; then
|
||||
optional_refresh "кэш KDE" kbuildsycoca5 --noincremental
|
||||
fi
|
||||
@@ -0,0 +1 @@
|
||||
include = "../stapler-repo.toml"
|
||||
|
After Width: | Height: | Size: 20 KiB |
@@ -2,10 +2,12 @@
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
launcher="${repo_root}/claude-desktop/claude-alt"
|
||||
icon="${repo_root}/claude-desktop/claude-alt.png"
|
||||
primary_tray_icon="${repo_root}/claude-desktop/claude-tray-orange.png"
|
||||
alternate_tray_icon="${repo_root}/claude-desktop/claude-alt-tray-turquoise.png"
|
||||
launcher="${repo_root}/claude-alt/claude-alt"
|
||||
icon="${repo_root}/claude/claude-alt.png"
|
||||
primary_tray_icon="${repo_root}/claude/claude-tray-orange.png"
|
||||
alternate_tray_icon="${repo_root}/claude/claude-alt-tray-turquoise.png"
|
||||
primary_recipe="${repo_root}/claude/Staplerfile"
|
||||
alternate_recipe="${repo_root}/claude-alt/Staplerfile"
|
||||
temp_dir="$(mktemp -d)"
|
||||
|
||||
cleanup() {
|
||||
@@ -14,6 +16,15 @@ cleanup() {
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
if grep -Eq '/usr/lib/claude-alt|com\\.anthropic\\.ClaudeAlt|claude-alt\\.png' \
|
||||
"$primary_recipe"; then
|
||||
echo 'claude-desktop must not ship ClaudeAlt files' >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -Fq 'python3 patch-asar.py' "$alternate_recipe"
|
||||
grep -Fq 'com.anthropic.ClaudeAlt.desktop' "$alternate_recipe"
|
||||
python3 -m py_compile "${repo_root}/claude-alt/patch-asar.py"
|
||||
|
||||
mkdir -p "${temp_dir}/bin" "${temp_dir}/home"
|
||||
log="${temp_dir}/launch.log"
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
temp_dir="$(mktemp -d)"
|
||||
|
||||
cleanup() {
|
||||
find "$temp_dir" -mindepth 1 -delete
|
||||
rmdir "$temp_dir"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
mkdir -p "${temp_dir}/bin"
|
||||
log="${temp_dir}/commands.log"
|
||||
|
||||
cat >"${temp_dir}/bin/stplr" <<'EOF'
|
||||
#!/bin/bash
|
||||
printf 'stplr' >>"$NIVORA_TEST_LOG"
|
||||
printf ' %s' "$@" >>"$NIVORA_TEST_LOG"
|
||||
printf '\n' >>"$NIVORA_TEST_LOG"
|
||||
EOF
|
||||
|
||||
cat >"${temp_dir}/bin/test-sudo" <<'EOF'
|
||||
#!/bin/bash
|
||||
printf 'sudo' >>"$NIVORA_TEST_LOG"
|
||||
printf ' %s' "$@" >>"$NIVORA_TEST_LOG"
|
||||
printf '\n' >>"$NIVORA_TEST_LOG"
|
||||
exec "$@"
|
||||
EOF
|
||||
|
||||
chmod 0755 "${temp_dir}/bin/"*
|
||||
for alias in sli slii sl; do
|
||||
ln -s "$repo_root/nivora-stplr/nivora-stplr" "${temp_dir}/bin/${alias}"
|
||||
done
|
||||
|
||||
export NIVORA_TEST_LOG="$log"
|
||||
export NIVORA_STPLR_SUDO=test-sudo
|
||||
export NIVORA_STPLR_QUIET=1
|
||||
export PATH="${temp_dir}/bin:${PATH}"
|
||||
|
||||
sli --repo nivora parsec --clean
|
||||
slii nivora/codex
|
||||
|
||||
cat >"${temp_dir}/expected" <<'EOF'
|
||||
sudo stplr install nivora/parsec --clean
|
||||
stplr install nivora/parsec --clean
|
||||
stplr info nivora/codex
|
||||
EOF
|
||||
|
||||
diff -u "${temp_dir}/expected" "$log"
|
||||
echo 'OK: Nivora helper'
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
temp_dir="$(mktemp -d)"
|
||||
|
||||
cleanup() {
|
||||
find "$temp_dir" -mindepth 1 -delete
|
||||
rmdir "$temp_dir"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
mkdir -p "${temp_dir}/bin"
|
||||
log="${temp_dir}/commands.log"
|
||||
|
||||
cat >"${temp_dir}/bin/stplr" <<'EOF'
|
||||
#!/bin/bash
|
||||
printf 'stplr' >>"$NIVORA_TEST_LOG"
|
||||
printf ' %s' "$@" >>"$NIVORA_TEST_LOG"
|
||||
printf '\n' >>"$NIVORA_TEST_LOG"
|
||||
EOF
|
||||
|
||||
cat >"${temp_dir}/bin/test-sudo" <<'EOF'
|
||||
#!/bin/bash
|
||||
printf 'sudo' >>"$NIVORA_TEST_LOG"
|
||||
printf ' %s' "$@" >>"$NIVORA_TEST_LOG"
|
||||
printf '\n' >>"$NIVORA_TEST_LOG"
|
||||
exec "$@"
|
||||
EOF
|
||||
|
||||
chmod 0755 "${temp_dir}/bin/"*
|
||||
for alias in nv nvi nve nvu nvs nvqi nvqa nvr nvrl nvf nvd nvc; do
|
||||
ln -s "${repo_root}/nivora-cli/nivora" "${temp_dir}/bin/${alias}"
|
||||
done
|
||||
|
||||
export NIVORA_TEST_LOG="$log"
|
||||
export NIVORA_SUDO='test-sudo'
|
||||
export NIVORA_QUIET=1
|
||||
export PATH="${temp_dir}/bin:${PATH}"
|
||||
|
||||
nvi codex --clean
|
||||
nve other/package
|
||||
nvu
|
||||
nvs editor
|
||||
nvqi --json codex
|
||||
nvqa --installed
|
||||
nvr
|
||||
nvrl
|
||||
nvf
|
||||
nvc
|
||||
nv --repo none install local-name
|
||||
|
||||
cat >"${temp_dir}/expected" <<'EOF'
|
||||
sudo stplr install nivora/codex --clean
|
||||
stplr install nivora/codex --clean
|
||||
sudo stplr remove other/package
|
||||
stplr remove other/package
|
||||
sudo stplr up
|
||||
stplr up
|
||||
stplr search editor
|
||||
stplr info --json nivora/codex
|
||||
stplr list --installed
|
||||
sudo stplr refresh
|
||||
stplr refresh
|
||||
stplr repo list
|
||||
sudo stplr fix
|
||||
stplr fix
|
||||
stplr config show
|
||||
sudo stplr install local-name
|
||||
stplr install local-name
|
||||
EOF
|
||||
|
||||
diff -u "${temp_dir}/expected" "$log"
|
||||
|
||||
nv --lang en --help >"${temp_dir}/help-en"
|
||||
nv --lang ru --help >"${temp_dir}/help-ru"
|
||||
nv --lang ru completion fish >"${temp_dir}/completion"
|
||||
nvd --lang en >"${temp_dir}/doctor"
|
||||
NIVORA_QUIET=0 nv --lang en --dry-run install codex \
|
||||
>"${temp_dir}/preview-stdout" 2>"${temp_dir}/preview"
|
||||
|
||||
grep -q 'Simple Stapler package management' "${temp_dir}/help-en"
|
||||
grep -q 'Простое управление пакетами Stapler' "${temp_dir}/help-ru"
|
||||
grep -q 'nvi.*установить' "${temp_dir}/help-ru"
|
||||
grep -q '__fish_use_subcommand' "${temp_dir}/completion"
|
||||
grep -q 'The system is ready' "${temp_dir}/doctor"
|
||||
grep -q 'Preview.*test-sudo stplr install nivora/codex' "${temp_dir}/preview"
|
||||
[[ ! -s "${temp_dir}/preview-stdout" ]]
|
||||
|
||||
if nv --lang de help >"${temp_dir}/invalid-out" 2>"${temp_dir}/invalid"; then
|
||||
echo 'Ожидалась ошибка для неподдерживаемого языка' >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -q 'supported languages are ru and en' "${temp_dir}/invalid"
|
||||
|
||||
echo 'OK: Nivora CLI'
|
||||
@@ -13,6 +13,7 @@ grep -Fq 'compatibility_desktop=' "$recipe"
|
||||
grep -Fq 'canonical_desktop=' "$recipe"
|
||||
grep -Fq "sed -i '/^NoDisplay=true\$/d'" "$recipe"
|
||||
grep -Fq "sed -i '/^\\[Desktop Entry\\]\$/a NoDisplay=true'" "$recipe"
|
||||
grep -Fq 'StartupWMClass=Yandex-browser' "$recipe"
|
||||
grep -Fq 'update_codecs' "$postinstall"
|
||||
|
||||
if grep -Eq '/etc/(cron|xdg/autostart)' "$recipe"; then
|
||||
|
||||
@@ -7,18 +7,23 @@ readonly -a PACKAGES=(
|
||||
balena-etcher
|
||||
chatbox
|
||||
clash-verge-rev
|
||||
claude-desktop
|
||||
claude-alt
|
||||
claude
|
||||
codex
|
||||
fisher
|
||||
github-desktop
|
||||
happ
|
||||
max
|
||||
netbird
|
||||
nivora-stplr
|
||||
nivora-cli
|
||||
opencode
|
||||
parsec
|
||||
pineconemc
|
||||
tailscale
|
||||
telegram
|
||||
ventoy
|
||||
vintner
|
||||
vk-messenger
|
||||
vual
|
||||
yandex-browser-stable
|
||||
)
|
||||
@@ -211,6 +216,51 @@ latest_yandex_browser() {
|
||||
printf '%s\n' "$version"
|
||||
}
|
||||
|
||||
latest_max() {
|
||||
local filename ver build
|
||||
filename="$(
|
||||
curl --retry 3 --retry-delay 2 --retry-all-errors \
|
||||
--connect-timeout 30 --max-time 120 -fsSL \
|
||||
'https://download.max.ru/linux/deb/dists/stable/main/binary-amd64/Packages.gz' |
|
||||
gzip -dc |
|
||||
awk '
|
||||
/^Package: max$/ { selected = 1; next }
|
||||
/^Package: / { selected = 0 }
|
||||
selected && /^Filename: / { print $2 }
|
||||
' |
|
||||
sort -V |
|
||||
tail -1
|
||||
)"
|
||||
[[ -n "$filename" ]] || die 'cannot determine latest MAX version'
|
||||
filename="$(basename "$filename")"
|
||||
filename="${filename#MAX-}"
|
||||
filename="${filename%.deb}"
|
||||
ver="${filename%.*}"
|
||||
build="${filename##*.}"
|
||||
[[ -n "$ver" && -n "$build" ]] || die 'cannot parse latest MAX filename'
|
||||
printf '%s~%s\n' "$ver" "$build"
|
||||
}
|
||||
|
||||
latest_vk_messenger() {
|
||||
local temp_dir version
|
||||
temp_dir="$(mktemp -d)"
|
||||
curl --retry 3 --retry-delay 2 --retry-all-errors \
|
||||
--connect-timeout 30 --max-time 300 -fsSL \
|
||||
-o "${temp_dir}/vk-messenger.deb" \
|
||||
'https://upload.object2.vk-apps.com/vk-me-desktop-dev-5837a06d-5f28-484a-ac22-045903cb1b1a/latest/vk-messenger.deb'
|
||||
(
|
||||
cd "$temp_dir"
|
||||
ar x vk-messenger.deb
|
||||
tar -xOf control.tar.* ./control
|
||||
) >"${temp_dir}/control"
|
||||
version="$(awk '$1 == "Version:" {print $2; exit}' "${temp_dir}/control")"
|
||||
version="${version%-*}"
|
||||
[[ -n "$version" ]] || die 'cannot determine latest VK Messenger version'
|
||||
printf '%s\n' "$version"
|
||||
find "$temp_dir" -mindepth 1 -delete
|
||||
rmdir "$temp_dir"
|
||||
}
|
||||
|
||||
latest_version() {
|
||||
case "$1" in
|
||||
adwyra) github_latest_release Cheviiot/Adwyra ;;
|
||||
@@ -218,20 +268,24 @@ latest_version() {
|
||||
balena-etcher) github_latest_release balena-io/etcher ;;
|
||||
chatbox) latest_chatbox ;;
|
||||
clash-verge-rev) github_latest_release clash-verge-rev/clash-verge-rev ;;
|
||||
claude-desktop) latest_claude_desktop ;;
|
||||
claude | claude-alt) latest_claude_desktop ;;
|
||||
codex) github_latest_release Boria138/codex-app-linux ;;
|
||||
fisher) github_latest_release jorgebucaran/fisher ;;
|
||||
github-desktop)
|
||||
github_latest_release desktop/desktop | sed 's/^release-//'
|
||||
;;
|
||||
happ) github_latest_release Happ-proxy/happ-desktop ;;
|
||||
max) latest_max ;;
|
||||
netbird) github_latest_release netbirdio/netbird ;;
|
||||
nivora-stplr) current_version nivora-stplr ;;
|
||||
nivora-cli) current_version nivora-cli ;;
|
||||
opencode) github_latest_release anomalyco/opencode ;;
|
||||
parsec) latest_parsec ;;
|
||||
pineconemc) github_latest_release ElyPrismLauncher/Launcher ;;
|
||||
tailscale) latest_tailscale ;;
|
||||
telegram) github_latest_release telegramdesktop/tdesktop ;;
|
||||
ventoy) github_latest_release ventoy/Ventoy ;;
|
||||
vintner) github_latest_release Cheviiot/vintner ;;
|
||||
vk-messenger) latest_vk_messenger ;;
|
||||
vual) github_latest_release Cheviiot/Vual ;;
|
||||
yandex-browser-stable) latest_yandex_browser ;;
|
||||
*) die "unknown package: $1" ;;
|
||||
|
||||
@@ -32,7 +32,7 @@ if [[ "${#python_files[@]}" -gt 0 ]]; then
|
||||
fi
|
||||
|
||||
python3 -m unittest discover -s tests -p 'test_*.py' -v
|
||||
bash tests/test_helper.sh
|
||||
bash tests/test_nivora_cli.sh
|
||||
bash tests/test_claude_alt.sh
|
||||
bash tests/test_codex_computer_use.sh
|
||||
bash tests/test_happ_theme.sh
|
||||
|
||||
@@ -41,7 +41,7 @@ def main() -> None:
|
||||
)
|
||||
|
||||
for package in package_dirs:
|
||||
command = f"stplr install nivora/{package}"
|
||||
command = f"`stplr install nivora/{package}`"
|
||||
version, architectures = package_metadata(package)
|
||||
matching_lines = [
|
||||
index
|
||||
|
||||
@@ -26,9 +26,9 @@ esac
|
||||
# package | command | persistent state marker | desktop/unit | icon
|
||||
readonly -a lifecycle_packages=(
|
||||
'clash-verge-rev|/usr/bin/clash-verge|/home/nivora-test/.local/share/io.github.clash-verge-rev.clash-verge-rev/nivora-lifecycle-state|/usr/share/applications/Clash Verge.desktop|/usr/share/icons/hicolor/128x128/apps/clash-verge.png'
|
||||
'claude-desktop|/usr/bin/claude-desktop|/home/nivora-test/.config/Claude/nivora-lifecycle-state|/usr/share/applications/com.anthropic.Claude.desktop|/usr/share/icons/hicolor/128x128/apps/claude-desktop.png'
|
||||
'claude|/usr/bin/claude-desktop|/home/nivora-test/.config/Claude/nivora-lifecycle-state|/usr/share/applications/com.anthropic.Claude.desktop|/usr/share/icons/hicolor/128x128/apps/claude-desktop.png'
|
||||
'codex|/usr/bin/codex-app|/home/nivora-test/.codex/nivora-lifecycle-state|/usr/share/applications/codex-app.desktop|/usr/share/icons/hicolor/512x512/apps/codex-app.png'
|
||||
'nivora-stplr|/usr/bin/sl|/home/nivora-test/.config/nivora-stplr/nivora-lifecycle-state|-|-'
|
||||
'nivora-cli|/usr/bin/nv|/home/nivora-test/.config/nivora-cli/nivora-lifecycle-state|-|-'
|
||||
'opencode|/usr/bin/opencode-desktop|/home/nivora-test/.config/opencode/nivora-lifecycle-state|/usr/share/applications/opencode-desktop.desktop|/usr/share/icons/hicolor/128x128/apps/ai.opencode.desktop.png'
|
||||
'tailscale|/usr/bin/tailscale|/var/lib/tailscale/nivora-lifecycle-state|/usr/lib/systemd/system/tailscaled.service|-'
|
||||
'netbird|/usr/bin/netbird|/var/lib/netbird/nivora-lifecycle-state|/usr/lib/systemd/system/netbird.service|-'
|
||||
|
||||
@@ -17,18 +17,23 @@ EXPECTED_PACKAGES = (
|
||||
"balena-etcher",
|
||||
"chatbox",
|
||||
"clash-verge-rev",
|
||||
"claude-desktop",
|
||||
"claude",
|
||||
"claude-alt",
|
||||
"codex",
|
||||
"fisher",
|
||||
"github-desktop",
|
||||
"happ",
|
||||
"max",
|
||||
"netbird",
|
||||
"nivora-stplr",
|
||||
"nivora-cli",
|
||||
"opencode",
|
||||
"parsec",
|
||||
"pineconemc",
|
||||
"tailscale",
|
||||
"telegram",
|
||||
"ventoy",
|
||||
"vintner",
|
||||
"vk-messenger",
|
||||
"vual",
|
||||
"yandex-browser-stable",
|
||||
)
|
||||
@@ -42,11 +47,12 @@ REQUIRED_ROOT_FILES = {
|
||||
Path("stapler-repo.toml"),
|
||||
Path("docs/maintenance.md"),
|
||||
Path("docs/security-model.md"),
|
||||
Path("docs/packages/claude-desktop.md"),
|
||||
Path("docs/packages/claude.md"),
|
||||
Path("docs/packages/claude-alt.md"),
|
||||
Path("docs/packages/codex.md"),
|
||||
Path("docs/packages/github-desktop.md"),
|
||||
Path("docs/packages/opencode.md"),
|
||||
Path("docs/packages/nivora-stplr.md"),
|
||||
Path("docs/packages/nivora-cli.md"),
|
||||
Path("docs/packages/ventoy.md"),
|
||||
}
|
||||
|
||||
@@ -164,8 +170,13 @@ def validate_package(package: str, errors: list[str]) -> dict[str, object]:
|
||||
|
||||
if provides != [] or conflicts != []:
|
||||
errors.append(f"{package}: provides/conflicts must not contain binary aliases")
|
||||
if replaces != [package]:
|
||||
errors.append(f"{package}: replaces must contain only its own base package name")
|
||||
expected_replaces = [package]
|
||||
if package == "claude":
|
||||
expected_replaces.append("claude-desktop")
|
||||
if replaces != expected_replaces:
|
||||
errors.append(
|
||||
f"{package}: replaces must be {expected_replaces}, got {replaces}"
|
||||
)
|
||||
|
||||
if "package()" not in text or "files()" not in text:
|
||||
errors.append(f"{package}: package() or files() is missing")
|
||||
@@ -239,7 +250,7 @@ def validate_readme(metadata: dict[str, dict[str, object]], errors: list[str]) -
|
||||
errors.append("README.md: catalog must contain exactly six categories")
|
||||
|
||||
for package, values in metadata.items():
|
||||
command = f"stplr install nivora/{package}"
|
||||
command = f"`stplr install nivora/{package}`"
|
||||
catalog_rows = [
|
||||
line for line in text.splitlines() if line.startswith("|") and command in line
|
||||
]
|
||||
|
||||
@@ -93,17 +93,23 @@ for package in "${packages[@]}"; do
|
||||
}
|
||||
fi
|
||||
|
||||
if [[ "$package" == 'claude-desktop' ]]; then
|
||||
if [[ "$package" == 'claude' ]]; then
|
||||
for forbidden_path in \
|
||||
/usr/bin/claude-alt \
|
||||
/usr/lib/claude-alt/claude-alt-bin \
|
||||
/usr/share/applications/com.anthropic.ClaudeAlt.desktop; do
|
||||
contains_path "$forbidden_path" && {
|
||||
echo "${package}: обнаружен компонент отдельного пакета ClaudeAlt: ${forbidden_path}" >&2
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ "$package" == 'claude-alt' ]]; then
|
||||
for required_path in \
|
||||
/usr/bin/claude-alt \
|
||||
/usr/bin/claude-desktop-account2 \
|
||||
/usr/lib/claude-desktop/resources/TrayIconLinux.png \
|
||||
/usr/lib/claude-desktop/resources/TrayIconLinux-Dark.png \
|
||||
/usr/lib/claude-alt/claude-alt-bin \
|
||||
/usr/lib/claude-alt/resources/app.asar \
|
||||
/usr/lib/claude-alt/resources/icon.png \
|
||||
/usr/lib/claude-alt/resources/TrayIconLinux.png \
|
||||
/usr/lib/claude-alt/resources/TrayIconLinux-Dark.png \
|
||||
/usr/share/applications/com.anthropic.ClaudeAlt.desktop \
|
||||
/usr/share/icons/hicolor/512x512/apps/claude-alt.png; do
|
||||
contains_path "$required_path" || {
|
||||
@@ -111,10 +117,6 @@ for package in "${packages[@]}"; do
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
contains_path '/usr/share/applications/claude-desktop-account2.desktop' && {
|
||||
echo "${package}: обнаружен устаревший desktop-файл второго профиля" >&2
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
if [[ "$package" == 'balena-etcher' ]]; then
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
package_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
repo_root="$(cd "${package_dir}/.." && pwd)"
|
||||
exec "${repo_root}/tools/package_updates.sh" check "$(basename "$package_dir")"
|
||||
@@ -0,0 +1,25 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Cheviiot
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
This license covers vintner's own source code. It does not cover the
|
||||
Microsoft Visual C++ Build Tools / Windows SDK that `vintner download`
|
||||
fetches and unpacks, which remain governed by Microsoft's own license terms.
|
||||
@@ -0,0 +1,76 @@
|
||||
name='vintner'
|
||||
version=0.5.0
|
||||
release=1
|
||||
summary='Cross compile with MSVC on Linux via Wine'
|
||||
summary_ru='Кросс-компиляция с MSVC на Linux через Wine'
|
||||
group='Development/Tools'
|
||||
desc='vintner is a single-binary tool for cross compiling with the real MSVC toolchain on Linux via Wine. Once you run its download/install subcommands, cl, link, lib, rc, midl, mc, mt, dumpbin, msbuild, nmake, ml, ml64, armasm, armasm64, cmd and findstr all work as drop-in commands, exactly like on Windows, or can be invoked directly as "vintner cl", "vintner msbuild", etc. without touching PATH. Supports building real KMDF/UMDF drivers via the Windows Driver Kit (--with-wdk), legacy D3DX9 code via the DirectX SDK (--with-dxsdk), old PlatformToolset-pinned .vcxproj files against the one installed compiler, resumes interrupted downloads, and "vintner doctor" diagnoses a broken wine/toolchain setup. Its own CLI is available in English and Russian.'
|
||||
desc_ru='vintner — однобинарный инструмент для кросс-компиляции с реальным MSVC на Linux через Wine. После выполнения его подкоманд download/install команды cl, link, lib, rc, midl, mc, mt, dumpbin, msbuild, nmake, ml, ml64, armasm, armasm64, cmd и findstr работают как обычные команды, точно как в Windows, либо вызываются напрямую как «vintner cl», «vintner msbuild» и т.д., не трогая PATH. Поддерживает сборку настоящих KMDF/UMDF-драйверов через Windows Driver Kit (--with-wdk), устаревший код D3DX9 через DirectX SDK (--with-dxsdk), старые .vcxproj с закреплённым PlatformToolset против единственного установленного компилятора, докачивает прерванные загрузки, а «vintner doctor» диагностирует неисправную настройку wine/toolchain. Сам CLI доступен на английском и русском.'
|
||||
homepage='https://github.com/Cheviiot/vintner'
|
||||
maintainer='Cheviiot <https://github.com/Cheviiot>'
|
||||
|
||||
architectures=('amd64' 'arm64')
|
||||
|
||||
license=('MIT')
|
||||
|
||||
provides=()
|
||||
replaces=('vintner')
|
||||
conflicts=()
|
||||
|
||||
auto_reqprov_method="dirty"
|
||||
auto_req=0
|
||||
auto_prov=0
|
||||
|
||||
# wine/msitools/git/cabextract are needed at runtime by `vintner
|
||||
# download`/`install` and by the tool wrappers themselves, not just at
|
||||
# build time. cabextract is only exercised by --with-dxsdk, but kept a
|
||||
# hard dep for the same reason msitools is: small, no heavy transitive
|
||||
# deps, and simpler than making package deps conditional on a flag.
|
||||
deps=()
|
||||
deps_debian=('wine' 'msitools' 'git' 'cabextract')
|
||||
deps_ubuntu=("${deps_debian[@]}")
|
||||
deps_fedora=('wine' 'msitools' 'git' 'cabextract')
|
||||
deps_arch=('wine' 'msitools' 'git' 'cabextract')
|
||||
deps_opensuse=('wine' 'msitools' 'git' 'cabextract')
|
||||
deps_altlinux=('wine' 'msitools' 'git' 'cabextract')
|
||||
|
||||
build_deps=('binutils')
|
||||
|
||||
# Prebuilt by vintner's own CI (.github/workflows/release.yml) and
|
||||
# published to its GitHub Releases; renamed to a common local name so
|
||||
# package() doesn't need to branch on architecture.
|
||||
sources=(
|
||||
"https://github.com/Cheviiot/vintner/releases/download/v${version}/vintner-linux-amd64?~archive=false&~name=vintner"
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
sources_arm64=(
|
||||
"https://github.com/Cheviiot/vintner/releases/download/v${version}/vintner-linux-arm64?~archive=false&~name=vintner"
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:c06edc2c6469f3a6bac63bd2a1e811f6fe03cc05c49871413a8f58d5e382732a'
|
||||
'sha256:e377b84adc5315cf372c3d80ecbd3008402d8b07f248e711c7553784e0c33168'
|
||||
)
|
||||
|
||||
checksums_arm64=(
|
||||
'sha256:4ddb97ad6c193058589564f99781b3ef5e5725d243d3c1cbb895b81c35799144'
|
||||
'sha256:e377b84adc5315cf372c3d80ecbd3008402d8b07f248e711c7553784e0c33168'
|
||||
)
|
||||
|
||||
package() {
|
||||
cd "${srcdir}"
|
||||
chmod +x "${srcdir}/vintner"
|
||||
install-binary "${srcdir}/vintner"
|
||||
install-license "${srcdir}/LICENSE" "vintner/LICENSE"
|
||||
"${srcdir}/vintner" completion bash | install-completion bash vintner
|
||||
"${srcdir}/vintner" completion zsh | install-completion zsh vintner
|
||||
}
|
||||
|
||||
files() {
|
||||
files-find-binary
|
||||
files-find-license
|
||||
files-find "/usr/share/bash-completion/completions/vintner"
|
||||
files-find "/usr/share/zsh/site-functions/_vintner"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
package_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
repo_root="$(cd "${package_dir}/.." && pwd)"
|
||||
exec "${repo_root}/tools/package_updates.sh" check "$(basename "$package_dir")"
|
||||
@@ -0,0 +1,19 @@
|
||||
Сведения о лицензии пакета vk-messenger
|
||||
|
||||
Лицензия: Custom (проприетарная).
|
||||
Исходный продукт: https://vk.me/app
|
||||
Официальный deb/rpm-артефакт: https://vk.me/app (объектное хранилище VK)
|
||||
|
||||
Нюансы пакета:
|
||||
- Пакет перепаковывает официальный Linux-артефакт VK Messenger, распространяемый
|
||||
напрямую с vk.me — отдельного публичного репозитория или GitHub-релиза
|
||||
у продукта нет, поэтому используется прямая ссылка на объектное хранилище VK.
|
||||
- Приложение собрано на Electron/Chromium; лицензии этих компонентов
|
||||
устанавливаются рядом с остальными лицензиями пакета.
|
||||
- Для полноценной работы требуется учетная запись VK ID.
|
||||
- Использование мессенджера, учетной записи и сетевых функций регулируется
|
||||
условиями VK.
|
||||
- Пакет помечен как несвободный через `nonfree=1`.
|
||||
|
||||
Официальные условия:
|
||||
https://vk.com/terms
|
||||
@@ -0,0 +1,102 @@
|
||||
name='vk-messenger'
|
||||
version='6.0.57'
|
||||
release=1
|
||||
summary='VK Messenger client'
|
||||
summary_ru='Официальный клиент VK Messenger'
|
||||
group='Networking/Instant messaging'
|
||||
desc='VK Messenger is the official VK instant messaging client, distributed as an Electron desktop application directly from vk.me.'
|
||||
desc_ru='VK Messenger — официальный клиент мессенджера VK, распространяемый в виде Electron-приложения напрямую с vk.me.'
|
||||
homepage='https://vk.me/app'
|
||||
maintainer='VK Support <support@vk.com>'
|
||||
|
||||
architectures=('amd64')
|
||||
|
||||
license=('Custom')
|
||||
nonfree=1
|
||||
nonfree_msg='VK Messenger является проприетарным приложением VK. Использование мессенджера, учетной записи VK ID и сетевых функций регулируется условиями VK.'
|
||||
nonfree_url='https://vk.com/terms'
|
||||
|
||||
provides=()
|
||||
replaces=('vk-messenger')
|
||||
conflicts=()
|
||||
|
||||
auto_reqprov_method="dirty"
|
||||
auto_req=0
|
||||
auto_prov=0
|
||||
|
||||
deps=()
|
||||
deps_debian=('libc6' 'libglib2.0-0t64 | libglib2.0-0' 'libgtk-3-0t64 | libgtk-3-0' 'libnotify4' 'libnss3' 'libxss1' 'libxtst6' 'xdg-utils' 'libatspi2.0-0' 'libuuid1' 'libsecret-1-0' 'libasound2t64 | libasound2 | pulseaudio' 'libgbm1' 'libdrm2' 'pulseaudio | pulseaudio-utils | pipewire-pulse')
|
||||
deps_ubuntu=("${deps_debian[@]}")
|
||||
deps_fedora=('glibc' 'glib2' 'gtk3' 'libnotify' 'nss' 'libXScrnSaver' 'libXtst' 'xdg-utils' 'at-spi2-core' 'libuuid' 'libsecret' 'alsa-lib' 'mesa-libgbm' 'libdrm' 'pulseaudio-utils')
|
||||
deps_arch=('glibc' 'glib2' 'gtk3' 'libnotify' 'nss' 'libxss' 'libxtst' 'xdg-utils' 'at-spi2-core' 'libutil-linux' 'libsecret' 'alsa-lib' 'libgbm' 'libdrm' 'libpulse')
|
||||
deps_opensuse=('glibc' 'libglib-2_0-0' 'gtk3' 'libnotify4' 'mozilla-nss' 'libXss1' 'libXtst6' 'xdg-utils' 'at-spi2-core' 'libuuid1' 'libsecret-1-0' 'libasound2' 'libgbm1' 'libdrm2' 'pulseaudio-utils')
|
||||
deps_altlinux=('glibc' 'glib2' 'libgtk+3' 'libnotify' 'libnss' 'libXScrnSaver' 'libXtst' 'xdg-utils' 'libat-spi2-core' 'libuuid' 'libsecret' 'libalsa' 'libgbm' 'libdrm' 'pulseaudio-utils')
|
||||
|
||||
opt_deps=()
|
||||
opt_deps_debian=('libayatana-appindicator3-1 | libappindicator3-1')
|
||||
opt_deps_ubuntu=("${opt_deps_debian[@]}")
|
||||
opt_deps_fedora=('libappindicator-gtk3')
|
||||
opt_deps_arch=('libappindicator-gtk3')
|
||||
opt_deps_opensuse=('libappindicator3-1')
|
||||
opt_deps_altlinux=('libappindicator-gtk3')
|
||||
|
||||
build_deps=('binutils')
|
||||
|
||||
sources=(
|
||||
"https://upload.object2.vk-apps.com/vk-me-desktop-dev-5837a06d-5f28-484a-ac22-045903cb1b1a/latest/vk-messenger.deb?~archive=false&~name=vk-messenger.deb"
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:cb4fa7a8fb3c6af5c432696e4653751393c9c5c655b6bf0e2d944ff7483ec784'
|
||||
'sha256:ab672f11775fc2a579a2001bef3c8b75d78159a67e004dd55339befe98f9e232'
|
||||
)
|
||||
|
||||
scripts=(
|
||||
['postinstall']='postinstall.sh'
|
||||
['postremove']='postremove.sh'
|
||||
)
|
||||
|
||||
package() {
|
||||
cd "${srcdir}"
|
||||
|
||||
mkdir -p "${srcdir}/extracted"
|
||||
ar x vk-messenger.deb
|
||||
tar -xf data.tar.* -C "${srcdir}/extracted"
|
||||
|
||||
# Upstream's own installer uses the literal (Cyrillic, spaced) product name
|
||||
# as the /opt directory, not a clean slug — find it rather than hardcode it.
|
||||
opt_src="$(find "${srcdir}/extracted/opt" -mindepth 1 -maxdepth 1 -type d | head -1)"
|
||||
[[ -n "$opt_src" ]] || { echo "не найден каталог /opt/* внутри vk-messenger.deb" >&2; exit 1; }
|
||||
|
||||
install -dm755 "${pkgdir}/opt/vk-messenger"
|
||||
cp -a "${opt_src}/." "${pkgdir}/opt/vk-messenger/"
|
||||
chmod 0755 "${pkgdir}/opt/vk-messenger/chrome-sandbox"
|
||||
|
||||
install -dm755 "${pkgdir}/usr/bin"
|
||||
ln -sfn /opt/vk-messenger/vk-messenger "${pkgdir}/usr/bin/vk-messenger"
|
||||
|
||||
install -Dm644 "${srcdir}/extracted/usr/share/applications/vk-messenger.desktop" \
|
||||
"${pkgdir}/usr/share/applications/vk-messenger.desktop"
|
||||
|
||||
for icon in "${srcdir}"/extracted/usr/share/icons/hicolor/*/apps/vk-messenger.*; do
|
||||
size="$(basename "$(dirname "$(dirname "$icon")")")"
|
||||
install -Dm644 "$icon" \
|
||||
"${pkgdir}/usr/share/icons/hicolor/${size}/apps/$(basename "$icon")"
|
||||
done
|
||||
|
||||
install-license "${srcdir}/LICENSE" "vk-messenger/LICENSE.nivora"
|
||||
install -Dm644 "${opt_src}/LICENSE.electron.txt" \
|
||||
"${pkgdir}/usr/share/licenses/vk-messenger/LICENSE.electron.txt"
|
||||
install -Dm644 "${opt_src}/LICENSES.chromium.html" \
|
||||
"${pkgdir}/usr/share/licenses/vk-messenger/LICENSES.chromium.html"
|
||||
}
|
||||
|
||||
files() {
|
||||
files-find-binary
|
||||
files-find-desktop
|
||||
files-find-license
|
||||
files-find \
|
||||
"/opt/vk-messenger/**/*" \
|
||||
"/usr/share/icons/hicolor/*/apps/vk-messenger.*"
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
optional_refresh() {
|
||||
local label=$1
|
||||
shift
|
||||
if ! "$@"; then
|
||||
echo "Предупреждение: не удалось обновить ${label}." >&2
|
||||
fi
|
||||
}
|
||||
|
||||
sandbox=/opt/vk-messenger/chrome-sandbox
|
||||
if [[ ! -f "$sandbox" ]]; then
|
||||
echo "Ошибка: не найден Electron sandbox: ${sandbox}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -L /proc/self/ns/user ]] && command -v unshare >/dev/null 2>&1 \
|
||||
&& unshare --user true 2>/dev/null; then
|
||||
chmod 0755 "$sandbox"
|
||||
else
|
||||
chmod 4755 "$sandbox"
|
||||
fi
|
||||
|
||||
if command -v update-desktop-database >/dev/null 2>&1; then
|
||||
optional_refresh "desktop-базу" update-desktop-database -q /usr/share/applications
|
||||
fi
|
||||
|
||||
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
|
||||
optional_refresh "кэш иконок" gtk-update-icon-cache -f -q /usr/share/icons/hicolor
|
||||
fi
|
||||
|
||||
if command -v kbuildsycoca6 >/dev/null 2>&1; then
|
||||
optional_refresh "кэш KDE" kbuildsycoca6 --noincremental
|
||||
elif command -v kbuildsycoca5 >/dev/null 2>&1; then
|
||||
optional_refresh "кэш KDE" kbuildsycoca5 --noincremental
|
||||
fi
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
optional_refresh() {
|
||||
local label=$1
|
||||
shift
|
||||
if ! "$@"; then
|
||||
echo "Предупреждение: не удалось обновить ${label}." >&2
|
||||
fi
|
||||
}
|
||||
|
||||
if command -v update-desktop-database >/dev/null 2>&1; then
|
||||
optional_refresh "desktop-базу" update-desktop-database -q /usr/share/applications
|
||||
fi
|
||||
|
||||
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
|
||||
optional_refresh "кэш иконок" gtk-update-icon-cache -f -q /usr/share/icons/hicolor
|
||||
fi
|
||||
|
||||
if command -v kbuildsycoca6 >/dev/null 2>&1; then
|
||||
optional_refresh "кэш KDE" kbuildsycoca6 --noincremental
|
||||
elif command -v kbuildsycoca5 >/dev/null 2>&1; then
|
||||
optional_refresh "кэш KDE" kbuildsycoca5 --noincremental
|
||||
fi
|
||||
@@ -0,0 +1 @@
|
||||
include = "../stapler-repo.toml"
|
||||
@@ -1,6 +1,6 @@
|
||||
name='yandex-browser-stable'
|
||||
version='26.4.1.1110'
|
||||
release=3
|
||||
version=26.6.1.1003
|
||||
release=1
|
||||
summary='Fast and secure Chromium-based web browser from Yandex'
|
||||
summary_ru='Быстрый и безопасный браузер Яндекса на основе Chromium'
|
||||
group='Networking/WWW'
|
||||
@@ -79,7 +79,7 @@ sources=(
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:27c8570c68a5e1b475304aaa4e8accefbc21e150b644a9cbc998ed32d952c8ba'
|
||||
'sha256:740006518ea877303b70a69e063dcc8531fe05b4d1582f270b783e22a83cf852'
|
||||
'sha256:36fb82bc8a2bb99eea41807712d9abf810edd562fa521955444e2dbef26ff40d'
|
||||
)
|
||||
|
||||
@@ -110,6 +110,9 @@ package() {
|
||||
canonical_desktop="${pkgdir}/usr/share/applications/ru.yandex.desktop.browser.desktop"
|
||||
sed -i '/^NoDisplay=true$/d' "${compatibility_desktop}" "${canonical_desktop}"
|
||||
sed -i '/^\[Desktop Entry\]$/a NoDisplay=true' "${compatibility_desktop}"
|
||||
sed -i '/^StartupWMClass=/d' "${canonical_desktop}"
|
||||
sed -i '/^\[Desktop Entry\]$/a StartupWMClass=Yandex-browser' \
|
||||
"${canonical_desktop}"
|
||||
cp -a "${srcdir}/extracted/usr/share/appdata" "${pkgdir}/usr/share/"
|
||||
cp -a "${srcdir}/extracted/usr/share/gnome-control-center" \
|
||||
"${pkgdir}/usr/share/"
|
||||
|
||||