s-skillkit 0.4.0__tar.gz → 0.4.1__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 (89) hide show
  1. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/CHANGELOG.md +22 -0
  2. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/PKG-INFO +1 -1
  3. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/pyproject.toml +1 -1
  4. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/targets/__init__.py +7 -0
  5. s_skillkit-0.4.1/tests/test_targets_public_names.py +83 -0
  6. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/.gitignore +0 -0
  7. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/.gitlab-ci.yml +0 -0
  8. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/AGENTS.md +0 -0
  9. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/LICENSE +0 -0
  10. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/README.md +0 -0
  11. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/docs/adr/0000-template.md +0 -0
  12. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/docs/adr/0001-kanon-navyka-zhivet-v-skillkit.md +0 -0
  13. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/docs/adr/README.md +0 -0
  14. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/__init__.py +0 -0
  15. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/binary_installer.py +0 -0
  16. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/bootstrap.py +0 -0
  17. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/canon.py +0 -0
  18. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/collections.py +0 -0
  19. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/config.py +0 -0
  20. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/deps_installer.py +0 -0
  21. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/errors.py +0 -0
  22. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/filter.py +0 -0
  23. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/hook_register.py +0 -0
  24. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/installer/__init__.py +0 -0
  25. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/installer/differ.py +0 -0
  26. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/installer/fetchers.py +0 -0
  27. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/installer/fsops.py +0 -0
  28. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/installer/meta.py +0 -0
  29. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/installer/models.py +0 -0
  30. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/installer/ownership.py +0 -0
  31. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/linker.py +0 -0
  32. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/manifest.py +0 -0
  33. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/mcp_register.py +0 -0
  34. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/path_store.py +0 -0
  35. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/paths.py +0 -0
  36. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/pkg_manager.py +0 -0
  37. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/plugin_register.py +0 -0
  38. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/proc.py +0 -0
  39. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/project.py +0 -0
  40. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/targets/antigravity.py +0 -0
  41. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/targets/base.py +0 -0
  42. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/targets/claude_code.py +0 -0
  43. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/targets/codex.py +0 -0
  44. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/targets/detect.py +0 -0
  45. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/targets/opencode.py +0 -0
  46. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/telemetry.py +0 -0
  47. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/tooling.py +0 -0
  48. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/skillkit/uv_bootstrap.py +0 -0
  49. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/conftest.py +0 -0
  50. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_agent_skill_layouts_2026_07_21.py +0 -0
  51. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_artifact_ownership_2272.py +0 -0
  52. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_binary_installer.py +0 -0
  53. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_bootstrap.py +0 -0
  54. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_canon.py +0 -0
  55. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_claude_frontmatter.py +0 -0
  56. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_collections.py +0 -0
  57. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_config.py +0 -0
  58. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_deps_binary.py +0 -0
  59. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_deps_installer.py +0 -0
  60. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_destructive_ownership_gate_2026_07_21.py +0 -0
  61. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_errors.py +0 -0
  62. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_filter.py +0 -0
  63. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_git_install.py +0 -0
  64. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_hooks.py +0 -0
  65. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_installer.py +0 -0
  66. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_legacy_paths_no_orphans_2026_07_21.py +0 -0
  67. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_manifest.py +0 -0
  68. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_mcp_register.py +0 -0
  69. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_no_raw_subprocess.py +0 -0
  70. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_packaging_lock.py +0 -0
  71. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_path_store.py +0 -0
  72. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_paths.py +0 -0
  73. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_pkg_manager.py +0 -0
  74. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_pkgsrc_not_in_agent_zone.py +0 -0
  75. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_plugin_register.py +0 -0
  76. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_proc.py +0 -0
  77. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_project.py +0 -0
  78. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_remove_ownership_guard_2026_07_21.py +0 -0
  79. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_stub_guard.py +0 -0
  80. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_targets.py +0 -0
  81. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_telemetry_adapter.py +0 -0
  82. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_tooling.py +0 -0
  83. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_transactional_install.py +0 -0
  84. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_traversal_guard.py +0 -0
  85. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_typed_fields.py +0 -0
  86. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_uv_bootstrap.py +0 -0
  87. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_w268_subdir_skill.py +0 -0
  88. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/tests/test_w272_empty_manifest_guard.py +0 -0
  89. {s_skillkit-0.4.0 → s_skillkit-0.4.1}/uv.lock +0 -0
