s-skillkit 0.4.1__tar.gz → 0.6.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 (130) hide show
  1. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/.gitignore +5 -0
  2. s_skillkit-0.6.2/.gitlab-ci.yml +138 -0
  3. s_skillkit-0.6.2/.gitlab-ci.yml.bak +128 -0
  4. s_skillkit-0.6.2/.importlinter +70 -0
  5. s_skillkit-0.6.2/.importlinter.bak +69 -0
  6. s_skillkit-0.6.2/.skillgateignore +12 -0
  7. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/CHANGELOG.md +133 -1
  8. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/PKG-INFO +7 -5
  9. s_skillkit-0.6.2/docs/agent-projections.md +76 -0
  10. s_skillkit-0.6.2/docs/safe-updates.md +41 -0
  11. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/pyproject.toml +46 -3
  12. s_skillkit-0.6.2/scripts/check_dist_leaks.py +180 -0
  13. s_skillkit-0.6.2/scripts/cycles_gate.py +397 -0
  14. s_skillkit-0.6.2/scripts/cycles_gate.py.bak +397 -0
  15. s_skillkit-0.6.2/scripts/lock_gate.py +228 -0
  16. s_skillkit-0.6.2/scripts/pins_gate.py +268 -0
  17. s_skillkit-0.6.2/scripts/pins_gate.py.bak +269 -0
  18. s_skillkit-0.6.2/scripts/release_guard.py +275 -0
  19. s_skillkit-0.6.2/scripts/release_guard.py.bak +138 -0
  20. s_skillkit-0.6.2/scripts/source_guard.py +104 -0
  21. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/__init__.py +8 -2
  22. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/binary_installer.py +3 -3
  23. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/installer/__init__.py +189 -20
  24. s_skillkit-0.6.2/skillkit/installer/differ.py +168 -0
  25. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/installer/fetchers.py +6 -1
  26. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/installer/models.py +7 -0
  27. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/installer/ownership.py +35 -0
  28. s_skillkit-0.6.2/skillkit/installer/projections.py +338 -0
  29. s_skillkit-0.6.2/skillkit/installer_cli/__init__.py +77 -0
  30. s_skillkit-0.6.2/skillkit/installer_cli/_branding.py +30 -0
  31. s_skillkit-0.6.2/skillkit/installer_cli/_detached.py +33 -0
  32. s_skillkit-0.6.2/skillkit/installer_cli/config.py +104 -0
  33. s_skillkit-0.6.2/skillkit/installer_cli/direct.py +285 -0
  34. s_skillkit-0.6.2/skillkit/installer_cli/doctor.py +88 -0
  35. s_skillkit-0.6.2/skillkit/installer_cli/install_scripts.py +108 -0
  36. s_skillkit-0.6.2/skillkit/installer_cli/publish.py +331 -0
  37. s_skillkit-0.6.2/skillkit/installer_cli/self_update.py +217 -0
  38. s_skillkit-0.6.2/skillkit/installer_cli/tokens.py +170 -0
  39. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/mcp_register.py +4 -0
  40. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/targets/__init__.py +3 -1
  41. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/targets/antigravity.py +0 -22
  42. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/targets/base.py +0 -55
  43. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/targets/claude_code.py +15 -29
  44. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/targets/codex.py +14 -2
  45. s_skillkit-0.6.2/skillkit/targets/deepseek.py +18 -0
  46. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/targets/detect.py +3 -0
  47. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/uv_bootstrap.py +2 -1
  48. s_skillkit-0.6.2/tests/conftest.py +75 -0
  49. s_skillkit-0.6.2/tests/test_agent_projections.py +424 -0
  50. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_bootstrap.py +1 -4
  51. s_skillkit-0.6.2/tests/test_deepseek_target.py +19 -0
  52. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_destructive_ownership_gate_2026_07_21.py +43 -3
  53. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_git_install.py +2 -1
  54. s_skillkit-0.6.2/tests/test_git_payload_bytes.py +49 -0
  55. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_installer.py +7 -3
  56. s_skillkit-0.6.2/tests/test_installer_cli_direct.py +147 -0
  57. s_skillkit-0.6.2/tests/test_installer_cli_doctor.py +103 -0
  58. s_skillkit-0.6.2/tests/test_installer_cli_publish.py +160 -0
  59. s_skillkit-0.6.2/tests/test_installer_cli_smoke.py +104 -0
  60. s_skillkit-0.6.2/tests/test_installer_cli_tokens.py +129 -0
  61. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_legacy_paths_no_orphans_2026_07_21.py +37 -7
  62. s_skillkit-0.6.2/tests/test_mcp_disabled_preference.py +40 -0
  63. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_no_raw_subprocess.py +12 -6
  64. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_remove_ownership_guard_2026_07_21.py +10 -2
  65. s_skillkit-0.6.2/tests/test_safe_update_gate.py +304 -0
  66. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_targets.py +2 -1
  67. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_targets_public_names.py +7 -3
  68. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_w272_empty_manifest_guard.py +2 -1
  69. s_skillkit-0.6.2/uv.lock +1142 -0
  70. s_skillkit-0.4.1/.gitlab-ci.yml +0 -31
  71. s_skillkit-0.4.1/skillkit/installer/differ.py +0 -44
  72. s_skillkit-0.4.1/skillkit/plugin_register.py +0 -260
  73. s_skillkit-0.4.1/tests/conftest.py +0 -40
  74. s_skillkit-0.4.1/tests/test_plugin_register.py +0 -163
  75. s_skillkit-0.4.1/uv.lock +0 -150
  76. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/AGENTS.md +0 -0
  77. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/LICENSE +0 -0
  78. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/README.md +0 -0
  79. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/docs/adr/0000-template.md +0 -0
  80. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/docs/adr/0001-kanon-navyka-zhivet-v-skillkit.md +0 -0
  81. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/docs/adr/README.md +0 -0
  82. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/bootstrap.py +0 -0
  83. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/canon.py +0 -0
  84. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/collections.py +0 -0
  85. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/config.py +0 -0
  86. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/deps_installer.py +0 -0
  87. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/errors.py +0 -0
  88. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/filter.py +0 -0
  89. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/hook_register.py +0 -0
  90. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/installer/fsops.py +0 -0
  91. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/installer/meta.py +0 -0
  92. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/linker.py +0 -0
  93. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/manifest.py +0 -0
  94. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/path_store.py +0 -0
  95. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/paths.py +0 -0
  96. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/pkg_manager.py +0 -0
  97. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/proc.py +0 -0
  98. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/project.py +0 -0
  99. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/targets/opencode.py +0 -0
  100. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/telemetry.py +0 -0
  101. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/skillkit/tooling.py +0 -0
  102. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_agent_skill_layouts_2026_07_21.py +0 -0
  103. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_artifact_ownership_2272.py +0 -0
  104. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_binary_installer.py +0 -0
  105. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_canon.py +0 -0
  106. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_claude_frontmatter.py +0 -0
  107. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_collections.py +0 -0
  108. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_config.py +0 -0
  109. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_deps_binary.py +0 -0
  110. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_deps_installer.py +0 -0
  111. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_errors.py +0 -0
  112. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_filter.py +0 -0
  113. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_hooks.py +0 -0
  114. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_manifest.py +0 -0
  115. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_mcp_register.py +0 -0
  116. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_packaging_lock.py +0 -0
  117. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_path_store.py +0 -0
  118. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_paths.py +0 -0
  119. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_pkg_manager.py +0 -0
  120. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_pkgsrc_not_in_agent_zone.py +0 -0
  121. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_proc.py +0 -0
  122. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_project.py +0 -0
  123. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_stub_guard.py +0 -0
  124. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_telemetry_adapter.py +0 -0
  125. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_tooling.py +0 -0
  126. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_transactional_install.py +0 -0
  127. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_traversal_guard.py +0 -0
  128. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_typed_fields.py +0 -0
  129. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_uv_bootstrap.py +0 -0
  130. {s_skillkit-0.4.1 → s_skillkit-0.6.2}/tests/test_w268_subdir_skill.py +0 -0
