capt-hook 9.0.0__tar.gz → 9.2.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-9.0.0 → capt_hook-9.2.0}/PKG-INFO +2 -2
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/cli.py +1 -1
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/hooks/hooks.json +2 -1
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/once.py +9 -5
- capt_hook-9.2.0/captain_hook/packs/general/capt-hook.toml +5 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/models.py +9 -9
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts/models/implementation_spawn_nudge.md +2 -2
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts/models/inline_edit_nudge.md +1 -1
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts/models/review_routing_spawn_nudge.md +7 -7
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts/models/review_routing_workflow_nudge.md +2 -2
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/cli.py +2 -33
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/fix.py +12 -18
- {capt_hook-9.0.0 → capt_hook-9.2.0}/pyproject.toml +2 -2
- capt_hook-9.0.0/captain_hook/packs/general/capt-hook.toml +0 -5
- {capt_hook-9.0.0 → capt_hook-9.2.0}/LICENSE +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/README.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/.claude-plugin/plugin.json +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/__main__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/app.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/ast_grep.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/classifiers/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/classifiers/conductor.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/classifiers/droid.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/classifiers/native.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/conditions.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/context.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/contexts.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/decisions.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/dispatch.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/durable.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/events.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/fields.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/file.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/loader.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/log.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/fixes/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/fixes/capt-hook.toml +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/fixes/teammate_permissions.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/_lib.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/commands.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/comments.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/detours.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/docs.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/plans.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts/fragments/deliverable_rubric.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts/fragments/workflow_script_header.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts/models/prose_spawn_gate.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts/models/prose_workflow_nudge.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts/models/writing_docs_spawn_nudge.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts/models/writing_docs_workflow_nudge.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/review.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/tasks.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/tombstones.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/go/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/go/capt-hook.toml +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/go/testing.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/go/toolchain.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/manager.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/python/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/python/capt-hook.toml +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/python/style.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/python/testing.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/python/toolchain.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/steering/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/steering/capt-hook.toml +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/steering/steering.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/steering/teammates.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/primitives/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/primitives/commands.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/primitives/lint.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/primitives/llm.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/primitives/nudge.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/primitives/permissions.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/primitives/rewrite.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/primitives/workflow.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/prompt.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/py.typed +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/dashboard.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/formats.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/judge.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/pipeline.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/prompts.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/repo.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/scan.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/settings.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/store.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/review/sync.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/session.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/settings.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/signals/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/signals/nlp.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/authoring-hooks/SKILL.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/authoring-hooks/references/capt-hook-api.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/authoring-hooks/references/pattern-catalog.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/authoring-hooks/references/pitfalls.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/authoring-hooks/references/testing-hooks.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/bootstrapping-hooks/SKILL.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/scanning-sessions/SKILL.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/scanning-sessions/references/pr-workflow.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/scanning-sessions/references/review-cli.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/translating-styleguides/SKILL.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/translating-styleguides/references/llm-rule-patterns.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/translating-styleguides/references/matcher-reference.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/translating-styleguides/references/tier-rubric.md +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/state.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/style/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/style/ast_grep.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/style/matchers.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/style/scope.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/style/types.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/tasks.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/templates/example_hook.py.tmpl +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/testing/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/testing/helpers.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/testing/session_cache.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/testing/types.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/transcripts.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/types.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/util/__init__.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/util/automode.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/util/fs.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/util/http.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/util/model_cache.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/util/paths.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/util/proc.py +0 -0
- {capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/util/text.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: capt-hook
|
|
3
|
-
Version: 9.
|
|
3
|
+
Version: 9.2.0
|
|
4
4
|
Summary: Stop repeating yourself to Claude.
|
|
5
5
|
Keywords: claude,claude-code,hooks,llm,agents,guardrails,cli
|
|
6
6
|
Author: Yasyf Mohamedali
|
|
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
16
16
|
Classifier: Topic :: Software Development :: Quality Assurance
|
|
17
17
|
Classifier: Topic :: Software Development :: Testing
|
|
18
18
|
Classifier: Typing :: Typed
|
|
19
|
-
Requires-Dist: cc-transcript[judge]>=
|
|
19
|
+
Requires-Dist: cc-transcript[judge]>=11,<12
|
|
20
20
|
Requires-Dist: pydantic>=2.0
|
|
21
21
|
Requires-Dist: pydantic-settings>=2.0
|
|
22
22
|
Requires-Dist: ast-grep-py>=0.39,<1
|
|
@@ -209,7 +209,7 @@ def run_event(state: CliState, event_name: str, *, async_: bool = False) -> None
|
|
|
209
209
|
# Collapse the N byte-identical siblings Claude Code spawns per event to one
|
|
210
210
|
# dispatch. Decision-capable events (DECISION_EVENTS) are exempt: swallowing a
|
|
211
211
|
# sibling there could bypass a gate, which outweighs a duplicated side effect.
|
|
212
|
-
if event not in DECISION_EVENTS and not claim_once(event_name, raw_text.encode()):
|
|
212
|
+
if event not in DECISION_EVENTS and not claim_once(event_name, raw_text.encode(), async_=async_):
|
|
213
213
|
return
|
|
214
214
|
|
|
215
215
|
try:
|
|
@@ -80,7 +80,8 @@
|
|
|
80
80
|
"SessionEnd": [
|
|
81
81
|
{
|
|
82
82
|
"hooks": [
|
|
83
|
-
{ "type": "command", "command": "uvx capt-hook review run", "async": true }
|
|
83
|
+
{ "type": "command", "command": "uvx capt-hook review run", "async": true },
|
|
84
|
+
{ "type": "command", "command": "uvx capt-hook run SessionEnd --async", "async": true }
|
|
84
85
|
]
|
|
85
86
|
}
|
|
86
87
|
]
|
|
@@ -26,12 +26,15 @@ DEFAULT_TTL = 10.0
|
|
|
26
26
|
TTL_ENV = "CAPT_HOOK_ONCE_TTL"
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
def claim_once(event_name: str, payload: bytes) -> bool:
|
|
30
|
-
"""Claim the one-time dispatch of ``payload`` under ``event_name
|
|
29
|
+
def claim_once(event_name: str, payload: bytes, *, async_: bool) -> bool:
|
|
30
|
+
"""Claim the one-time dispatch of ``payload`` under ``event_name``'s ``async_`` variant.
|
|
31
31
|
|
|
32
32
|
Returns True when this process won the claim and should dispatch, False when a
|
|
33
|
-
still-fresh sibling already claimed it (a duplicate that must exit silently).
|
|
34
|
-
|
|
33
|
+
still-fresh sibling already claimed it (a duplicate that must exit silently). The sync
|
|
34
|
+
and async passes of one event dispatch disjoint hook sets (``dispatch`` filters on
|
|
35
|
+
``spec.async_``), so ``async_`` is part of the key: each variant claims its own token and
|
|
36
|
+
both run even on byte-identical stdin. ``CAPT_HOOK_ONCE_TTL=0`` disables the guard, so
|
|
37
|
+
every call wins.
|
|
35
38
|
"""
|
|
36
39
|
ttl = _ttl()
|
|
37
40
|
if ttl <= 0:
|
|
@@ -40,7 +43,8 @@ def claim_once(event_name: str, payload: bytes) -> bool:
|
|
|
40
43
|
if sentinel_dir is None:
|
|
41
44
|
return True
|
|
42
45
|
_reap(sentinel_dir, ttl)
|
|
43
|
-
|
|
46
|
+
variant = b"async" if async_ else b"sync"
|
|
47
|
+
key = hashlib.sha256(event_name.encode() + b"\0" + variant + b"\0" + payload).hexdigest()
|
|
44
48
|
return _try_claim(sentinel_dir / key, ttl)
|
|
45
49
|
|
|
46
50
|
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
name = "general"
|
|
2
|
+
version = "0.17.0"
|
|
3
|
+
description = "Language-agnostic guards: git/jj command safety, doc & prompt nudges, task & plan discipline, model-routing nudges (review, security audit, and diagnosis route to gpt-5.6-sol via the codex-wrapper agent), code-review + docs-freshness gates, a detour check-in nudge, a verbose-comment nudge, and delegated-prose nudges that catch doc writing handed to a subagent or workflow without the writing-docs skill."
|
|
4
|
+
hooks = "."
|
|
5
|
+
nlp = true
|
|
@@ -263,7 +263,7 @@ llm_nudge(
|
|
|
263
263
|
message=lambda r: (
|
|
264
264
|
f"This delegation would run on fable, but it reads as routine implementation. {r.reasoning} "
|
|
265
265
|
"Implementation defaults to model='opus' + effort='xhigh' (~2x cheaper, nearly as capable); "
|
|
266
|
-
"a well-scoped edit to existing code can also go to gpt-5.
|
|
266
|
+
"a well-scoped edit to existing code can also go to gpt-5.6-sol: spawn the codex:codex-wrapper "
|
|
267
267
|
"agent with a self-contained prompt. Keep fable if this genuinely is sensitive or error-prone. "
|
|
268
268
|
"See CLAUDE.md § Plan Execution & Orchestration (Models)."
|
|
269
269
|
),
|
|
@@ -291,7 +291,7 @@ llm_nudge(
|
|
|
291
291
|
message=lambda r: (
|
|
292
292
|
f"This inline edit reads as routine implementation on fable. {r.reasoning} "
|
|
293
293
|
"Implementation delegates: spawn a model='opus', effort='xhigh' subagent to own the change, "
|
|
294
|
-
"or route a well-scoped edit to gpt-5.
|
|
294
|
+
"or route a well-scoped edit to gpt-5.6-sol via the codex skill. Keep editing inline only when "
|
|
295
295
|
"the change is small, sensitive, or bound to judgment you just exercised. "
|
|
296
296
|
"See CLAUDE.md § Plan Execution & Orchestration (Models)."
|
|
297
297
|
),
|
|
@@ -352,9 +352,9 @@ llm_nudge(
|
|
|
352
352
|
message=lambda r: (
|
|
353
353
|
f"This review/diagnosis delegation would run on fable. {r.reasoning} "
|
|
354
354
|
"Code/diff review, security review/audit and verification of security-sensitive code, "
|
|
355
|
-
"and bug diagnosis route to gpt-5.
|
|
355
|
+
"and bug diagnosis route to gpt-5.6-sol: spawn the codex:codex-wrapper agent with the "
|
|
356
356
|
"self-contained question as its prompt (from the main conversation, run the codex skill "
|
|
357
|
-
"directly), and escalate to fable only when gpt-5.
|
|
357
|
+
"directly), and escalate to fable only when gpt-5.6-sol's output misses. "
|
|
358
358
|
"Design review and findings synthesis stay on fable. "
|
|
359
359
|
"See CLAUDE.md § Plan Execution & Orchestration (Models)."
|
|
360
360
|
),
|
|
@@ -378,7 +378,7 @@ llm_nudge(
|
|
|
378
378
|
agent=False,
|
|
379
379
|
transcript=False,
|
|
380
380
|
tests={
|
|
381
|
-
Input(prompt="Review the diff for correctness and concurrency issues"): Warn(pattern="gpt-5.
|
|
381
|
+
Input(prompt="Review the diff for correctness and concurrency issues"): Warn(pattern="gpt-5.6"),
|
|
382
382
|
Input(model="fable", prompt="Adversarially refute this finding: the retry loop is wrong"): Warn(
|
|
383
383
|
pattern="codex"
|
|
384
384
|
),
|
|
@@ -395,7 +395,7 @@ llm_nudge(
|
|
|
395
395
|
prompt="Synthesize the confirmed review findings and decide which to fix",
|
|
396
396
|
llm={"fire": False},
|
|
397
397
|
): Allow(),
|
|
398
|
-
Input(prompt="Audit auth/session.py for security vulnerabilities"): Warn(pattern="gpt-5.
|
|
398
|
+
Input(prompt="Audit auth/session.py for security vulnerabilities"): Warn(pattern="gpt-5.6"),
|
|
399
399
|
Input(prompt="Verify the input-validation change blocks path traversal"): Warn(pattern="codex"),
|
|
400
400
|
Input(prompt="Verify the pagination change renders the last page correctly"): Allow(),
|
|
401
401
|
Input(
|
|
@@ -456,7 +456,7 @@ llm_nudge(
|
|
|
456
456
|
REVIEW_ROUTING_WORKFLOW_NUDGE,
|
|
457
457
|
message=lambda r: (
|
|
458
458
|
f"This workflow runs review/diagnosis stages on fable. {r.reasoning} "
|
|
459
|
-
"Route finder, refuter, security-audit, and diagnosis stages to gpt-5.
|
|
459
|
+
"Route finder, refuter, security-audit, and diagnosis stages to gpt-5.6-sol: give each stage "
|
|
460
460
|
"agentType: 'codex:codex-wrapper' with the self-contained question as its prompt; "
|
|
461
461
|
"keep the synthesis/accept-reject stage on fable (inherit the session model). "
|
|
462
462
|
"See CLAUDE.md § Plan Execution & Orchestration (Models)."
|
|
@@ -479,7 +479,7 @@ llm_nudge(
|
|
|
479
479
|
pattern="codex"
|
|
480
480
|
),
|
|
481
481
|
Input(script="agent(`Adversarially refute: ${f.title}`, {model: 'fable', effort: 'max'})"): Warn(
|
|
482
|
-
pattern="gpt-5.
|
|
482
|
+
pattern="gpt-5.6"
|
|
483
483
|
),
|
|
484
484
|
Input(
|
|
485
485
|
script="agent('Write a self-contained codex prompt reviewing this diff, "
|
|
@@ -496,7 +496,7 @@ llm_nudge(
|
|
|
496
496
|
llm={"fire": False},
|
|
497
497
|
): Allow(),
|
|
498
498
|
Input(script="agent(`Audit the login flow for auth bypass and injection; return findings as JSON`)"): Warn(
|
|
499
|
-
pattern="gpt-5.
|
|
499
|
+
pattern="gpt-5.6"
|
|
500
500
|
),
|
|
501
501
|
Input(script="agent('Verify the CLI renders the last page correctly')"): Allow(),
|
|
502
502
|
},
|
|
@@ -7,7 +7,7 @@ The Models rubric: implementation delegates to opus-4.8 at xhigh — opus is ~2x
|
|
|
7
7
|
than fable and nearly as capable. Fable's lanes are orchestration, design/architecture
|
|
8
8
|
review, hard planning, all prose/writing, and implementation that is very sensitive or
|
|
9
9
|
error-prone (auth, migrations, concurrency, data loss, crypto, subtle algorithms).
|
|
10
|
-
Code/diff review, security review/audit, and bug diagnosis have their own gpt-5.
|
|
10
|
+
Code/diff review, security review/audit, and bug diagnosis have their own gpt-5.6-sol
|
|
11
11
|
lanes with separate nudges.
|
|
12
12
|
|
|
13
13
|
Set fire=true only when the prompt is clearly routine implementation — building, fixing,
|
|
@@ -28,7 +28,7 @@ Well-scoped feature wiring; the default implementation lane.
|
|
|
28
28
|
</example>
|
|
29
29
|
<example fire="false">
|
|
30
30
|
Review the diff for correctness and concurrency issues.
|
|
31
|
-
Not implementation — review routes via its own nudge (gpt-5.
|
|
31
|
+
Not implementation — review routes via its own nudge (gpt-5.6-sol's lane), not to opus.
|
|
32
32
|
</example>
|
|
33
33
|
<example fire="false">
|
|
34
34
|
Design the migration strategy for the sharded session store.
|
{capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts/models/inline_edit_nudge.md
RENAMED
|
@@ -7,7 +7,7 @@ and written.
|
|
|
7
7
|
|
|
8
8
|
The Models rubric: implementation belongs to a delegated opus-4.8 subagent at xhigh —
|
|
9
9
|
~2x cheaper than fable and nearly as capable — or, for a well-scoped edit to existing
|
|
10
|
-
code, to gpt-5.
|
|
10
|
+
code, to gpt-5.6-sol via the codex skill. Fable edits inline when the change is small or
|
|
11
11
|
judgment-bound: a fix-up finishing work it just reasoned through, a subtle algorithm,
|
|
12
12
|
or a sensitive surface (auth, migrations, concurrency, data loss, crypto).
|
|
13
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Decide whether this delegated subagent runs code review, a security review/audit
|
|
2
2
|
or verification of security-sensitive code, or bug diagnosis that should route to
|
|
3
|
-
gpt-5.
|
|
3
|
+
gpt-5.6-sol instead of fable.
|
|
4
4
|
|
|
5
5
|
<delegated_spawn> holds the pending Agent/Task call: its model pin (or that it inherits
|
|
6
6
|
the session model, fable), agent type, and prompt.
|
|
@@ -8,9 +8,9 @@ the session model, fable), agent type, and prompt.
|
|
|
8
8
|
The Models rubric: code/diff review — sweeping a diff or codebase for bugs,
|
|
9
9
|
correctness, or cleanups; finder and refuter passes over findings — security
|
|
10
10
|
review/audit and verification of security-sensitive code (auth, input validation,
|
|
11
|
-
crypto, secrets), and bug diagnosis route to gpt-5.
|
|
11
|
+
crypto, secrets), and bug diagnosis route to gpt-5.6-sol via the codex-wrapper agent —
|
|
12
12
|
spawn agent type 'codex:codex-wrapper' with the self-contained question; fable is
|
|
13
|
-
the escalation target when gpt-5.
|
|
13
|
+
the escalation target when gpt-5.6-sol's output misses. Fable keeps design/architecture
|
|
14
14
|
review, "is this the right approach" judgment, prose review, the synthesis/
|
|
15
15
|
accept-reject pass over review findings — and security-sensitive implementation,
|
|
16
16
|
which is not review.
|
|
@@ -26,7 +26,7 @@ shape: fire=true. Keep reasoning under 40 words.
|
|
|
26
26
|
<examples>
|
|
27
27
|
<example fire="true">
|
|
28
28
|
Review the diff for correctness and concurrency issues; report findings as JSON.
|
|
29
|
-
Diff review for defects — gpt-5.
|
|
29
|
+
Diff review for defects — gpt-5.6-sol's lane via the codex-wrapper agent.
|
|
30
30
|
</example>
|
|
31
31
|
<example fire="true">
|
|
32
32
|
Adversarially refute this finding: the retry loop double-increments the counter.
|
|
@@ -34,7 +34,7 @@ A refuter pass over a code finding is review work.
|
|
|
34
34
|
</example>
|
|
35
35
|
<example fire="true">
|
|
36
36
|
Diagnose why the exporter hangs when two workers flush concurrently.
|
|
37
|
-
Bug diagnosis starts on gpt-5.
|
|
37
|
+
Bug diagnosis starts on gpt-5.6-sol; fable is the escalation target.
|
|
38
38
|
</example>
|
|
39
39
|
<example fire="true">
|
|
40
40
|
You are a low-cost wrapper: write a self-contained codex prompt reviewing this diff, then run the codex skill.
|
|
@@ -54,11 +54,11 @@ Prose review stays on fable.
|
|
|
54
54
|
</example>
|
|
55
55
|
<example fire="true">
|
|
56
56
|
Audit the session-token handling in auth/middleware.py for vulnerabilities.
|
|
57
|
-
Security review/audit of code — gpt-5.
|
|
57
|
+
Security review/audit of code — gpt-5.6-sol's lane via the codex-wrapper agent.
|
|
58
58
|
</example>
|
|
59
59
|
<example fire="true">
|
|
60
60
|
Verify the new input-validation layer rejects path traversal and injection payloads.
|
|
61
|
-
Verification of security-sensitive code routes to gpt-5.
|
|
61
|
+
Verification of security-sensitive code routes to gpt-5.6-sol.
|
|
62
62
|
</example>
|
|
63
63
|
<example fire="false">
|
|
64
64
|
Implement mitigations for the security-audit findings in auth.py.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Decide whether this workflow script runs code review or bug diagnosis stages on
|
|
2
|
-
fable that should route to gpt-5.
|
|
2
|
+
fable that should route to gpt-5.6-sol.
|
|
3
3
|
|
|
4
4
|
<workflow_script> holds the pending Workflow call's script source.
|
|
5
5
|
{workflow_script_header}
|
|
@@ -7,7 +7,7 @@ fable that should route to gpt-5.5.
|
|
|
7
7
|
The Models rubric: code/diff review stages — finder sweeps over a diff or codebase,
|
|
8
8
|
adversarial refuters over findings — security review/audit stages and verification
|
|
9
9
|
of security-sensitive code (auth, input validation, crypto, secrets), and bug
|
|
10
|
-
diagnosis route to gpt-5.
|
|
10
|
+
diagnosis route to gpt-5.6-sol via the codex-wrapper agent. A stage does that correctly
|
|
11
11
|
when its agent() call pins agentType 'codex:codex-wrapper' and its prompt is the
|
|
12
12
|
self-contained question (or pointers to the files/diff to gather plus the questions
|
|
13
13
|
to answer). A stage that pins a Claude model and asks its agent to run the codex
|
|
@@ -8,7 +8,6 @@ machinery lazily once it actually runs, and async store calls bridge with
|
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
|
-
import json
|
|
12
11
|
import os
|
|
13
12
|
import sys
|
|
14
13
|
from datetime import UTC, datetime
|
|
@@ -19,7 +18,6 @@ import click
|
|
|
19
18
|
|
|
20
19
|
if TYPE_CHECKING:
|
|
21
20
|
from collections.abc import Awaitable, Callable
|
|
22
|
-
from typing import Any
|
|
23
21
|
|
|
24
22
|
from cc_transcript.corrections import Correction
|
|
25
23
|
from cc_transcript.judge.similar import KeyOverlap
|
|
@@ -31,7 +29,6 @@ if TYPE_CHECKING:
|
|
|
31
29
|
from captain_hook.review.store import ReviewStore, ThresholdStatus
|
|
32
30
|
from captain_hook.review.sync import SyncReport
|
|
33
31
|
|
|
34
|
-
REVIEW_RUN_COMMAND = "capt-hook review run"
|
|
35
32
|
STATUS_CHOICES = ("watching", "pr_open", "stale", "accepted", "rejected")
|
|
36
33
|
|
|
37
34
|
|
|
@@ -51,33 +48,6 @@ def resolve_repo(repo_: str | None, root: Path) -> RepoKey:
|
|
|
51
48
|
return RepoKey(repo_) if repo_ else current_repo(root)
|
|
52
49
|
|
|
53
50
|
|
|
54
|
-
def group_commands(group: dict[str, Any]) -> list[str]:
|
|
55
|
-
entries: list[dict[str, Any]] = group.get("hooks") or []
|
|
56
|
-
return [str(entry.get("command") or "") for entry in entries]
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def review_wired(hooks: dict[str, Any]) -> bool:
|
|
60
|
-
groups: list[dict[str, Any]] = hooks.get("SessionEnd") or []
|
|
61
|
-
return any(REVIEW_RUN_COMMAND in command for group in groups for command in group_commands(group))
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def ensure_review_wiring(settings_path: Path) -> bool:
|
|
65
|
-
from captain_hook.cli import sibling_settings, write_settings
|
|
66
|
-
|
|
67
|
-
existing: dict[str, Any] = json.loads(settings_path.read_text()) if settings_path.exists() else {}
|
|
68
|
-
sibling = sibling_settings(settings_path)
|
|
69
|
-
sibling_hooks: dict[str, Any] = (json.loads(sibling.read_text()).get("hooks") or {}) if sibling.exists() else {}
|
|
70
|
-
hooks: dict[str, Any] = existing.get("hooks") or {}
|
|
71
|
-
if review_wired(hooks) or review_wired(sibling_hooks):
|
|
72
|
-
return False
|
|
73
|
-
group = {"hooks": [{"type": "command", "command": f"uvx {REVIEW_RUN_COMMAND}", "async": True}]}
|
|
74
|
-
write_settings(
|
|
75
|
-
settings_path,
|
|
76
|
-
existing | {"hooks": hooks | {"SessionEnd": [*(hooks.get("SessionEnd") or []), group]}},
|
|
77
|
-
)
|
|
78
|
-
return True
|
|
79
|
-
|
|
80
|
-
|
|
81
51
|
def run_store[T](fn: Callable[[ReviewStore], Awaitable[T]]) -> T:
|
|
82
52
|
"""Open the review store, run ``fn`` against it, and bridge with ``asyncio.run`` at the command boundary."""
|
|
83
53
|
import asyncio
|
|
@@ -136,14 +106,13 @@ def spawn(transcript: Path, cwd: str | None) -> None:
|
|
|
136
106
|
@review.command()
|
|
137
107
|
@click.pass_obj
|
|
138
108
|
def enable(state: CliState) -> None:
|
|
139
|
-
"""Watch the current repo
|
|
109
|
+
"""Watch the current repo and register the captain-hook plugin."""
|
|
140
110
|
from captain_hook.cli import register_marketplace
|
|
141
111
|
|
|
142
112
|
repo = current_repo(state.root)
|
|
143
113
|
watch_repo(repo)
|
|
144
114
|
register_marketplace(state.root)
|
|
145
|
-
|
|
146
|
-
click.echo(f"watching {repo}" + (" (SessionEnd hook wired into .claude/settings.json)" if wired else ""))
|
|
115
|
+
click.echo(f"watching {repo}")
|
|
147
116
|
|
|
148
117
|
|
|
149
118
|
@review.command()
|
|
@@ -46,11 +46,17 @@ from cc_transcript.mining.confidence import MEDIUM, VERY_HIGH, CandidateSignal
|
|
|
46
46
|
from cc_transcript.mining.signals import MiningSignal
|
|
47
47
|
from cc_transcript.mining.sourcekind import SourceKind
|
|
48
48
|
from cc_transcript.mining.spec import CONFIDENCE_STEP, bump
|
|
49
|
-
from cc_transcript.models import
|
|
49
|
+
from cc_transcript.models import (
|
|
50
|
+
AssistantEvent,
|
|
51
|
+
AttachmentEvent,
|
|
52
|
+
HookAdditionalContext,
|
|
53
|
+
HookBlockingError,
|
|
54
|
+
ToolResultBlock,
|
|
55
|
+
UserEvent,
|
|
56
|
+
)
|
|
50
57
|
|
|
51
58
|
if TYPE_CHECKING:
|
|
52
59
|
from collections.abc import Iterator, Mapping, Sequence
|
|
53
|
-
from typing import Any
|
|
54
60
|
|
|
55
61
|
from cc_transcript.decisions import Decision, DecisionLog
|
|
56
62
|
from cc_transcript.ids import SessionId, ToolUseId
|
|
@@ -137,22 +143,10 @@ def classify_marker(text: str) -> Marker | None:
|
|
|
137
143
|
|
|
138
144
|
def fingerprint_of(event: TranscriptEvent) -> Fingerprint | None:
|
|
139
145
|
match event:
|
|
140
|
-
case
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return Fingerprint(
|
|
145
|
-
message="\n".join(str(part) for part in attachment["content"]),
|
|
146
|
-
tool_use_id=attachment.get("toolUseID"),
|
|
147
|
-
event=attachment.get("hookEvent"),
|
|
148
|
-
)
|
|
149
|
-
case "hook_blocking_error":
|
|
150
|
-
return Fingerprint(
|
|
151
|
-
message=str(attachment["blockingError"]["blockingError"]),
|
|
152
|
-
event=str(attachment.get("hookEvent") or "Stop"),
|
|
153
|
-
)
|
|
154
|
-
case _:
|
|
155
|
-
return None
|
|
146
|
+
case AttachmentEvent(detail=HookAdditionalContext(content=content, tool_use_id=tool_use_id, hook_event=hook_event)):
|
|
147
|
+
return Fingerprint(message="\n".join(content), tool_use_id=tool_use_id, event=hook_event)
|
|
148
|
+
case AttachmentEvent(detail=HookBlockingError(blocking_error={"blockingError": blocking_error}, hook_event=hook_event)):
|
|
149
|
+
return Fingerprint(message=str(blocking_error), event=str(hook_event or "Stop"))
|
|
156
150
|
case UserEvent(meta=meta, text=text) if meta.is_meta and text.startswith(STOP_FEEDBACK_PREFIX):
|
|
157
151
|
return Fingerprint(message=text.removeprefix(STOP_FEEDBACK_PREFIX), event="Stop")
|
|
158
152
|
case UserEvent(blocks=blocks):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "capt-hook"
|
|
3
3
|
# Inert sentinel — the real version is stamped from the release tag (uv version --frozen).
|
|
4
|
-
version = "9.
|
|
4
|
+
version = "9.2.0"
|
|
5
5
|
description = "Stop repeating yourself to Claude."
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = "PolyForm-Noncommercial-1.0.0"
|
|
@@ -29,7 +29,7 @@ classifiers = [
|
|
|
29
29
|
]
|
|
30
30
|
requires-python = ">=3.13"
|
|
31
31
|
dependencies = [
|
|
32
|
-
"cc-transcript[judge]>=
|
|
32
|
+
"cc-transcript[judge]>=11,<12",
|
|
33
33
|
"pydantic>=2.0",
|
|
34
34
|
"pydantic-settings>=2.0",
|
|
35
35
|
"ast-grep-py>=0.39,<1",
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
name = "general"
|
|
2
|
-
version = "0.16.0"
|
|
3
|
-
description = "Language-agnostic guards: git/jj command safety, doc & prompt nudges, task & plan discipline, model-routing nudges (review, security audit, and diagnosis route to gpt-5.5 via the codex-wrapper agent), code-review + docs-freshness gates, a detour check-in nudge, a verbose-comment nudge, and delegated-prose nudges that catch doc writing handed to a subagent or workflow without the writing-docs skill."
|
|
4
|
-
hooks = "."
|
|
5
|
-
nlp = true
|
|
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-9.0.0 → capt_hook-9.2.0}/captain_hook/packs/general/prompts/models/prose_spawn_gate.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
|
|
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-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/authoring-hooks/references/capt-hook-api.md
RENAMED
|
File without changes
|
|
File without changes
|
{capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/authoring-hooks/references/pitfalls.md
RENAMED
|
File without changes
|
{capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/authoring-hooks/references/testing-hooks.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{capt_hook-9.0.0 → capt_hook-9.2.0}/captain_hook/skills/scanning-sessions/references/pr-workflow.md
RENAMED
|
File without changes
|
{capt_hook-9.0.0 → capt_hook-9.2.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|