capt-hook 3.3.0__tar.gz → 3.3.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.
- {capt_hook-3.3.0 → capt_hook-3.3.1}/PKG-INFO +1 -1
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/cli.py +19 -12
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/review/cli.py +3 -1
- {capt_hook-3.3.0 → capt_hook-3.3.1}/pyproject.toml +1 -1
- {capt_hook-3.3.0 → capt_hook-3.3.1}/LICENSE +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/README.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/.claude-plugin/plugin.json +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/__init__.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/__main__.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/app.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/classifiers/__init__.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/classifiers/conductor.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/classifiers/droid.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/classifiers/native.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/command.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/conditions.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/context.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/decisions.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/dispatch.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/events.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/file.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/llm/__init__.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/loader.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/log.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/__init__.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/general/capt-hook.toml +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/general/commands.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/general/docs.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/general/plans.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/general/prompts.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/general/review.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/general/stewardship.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/general/tasks.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/manager.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/python/capt-hook.toml +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/python/style.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/python/testing.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/packs/python/toolchain.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/primitives/__init__.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/primitives/commands.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/primitives/lint.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/primitives/llm.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/primitives/nudge.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/primitives/workflow.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/prompt.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/py.typed +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/review/__init__.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/review/fix.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/review/formats.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/review/judge.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/review/pipeline.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/review/repo.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/review/scan.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/review/settings.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/review/store.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/review/sync.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/session.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/settings.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/signals/__init__.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/signals/nlp.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/authoring-hooks/SKILL.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/authoring-hooks/references/capt-hook-api.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/authoring-hooks/references/pattern-catalog.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/authoring-hooks/references/pitfalls.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/authoring-hooks/references/testing-hooks.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/bootstrapping-hooks/SKILL.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/scanning-sessions/SKILL.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/scanning-sessions/references/pr-workflow.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/scanning-sessions/references/review-cli.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/translating-styleguides/SKILL.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/translating-styleguides/references/llm-rule-patterns.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/translating-styleguides/references/matcher-reference.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/translating-styleguides/references/tier-rubric.md +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/state.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/style/__init__.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/style/matchers.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/style/scope.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/style/types.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/tasks.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/templates/example_hook.py.tmpl +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/testing/__init__.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/testing/helpers.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/testing/session_cache.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/testing/types.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/tests/__init__.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/tests/helpers.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/types.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/util/__init__.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/util/model_cache.py +0 -0
- {capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/utils.py +0 -0
|
@@ -157,20 +157,33 @@ def is_captain_hook_group(group: dict[str, Any]) -> bool:
|
|
|
157
157
|
return any("capt-hook" in (h.get("command") or "") for h in group.get("hooks") or [])
|
|
158
158
|
|
|
159
159
|
|
|
160
|
+
def capt_hook_events(path: Path) -> set[str]:
|
|
161
|
+
if not path.exists():
|
|
162
|
+
return set()
|
|
163
|
+
return {
|
|
164
|
+
event
|
|
165
|
+
for event, groups in (json.loads(path.read_text()).get("hooks") or {}).items()
|
|
166
|
+
if any(is_captain_hook_group(g) for g in groups)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
160
170
|
def merge_settings(
|
|
161
171
|
hooks_dir: str, settings_path: Path, from_source: str = DIST_NAME
|
|
162
172
|
) -> tuple[dict[str, Any], dict[str, str]]:
|
|
163
173
|
new_hooks: dict[str, list[dict[str, Any]]] = generate_settings(hooks_dir, from_source=from_source)["hooks"]
|
|
164
174
|
existing = json.loads(settings_path.read_text()) if settings_path.exists() else {}
|
|
165
175
|
existing_hooks: dict[str, list[dict[str, Any]]] = existing.get("hooks") or {}
|
|
176
|
+
committed = capt_hook_events(settings_path.parent / "settings.json")
|
|
166
177
|
|
|
167
178
|
summary: dict[str, str] = {}
|
|
168
179
|
merged_hooks: dict[str, list[dict[str, Any]]] = {}
|
|
169
180
|
for event in sorted(existing_hooks.keys() | new_hooks.keys()):
|
|
170
181
|
foreign = [g for g in existing_hooks.get(event, []) if not is_captain_hook_group(g)]
|
|
171
182
|
old_own = [g for g in existing_hooks.get(event, []) if is_captain_hook_group(g)]
|
|
172
|
-
fresh_own = new_hooks.get(event, [])
|
|
173
|
-
if old_own or
|
|
183
|
+
fresh_own = [] if event in committed else new_hooks.get(event, [])
|
|
184
|
+
if event in committed and (old_own or new_hooks.get(event)):
|
|
185
|
+
summary[event] = "deferred"
|
|
186
|
+
elif old_own or fresh_own:
|
|
174
187
|
summary[event] = (
|
|
175
188
|
"unchanged"
|
|
176
189
|
if old_own == fresh_own
|
|
@@ -207,6 +220,8 @@ def print_hook_summary(label: str, summary: dict[str, str]) -> None:
|
|
|
207
220
|
click.echo(f" - removed {event}")
|
|
208
221
|
if unchanged := by_status["unchanged"]:
|
|
209
222
|
click.echo(f" unchanged: {', '.join(unchanged)} (already present)")
|
|
223
|
+
if deferred := by_status["deferred"]:
|
|
224
|
+
click.echo(f" deferred to settings.json: {', '.join(deferred)}")
|
|
210
225
|
|
|
211
226
|
|
|
212
227
|
def regenerate_settings(state: CliState) -> None:
|
|
@@ -218,16 +233,8 @@ def regenerate_settings(state: CliState) -> None:
|
|
|
218
233
|
|
|
219
234
|
|
|
220
235
|
def settings_drift(root: Path) -> set[str]:
|
|
221
|
-
|
|
222
|
-
if
|
|
223
|
-
return set()
|
|
224
|
-
wired = {
|
|
225
|
-
event
|
|
226
|
-
for path in settings
|
|
227
|
-
for event, groups in (json.loads(path.read_text()).get("hooks") or {}).items()
|
|
228
|
-
if any(is_captain_hook_group(g) for g in groups)
|
|
229
|
-
}
|
|
230
|
-
return subscribed_events() - wired
|
|
236
|
+
paths = [p for name in ("settings.json", "settings.local.json") if (p := root / ".claude" / name).exists()]
|
|
237
|
+
return subscribed_events() - {event for p in paths for event in capt_hook_events(p)} if paths else set()
|
|
231
238
|
|
|
232
239
|
|
|
233
240
|
def warn_settings_drift(
|
|
@@ -60,8 +60,10 @@ def ensure_review_wiring(settings_path: Path) -> bool:
|
|
|
60
60
|
from captain_hook.cli import write_settings
|
|
61
61
|
|
|
62
62
|
existing: dict[str, Any] = json.loads(settings_path.read_text()) if settings_path.exists() else {}
|
|
63
|
+
committed = settings_path.parent / "settings.json"
|
|
64
|
+
committed_hooks: dict[str, Any] = (json.loads(committed.read_text()).get("hooks") or {}) if committed.exists() else {}
|
|
63
65
|
hooks: dict[str, Any] = existing.get("hooks") or {}
|
|
64
|
-
if review_wired(hooks):
|
|
66
|
+
if review_wired(hooks) or review_wired(committed_hooks):
|
|
65
67
|
return False
|
|
66
68
|
group = {"hooks": [{"type": "command", "command": f"uvx {REVIEW_RUN_COMMAND}"}]}
|
|
67
69
|
write_settings(
|
|
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.3.0 → capt_hook-3.3.1}/captain_hook/skills/authoring-hooks/references/capt-hook-api.md
RENAMED
|
File without changes
|
|
File without changes
|
{capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/authoring-hooks/references/pitfalls.md
RENAMED
|
File without changes
|
{capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/authoring-hooks/references/testing-hooks.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{capt_hook-3.3.0 → capt_hook-3.3.1}/captain_hook/skills/scanning-sessions/references/pr-workflow.md
RENAMED
|
File without changes
|
{capt_hook-3.3.0 → capt_hook-3.3.1}/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
|