Metadata-Version: 2.5
Name: s-installerkit
Version: 0.1.0
Summary: Универсальный установщик/self-update CLI-продуктов: uv-bootstrap, self-update (PyPI JSON API), генератор ASCII install-скриптов. Тонкий слой над s-skillkit.
Author: Dmitry
License: MIT
Requires-Python: >=3.11
Requires-Dist: s-clikit
Requires-Dist: s-librarykit
Requires-Dist: s-skillgate
Requires-Dist: s-skillkit
Provides-Extra: dev
Requires-Dist: pytest>=8.3; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Description-Content-Type: text/markdown

# s-installerkit

> Универсальный installer-kit: uv-bootstrap, self-update (модель skillery), генератор install-скриптов, прямая регистрация навыка + публикация в skillery. Тонкий слой над s-skillkit+clikit+librarykit.

## Что это

Тонкий верхний слой над **s-skillkit**: даёт CLI-продукту установку и
самообновление «под ключ», НЕ дублируя механику skillkit (`ensure_uv`,
`bootstrap_skill`, manifest, линковка навыка — импортируются из него).

Dist-имя — `s-installerkit`; имя для импорта — `installerkit`.

```bash
uv add s-installerkit
```

## Публичный API

```python
from installerkit import (
    configure, InstallerConfig,   # единая конфигурация (прокси на skillkit + dist-имя)
    make_self_update_command,     # фабрика clikit-команды `self-update` (PyPI)
    render_install_script,        # генератор ASCII bootstrap-скриптов (sh/ps1)
    ensure_uv, run_doctor,        # окружение продукта: uv + scripts/self_check.py
    install_direct,               # прямая установка навыка (линковка + bootstrap)
    publish_to_store,             # публикация в skillery-store (с секрет-гейтом)
    run_publish_gate,             # секрет-скан + денилист (gitleaks + s-skillgate)
    build_publish_payload,        # payload POST /skills по манифесту навыка
)
```

Кит ставит и CLI `installer`:

```bash
installer install <путь-к-навыку> [--scope global|project] [--all-agents]
installer ensure-uv
installer doctor <каталог-продукта> [--no-self-check]
installer publish <путь-к-навыку> --tag v1.2.3 [--dry-run] [--force]
```

- **`configure(InstallerConfig(app_name, dist_name, ...))`** — идемпотентно
  проецирует брендинг/каталоги на `skillkit.configure` и запоминает `dist_name`
  для self-update. Каталоги — ленивыми провайдерами (кит env сам не читает).
- **`make_self_update_command(dist_name)`** → clikit-команда: сверяет версию с
  PyPI JSON API (`pypi.org/pypi/<dist>/json`), обновляет авто-детектом менеджера
  (`uv tool` / `pipx` / `pip`), `--check` — только показать. На Windows апгрейд —
  detached-процессом (launcher `.exe` залочен), применяется со след. запуска.
  Регистрация: `app.command(name="self-update")(make_self_update_command("s-myctl"))`.
- **`render_install_script("sh"|"ps1", dist_name, cli_name)`** → строка
  ASCII-only bootstrap-скрипта (ставит `uv` при отсутствии → `uv tool install
  --upgrade <dist>`). ASCII гарантируется (иначе `curl|sh` / `irm|iex` ломаются).
- **`install_direct(path, scope=..., all_agents=...)`** — прямой путь установки
  (без хаба): материализует навык в центральный стор и линкует
  junction/symlink'ом в `~/.claude/skills/<slug>` (или в project-scope), гоняет
  `skillkit.bootstrap_skill` (ensure_uv → deps → бинари → self_check), для
  `kind = "tooling"` регистрирует MCP-серверы у агента. Возвращает
  graceful-отчёт `{ok, slug, agents, bootstrap, mcp, errors}` и НЕ бросает;
  битая ссылка в scope детектится (`link_status = "broken"`).
- **`ensure_uv()`** — идемпотентно найти/поставить `uv`:
  `{"uv": <путь|None>, "status": "found" | "installed" | "missing"}`. `found` —
  uv уже был и ничего не делалось.
- **`run_doctor(product_dir)`** — сводная проверка окружения продукта: uv, `.venv`,
  наличие и прогон `scripts/self_check.py`. Возвращает
  `{ok, uv, venv, self_check_script, self_check, problems}`, не бросает;
  `installer doctor` печатает отчёт и выходит с кодом 1, если `ok=False`.
- **`publish_to_store(path, tag=..., client=...)`** — публикация навыка:
  сначала ГЕЙТ (`run_publish_gate`: gitleaks, если бинарь есть в PATH, плюс
  `s-skillgate` — regex-секреты и денилист внутренней инфы), затем сборка
  манифеста (`kind`/`cli`/`mcp`/`runtime_dependencies` — без них хаб не
  поставит сам инструмент), затем отправка через `client.publish_skill(payload)`
  (sync и async-клиенты оба). Блокирующие находки → `CliError`
  (`publish_gate_failed`, exit 1) ДО сборки и сети; `force=True` — сознательный
  обход. `dry_run=True` возвращает payload, не отправляя (секретные поля в нём
  замаскированы). Транспорта кит не несёт — клиент инъектирует потребитель;
  команда `installer publish` без клиента умеет `--dry-run`.
- Команда `installer publish` закрыта правом **`skill.publish`**: если задан
  env `INSTALLER_PERMISSIONS`, она регистрируется только при наличии права.

## Контракт `scripts/self_check.py` (самопроверка продукта)

Финальный gate установки: его гоняет и `skillkit.bootstrap_skill`, и
`installer doctor`. Продукт обязан положить скрипт по пути
`scripts/self_check.py` в своём корне.

- **Вход**: аргументов нет, stdin не читается (запуск неинтерактивный).
  Рабочий каталог — корень продукта; интерпретатор выбирается в порядке
  `<продукт>/.venv/bin/python` → `uv run python` → текущий `sys.executable`.
- **Выход**: человекочитаемый отчёт в stdout/stderr (оба потока попадают в
  `self_check.output`). Формат свободный; пишите, ЧТО именно не так.
- **Коды возврата**: `0` — окружение исправно; **любой ненулевой** — нет
  (различать 1/2/3 инсталлятор не станет, коды нужны только вашим тестам).
- **Ограничения**: без сети и без секретов в выводе; таймаут 300 с (skillkit
  убьёт зависший скрипт). Скрипта нет ⇒ это САМО ПО СЕБЕ проблема:
  подтвердить окружение нечем, `doctor` вернёт `ok=False`.

```python
# scripts/self_check.py
import shutil, sys

problems = [] if shutil.which("uv") else ["нет uv в PATH"]
print("
".join(problems) or "окружение исправно")
sys.exit(1 if problems else 0)
```

## Разработка

```bash
uv sync --extra dev
uv run --extra dev pytest -q
uv run --extra dev ruff check installerkit tests
```

## Статус

- **Type**: `kit`
- **Status**: `experiment`
- **Priority**: P1
- **Slug**: `s-installerkit`
- **Prefix**: `si`
- **Tags**: —
- Создан: 2026-07-17

## Atlas

Карточка проекта в Atlas-БД (Atlas):

```sh
atlas projects get s-installerkit
```

Физический layout:

- Storage: `_storage/s-installerkit/`
- Junction: `Products\s-installerkit` → `_storage/s-installerkit`

## TODO (placeholder)

- [ ] Заполнить README реальным контентом проекта.
- [ ] Подключить GitLab-репозиторий (если ещё нет): `atlas projects git init s-installerkit`.
