@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.
Files changed (178) hide show
  1. package/.claude/agents/code-reviewer.md +170 -0
  2. package/.claude/agents/docs-generator.md +80 -0
  3. package/.claude/agents/implementation-reviewer.md +119 -0
  4. package/.claude/agents/parallel-researcher.md +52 -0
  5. package/.claude/agents/research-validator.md +116 -0
  6. package/.claude/agents/schema-generator.md +70 -0
  7. package/.claude/agents/test-writer.md +104 -0
  8. package/.claude/api-dev-state.json +331 -0
  9. package/.claude/commands/README.md +196 -0
  10. package/.claude/commands/add-command.md +212 -0
  11. package/.claude/commands/api-create.md +510 -0
  12. package/.claude/commands/api-env.md +51 -0
  13. package/.claude/commands/api-interview.md +344 -0
  14. package/.claude/commands/api-research.md +357 -0
  15. package/.claude/commands/api-status.md +279 -0
  16. package/.claude/commands/api-verify.md +232 -0
  17. package/.claude/commands/beepboop.md +96 -0
  18. package/.claude/commands/busycommit.md +111 -0
  19. package/.claude/commands/commit.md +82 -0
  20. package/.claude/commands/cycle.md +137 -0
  21. package/.claude/commands/gap.md +85 -0
  22. package/.claude/commands/green.md +137 -0
  23. package/.claude/commands/issue.md +187 -0
  24. package/.claude/commands/ntfy-setup.md +91 -0
  25. package/.claude/commands/ntfy-test.md +74 -0
  26. package/.claude/commands/plan.md +167 -0
  27. package/.claude/commands/pr.md +121 -0
  28. package/.claude/commands/publish.md +40 -0
  29. package/.claude/commands/red.md +137 -0
  30. package/.claude/commands/refactor.md +137 -0
  31. package/.claude/commands/spike.md +137 -0
  32. package/.claude/commands/summarize.md +93 -0
  33. package/.claude/commands/tdd.md +139 -0
  34. package/.claude/commands/worktree-add.md +307 -0
  35. package/.claude/commands/worktree-cleanup.md +275 -0
  36. package/.claude/hooks/api-workflow-check.py +227 -0
  37. package/.claude/hooks/enforce-deep-research.py +185 -0
  38. package/.claude/hooks/enforce-disambiguation.py +155 -0
  39. package/.claude/hooks/enforce-documentation.py +192 -0
  40. package/.claude/hooks/enforce-environment.py +253 -0
  41. package/.claude/hooks/enforce-external-research.py +328 -0
  42. package/.claude/hooks/enforce-interview.py +421 -0
  43. package/.claude/hooks/enforce-refactor.py +189 -0
  44. package/.claude/hooks/enforce-research.py +159 -0
  45. package/.claude/hooks/enforce-schema.py +186 -0
  46. package/.claude/hooks/enforce-scope.py +160 -0
  47. package/.claude/hooks/enforce-tdd-red.py +250 -0
  48. package/.claude/hooks/enforce-verify.py +186 -0
  49. package/.claude/hooks/periodic-reground.py +154 -0
  50. package/.claude/hooks/session-startup.py +151 -0
  51. package/.claude/hooks/track-tool-use.py +626 -0
  52. package/.claude/hooks/verify-after-green.py +282 -0
  53. package/.claude/hooks/verify-implementation.py +225 -0
  54. package/.claude/research/index.json +6 -0
  55. package/.claude/settings.json +144 -0
  56. package/.claude/settings.local.json +12 -0
  57. package/.claude-plugin/marketplace.json +103 -0
  58. package/.skills/README.md +293 -0
  59. package/.skills/_shared/convert-commands.py +192 -0
  60. package/.skills/_shared/hooks/api-workflow-check.py +227 -0
  61. package/.skills/_shared/hooks/enforce-deep-research.py +185 -0
  62. package/.skills/_shared/hooks/enforce-disambiguation.py +155 -0
  63. package/.skills/_shared/hooks/enforce-documentation.py +192 -0
  64. package/.skills/_shared/hooks/enforce-environment.py +253 -0
  65. package/.skills/_shared/hooks/enforce-external-research.py +328 -0
  66. package/.skills/_shared/hooks/enforce-interview.py +421 -0
  67. package/.skills/_shared/hooks/enforce-refactor.py +189 -0
  68. package/.skills/_shared/hooks/enforce-research.py +159 -0
  69. package/.skills/_shared/hooks/enforce-schema.py +186 -0
  70. package/.skills/_shared/hooks/enforce-scope.py +160 -0
  71. package/.skills/_shared/hooks/enforce-tdd-red.py +250 -0
  72. package/.skills/_shared/hooks/enforce-verify.py +186 -0
  73. package/.skills/_shared/hooks/periodic-reground.py +154 -0
  74. package/.skills/_shared/hooks/session-startup.py +151 -0
  75. package/.skills/_shared/hooks/track-tool-use.py +626 -0
  76. package/.skills/_shared/hooks/verify-after-green.py +282 -0
  77. package/.skills/_shared/hooks/verify-implementation.py +225 -0
  78. package/.skills/_shared/install.sh +114 -0
  79. package/.skills/_shared/settings.json +93 -0
  80. package/.skills/add-command/SKILL.md +227 -0
  81. package/.skills/api-create/SKILL.md +623 -0
  82. package/.skills/api-env/SKILL.md +64 -0
  83. package/.skills/api-interview/SKILL.md +357 -0
  84. package/.skills/api-research/SKILL.md +370 -0
  85. package/.skills/api-status/SKILL.md +292 -0
  86. package/.skills/api-verify/SKILL.md +245 -0
  87. package/.skills/beepboop/SKILL.md +111 -0
  88. package/.skills/busycommit/SKILL.md +126 -0
  89. package/.skills/commit/SKILL.md +97 -0
  90. package/.skills/cycle/SKILL.md +152 -0
  91. package/.skills/gap/SKILL.md +100 -0
  92. package/.skills/green/SKILL.md +152 -0
  93. package/.skills/issue/SKILL.md +202 -0
  94. package/.skills/plan/SKILL.md +182 -0
  95. package/.skills/pr/SKILL.md +136 -0
  96. package/.skills/publish/SKILL.md +160 -0
  97. package/.skills/red/SKILL.md +152 -0
  98. package/.skills/refactor/SKILL.md +152 -0
  99. package/.skills/spike/SKILL.md +152 -0
  100. package/.skills/summarize/SKILL.md +108 -0
  101. package/.skills/tdd/SKILL.md +154 -0
  102. package/.skills/update-todos/SKILL.md +250 -0
  103. package/.skills/worktree-add/SKILL.md +322 -0
  104. package/.skills/worktree-cleanup/SKILL.md +290 -0
  105. package/CHANGELOG.md +115 -0
  106. package/README.md +161 -7101
  107. package/bin/cli.js +448 -805
  108. package/commands/README.md +66 -31
  109. package/commands/add-command.md +8 -5
  110. package/commands/beepboop.md +4 -5
  111. package/commands/busycommit.md +2 -3
  112. package/commands/commit.md +2 -3
  113. package/commands/cycle.md +2 -7
  114. package/commands/gap.md +2 -3
  115. package/commands/green.md +2 -7
  116. package/commands/hustle-api-continue.md +8 -5
  117. package/commands/hustle-api-create.md +70 -29
  118. package/commands/hustle-api-env.md +1 -0
  119. package/commands/hustle-api-interview.md +32 -19
  120. package/commands/hustle-api-research.md +47 -21
  121. package/commands/hustle-api-sessions.md +8 -7
  122. package/commands/hustle-api-status.md +21 -1
  123. package/commands/hustle-api-verify.md +14 -13
  124. package/commands/hustle-combine.md +488 -241
  125. package/commands/hustle-ui-create-page.md +113 -50
  126. package/commands/hustle-ui-create.md +179 -26
  127. package/commands/issue.md +3 -8
  128. package/commands/plan.md +2 -3
  129. package/commands/pr.md +2 -3
  130. package/commands/red.md +2 -7
  131. package/commands/refactor.md +2 -7
  132. package/commands/spike.md +2 -7
  133. package/commands/summarize.md +2 -3
  134. package/commands/tdd.md +2 -7
  135. package/commands/worktree-add.md +208 -216
  136. package/commands/worktree-cleanup.md +172 -178
  137. package/hooks/api-workflow-check.py +5 -3
  138. package/hooks/enforce-component-type-confirm.py +97 -0
  139. package/hooks/lib/__init__.py +1 -0
  140. package/hooks/lib/greptile.py +355 -0
  141. package/hooks/lib/ntfy.py +209 -0
  142. package/hooks/notify-input-needed.py +73 -0
  143. package/hooks/notify-phase-complete.py +90 -0
  144. package/hooks/run-code-review.py +246 -0
  145. package/hooks/track-token-usage.py +121 -0
  146. package/package.json +33 -12
  147. package/scripts/collect-test-results.ts +102 -77
  148. package/scripts/extract-parameters.ts +112 -70
  149. package/scripts/generate-test-manifest.ts +118 -77
  150. package/templates/.env.example +57 -0
  151. package/templates/BRAND_GUIDE.md +92 -52
  152. package/templates/CLAUDE-SECTION.md +40 -37
  153. package/templates/SPEC.json +186 -38
  154. package/templates/api-dev-state.json +33 -4
  155. package/templates/api-showcase/_components/APICard.tsx +22 -18
  156. package/templates/api-showcase/_components/APIModal.tsx +110 -64
  157. package/templates/api-showcase/_components/APIShowcase.tsx +53 -35
  158. package/templates/api-showcase/_components/APITester.tsx +128 -67
  159. package/templates/api-showcase/page.tsx +4 -4
  160. package/templates/api-test/page.tsx +51 -30
  161. package/templates/api-test/test-structure/route.ts +43 -34
  162. package/templates/component/Component.stories.tsx +41 -39
  163. package/templates/component/Component.test.tsx +96 -78
  164. package/templates/component/Component.tsx +63 -52
  165. package/templates/component/Component.types.ts +10 -6
  166. package/templates/component/Component.visual.spec.ts +170 -0
  167. package/templates/component/index.ts +2 -2
  168. package/templates/dev-tools/_components/DevToolsLanding.tsx +8 -8
  169. package/templates/dev-tools/page.tsx +4 -3
  170. package/templates/mcp-servers.json +30 -2
  171. package/templates/page/page.e2e.test.ts +56 -48
  172. package/templates/page/page.tsx +3 -3
  173. package/templates/shared/HeroHeader.tsx +16 -15
  174. package/templates/shared/index.ts +1 -1
  175. package/templates/ui-showcase/_components/PreviewCard.tsx +20 -20
  176. package/templates/ui-showcase/_components/PreviewModal.tsx +149 -108
  177. package/templates/ui-showcase/_components/UIShowcase.tsx +43 -35
  178. 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()