s-skillkit 0.1.9__tar.gz → 0.2.2__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.
Files changed (68) hide show
  1. s_skillkit-0.2.2/AGENTS.md +45 -0
  2. s_skillkit-0.2.2/CHANGELOG.md +73 -0
  3. s_skillkit-0.2.2/PKG-INFO +144 -0
  4. s_skillkit-0.2.2/README.md +128 -0
  5. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/pyproject.toml +1 -1
  6. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/__init__.py +180 -109
  7. s_skillkit-0.2.2/skillkit/binary_installer.py +308 -0
  8. s_skillkit-0.2.2/skillkit/bootstrap.py +234 -0
  9. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/deps_installer.py +113 -26
  10. s_skillkit-0.2.2/skillkit/errors.py +33 -0
  11. s_skillkit-0.2.2/skillkit/installer/__init__.py +943 -0
  12. s_skillkit-0.2.2/skillkit/installer/differ.py +44 -0
  13. s_skillkit-0.2.2/skillkit/installer/fetchers.py +99 -0
  14. s_skillkit-0.2.2/skillkit/installer/fsops.py +198 -0
  15. s_skillkit-0.2.2/skillkit/installer/meta.py +175 -0
  16. s_skillkit-0.2.2/skillkit/installer/models.py +171 -0
  17. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/manifest.py +53 -3
  18. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/mcp_register.py +24 -38
  19. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/path_store.py +3 -1
  20. s_skillkit-0.2.2/skillkit/pkg_manager.py +190 -0
  21. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/targets/__init__.py +21 -16
  22. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/targets/antigravity.py +18 -18
  23. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/targets/base.py +32 -17
  24. s_skillkit-0.2.2/skillkit/targets/claude_code.py +21 -0
  25. s_skillkit-0.2.2/skillkit/targets/codex.py +21 -0
  26. s_skillkit-0.2.2/skillkit/uv_bootstrap.py +178 -0
  27. s_skillkit-0.2.2/tests/test_binary_installer.py +265 -0
  28. s_skillkit-0.2.2/tests/test_bootstrap.py +233 -0
  29. s_skillkit-0.2.2/tests/test_deps_binary.py +218 -0
  30. s_skillkit-0.2.2/tests/test_errors.py +98 -0
  31. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_manifest.py +245 -127
  32. s_skillkit-0.2.2/tests/test_pkg_manager.py +117 -0
  33. s_skillkit-0.2.2/tests/test_typed_fields.py +75 -0
  34. s_skillkit-0.2.2/tests/test_uv_bootstrap.py +122 -0
  35. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_w268_subdir_skill.py +53 -0
  36. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/uv.lock +1 -1
  37. s_skillkit-0.1.9/PKG-INFO +0 -61
  38. s_skillkit-0.1.9/README.md +0 -45
  39. s_skillkit-0.1.9/skillkit/installer.py +0 -1165
  40. s_skillkit-0.1.9/skillkit/targets/claude_code.py +0 -8
  41. s_skillkit-0.1.9/skillkit/targets/codex.py +0 -8
  42. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/.gitignore +0 -0
  43. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/LICENSE +0 -0
  44. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/collections.py +0 -0
  45. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/config.py +0 -0
  46. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/filter.py +0 -0
  47. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/linker.py +0 -0
  48. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/paths.py +0 -0
  49. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/project.py +0 -0
  50. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/targets/detect.py +0 -0
  51. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/tooling.py +0 -0
  52. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/conftest.py +0 -0
  53. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_collections.py +0 -0
  54. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_config.py +0 -0
  55. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_deps_installer.py +0 -0
  56. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_filter.py +0 -0
  57. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_git_install.py +0 -0
  58. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_installer.py +0 -0
  59. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_mcp_register.py +0 -0
  60. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_path_store.py +0 -0
  61. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_paths.py +0 -0
  62. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_project.py +0 -0
  63. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_stub_guard.py +0 -0
  64. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_targets.py +0 -0
  65. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_tooling.py +0 -0
  66. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_transactional_install.py +0 -0
  67. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_traversal_guard.py +0 -0
  68. {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_w272_empty_manifest_guard.py +0 -0
@@ -0,0 +1,45 @@
1
+ # AGENTS.md — skillkit
2
+
3
+ > Контекст для AI-ассистентов (Claude Code, ChatGPT, Cursor и т.п.), работающих
4
+ > над этим проектом.
5
+
6
+ ## Что это
7
+
8
+ (заполнить one-line)
9
+
10
+ ## Atlas
11
+
12
+ Проект зарегистрирован в Atlas-БД (Atlas). Карточка:
13
+
14
+ ```sh
15
+ atlas projects get skillkit
16
+ ```
17
+
18
+ Любые изменения метаданных (приоритет, статус, теги) — через atlas CLI:
19
+
20
+ - `atlas projects update skillkit --priority P0` — поменять приоритет
21
+ - `atlas add-tags skillkit -t domain:<slug>` — добавить тег
22
+ - `atlas projects move skillkit --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 skillkit` — карточка проекта
37
+ - `atlas task list --project skillkit` — задачи проекта (когда W7
38
+ волна будет реализована)
39
+
40
+ <!-- atlas:usage:start -->
41
+ ## Управление проектом — через Atlas
42
+
43
+ Этот проект ведётся в Atlas (личная PM-система портфеля). Для задач/проектов/эпиков/бэкапов
44
+ используй CLI `atlas` и вызывай навык `atlas` — вся логика и роутинг внутри навыка.
45
+ <!-- atlas:usage:end -->
@@ -0,0 +1,73 @@
1
+ # Changelog
2
+
3
+ Все заметные изменения кита `s-skillkit` фиксируются здесь. Формат близок к
4
+ [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/); версионирование —
5
+ [SemVer](https://semver.org/lang/ru/).
6
+
7
+ ## [0.2.2] — 2026-07-21
8
+
9
+ ### Fixed — монорепо-навык (навык в подпапке репозитория)
10
+
11
+ - **`skill_path` переживает установку**: `_skill_meta.json` теперь хранит
12
+ подпапку навыка, а `SkillStore.update()` берёт её оттуда, если не передали
13
+ явно. Раньше в `update` стоял жёсткий `skill_path=None` — обновление
14
+ материализовало КОРЕНЬ монорепо, и в папку навыка налипали `src/`,
15
+ `pyproject.toml` и копия самого навыка, а `SKILL.md` оказывался этажом ниже
16
+ (в таком виде Claude Code навык не видит).
17
+ - **`preserved_paths` читаются из `_skill_meta.toml`** навыка, а не только из
18
+ захардкоженного списка. Навык может защитить свои данные (папку с БД,
19
+ кэш) — они переживут обновление; общие дефолты (`_local/`,
20
+ `browser_profiles/`) при этом сохраняются.
21
+
22
+ ### Added — детект пакетного менеджера (`pkg_manager`)
23
+
24
+ - `detect_project()` определяет экосистему по маркерам: python (`uv.lock`,
25
+ `pyproject.toml`, `requirements.txt`), node с КОНКРЕТНЫМ менеджером по
26
+ lock-файлу (`bun`/`pnpm`/`yarn`/`npm`, при нескольких — по времени
27
+ изменения), rust, go, ruby, php.
28
+ - `missing_manager_report()` вместо голого «не найдены ни uv, ни pip» отдаёт
29
+ машиночитаемые факты: тип проекта и маркер, чего не хватает, команда
30
+ установки под ТЕКУЩУЮ ОС и список реально доступных альтернатив. ИИ-агент
31
+ может довести установку сам.
32
+
33
+ ## [0.2.0] — 2026-07-15
34
+
35
+ ### Added — install-kit (установка навыка «под ключ» со ВСЕМИ зависимостями)
36
+
37
+ - **`uv_bootstrap.ensure_uv()`** — гарантирует наличие `uv`: `which` →
38
+ официальный Astral-инсталлер (Windows PowerShell `install.ps1` / POSIX
39
+ `curl … install.sh | sh`) → фолбэк `python -m pip install uv`; PATH-плюмбинг
40
+ через `path_store`. Идемпотентно, graceful (не смогли поставить → `None`),
41
+ мокабельно (сеть не дёргается в тестах).
42
+ - **`binary_installer`** — обобщение bespoke-`install_xray` в переиспользуемый
43
+ примитив внешних бинарей с GitHub Releases:
44
+ - `ensure_binary(name, *, github_repo, asset_match, dest_dir, version=None,
45
+ bin_subpath=None, force=False) -> Path` — latest/тег → выбор ассета
46
+ (callable/паттерн) → скачивание → распаковка zip/tar → `chmod 0o755` (POSIX)
47
+ → удаление архива; идемпотентно; на сбое — `BinaryInstallError`;
48
+ - `platform_asset_name(templates, *, system=None, arch=None)` — резолв имени
49
+ ассета по текущей ОС×архитектуре (ключи `(os, arch)` или строки `"os-arch"`);
50
+ - `is_binary_installed(name, dest_dir, *, bin_subpath=None)`.
51
+ - **`deps_installer`** — новые kind `binary` / `github-release` в
52
+ `runtime_dependencies`: несут spec-словарь `{name, github_repo,
53
+ asset_match|asset_templates, dest, version?, bin_subpath?}` и делегируют
54
+ `ensure_binary`. Ветки `pip`/`npm`/`system` не изменены.
55
+ - **`manifest.build_manifest`** — сохраняет полный spec-словарь бинарей (не
56
+ только `kind`/`spec`), чтобы install мог поставить внешний бинарь.
57
+ - **`bootstrap.bootstrap_skill(skill_dir, *, manifest=None, gate_check=None,
58
+ run_self_check=True) -> dict`** — оркестрация: `ensure_uv` → python-deps
59
+ (`uv sync` при наличии `pyproject.toml`, иначе per-spec) → внешние бинари →
60
+ опциональный `gate_check`-хук (graceful, без жёсткой завязки на s-xray-gate) →
61
+ `run_self_check`. Отчёт `{uv, deps, binaries, gate, self_check}`; ни один шаг
62
+ не роняет установку.
63
+ - **`bootstrap.run_self_check(skill_dir) -> (bool, str)`** — находит и запускает
64
+ `scripts/self_check.py` (venv-python навыка → `uv run` → текущий интерпретатор),
65
+ возвращает `(ok, output)`.
66
+ - Экспорт в `skillkit.__all__`: `ensure_uv`, `ensure_binary`,
67
+ `is_binary_installed`, `platform_asset_name`, `bootstrap_skill`,
68
+ `run_self_check` (+ `BinaryInstallError`, подмодули `uv_bootstrap` /
69
+ `binary_installer` / `bootstrap`).
70
+
71
+ ### Changed
72
+
73
+ - `version` 0.1.9 → 0.2.0.
@@ -0,0 +1,144 @@
1
+ Metadata-Version: 2.4
2
+ Name: s-skillkit
3
+ Version: 0.2.2
4
+ Summary: Локальное ядро управления навыками: install из git/локальной папки, junction/symlink-линковка в scope агента, .skillignore-фильтр, build manifest, project-манифест. 0 завязок на сеть/auth — stdlib + tomli-w + pathspec + platformdirs.
5
+ Author: Dmitry
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: pathspec>=0.12.0
10
+ Requires-Dist: platformdirs>=4.0
11
+ Requires-Dist: tomli-w>=1.0
12
+ Provides-Extra: dev
13
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
14
+ Requires-Dist: pytest>=8; extra == 'dev'
15
+ Description-Content-Type: text/markdown
16
+
17
+ # s-skillkit
18
+
19
+ Локальное ядро управления навыками (skills) — **SIBLING** `librarykit`
20
+ (не зависит от него, от httpx, auth или сети). Только локальная ФС-механика.
21
+
22
+ ## Что внутри
23
+
24
+ - **`SkillStore`** (`skillkit.installer`) — материализация навыка в центральный
25
+ стор и линковка (junction на Windows / symlink на POSIX) в scope агента:
26
+ - `install_from_git` / `install_from_path` / `install` / `materialize`
27
+ - `update` (инкрементальный sha-diff), `link_existing`, `migrate_scope`
28
+ - `remove` (keep-local / purge)
29
+ - P0 **stub-would-clobber guard** (stub не затирает живой контент).
30
+ - **`targets`** — `IAgentTarget` + `detect_agent` / `get_target` (Claude Code,
31
+ Codex, Antigravity).
32
+ - **`manifest`** — `build_manifest` для publish + ридеры frontmatter /
33
+ `_skill_meta.toml`.
34
+ - **`filter`** — `.skillignore` / `files`-allowlist фильтр (pathspec).
35
+ - **`project`** — проектный манифест `.skills-hub/skills.toml`.
36
+ - **`Paths`** — инъекция каталогов (`store_dir` / `config_dir` / `bin_dir`).
37
+ `Paths.default()` — нативная раскладка через platformdirs.
38
+
39
+ ## Инъекция вместо завязки на конфиг
40
+
41
+ Кит НЕ читает env/config. Каталоги передаются явным `Paths`; git-учётка —
42
+ инъектируемым `credential_resolver` (callable `url -> url`). Потребитель (CLI)
43
+ читает env-токен и собирает резолвер:
44
+
45
+ ```python
46
+ from skillkit import SkillStore, Paths, get_target
47
+
48
+ paths = Paths.default() # или из ClientConfig
49
+
50
+ def resolver(url: str) -> str:
51
+ token = os.environ.get("SKILLS_HUB_GIT_TOKEN")
52
+ if token and url.startswith("https://") and "@" not in url:
53
+ return url.replace("https://", f"https://oauth2:{token}@", 1)
54
+ return url
55
+
56
+ store = SkillStore(get_target(None), paths.store_dir, credential_resolver=resolver)
57
+ ```
58
+
59
+ ## Канон «супер-навыка» (навык + CLI + онбординг)
60
+
61
+ **Супер-навык** — навык, который несёт собственный CLI-инструмент. Канон нужен,
62
+ чтобы ОДИН и тот же навык одинаково ставился тремя путями: локальным
63
+ install-скриптом, `skillery install` из хаба и `skillery install --path/--from-git`.
64
+
65
+ ### Структура репозитория
66
+
67
+ ```
68
+ <repo>/
69
+ pyproject.toml # пакет CLI-инструмента (публикуется на PyPI)
70
+ src/<tool>/ # исходники CLI
71
+ install/install.sh|.ps1 # локальный установщик (см. ниже)
72
+ skills/<name>/ # САМ НАВЫК — только это материализуется агенту
73
+ SKILL.md # инструкция для ИИ-агента
74
+ _skill_meta.toml # ДЕКЛАРАЦИЯ навыка (источник истины)
75
+ references/ agents/
76
+ ```
77
+
78
+ Навык может лежать и в корне репо (`SKILL.md` рядом с `_skill_meta.toml`) — тогда
79
+ подпапка не нужна. Если навык в подпапке, хаб хранит её в `Skill.skill_path`, и
80
+ манифест версии читается ИМЕННО оттуда (иначе tooling-поля теряются).
81
+
82
+ ### `_skill_meta.toml` — полная декларация
83
+
84
+ ```toml
85
+ description = "Atlas - local-first PM портфеля проектов и задач."
86
+ version = "0.3.0"
87
+ kind = "tooling" # prompt | comprehensive | tooling
88
+ tags = ["pm", "cli"]
89
+
90
+ # ВАЖНО (TOML): top-level массивы объявляются ДО заголовков [[...]] —
91
+ # иначе tomllib отнесёт ключ ВНУТРЬ таблицы, а не на верхний уровень.
92
+ runtime_dependencies = [
93
+ { kind = "pip", spec = "atlas-pm==0.3.0" }, # чем ставится CLI
94
+ ]
95
+
96
+ [[cli]] # какие команды навык приносит
97
+ command_name = "atlas"
98
+ entrypoint = "atlas.cli:app"
99
+
100
+ [onboarding] # что делать ПОСЛЕ установки
101
+ summary = "Локальный PM портфеля: проекты, задачи, эпики."
102
+ next_steps = [
103
+ "atlas setup # правила в CLAUDE.md/AGENTS.md + SessionStart-хук",
104
+ "atlas task triage # что в работе / застряло / забыто",
105
+ ]
106
+ docs = "https://github.com/<owner>/<repo>#readme"
107
+ ```
108
+
109
+ ### Как ставится: две дороги, один источник истины
110
+
111
+ **Локальный install-скрипт** (`install/install.sh|.ps1`) — для человека «с нуля»:
112
+ ставит `uv` (если нет) → `uv tool install <пакет>` → запускает post-setup
113
+ инструмента (напр. `atlas setup`). Скрипты держим **ASCII-only**: их тянут через
114
+ `irm | iex` / `curl | sh`, и не-ASCII может побиться.
115
+
116
+ **`skillery install <skill>`** — та же логика, но декларативно:
117
+ 1. материализует папку навыка агенту (global или project scope);
118
+ 2. читает `_skill_meta.toml` **из установленного навыка** и ставит
119
+ `runtime_dependencies` + регистрирует `cli[]` (`apply_tooling_artifacts`);
120
+ 3. печатает `[onboarding]` — «что делать дальше».
121
+
122
+ Источник истины для tooling — **декларация в самом навыке**, а не то, что доехало
123
+ в манифесте бандла хаба: у навыка в подпапке бандл может прийти без `cli`/
124
+ `runtime_dependencies`, поэтому инсталлятор до-читывает `_skill_meta.toml`.
125
+
126
+ ### Детект: не навреди стороннему навыку
127
+
128
+ Установка CLI запускается **только по явной декларации** (`runtime_dependencies` /
129
+ `cli` в `_skill_meta.toml`). Эвристики вида «рядом лежит `pyproject.toml` — значит
130
+ надо поставить пакет» ЗАПРЕЩЕНЫ: сторонний навык часто живёт в чужом репо, и такая
131
+ догадка поставила бы левый пакет. Навык без `_skill_meta.toml` (просто `SKILL.md`)
132
+ материализуется как есть — ничего не выполняется и не ставится.
133
+
134
+ ### Онбординг обязателен для супер-навыка
135
+
136
+ Навык, приносящий CLI, ОБЯЗАН объявить `[onboarding].next_steps`. Инсталлятор
137
+ печатает их сразу после установки, чтобы **ИИ-агент довёл настройку сам**, а не
138
+ оставлял пользователя с установленным, но ненастроенным инструментом. Контракт
139
+ вывода: в text-режиме — человекочитаемый список, в `--json` — структурные поля
140
+ (`next_steps`) в stderr, чтобы не засорять stdout с основным payload'ом.
141
+
142
+ ## Зависимости
143
+
144
+ `tomli-w`, `pathspec`, `platformdirs`. requires-python `>=3.11`. MIT.
@@ -0,0 +1,128 @@
1
+ # s-skillkit
2
+
3
+ Локальное ядро управления навыками (skills) — **SIBLING** `librarykit`
4
+ (не зависит от него, от httpx, auth или сети). Только локальная ФС-механика.
5
+
6
+ ## Что внутри
7
+
8
+ - **`SkillStore`** (`skillkit.installer`) — материализация навыка в центральный
9
+ стор и линковка (junction на Windows / symlink на POSIX) в scope агента:
10
+ - `install_from_git` / `install_from_path` / `install` / `materialize`
11
+ - `update` (инкрементальный sha-diff), `link_existing`, `migrate_scope`
12
+ - `remove` (keep-local / purge)
13
+ - P0 **stub-would-clobber guard** (stub не затирает живой контент).
14
+ - **`targets`** — `IAgentTarget` + `detect_agent` / `get_target` (Claude Code,
15
+ Codex, Antigravity).
16
+ - **`manifest`** — `build_manifest` для publish + ридеры frontmatter /
17
+ `_skill_meta.toml`.
18
+ - **`filter`** — `.skillignore` / `files`-allowlist фильтр (pathspec).
19
+ - **`project`** — проектный манифест `.skills-hub/skills.toml`.
20
+ - **`Paths`** — инъекция каталогов (`store_dir` / `config_dir` / `bin_dir`).
21
+ `Paths.default()` — нативная раскладка через platformdirs.
22
+
23
+ ## Инъекция вместо завязки на конфиг
24
+
25
+ Кит НЕ читает env/config. Каталоги передаются явным `Paths`; git-учётка —
26
+ инъектируемым `credential_resolver` (callable `url -> url`). Потребитель (CLI)
27
+ читает env-токен и собирает резолвер:
28
+
29
+ ```python
30
+ from skillkit import SkillStore, Paths, get_target
31
+
32
+ paths = Paths.default() # или из ClientConfig
33
+
34
+ def resolver(url: str) -> str:
35
+ token = os.environ.get("SKILLS_HUB_GIT_TOKEN")
36
+ if token and url.startswith("https://") and "@" not in url:
37
+ return url.replace("https://", f"https://oauth2:{token}@", 1)
38
+ return url
39
+
40
+ store = SkillStore(get_target(None), paths.store_dir, credential_resolver=resolver)
41
+ ```
42
+
43
+ ## Канон «супер-навыка» (навык + CLI + онбординг)
44
+
45
+ **Супер-навык** — навык, который несёт собственный CLI-инструмент. Канон нужен,
46
+ чтобы ОДИН и тот же навык одинаково ставился тремя путями: локальным
47
+ install-скриптом, `skillery install` из хаба и `skillery install --path/--from-git`.
48
+
49
+ ### Структура репозитория
50
+
51
+ ```
52
+ <repo>/
53
+ pyproject.toml # пакет CLI-инструмента (публикуется на PyPI)
54
+ src/<tool>/ # исходники CLI
55
+ install/install.sh|.ps1 # локальный установщик (см. ниже)
56
+ skills/<name>/ # САМ НАВЫК — только это материализуется агенту
57
+ SKILL.md # инструкция для ИИ-агента
58
+ _skill_meta.toml # ДЕКЛАРАЦИЯ навыка (источник истины)
59
+ references/ agents/
60
+ ```
61
+
62
+ Навык может лежать и в корне репо (`SKILL.md` рядом с `_skill_meta.toml`) — тогда
63
+ подпапка не нужна. Если навык в подпапке, хаб хранит её в `Skill.skill_path`, и
64
+ манифест версии читается ИМЕННО оттуда (иначе tooling-поля теряются).
65
+
66
+ ### `_skill_meta.toml` — полная декларация
67
+
68
+ ```toml
69
+ description = "Atlas - local-first PM портфеля проектов и задач."
70
+ version = "0.3.0"
71
+ kind = "tooling" # prompt | comprehensive | tooling
72
+ tags = ["pm", "cli"]
73
+
74
+ # ВАЖНО (TOML): top-level массивы объявляются ДО заголовков [[...]] —
75
+ # иначе tomllib отнесёт ключ ВНУТРЬ таблицы, а не на верхний уровень.
76
+ runtime_dependencies = [
77
+ { kind = "pip", spec = "atlas-pm==0.3.0" }, # чем ставится CLI
78
+ ]
79
+
80
+ [[cli]] # какие команды навык приносит
81
+ command_name = "atlas"
82
+ entrypoint = "atlas.cli:app"
83
+
84
+ [onboarding] # что делать ПОСЛЕ установки
85
+ summary = "Локальный PM портфеля: проекты, задачи, эпики."
86
+ next_steps = [
87
+ "atlas setup # правила в CLAUDE.md/AGENTS.md + SessionStart-хук",
88
+ "atlas task triage # что в работе / застряло / забыто",
89
+ ]
90
+ docs = "https://github.com/<owner>/<repo>#readme"
91
+ ```
92
+
93
+ ### Как ставится: две дороги, один источник истины
94
+
95
+ **Локальный install-скрипт** (`install/install.sh|.ps1`) — для человека «с нуля»:
96
+ ставит `uv` (если нет) → `uv tool install <пакет>` → запускает post-setup
97
+ инструмента (напр. `atlas setup`). Скрипты держим **ASCII-only**: их тянут через
98
+ `irm | iex` / `curl | sh`, и не-ASCII может побиться.
99
+
100
+ **`skillery install <skill>`** — та же логика, но декларативно:
101
+ 1. материализует папку навыка агенту (global или project scope);
102
+ 2. читает `_skill_meta.toml` **из установленного навыка** и ставит
103
+ `runtime_dependencies` + регистрирует `cli[]` (`apply_tooling_artifacts`);
104
+ 3. печатает `[onboarding]` — «что делать дальше».
105
+
106
+ Источник истины для tooling — **декларация в самом навыке**, а не то, что доехало
107
+ в манифесте бандла хаба: у навыка в подпапке бандл может прийти без `cli`/
108
+ `runtime_dependencies`, поэтому инсталлятор до-читывает `_skill_meta.toml`.
109
+
110
+ ### Детект: не навреди стороннему навыку
111
+
112
+ Установка CLI запускается **только по явной декларации** (`runtime_dependencies` /
113
+ `cli` в `_skill_meta.toml`). Эвристики вида «рядом лежит `pyproject.toml` — значит
114
+ надо поставить пакет» ЗАПРЕЩЕНЫ: сторонний навык часто живёт в чужом репо, и такая
115
+ догадка поставила бы левый пакет. Навык без `_skill_meta.toml` (просто `SKILL.md`)
116
+ материализуется как есть — ничего не выполняется и не ставится.
117
+
118
+ ### Онбординг обязателен для супер-навыка
119
+
120
+ Навык, приносящий CLI, ОБЯЗАН объявить `[onboarding].next_steps`. Инсталлятор
121
+ печатает их сразу после установки, чтобы **ИИ-агент довёл настройку сам**, а не
122
+ оставлял пользователя с установленным, но ненастроенным инструментом. Контракт
123
+ вывода: в text-режиме — человекочитаемый список, в `--json` — структурные поля
124
+ (`next_steps`) в stderr, чтобы не засорять stdout с основным payload'ом.
125
+
126
+ ## Зависимости
127
+
128
+ `tomli-w`, `pathspec`, `platformdirs`. requires-python `>=3.11`. MIT.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "s-skillkit"
3
- version = "0.1.9"
3
+ version = "0.2.2"
4
4
  description = "Локальное ядро управления навыками: install из git/локальной папки, junction/symlink-линковка в scope агента, .skillignore-фильтр, build manifest, project-манифест. 0 завязок на сеть/auth — stdlib + tomli-w + pathspec + platformdirs."
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }