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.
- s_skillkit-0.2.2/AGENTS.md +45 -0
- s_skillkit-0.2.2/CHANGELOG.md +73 -0
- s_skillkit-0.2.2/PKG-INFO +144 -0
- s_skillkit-0.2.2/README.md +128 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/pyproject.toml +1 -1
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/__init__.py +180 -109
- s_skillkit-0.2.2/skillkit/binary_installer.py +308 -0
- s_skillkit-0.2.2/skillkit/bootstrap.py +234 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/deps_installer.py +113 -26
- s_skillkit-0.2.2/skillkit/errors.py +33 -0
- s_skillkit-0.2.2/skillkit/installer/__init__.py +943 -0
- s_skillkit-0.2.2/skillkit/installer/differ.py +44 -0
- s_skillkit-0.2.2/skillkit/installer/fetchers.py +99 -0
- s_skillkit-0.2.2/skillkit/installer/fsops.py +198 -0
- s_skillkit-0.2.2/skillkit/installer/meta.py +175 -0
- s_skillkit-0.2.2/skillkit/installer/models.py +171 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/manifest.py +53 -3
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/mcp_register.py +24 -38
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/path_store.py +3 -1
- s_skillkit-0.2.2/skillkit/pkg_manager.py +190 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/targets/__init__.py +21 -16
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/targets/antigravity.py +18 -18
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/targets/base.py +32 -17
- s_skillkit-0.2.2/skillkit/targets/claude_code.py +21 -0
- s_skillkit-0.2.2/skillkit/targets/codex.py +21 -0
- s_skillkit-0.2.2/skillkit/uv_bootstrap.py +178 -0
- s_skillkit-0.2.2/tests/test_binary_installer.py +265 -0
- s_skillkit-0.2.2/tests/test_bootstrap.py +233 -0
- s_skillkit-0.2.2/tests/test_deps_binary.py +218 -0
- s_skillkit-0.2.2/tests/test_errors.py +98 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_manifest.py +245 -127
- s_skillkit-0.2.2/tests/test_pkg_manager.py +117 -0
- s_skillkit-0.2.2/tests/test_typed_fields.py +75 -0
- s_skillkit-0.2.2/tests/test_uv_bootstrap.py +122 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_w268_subdir_skill.py +53 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/uv.lock +1 -1
- s_skillkit-0.1.9/PKG-INFO +0 -61
- s_skillkit-0.1.9/README.md +0 -45
- s_skillkit-0.1.9/skillkit/installer.py +0 -1165
- s_skillkit-0.1.9/skillkit/targets/claude_code.py +0 -8
- s_skillkit-0.1.9/skillkit/targets/codex.py +0 -8
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/.gitignore +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/LICENSE +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/collections.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/config.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/filter.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/linker.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/paths.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/project.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/targets/detect.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/skillkit/tooling.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/conftest.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_collections.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_config.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_deps_installer.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_filter.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_git_install.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_installer.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_mcp_register.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_path_store.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_paths.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_project.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_stub_guard.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_targets.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_tooling.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_transactional_install.py +0 -0
- {s_skillkit-0.1.9 → s_skillkit-0.2.2}/tests/test_traversal_guard.py +0 -0
- {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.
|
|
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" }
|