s-installerkit 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- s_installerkit-0.1.0/.gitignore +47 -0
- s_installerkit-0.1.0/AGENTS.md +45 -0
- s_installerkit-0.1.0/PKG-INFO +156 -0
- s_installerkit-0.1.0/README.md +140 -0
- s_installerkit-0.1.0/docs/adr/0000-template.md +20 -0
- s_installerkit-0.1.0/docs/adr/README.md +30 -0
- s_installerkit-0.1.0/installerkit/__init__.py +61 -0
- s_installerkit-0.1.0/installerkit/_branding.py +30 -0
- s_installerkit-0.1.0/installerkit/cli.py +246 -0
- s_installerkit-0.1.0/installerkit/config.py +101 -0
- s_installerkit-0.1.0/installerkit/direct.py +285 -0
- s_installerkit-0.1.0/installerkit/doctor.py +88 -0
- s_installerkit-0.1.0/installerkit/install_scripts.py +108 -0
- s_installerkit-0.1.0/installerkit/publish.py +327 -0
- s_installerkit-0.1.0/installerkit/self_update.py +225 -0
- s_installerkit-0.1.0/installerkit/tokens.py +170 -0
- s_installerkit-0.1.0/pyproject.toml +68 -0
- s_installerkit-0.1.0/tests/test_direct.py +145 -0
- s_installerkit-0.1.0/tests/test_doctor.py +111 -0
- s_installerkit-0.1.0/tests/test_publish.py +163 -0
- s_installerkit-0.1.0/tests/test_smoke.py +104 -0
- s_installerkit-0.1.0/tests/test_tokens.py +142 -0
- s_installerkit-0.1.0/uv.lock +836 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# === atlas universal gitignore ===
|
|
2
|
+
|
|
3
|
+
# OS / IDE
|
|
4
|
+
.DS_Store
|
|
5
|
+
Thumbs.db
|
|
6
|
+
.vscode/
|
|
7
|
+
.idea/
|
|
8
|
+
*.swp
|
|
9
|
+
*.swo
|
|
10
|
+
|
|
11
|
+
# Sensitive
|
|
12
|
+
.env
|
|
13
|
+
.env.local
|
|
14
|
+
*.key
|
|
15
|
+
*.pem
|
|
16
|
+
secrets/
|
|
17
|
+
private/
|
|
18
|
+
|
|
19
|
+
# Python
|
|
20
|
+
__pycache__/
|
|
21
|
+
*.py[cod]
|
|
22
|
+
.venv/
|
|
23
|
+
venv/
|
|
24
|
+
.pytest_cache/
|
|
25
|
+
.ruff_cache/
|
|
26
|
+
*.egg-info/
|
|
27
|
+
|
|
28
|
+
# Node / JS
|
|
29
|
+
node_modules/
|
|
30
|
+
.next/
|
|
31
|
+
dist/
|
|
32
|
+
build/
|
|
33
|
+
|
|
34
|
+
# Temporary / large
|
|
35
|
+
*.log
|
|
36
|
+
*.tmp
|
|
37
|
+
nul
|
|
38
|
+
NUL
|
|
39
|
+
*.zip
|
|
40
|
+
*.rar
|
|
41
|
+
*.7z
|
|
42
|
+
|
|
43
|
+
# Media (selectively unignore via !path/*.ext if needed for fixtures)
|
|
44
|
+
*.mp4
|
|
45
|
+
*.mov
|
|
46
|
+
*.avi
|
|
47
|
+
*.mkv
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# AGENTS.md — s-installerkit
|
|
2
|
+
|
|
3
|
+
> Контекст для AI-ассистентов (Claude Code, ChatGPT, Cursor и т.п.), работающих
|
|
4
|
+
> над этим проектом.
|
|
5
|
+
|
|
6
|
+
## Что это
|
|
7
|
+
|
|
8
|
+
Универсальный installer-kit: uv-bootstrap, self-update (модель skillery), генератор install-скриптов, прямая регистрация навыка + публикация в skillery. Тонкий слой над s-skillkit+clikit+librarykit.
|
|
9
|
+
|
|
10
|
+
## Atlas
|
|
11
|
+
|
|
12
|
+
Проект зарегистрирован в Atlas-БД (Atlas). Карточка:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
atlas projects get s-installerkit
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Любые изменения метаданных (приоритет, статус, теги) — через atlas CLI:
|
|
19
|
+
|
|
20
|
+
- `atlas projects update s-installerkit --priority P0` — поменять приоритет
|
|
21
|
+
- `atlas add-tags s-installerkit -t domain:<slug>` — добавить тег
|
|
22
|
+
- `atlas projects move s-installerkit --to-type <type>` — конвертировать тип
|
|
23
|
+
|
|
24
|
+
## Тип / Статус (на момент создания)
|
|
25
|
+
|
|
26
|
+
- type=`kit`, status=`experiment`, priority=`P1`
|
|
27
|
+
|
|
28
|
+
## Правила работы
|
|
29
|
+
|
|
30
|
+
- Все исходные тексты, документы, код проекта — в этом репо.
|
|
31
|
+
- Чувствительные данные (`.env`, токены, ключи) — игнорируются `.gitignore`.
|
|
32
|
+
- AI-ассистенту разрешено: читать, генерировать, редактировать в этом репо.
|
|
33
|
+
|
|
34
|
+
## Канонические команды
|
|
35
|
+
|
|
36
|
+
- `atlas projects get s-installerkit` — карточка проекта
|
|
37
|
+
- `atlas task list --project s-installerkit` — задачи проекта (когда W7
|
|
38
|
+
волна будет реализована)
|
|
39
|
+
|
|
40
|
+
<!-- atlas:usage:start -->
|
|
41
|
+
## Управление проектом — через Atlas
|
|
42
|
+
|
|
43
|
+
Этот проект ведётся в Atlas (личная PM-система портфеля). Для задач/проектов/эпиков/бэкапов
|
|
44
|
+
используй CLI `atlas` и вызывай навык `atlas` — вся логика и роутинг внутри навыка.
|
|
45
|
+
<!-- atlas:usage:end -->
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: s-installerkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Универсальный установщик/self-update CLI-продуктов: uv-bootstrap, self-update (PyPI JSON API), генератор ASCII install-скриптов. Тонкий слой над s-skillkit.
|
|
5
|
+
Author: Dmitry
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Requires-Dist: s-clikit
|
|
9
|
+
Requires-Dist: s-librarykit
|
|
10
|
+
Requires-Dist: s-skillgate
|
|
11
|
+
Requires-Dist: s-skillkit
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: pytest>=8.3; extra == 'dev'
|
|
14
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# s-installerkit
|
|
18
|
+
|
|
19
|
+
> Универсальный installer-kit: uv-bootstrap, self-update (модель skillery), генератор install-скриптов, прямая регистрация навыка + публикация в skillery. Тонкий слой над s-skillkit+clikit+librarykit.
|
|
20
|
+
|
|
21
|
+
## Что это
|
|
22
|
+
|
|
23
|
+
Тонкий верхний слой над **s-skillkit**: даёт CLI-продукту установку и
|
|
24
|
+
самообновление «под ключ», НЕ дублируя механику skillkit (`ensure_uv`,
|
|
25
|
+
`bootstrap_skill`, manifest, линковка навыка — импортируются из него).
|
|
26
|
+
|
|
27
|
+
Dist-имя — `s-installerkit`; имя для импорта — `installerkit`.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv add s-installerkit
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Публичный API
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from installerkit import (
|
|
37
|
+
configure, InstallerConfig, # единая конфигурация (прокси на skillkit + dist-имя)
|
|
38
|
+
make_self_update_command, # фабрика clikit-команды `self-update` (PyPI)
|
|
39
|
+
render_install_script, # генератор ASCII bootstrap-скриптов (sh/ps1)
|
|
40
|
+
ensure_uv, run_doctor, # окружение продукта: uv + scripts/self_check.py
|
|
41
|
+
install_direct, # прямая установка навыка (линковка + bootstrap)
|
|
42
|
+
publish_to_store, # публикация в skillery-store (с секрет-гейтом)
|
|
43
|
+
run_publish_gate, # секрет-скан + денилист (gitleaks + s-skillgate)
|
|
44
|
+
build_publish_payload, # payload POST /skills по манифесту навыка
|
|
45
|
+
)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Кит ставит и CLI `installer`:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
installer install <путь-к-навыку> [--scope global|project] [--all-agents]
|
|
52
|
+
installer ensure-uv
|
|
53
|
+
installer doctor <каталог-продукта> [--no-self-check]
|
|
54
|
+
installer publish <путь-к-навыку> --tag v1.2.3 [--dry-run] [--force]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- **`configure(InstallerConfig(app_name, dist_name, ...))`** — идемпотентно
|
|
58
|
+
проецирует брендинг/каталоги на `skillkit.configure` и запоминает `dist_name`
|
|
59
|
+
для self-update. Каталоги — ленивыми провайдерами (кит env сам не читает).
|
|
60
|
+
- **`make_self_update_command(dist_name)`** → clikit-команда: сверяет версию с
|
|
61
|
+
PyPI JSON API (`pypi.org/pypi/<dist>/json`), обновляет авто-детектом менеджера
|
|
62
|
+
(`uv tool` / `pipx` / `pip`), `--check` — только показать. На Windows апгрейд —
|
|
63
|
+
detached-процессом (launcher `.exe` залочен), применяется со след. запуска.
|
|
64
|
+
Регистрация: `app.command(name="self-update")(make_self_update_command("s-myctl"))`.
|
|
65
|
+
- **`render_install_script("sh"|"ps1", dist_name, cli_name)`** → строка
|
|
66
|
+
ASCII-only bootstrap-скрипта (ставит `uv` при отсутствии → `uv tool install
|
|
67
|
+
--upgrade <dist>`). ASCII гарантируется (иначе `curl|sh` / `irm|iex` ломаются).
|
|
68
|
+
- **`install_direct(path, scope=..., all_agents=...)`** — прямой путь установки
|
|
69
|
+
(без хаба): материализует навык в центральный стор и линкует
|
|
70
|
+
junction/symlink'ом в `~/.claude/skills/<slug>` (или в project-scope), гоняет
|
|
71
|
+
`skillkit.bootstrap_skill` (ensure_uv → deps → бинари → self_check), для
|
|
72
|
+
`kind = "tooling"` регистрирует MCP-серверы у агента. Возвращает
|
|
73
|
+
graceful-отчёт `{ok, slug, agents, bootstrap, mcp, errors}` и НЕ бросает;
|
|
74
|
+
битая ссылка в scope детектится (`link_status = "broken"`).
|
|
75
|
+
- **`ensure_uv()`** — идемпотентно найти/поставить `uv`:
|
|
76
|
+
`{"uv": <путь|None>, "status": "found" | "installed" | "missing"}`. `found` —
|
|
77
|
+
uv уже был и ничего не делалось.
|
|
78
|
+
- **`run_doctor(product_dir)`** — сводная проверка окружения продукта: uv, `.venv`,
|
|
79
|
+
наличие и прогон `scripts/self_check.py`. Возвращает
|
|
80
|
+
`{ok, uv, venv, self_check_script, self_check, problems}`, не бросает;
|
|
81
|
+
`installer doctor` печатает отчёт и выходит с кодом 1, если `ok=False`.
|
|
82
|
+
- **`publish_to_store(path, tag=..., client=...)`** — публикация навыка:
|
|
83
|
+
сначала ГЕЙТ (`run_publish_gate`: gitleaks, если бинарь есть в PATH, плюс
|
|
84
|
+
`s-skillgate` — regex-секреты и денилист внутренней инфы), затем сборка
|
|
85
|
+
манифеста (`kind`/`cli`/`mcp`/`runtime_dependencies` — без них хаб не
|
|
86
|
+
поставит сам инструмент), затем отправка через `client.publish_skill(payload)`
|
|
87
|
+
(sync и async-клиенты оба). Блокирующие находки → `CliError`
|
|
88
|
+
(`publish_gate_failed`, exit 1) ДО сборки и сети; `force=True` — сознательный
|
|
89
|
+
обход. `dry_run=True` возвращает payload, не отправляя (секретные поля в нём
|
|
90
|
+
замаскированы). Транспорта кит не несёт — клиент инъектирует потребитель;
|
|
91
|
+
команда `installer publish` без клиента умеет `--dry-run`.
|
|
92
|
+
- Команда `installer publish` закрыта правом **`skill.publish`**: если задан
|
|
93
|
+
env `INSTALLER_PERMISSIONS`, она регистрируется только при наличии права.
|
|
94
|
+
|
|
95
|
+
## Контракт `scripts/self_check.py` (самопроверка продукта)
|
|
96
|
+
|
|
97
|
+
Финальный gate установки: его гоняет и `skillkit.bootstrap_skill`, и
|
|
98
|
+
`installer doctor`. Продукт обязан положить скрипт по пути
|
|
99
|
+
`scripts/self_check.py` в своём корне.
|
|
100
|
+
|
|
101
|
+
- **Вход**: аргументов нет, stdin не читается (запуск неинтерактивный).
|
|
102
|
+
Рабочий каталог — корень продукта; интерпретатор выбирается в порядке
|
|
103
|
+
`<продукт>/.venv/bin/python` → `uv run python` → текущий `sys.executable`.
|
|
104
|
+
- **Выход**: человекочитаемый отчёт в stdout/stderr (оба потока попадают в
|
|
105
|
+
`self_check.output`). Формат свободный; пишите, ЧТО именно не так.
|
|
106
|
+
- **Коды возврата**: `0` — окружение исправно; **любой ненулевой** — нет
|
|
107
|
+
(различать 1/2/3 инсталлятор не станет, коды нужны только вашим тестам).
|
|
108
|
+
- **Ограничения**: без сети и без секретов в выводе; таймаут 300 с (skillkit
|
|
109
|
+
убьёт зависший скрипт). Скрипта нет ⇒ это САМО ПО СЕБЕ проблема:
|
|
110
|
+
подтвердить окружение нечем, `doctor` вернёт `ok=False`.
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
# scripts/self_check.py
|
|
114
|
+
import shutil, sys
|
|
115
|
+
|
|
116
|
+
problems = [] if shutil.which("uv") else ["нет uv в PATH"]
|
|
117
|
+
print("
|
|
118
|
+
".join(problems) or "окружение исправно")
|
|
119
|
+
sys.exit(1 if problems else 0)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Разработка
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
uv sync --extra dev
|
|
126
|
+
uv run --extra dev pytest -q
|
|
127
|
+
uv run --extra dev ruff check installerkit tests
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Статус
|
|
131
|
+
|
|
132
|
+
- **Type**: `kit`
|
|
133
|
+
- **Status**: `experiment`
|
|
134
|
+
- **Priority**: P1
|
|
135
|
+
- **Slug**: `s-installerkit`
|
|
136
|
+
- **Prefix**: `si`
|
|
137
|
+
- **Tags**: —
|
|
138
|
+
- Создан: 2026-07-17
|
|
139
|
+
|
|
140
|
+
## Atlas
|
|
141
|
+
|
|
142
|
+
Карточка проекта в Atlas-БД (Atlas):
|
|
143
|
+
|
|
144
|
+
```sh
|
|
145
|
+
atlas projects get s-installerkit
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Физический layout:
|
|
149
|
+
|
|
150
|
+
- Storage: `_storage/s-installerkit/`
|
|
151
|
+
- Junction: `Products\s-installerkit` → `_storage/s-installerkit`
|
|
152
|
+
|
|
153
|
+
## TODO (placeholder)
|
|
154
|
+
|
|
155
|
+
- [ ] Заполнить README реальным контентом проекта.
|
|
156
|
+
- [ ] Подключить GitLab-репозиторий (если ещё нет): `atlas projects git init s-installerkit`.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# s-installerkit
|
|
2
|
+
|
|
3
|
+
> Универсальный installer-kit: uv-bootstrap, self-update (модель skillery), генератор install-скриптов, прямая регистрация навыка + публикация в skillery. Тонкий слой над s-skillkit+clikit+librarykit.
|
|
4
|
+
|
|
5
|
+
## Что это
|
|
6
|
+
|
|
7
|
+
Тонкий верхний слой над **s-skillkit**: даёт CLI-продукту установку и
|
|
8
|
+
самообновление «под ключ», НЕ дублируя механику skillkit (`ensure_uv`,
|
|
9
|
+
`bootstrap_skill`, manifest, линковка навыка — импортируются из него).
|
|
10
|
+
|
|
11
|
+
Dist-имя — `s-installerkit`; имя для импорта — `installerkit`.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv add s-installerkit
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Публичный API
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from installerkit import (
|
|
21
|
+
configure, InstallerConfig, # единая конфигурация (прокси на skillkit + dist-имя)
|
|
22
|
+
make_self_update_command, # фабрика clikit-команды `self-update` (PyPI)
|
|
23
|
+
render_install_script, # генератор ASCII bootstrap-скриптов (sh/ps1)
|
|
24
|
+
ensure_uv, run_doctor, # окружение продукта: uv + scripts/self_check.py
|
|
25
|
+
install_direct, # прямая установка навыка (линковка + bootstrap)
|
|
26
|
+
publish_to_store, # публикация в skillery-store (с секрет-гейтом)
|
|
27
|
+
run_publish_gate, # секрет-скан + денилист (gitleaks + s-skillgate)
|
|
28
|
+
build_publish_payload, # payload POST /skills по манифесту навыка
|
|
29
|
+
)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Кит ставит и CLI `installer`:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
installer install <путь-к-навыку> [--scope global|project] [--all-agents]
|
|
36
|
+
installer ensure-uv
|
|
37
|
+
installer doctor <каталог-продукта> [--no-self-check]
|
|
38
|
+
installer publish <путь-к-навыку> --tag v1.2.3 [--dry-run] [--force]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- **`configure(InstallerConfig(app_name, dist_name, ...))`** — идемпотентно
|
|
42
|
+
проецирует брендинг/каталоги на `skillkit.configure` и запоминает `dist_name`
|
|
43
|
+
для self-update. Каталоги — ленивыми провайдерами (кит env сам не читает).
|
|
44
|
+
- **`make_self_update_command(dist_name)`** → clikit-команда: сверяет версию с
|
|
45
|
+
PyPI JSON API (`pypi.org/pypi/<dist>/json`), обновляет авто-детектом менеджера
|
|
46
|
+
(`uv tool` / `pipx` / `pip`), `--check` — только показать. На Windows апгрейд —
|
|
47
|
+
detached-процессом (launcher `.exe` залочен), применяется со след. запуска.
|
|
48
|
+
Регистрация: `app.command(name="self-update")(make_self_update_command("s-myctl"))`.
|
|
49
|
+
- **`render_install_script("sh"|"ps1", dist_name, cli_name)`** → строка
|
|
50
|
+
ASCII-only bootstrap-скрипта (ставит `uv` при отсутствии → `uv tool install
|
|
51
|
+
--upgrade <dist>`). ASCII гарантируется (иначе `curl|sh` / `irm|iex` ломаются).
|
|
52
|
+
- **`install_direct(path, scope=..., all_agents=...)`** — прямой путь установки
|
|
53
|
+
(без хаба): материализует навык в центральный стор и линкует
|
|
54
|
+
junction/symlink'ом в `~/.claude/skills/<slug>` (или в project-scope), гоняет
|
|
55
|
+
`skillkit.bootstrap_skill` (ensure_uv → deps → бинари → self_check), для
|
|
56
|
+
`kind = "tooling"` регистрирует MCP-серверы у агента. Возвращает
|
|
57
|
+
graceful-отчёт `{ok, slug, agents, bootstrap, mcp, errors}` и НЕ бросает;
|
|
58
|
+
битая ссылка в scope детектится (`link_status = "broken"`).
|
|
59
|
+
- **`ensure_uv()`** — идемпотентно найти/поставить `uv`:
|
|
60
|
+
`{"uv": <путь|None>, "status": "found" | "installed" | "missing"}`. `found` —
|
|
61
|
+
uv уже был и ничего не делалось.
|
|
62
|
+
- **`run_doctor(product_dir)`** — сводная проверка окружения продукта: uv, `.venv`,
|
|
63
|
+
наличие и прогон `scripts/self_check.py`. Возвращает
|
|
64
|
+
`{ok, uv, venv, self_check_script, self_check, problems}`, не бросает;
|
|
65
|
+
`installer doctor` печатает отчёт и выходит с кодом 1, если `ok=False`.
|
|
66
|
+
- **`publish_to_store(path, tag=..., client=...)`** — публикация навыка:
|
|
67
|
+
сначала ГЕЙТ (`run_publish_gate`: gitleaks, если бинарь есть в PATH, плюс
|
|
68
|
+
`s-skillgate` — regex-секреты и денилист внутренней инфы), затем сборка
|
|
69
|
+
манифеста (`kind`/`cli`/`mcp`/`runtime_dependencies` — без них хаб не
|
|
70
|
+
поставит сам инструмент), затем отправка через `client.publish_skill(payload)`
|
|
71
|
+
(sync и async-клиенты оба). Блокирующие находки → `CliError`
|
|
72
|
+
(`publish_gate_failed`, exit 1) ДО сборки и сети; `force=True` — сознательный
|
|
73
|
+
обход. `dry_run=True` возвращает payload, не отправляя (секретные поля в нём
|
|
74
|
+
замаскированы). Транспорта кит не несёт — клиент инъектирует потребитель;
|
|
75
|
+
команда `installer publish` без клиента умеет `--dry-run`.
|
|
76
|
+
- Команда `installer publish` закрыта правом **`skill.publish`**: если задан
|
|
77
|
+
env `INSTALLER_PERMISSIONS`, она регистрируется только при наличии права.
|
|
78
|
+
|
|
79
|
+
## Контракт `scripts/self_check.py` (самопроверка продукта)
|
|
80
|
+
|
|
81
|
+
Финальный gate установки: его гоняет и `skillkit.bootstrap_skill`, и
|
|
82
|
+
`installer doctor`. Продукт обязан положить скрипт по пути
|
|
83
|
+
`scripts/self_check.py` в своём корне.
|
|
84
|
+
|
|
85
|
+
- **Вход**: аргументов нет, stdin не читается (запуск неинтерактивный).
|
|
86
|
+
Рабочий каталог — корень продукта; интерпретатор выбирается в порядке
|
|
87
|
+
`<продукт>/.venv/bin/python` → `uv run python` → текущий `sys.executable`.
|
|
88
|
+
- **Выход**: человекочитаемый отчёт в stdout/stderr (оба потока попадают в
|
|
89
|
+
`self_check.output`). Формат свободный; пишите, ЧТО именно не так.
|
|
90
|
+
- **Коды возврата**: `0` — окружение исправно; **любой ненулевой** — нет
|
|
91
|
+
(различать 1/2/3 инсталлятор не станет, коды нужны только вашим тестам).
|
|
92
|
+
- **Ограничения**: без сети и без секретов в выводе; таймаут 300 с (skillkit
|
|
93
|
+
убьёт зависший скрипт). Скрипта нет ⇒ это САМО ПО СЕБЕ проблема:
|
|
94
|
+
подтвердить окружение нечем, `doctor` вернёт `ok=False`.
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
# scripts/self_check.py
|
|
98
|
+
import shutil, sys
|
|
99
|
+
|
|
100
|
+
problems = [] if shutil.which("uv") else ["нет uv в PATH"]
|
|
101
|
+
print("
|
|
102
|
+
".join(problems) or "окружение исправно")
|
|
103
|
+
sys.exit(1 if problems else 0)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Разработка
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uv sync --extra dev
|
|
110
|
+
uv run --extra dev pytest -q
|
|
111
|
+
uv run --extra dev ruff check installerkit tests
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Статус
|
|
115
|
+
|
|
116
|
+
- **Type**: `kit`
|
|
117
|
+
- **Status**: `experiment`
|
|
118
|
+
- **Priority**: P1
|
|
119
|
+
- **Slug**: `s-installerkit`
|
|
120
|
+
- **Prefix**: `si`
|
|
121
|
+
- **Tags**: —
|
|
122
|
+
- Создан: 2026-07-17
|
|
123
|
+
|
|
124
|
+
## Atlas
|
|
125
|
+
|
|
126
|
+
Карточка проекта в Atlas-БД (Atlas):
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
atlas projects get s-installerkit
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Физический layout:
|
|
133
|
+
|
|
134
|
+
- Storage: `_storage/s-installerkit/`
|
|
135
|
+
- Junction: `Products\s-installerkit` → `_storage/s-installerkit`
|
|
136
|
+
|
|
137
|
+
## TODO (placeholder)
|
|
138
|
+
|
|
139
|
+
- [ ] Заполнить README реальным контентом проекта.
|
|
140
|
+
- [ ] Подключить GitLab-репозиторий (если ещё нет): `atlas projects git init s-installerkit`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# NNNN. Краткий заголовок решения
|
|
2
|
+
|
|
3
|
+
- **Статус:** proposed | accepted | superseded (→ ADR-NNNN) | deprecated
|
|
4
|
+
- **Дата:** ГГГГ-ММ-ДД
|
|
5
|
+
|
|
6
|
+
## Контекст
|
|
7
|
+
|
|
8
|
+
Какую ситуацию/проблему решаем. Что вынуждает принять решение сейчас: ограничения, требования, силы, которые тянут в разные стороны. Достаточно, чтобы понять «почему» без внешнего контекста.
|
|
9
|
+
|
|
10
|
+
## Решение
|
|
11
|
+
|
|
12
|
+
Что именно решили — одной-двумя фразами, в настоящем времени: «Делаем X». Конкретно и проверяемо.
|
|
13
|
+
|
|
14
|
+
## Последствия
|
|
15
|
+
|
|
16
|
+
Что становится проще и что — сложнее/дороже после принятия. Плюсы, минусы, новые обязательства и ограничения, которые теперь придётся держать.
|
|
17
|
+
|
|
18
|
+
## Альтернативы
|
|
19
|
+
|
|
20
|
+
Какие варианты рассматривали и **почему отклонили** (в этом ценность записи). Кратко: вариант → причина отказа / отложено до условия.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# ADR — журнал архитектурных решений
|
|
2
|
+
|
|
3
|
+
**Что это.** ADR (Architecture Decision Record) — короткий документ на **одно** архитектурное решение: контекст → что решили → почему → последствия. Лежат здесь, в `docs/adr/`, со **сквозной нумерацией** (`0001-…`, `0002-…`). Шаблон — [`0000-template.md`](0000-template.md).
|
|
4
|
+
|
|
5
|
+
**Зачем.** «Почему» проекта нельзя держать в комментариях к задачам и переписке — оно теряется. ADR — дистиллят решения: агент читает его **перед** правкой и не «чинит» то, что было выбрано сознательно. Дёшев по токенам: одно решение прочитать проще, чем реконструировать его из истории коммитов.
|
|
6
|
+
|
|
7
|
+
## Когда заводить ADR — когда сошлись 3 условия
|
|
8
|
+
|
|
9
|
+
1. решение **дорого откатить** (влияет на структуру, данные, контракты);
|
|
10
|
+
2. без контекста оно **выглядит странно** (кто-то потом захочет «починить»);
|
|
11
|
+
3. были **реальные альтернативы** и выбор — осознанный трейдофф.
|
|
12
|
+
|
|
13
|
+
Если хотя бы одно условие не выполнено — ADR не нужен, хватит `comment` на задаче в Atlas.
|
|
14
|
+
|
|
15
|
+
## Правила ведения
|
|
16
|
+
|
|
17
|
+
- **Нумерация сквозная**, файл — `NNNN-краткий-слаг.md` (`0001-operating-model-foundamentals.md`).
|
|
18
|
+
- **Не редактировать задним числом.** Принятое решение — исторический факт. Если решение отменено новым — старому ставим `Статус: superseded` (со ссылкой на новое ADR), а не переписываем его.
|
|
19
|
+
- **«Схлопывание».** Когда цепочка `superseded` разрослась, допустимо свести её к одному ADR с текущим состоянием — ради экономии контекста агента. Прежние помечаем как схлопнутые.
|
|
20
|
+
- **Статусы:** `proposed` → `accepted` → (`superseded` / `deprecated`).
|
|
21
|
+
|
|
22
|
+
## Что НЕ идёт в ADR
|
|
23
|
+
|
|
24
|
+
- **состояние** (ветка/worktree, стадия) — это тег/поле задачи в Atlas;
|
|
25
|
+
- **ход работы / handoff** — `comment` на задаче в Atlas;
|
|
26
|
+
- **черновой план реализации** — scratchpad, в `.gitignore`, в репо не коммитится.
|
|
27
|
+
|
|
28
|
+
Полная модель фиксации артефактов (4 слоя) — в `ai-ecosystem-core/AGENT-OPERATING-MODEL.md`, раздел «Модель фиксации артефактов».
|
|
29
|
+
|
|
30
|
+
**Методология:** практика ADR (Michael Nygard), компактный формат Matt Pocock (`github.com/mattpocock/skills`, grill-with-docs), примеры в NATS / AG2.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""installerkit — тонкий слой установки/самообновления CLI-продуктов над skillkit.
|
|
2
|
+
|
|
3
|
+
Кит НЕ дублирует механику skillkit (``ensure_uv`` / ``bootstrap_skill`` /
|
|
4
|
+
manifest / линковка навыка) — он её ПЕРЕИСПОЛЬЗУЕТ и добавляет верхний слой:
|
|
5
|
+
|
|
6
|
+
- ``configure`` / ``InstallerConfig`` — единая конфигурация установщика
|
|
7
|
+
(проксирует ``skillkit.configure`` + хранит dist-имя для self-update);
|
|
8
|
+
- ``make_self_update_command`` — фабрика clikit-команды ``self-update`` (сверка
|
|
9
|
+
версии с PyPI + авто-детект менеджера uv tool/pipx/pip);
|
|
10
|
+
- ``render_install_script`` — генератор ASCII bootstrap install-скриптов
|
|
11
|
+
(curl|sh / irm|iex, ставит uv → ``uv tool install <dist>``);
|
|
12
|
+
- ``ensure_uv`` / ``run_doctor`` — окружение продукта: идемпотентный uv и прогон
|
|
13
|
+
``scripts/self_check.py`` со сводным отчётом;
|
|
14
|
+
- ``install_direct`` — прямой путь установки: линковка навыка в scope агента
|
|
15
|
+
(junction/symlink) + ``skillkit.bootstrap_skill`` + регистрация MCP;
|
|
16
|
+
- ``publish_to_store`` / ``run_publish_gate`` / ``build_publish_payload`` — путь
|
|
17
|
+
через skillery: секрет+денилист-гейт (gitleaks + s-skillgate) ПЕРЕД сборкой,
|
|
18
|
+
манифест публикации и отправка инъектируемым клиентом.
|
|
19
|
+
|
|
20
|
+
Dist-имя для импорта — ``installerkit``; имя дистрибутива — ``s-installerkit``.
|
|
21
|
+
"""
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
from installerkit.config import InstallerConfig, configure
|
|
25
|
+
from installerkit.direct import install_direct
|
|
26
|
+
from installerkit.doctor import ensure_uv, run_doctor
|
|
27
|
+
from installerkit.install_scripts import render_install_script
|
|
28
|
+
from installerkit.publish import (
|
|
29
|
+
PUBLISH_PERMISSION,
|
|
30
|
+
GateFinding,
|
|
31
|
+
GateResult,
|
|
32
|
+
build_publish_payload,
|
|
33
|
+
publish_to_store,
|
|
34
|
+
run_publish_gate,
|
|
35
|
+
)
|
|
36
|
+
from installerkit.self_update import make_self_update_command
|
|
37
|
+
|
|
38
|
+
__version__ = "0.1.0"
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"__version__",
|
|
42
|
+
# конфигурация установщика (прокси на skillkit + dist-имя)
|
|
43
|
+
"configure",
|
|
44
|
+
"InstallerConfig",
|
|
45
|
+
# self-update (PyPI + авто-детект менеджера)
|
|
46
|
+
"make_self_update_command",
|
|
47
|
+
# генератор install-скриптов (ASCII bootstrap)
|
|
48
|
+
"render_install_script",
|
|
49
|
+
# окружение продукта (uv + self_check)
|
|
50
|
+
"ensure_uv",
|
|
51
|
+
"run_doctor",
|
|
52
|
+
# прямой путь установки (линковка + bootstrap + MCP)
|
|
53
|
+
"install_direct",
|
|
54
|
+
# публикация в skillery-store (гейт -> манифест -> отправка)
|
|
55
|
+
"publish_to_store",
|
|
56
|
+
"run_publish_gate",
|
|
57
|
+
"build_publish_payload",
|
|
58
|
+
"GateResult",
|
|
59
|
+
"GateFinding",
|
|
60
|
+
"PUBLISH_PERMISSION",
|
|
61
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Брендо-строки s-installerkit в одном месте (namespace S-kits + дефолты).
|
|
2
|
+
|
|
3
|
+
Кит брендо-нейтрален: потребитель переопределяет ``app_name`` через
|
|
4
|
+
:class:`~installerkit.config.InstallerConfig`. Здесь — лишь дефолты и публичные
|
|
5
|
+
константы (git-namespace открытой группы S-kits, URL официальных инсталлеров
|
|
6
|
+
менеджера пакетов ``uv``). Ни одного секрета — только публичные адреса.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
#: platformdirs app-name по умолчанию (само-имя кита; переопределяется потребителем
|
|
11
|
+
#: через ``InstallerConfig.app_name`` → ``skillkit.configure``).
|
|
12
|
+
DEFAULT_APP_NAME = "installerkit"
|
|
13
|
+
|
|
14
|
+
#: Открытая группа S-kits на GitLab — namespace git-репозиториев китов.
|
|
15
|
+
#: Имя репозитория БЕЗ префикса ``s-`` (skillkit/clikit/librarykit); dist-имя — С ним.
|
|
16
|
+
SKITS_GITLAB_NAMESPACE = "https://gitlab.com/S-kits"
|
|
17
|
+
|
|
18
|
+
#: Официальные инсталлеры менеджера пакетов ``uv`` (Astral) — публичные скрипты.
|
|
19
|
+
#: В install-скриптах используются как источник bootstrap uv при его отсутствии.
|
|
20
|
+
UV_INSTALL_SH = "https://astral.sh/uv/install.sh"
|
|
21
|
+
UV_INSTALL_PS1 = "https://astral.sh/uv/install.ps1"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def skit_git_url(repo: str) -> str:
|
|
25
|
+
"""git-URL кита в группе S-kits (``repo`` — имя без префикса ``s-``).
|
|
26
|
+
|
|
27
|
+
Ветку задаёт потребитель в ``[tool.uv.sources]`` своего pyproject; здесь —
|
|
28
|
+
лишь базовый URL репозитория.
|
|
29
|
+
"""
|
|
30
|
+
return f"{SKITS_GITLAB_NAMESPACE}/{repo}.git"
|