Skip to content

📦 Пакетный менеджер и реестры

📌 Описание

Пакетный менеджер в духе apt/homebrew: приложения описываются манифестом asc.yaml, публикуются в реестрах, ставятся командой asc install <package>. Реестры бывают официальные и кастомные, локальные (file://) и удалённые (https://), включая GitHub-репозитории.

🎯 Сценарии использования

  • asc install nginx — установка из официального реестра.
  • asc source add https://registry.example.com — подключение кастомного реестра (как apt source).
  • asc source add https://github.com/user/my-app — приложение прямо из GitHub (asc.yaml в корне); для приватного при 404 — предложение подключить токен.
  • asc install https://github.com/user/my-app --branch dev — установка прямо из URL репозитория, вообще без реестра (DMN-040): для форков и пакетов, которые никогда не публиковались. asc source add выше подключает репозиторий к реестрам насовсем; это — для разовой пробы.
  • Магазин платформы (🛍️ app-store) — витрина над теми же реестрами.

🏗️ Техническое решение

Манифест asc.yaml (черновик)

yaml
name: my-app
version: 1.2.0
type: docker | native | utility
category: web                 # тема для реестра (databases, ai, bots, game-servers…)
description: "..."            # EN в официальном реестре
settings: ./asc.settings.yaml # необязательно: файл настроек приложения (см. ниже)
runtime:
  image: nginx:1.27           # для docker
  stdin: true                 # docker, необязательно: держать stdin открытым (docker run -i) — ввод из `asc attach` доходит до приложения
  tty: true                   # docker, необязательно: выделить псевдо-TTY (docker run -t)
  # или install/start/stop команды для native
requirements: { ram: 256M, disk: 1G }
healthcheck: { http: /health }

ℹ️ В манифесте нет секций env:, ports: и volumes: (DMN-027/030): environment-переменные, публикуемые порты и тома объявляются в asc.settings.yaml — настройками с ключом env: и типами ports / volumes (см. ниже). Один источник истины: что пользователь может настроить — то приложение и получает.

ℹ️ Каждый контейнер type: docker получает повышенный лимит открытых файлов (ulimit nofile, 10240 soft/hard) вместо дефолта самого движка в 1024 — некоторые игровые серверы (задокументированный случай — EOS SDK в 7 Days to Die) виснут или падают при старте на этом дефолте, причём без внятного симптома, кроме тишины в логе после первой же строчки.

🏗️ Локальная сборка образа: image-build (DMN-050)

Приложение type: docker может поставлять собственный Dockerfile и собирать образ локально движком вместо (или наряду с) скачиванием готового:

yaml
runtime:
  image-build:
    context: .              # каталог контекста сборки относительно манифеста (по умолчанию '.')
    dockerfile: Dockerfile  # относительно контекста (по умолчанию 'Dockerfile')
    args:                   # необязательные значения --build-arg
      VERSION: "1.0"
    tag: asc-local/my-app   # необязательно; по умолчанию 'asc-local/<app>:latest'
  • Только image → скачивается, как раньше.
  • Только image-build → образ собирается из Dockerfile пакета при установке (и пересобирается при upgrade / пересоздании контейнера из-за дрейфа настроек; кэш слоёв делает это дёшево). Контекст сборки упаковывается из репозитория пакета и не выходит за его пределы.
  • И image, и image-build → установщик предлагает выбор: интерактивно asc install <app> печатает два варианта и спрашивает; неинтерактивно (или чтобы пропустить вопрос) передайте --image (скачать готовый) или --build (собрать локально). Выбранный источник записывается в meta.json, чтобы последующее пересоздание или upgrade использовали тот же вариант без повторного вопроса.

⚠️ Сборка выполняется от демона (root). До появления пер-пользовательской политики контейнеров (DMN-043) сборка рассчитана на доверенные пакеты; базовый образ из FROM движок тянет анонимно (приватные базовые образы для локальной сборки — следующий инкремент).

Сборка всегда идёт через бэкенд BuildKit движка, а не через старый билдер — синтаксис Dockerfile вроде COPY --chmod/--chown требует BuildKit, иначе старый билдер падает с ошибкой «the --chmod option requires BuildKit». В терминале каждый шаг сборки отображается отдельным прогресс-баром в стиле docker build (как и полосы по слоям при docker pull), независимо от уровня логирования.

📐 JSON-схемы манифестов: asc.schema.json, asc.stack.schema.json и asc.settings.schema.json в репозитории registry.

Настройки приложения: asc.settings.yaml

Настройки приложения выносятся в отдельный файл, на который ссылается asc.yaml (settings: ./asc.settings.yaml). В нём описываются параметры: тип, лимиты, перечисления, значения по умолчанию — при установке пользователь заполняет их (UI платформы рисует форму, CLI задаёт вопросы; в silent-режиме берутся дефолты):

yaml
settings:
  - key: server_name
    type: string                # string | number | boolean | enum | secret
    title: "Server name"
    default: "My Server"
    required: true
    env: SERVER_NAME            # пробрасывается приложению этой env-переменной

  - key: max_players
    type: number
    default: 10
    limits: { min: 1, max: 200 }   # лимиты значений

  - key: difficulty
    type: enum                  # перечисление
    values: [peaceful, easy, normal, hard]
    default: normal

  - key: game_version
    type: enum                  # пресеты, но допускается и своё значение
    values: [public, latest_experimental]
    default: public
    allow_custom: true           # любая другая ветка/build id принимается как есть

  - key: rcon_password
    type: secret                # хранится как секрет, маскируется
    required: true

  - key: enable_backups
    type: boolean
    default: true

  - key: game_port
    type: ports                 # публикуемые порты контейнера (список)
    default: [27015]
    limits: { min: 1024, max: 65535 }
    env: CS2_PORT               # в env — через запятую; один порт — как есть
    protocol: both               # tcp (по умолчанию) | udp | both

  - key: game_data
    type: volumes               # тома приложения (список, формы — ниже)
    default: [/home/steam/cs2-dedicated]
  • Значения настроек сохраняются в /asc/apps/<id>/config/settings.json (0600 — файл может содержать секреты); при установке заполняются дефолтами, при обновлении новые ключи получают дефолты, а выбор пользователя не трогается.
  • Проброс в env: каждая настройка с env: VAR_NAME попадает в окружение приложения (секреты тоже — для этого их env: и нужен). Для Docker-приложений переменные записываются в env контейнера при создании. Списковые значения (ports, volumes) пробрасываются через запятую.
  • type: ports — публикуемые порты контейнера (порт хоста == порту контейнера). Настройка с env: держит приложение и Docker синхронными: сервер слушает ровно там, куда проброшен порт. protocol задаёт транспорт: tcp (по умолчанию), udp или both (один и тот же порт хоста==контейнера пробрасывается и на TCP, и на UDP).
  • type: volumes — тома приложения; каждая запись — одна из трёх форм:
    • /путь/в/контейнере — приватные данные приложения: в этот путь контейнера монтируется папка data приложения (/asc/apps/<id>/data). Папка создаётся world-writable (0777): образы работают от произвольных непривилегированных пользователей, а bind-монтирование сохраняет владельца хоста; каталог приложения выше остаётся закрытым. Если образ объявляет числовой USER uid:gid, папка дополнительно chown'ится под него (DMN-038) — непривилегированный процесс может сделать chown только пути, которым уже владеет, поэтому образу, который при первом старте сам меняет владельца своей папки данных (а не только пишет в неё), без этого падает с EPERM; именованный (steam) или голый числовой USER без группы оставляет только world-writable — его группа известна лишь /etc/passwd самого образа;
    • /путь/в/контейнере:хост — то же, но вместо data используется указанное после двоеточия: простое имя папки — внутри каталога приложения (/asc/apps/<id>/<папка>; repository, config и meta.json зарезервированы), абсолютный путь — путь хостовой машины, монтируется как есть (существующий каталог сохраняет владельца и права);
    • имя:/путь/в/контейнере[:ro|:rw]именованный том Docker, Engine создаёт его при первом использовании. Именованные тома — способ разделить данные между приложениями: одно приложение пишет в том, остальные монтируют его :ro (см. стек cs2 в asc-example-apps). Именованные тома не удаляются вместе с приложением.
  • Применение изменений: конфигурация контейнера фиксируется при создании, поэтому при следующем asc app start / asc app restart демон сравнивает желаемое состояние — env, публикуемые порты, тома, квоту, команду запуска — с фактическим состоянием контейнера и пересоздаёт контейнер при расхождении (или если контейнер пропал). Данные приложения живут в томах и переживают пересоздание. Если желаемое состояние вычислить не удалось (например, источник реестра удалён) — приложение всё равно стартует как есть, с предупреждением в логе: доступность важнее.
  • Изменение настроек — asc app settings <id>: интерактивный редактор в терминале. Сначала показываются категорииenvironments (настройки string/number/boolean/enum/secret), ports, volumes, quota, start_command — затем настройки выбранной категории: выбираете по номеру, вводите значение, оно валидируется по описанию (тип, limits, значения values у enum; секреты в списке маскируются; порты и тома вводятся списком через пробел). Также через UI платформы. После изменения — перезапуск приложения (asc app restart <id>).
  • allow_custom (только type: enum) — принимает любое значение вне списка values как свободный текст, вместо отклонения. Используйте для перечислений, где перечислены частые пресеты, но пользователя не должно ограничивать значение, которое автор не предусмотрел (ветка/build id игры, своё имя мира). Пронумерованный список в asc app settings по-прежнему показывает пресеты; ввод чего-то другого просто принимается.

📏 Квоты ресурсов (quota)

Секция quota: в asc.settings.yaml ограничивает ресурсы инстанса приложения (DMN-021):

yaml
quota:
  max_cpu: 2        # лимит CPU в ядрах (0.5, 2, …)
  max_ram: 1G       # лимит памяти: 512M, 2G, … (двоичные единицы, как docker -m)
  max_disk: 10G     # лимит места на диске
  • Значения нормализуются при установке/обновлении и записываются в meta.json; asc app info <id> показывает их (quota: cpu ≤ 2, ram ≤ 1.0 GiB, …).
  • Docker-приложения: применяются при создании контейнера через Engine API (NanoCpus, Memory).
  • native/process: записываются в meta.json; применение через cgroups — следующий инкремент.
  • max_disk записывается для всех рантаймов; дисковое ограничение per-runtime (Docker storage-opt / квоты ФС) — инкрементально.
  • Пользовательские переопределения (DMN-030): категория quota в asc app settings переопределяет отдельные поля поверх значений пакета ('-' сбрасывает поле обратно); переопределение хранится в settings.json и применяется через пересоздание контейнера при следующем перезапуске.

🚀 Команда запуска (start_command)

Команда запуска приложения настраивается в asc.settings.yaml. В строку можно подставлять environment-переменные пакета — синтаксис ${VAR}:

yaml
start_command: "steamcmd +force_install_dir /data +login anonymous +app_update ${STEAM_APP_ID} validate +quit"
  • Подстановка выполняется демоном при установке/обновлении из env приложения — значений настроек с ключами env:, включая дефолты. Неразрешённая переменная — ошибка установки с указанием имени переменной.
  • Docker-приложения: команда заменяет то, что запустил бы образ (entrypoint становится /bin/sh -c, поэтому аргументы и кавычки работают как в shell).
  • native-приложения: команда переопределяет runtime.start из asc.yaml.
  • Подстановка из итогового окружения приложения (env-уровни организации/ноды/приложения — 🌱 environments) и предпросмотр команды в UI — следующий инкремент; значения настроек уже доходят до приложения env-переменными (см. раздел настроек выше).
  • Пользовательское переопределение (DMN-030): категория start_command в asc app settings заменяет команду пакета для этого инстанса ('-' сбрасывает обратно); ссылки ${VAR} разрешаются из env настроек при применении.

🐳 Скрипты install/update: native или docker

Скрипты install и update пакета могут исполняться как нативно на хосте, так и в docker — управляется полем run_in в блоке scripts: манифеста:

yaml
scripts:
  install:
    run: ./scripts/install.sh
    run_in: native            # native | docker
  update:
    run: ./scripts/update.sh
    run_in: docker            # одноразовый контейнер
    image: debian:12          # образ для docker-исполнения (опционально)
  • native — скрипт исполняется на хосте от пользователя приложения.
  • docker — скрипт исполняется в одноразовом контейнере с примонтированным каталогом /asc/apps/<id>/ (изоляция зависимостей сборки от хоста).
  • По умолчанию run_in наследует type пакета: docker → docker, native/utility → native.

Механика установки: клонирование репозитория

Установка приложения = клонирование его репозитория:

  1. asc install <package> → демон клонирует репозиторий пакета в /asc/apps/<id>/repository/.
  2. Версии приложения = git-теги (GitHub tags), берутся из репозитория, а не из реестра (DMN-047): установка конкретной версии — asc install <package>@1.2.0 (checkout тега); asc install <package> без версии резолвит последний тег репозитория через git ls-remote (нет тегов → HEAD ветки по умолчанию); asc install <package>@ (пустой @) показывает теги и ветки репозитория для интерактивного выбора (DMN-048), либо неинтерактивно возвращает список доступных версий ошибкой. Обновление — asc app upgrade <name> (checkout нового тега). Поэтому индекс реестра не хранит поле версии — версии пакета это то, чем протегирован его репозиторий.
  3. Согласие с лицензией (DMN-028, DMN-032): если клонированный пакет содержит лицензию (LICENSE.md / LICENSE / LICENSE.txt), CLI показывает, откуда ставится пакет (источник реестра + репозиторий), выводит текст лицензии и спрашивает согласие — отказ прерывает установку, не оставляя следов. Лицензия сначала ищется в каталоге самого пакета (пакет монорепозитория может иметь свою лицензию), затем в корне репозитория. Неинтерактивный ввод принимает лицензию автоматически с печатным уведомлением; вызовы через API получают структурированную ошибку с источником, репозиторием и текстом лицензии (UI платформы отрисует свой диалог согласия). Для стека вопрос задаётся один раз на репозиторий. Пакеты без файла лицензии ставятся без вопроса.
  4. Пользовательское название и несколько инстансов (DMN-024, DMN-033): в терминале asc install спрашивает название приложения — Enter оставляет значение по умолчанию, любой другой ввод становится названием приложения. Неинтерактивно — флаг --name "My Server". Установка уже установленного пакета больше не завершается ошибкой: создаётся новый инстанс со следующим свободным id (<пакет>-2, <пакет>-3, …), который становится и его custom_name, если --name его не переопределяет. Название хранится в meta.json (custom_name), должно быть уникально среди приложений пользователя, переживает обновления, и все команды принимают его наравне с id. Суффиксированный инстанс запоминает пакет реестра, из которого он поставлен (meta.package), поэтому asc app upgrade продолжает резолвить его корректно.
  5. Дальше демон работает с локальной копией: читает asc.yaml/asc.settings.yaml, собирает/запускает по типу приложения.
  6. Для Docker-приложений контейнер создаётся через Engine API; отсутствующий на хосте образ скачивается автоматически из его реестра (runtime.image; имя без тега означает latest) — и при установке, и при обновлении.
  7. Прогресс-бары: в терминале клонирование репозитория (git clone --progress) и скачивание Docker-образа отображаются живыми полосами прогресса (в стиле docker pull/docker-compose pull — по одной полосе на слой образа) — включены по умолчанию, независимо от asc config debug. При неинтерактивном вызове (перенаправленный вывод, API демона) полос нет — те же события всегда доступны как debug-логи (asc config debug on).

Requirements при запуске (DMN-029): requirements манифеста (ram, disk, cpu) сравниваются с тем, что свободно на хосте в момент запуска приложения. При нехватке asc app start предупреждает с точными цифрами и — в терминале — спрашивает, запускать ли всё равно на свой страх и риск; неинтерактивные вызовы получают предупреждение в stderr и продолжают. Проверка — совет, а не запрет: ошибки чтения никогда не блокируют запуск.

Обновление (asc app upgrade <name>[@версия], синоним — asc upgrade): приложение должно быть остановлено; новый тег клонируется рядом с текущей копией (repository.new), манифест валидируется, и только затем каталоги меняются местами и рантайм пересоздаётся (для Docker — контейнер пересоздаётся с новым образом). Ошибка до подмены не трогает установленное приложение; ошибка пересоздания рантайма откатывает на предыдущую версию. Без явной версии берётся последний тег репозитория (DMN-047); репозиторий без тегов нельзя обновить без явной @версии.

Прямая установка из git-репозитория (asc install <url> [--branch <имя>|--tag <имя>], DMN-040): если спецификация — git-URL (https://, ssh:// или scp-подобный git@хост:путь), а не имя пакета, демон полностью пропускает реестр и клонирует репозиторий напрямую — тот же конвейер клонирование/манифест/провижининг, что и при установке из реестра, минус шаг резолвинга. asc.yaml должен лежать в корне репозитория (без пути монорепозитория — резолвить его неоткуда, нет записи реестра). --branch/--tag выбирают ref для checkout; без флагов клонируется HEAD ветки по умолчанию. Id приложения по умолчанию — имя самого репозитория (bar и для https://github.com/foo/bar.git, и для git@github.com:foo/bar); --name переопределяет его, как и при установке из реестра. Приватные репозитории используют ровно ту же авторизацию asc auth, что и ниже — установка по URL это установка из реестра с выброшенным шагом резолвинга. asc upgrade пока не резолвит приложения, установленные так (резолвить не из чего — нет записи реестра); повторный asc install с тем же URL создаёт новый инстанс, а не обновляет существующий.

Учётные данные (DMN-045/046): единый пользовательский стор хранит авторизацию и для приватных репозиториев (git clone), и для приватных реестров образов (pull через Engine), различая их полем type (repo | registry). Записи ключуются на хост или префикс (github.com/myorg, ghcr.io/myorg) и хранятся отдельно от списков источников, в JSON: /etc/asc/auth.json (root) и ~/.asc/auth.json (пользователь, рядом с остальным пер-пользовательским деревом DMN-041), оба файла 0600. Секреты не попадают ни в world-readable файлы, ни в argv git-процессов (argv виден всем пользователям через /proc).

json
{
  "credentials": [
    { "type": "repo",     "pattern": "github.com/myorg", "token": "ghp_xxx" },
    { "type": "registry", "pattern": "ghcr.io/myorg", "username": "me", "token": "ghp_yyy" },
    { "type": "repo",     "pattern": "github.com/myorg/secret-app", "app": "6f8a…uuid", "key": "/home/me/.ssh/id_ed25519" }
  ]
}
  • Типы: repo авторизует git clone — токен для https://-URL (через GIT_ASKPASS + переменную окружения процесса git) или SSH-ключ для git@/ssh://-URL (GIT_SSH_COMMAND c -i <ключ> -o IdentitiesOnly=yes). registry авторизует pull образа — токен вместе с username, уходит в Docker Engine заголовком X-Registry-Auth (с реестром связывается Engine, а не демон, поэтому TLS-стек на стороне демона не нужен). Registry-запись отвергает SSH-ключ и требует --username.
  • Привязка к приложению (app, DMN-044): учётные данные можно ограничить одним приложением по его uuid или id (--app) — токен обслуживает ровно нужное приложение и никакое другое. Привязанная запись невидима для остальных приложений и для «своего» приложения побеждает равную по длине непривязанную; без app учётные данные применяются ко всем приложениям, чей URL/образ совпал с префиксом. В остальном правило совпадения одинаково для обоих типов: выбирается самый длинный префикс на границе пути, записи пользователя приоритетнее системных.
  • Детекция: git всегда запускается с GIT_TERMINAL_PROMPT=0 и BatchMode=yes — клонирование приватного репозитория без настроенной авторизации не подвисает на запросе пароля, а падает с распознаваемой ошибкой (включая «Repository not found», который GitHub отдаёт для приватных репозиториев без доступа). Pull приватного образа показывает собственную ошибку авторизации Engine.
  • Интерактивная настройка: обнаружив приватный репозиторий, CLI в терминале спрашивает разрешение настроить авторизацию сразу: для https — ввод токена, для ssh — выбор из найденных приватных ключей ~/.ssh; выбор сохраняется, установка повторяется автоматически. Неинтерактивный вызов (API, скрипты) получает структурированную ошибку с подсказкой asc auth add ....
  • Миграция: старые TOML-файлы (/etc/asc/git-auth.toml, ~/.config/asc/git-auth.toml) до DMN-045 по-прежнему читаются, если JSON-стора ещё нет — их записи без type грузятся как repo — и мигрируют в auth.json при первой записи через asc auth, так что настроенная авторизация переживает обновление.
  • CLI: asc auth add <хост|префикс> [--type repo|registry] --token <токен> [--username <user>] [--app <uuid|id>] · asc auth add <хост> --ssh-key [путь] (без пути — интерактивный выбор ключа) · asc auth list (типы и методы без секретов) · asc auth remove <хост> [--type repo|registry].

Несколько приложений в одном репозитории: asc.stack.yaml

Правило корня: репозиторий-пакет может содержать сколько угодно asc.yaml в подкаталогах, но в его корне обязан лежать ровно один манифест — либо asc.yaml (одиночное приложение), либо asc.stack.yaml (стек), который соединяет все вложенные asc.yaml. Вложенные манифесты без корневого не индексируются.

Манифест-стек asc.stack.yaml перечисляет приложения и пути к их asc.yaml:

yaml
name: my-stack
version: 1.0.0
description: "..."
apps:
  - name: web
    path: ./web            # каталог с asc.yaml
  - name: worker
    path: ./worker
  - name: db
    path: ./db
    optional: true          # необязательный компонент стека
  • asc install my-stack — установка всего стека; asc install my-stack/web — только одного приложения из него.
  • Переименование стека при установке (DMN-034): asc install my-stack --name prod — это префикс, применяемый ко всем устанавливаемым приложениям — prod-web, prod-worker, prod-db — так как у стека нет собственной сущности, только приложения-участники. asc install my-stack/web --name prod-web называет только запрошенное приложение, как при установке одиночного приложения.
  • Стек может объявлять зависимости между приложениями (depends_on — порядок запуска), компоненты могут быть optional. Environment-переменные живут в asc.settings.yaml каждого приложения.
  • Реестры и магазин платформы индексируют как одиночные asc.yaml, так и стеки asc.stack.yaml.
  • Примеры — в репозитории asc-example-apps.

Механика установки стека: репозиторий клонируется один раз для чтения asc.stack.yaml, затем каждое выбранное приложение устанавливается как обычное — со своим клоном репозитория, каталогом /asc/apps/<id>/ и meta.json:

  • id приложения — это name из его собственного asc.yaml (в примере выше приложение web стека может называться my-stack-web); происхождение записывается в meta.json как package: "my-stack/web" — по нему asc app upgrade заново резолвит пакет.
  • Порядок: зависимости (depends_on) устанавливаются первыми; циклы отклоняются при валидации. asc install my-stack ставит все компоненты кроме optional; asc install my-stack/db ставит запрошенный компонент (в том числе optional) и его зависимости.
  • Повторная установка: запрошенное приложение (то, что указано явно, а не подтянутая зависимость), если оно уже установлено, становится новым инстансом (DMN-033) вместо пропуска; уже установленная зависимость по-прежнему переиспользуется, а не дублируется. Каждое приложение ставится атомарно (ошибка убирает только его каталог, ранее установленные компоненты остаются).
  • Согласие с лицензией запрашивается один раз на репозиторий (один репозиторий = одна лицензия), а не на каждое приложение стека.

Реестры

  • Формат реестра (repo registry) — иерархия JSON-файлов: корневой индекс registry.json → файлы категорий categories/<тема>.json (databases, ai, bots, game-servers, system-utilities, web…) → опциональные подкатегории (children). Пакеты бывают двух типов: app (asc.yaml) и stack (asc.stack.yaml). Схемы валидации — в registry/schema/. Описания — на английском.
  • Дерево источников: sourcelist демона → из всех реестров строится дерево (по ссылкам index/children корневого индекса), затем объединённый список приложений (для каждого пользователя); в результатах поиска конфликт имён решает приоритет источника.
  • Конфликт имён при установке: если пакет предоставляют несколько источников, asc install в терминале выводит список кандидатов (имя источника + репозиторий) и спрашивает, какой использовать (выбор номера); неинтерактивные вызовы получают ошибку с тем же списком — реестр указывается явно: asc install <пакет> --source <имя> (API: поле source в InstallAppRequest). asc app upgrade предпочитает источник, из которого приложение было установлено.
  • Типы источников: file:// (локальный каталог) и https:// (реестр, GitHub raw).
  • Устойчивость загрузки (DMN-036): каждый файл индекса реестра (registry.json, файлы категорий) — отдельный вызов curl без переиспользования соединения между ними, то есть весь asc update/asc search — это короткая серия из нескольких мелких HTTPS-запросов к одному хосту. Раньше зависшее соединение на любом из них (throttling CDN, временный сетевой сбой) вешало всю команду на срок до 5 минут без единого вывода. Теперь запросы к реестру используют короткий таймаут на запрос (20с) и пару ретраев на транзиентные ошибки — вместо щедрого бюджета в 300с, зарезервированного для больших загрузок (релизные файлы asc-updater).
  • Прогресс asc update (DMN-037): в терминале на каждый файл индекса выводится своя строка прогресса, в стиле docker pull/git clone — спиннер, пока запрос выполняется, и заморозка на размере в байтах при успехе или на тексте ошибки при провале. Поскольку реестр забирается по одному мелкому файлу за раз, это превращает застрявшую загрузку в видимо застрявший спиннер вместо молчаливого ожидания.
  • Source list по пользователям: два уровня списков —
    • системный /etc/asc/sources.toml — правит root (sudo asc source add|remove), источники видны всем пользователям сервера;
    • пользовательский ~/.config/asc/sources.toml — каждый пользователь ведёт свой список (asc source add|remove без sudo), он дополняет системный.
    • Эффективный список = системные источники (приоритетнее) + свои; затенять и удалять системные источники пользователь не может (asc source list показывает происхождение каждого источника). Кэш индексов у root — в data_dir, у пользователя — в ~/.cache/asc/.
  • Политика установки ([policy] в /etc/asc/config.toml, правит root): user_install = "all" (по умолчанию — пользователи ставят любые пакеты: Docker, нативные, утилиты) или user_install = "docker" (пользователям — только Docker-приложения; нативные и утилиты ставит только root). Применяется при asc install; на root не действует.
  • Кэш индексов с TTL + asc update для принудительного обновления.
  • CLI: asc install|remove|upgrade <pkg> (или asc install <git-url> [--branch|--tag]), asc search <query>, asc source add|remove|list, asc update.

🔗 Связанные задачи

DMN-003, DMN-018, DMN-038, DMN-040, DMN-045, DMN-046, DMN-047, DMN-048, REG-001, REG-002, BE-002, BE-003 в ROADMAP.md; GRW-011 в ROADMAP-GROWTH.md.

Распространяется по лицензии MIT.