capt-hook 3.5.0__tar.gz → 3.6.0__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.
- {capt_hook-3.5.0 → capt_hook-3.6.0}/PKG-INFO +1 -1
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/manager.py +25 -9
- {capt_hook-3.5.0 → capt_hook-3.6.0}/pyproject.toml +1 -1
- {capt_hook-3.5.0 → capt_hook-3.6.0}/LICENSE +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/README.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/.claude-plugin/plugin.json +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/__init__.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/__main__.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/app.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/classifiers/__init__.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/classifiers/conductor.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/classifiers/droid.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/classifiers/native.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/cli.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/command.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/conditions.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/context.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/decisions.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/dispatch.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/events.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/file.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/llm/__init__.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/loader.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/log.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/__init__.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/general/capt-hook.toml +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/general/commands.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/general/docs.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/general/plans.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/general/prompts.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/general/review.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/general/stewardship.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/general/tasks.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/python/capt-hook.toml +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/python/style.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/python/testing.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/packs/python/toolchain.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/primitives/__init__.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/primitives/commands.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/primitives/lint.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/primitives/llm.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/primitives/nudge.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/primitives/workflow.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/prompt.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/py.typed +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/review/__init__.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/review/cli.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/review/dashboard.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/review/fix.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/review/formats.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/review/judge.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/review/pipeline.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/review/repo.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/review/scan.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/review/settings.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/review/store.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/review/sync.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/session.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/settings.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/signals/__init__.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/signals/nlp.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/authoring-hooks/SKILL.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/authoring-hooks/references/capt-hook-api.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/authoring-hooks/references/pattern-catalog.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/authoring-hooks/references/pitfalls.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/authoring-hooks/references/testing-hooks.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/bootstrapping-hooks/SKILL.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/scanning-sessions/SKILL.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/scanning-sessions/references/pr-workflow.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/scanning-sessions/references/review-cli.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/translating-styleguides/SKILL.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/translating-styleguides/references/llm-rule-patterns.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/translating-styleguides/references/matcher-reference.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/translating-styleguides/references/tier-rubric.md +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/state.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/style/__init__.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/style/matchers.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/style/scope.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/style/types.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/tasks.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/templates/example_hook.py.tmpl +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/testing/__init__.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/testing/helpers.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/testing/session_cache.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/testing/types.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/tests/__init__.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/tests/helpers.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/types.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/util/__init__.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/util/model_cache.py +0 -0
- {capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/utils.py +0 -0
|
@@ -27,6 +27,8 @@ from captain_hook import state
|
|
|
27
27
|
|
|
28
28
|
PACKS_TOML = "packs.toml"
|
|
29
29
|
PACK_MANIFEST = "capt-hook.toml"
|
|
30
|
+
# A pack's manifest may sit in .claude/ (preferred) or at the repo root.
|
|
31
|
+
MANIFEST_MEMBERS = (f".claude/{PACK_MANIFEST}", PACK_MANIFEST)
|
|
30
32
|
SHA_MARKER = ".sha"
|
|
31
33
|
SOURCE_RE = re.compile(r"^github:(?P<owner>[\w.-]+)/(?P<repo>[\w.-]+?)(?:@(?P<ref>[\w./-]+))?$")
|
|
32
34
|
PACK_NAME_RE = re.compile(r"[a-z][a-z0-9-]*")
|
|
@@ -102,6 +104,16 @@ def packs_toml_path(root: Path) -> Path:
|
|
|
102
104
|
return root / ".claude" / "hooks" / PACKS_TOML
|
|
103
105
|
|
|
104
106
|
|
|
107
|
+
def manifest_in(root: Path) -> Path:
|
|
108
|
+
"""Return the pack manifest path under root, preferring .claude/capt-hook.toml.
|
|
109
|
+
|
|
110
|
+
Falls back to the repo-root location. The returned path may not exist (the
|
|
111
|
+
canonical missing location), so PackManifest.load still fails loudly.
|
|
112
|
+
"""
|
|
113
|
+
claude = root / ".claude" / PACK_MANIFEST
|
|
114
|
+
return claude if claude.is_file() else root / PACK_MANIFEST
|
|
115
|
+
|
|
116
|
+
|
|
105
117
|
def parse_entry(name: str, table: dict[str, Any]) -> PackEntry:
|
|
106
118
|
match table:
|
|
107
119
|
case {"source": source, "commit": commit}:
|
|
@@ -175,17 +187,18 @@ def strip_top_level(tf: tarfile.TarFile) -> Iterator[tarfile.TarInfo]:
|
|
|
175
187
|
yield member
|
|
176
188
|
|
|
177
189
|
|
|
178
|
-
def members_under(members: list[tarfile.TarInfo], hooks: str) -> Iterator[tarfile.TarInfo]:
|
|
190
|
+
def members_under(members: list[tarfile.TarInfo], hooks: str, manifest_path: str) -> Iterator[tarfile.TarInfo]:
|
|
179
191
|
"""Yield the manifest plus members within the pack's hooks dir.
|
|
180
192
|
|
|
181
193
|
hooks == "." (hooks beside the manifest) selects the whole tree; a real
|
|
182
194
|
subdir selects only the manifest and that subtree, so the cache holds just
|
|
183
|
-
what the loader imports.
|
|
195
|
+
what the loader imports. The manifest is included by its actual archive path
|
|
196
|
+
so a .claude/ manifest survives without dragging in the rest of .claude/.
|
|
184
197
|
"""
|
|
185
198
|
rel = hooks.strip("/")
|
|
186
199
|
prefix = "" if rel in ("", ".") else rel + "/"
|
|
187
200
|
for m in members:
|
|
188
|
-
if m.path ==
|
|
201
|
+
if m.path == manifest_path or not prefix or m.path == rel or m.path.startswith(prefix):
|
|
189
202
|
yield m
|
|
190
203
|
|
|
191
204
|
|
|
@@ -203,12 +216,15 @@ def fetch_commit(source: PackSource, sha: str) -> ResolvedPack:
|
|
|
203
216
|
shutil.rmtree(staging)
|
|
204
217
|
with tarfile.open(tarball) as tf:
|
|
205
218
|
members = list(strip_top_level(tf))
|
|
206
|
-
|
|
219
|
+
by_path = {m.path: m for m in members}
|
|
220
|
+
manifest_member = next((by_path[p] for p in MANIFEST_MEMBERS if p in by_path), None)
|
|
207
221
|
if manifest_member is None:
|
|
208
222
|
raise PackError(f"pack manifest {PACK_MANIFEST} missing in {source}")
|
|
209
223
|
tf.extract(manifest_member, staging, filter="data")
|
|
210
|
-
manifest = PackManifest.load(staging /
|
|
211
|
-
tf.extractall(
|
|
224
|
+
manifest = PackManifest.load(staging / manifest_member.path)
|
|
225
|
+
tf.extractall(
|
|
226
|
+
staging, members=list(members_under(members, manifest.hooks, manifest_member.path)), filter="data"
|
|
227
|
+
)
|
|
212
228
|
final = root / f"{manifest.name}@{sha}"
|
|
213
229
|
if final.exists():
|
|
214
230
|
shutil.rmtree(final)
|
|
@@ -225,20 +241,20 @@ def fetch_pack(source: PackSource) -> ResolvedPack:
|
|
|
225
241
|
|
|
226
242
|
def builtin_packs() -> dict[str, Path]:
|
|
227
243
|
base = Path(str(importlib.resources.files("captain_hook") / "packs"))
|
|
228
|
-
return {p.name: p for p in base.iterdir() if p.is_dir() and (p
|
|
244
|
+
return {p.name: p for p in base.iterdir() if p.is_dir() and manifest_in(p).is_file()}
|
|
229
245
|
|
|
230
246
|
|
|
231
247
|
def resolve_builtin(name: str) -> ResolvedPack:
|
|
232
248
|
if not (pack_dir := builtin_packs().get(name)):
|
|
233
249
|
raise PackError(f"unknown builtin pack {name!r}; available: {', '.join(sorted(builtin_packs())) or 'none'}")
|
|
234
|
-
manifest = PackManifest.load(pack_dir
|
|
250
|
+
manifest = PackManifest.load(manifest_in(pack_dir))
|
|
235
251
|
return ResolvedPack(BuiltinPack(name=name), manifest.hooks_dir(pack_dir), manifest)
|
|
236
252
|
|
|
237
253
|
|
|
238
254
|
def resolve_external(entry: ExternalPack) -> ResolvedPack | None:
|
|
239
255
|
if not (cached := find_cached(entry.name, entry.commit)):
|
|
240
256
|
return None
|
|
241
|
-
manifest = PackManifest.load(cached
|
|
257
|
+
manifest = PackManifest.load(manifest_in(cached))
|
|
242
258
|
return ResolvedPack(entry, manifest.hooks_dir(cached), manifest)
|
|
243
259
|
|
|
244
260
|
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
{capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/authoring-hooks/references/capt-hook-api.md
RENAMED
|
File without changes
|
|
File without changes
|
{capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/authoring-hooks/references/pitfalls.md
RENAMED
|
File without changes
|
{capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/authoring-hooks/references/testing-hooks.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/scanning-sessions/references/pr-workflow.md
RENAMED
|
File without changes
|
{capt_hook-3.5.0 → capt_hook-3.6.0}/captain_hook/skills/scanning-sessions/references/review-cli.md
RENAMED
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|