@hustle-together/api-dev-tools 3.10.1 → 3.12.1
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.
- package/.claude/agents/code-reviewer.md +170 -0
- package/.claude/agents/docs-generator.md +80 -0
- package/.claude/agents/implementation-reviewer.md +119 -0
- package/.claude/agents/parallel-researcher.md +52 -0
- package/.claude/agents/research-validator.md +116 -0
- package/.claude/agents/schema-generator.md +70 -0
- package/.claude/agents/test-writer.md +104 -0
- package/.claude/api-dev-state.json +331 -0
- package/.claude/commands/README.md +196 -0
- package/.claude/commands/add-command.md +212 -0
- package/.claude/commands/api-create.md +510 -0
- package/.claude/commands/api-env.md +51 -0
- package/.claude/commands/api-interview.md +344 -0
- package/.claude/commands/api-research.md +357 -0
- package/.claude/commands/api-status.md +279 -0
- package/.claude/commands/api-verify.md +232 -0
- package/.claude/commands/beepboop.md +96 -0
- package/.claude/commands/busycommit.md +111 -0
- package/.claude/commands/commit.md +82 -0
- package/.claude/commands/cycle.md +137 -0
- package/.claude/commands/gap.md +85 -0
- package/.claude/commands/green.md +137 -0
- package/.claude/commands/issue.md +187 -0
- package/.claude/commands/ntfy-setup.md +91 -0
- package/.claude/commands/ntfy-test.md +74 -0
- package/.claude/commands/plan.md +167 -0
- package/.claude/commands/pr.md +121 -0
- package/.claude/commands/publish.md +40 -0
- package/.claude/commands/red.md +137 -0
- package/.claude/commands/refactor.md +137 -0
- package/.claude/commands/spike.md +137 -0
- package/.claude/commands/summarize.md +93 -0
- package/.claude/commands/tdd.md +139 -0
- package/.claude/commands/worktree-add.md +307 -0
- package/.claude/commands/worktree-cleanup.md +275 -0
- package/.claude/hooks/api-workflow-check.py +227 -0
- package/.claude/hooks/enforce-deep-research.py +185 -0
- package/.claude/hooks/enforce-disambiguation.py +155 -0
- package/.claude/hooks/enforce-documentation.py +192 -0
- package/.claude/hooks/enforce-environment.py +253 -0
- package/.claude/hooks/enforce-external-research.py +328 -0
- package/.claude/hooks/enforce-interview.py +421 -0
- package/.claude/hooks/enforce-refactor.py +189 -0
- package/.claude/hooks/enforce-research.py +159 -0
- package/.claude/hooks/enforce-schema.py +186 -0
- package/.claude/hooks/enforce-scope.py +160 -0
- package/.claude/hooks/enforce-tdd-red.py +250 -0
- package/.claude/hooks/enforce-verify.py +186 -0
- package/.claude/hooks/periodic-reground.py +154 -0
- package/.claude/hooks/session-startup.py +151 -0
- package/.claude/hooks/track-tool-use.py +626 -0
- package/.claude/hooks/verify-after-green.py +282 -0
- package/.claude/hooks/verify-implementation.py +225 -0
- package/.claude/research/index.json +6 -0
- package/.claude/settings.json +144 -0
- package/.claude/settings.local.json +12 -0
- package/.claude-plugin/marketplace.json +103 -0
- package/.skills/README.md +293 -0
- package/.skills/_shared/convert-commands.py +192 -0
- package/.skills/_shared/hooks/api-workflow-check.py +227 -0
- package/.skills/_shared/hooks/enforce-deep-research.py +185 -0
- package/.skills/_shared/hooks/enforce-disambiguation.py +155 -0
- package/.skills/_shared/hooks/enforce-documentation.py +192 -0
- package/.skills/_shared/hooks/enforce-environment.py +253 -0
- package/.skills/_shared/hooks/enforce-external-research.py +328 -0
- package/.skills/_shared/hooks/enforce-interview.py +421 -0
- package/.skills/_shared/hooks/enforce-refactor.py +189 -0
- package/.skills/_shared/hooks/enforce-research.py +159 -0
- package/.skills/_shared/hooks/enforce-schema.py +186 -0
- package/.skills/_shared/hooks/enforce-scope.py +160 -0
- package/.skills/_shared/hooks/enforce-tdd-red.py +250 -0
- package/.skills/_shared/hooks/enforce-verify.py +186 -0
- package/.skills/_shared/hooks/periodic-reground.py +154 -0
- package/.skills/_shared/hooks/session-startup.py +151 -0
- package/.skills/_shared/hooks/track-tool-use.py +626 -0
- package/.skills/_shared/hooks/verify-after-green.py +282 -0
- package/.skills/_shared/hooks/verify-implementation.py +225 -0
- package/.skills/_shared/install.sh +114 -0
- package/.skills/_shared/settings.json +93 -0
- package/.skills/add-command/SKILL.md +227 -0
- package/.skills/api-create/SKILL.md +623 -0
- package/.skills/api-env/SKILL.md +64 -0
- package/.skills/api-interview/SKILL.md +357 -0
- package/.skills/api-research/SKILL.md +370 -0
- package/.skills/api-status/SKILL.md +292 -0
- package/.skills/api-verify/SKILL.md +245 -0
- package/.skills/beepboop/SKILL.md +111 -0
- package/.skills/busycommit/SKILL.md +126 -0
- package/.skills/commit/SKILL.md +97 -0
- package/.skills/cycle/SKILL.md +152 -0
- package/.skills/gap/SKILL.md +100 -0
- package/.skills/green/SKILL.md +152 -0
- package/.skills/issue/SKILL.md +202 -0
- package/.skills/plan/SKILL.md +182 -0
- package/.skills/pr/SKILL.md +136 -0
- package/.skills/publish/SKILL.md +160 -0
- package/.skills/red/SKILL.md +152 -0
- package/.skills/refactor/SKILL.md +152 -0
- package/.skills/spike/SKILL.md +152 -0
- package/.skills/summarize/SKILL.md +108 -0
- package/.skills/tdd/SKILL.md +154 -0
- package/.skills/update-todos/SKILL.md +250 -0
- package/.skills/worktree-add/SKILL.md +322 -0
- package/.skills/worktree-cleanup/SKILL.md +290 -0
- package/CHANGELOG.md +115 -0
- package/README.md +161 -7101
- package/bin/cli.js +448 -805
- package/commands/README.md +66 -31
- package/commands/add-command.md +8 -5
- package/commands/beepboop.md +4 -5
- package/commands/busycommit.md +2 -3
- package/commands/commit.md +2 -3
- package/commands/cycle.md +2 -7
- package/commands/gap.md +2 -3
- package/commands/green.md +2 -7
- package/commands/hustle-api-continue.md +8 -5
- package/commands/hustle-api-create.md +70 -29
- package/commands/hustle-api-env.md +1 -0
- package/commands/hustle-api-interview.md +32 -19
- package/commands/hustle-api-research.md +47 -21
- package/commands/hustle-api-sessions.md +8 -7
- package/commands/hustle-api-status.md +21 -1
- package/commands/hustle-api-verify.md +14 -13
- package/commands/hustle-combine.md +488 -241
- package/commands/hustle-ui-create-page.md +113 -50
- package/commands/hustle-ui-create.md +179 -26
- package/commands/issue.md +3 -8
- package/commands/plan.md +2 -3
- package/commands/pr.md +2 -3
- package/commands/red.md +2 -7
- package/commands/refactor.md +2 -7
- package/commands/spike.md +2 -7
- package/commands/summarize.md +2 -3
- package/commands/tdd.md +2 -7
- package/commands/worktree-add.md +208 -216
- package/commands/worktree-cleanup.md +172 -178
- package/hooks/api-workflow-check.py +5 -3
- package/hooks/enforce-component-type-confirm.py +97 -0
- package/hooks/lib/__init__.py +1 -0
- package/hooks/lib/greptile.py +355 -0
- package/hooks/lib/ntfy.py +209 -0
- package/hooks/notify-input-needed.py +73 -0
- package/hooks/notify-phase-complete.py +90 -0
- package/hooks/run-code-review.py +246 -0
- package/hooks/track-token-usage.py +121 -0
- package/package.json +33 -12
- package/scripts/collect-test-results.ts +102 -77
- package/scripts/extract-parameters.ts +112 -70
- package/scripts/generate-test-manifest.ts +118 -77
- package/templates/.env.example +57 -0
- package/templates/BRAND_GUIDE.md +92 -52
- package/templates/CLAUDE-SECTION.md +40 -37
- package/templates/SPEC.json +186 -38
- package/templates/api-dev-state.json +33 -4
- package/templates/api-showcase/_components/APICard.tsx +22 -18
- package/templates/api-showcase/_components/APIModal.tsx +110 -64
- package/templates/api-showcase/_components/APIShowcase.tsx +53 -35
- package/templates/api-showcase/_components/APITester.tsx +128 -67
- package/templates/api-showcase/page.tsx +4 -4
- package/templates/api-test/page.tsx +51 -30
- package/templates/api-test/test-structure/route.ts +43 -34
- package/templates/component/Component.stories.tsx +41 -39
- package/templates/component/Component.test.tsx +96 -78
- package/templates/component/Component.tsx +63 -52
- package/templates/component/Component.types.ts +10 -6
- package/templates/component/Component.visual.spec.ts +170 -0
- package/templates/component/index.ts +2 -2
- package/templates/dev-tools/_components/DevToolsLanding.tsx +8 -8
- package/templates/dev-tools/page.tsx +4 -3
- package/templates/mcp-servers.json +30 -2
- package/templates/page/page.e2e.test.ts +56 -48
- package/templates/page/page.tsx +3 -3
- package/templates/shared/HeroHeader.tsx +16 -15
- package/templates/shared/index.ts +1 -1
- package/templates/ui-showcase/_components/PreviewCard.tsx +20 -20
- package/templates/ui-showcase/_components/PreviewModal.tsx +149 -108
- package/templates/ui-showcase/_components/UIShowcase.tsx +43 -35
- package/templates/ui-showcase/page.tsx +4 -4
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Hook: UserPromptSubmit
|
|
4
|
+
Purpose: ALWAYS enforce research before answering technical questions
|
|
5
|
+
|
|
6
|
+
This hook runs BEFORE Claude processes the user's prompt. It aggressively
|
|
7
|
+
detects ANY technical question and requires comprehensive research using
|
|
8
|
+
BOTH Context7 AND multiple WebSearches before answering.
|
|
9
|
+
|
|
10
|
+
Philosophy: "ALWAYS research. Training data is NEVER trustworthy for technical info."
|
|
11
|
+
|
|
12
|
+
The hook triggers on:
|
|
13
|
+
- ANY mention of APIs, SDKs, libraries, packages, frameworks
|
|
14
|
+
- ANY technical "how to" or capability questions
|
|
15
|
+
- ANY code-related questions (functions, methods, parameters, types)
|
|
16
|
+
- ANY questions about tools, services, or platforms
|
|
17
|
+
- ANY request for implementation, editing, or changes
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
- Prints context to stdout (injected into conversation)
|
|
21
|
+
- Exit 0 to allow the prompt to proceed
|
|
22
|
+
"""
|
|
23
|
+
import json
|
|
24
|
+
import sys
|
|
25
|
+
import re
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
from datetime import datetime
|
|
28
|
+
|
|
29
|
+
# State file is in .claude/ directory (sibling to hooks/)
|
|
30
|
+
STATE_FILE = Path(__file__).parent.parent / "api-dev-state.json"
|
|
31
|
+
|
|
32
|
+
# ============================================================================
|
|
33
|
+
# AGGRESSIVE DETECTION PATTERNS
|
|
34
|
+
# ============================================================================
|
|
35
|
+
|
|
36
|
+
# Technical terms that ALWAYS trigger research
|
|
37
|
+
TECHNICAL_TERMS = [
|
|
38
|
+
# Code/Development
|
|
39
|
+
r"\b(?:function|method|class|interface|type|schema|model)\b",
|
|
40
|
+
r"\b(?:parameter|argument|option|config|setting|property)\b",
|
|
41
|
+
r"\b(?:import|export|require|module|package|library|dependency)\b",
|
|
42
|
+
r"\b(?:api|sdk|framework|runtime|engine|platform)\b",
|
|
43
|
+
r"\b(?:endpoint|route|url|path|request|response|header)\b",
|
|
44
|
+
r"\b(?:database|query|table|collection|document|record)\b",
|
|
45
|
+
r"\b(?:authentication|authorization|token|key|secret|credential)\b",
|
|
46
|
+
r"\b(?:error|exception|bug|issue|problem|fix)\b",
|
|
47
|
+
r"\b(?:test|spec|coverage|mock|stub|fixture)\b",
|
|
48
|
+
r"\b(?:deploy|build|compile|bundle|publish|release)\b",
|
|
49
|
+
r"\b(?:install|setup|configure|initialize|migrate)\b",
|
|
50
|
+
r"\b(?:provider|service|client|server|handler|middleware)\b",
|
|
51
|
+
r"\b(?:stream|async|await|promise|callback|event)\b",
|
|
52
|
+
r"\b(?:component|widget|element|view|layout|template)\b",
|
|
53
|
+
r"\b(?:state|store|reducer|action|context|hook)\b",
|
|
54
|
+
r"\b(?:validate|parse|serialize|transform|convert)\b",
|
|
55
|
+
|
|
56
|
+
# Package patterns
|
|
57
|
+
r"@[\w-]+/[\w-]+", # @scope/package
|
|
58
|
+
r"\b[\w-]+-(?:sdk|api|js|ts|py|go|rs)\b", # something-sdk, something-api
|
|
59
|
+
|
|
60
|
+
# Version patterns
|
|
61
|
+
r"\bv?\d+\.\d+(?:\.\d+)?(?:-[\w.]+)?\b", # v1.2.3, 2.0.0-beta
|
|
62
|
+
|
|
63
|
+
# File patterns
|
|
64
|
+
r"\b[\w-]+\.(?:ts|js|tsx|jsx|py|go|rs|json|yaml|yml|toml|env)\b",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
# Question patterns that indicate asking about functionality
|
|
68
|
+
QUESTION_PATTERNS = [
|
|
69
|
+
# Direct questions
|
|
70
|
+
r"\b(?:what|which|where|when|why|how)\b",
|
|
71
|
+
r"\b(?:can|could|would|should|will|does|do|is|are)\b.*\?",
|
|
72
|
+
|
|
73
|
+
# Requests
|
|
74
|
+
r"\b(?:show|tell|explain|describe|list|find|get|give)\b",
|
|
75
|
+
r"\b(?:help|need|want|looking for|trying to)\b",
|
|
76
|
+
|
|
77
|
+
# Actions
|
|
78
|
+
r"\b(?:create|make|build|add|implement|write|generate)\b",
|
|
79
|
+
r"\b(?:update|change|modify|edit|fix|refactor|improve)\b",
|
|
80
|
+
r"\b(?:delete|remove|drop|clear|reset)\b",
|
|
81
|
+
r"\b(?:connect|integrate|link|sync|merge)\b",
|
|
82
|
+
r"\b(?:debug|trace|log|monitor|track)\b",
|
|
83
|
+
|
|
84
|
+
# Comparisons
|
|
85
|
+
r"\b(?:difference|compare|versus|vs|between|or)\b",
|
|
86
|
+
r"\b(?:better|best|recommended|preferred|alternative)\b",
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
# Phrases that ALWAYS require research (no exceptions)
|
|
90
|
+
ALWAYS_RESEARCH_PHRASES = [
|
|
91
|
+
r"how (?:to|do|does|can|should|would)",
|
|
92
|
+
r"what (?:is|are|does|can|should)",
|
|
93
|
+
r"(?:does|can|will|should) .+ (?:support|have|handle|work|do)",
|
|
94
|
+
r"(?:list|show|get|find) (?:all|available|supported)",
|
|
95
|
+
r"example (?:of|for|using|with|code)",
|
|
96
|
+
r"(?:implement|add|create|build|write|generate) .+",
|
|
97
|
+
r"(?:update|change|modify|edit|fix) .+",
|
|
98
|
+
r"(?:configure|setup|install|deploy) .+",
|
|
99
|
+
r"(?:error|issue|problem|bug|not working)",
|
|
100
|
+
r"(?:api|sdk|library|package|module|framework)",
|
|
101
|
+
r"(?:documentation|docs|reference|guide)",
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
# Exclusion patterns - things that DON'T need research
|
|
105
|
+
EXCLUDE_PATTERNS = [
|
|
106
|
+
r"^(?:hi|hello|hey|thanks|thank you|ok|okay|yes|no|sure)[\s!?.]*$",
|
|
107
|
+
r"^(?:good morning|good afternoon|good evening|goodbye|bye)[\s!?.]*$",
|
|
108
|
+
r"^(?:please|sorry|excuse me)[\s!?.]*$",
|
|
109
|
+
r"^(?:\d+[\s+\-*/]\d+|calculate|math).*$", # Simple math
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
# ============================================================================
|
|
113
|
+
# DETECTION LOGIC
|
|
114
|
+
# ============================================================================
|
|
115
|
+
|
|
116
|
+
def is_excluded(prompt: str) -> bool:
|
|
117
|
+
"""Check if prompt is a simple greeting or non-technical."""
|
|
118
|
+
prompt_clean = prompt.strip().lower()
|
|
119
|
+
|
|
120
|
+
# Very short prompts that are just greetings
|
|
121
|
+
if len(prompt_clean) < 20:
|
|
122
|
+
for pattern in EXCLUDE_PATTERNS:
|
|
123
|
+
if re.match(pattern, prompt_clean, re.IGNORECASE):
|
|
124
|
+
return True
|
|
125
|
+
|
|
126
|
+
return False
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def detect_technical_question(prompt: str) -> dict:
|
|
130
|
+
"""
|
|
131
|
+
Aggressively detect if the prompt is technical and requires research.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
{
|
|
135
|
+
"detected": bool,
|
|
136
|
+
"terms": list of detected terms,
|
|
137
|
+
"patterns_matched": list of pattern types,
|
|
138
|
+
"confidence": "critical" | "high" | "medium" | "low" | "none"
|
|
139
|
+
}
|
|
140
|
+
"""
|
|
141
|
+
if is_excluded(prompt):
|
|
142
|
+
return {
|
|
143
|
+
"detected": False,
|
|
144
|
+
"terms": [],
|
|
145
|
+
"patterns_matched": [],
|
|
146
|
+
"confidence": "none",
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
prompt_lower = prompt.lower()
|
|
150
|
+
detected_terms = []
|
|
151
|
+
patterns_matched = []
|
|
152
|
+
|
|
153
|
+
# Check for ALWAYS_RESEARCH_PHRASES first (highest priority)
|
|
154
|
+
for pattern in ALWAYS_RESEARCH_PHRASES:
|
|
155
|
+
if re.search(pattern, prompt_lower, re.IGNORECASE):
|
|
156
|
+
patterns_matched.append("always_research")
|
|
157
|
+
# Extract the matched phrase
|
|
158
|
+
match = re.search(pattern, prompt_lower, re.IGNORECASE)
|
|
159
|
+
if match:
|
|
160
|
+
detected_terms.append(match.group(0)[:50])
|
|
161
|
+
|
|
162
|
+
# Check technical terms
|
|
163
|
+
for pattern in TECHNICAL_TERMS:
|
|
164
|
+
matches = re.findall(pattern, prompt_lower, re.IGNORECASE)
|
|
165
|
+
if matches:
|
|
166
|
+
detected_terms.extend(matches[:3]) # Limit per pattern
|
|
167
|
+
patterns_matched.append("technical_term")
|
|
168
|
+
|
|
169
|
+
# Check question patterns
|
|
170
|
+
for pattern in QUESTION_PATTERNS:
|
|
171
|
+
if re.search(pattern, prompt_lower, re.IGNORECASE):
|
|
172
|
+
patterns_matched.append("question_pattern")
|
|
173
|
+
break
|
|
174
|
+
|
|
175
|
+
# Deduplicate
|
|
176
|
+
detected_terms = list(dict.fromkeys(detected_terms))[:10]
|
|
177
|
+
patterns_matched = list(set(patterns_matched))
|
|
178
|
+
|
|
179
|
+
# Determine confidence - MUCH more aggressive
|
|
180
|
+
if "always_research" in patterns_matched:
|
|
181
|
+
confidence = "critical"
|
|
182
|
+
elif "technical_term" in patterns_matched and "question_pattern" in patterns_matched:
|
|
183
|
+
confidence = "high"
|
|
184
|
+
elif "technical_term" in patterns_matched:
|
|
185
|
+
confidence = "high" # Technical terms alone = high
|
|
186
|
+
elif "question_pattern" in patterns_matched and len(prompt) > 30:
|
|
187
|
+
confidence = "medium" # Questions longer than 30 chars
|
|
188
|
+
elif len(prompt) > 50:
|
|
189
|
+
confidence = "low" # Longer prompts default to low (still triggers)
|
|
190
|
+
else:
|
|
191
|
+
confidence = "none"
|
|
192
|
+
|
|
193
|
+
# AGGRESSIVE: Trigger on anything except "none"
|
|
194
|
+
detected = confidence != "none"
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
"detected": detected,
|
|
198
|
+
"terms": detected_terms,
|
|
199
|
+
"patterns_matched": patterns_matched,
|
|
200
|
+
"confidence": confidence,
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def check_active_workflow() -> bool:
|
|
205
|
+
"""Check if there's an active API development workflow."""
|
|
206
|
+
if not STATE_FILE.exists():
|
|
207
|
+
return False
|
|
208
|
+
|
|
209
|
+
try:
|
|
210
|
+
state = json.loads(STATE_FILE.read_text())
|
|
211
|
+
phases = state.get("phases", {})
|
|
212
|
+
|
|
213
|
+
for phase_key, phase_data in phases.items():
|
|
214
|
+
if isinstance(phase_data, dict):
|
|
215
|
+
status = phase_data.get("status", "")
|
|
216
|
+
if status in ["in_progress", "pending", "complete"]:
|
|
217
|
+
# If ANY phase has been touched, we're in a workflow
|
|
218
|
+
return True
|
|
219
|
+
|
|
220
|
+
return False
|
|
221
|
+
except (json.JSONDecodeError, Exception):
|
|
222
|
+
return False
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def log_detection(prompt: str, detection: dict, injected: bool) -> None:
|
|
226
|
+
"""Log this detection for debugging/auditing."""
|
|
227
|
+
try:
|
|
228
|
+
if STATE_FILE.exists():
|
|
229
|
+
state = json.loads(STATE_FILE.read_text())
|
|
230
|
+
else:
|
|
231
|
+
state = {"prompt_detections": []}
|
|
232
|
+
|
|
233
|
+
if "prompt_detections" not in state:
|
|
234
|
+
state["prompt_detections"] = []
|
|
235
|
+
|
|
236
|
+
state["prompt_detections"].append({
|
|
237
|
+
"timestamp": datetime.now().isoformat(),
|
|
238
|
+
"prompt_preview": prompt[:100] + "..." if len(prompt) > 100 else prompt,
|
|
239
|
+
"detection": detection,
|
|
240
|
+
"injected": injected,
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
# Keep only last 50 detections
|
|
244
|
+
state["prompt_detections"] = state["prompt_detections"][-50:]
|
|
245
|
+
|
|
246
|
+
STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
247
|
+
STATE_FILE.write_text(json.dumps(state, indent=2))
|
|
248
|
+
except Exception:
|
|
249
|
+
pass # Don't fail the hook on logging errors
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
# ============================================================================
|
|
253
|
+
# MAIN
|
|
254
|
+
# ============================================================================
|
|
255
|
+
|
|
256
|
+
def main():
|
|
257
|
+
# Read hook input from stdin
|
|
258
|
+
try:
|
|
259
|
+
input_data = json.load(sys.stdin)
|
|
260
|
+
except json.JSONDecodeError:
|
|
261
|
+
sys.exit(0)
|
|
262
|
+
|
|
263
|
+
prompt = input_data.get("prompt", "")
|
|
264
|
+
|
|
265
|
+
if not prompt or len(prompt.strip()) < 5:
|
|
266
|
+
sys.exit(0)
|
|
267
|
+
|
|
268
|
+
# Check if in active workflow mode
|
|
269
|
+
active_workflow = check_active_workflow()
|
|
270
|
+
|
|
271
|
+
# Detect technical questions
|
|
272
|
+
detection = detect_technical_question(prompt)
|
|
273
|
+
|
|
274
|
+
# In active workflow, ALWAYS inject (even for low confidence)
|
|
275
|
+
if active_workflow and detection["confidence"] != "none":
|
|
276
|
+
detection["detected"] = True
|
|
277
|
+
|
|
278
|
+
# Log all detections
|
|
279
|
+
log_detection(prompt, detection, detection["detected"])
|
|
280
|
+
|
|
281
|
+
# Inject context if detected
|
|
282
|
+
if detection["detected"]:
|
|
283
|
+
terms_str = ", ".join(detection["terms"][:5]) if detection["terms"] else "technical question"
|
|
284
|
+
confidence = detection["confidence"]
|
|
285
|
+
|
|
286
|
+
# Build the injection message
|
|
287
|
+
injection = f"""
|
|
288
|
+
<user-prompt-submit-hook>
|
|
289
|
+
RESEARCH REQUIRED - {confidence.upper()} CONFIDENCE
|
|
290
|
+
Detected: {terms_str}
|
|
291
|
+
{"MODE: Active API Development Workflow - STRICT ENFORCEMENT" if active_workflow else ""}
|
|
292
|
+
|
|
293
|
+
MANDATORY BEFORE ANSWERING:
|
|
294
|
+
|
|
295
|
+
1. USE CONTEXT7 FIRST:
|
|
296
|
+
- Call mcp__context7__resolve-library-id to find the library
|
|
297
|
+
- Call mcp__context7__get-library-docs to get CURRENT documentation
|
|
298
|
+
- This gives you the ACTUAL source of truth
|
|
299
|
+
|
|
300
|
+
2. USE WEBSEARCH (2-3 SEARCHES MINIMUM):
|
|
301
|
+
- Search for official documentation
|
|
302
|
+
- Search with different phrasings to get comprehensive coverage
|
|
303
|
+
- Search for recent updates, changes, or known issues
|
|
304
|
+
- Example searches:
|
|
305
|
+
* "[topic] official documentation"
|
|
306
|
+
* "[topic] API reference guide"
|
|
307
|
+
* "[topic] latest updates 2024 2025"
|
|
308
|
+
|
|
309
|
+
3. NEVER TRUST TRAINING DATA:
|
|
310
|
+
- Training data can be months or years outdated
|
|
311
|
+
- APIs change constantly
|
|
312
|
+
- Features get added, deprecated, or modified
|
|
313
|
+
- Parameter names and types change
|
|
314
|
+
|
|
315
|
+
4. CITE YOUR SOURCES:
|
|
316
|
+
- After researching, mention where the information came from
|
|
317
|
+
- Include links when available
|
|
318
|
+
|
|
319
|
+
RESEARCH FIRST. ANSWER SECOND.
|
|
320
|
+
</user-prompt-submit-hook>
|
|
321
|
+
"""
|
|
322
|
+
print(injection)
|
|
323
|
+
|
|
324
|
+
sys.exit(0)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
if __name__ == "__main__":
|
|
328
|
+
main()
|