capt-hook 6.2.0__tar.gz → 6.4.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-6.2.0 → capt_hook-6.4.0}/PKG-INFO +1 -1
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/cli.py +3 -1
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/context.py +4 -3
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/durable.py +1 -8
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/loader.py +5 -6
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/general/capt-hook.toml +1 -1
- capt_hook-6.4.0/captain_hook/packs/general/models.py +734 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/manager.py +2 -2
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/primitives/llm.py +4 -4
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/prompt.py +5 -6
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/session.py +0 -6
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/settings.py +14 -9
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/state.py +0 -2
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/testing/helpers.py +60 -44
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/testing/session_cache.py +3 -1
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/util/model_cache.py +2 -3
- {capt_hook-6.2.0 → capt_hook-6.4.0}/pyproject.toml +1 -1
- capt_hook-6.2.0/captain_hook/packs/general/models.py +0 -378
- {capt_hook-6.2.0 → capt_hook-6.4.0}/LICENSE +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/README.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/.claude-plugin/plugin.json +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/__main__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/app.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/ast_grep.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/classifiers/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/classifiers/conductor.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/classifiers/droid.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/classifiers/native.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/command.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/conditions.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/contexts.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/decisions.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/dispatch.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/events.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/fields.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/file.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/log.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/general/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/general/_lib.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/general/commands.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/general/docs.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/general/plans.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/general/prompts.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/general/review.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/general/tasks.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/general/tombstones.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/go/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/go/capt-hook.toml +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/go/testing.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/go/toolchain.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/python/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/python/capt-hook.toml +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/python/style.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/python/testing.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/python/toolchain.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/steering/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/steering/capt-hook.toml +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/packs/steering/steering.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/primitives/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/primitives/commands.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/primitives/lint.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/primitives/nudge.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/primitives/rewrite.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/primitives/workflow.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/py.typed +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/review/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/review/cli.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/review/dashboard.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/review/fix.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/review/formats.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/review/judge.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/review/pipeline.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/review/repo.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/review/scan.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/review/settings.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/review/store.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/review/sync.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/signals/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/signals/nlp.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/authoring-hooks/SKILL.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/authoring-hooks/references/capt-hook-api.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/authoring-hooks/references/pattern-catalog.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/authoring-hooks/references/pitfalls.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/authoring-hooks/references/testing-hooks.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/bootstrapping-hooks/SKILL.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/scanning-sessions/SKILL.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/scanning-sessions/references/pr-workflow.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/scanning-sessions/references/review-cli.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/translating-styleguides/SKILL.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/translating-styleguides/references/llm-rule-patterns.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/translating-styleguides/references/matcher-reference.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/skills/translating-styleguides/references/tier-rubric.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/style/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/style/ast_grep.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/style/matchers.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/style/scope.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/style/types.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/tasks.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/templates/example_hook.py.tmpl +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/testing/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/testing/types.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/types.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/util/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/util/fs.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/util/http.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.4.0}/captain_hook/util/text.py +0 -0
|
@@ -501,7 +501,9 @@ def run_tests(json_output: bool = False) -> None:
|
|
|
501
501
|
@click.pass_context
|
|
502
502
|
def cli(ctx: click.Context, hooks: str | None, root_path: str | None) -> None:
|
|
503
503
|
"""Captain Hook — declarative hook framework for Claude Code lifecycle events."""
|
|
504
|
-
|
|
504
|
+
from captain_hook.settings import resolve_project_dir
|
|
505
|
+
|
|
506
|
+
root = Path(root_path) if root_path else Path(p) if (p := resolve_project_dir()) else Path.cwd()
|
|
505
507
|
ctx.obj = CliState(root=root, hooks=hooks or str(root / ".claude" / "hooks"))
|
|
506
508
|
|
|
507
509
|
|
|
@@ -21,6 +21,7 @@ from spawnllm.proc import run_cli
|
|
|
21
21
|
from captain_hook.classifiers import detect
|
|
22
22
|
from captain_hook.prompt import Prompt
|
|
23
23
|
from captain_hook.session import SessionStore
|
|
24
|
+
from captain_hook.settings import resolve_project_dir
|
|
24
25
|
|
|
25
26
|
if TYPE_CHECKING:
|
|
26
27
|
from collections.abc import Sequence
|
|
@@ -78,7 +79,7 @@ def lift_session(events: Sequence[TranscriptEvent], *, path: Path | None = None)
|
|
|
78
79
|
from captain_hook.app import _state
|
|
79
80
|
|
|
80
81
|
classifier = _state.classifier or detect(
|
|
81
|
-
cwd=
|
|
82
|
+
cwd=resolve_project_dir(),
|
|
82
83
|
transcript_path=str(path) if path else None,
|
|
83
84
|
events=events,
|
|
84
85
|
)
|
|
@@ -185,7 +186,7 @@ class HookContext:
|
|
|
185
186
|
input=input,
|
|
186
187
|
timeout=timeout,
|
|
187
188
|
env=os.environ | (env or {}),
|
|
188
|
-
cwd=
|
|
189
|
+
cwd=resolve_project_dir(),
|
|
189
190
|
)
|
|
190
191
|
except (OSError, subprocess.SubprocessError):
|
|
191
192
|
if throw:
|
|
@@ -309,7 +310,7 @@ class HookContext:
|
|
|
309
310
|
) -> str | BaseModel:
|
|
310
311
|
diff_text = self.diff("uncommitted" if diff is True else diff) if diff else None
|
|
311
312
|
prompt = self.assemble_prompt(template, args, kwargs, transcript=transcript, diff_text=diff_text)
|
|
312
|
-
cwd =
|
|
313
|
+
cwd = resolve_project_dir()
|
|
313
314
|
if response_model is not None:
|
|
314
315
|
return extract_sync(
|
|
315
316
|
prompt, response_model, specialty=specialty, model=model, agent=agent, cwd=cwd, timeout=timeout
|
|
@@ -26,13 +26,11 @@ if TYPE_CHECKING:
|
|
|
26
26
|
|
|
27
27
|
Scope = Literal["project", "global"]
|
|
28
28
|
|
|
29
|
-
DURABLE_ROOT_OVERRIDE: list[Path] = []
|
|
30
|
-
|
|
31
29
|
|
|
32
30
|
def durable_root() -> Path:
|
|
33
31
|
from captain_hook.settings import resolve_state_dir
|
|
34
32
|
|
|
35
|
-
return
|
|
33
|
+
return resolve_state_dir() / "hooks" / "durable"
|
|
36
34
|
|
|
37
35
|
|
|
38
36
|
def project_key(repo_root: Path) -> str:
|
|
@@ -98,11 +96,6 @@ class DurableStore:
|
|
|
98
96
|
if model not in cls.TRACKED:
|
|
99
97
|
cls.TRACKED.append(model)
|
|
100
98
|
|
|
101
|
-
@classmethod
|
|
102
|
-
def untrack(cls, model: type[BaseModel]) -> None:
|
|
103
|
-
if model in cls.TRACKED:
|
|
104
|
-
cls.TRACKED.remove(model)
|
|
105
|
-
|
|
106
99
|
@classmethod
|
|
107
100
|
def tracked_models(cls) -> Sequence[type[BaseModel]]:
|
|
108
101
|
return tuple(cls.TRACKED)
|
|
@@ -13,7 +13,7 @@ from typing import TYPE_CHECKING
|
|
|
13
13
|
|
|
14
14
|
from loguru import logger
|
|
15
15
|
|
|
16
|
-
from captain_hook.app import
|
|
16
|
+
from captain_hook.app import _state, on
|
|
17
17
|
from captain_hook.settings import build_settings
|
|
18
18
|
from captain_hook.types import Event
|
|
19
19
|
|
|
@@ -47,8 +47,7 @@ def import_or_reload(fqn: str, fresh_this_pass: set[str]) -> ModuleType:
|
|
|
47
47
|
return mod
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
def discover_hooks(hooks_dir: str | Path
|
|
51
|
-
target = state or _state
|
|
50
|
+
def discover_hooks(hooks_dir: str | Path) -> None:
|
|
52
51
|
hooks_path = Path(hooks_dir).resolve()
|
|
53
52
|
if str(hooks_path.parent) not in sys.path:
|
|
54
53
|
sys.path.insert(0, str(hooks_path.parent))
|
|
@@ -60,9 +59,9 @@ def discover_hooks(hooks_dir: str | Path, state: State | None = None) -> None:
|
|
|
60
59
|
|
|
61
60
|
if CONF_MODULE in top_level:
|
|
62
61
|
conf_module = import_or_reload(f"{pkg}.{CONF_MODULE}", fresh_this_pass)
|
|
63
|
-
|
|
62
|
+
_state.settings = build_settings(conf_module)
|
|
64
63
|
if classifier := getattr(conf_module, "classifier", None):
|
|
65
|
-
|
|
64
|
+
_state.classifier = classifier
|
|
66
65
|
|
|
67
66
|
all_modules = {
|
|
68
67
|
info.name
|
|
@@ -80,7 +79,7 @@ def discover_hooks(hooks_dir: str | Path, state: State | None = None) -> None:
|
|
|
80
79
|
import_or_reload(fqn, fresh_this_pass)
|
|
81
80
|
except Exception as exc:
|
|
82
81
|
logger.bind(module=fqn).opt(exception=True).warning("skipped unloadable hook module")
|
|
83
|
-
|
|
82
|
+
_state.load_errors.append((fqn, exc))
|
|
84
83
|
|
|
85
84
|
|
|
86
85
|
def ensure_pack_package(fqn: str, search_paths: list[str]) -> ModuleType:
|