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.
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/CHANGELOG.md +65 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/PKG-INFO +9 -2
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/README.md +8 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/pyproject.toml +7 -8
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/__init__.py +5 -2
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/bootstrap.py +4 -6
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/config.py +14 -1
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/deps_installer.py +2 -4
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/__init__.py +1 -1
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/fetchers.py +2 -3
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/linker.py +2 -2
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/manifest.py +25 -1
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/path_store.py +197 -28
- s_skillkit-0.3.6/skillkit/proc.py +260 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/tooling.py +2 -4
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/uv_bootstrap.py +3 -5
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_errors.py +1 -1
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_manifest.py +45 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_no_raw_subprocess.py +9 -9
- s_skillkit-0.3.6/tests/test_path_store.py +582 -0
- s_skillkit-0.3.6/tests/test_proc.py +128 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_uv_bootstrap.py +1 -1
- s_skillkit-0.3.6/uv.lock +150 -0
- s_skillkit-0.3.4/tests/test_path_store.py +0 -320
- s_skillkit-0.3.4/uv.lock +0 -580
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/.gitignore +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/.gitlab-ci.yml +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/AGENTS.md +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/LICENSE +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/binary_installer.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/collections.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/errors.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/filter.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/hook_register.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/differ.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/fsops.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/meta.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/models.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/installer/ownership.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/mcp_register.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/paths.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/pkg_manager.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/project.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/__init__.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/antigravity.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/base.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/claude_code.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/codex.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/detect.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/targets/opencode.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/skillkit/telemetry.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/conftest.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_agent_skill_layouts_2026_07_21.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_binary_installer.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_bootstrap.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_collections.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_config.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_deps_binary.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_deps_installer.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_destructive_ownership_gate_2026_07_21.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_filter.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_git_install.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_hooks.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_installer.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_legacy_paths_no_orphans_2026_07_21.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_mcp_register.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_packaging_lock.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_paths.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_pkg_manager.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_pkgsrc_not_in_agent_zone.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_project.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_remove_ownership_guard_2026_07_21.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_stub_guard.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_targets.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_telemetry_adapter.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_tooling.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_transactional_install.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_traversal_guard.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_typed_fields.py +0 -0
- {s_skillkit-0.3.4 → s_skillkit-0.3.6}/tests/test_w268_subdir_skill.py +0 -0
- {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.
|
|
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.
|
|
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
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
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.
|
|
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
|
-
Оба примитива — обёртки над ``
|
|
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
|
|
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`` — это
|
|
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
|
-
Запуск идёт ТОЛЬКО через ``
|
|
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
|
|
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) — их гоняет ``
|
|
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 идёт через ``
|
|
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
|
|
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
|
|
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`` — одна операция ФС; секунды. Запуск через ``
|
|
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
|
|
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
|
)
|