@@ -48,3 +48,8 @@ NUL
48
48
 
49
49
  # git worktrees (агентские)
50
50
  .worktrees/
51
+
52
+ # Отметка локального прогона гейта 3 — свидетельство «на ЭТОЙ машине
53
+ # потребители были зелёные». В git ей не место: там она означала бы, что
54
+ # прогон был у всех, а он локальный по построению (раннер не видит соседей).
55
+ .kits-gate3.json
@@ -0,0 +1,138 @@
1
+ # СГЕНЕРИРОВАНО из devcontour/tools/kits/template/gitlab-ci.yml — не правь здесь.
2
+ # Правка идёт в шаблон, затем `python tools/kits/apply_template.py <кит>`.
3
+ # Сверка: `python tools/kits/apply_template.py <кит> --check` (код 1 при расхождении).
4
+ #
5
+ # Автопубликация на PyPI по семвер-тегу vX.Y.Z через Trusted Publishing (OIDC).
6
+ # Три стадии, и это не украшение: версии на PyPI неизменяемы, и шесть китов
7
+ # уезжали туда без единого теста (browserkit 0.0.18, netkit ≤0.0.12 — оба в бою).
8
+ # gates — тесты, линтер, слои, doctor: на каждый push и на тег
9
+ # release-guard — тег == версия во всех местах (pyproject/uv.lock/CHANGELOG)
10
+ # publish-pypi — только после двух первых; версия, уже лежащая на PyPI, не
11
+ # публикуется повторно (тег «догоняет» выпуск, а не роняет CI);
12
+ # после сборки и до обмена токена — check_dist_leaks.py
13
+ # (личные данные разработчика в собранном дистрибутиве)
14
+ # Токены НИГДЕ не хранятся: GitLab выдаёт короткоживущий OIDC-токен (PYPI_ID_TOKEN),
15
+ # он одноразово обменивается на PyPI API-токен. Издатель настраивается на pypi.org:
16
+ # Manage -> Publishing -> GitLab (namespace=S-kits, project=skillkit,
17
+ # top-level pipeline file=.gitlab-ci.yml, environment — пусто).
18
+ # Дистрибутив на PyPI: s-skillkit.
19
+ stages: [test, guard, publish]
20
+
21
+ .uv:
22
+ image: ghcr.io/astral-sh/uv:python3.12-bookworm
23
+
24
+ gates:
25
+ extends: .uv
26
+ stage: test
27
+ rules:
28
+ - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
29
+ - if: $CI_PIPELINE_SOURCE == "push"
30
+ script:
31
+ # dev-зависимости у китов объявлены двумя способами — extra `dev` и группа
32
+ # `[dependency-groups] dev`; --all-extras покрывает первое, группу добавляем
33
+ # только если она объявлена, иначе uv падает «Group dev is not defined».
34
+ # `--locked`: замок обязан соответствовать манифесту, а не тихо
35
+ # пересобираться под него. Без флага правка пина без `uv lock` доезжает до
36
+ # прода незамеченной — CI зелёный, а у потребителя приезжает старая версия.
37
+ - uv sync --locked --all-extras $(python3 -c "import tomllib;print('--group dev' if 'dev' in tomllib.load(open('pyproject.toml','rb')).get('dependency-groups',{}) else '')")
38
+ - uv run pytest tests/ -q
39
+ # Линтер по ВСЕМУ пакету, а не по списку файлов: сужение до «файлов волны 0»
40
+ # держалось девять китов и ни разу не было расширено — сужение приживается,
41
+ # расширение нет.
42
+ - uv run ruff check .
43
+ # Границы слоёв: контракт в .importlinter (ставится тем же шаблоном).
44
+ # — доп. пакеты через --with (пусто у большинства
45
+ # китов; adapterkit — пример кита, которому нужен сосед на прогоне
46
+ # lint-imports, см. apply_template.py --extra-with).
47
+ - uv run --with import-linter lint-imports
48
+ # Гейт 1, часть «согласованность локальных venv» (kitsctl doctor). Скрипт
49
+ # раздаётся шаблоном не всем: в раннере видно ОДИН репозиторий, соседних
50
+ # venv'ов там нет, — поэтому шаг условный и молча пропускается, когда
51
+ # инструмента у кита нет. Настоящее место doctor — локальный прогон перед
52
+ # тегом; см. docs/kits/SAFETY-NET.md, «Известные ограничения».
53
+ - 'if [ -f scripts/kitsctl.py ]; then python3 scripts/kitsctl.py doctor; else echo "kitsctl doctor — инструмента нет в репозитории, пропуск (см. SAFETY-NET.md)"; fi'
54
+ # Гейт 2: у каждой зависимости на кит есть верхняя граница. Значение границы
55
+ # здесь не вычисляется — в раннере соседних репозиториев нет, версий взять
56
+ # неоткуда; проверяется НАЛИЧИЕ. Без этого шага правило остаётся устной
57
+ # дисциплиной, которую забывают: портфель дожил до 248 незакрытых пинов
58
+ # ровно потому, что напоминать о нём было некому (#2800).
59
+ - 'if [ -f scripts/pins_gate.py ]; then python3 scripts/pins_gate.py --self-check --root .; else echo "гейт пинов — инструмента нет в репозитории, пропуск"; fi'
60
+ # Гейт колец: объявленное в `[tool.kit] lazy_deps` и правда грузится лениво.
61
+ # Колец здесь не увидеть (соседей в раннере нет), но видно главное: подъём
62
+ # такого импорта на верхний уровень замыкает кольцо ПРЯМО СЕЙЧАС, а
63
+ # выглядит безобидной уборкой («чего он тут в теле функции») — #2833.
64
+ - 'if [ -f scripts/cycles_gate.py ]; then python3 scripts/cycles_gate.py --self-check --root .; else echo "гейт колец — инструмента нет в репозитории, пропуск"; fi'
65
+ # Гейт замка: объявленная версия кита ДОЕЗЖАЕТ до окружения. `--locked`
66
+ # выше ловит другое — что замок не пересобран под манифест; а если у
67
+ # зависимости переопределён источник (`[tool.uv.sources]` = git/path), то
68
+ # спецификатор версии в разрешении не участвует вовсе, замок считается
69
+ # актуальным, и отставание не видит НИКТО. Так agentskit и issuekit
70
+ # держали clikit 0.1.6 при объявленном >=0.2.1 (#2921).
71
+ - 'if [ -f scripts/lock_gate.py ]; then python3 scripts/lock_gate.py --self-check --root .; else echo "гейт замка — инструмента нет в репозитории, пропуск"; fi'
72
+
73
+ release-guard:
74
+ extends: .uv
75
+ stage: guard
76
+ needs: [gates]
77
+ rules:
78
+ - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
79
+ script:
80
+ - python3 scripts/release_guard.py "$CI_COMMIT_TAG"
81
+
82
+ publish-pypi:
83
+ extends: .uv
84
+ stage: publish
85
+ needs: [release-guard]
86
+ rules:
87
+ - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
88
+ id_tokens:
89
+ PYPI_ID_TOKEN:
90
+ aud: pypi
91
+ script:
92
+ # КУДА уезжает выпуск, решает признак В САМОМ КИТЕ ([tool.kit] visibility),
93
+ # а не память человека и не отдельный список где-то в стороне. Приватный кит
94
+ # (готовый сервис, реализация чужой площадки) уходит в приватный индекс
95
+ # GitLab по ВСТРОЕННОМУ токену задания — новых секретов заводить не нужно.
96
+ # Умолчание — private: забыть пометить приватный кит дороже, чем забыть
97
+ # пометить открытый, и ошибаться надо в безопасную сторону.
98
+ - |
99
+ VIS=$(python3 -c "import tomllib;print((tomllib.load(open('pyproject.toml','rb')).get('tool') or {}).get('kit',{}).get('visibility','private'))")
100
+ echo "видимость кита: $VIS"
101
+ if [ "$VIS" != "public" ]; then
102
+ uv build
103
+ python3 scripts/check_dist_leaks.py dist/
104
+ uv publish --publish-url "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi" --username gitlab-ci-token --password "$CI_JOB_TOKEN"
105
+ echo "выпуск ушёл в приватный индекс проекта, на публичный PyPI НЕ уезжал"
106
+ exit 0
107
+ fi
108
+ - |
109
+ DIST=$(python3 -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['name'])")
110
+ VER="${CI_COMMIT_TAG#v}"
111
+ if python3 - "$DIST" "$VER" <<'PY'
112
+ import json, sys, urllib.request
113
+ dist, ver = sys.argv[1], sys.argv[2]
114
+ try:
115
+ data = json.load(urllib.request.urlopen(f"https://pypi.org/pypi/{dist}/json"))
116
+ except Exception:
117
+ sys.exit(1)
118
+ sys.exit(0 if ver in data.get("releases", {}) else 1)
119
+ PY
120
+ then echo "версия $VER уже на PyPI — публикацию пропускаем"; exit 0; fi
121
+ - uv build
122
+ # Последний рубеж перед необратимым шагом (версии на PyPI неизменяемы,
123
+ # yank — не удаление). Прецедент — leasekit: реальный email и домашний
124
+ # путь разработчика уехали в публичный индекс из тестовых фикстур. Ловит
125
+ # по классам, не по строкам; см. docs/kits/SAFETY-NET.md.
126
+ - python3 scripts/check_dist_leaks.py dist/
127
+ - |
128
+ export UV_PUBLISH_TOKEN=$(python3 - <<'PY'
129
+ import json, os, urllib.request
130
+ req = urllib.request.Request(
131
+ "https://pypi.org/_/oidc/mint-token",
132
+ data=json.dumps({"token": os.environ["PYPI_ID_TOKEN"]}).encode(),
133
+ headers={"Content-Type": "application/json"},
134
+ )
135
+ print(json.load(urllib.request.urlopen(req))["token"])
136
+ PY
137
+ )
138
+ - uv publish
@@ -0,0 +1,128 @@
1
+ # СГЕНЕРИРОВАНО из devcontour/tools/kits/template/gitlab-ci.yml — не правь здесь.
2
+ # Правка идёт в шаблон, затем `python tools/kits/apply_template.py <кит>`.
3
+ # Сверка: `python tools/kits/apply_template.py <кит> --check` (код 1 при расхождении).
4
+ #
5
+ # Автопубликация на PyPI по семвер-тегу vX.Y.Z через Trusted Publishing (OIDC).
6
+ # Три стадии, и это не украшение: версии на PyPI неизменяемы, и шесть китов
7
+ # уезжали туда без единого теста (browserkit 0.0.18, netkit ≤0.0.12 — оба в бою).
8
+ # gates — тесты, линтер, слои, doctor: на каждый push и на тег
9
+ # release-guard — тег == версия во всех местах (pyproject/uv.lock/CHANGELOG)
10
+ # publish-pypi — только после двух первых; версия, уже лежащая на PyPI, не
11
+ # публикуется повторно (тег «догоняет» выпуск, а не роняет CI);
12
+ # после сборки и до обмена токена — check_dist_leaks.py
13
+ # (личные данные разработчика в собранном дистрибутиве)
14
+ # Токены НИГДЕ не хранятся: GitLab выдаёт короткоживущий OIDC-токен (PYPI_ID_TOKEN),
15
+ # он одноразово обменивается на PyPI API-токен. Издатель настраивается на pypi.org:
16
+ # Manage -> Publishing -> GitLab (namespace=S-kits, project=skillkit,
17
+ # top-level pipeline file=.gitlab-ci.yml, environment — пусто).
18
+ # Дистрибутив на PyPI: s-skillkit.
19
+ stages: [test, guard, publish]
20
+
21
+ .uv:
22
+ image: ghcr.io/astral-sh/uv:python3.12-bookworm
23
+
24
+ gates:
25
+ extends: .uv
26
+ stage: test
27
+ rules:
28
+ - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
29
+ - if: $CI_PIPELINE_SOURCE == "push"
30
+ script:
31
+ # dev-зависимости у китов объявлены двумя способами — extra `dev` и группа
32
+ # `[dependency-groups] dev`; --all-extras покрывает первое, группу добавляем
33
+ # только если она объявлена, иначе uv падает «Group dev is not defined».
34
+ - uv sync --all-extras $(python3 -c "import tomllib;print('--group dev' if 'dev' in tomllib.load(open('pyproject.toml','rb')).get('dependency-groups',{}) else '')")
35
+ - uv run pytest tests/ -q
36
+ # Линтер по ВСЕМУ пакету, а не по списку файлов: сужение до «файлов волны 0»
37
+ # держалось девять китов и ни разу не было расширено — сужение приживается,
38
+ # расширение нет.
39
+ - uv run ruff check .
40
+ # Границы слоёв: контракт в .importlinter (ставится тем же шаблоном).
41
+ # — доп. пакеты через --with (пусто у большинства
42
+ # китов; adapterkit — пример кита, которому нужен сосед на прогоне
43
+ # lint-imports, см. apply_template.py --extra-with).
44
+ - uv run --with import-linter lint-imports
45
+ # Гейт 1, часть «согласованность локальных venv» (kitsctl doctor). Скрипт
46
+ # раздаётся шаблоном не всем: в раннере видно ОДИН репозиторий, соседних
47
+ # venv'ов там нет, — поэтому шаг условный и молча пропускается, когда
48
+ # инструмента у кита нет. Настоящее место doctor — локальный прогон перед
49
+ # тегом; см. docs/kits/SAFETY-NET.md, «Известные ограничения».
50
+ - 'if [ -f scripts/kitsctl.py ]; then python3 scripts/kitsctl.py doctor; else echo "kitsctl doctor — инструмента нет в репозитории, пропуск (см. SAFETY-NET.md)"; fi'
51
+ # Гейт 2: у каждой зависимости на кит есть верхняя граница. Значение границы
52
+ # здесь не вычисляется — в раннере соседних репозиториев нет, версий взять
53
+ # неоткуда; проверяется НАЛИЧИЕ. Без этого шага правило остаётся устной
54
+ # дисциплиной, которую забывают: портфель дожил до 248 незакрытых пинов
55
+ # ровно потому, что напоминать о нём было некому (#2800).
56
+ - 'if [ -f scripts/pins_gate.py ]; then python3 scripts/pins_gate.py --self-check --root .; else echo "гейт пинов — инструмента нет в репозитории, пропуск"; fi'
57
+ # Гейт колец: объявленное в `[tool.kit] lazy_deps` и правда грузится лениво.
58
+ # Колец здесь не увидеть (соседей в раннере нет), но видно главное: подъём
59
+ # такого импорта на верхний уровень замыкает кольцо ПРЯМО СЕЙЧАС, а
60
+ # выглядит безобидной уборкой («чего он тут в теле функции») — #2833.
61
+ - 'if [ -f scripts/cycles_gate.py ]; then python3 scripts/cycles_gate.py --self-check --root .; else echo "гейт колец — инструмента нет в репозитории, пропуск"; fi'
62
+
63
+ release-guard:
64
+ extends: .uv
65
+ stage: guard
66
+ needs: [gates]
67
+ rules:
68
+ - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
69
+ script:
70
+ - python3 scripts/release_guard.py "$CI_COMMIT_TAG"
71
+
72
+ publish-pypi:
73
+ extends: .uv
74
+ stage: publish
75
+ needs: [release-guard]
76
+ rules:
77
+ - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
78
+ id_tokens:
79
+ PYPI_ID_TOKEN:
80
+ aud: pypi
81
+ script:
82
+ # КУДА уезжает выпуск, решает признак В САМОМ КИТЕ ([tool.kit] visibility),
83
+ # а не память человека и не отдельный список где-то в стороне. Приватный кит
84
+ # (готовый сервис, реализация чужой площадки) уходит в приватный индекс
85
+ # GitLab по ВСТРОЕННОМУ токену задания — новых секретов заводить не нужно.
86
+ # Умолчание — private: забыть пометить приватный кит дороже, чем забыть
87
+ # пометить открытый, и ошибаться надо в безопасную сторону.
88
+ - |
89
+ VIS=$(python3 -c "import tomllib;print((tomllib.load(open('pyproject.toml','rb')).get('tool') or {}).get('kit',{}).get('visibility','private'))")
90
+ echo "видимость кита: $VIS"
91
+ if [ "$VIS" != "public" ]; then
92
+ uv build
93
+ python3 scripts/check_dist_leaks.py dist/
94
+ uv publish --publish-url "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi" --username gitlab-ci-token --password "$CI_JOB_TOKEN"
95
+ echo "выпуск ушёл в приватный индекс проекта, на публичный PyPI НЕ уезжал"
96
+ exit 0
97
+ fi
98
+ - |
99
+ DIST=$(python3 -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['name'])")
100
+ VER="${CI_COMMIT_TAG#v}"
101
+ if python3 - "$DIST" "$VER" <<'PY'
102
+ import json, sys, urllib.request
103
+ dist, ver = sys.argv[1], sys.argv[2]
104
+ try:
105
+ data = json.load(urllib.request.urlopen(f"https://pypi.org/pypi/{dist}/json"))
106
+ except Exception:
107
+ sys.exit(1)
108
+ sys.exit(0 if ver in data.get("releases", {}) else 1)
109
+ PY
110
+ then echo "версия $VER уже на PyPI — публикацию пропускаем"; exit 0; fi
111
+ - uv build
112
+ # Последний рубеж перед необратимым шагом (версии на PyPI неизменяемы,
113
+ # yank — не удаление). Прецедент — leasekit: реальный email и домашний
114
+ # путь разработчика уехали в публичный индекс из тестовых фикстур. Ловит
115
+ # по классам, не по строкам; см. docs/kits/SAFETY-NET.md.
116
+ - python3 scripts/check_dist_leaks.py dist/
117
+ - |
118
+ export UV_PUBLISH_TOKEN=$(python3 - <<'PY'
119
+ import json, os, urllib.request
120
+ req = urllib.request.Request(
121
+ "https://pypi.org/_/oidc/mint-token",
122
+ data=json.dumps({"token": os.environ["PYPI_ID_TOKEN"]}).encode(),
123
+ headers={"Content-Type": "application/json"},
124
+ )
125
+ print(json.load(urllib.request.urlopen(req))["token"])
126
+ PY
127
+ )
128
+ - uv publish
@@ -0,0 +1,70 @@
1
+ # СГЕНЕРИРОВАНО из devcontour/tools/kits/template/importlinter.ini — не правь
2
+ # здесь. Правка идёт в шаблон, затем `python tools/kits/apply_template.py <кит>`.
3
+ #
4
+ # Заготовка контракта слоёв. Запуск: `uv run --with import-linter lint-imports`.
5
+ #
6
+ # Контракт ниже — минимум, который годится ЛЮБОМУ киту и не требует ручной
7
+ # настройки: «skillkit не импортирует те киты экосистемы, которых нет в его
8
+ # объявленных зависимостях». Скрытая зависимость — это кит, который работает у
9
+ # автора (сосед стоит в venv) и разваливается у потребителя на первом импорте;
10
+ # именно так ломались pypi-publish и gemini-chat.
11
+ #
12
+ # Список forbidden_modules подставлен установщиком из реестра китов на момент
13
+ # установки: все известные пакеты китов МИНУС собственный МИНУС объявленные в
14
+ # pyproject зависимости. Появилась новая честная зависимость — объяви её в
15
+ # pyproject и переустанови шаблон, а не правь этот файл.
16
+ #
17
+ # Собственные контракты кита (layers/eager_forbidden/declared_dependencies,
18
+ # как у adapterkit) дописываются НИЖЕ отдельными секциями прямо в этом файле.
19
+ # Установщик сверяет файл целиком, поэтому `--check` после такой правки
20
+ # закономерно покажет расхождение с каноном — это ожидаемо и осознанно
21
+ # игнорируется в отчёте ревью, см. docs/kits/SAFETY-NET.md, «Что делать при
22
+ # расхождении» (п.2).
23
+
24
+ [importlinter]
25
+ # include_external_packages нужен: forbidden_modules перечисляет пакеты,
26
+ # внешние относительно root_packages.
27
+ include_external_packages = True
28
+ root_packages =
29
+ skillkit
30
+ exclude_type_checking_imports = True
31
+
32
+ [importlinter:contract:no-undeclared-kits]
33
+ name = skillkit не импортирует киты, которых нет в его зависимостях
34
+ type = forbidden
35
+ source_modules =
36
+ skillkit
37
+ forbidden_modules =
38
+ accountpoolkit
39
+ adapterkit
40
+ agentskit
41
+ aichatkit
42
+ authkit_client
43
+ authkit_contracts
44
+ authkit_server
45
+ b24kit
46
+ browserkit
47
+ chatkit
48
+ clientkit
49
+ corekit
50
+ emojikit
51
+ gitkit
52
+ installerkit
53
+ iokit
54
+ issuekit
55
+ leasekit
56
+ maxkit
57
+ modelkit
58
+ netkit
59
+ orchestrationkit
60
+ ormkit
61
+ persistkit
62
+ pluginkit
63
+ replicationkit
64
+ servicekit
65
+ sessionkit
66
+ socialkit
67
+ storagekit
68
+ totp_client
69
+ vaultkit
70
+ worker_service
@@ -0,0 +1,69 @@
1
+ # СГЕНЕРИРОВАНО из devcontour/tools/kits/template/importlinter.ini — не правь
2
+ # здесь. Правка идёт в шаблон, затем `python tools/kits/apply_template.py <кит>`.
3
+ #
4
+ # Заготовка контракта слоёв. Запуск: `uv run --with import-linter lint-imports`.
5
+ #
6
+ # Контракт ниже — минимум, который годится ЛЮБОМУ киту и не требует ручной
7
+ # настройки: «skillkit не импортирует те киты экосистемы, которых нет в его
8
+ # объявленных зависимостях». Скрытая зависимость — это кит, который работает у
9
+ # автора (сосед стоит в venv) и разваливается у потребителя на первом импорте;
10
+ # именно так ломались pypi-publish и gemini-chat.
11
+ #
12
+ # Список forbidden_modules подставлен установщиком из реестра китов на момент
13
+ # установки: все известные пакеты китов МИНУС собственный МИНУС объявленные в
14
+ # pyproject зависимости. Появилась новая честная зависимость — объяви её в
15
+ # pyproject и переустанови шаблон, а не правь этот файл.
16
+ #
17
+ # Собственные контракты кита (layers/eager_forbidden/declared_dependencies,
18
+ # как у adapterkit) дописываются НИЖЕ отдельными секциями прямо в этом файле.
19
+ # Установщик сверяет файл целиком, поэтому `--check` после такой правки
20
+ # закономерно покажет расхождение с каноном — это ожидаемо и осознанно
21
+ # игнорируется в отчёте ревью, см. docs/kits/SAFETY-NET.md, «Что делать при
22
+ # расхождении» (п.2).
23
+
24
+ [importlinter]
25
+ # include_external_packages нужен: forbidden_modules перечисляет пакеты,
26
+ # внешние относительно root_packages.
27
+ include_external_packages = True
28
+ root_packages =
29
+ skillkit
30
+ exclude_type_checking_imports = True
31
+
32
+ [importlinter:contract:no-undeclared-kits]
33
+ name = skillkit не импортирует киты, которых нет в его зависимостях
34
+ type = forbidden
35
+ source_modules =
36
+ skillkit
37
+ forbidden_modules =
38
+ accountpoolkit
39
+ adapterkit
40
+ agentskit
41
+ aichatkit
42
+ authkit_client
43
+ authkit_contracts
44
+ authkit_server
45
+ b24kit
46
+ browserkit
47
+ chatkit
48
+ clientkit
49
+ corekit
50
+ emojikit
51
+ gitkit
52
+ installerkit
53
+ iokit
54
+ issuekit
55
+ leasekit
56
+ maxkit
57
+ modelkit
58
+ netkit
59
+ orchestrationkit
60
+ ormkit
61
+ persistkit
62
+ pluginkit
63
+ replicationkit
64
+ servicekit
65
+ sessionkit
66
+ socialkit
67
+ storagekit
68
+ totp_client
69
+ worker_service
@@ -0,0 +1,12 @@
1
+ # Исключения для секрет-скана s-skillgate перед push. Глобы — от корня репо.
2
+ #
3
+ # scripts/check_dist_leaks.py — сам гейт утечки личных данных (сетка
4
+ # безопасности китов, docs/kits/SAFETY-NET.md в devcontour), копия из
5
+ # tools/kits/template/check_dist_leaks.py. Ловит по классам, не по строкам:
6
+ # windows-путь с числовым именем пользователя, личный ящик на публичном
7
+ # провайдере, юникс-домашний путь. Regex-паттерны и пример подсказки
8
+ # (windows-путь с числовым account, «/home/user») по определению совпадают
9
+ # с собственным денилистом — иначе гейт не проверял бы то, ради чего написан (та же
10
+ # ситуация, что и с tests/golden/ у самого check_dist_leaks.py). Файл
11
+ # копируется буквально из канона — правки идут в шаблон, не сюда.
12
+ scripts/check_dist_leaks.py
@@ -4,7 +4,69 @@
4
4
  [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/); версионирование —
