s-skillkit 0.3.4__tar.gz → 0.3.6__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 (81) hide show
  1. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/CHANGELOG.md +65 -0
  2. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/PKG-INFO +9 -2
  3. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/README.md +8 -0
  4. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/pyproject.toml +7 -8
  5. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/__init__.py +5 -2
  6. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/bootstrap.py +4 -6
  7. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/config.py +14 -1
  8. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/deps_installer.py +2 -4
  9. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/__init__.py +1 -1
  10. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/fetchers.py +2 -3
  11. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/linker.py +2 -2
  12. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/manifest.py +25 -1
  13. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/path_store.py +197 -28
  14. s_skillkit-0.3.6/skillkit/proc.py +260 -0
  15. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/tooling.py +2 -4
  16. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/uv_bootstrap.py +3 -5
  17. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_errors.py +1 -1
  18. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_manifest.py +45 -0
  19. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_no_raw_subprocess.py +9 -9
  20. s_skillkit-0.3.6/tests/test_path_store.py +582 -0
  21. s_skillkit-0.3.6/tests/test_proc.py +128 -0
  22. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_uv_bootstrap.py +1 -1
  23. s_skillkit-0.3.6/uv.lock +150 -0
  24. s_skillkit-0.3.4/tests/test_path_store.py +0 -320
  25. s_skillkit-0.3.4/uv.lock +0 -580
  26. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/.gitignore +0 -0
  27. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/.gitlab-ci.yml +0 -0
  28. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/AGENTS.md +0 -0
  29. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/LICENSE +0 -0
  30. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/binary_installer.py +0 -0
  31. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/collections.py +0 -0
  32. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/errors.py +0 -0
  33. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/filter.py +0 -0
  34. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/hook_register.py +0 -0
  35. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/differ.py +0 -0
  36. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/fsops.py +0 -0
  37. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/meta.py +0 -0
  38. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/models.py +0 -0
  39. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/ownership.py +0 -0
  40. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/mcp_register.py +0 -0
  41. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/paths.py +0 -0
  42. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/pkg_manager.py +0 -0
  43. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/project.py +0 -0
  44. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/__init__.py +0 -0
  45. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/antigravity.py +0 -0
  46. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/base.py +0 -0
  47. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/claude_code.py +0 -0
  48. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/codex.py +0 -0
  49. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/detect.py +0 -0
  50. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/opencode.py +0 -0
  51. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/telemetry.py +0 -0
  52. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/conftest.py +0 -0
  53. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_agent_skill_layouts_2026_07_21.py +0 -0
  54. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_binary_installer.py +0 -0
  55. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_bootstrap.py +0 -0
  56. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_collections.py +0 -0
  57. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_config.py +0 -0
  58. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_deps_binary.py +0 -0
  59. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_deps_installer.py +0 -0
  60. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_destructive_ownership_gate_2026_07_21.py +0 -0
  61. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_filter.py +0 -0
  62. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_git_install.py +0 -0
  63. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_hooks.py +0 -0
  64. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_installer.py +0 -0
  65. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_legacy_paths_no_orphans_2026_07_21.py +0 -0
  66. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_mcp_register.py +0 -0
  67. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_packaging_lock.py +0 -0
  68. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_paths.py +0 -0
  69. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_pkg_manager.py +0 -0
  70. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_pkgsrc_not_in_agent_zone.py +0 -0
  71. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_project.py +0 -0
  72. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_remove_ownership_guard_2026_07_21.py +0 -0
  73. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_stub_guard.py +0 -0
  74. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_targets.py +0 -0
  75. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_telemetry_adapter.py +0 -0
  76. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_tooling.py +0 -0
  77. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_transactional_install.py +0 -0
  78. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_traversal_guard.py +0 -0
  79. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_typed_fields.py +0 -0
  80. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_w268_subdir_skill.py +0 -0
  81. {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_w272_empty_manifest_guard.py +0 -0
@@ -4,6 +4,71 @@
4
4
  [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/); версионирование —
5
5
  [SemVer](https://semver.org/lang/ru/).
6
6
 
7
+ ## [0.3.6]
8
+
9
+ ### Changed — своя политика запуска подпроцессов, s-librarykit убран (#1644)
10
+
11
+ - **Кит перестал тянуть `s-librarykit`.** Зависимость стояла ТОЛЬКО ради
12
+ `librarykit.proc` (восемь вызовов `run`), а вместе с ней в установку приезжали
13
+ httpx / cryptography / keyring — сетевой и криптографический стек в ките,
14
+ который в манифесте обещает «stdlib + tomli-w + pathspec + platformdirs», в
15
+ сеть не ходит и про auth не знает. Обещание манифеста и факт установки
16
+ разъезжались.
17
+ - **Появился `skillkit.proc` — перенесённый МИНИМУМ на stdlib.** Ровно то, что
18
+ кит реально зовёт: синхронный `run` с `timeout` (обязательный keyword-only),
19
+ `cwd`, `log`, `check`; `CREATE_NO_WINDOW` на Windows; `ProcResult` с
20
+ `ok`/`timed_out`. НЕ переносились долгоживущий `popen`, `env`, `text=False`,
21
+ `allow_console` и полный движок маскировки — ни один вызов кита их не
22
+ использует, а мёртвый код пришлось бы поддерживать. Маскировка сведена к тому,
23
+ что здесь действительно нужно: креды внутри URL (`git clone` по URL с токеном).
24
+ - **Форма результата сохранена один в один**, поэтому вызывающий код (bootstrap,
25
+ deps_installer, fetchers, linker, manifest, tooling, uv_bootstrap) не менялся —
26
+ только импорт. Прежний seam тестов (`monkeypatch` на `subprocess.run`) тоже
27
+ продолжает работать: `skillkit.proc` зовёт тот же stdlib-модуль.
28
+ - **Гейты.** Allowlist «прямого subprocess» теперь содержит ровно один модуль —
29
+ сам `skillkit/proc.py`; добавлены тесты, что `librarykit` не вернётся ни в
30
+ зависимости `pyproject.toml`, ни в импорты пакета.
31
+
32
+ ## [0.3.5]
33
+
34
+ ### Changed — shim навыка ведёт вызов через раннер учёта (#1221)
35
+
36
+ - **Учёт вызова навыка стал НЕОБХОДИМЫМ, а не зависящим от модели.** Раньше
37
+ событие «навыком воспользовались» появлялось, только если LLM вспоминала
38
+ позвать обёртку — метрика «запуски» фактически равнялась числу установок.
39
+ Теперь shim, который кладёт `add_cli`, зовёт раннер потребителя:
40
+ `<runner> run <skill_slug> --command <command_name> <аргументы как есть>`.
41
+ Учёт срабатывает при ЛЮБОМ вызове (`vk …`, `atlas …`), включая уже
42
+ опубликованные навыки — их `SKILL.md` править не нужно.
43
+ - **Fallback обязателен.** Кит самостоятелен и может использоваться без CLI.
44
+ Проверка «есть ли раннер в PATH» делается ВНУТРИ shim'а (`where` на Windows,
45
+ `command -v` на POSIX), а не при генерации: PATH меняется после установки.
46
+ Нет раннера → прямой вызов entrypoint, как раньше. Навык не имеет права
47
+ перестать работать из-за отсутствия учёта.
48
+ - **Антирекурсия.** Раннер обязан запускать entrypoint из sidecar'а НАПРЯМУЮ
49
+ (sidecar по-прежнему хранит прямой entrypoint — это источник правды) и
50
+ выставлять дочернему процессу маркер `<APP>_RUN_ACTIVE`. Shim, увидев маркер,
51
+ уходит на прямой вызов. Без обоих предохранителей пара «shim → раннер → shim»
52
+ зациклилась бы и положила машину пользователя.
53
+ - **POSIX-shim больше НЕ symlink.** Даже на исполняемый entrypoint ставится
54
+ скрипт: symlink не носит логики и не может ни позвать раннер, ни проверить
55
+ маркер. `kind` в sidecar на POSIX теперь всегда `script`.
56
+ - **Новое: `path_store.regenerate_shims()`** — перегенерация шимов из
57
+ sidecar'ов. Нужна потому, что у пользователей УЖЕ лежат шимы старого формата:
58
+ без неё учёт включился бы только для новых установок. Проход
59
+ самосходящийся (`only_stale=True` трогает лишь шимы, ещё не ведущие через
60
+ раннер), маркера «мигрировано» не требует, битый sidecar соседа пропускает.
61
+ - **Новое в `SkillkitConfig`:** `runner_command` (None → `app_name`) и
62
+ `runner_guard_env` (None → выводится из имени раннера, `skillery` →
63
+ `SKILLERY_RUN_ACTIVE`). Точечные сеттеры — `path_store.set_runner`,
64
+ `path_store.runner_command()`, `path_store.guard_env_name()`.
65
+
66
+ ### Fixed
67
+
68
+ - `__version__` в `skillkit/__init__.py` отстал от `pyproject.toml` (0.3.2 при
69
+ выпущенных 0.3.3/0.3.4) — синхронизирован. Расхождение версии в двух местах
70
+ уже однажды дало бесконечную петлю самообновления CLI.
71
+
7
72
  ## [Unreleased]
8
73
 
9
74
  ### Fixed — окна консоли, `.pkgsrc` в зоне агента, потеря происхождения снапшота
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: s-skillkit
3
- Version: 0.3.4
3
+ Version: 0.3.6
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,7 +8,6 @@ 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-librarykit>=0.7.1
12
11
  Requires-Dist: s-telemetrykit>=0.2.0
13
12
  Requires-Dist: tomli-w>=1.0
14
13
  Provides-Extra: dev
@@ -127,6 +126,14 @@ version = "0.3.0"
127
126
  kind = "tooling" # prompt | comprehensive | tooling
128
127
  tags = ["pm", "cli"]
129
128
 
129
+ # Release notes ЭТОЙ версии — «что изменилось». Опционально: нет поля — нет
130
+ # release notes. Хаб сохраняет текст у версии навыка и показывает на странице
131
+ # версий. Можно строкой (в т.ч. многострочной """...""") или списком пунктов.
132
+ changelog = [
133
+ "Добавлен `atlas backlog` — пул сырых идей.",
134
+ "Починен триаж забытых задач.",
135
+ ]
136
+
130
137
  # ВАЖНО (TOML): top-level массивы объявляются ДО заголовков [[...]] —
131
138
  # иначе tomllib отнесёт ключ ВНУТРЬ таблицы, а не на верхний уровень.
132
139
  runtime_dependencies = [
@@ -109,6 +109,14 @@ version = "0.3.0"
109
109
  kind = "tooling" # prompt | comprehensive | tooling
110
110
  tags = ["pm", "cli"]
111
111
 
112
+ # Release notes ЭТОЙ версии — «что изменилось». Опционально: нет поля — нет
113
+ # release notes. Хаб сохраняет текст у версии навыка и показывает на странице
114
+ # версий. Можно строкой (в т.ч. многострочной """...""") или списком пунктов.
115
+ changelog = [
116
+ "Добавлен `atlas backlog` — пул сырых идей.",
117
+ "Починен триаж забытых задач.",
118
+ ]
119
+
112
120
  # ВАЖНО (TOML): top-level массивы объявляются ДО заголовков [[...]] —
113
121
  # иначе tomllib отнесёт ключ ВНУТРЬ таблицы, а не на верхний уровень.
114
122
  runtime_dependencies = [
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "s-skillkit"
3
- version = "0.3.4"
3
+ version = "0.3.6"
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" }
@@ -12,12 +12,12 @@ authors = [{ name = "Dmitry" }]
12
12
  # _skill_meta.toml ридеры используют stdlib tomllib на чтение);
13
13
  # pathspec — gitignore-стиль .skillignore / files-allowlist фильтр;
14
14
  # platformdirs — нативные дефолтные пути (Paths.default) по ОС;
15
- # s-librarykit — ТОЛЬКО ради ``librarykit.proc`` (#1144): единая политика запуска
16
- # подпроцессов. Кит запускает uv/git/npm/powershell, а на Windows консольный
17
- # ребёнок демона (у него нет своей консоли) без CREATE_NO_WINDOW получает
18
- # ВИДИМОЕ окно поверх браузера; ``capture_output`` его не подавляет. Своей
19
- # второй реализации «как правильно на Windows» в ките быть не должно —
20
- # поэтому прежний статус «sibling, ни от чего не зависим» осознанно снят.
15
+ # s-librarykit УБРАН (#1644): он тянулся ТОЛЬКО ради ``librarykit.proc``, а с
16
+ # ним приезжали httpx / cryptography / keyring — сетевой и криптографический
17
+ # стек в ките, который в сеть не ходит и про auth не знает. Нужный минимум
18
+ # (CREATE_NO_WINDOW + обязательный таймаут + ProcResult) перенесён в
19
+ # ``skillkit.proc`` на голом stdlib-``subprocess``; форма результата
20
+ # сохранена, вызывающий код не менялся.
21
21
  # s-telemetrykit — продуктово-нейтральный SDK учёта запусков. Кит нейтрален
22
22
  # намеренно (он переиспользуем в любом продукте), поэтому skillery-специфику
23
23
  # телеметрии — каталог ~/.skillery, префикс SKILLERY_*, канон _skill_meta.* и
@@ -28,7 +28,6 @@ dependencies = [
28
28
  "tomli-w>=1.0",
29
29
  "pathspec>=0.12.0",
30
30
  "platformdirs>=4.0",
31
- "s-librarykit>=0.7.1",
32
31
  "s-telemetrykit>=0.2.0",
33
32
  ]
34
33
 
@@ -1,7 +1,10 @@
1
1
  """skillkit — локальное ядро управления навыками (SIBLING librarykit).
2
2
 
3
3
  0 завязок на сеть/auth/librarykit: только stdlib + tomli-w + pathspec +
4
- platformdirs. Отвечает за ФС-механику навыка:
4
+ platformdirs. Запуск подпроцессов (uv/git/cmd/powershell) — свой ``skillkit.proc``
5
+ на stdlib (#1644): тянуть ради него весь ``s-librarykit`` значило приводить в
6
+ кит httpx/cryptography/keyring, которым тут делать нечего.
7
+ Отвечает за ФС-механику навыка:
5
8
 
6
9
  - ``SkillStore`` — материализация навыка в центральный стор (git clone /
7
10
  локальная папка / stub) + junction/symlink-линковка в scope агента,
@@ -116,7 +119,7 @@ from skillkit.targets import (
116
119
  )
117
120
  from skillkit.uv_bootstrap import ensure_uv
118
121
 
119
- __version__ = "0.3.2"
122
+ __version__ = "0.3.5"
120
123
 
121
124
  __all__ = [
122
125
  "__version__",
@@ -24,7 +24,7 @@ s-xray-gate). Кит НЕ зависит от него жёстко: это ``Ca
24
24
 
25
25
  Мокабельность: запуск идёт через ``_run_cmd`` (uv sync) и ``_run_capture``
26
26
  (self_check); поиск uv — через ``_which``; ОС — константа ``IS_WINDOWS``.
27
- Оба примитива — обёртки над ``librarykit.proc.run`` (#1144): на Windows он
27
+ Оба примитива — обёртки над ``skillkit.proc.run`` (#1144): на Windows он
28
28
  всегда ставит ``CREATE_NO_WINDOW`` (bootstrap зовёт демон, у которого нет своей
29
29
  консоли — иначе окна поверх браузера) и требует явный таймаут.
30
30
  """
@@ -37,11 +37,9 @@ from collections.abc import Callable
37
37
  from pathlib import Path
38
38
  from typing import Any
39
39
 
40
- from librarykit import proc
41
- from librarykit.proc import ProcResult
42
-
43
- from skillkit import deps_installer, uv_bootstrap
40
+ from skillkit import deps_installer, proc, uv_bootstrap
44
41
  from skillkit.deps_installer import _BINARY_KINDS
42
+ from skillkit.proc import ProcResult
45
43
 
46
44
  IS_WINDOWS = sys.platform == "win32"
47
45
 
@@ -145,7 +143,7 @@ def run_self_check(skill_dir: Path | str) -> tuple[bool, str]:
145
143
  script = skill_dir / "scripts" / "self_check.py"
146
144
  if not script.exists():
147
145
  return (False, f"scripts/self_check.py не найден в {skill_dir}")
148
- # Имя ``result``, а не ``proc``: модульный ``proc`` — это librarykit.proc.
146
+ # Имя ``result``, а не ``proc``: модульный ``proc`` — это skillkit.proc.
149
147
  result = _run_capture(_self_check_command(skill_dir, script), cwd=skill_dir)
150
148
  output = (result.stdout or "") + (result.stderr or "")
151
149
  return (result.returncode == 0, output)
@@ -59,6 +59,12 @@ class SkillkitConfig:
59
59
  rc_marker: str | None = None
60
60
  clone_prefix: str | None = None
61
61
  managed_by: str | None = None
62
+ # Раннер учёта вызовов навыка (#1221): исполняемое, которое зовёт shim как
63
+ # ``<runner> run <slug> --command <name> …``. None → app_name (у skillery
64
+ # это и есть имя CLI). ``runner_guard_env`` — маркер антирекурсии, None →
65
+ # выводится из имени раннера (``skillery`` → ``SKILLERY_RUN_ACTIVE``).
66
+ runner_command: str | None = None
67
+ runner_guard_env: str | None = None
62
68
  # Ленивые провайдеры каталогов (None → нативный platformdirs-дефолт).
63
69
  config_dir_provider: Callable[[], Path] | None = None
64
70
  bin_dir_provider: Callable[[], Path] | None = None
@@ -71,6 +77,10 @@ class SkillkitConfig:
71
77
  """Префикс временной папки git-clone (производный или явный)."""
72
78
  return self.clone_prefix or f"{self.app_name}-clone-"
73
79
 
80
+ def resolved_runner_command(self) -> str:
81
+ """Исполняемое раннера учёта вызовов (производное или явное)."""
82
+ return self.runner_command or self.app_name
83
+
74
84
  def resolved_managed_by(self) -> str:
75
85
  """Владелец управляемых папок (производный или явный)."""
76
86
  return self.managed_by or self.app_name
@@ -98,8 +108,11 @@ def configure(config: SkillkitConfig) -> None:
98
108
  project.set_manifest_rel_provider(project._default_manifest_rel)
99
109
  project.set_manifest_fallbacks(config.manifest_fallbacks)
100
110
 
101
- # 3. PATH-интеграция: rc-маркер + ленивый bin-каталог.
111
+ # 3. PATH-интеграция: rc-маркер + ленивый bin-каталог + раннер учёта.
102
112
  path_store.set_rc_marker(config.resolved_rc_marker())
113
+ path_store.set_runner(
114
+ config.resolved_runner_command(), guard_env=config.runner_guard_env
115
+ )
103
116
  path_store.set_bin_dir_provider(
104
117
  config.bin_dir_provider or path_store._default_bin_dir
105
118
  )
@@ -29,7 +29,7 @@
29
29
  ``_which`` для мокабельности) + ``python -m pip`` (текущий интерпретатор,
30
30
  работает на win/mac/linux). Примитив запуска ``_run`` тоже подменяем в тестах.
31
31
 
32
- Запуск идёт ТОЛЬКО через ``librarykit.proc.run`` (#1144): на Windows он всегда
32
+ Запуск идёт ТОЛЬКО через ``skillkit.proc.run`` (#1144): на Windows он всегда
33
33
  ставит ``CREATE_NO_WINDOW`` (иначе фоновая установка навыка демоном рисует
34
34
  пользователю окна ``uv.EXE`` поверх браузера) и требует явный таймаут — висящий
35
35
  ``uv`` в демоне некому прервать. Заодно снят прежний дефект: ``uv pip install``
@@ -43,9 +43,7 @@ import sys
43
43
  from pathlib import Path
44
44
  from typing import Any
45
45
 
46
- from librarykit import proc
47
-
48
- from skillkit import binary_installer
46
+ from skillkit import binary_installer, proc
49
47
  from skillkit.pkg_manager import detect_project, missing_manager_report
50
48
 
51
49
  _LOG = logging.getLogger(__name__)
@@ -30,7 +30,7 @@ import contextlib
30
30
  import logging
31
31
 
32
32
  # re-export seam: тесты патчат installer.subprocess.run. Сам кит подпроцессы
33
- # НЕ запускает напрямую (#1144) — их гоняет ``librarykit.proc.run``, который
33
+ # НЕ запускает напрямую (#1144) — их гоняет ``skillkit.proc.run``, который
34
34
  # внутри зовёт этот же stdlib-``subprocess``, поэтому патч продолжает работать.
35
35
  import subprocess # noqa: F401
36
36
  import tarfile
@@ -6,7 +6,7 @@
6
6
  позволяет подменить получение источника (офлайн-зеркало, кеш, фейк в тестах)
7
7
  НЕ трогая оркестратор ``SkillStore``.
8
8
 
9
- Запуск git идёт через ``librarykit.proc.run`` (#1144) — единая политика окон и
9
+ Запуск git идёт через ``skillkit.proc.run`` (#1144) — единая политика окон и
10
10
  таймаутов кита. Здесь исторически стоял ЕДИНСТВЕННЫЙ во всём ките
11
11
  ``CREATE_NO_WINDOW``; теперь флаг не дублируется в вызове, а приходит из ``proc``.
12
12
 
@@ -23,8 +23,7 @@ from collections.abc import Iterator
23
23
  from pathlib import Path
24
24
  from typing import Protocol, runtime_checkable
25
25
 
26
- from librarykit import proc
27
-
26
+ from skillkit import proc
28
27
  from skillkit.errors import CloneError
29
28
  from skillkit.installer.fsops import _force_rmtree
30
29
 
@@ -19,13 +19,13 @@ import stat
19
19
  import sys
20
20
  from pathlib import Path
21
21
 
22
- from librarykit import proc
22
+ from skillkit import proc
23
23
 
24
24
  IS_WINDOWS = sys.platform == "win32"
25
25
 
26
26
  _LOG = logging.getLogger(__name__)
27
27
 
28
- #: ``mklink /J`` — одна операция ФС; секунды. Запуск через ``librarykit.proc.run``
28
+ #: ``mklink /J`` — одна операция ФС; секунды. Запуск через ``skillkit.proc.run``
29
29
  #: (#1144): ``cmd.exe`` из демона без консоли иначе мигает окном пользователю.
30
30
  _MKLINK_TIMEOUT = 30.0
31
31
 
@@ -16,7 +16,7 @@ from dataclasses import dataclass, field
16
16
  from pathlib import Path
17
17
  from typing import Any
18
18
 
19
- from librarykit import proc
19
+ from skillkit import proc
20
20
 
21
21
  #: ``git rev-parse HEAD`` читает локальный .git — это секунды (#1144: запуск
22
22
  #: через ``proc.run``, на Windows без всплывающего окна консоли).
@@ -67,6 +67,10 @@ class BuiltManifest:
67
67
  # это пользователю/ИИ-агенту, чтобы тот сам довёл настройку до конца.
68
68
  # {"summary": str, "next_steps": [str, ...], "docs": str}
69
69
  onboarding: dict = field(default_factory=dict)
70
+ # Release notes ЭТОЙ версии — «что изменилось» (#1192). Свободный markdown
71
+ # либо список пунктов; хаб сохраняет его у версии навыка и показывает на
72
+ # странице версий. None ⇒ навык поле не объявил (норма).
73
+ changelog: str | None = None
70
74
 
71
75
 
72
76
  def _sha256_of(path: Path) -> str:
@@ -248,6 +252,25 @@ def _hooks(meta_toml: dict) -> list[dict]:
248
252
  return out
249
253
 
250
254
 
255
+ def _changelog(meta_toml: dict, fm: dict) -> str | None:
256
+ """Release notes версии из ``_skill_meta.toml`` > frontmatter (#1192).
257
+
258
+ Контракт нормализации как у ``onboarding``/``hooks``: поля нет — пусто
259
+ (None), мусор не роняет сборку манифеста. Список пунктов склеивается
260
+ переносами: release notes в TOML удобно писать массивом строк.
261
+ """
262
+ raw = meta_toml.get("changelog")
263
+ if raw is None:
264
+ raw = fm.get("changelog")
265
+ if raw is None:
266
+ return None
267
+ if isinstance(raw, (list, tuple)):
268
+ text = "\n".join(str(x).strip() for x in raw if str(x).strip())
269
+ else:
270
+ text = str(raw).strip()
271
+ return text or None
272
+
273
+
251
274
  def build_manifest(skill_dir: Path, *, version: str) -> BuiltManifest:
252
275
  if not skill_dir.is_dir():
253
276
  raise FileNotFoundError(f"Skill папка не найдена: {skill_dir}")
@@ -359,4 +382,5 @@ def build_manifest(skill_dir: Path, *, version: str) -> BuiltManifest:
359
382
  runtime_dependencies=runtime_deps,
360
383
  onboarding=onboarding,
361
384
  hooks=_hooks(meta_toml),
385
+ changelog=_changelog(meta_toml, fm),
362
386
  )