@hustle-together/api-dev-tools 3.12.3 → 3.12.16

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 (96) hide show
  1. package/.claude/commands/hustle-build.md +259 -0
  2. package/.claude/commands/hustle-combine.md +1089 -0
  3. package/.claude/commands/hustle-ui-create-page.md +1078 -0
  4. package/.claude/commands/hustle-ui-create.md +1058 -0
  5. package/.claude/hooks/auto-answer.py +305 -0
  6. package/.claude/hooks/cache-research.py +337 -0
  7. package/.claude/hooks/check-api-routes.py +168 -0
  8. package/.claude/hooks/check-playwright-setup.py +103 -0
  9. package/.claude/hooks/check-storybook-setup.py +81 -0
  10. package/.claude/hooks/check-update.py +132 -0
  11. package/.claude/hooks/completion-promise-detector.py +293 -0
  12. package/.claude/hooks/context-capacity-warning.py +171 -0
  13. package/.claude/hooks/detect-interruption.py +165 -0
  14. package/.claude/hooks/docs-update-check.py +120 -0
  15. package/.claude/hooks/enforce-a11y-audit.py +202 -0
  16. package/.claude/hooks/enforce-brand-guide.py +241 -0
  17. package/.claude/hooks/enforce-component-type-confirm.py +97 -0
  18. package/.claude/hooks/enforce-dry-run.py +134 -0
  19. package/.claude/hooks/enforce-freshness.py +184 -0
  20. package/.claude/hooks/enforce-page-components.py +186 -0
  21. package/.claude/hooks/enforce-page-data-schema.py +155 -0
  22. package/.claude/hooks/enforce-questions-sourced.py +146 -0
  23. package/.claude/hooks/enforce-schema-from-interview.py +248 -0
  24. package/.claude/hooks/enforce-ui-disambiguation.py +108 -0
  25. package/.claude/hooks/enforce-ui-interview.py +130 -0
  26. package/.claude/hooks/generate-adr-options.py +282 -0
  27. package/.claude/hooks/generate-manifest-entry.py +1161 -0
  28. package/.claude/hooks/hook_utils.py +609 -0
  29. package/.claude/hooks/lib/__init__.py +1 -0
  30. package/.claude/hooks/lib/__pycache__/__init__.cpython-314.pyc +0 -0
  31. package/.claude/hooks/lib/__pycache__/greptile.cpython-314.pyc +0 -0
  32. package/.claude/hooks/lib/__pycache__/ntfy.cpython-314.pyc +0 -0
  33. package/.claude/hooks/lib/greptile.py +355 -0
  34. package/.claude/hooks/lib/ntfy.py +209 -0
  35. package/.claude/hooks/notify-input-needed.py +73 -0
  36. package/.claude/hooks/notify-phase-complete.py +90 -0
  37. package/.claude/hooks/ntfy-on-question.py +240 -0
  38. package/.claude/hooks/orchestrator-completion.py +313 -0
  39. package/.claude/hooks/orchestrator-handoff.py +267 -0
  40. package/.claude/hooks/orchestrator-session-startup.py +146 -0
  41. package/.claude/hooks/parallel-orchestrator.py +451 -0
  42. package/.claude/hooks/project-document-prompt.py +302 -0
  43. package/.claude/hooks/remote-question-proxy.py +284 -0
  44. package/.claude/hooks/remote-question-server.py +1224 -0
  45. package/.claude/hooks/run-code-review.py +393 -0
  46. package/.claude/hooks/run-visual-qa.py +338 -0
  47. package/.claude/hooks/session-logger.py +323 -0
  48. package/.claude/hooks/test-orchestrator-reground.py +248 -0
  49. package/.claude/hooks/track-scope-coverage.py +220 -0
  50. package/.claude/hooks/track-token-usage.py +121 -0
  51. package/.claude/hooks/update-adr-decision.py +236 -0
  52. package/.claude/hooks/update-api-showcase.py +161 -0
  53. package/.claude/hooks/update-registry.py +352 -0
  54. package/.claude/hooks/update-testing-checklist.py +195 -0
  55. package/.claude/hooks/update-ui-showcase.py +224 -0
  56. package/.claude/settings.local.json +7 -1
  57. package/.claude/test-auto-answer-bot.py +183 -0
  58. package/.claude/test-completion-detector.py +263 -0
  59. package/.claude/test-orchestrator-state.json +20 -0
  60. package/.claude/test-orchestrator.sh +271 -0
  61. package/.skills/api-create/SKILL.md +88 -3
  62. package/.skills/docs-sync/SKILL.md +260 -0
  63. package/.skills/hustle-build/SKILL.md +459 -0
  64. package/.skills/hustle-build-review/SKILL.md +518 -0
  65. package/CHANGELOG.md +87 -0
  66. package/README.md +86 -9
  67. package/bin/cli.js +1302 -88
  68. package/commands/hustle-api-create.md +22 -0
  69. package/commands/hustle-combine.md +81 -2
  70. package/commands/hustle-ui-create-page.md +84 -2
  71. package/commands/hustle-ui-create.md +82 -2
  72. package/hooks/auto-answer.py +228 -0
  73. package/hooks/check-update.py +132 -0
  74. package/hooks/ntfy-on-question.py +227 -0
  75. package/hooks/orchestrator-completion.py +313 -0
  76. package/hooks/orchestrator-handoff.py +189 -0
  77. package/hooks/orchestrator-session-startup.py +146 -0
  78. package/hooks/periodic-reground.py +230 -67
  79. package/hooks/update-api-showcase.py +13 -1
  80. package/hooks/update-ui-showcase.py +13 -1
  81. package/package.json +7 -3
  82. package/scripts/extract-schema-docs.cjs +322 -0
  83. package/templates/CLAUDE-SECTION.md +89 -64
  84. package/templates/api-showcase/_components/APIModal.tsx +100 -8
  85. package/templates/api-showcase/_components/APIShowcase.tsx +36 -4
  86. package/templates/api-showcase/_components/APITester.tsx +367 -58
  87. package/templates/docs/page.tsx +230 -0
  88. package/templates/hustle-build-defaults.json +84 -0
  89. package/templates/hustle-dev-dashboard/page.tsx +365 -0
  90. package/templates/playwright-report/page.tsx +258 -0
  91. package/templates/settings.json +88 -7
  92. package/templates/test-results/page.tsx +237 -0
  93. package/templates/typedoc.json +19 -0
  94. package/templates/ui-showcase/_components/UIShowcase.tsx +1 -1
  95. package/templates/ui-showcase/page.tsx +1 -1
  96. package/.claude/api-dev-state.json +0 -466
@@ -468,6 +468,28 @@ Both conditions must be true for the flag to be set.
468
468
  └───────────────────────────────────────────────────────────┘
469
469
  ```
470
470
 
471
+ ### End-of-Workflow Summary
472
+
473
+ After successful API creation, display:
474
+
475
+ ```
476
+ ═══════════════════════════════════════════════════════════════
477
+ ✅ API CREATED: [endpoint-name]
478
+
479
+ 📍 Quick Links:
480
+ • Test it: /api-showcase
481
+ • API Docs: /docs/api/[endpoint-name]
482
+ • Run tests: pnpm test src/app/api/v2/[endpoint-name]
483
+ • TypeDoc: pnpm typedoc
484
+
485
+ 📊 Dashboard: /hustle-dev-dashboard
486
+
487
+ Next Steps:
488
+ • /hustle-combine - Combine with other APIs
489
+ • /commit - Commit your changes
490
+ ═══════════════════════════════════════════════════════════════
491
+ ```
492
+
471
493
  ### Showcase Redirect
472
494
 
473
495
  After successful API creation, output:
@@ -1,9 +1,65 @@
1
- # Hustle Combine - API and UI Orchestration Workflow v3.11.0
1
+ # Hustle Combine - API and UI Orchestration Workflow v4.0.0
2
2
 
3
- **Usage:** `/hustle-combine [api|ui]`
3
+ **Usage:** `/hustle-combine [api|ui] [--auto] [--resume [workflow-id]]`
4
4
 
5
5
  **Purpose:** Combines existing APIs or UI elements from the registry into new orchestration endpoints or composed components.
6
6
 
7
+ ## Arguments
8
+
9
+ - `[api|ui]` - Mode: combine APIs or UI elements
10
+ - `--auto` - Fully autonomous mode, auto-answers all questions with comprehensive defaults
11
+ - `--resume [workflow-id]` - Resume an interrupted workflow from its last phase
12
+
13
+ ---
14
+
15
+ ## Auto Mode (`--auto`)
16
+
17
+ When `--auto` flag is used:
18
+
19
+ 1. **No Interactive Questions:**
20
+ - All questions auto-answered with comprehensive defaults
21
+ - Uses `.claude/hustle-build-defaults.json` for configured answers
22
+ - Falls back to "most comprehensive" option when no default exists
23
+
24
+ 2. **Comprehensive Selection Logic:**
25
+ - Selects parallel execution (when APIs are independent)
26
+ - Uses partial-success error handling
27
+ - Enables unified caching strategy
28
+ - Uses exponential retry with 30s timeout
29
+
30
+ 3. **API Selection in Orchestrated Mode:**
31
+ - When `orchestrated: true`, APIs are pre-selected by orchestrator
32
+ - Selection phase is skipped, proceeds directly to Scope
33
+
34
+ 4. **Logging:**
35
+ - All decisions logged to `.claude/workflow-logs/hustle-combine/[workflow-id].json`
36
+ - Review with `/hustle-combine-review [workflow-id]`
37
+
38
+ ---
39
+
40
+ ## Resume Mode (`--resume`)
41
+
42
+ When `--resume [workflow-id]` is used:
43
+
44
+ 1. Load state from `.claude/api-dev-state.json`
45
+ 2. Find the last incomplete phase
46
+ 3. Continue from that point
47
+ 4. Preserve all previous decisions and API selections
48
+
49
+ ---
50
+
51
+ ## Orchestrated Mode
52
+
53
+ When running as part of `/hustle-build`:
54
+
55
+ 1. `orchestrated: true` flag is set in state
56
+ 2. `shared_decisions` are pre-filled from orchestrator interview
57
+ 3. Source APIs are pre-selected based on orchestrator decomposition
58
+ 4. Questions covered by shared_decisions are SKIPPED
59
+ 5. Only combination-specific questions are asked (execution order, caching)
60
+
61
+ ---
62
+
7
63
  ## Overview
8
64
 
9
65
  This command reads from `.claude/registry.json` to present available elements for combination. It creates NEW orchestration layers using EXISTING, tested components.
@@ -837,6 +893,29 @@ Update registry.json with the new combined API:
837
893
  }
838
894
  ```
839
895
 
896
+ ### End-of-Workflow Summary
897
+
898
+ After successful combination, display:
899
+
900
+ ```
901
+ ═══════════════════════════════════════════════════════════════
902
+ ✅ COMBINED API CREATED: [combined-name]
903
+
904
+ 📍 Quick Links:
905
+ • Test it: /api-showcase
906
+ • API Docs: /docs/api/[combined-name]
907
+ • Run tests: pnpm test src/app/api/v2/[combined-name]
908
+ • TypeDoc: pnpm typedoc
909
+
910
+ 📦 Combined: [api1] + [api2]
911
+ 📊 Dashboard: /hustle-dev-dashboard
912
+
913
+ Next Steps:
914
+ • /commit - Commit your changes
915
+ • /hustle-api-create - Create another API
916
+ ═══════════════════════════════════════════════════════════════
917
+ ```
918
+
840
919
  ---
841
920
 
842
921
  ## Mode B: Combine UI (Coming Soon)
@@ -5,11 +5,71 @@ argument-hint: [page-name]
5
5
 
6
6
  # Hustle UI Create - Page Mode
7
7
 
8
- **Version:** 3.11.0
8
+ **Version:** 4.0.0
9
9
  **14-phase workflow for creating Next.js App Router pages**
10
10
 
11
+ **Usage:** `/hustle-ui-create-page [page-name] [--auto] [--resume [workflow-id]]`
12
+
11
13
  You are creating a page using the Hustle Together interview-driven workflow.
12
14
 
15
+ ## Arguments
16
+
17
+ - `[page-name]` - Name of the page to create
18
+ - `--auto` - Fully autonomous mode, auto-answers all questions with comprehensive defaults
19
+ - `--resume [workflow-id]` - Resume an interrupted workflow from its last phase
20
+
21
+ ---
22
+
23
+ ## Auto Mode (`--auto`)
24
+
25
+ When `--auto` flag is used:
26
+
27
+ 1. **No Interactive Questions:**
28
+ - All questions auto-answered with comprehensive defaults
29
+ - Uses `.claude/hustle-build-defaults.json` for configured answers
30
+ - Falls back to "most comprehensive" option when no default exists
31
+
32
+ 2. **Comprehensive Selection Logic:**
33
+ - Uses responsive-grid layout
34
+ - Enables full SEO (Open Graph, Twitter cards, JSON-LD)
35
+ - Creates loading states and error boundaries
36
+ - Enables prefetching and Suspense
37
+ - Uses all available components from registry
38
+
39
+ 3. **Error Handling:**
40
+ - E2E test failures: Retry 3x, then log and continue
41
+ - Missing API routes: Log warning, create stubs
42
+ - Performance budget exceeded: Log warning, continue
43
+
44
+ 4. **Logging:**
45
+ - All decisions logged to `.claude/workflow-logs/ui-create-page/[workflow-id].json`
46
+ - Review with `/hustle-ui-create-page-review [workflow-id]`
47
+
48
+ ---
49
+
50
+ ## Resume Mode (`--resume`)
51
+
52
+ When `--resume [workflow-id]` is used:
53
+
54
+ 1. Load state from `.claude/api-dev-state.json`
55
+ 2. Find the last incomplete phase
56
+ 3. Continue from that point
57
+ 4. Preserve all previous decisions
58
+
59
+ ---
60
+
61
+ ## Orchestrated Mode
62
+
63
+ When running as part of `/hustle-build`:
64
+
65
+ 1. `orchestrated: true` flag is set in state
66
+ 2. `shared_decisions` are pre-filled from orchestrator interview
67
+ 3. Questions covered by shared_decisions are SKIPPED (e.g., auth, brand guide, testing level)
68
+ 4. Components to use are pre-selected based on orchestrator decomposition
69
+ 5. Only page-specific questions are asked (layout, SEO details)
70
+
71
+ ---
72
+
13
73
  ## Pre-Flight Check
14
74
 
15
75
  Before starting, verify state file exists:
@@ -911,6 +971,28 @@ Run `pnpm dev` and navigate to /ui-showcase to see it.
911
971
 
912
972
  Update state: `phases.completion.status = "complete"`
913
973
 
974
+ ### End-of-Workflow Summary
975
+
976
+ After successful page creation, display:
977
+
978
+ ```
979
+ ═══════════════════════════════════════════════════════════════
980
+ ✅ PAGE CREATED: [PageName]
981
+
982
+ 📍 Quick Links:
983
+ • View page: /[page-name]
984
+ • UI Showcase: /ui-showcase
985
+ • Run E2E: pnpm playwright test src/app/[page-name]
986
+
987
+ 📊 Dashboard: /hustle-dev-dashboard
988
+
989
+ Next Steps:
990
+ • /hustle-ui-create - Create components for this page
991
+ • /hustle-api-create - Create APIs this page needs
992
+ • /commit - Commit your changes
993
+ ═══════════════════════════════════════════════════════════════
994
+ ```
995
+
914
996
  ---
915
997
 
916
998
  # State File Structure
@@ -992,5 +1074,5 @@ Update state: `phases.completion.status = "complete"`
992
1074
 
993
1075
  ---
994
1076
 
995
- **Version:** 3.11.0
1077
+ **Version:** 4.0.0
996
1078
  **Last Updated:** 2025-12-28
@@ -5,11 +5,69 @@ argument-hint: [component-name]
5
5
 
6
6
  # Hustle UI Create
7
7
 
8
- **Version:** 3.11.0
8
+ **Version:** 4.0.0
9
9
  **14-phase workflow for creating UI components and pages**
10
10
 
11
+ **Usage:** `/hustle-ui-create [component-name] [--auto] [--resume [workflow-id]]`
12
+
11
13
  You are creating a UI element using the Hustle Together interview-driven workflow.
12
14
 
15
+ ## Arguments
16
+
17
+ - `[component-name]` - Name of the component to create
18
+ - `--auto` - Fully autonomous mode, auto-answers all questions with comprehensive defaults
19
+ - `--resume [workflow-id]` - Resume an interrupted workflow from its last phase
20
+
21
+ ---
22
+
23
+ ## Auto Mode (`--auto`)
24
+
25
+ When `--auto` flag is used:
26
+
27
+ 1. **No Interactive Questions:**
28
+ - All questions auto-answered with comprehensive defaults
29
+ - Uses `.claude/hustle-build-defaults.json` for configured answers
30
+ - Falls back to "most comprehensive" option when no default exists
31
+
32
+ 2. **Comprehensive Selection Logic:**
33
+ - Selects ALL variants (size, color, state)
34
+ - Enables full accessibility (WCAG 2.1 AA)
35
+ - Enables animations and responsive design
36
+ - Creates all Storybook stories
37
+
38
+ 3. **Error Handling:**
39
+ - Test failures: Retry 3x, then log and continue
40
+ - Visual regression: Update baselines automatically
41
+ - Missing packages: Install automatically
42
+
43
+ 4. **Logging:**
44
+ - All decisions logged to `.claude/workflow-logs/ui-create/[workflow-id].json`
45
+ - Review with `/hustle-ui-create-review [workflow-id]`
46
+
47
+ ---
48
+
49
+ ## Resume Mode (`--resume`)
50
+
51
+ When `--resume [workflow-id]` is used:
52
+
53
+ 1. Load state from `.claude/api-dev-state.json`
54
+ 2. Find the last incomplete phase
55
+ 3. Continue from that point
56
+ 4. Preserve all previous decisions
57
+
58
+ ---
59
+
60
+ ## Orchestrated Mode
61
+
62
+ When running as part of `/hustle-build`:
63
+
64
+ 1. `orchestrated: true` flag is set in state
65
+ 2. `shared_decisions` are pre-filled from orchestrator interview
66
+ 3. Questions covered by shared_decisions are SKIPPED (e.g., brand guide, testing level)
67
+ 4. Only component-specific questions are asked (variants, props)
68
+
69
+ ---
70
+
13
71
  ## Pre-Flight Check
14
72
 
15
73
  Before starting, verify state file exists:
@@ -901,6 +959,28 @@ For Sandpack live editing, install: `pnpm add @codesandbox/sandpack-react`
901
959
 
902
960
  Update state: `phases.completion.status = "complete"`
903
961
 
962
+ ### End-of-Workflow Summary
963
+
964
+ After successful component creation, display:
965
+
966
+ ```
967
+ ═══════════════════════════════════════════════════════════════
968
+ ✅ COMPONENT CREATED: [ComponentName]
969
+
970
+ 📍 Quick Links:
971
+ • Preview it: /ui-showcase
972
+ • Storybook: http://localhost:6006
973
+ • Run tests: pnpm test src/components/[ComponentName]
974
+ • Visual tests: pnpm playwright test --grep "[ComponentName]"
975
+
976
+ 📊 Dashboard: /hustle-dev-dashboard
977
+
978
+ Next Steps:
979
+ • /hustle-ui-create-page - Create a page using this component
980
+ • /commit - Commit your changes
981
+ ═══════════════════════════════════════════════════════════════
982
+ ```
983
+
904
984
  ---
905
985
 
906
986
  # Page Mode (14 Phases)
@@ -974,5 +1054,5 @@ See full page mode documentation in `/hustle-ui-create-page.md` (if implementing
974
1054
 
975
1055
  ---
976
1056
 
977
- **Version:** 3.11.0
1057
+ **Version:** 4.0.0
978
1058
  **Last Updated:** 2025-12-28
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Auto-answer hook for --auto mode.
4
+
5
+ This hook intercepts AskUserQuestion calls when running in auto-mode
6
+ and either:
7
+ 1. Uses pre-configured defaults from hustle-build-defaults.json
8
+ 2. Spawns a Haiku sub-agent to pick the most comprehensive option
9
+
10
+ Hook Type: PreToolUse (matcher: AskUserQuestion)
11
+ """
12
+
13
+ import json
14
+ import os
15
+ import sys
16
+ from pathlib import Path
17
+
18
+
19
+ def load_state():
20
+ """Load workflow state to check if in auto mode"""
21
+ project_dir = os.environ.get("CLAUDE_PROJECT_DIR", ".")
22
+
23
+ # Check hustle-build state first
24
+ build_state = Path(project_dir) / ".claude" / "hustle-build-state.json"
25
+ if build_state.exists():
26
+ try:
27
+ state = json.loads(build_state.read_text())
28
+ if state.get("mode") == "auto":
29
+ return state, "build"
30
+ except Exception:
31
+ pass
32
+
33
+ # Check api-dev state
34
+ api_state = Path(project_dir) / ".claude" / "api-dev-state.json"
35
+ if api_state.exists():
36
+ try:
37
+ state = json.loads(api_state.read_text())
38
+ if state.get("mode") == "auto":
39
+ return state, "workflow"
40
+ except Exception:
41
+ pass
42
+
43
+ return None, None
44
+
45
+
46
+ def load_defaults():
47
+ """Load pre-configured default answers"""
48
+ project_dir = os.environ.get("CLAUDE_PROJECT_DIR", ".")
49
+ defaults_file = Path(project_dir) / ".claude" / "hustle-build-defaults.json"
50
+
51
+ if defaults_file.exists():
52
+ try:
53
+ return json.loads(defaults_file.read_text())
54
+ except Exception:
55
+ pass
56
+
57
+ return {}
58
+
59
+
60
+ def find_comprehensive_option(options):
61
+ """
62
+ Find the most comprehensive option based on keywords.
63
+
64
+ Comprehensive options typically include words like:
65
+ - "all", "full", "complete", "comprehensive"
66
+ - Higher numbers (e.g., "100%" vs "50%")
67
+ - More features listed
68
+ """
69
+ if not options:
70
+ return None
71
+
72
+ comprehensive_keywords = [
73
+ "all", "full", "complete", "comprehensive", "everything",
74
+ "maximum", "extensive", "detailed", "thorough", "wcag-aa"
75
+ ]
76
+
77
+ # Score each option
78
+ scored = []
79
+ for i, opt in enumerate(options):
80
+ label = opt.get("label", "").lower()
81
+ description = opt.get("description", "").lower()
82
+ text = f"{label} {description}"
83
+
84
+ score = 0
85
+
86
+ # Check for comprehensive keywords
87
+ for keyword in comprehensive_keywords:
88
+ if keyword in text:
89
+ score += 10
90
+
91
+ # Check for "(Recommended)" suffix
92
+ if "recommended" in label.lower():
93
+ score += 20
94
+
95
+ # Prefer options with more content (longer descriptions = more features)
96
+ score += len(description) / 50
97
+
98
+ scored.append((i, score, opt))
99
+
100
+ # Sort by score descending
101
+ scored.sort(key=lambda x: x[1], reverse=True)
102
+
103
+ # Return the index of the best option (0-based)
104
+ if scored:
105
+ return scored[0][0]
106
+
107
+ return 0 # Default to first option
108
+
109
+
110
+ def get_question_key(questions):
111
+ """Extract a key from the question for lookup in defaults"""
112
+ if not questions or len(questions) == 0:
113
+ return None
114
+
115
+ q = questions[0]
116
+ header = q.get("header", "").lower().replace(" ", "_")
117
+ return header
118
+
119
+
120
+ def main():
121
+ # Get tool input from environment
122
+ tool_input = os.environ.get("CLAUDE_TOOL_INPUT", "{}")
123
+
124
+ try:
125
+ input_data = json.loads(tool_input)
126
+ except Exception:
127
+ print(json.dumps({"continue": True}))
128
+ return
129
+
130
+ # Check if in auto mode
131
+ state, state_type = load_state()
132
+
133
+ if not state:
134
+ # Not in auto mode, continue normally
135
+ print(json.dumps({"continue": True}))
136
+ return
137
+
138
+ # Load defaults
139
+ defaults = load_defaults()
140
+
141
+ questions = input_data.get("questions", [])
142
+ if not questions:
143
+ print(json.dumps({"continue": True}))
144
+ return
145
+
146
+ # Try to find pre-configured answer
147
+ question_key = get_question_key(questions)
148
+ answers = {}
149
+
150
+ for q in questions:
151
+ header = q.get("header", "")
152
+ options = q.get("options", [])
153
+ question_text = q.get("question", "")
154
+
155
+ # Check defaults first
156
+ default_answer = None
157
+ if question_key and question_key in defaults:
158
+ default_answer = defaults[question_key]
159
+ elif header.lower().replace(" ", "_") in defaults:
160
+ default_answer = defaults[header.lower().replace(" ", "_")]
161
+
162
+ if default_answer is not None:
163
+ # Use pre-configured default
164
+ answers[question_text] = default_answer
165
+ else:
166
+ # Auto-select comprehensive option
167
+ best_idx = find_comprehensive_option(options)
168
+ if best_idx is not None and options:
169
+ answers[question_text] = options[best_idx].get("label", "")
170
+
171
+ if answers:
172
+ # Log the auto-answer
173
+ log_auto_answer(state, questions, answers)
174
+
175
+ # Return the auto-selected answers
176
+ # The hook will inject these as if the user selected them
177
+ result = {
178
+ "continue": True,
179
+ "additionalContext": f"""
180
+ ## Auto-Mode Active
181
+
182
+ Questions were auto-answered with comprehensive defaults:
183
+ {json.dumps(answers, indent=2)}
184
+
185
+ These selections prioritize:
186
+ - Maximum feature coverage
187
+ - Full testing
188
+ - Comprehensive documentation
189
+ - Best practices
190
+
191
+ Review in `/hustle-build-review` after completion.
192
+ """
193
+ }
194
+ print(json.dumps(result))
195
+ else:
196
+ print(json.dumps({"continue": True}))
197
+
198
+
199
+ def log_auto_answer(state, questions, answers):
200
+ """Log auto-answered questions to build log"""
201
+ project_dir = os.environ.get("CLAUDE_PROJECT_DIR", ".")
202
+ logs_dir = Path(project_dir) / ".claude" / "workflow-logs"
203
+ logs_dir.mkdir(parents=True, exist_ok=True)
204
+
205
+ build_id = state.get("build_id", state.get("workflow_id", "unknown"))
206
+ log_file = logs_dir / f"{build_id}.json"
207
+
208
+ try:
209
+ if log_file.exists():
210
+ log = json.loads(log_file.read_text())
211
+ else:
212
+ log = {"auto_answers": []}
213
+
214
+ from datetime import datetime
215
+ log["auto_answers"].append({
216
+ "timestamp": datetime.now().isoformat(),
217
+ "questions": [q.get("question") for q in questions],
218
+ "answers": answers,
219
+ "reason": "auto-comprehensive"
220
+ })
221
+
222
+ log_file.write_text(json.dumps(log, indent=2))
223
+ except Exception:
224
+ pass
225
+
226
+
227
+ if __name__ == "__main__":
228
+ main()
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Check for api-dev-tools updates at session start.
4
+
5
+ This hook runs at SessionStart and checks npm registry for newer versions.
6
+ Non-blocking - only injects a message if update available.
7
+
8
+ Hook Type: SessionStart
9
+ """
10
+
11
+ import json
12
+ import os
13
+ import sys
14
+ import subprocess
15
+ from pathlib import Path
16
+
17
+
18
+ def get_installed_version():
19
+ """Get currently installed version from package.json"""
20
+ project_dir = os.environ.get("CLAUDE_PROJECT_DIR", ".")
21
+ package_json = Path(project_dir) / "package.json"
22
+
23
+ if package_json.exists():
24
+ try:
25
+ data = json.loads(package_json.read_text())
26
+ # Check if this project uses api-dev-tools
27
+ deps = data.get("devDependencies", {})
28
+ deps.update(data.get("dependencies", {}))
29
+
30
+ if "@hustle-together/api-dev-tools" in deps:
31
+ version = deps["@hustle-together/api-dev-tools"]
32
+ # Remove ^ or ~ prefix
33
+ return version.lstrip("^~")
34
+ except Exception:
35
+ pass
36
+
37
+ # Check for version in state file
38
+ state_file = Path(project_dir) / ".claude" / "api-dev-state.json"
39
+ if state_file.exists():
40
+ try:
41
+ state = json.loads(state_file.read_text())
42
+ return state.get("version", "0.0.0")
43
+ except Exception:
44
+ pass
45
+
46
+ return None
47
+
48
+
49
+ def get_latest_version():
50
+ """Check npm registry for latest version"""
51
+ try:
52
+ result = subprocess.run(
53
+ ["npm", "view", "@hustle-together/api-dev-tools", "version"],
54
+ capture_output=True,
55
+ text=True,
56
+ timeout=5
57
+ )
58
+ if result.returncode == 0:
59
+ return result.stdout.strip()
60
+ except Exception:
61
+ pass
62
+ return None
63
+
64
+
65
+ def version_tuple(v):
66
+ """Convert version string to tuple for comparison"""
67
+ try:
68
+ return tuple(map(int, v.split(".")))
69
+ except Exception:
70
+ return (0, 0, 0)
71
+
72
+
73
+ def main():
74
+ # Check if we should skip (already checked recently)
75
+ project_dir = os.environ.get("CLAUDE_PROJECT_DIR", ".")
76
+ state_file = Path(project_dir) / ".claude" / "api-dev-state.json"
77
+
78
+ try:
79
+ if state_file.exists():
80
+ state = json.loads(state_file.read_text())
81
+ last_check = state.get("last_update_check")
82
+
83
+ if last_check:
84
+ from datetime import datetime, timedelta
85
+ last_check_dt = datetime.fromisoformat(last_check)
86
+ if datetime.now() - last_check_dt < timedelta(hours=24):
87
+ # Already checked today, skip
88
+ print(json.dumps({"continue": True}))
89
+ return
90
+ except Exception:
91
+ pass
92
+
93
+ installed = get_installed_version()
94
+ latest = get_latest_version()
95
+
96
+ result = {"continue": True}
97
+
98
+ if installed and latest:
99
+ if version_tuple(latest) > version_tuple(installed):
100
+ result["additionalContext"] = f"""
101
+ ## Update Available
102
+
103
+ A new version of api-dev-tools is available:
104
+ - **Current**: {installed}
105
+ - **Latest**: {latest}
106
+
107
+ To update, run:
108
+ ```bash
109
+ npx @hustle-together/api-dev-tools@latest
110
+ ```
111
+
112
+ This update may include new features, bug fixes, and improved workflows.
113
+ """
114
+ # Update state with last check time
115
+ try:
116
+ if state_file.exists():
117
+ state = json.loads(state_file.read_text())
118
+ else:
119
+ state = {}
120
+
121
+ from datetime import datetime
122
+ state["last_update_check"] = datetime.now().isoformat()
123
+ state["available_update"] = latest
124
+ state_file.write_text(json.dumps(state, indent=2))
125
+ except Exception:
126
+ pass
127
+
128
+ print(json.dumps(result))
129
+
130
+
131
+ if __name__ == "__main__":
132
+ main()