5
5
  [SemVer](https://semver.org/lang/ru/).
6
6
 
7
- ## [Unreleased]
7
+ ## [0.6.2] - 2026-10-14
8
+
9
+ ### Fixed
10
+
11
+ - Verify published payload bytes before hub updates and again before committing staged content; preserve local edits and refuse unknown baselines even with force.
12
+ - Preserve disabled managed MCP entries when updating their commands.
13
+ - Skip filesystem writes for verified current copy projections.
14
+ - Fetch Git releases without inherited newline conversion so Windows and Linux receive the same published bytes.
15
+
16
+ ### Added
17
+
18
+ - Native DeepSeek Harness skill installation roots with DSH_HOME support.
19
+ - Managed copy projections for agents running under Windows redirection restrictions, with conflict protection and explicit CODEX_HOME support.
20
+
21
+ ## [0.6.1] — 2026-09-09
22
+
23
+ ### Исправлено
24
+
25
+ - **`ClaudeCodeTarget.mcp_config()` больше не игнорирует подменённый `root`.**
26
+ Global-путь считался от `Path.home()`, поэтому прогон тестов кита писал
27
+ «чужой» образец `["важные", "данные", "пользователя"]` в НАСТОЯЩИЙ
28
+ `~/.claude.json` разработчика. Claude Code читал массив, превращал его в
29
+ ключи `"0"/"1"/"2"` и дописывал своё — список доверенных проектов пропадал, и
30
+ диалог «Trust this workspace?» возвращался на уже доверенных папках. На живой
31
+ машине это случилось дважды за час. Боевое поведение не меняется: по
32
+ умолчанию `root` = `~/.claude`, его родитель — тот же дом.
33
+ - **Сторож песочницы** (`test_podmenennyi_root_uvodit_vse_puti_v_pesochnitsu`):
34
+ при подменённом `root` ни один путь цели — ни `base_dir`, ни `slug_dir`, ни
35
+ дескрипторы MCP и хуков — не ведёт наружу. Проверяются ВСЕ цели разом:
36
+ соседний `hook_config` правило соблюдал и даже объяснял его в докстринге, так
37
+ что подвела именно помодульная бдительность.
38
+
39
+ ## [0.6.0] — 2026-09-09
40
+
41
+ ### Удалено (ломающее)
42
+
43
+ - **`skillkit.plugin_register`** — движок «плагин как единица поставки»
44
+ (манифест `plugin.json` + запись в реестр агента). Ноль потребителей во всём
45
+ портфеле, ноль публичной поверхности: нет ни в README, ни в `__all__`, ни в
46
+ `__init__`, ни в entry-points — причём групп entry-points у кита нет вовсе.
47
+ Написан 30.08.2026 одним коммитом и больше не трогался. Нишу занял живой
48
+ `pluginkit` с четырьмя потребителями (gateway, aichatkit, adapterkit, atlas):
49
+ формально он про python-пакеты, а не про `plugin.json` в каталоге агента, —
50
+ но второй незанятый движок в той же нише дороже, чем отсутствие обоих.
51
+ - **`PluginDescriptor` и методы `plugin_config`** в `targets/base.py`,
52
+ `targets/claude_code.py`, `targets/antigravity.py` — хвост, который держался
53
+ только на удалённом модуле. Убран тем же комплектом: иначе в ките осталась бы
54
+ раскладка плагинов, которую некому прочитать.
55
+
56
+ Ломающее для тех, кто аннотировал `PluginDescriptor` или переопределял
57
+ `plugin_config` в своей цели. Таких в портфеле нет (проверено грепом), но
58
+ поверхность целей публична, поэтому минор, а не патч (Atlas #2835).
59
+
60
+ ## [0.5.0] — 2026-09-08
61
+
62
+ ### Добавлено
63
+
64
+ - **`skillkit.installer_cli`** — установщик навыков переехал сюда из псевдокита
65
+ `s-installerkit` (волна 5, Atlas #2710). Зависимость объявлена ОПЦИОНАЛЬНЫМ
66
+ extra `installer_cli`: он тянет сеть, ключи и хранилище паролей, а базовый
67
+ `pip install s-skillkit` должен оставаться без них.
68
+ - Два сырых вызова подпроцесса в перенесённом коде переведены на `skillkit.proc.run`,
69
+ отсоединённый запуск самообновления вынесен в отдельный разрешённый модуль.
8
70
 
9
71
  ## [0.4.1] — 2026-09-01
10
72
 
@@ -78,6 +140,27 @@ ImportError: cannot import name 'IAgentTarget' from 'skillkit.targets'
78
140
  положил бы этот же навык сейчас. Повторная установка ТОГО ЖЕ навыка (в т.ч. с
79
141
  новым entrypoint/config) проходит как раньше.
80
142
 
143
+ ## [0.4.0] — 2026-09-01
144
+
145
+ Выпуск без отдельной записи в журнале на момент публикации. Изменения между `v0.3.7` и `v0.4.0` — по истории коммитов:
146
+
147
+ - IAgentTarget → AgentTarget: контракт без венгерского префикса (lib#667) (ce15ab5)
148
+ - changelog навыка можно держать файлом, а не строкой в TOML (f31a516)
149
+ - skillkit: богатые поля frontmatter Claude доезжают до манифеста (#2430) (54b5c74)
150
+ - skillkit: плагин как единица поставки — манифест плюс реестр (#2431) (6298cdf)
151
+ - docs/adr: журнал архитектурных решений заведён (#807) (951b39f)
152
+ - Канон навыка переехал в кит: один источник вместо трёх (#162) (39d73ae)
153
+
154
+ ## [0.3.7] — 2026-08-25
155
+
156
+ Выпуск без отдельной записи в журнале на момент публикации. Изменения между `v0.3.6` и `v0.3.7` — по истории коммитов:
157
+
158
+ - fix(владение): CLI-команда и MCP-сервер не перехватываются чужим навыком (#2272) (6480860)
159
+ - test(владение): три случая перехвата артефактов + идемпотентность (#2272) (faf534b)
160
+ - docs(владение): CHANGELOG + докстринги модулей про гейт принадлежности (#2272) (5dc6183)
161
+ - merge(#2272): артефакт навыка не перехватывается чужим — команда и MCP-сервер под владением (d6cefbf)
162
+ - chore(release): s-skillkit 0.3.7 — владение артефактами навыка (6dcf7de)
163
+
81
164
  ## [0.3.6]
82
165
 
83
166
  ### Changed — своя политика запуска подпроцессов, s-librarykit убран (#1644)
@@ -179,6 +262,34 @@ ImportError: cannot import name 'IAgentTarget' from 'skillkit.targets'
179
262
  `install_from_path` не изменилась. Миграция уже установленных сторов — на
180
263
  стороне CLI (признак: `source == "local-path"` при непустом `skill_id`).
181
264
 
265
+ ## [0.3.4] — 2026-07-28
266
+
267
+ Выпуск без отдельной записи в журнале на момент публикации. Изменения между `v0.3.3` и `v0.3.4` — по истории коммитов:
268
+
269
+ - feat(telemetry): адаптер Skillery поверх нейтрального telemetrykit (0.3.4) (ea7390e)
270
+
271
+ ## [0.3.3] — 2026-07-27
272
+
273
+ Выпуск без отдельной записи в журнале на момент публикации. Изменения между `v0.3.2` и `v0.3.3` — по истории коммитов:
274
+
275
+ - feat: единый запуск процессов, .pkgsrc не течёт в зону агента, снапшот = hub (#1144 #1145 #1147) (1e5ac4a)
276
+
277
+ ## [0.3.2] — 2026-07-22
278
+
279
+ Выпуск без отдельной записи в журнале на момент публикации. Изменения между `v0.2.1` и `v0.3.2` — по истории коммитов:
280
+
281
+ - @ fix: монорепо-навык (skill_path) + preserved_paths из манифеста + детект менеджера (b8a9bda)
282
+ - fix(antigravity): цель писала в путь, который агент не читает (067c840)
283
+ - feat(hooks): навык объявляет хук в манифесте; путь .antigravity убран совсем (4d093a2)
284
+ - fix(targets)!: раскладки навыков по доказанной таблице (agy/opencode/codex) (1b6ec80)
285
+ - fix(remove)!: кит удаляет только своё + миграция старого канона Codex + лок (9cb7d60)
286
+ - fix(ownership)!: гейт принадлежности — свойство ОПЕРАЦИИ + сирота .antigravity (круг 3) (1a14015)
287
+ - fix(ownership): маркер принадлежности в мете + детектор устойчив к алиасам (круг 4) (678bd85)
288
+ - fix(ownership): улика принадлежности строго по маркеру + детектор ловит свои модули (880aa18)
289
+ - fix(ownership): migrate штампует маркер владения для legacy-каталогов (круг 5) (58ceb0a)
290
+ - fix(fetcher): git clone без видимого окна на Windows (CREATE_NO_WINDOW) (#1028) (ab4eaf5)
291
+ - feat(targets): единый источник путей агентов + antigravity=.agents/skills; CI PyPI (b6ff6a8)
292
+
182
293
  ## [0.3.1] — 2026-07-21
183
294
 
184
295
  Круг 3 независимой проверки нашёл два настоящих дефекта в правках 0.3.0 и один
@@ -461,6 +572,27 @@ opencode её НЕ видит) доказывает, что модель не п
461
572
  установки под ТЕКУЩУЮ ОС и список реально доступных альтернатив. ИИ-агент
462
573
  может довести установку сам.
463
574
 
575
+ ## [0.2.1] — 2026-07-20
576
+
577
+ Выпуск без отдельной записи в журнале на момент публикации. Изменения до тега `v0.2.1` — по истории коммитов:
578
+
579
+ - feat: skillkit v0.1.0 — локальное ядро управления навыками (вырезано из Skillery CLI, cli-kits W7); sibling librarykit, 0 внешних завязок (4aa8ee2)
580
+ - feat: гибрид-модули (path_store/tooling/deps_installer/mcp_register/collections) из Skillery CLI — добивка W7; инъекция bin/config-провайдеров (c77c495)
581
+ - fix(deps): pip-установка с --upgrade — зависимости поднимаются при апдейте (gap B) (5d76a64)
582
+ - fix(installer): пустой files-инвентарь не затирает стор при update (#272 BUG-3) (e7bcb7e)
583
+ - chore(release): s-skillkit 0.1.2 (фикс BUG-3 #272 — пустой files-инвентарь не затирает стор) (230ab79)
584
+ - feat(installer): subdir-навык — материализация подпапки репо (#268) (4a479f3)
585
+ - chore(release): s-skillkit 0.1.3 (#268 subdir-навык: материализация подпапки репо) (e80b7c9)
586
+ - fix(manifest): build_manifest несёт kind/cli/mcp/runtime_dependencies (#271) (8f88a86)
587
+ - test(manifest): регресс на tooling-поля + TOML-порядок runtime_dependencies (#271) (582fdaa)
588
+ - fix(tooling): runtime_deps-CLI в выделенный venv + шим целит туда же (#271) (df9f16e)
589
+ - feat(config): SkillkitConfig + configure() — единая брендо-конфигурация (0.2.0) (b4366b0)
590
+ - chore(release): s-skillkit 0.1.5 — версия в патч-серии 0.1.x (не 0.2.0) (c15beb2)
591
+ - feat(installer): install_from_snapshot — установка навыка из tar.gz-слепка (4f8c748)
592
+ - feat(installer): транзакционный install (#437) + release 0.1.7 (e236c94)
593
+ - fix(manifest): folded YAML scalar (>) в _read_frontmatter + bump 0.1.8 (c5d26c1)
594
+ - …и ещё 14 коммит(ов), см. `git log v0.2.1`
595
+
464
596
  ## [0.2.0] — 2026-07-15
465
597
 
466
598
  ### Added — install-kit (установка навыка «под ключ» со ВСЕМИ зависимостями)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: s-skillkit
3
- Version: 0.4.1
3
+ Version: 0.6.2
4
4
  Summary: Локальное ядро управления навыками: install из git/локальной папки, junction/symlink-линковка в scope агента, .skillignore-фильтр, build manifest, project-манифест. 0 завязок на сеть/auth — stdlib + tomli-w + pathspec + platformdirs.
5
5
  Author: Dmitry
6
6
  License: MIT
@@ -8,11 +8,13 @@ License-File: LICENSE
8
8
  Requires-Python: >=3.11
9
9
  Requires-Dist: pathspec>=0.12.0
10
10
  Requires-Dist: platformdirs>=4.0
11
- Requires-Dist: s-telemetrykit>=0.2.0
11
+ Requires-Dist: s-telemetrykit<0.4,>=0.2.0
12
12
  Requires-Dist: tomli-w>=1.0
13
- Provides-Extra: dev
14
- Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
15
- Requires-Dist: pytest>=8; extra == 'dev'
13
+ Requires-Dist: typer>=0.15
14
+ Provides-Extra: installer-cli
15
+ Requires-Dist: s-clikit<0.3,>=0.1.6; extra == 'installer-cli'
16
+ Requires-Dist: s-librarykit<0.9; extra == 'installer-cli'
17
+ Requires-Dist: s-skillgate<0.2,>=0.1.0; extra == 'installer-cli'
16
18
  Description-Content-Type: text/markdown
17
19
 
18
20
  # s-skillkit