@@ -6,6 +6,28 @@
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.4.1] — 2026-09-01
10
+
11
+ ### Fixed — `IAgentTarget` снова экспортируется из `skillkit.targets` (#2542)
12
+
13
+ Выпуск 0.4.0 уронил `skillery login` у пользователя с чистой установкой:
14
+
15
+ ```
16
+ from skillkit.targets import (
17
+ ImportError: cannot import name 'IAgentTarget' from 'skillkit.targets'
18
+ ```
19
+
20
+ Протокол переименовали `IAgentTarget` → `AgentTarget` (lib#667) и положили
21
+ совместимое имя в `skillkit/targets/base.py`. Этого оказалось мало: чужой код
22
+ зовёт имя **из пакета**, а не из модуля `base`. Теперь алиас реэкспортируется
23
+ пакетом и объявлен в его `__all__`.
24
+
25
+ Почему не поймали заранее: у разработчика в окружении стоял кит 0.3.7 (там ещё
26
+ старое имя и нет нового), а `s-skillkit` тянется с верхней границей открытой —
27
+ пользователь получил 0.4.0 и упал. Сторож `tests/test_targets_public_names.py`
28
+ теперь проверяет ровно тот импорт, на котором падал клиент.
29
+
30
+
9
31
  ### Added — канон навыка переехал в кит: `skillkit.canon` (#162)
10
32
 
11
33
  - **Один источник правды вместо трёх.** Форма навыка (раскладка `src/<пакет>/` +
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: s-skillkit
3
- Version: 0.4.0
3
+ Version: 0.4.1
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "s-skillkit"
3
- version = "0.4.0"
3
+ version = "0.4.1"
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" }
@@ -8,6 +8,12 @@ from skillkit.targets.base import (
8
8
  BaseAgentTarget,
9
9
  HookConfigDescriptor,
10
10
  AgentTarget,
11
+ #: Совместимое имя (lib#667, skl#2542). Протокол переименован из
12
+ #: `IAgentTarget`, но чужой код продолжает звать старое имя — и зовёт его
13
+ #: ИЗ ПАКЕТА, а не из `base`. Алиас в `base` без этой строки никого не спас:
14
+ #: 01.09.2026 выпуск 0.4.0 уронил `skillery login` у живого пользователя
15
+ #: с `cannot import name 'IAgentTarget' from 'skillkit.targets'`.
16
+ IAgentTarget,
11
17
  McpConfigDescriptor,
12
18
  )
13
19
  from skillkit.targets.claude_code import ClaudeCodeTarget
@@ -53,6 +59,7 @@ __all__ = [
53
59
  "CodexTarget",
54
60
  "HookConfigDescriptor",
55
61
  "AgentTarget",
62
+ "IAgentTarget",
56
63
  "McpConfigDescriptor",
57
64
  "OpenCodeTarget",
58
65
  "agent_skill_dir",
@@ -0,0 +1,83 @@
1
+ """Пакет `skillkit.targets` отдаёт оба имени протокола (skl#2542).
2
+
3
+ Прецедент 01.09.2026: протокол переименовали `IAgentTarget` → `AgentTarget`
4
+ (lib#667) и положили алиас в `skillkit/targets/base.py`. Этого оказалось мало —
5
+ чужой код зовёт имя ИЗ ПАКЕТА:
6
+
7
+ from skillkit.targets import IAgentTarget
8
+
9
+ Выпуск 0.4.0 уехал на PyPI и уронил `skillery login` у живого пользователя:
10
+ `ImportError: cannot import name 'IAgentTarget' from 'skillkit.targets'`.
11
+
12
+ Урок, ради которого написан файл: алиас обязан стоять там, ГДЕ ЕГО ИЩУТ. Тесты
13
+ кита импортировали из `base` — и потому молчали, пока клиент падал.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+
19
+ def test_оба_имени_есть_в_пакете():
20
+ """Ровно тот импорт, на котором упал пользователь."""
21
+ from skillkit.targets import AgentTarget, IAgentTarget # noqa: F401
22
+
23
+ assert IAgentTarget is AgentTarget, "алиас обязан быть ТЕМ ЖЕ объектом"
24
+
25
+
26
+ def test_оба_имени_есть_в_модуле_base():
27
+ """Старый путь импорта тоже жив: им пользуется код, писавшийся до пакета."""
28
+ from skillkit.targets.base import AgentTarget, IAgentTarget
29
+
30
+ assert IAgentTarget is AgentTarget
31
+
32
+
33
+ def test_имена_объявлены_в_all():
34
+ """`__all__` — обещание пакета. Имя, которого там нет, легко потерять при
35
+ следующей уборке экспорта: ровно так оно и потерялось."""
36
+ import skillkit.targets as пакет
37
+
38
+ assert "AgentTarget" in пакет.__all__
39
+ assert "IAgentTarget" in пакет.__all__
40
+
41
+
42
+ def test_алиас_виден_снаружи_как_атрибут():
43
+ """`from ... import` и `getattr` — разные пути; проверяем оба, потому что
44
+ потребители пользуются и тем, и другим."""
45
+ import skillkit.targets as пакет
46
+
47
+ assert getattr(пакет, "IAgentTarget", None) is пакет.AgentTarget
48
+
49
+
50
+ def test_алиас_остаётся_протоколом_а_не_заглушкой():
51
+ """Имя должно оставаться РАБОЧИМ протоколом, а не просто существовать.
52
+
53
+ Иначе импорт легко «починить» строкой-пустышкой и перенести беду на шаг
54
+ дальше от места правки — туда, где именем аннотируют или наследуются.
55
+
56
+ `isinstance` здесь НЕ проверяется намеренно: протокол объявлен без
57
+ `@runtime_checkable`, он для аннотаций, а не для проверок во время работы.
58
+ Первая версия этого теста звала isinstance и упала — ошибка была в ожидании,
59
+ а не в ките.
60
+ """
61
+ from typing import get_protocol_members, is_protocol
62
+
63
+ from skillkit.targets import IAgentTarget
64
+
65
+ assert is_protocol(IAgentTarget), "имя перестало быть протоколом"
66
+ члены = get_protocol_members(IAgentTarget)
67
+ assert "base_dir" in члены, f"протокол потерял ключевой метод, осталось: {sorted(члены)}"
68
+
69
+
70
+ def test_настоящая_цель_подходит_под_протокол():
71
+ """Проверка формы БЕЗ isinstance: у живой цели есть всё, что обещает контракт.
72
+
73
+ Так ловится расхождение протокола и реализации, ради которого протокол и
74
+ заводился, — но без требования делать его runtime_checkable.
75
+ """
76
+ from typing import get_protocol_members
77
+
78
+ from skillkit.targets import IAgentTarget, get_target
79
+
80
+ цель = get_target("claude_code")
81
+ нет = [и for и in get_protocol_members(IAgentTarget) if not hasattr(цель, и)]
82
+
83
+ assert not нет, f"цель claude_code не выполняет контракт: не хватает {нет}"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes