@hustle-together/api-dev-tools 3.6.4 → 3.9.2

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 (61) hide show
  1. package/README.md +5307 -258
  2. package/bin/cli.js +348 -20
  3. package/commands/README.md +459 -71
  4. package/commands/hustle-api-continue.md +158 -0
  5. package/commands/{api-create.md → hustle-api-create.md} +22 -2
  6. package/commands/{api-env.md → hustle-api-env.md} +4 -4
  7. package/commands/{api-interview.md → hustle-api-interview.md} +1 -1
  8. package/commands/{api-research.md → hustle-api-research.md} +3 -3
  9. package/commands/hustle-api-sessions.md +149 -0
  10. package/commands/{api-status.md → hustle-api-status.md} +16 -16
  11. package/commands/{api-verify.md → hustle-api-verify.md} +2 -2
  12. package/commands/hustle-combine.md +763 -0
  13. package/commands/hustle-ui-create.md +825 -0
  14. package/hooks/api-workflow-check.py +385 -19
  15. package/hooks/cache-research.py +337 -0
  16. package/hooks/check-playwright-setup.py +103 -0
  17. package/hooks/check-storybook-setup.py +81 -0
  18. package/hooks/detect-interruption.py +165 -0
  19. package/hooks/enforce-brand-guide.py +131 -0
  20. package/hooks/enforce-documentation.py +60 -8
  21. package/hooks/enforce-freshness.py +184 -0
  22. package/hooks/enforce-questions-sourced.py +146 -0
  23. package/hooks/enforce-schema-from-interview.py +248 -0
  24. package/hooks/enforce-ui-disambiguation.py +108 -0
  25. package/hooks/enforce-ui-interview.py +130 -0
  26. package/hooks/generate-manifest-entry.py +981 -0
  27. package/hooks/session-logger.py +297 -0
  28. package/hooks/session-startup.py +65 -10
  29. package/hooks/track-scope-coverage.py +220 -0
  30. package/hooks/track-tool-use.py +81 -1
  31. package/hooks/update-api-showcase.py +149 -0
  32. package/hooks/update-registry.py +352 -0
  33. package/hooks/update-ui-showcase.py +148 -0
  34. package/package.json +8 -2
  35. package/templates/BRAND_GUIDE.md +299 -0
  36. package/templates/CLAUDE-SECTION.md +56 -24
  37. package/templates/SPEC.json +640 -0
  38. package/templates/api-dev-state.json +179 -161
  39. package/templates/api-showcase/APICard.tsx +153 -0
  40. package/templates/api-showcase/APIModal.tsx +375 -0
  41. package/templates/api-showcase/APIShowcase.tsx +231 -0
  42. package/templates/api-showcase/APITester.tsx +522 -0
  43. package/templates/api-showcase/page.tsx +41 -0
  44. package/templates/component/Component.stories.tsx +172 -0
  45. package/templates/component/Component.test.tsx +237 -0
  46. package/templates/component/Component.tsx +86 -0
  47. package/templates/component/Component.types.ts +55 -0
  48. package/templates/component/index.ts +15 -0
  49. package/templates/dev-tools/_components/DevToolsLanding.tsx +320 -0
  50. package/templates/dev-tools/page.tsx +10 -0
  51. package/templates/page/page.e2e.test.ts +218 -0
  52. package/templates/page/page.tsx +42 -0
  53. package/templates/performance-budgets.json +58 -0
  54. package/templates/registry.json +13 -0
  55. package/templates/settings.json +74 -0
  56. package/templates/shared/HeroHeader.tsx +261 -0
  57. package/templates/shared/index.ts +1 -0
  58. package/templates/ui-showcase/PreviewCard.tsx +315 -0
  59. package/templates/ui-showcase/PreviewModal.tsx +676 -0
  60. package/templates/ui-showcase/UIShowcase.tsx +262 -0
  61. package/templates/ui-showcase/page.tsx +26 -0
@@ -1,160 +1,14 @@
1
1
  {
2
- "version": "3.0.0",
2
+ "version": "3.7.0",
3
3
  "created_at": null,
4
- "endpoint": null,
5
- "library": null,
6
- "session_id": null,
4
+ "active_endpoint": null,
5
+ "endpoints": {},
7
6
  "turn_count": 0,
8
7
  "last_turn_timestamp": null,
9
8
  "research_queries": [],
10
9
  "prompt_detections": [],
11
- "phases": {
12
- "disambiguation": {
13
- "status": "not_started",
14
- "clarified": null,
15
- "search_variations": [],
16
- "user_question_asked": false,
17
- "user_selected": null,
18
- "phase_exit_confirmed": false,
19
- "last_question_type": null,
20
- "description": "Pre-research disambiguation to clarify ambiguous requests"
21
- },
22
- "scope": {
23
- "status": "not_started",
24
- "confirmed": false,
25
- "user_question_asked": false,
26
- "user_confirmed": false,
27
- "phase_exit_confirmed": false,
28
- "last_question_type": null,
29
- "description": "Initial scope understanding and confirmation"
30
- },
31
- "research_initial": {
32
- "status": "not_started",
33
- "sources": [],
34
- "summary_shown": false,
35
- "user_question_asked": false,
36
- "user_approved": false,
37
- "phase_exit_confirmed": false,
38
- "last_question_type": null,
39
- "description": "Context7/WebSearch research for live documentation"
40
- },
41
- "interview": {
42
- "status": "not_started",
43
- "questions": [],
44
- "user_question_count": 0,
45
- "structured_question_count": 0,
46
- "decisions": {},
47
- "user_question_asked": false,
48
- "user_completed": false,
49
- "phase_exit_confirmed": false,
50
- "last_question_type": null,
51
- "description": "Structured interview about requirements (generated FROM research)"
52
- },
53
- "research_deep": {
54
- "status": "not_started",
55
- "sources": [],
56
- "proposed_searches": [],
57
- "approved_searches": [],
58
- "executed_searches": [],
59
- "skipped_searches": [],
60
- "proposals_shown": false,
61
- "user_question_asked": false,
62
- "user_approved": false,
63
- "phase_exit_confirmed": false,
64
- "last_question_type": null,
65
- "description": "Deep dive based on interview answers (adaptive, not shotgun)"
66
- },
67
- "schema_creation": {
68
- "status": "not_started",
69
- "schema_file": null,
70
- "fields_count": 0,
71
- "schema_shown": false,
72
- "user_question_asked": false,
73
- "user_confirmed": false,
74
- "phase_exit_confirmed": false,
75
- "last_question_type": null,
76
- "description": "Zod schema creation from research"
77
- },
78
- "environment_check": {
79
- "status": "not_started",
80
- "keys_required": [],
81
- "keys_found": [],
82
- "keys_missing": [],
83
- "env_shown": false,
84
- "user_question_asked": false,
85
- "user_ready": false,
86
- "phase_exit_confirmed": false,
87
- "last_question_type": null,
88
- "description": "API key and environment verification"
89
- },
90
- "tdd_red": {
91
- "status": "not_started",
92
- "test_file": null,
93
- "test_count": 0,
94
- "test_scenarios": [],
95
- "matrix_shown": false,
96
- "user_question_asked": false,
97
- "user_approved": false,
98
- "phase_exit_confirmed": false,
99
- "last_question_type": null,
100
- "description": "Write failing tests first"
101
- },
102
- "tdd_green": {
103
- "status": "not_started",
104
- "implementation_file": null,
105
- "all_tests_passing": false,
106
- "phase_exit_confirmed": false,
107
- "last_question_type": null,
108
- "description": "Minimal implementation to pass tests"
109
- },
110
- "verify": {
111
- "status": "not_started",
112
- "gaps_found": 0,
113
- "gaps_fixed": 0,
114
- "gaps_skipped": 0,
115
- "intentional_omissions": [],
116
- "re_research_done": false,
117
- "gap_analysis_shown": false,
118
- "user_question_asked": false,
119
- "user_decided": false,
120
- "user_decision": null,
121
- "phase_exit_confirmed": false,
122
- "last_question_type": null,
123
- "description": "Re-research after Green to verify implementation matches docs"
124
- },
125
- "tdd_refactor": {
126
- "status": "not_started",
127
- "phase_exit_confirmed": false,
128
- "last_question_type": null,
129
- "description": "Code cleanup while keeping tests green"
130
- },
131
- "documentation": {
132
- "status": "not_started",
133
- "files_updated": [],
134
- "manifest_updated": false,
135
- "openapi_updated": false,
136
- "research_cached": false,
137
- "checklist_shown": false,
138
- "user_question_asked": false,
139
- "user_confirmed": false,
140
- "phase_exit_confirmed": false,
141
- "last_question_type": null,
142
- "description": "Update manifests, OpenAPI, cache research"
143
- },
144
- "completion": {
145
- "status": "not_started",
146
- "all_tests_passing": false,
147
- "coverage_100_percent": false,
148
- "typescript_compiles": false,
149
- "docs_updated": false,
150
- "commit_ready": false,
151
- "files_created": [],
152
- "files_modified": [],
153
- "phase_exit_confirmed": false,
154
- "last_question_type": null,
155
- "description": "Final verification - all tests pass, docs complete, ready for commit"
156
- }
157
- },
10
+ "decisions_history": [],
11
+ "reground_history": [],
158
12
  "manifest_generation": {
159
13
  "last_run": null,
160
14
  "manifest_generated": false,
@@ -166,14 +20,178 @@
166
20
  "results": "src/app/api-test/test-results.json"
167
21
  }
168
22
  },
169
- "verification": {
170
- "all_sources_fetched": false,
171
- "schema_matches_docs": false,
172
- "tests_cover_params": false,
173
- "all_tests_passing": false,
174
- "coverage_percent": null,
175
- "post_green_verification": false
176
- },
177
- "research_index": {},
178
- "reground_history": []
23
+ "_endpoint_template": {
24
+ "_comment": "This is a template for new endpoints - copy when creating a new workflow",
25
+ "started_at": null,
26
+ "status": "not_started",
27
+ "library": null,
28
+ "enforce_freshness": true,
29
+ "freshness_threshold_days": 7,
30
+ "scope": {
31
+ "discovered_features": [],
32
+ "implemented_features": [],
33
+ "deferred_features": [],
34
+ "coverage_percent": 0
35
+ },
36
+ "session": {
37
+ "interrupted_at": null,
38
+ "interrupted_phase": null,
39
+ "recovery_checkpoint": null
40
+ },
41
+ "phases": {
42
+ "disambiguation": {
43
+ "status": "not_started",
44
+ "clarified": null,
45
+ "search_variations": [],
46
+ "user_question_asked": false,
47
+ "user_selected": null,
48
+ "phase_exit_confirmed": false,
49
+ "last_question_type": null,
50
+ "description": "Pre-research disambiguation to clarify ambiguous requests"
51
+ },
52
+ "scope": {
53
+ "status": "not_started",
54
+ "confirmed": false,
55
+ "user_question_asked": false,
56
+ "user_confirmed": false,
57
+ "phase_exit_confirmed": false,
58
+ "last_question_type": null,
59
+ "description": "Initial scope understanding and confirmation"
60
+ },
61
+ "research_initial": {
62
+ "status": "not_started",
63
+ "sources": [],
64
+ "summary_shown": false,
65
+ "user_question_asked": false,
66
+ "user_approved": false,
67
+ "phase_exit_confirmed": false,
68
+ "last_question_type": null,
69
+ "description": "Context7/WebSearch research for live documentation"
70
+ },
71
+ "interview": {
72
+ "status": "not_started",
73
+ "questions": [],
74
+ "user_question_count": 0,
75
+ "structured_question_count": 0,
76
+ "decisions": {},
77
+ "user_question_asked": false,
78
+ "user_completed": false,
79
+ "phase_exit_confirmed": false,
80
+ "last_question_type": null,
81
+ "description": "Structured interview about requirements (generated FROM research)"
82
+ },
83
+ "research_deep": {
84
+ "status": "not_started",
85
+ "sources": [],
86
+ "proposed_searches": [],
87
+ "approved_searches": [],
88
+ "executed_searches": [],
89
+ "skipped_searches": [],
90
+ "proposals_shown": false,
91
+ "user_question_asked": false,
92
+ "user_approved": false,
93
+ "phase_exit_confirmed": false,
94
+ "last_question_type": null,
95
+ "description": "Deep dive based on interview answers (adaptive, not shotgun)"
96
+ },
97
+ "schema_creation": {
98
+ "status": "not_started",
99
+ "schema_file": null,
100
+ "fields_count": 0,
101
+ "schema_shown": false,
102
+ "user_question_asked": false,
103
+ "user_confirmed": false,
104
+ "phase_exit_confirmed": false,
105
+ "last_question_type": null,
106
+ "description": "Zod schema creation from research"
107
+ },
108
+ "environment_check": {
109
+ "status": "not_started",
110
+ "keys_required": [],
111
+ "keys_found": [],
112
+ "keys_missing": [],
113
+ "env_shown": false,
114
+ "user_question_asked": false,
115
+ "user_ready": false,
116
+ "phase_exit_confirmed": false,
117
+ "last_question_type": null,
118
+ "description": "API key and environment verification"
119
+ },
120
+ "tdd_red": {
121
+ "status": "not_started",
122
+ "test_file": null,
123
+ "test_count": 0,
124
+ "test_scenarios": [],
125
+ "matrix_shown": false,
126
+ "user_question_asked": false,
127
+ "user_approved": false,
128
+ "phase_exit_confirmed": false,
129
+ "last_question_type": null,
130
+ "description": "Write failing tests first"
131
+ },
132
+ "tdd_green": {
133
+ "status": "not_started",
134
+ "implementation_file": null,
135
+ "all_tests_passing": false,
136
+ "phase_exit_confirmed": false,
137
+ "last_question_type": null,
138
+ "description": "Minimal implementation to pass tests"
139
+ },
140
+ "verify": {
141
+ "status": "not_started",
142
+ "gaps_found": 0,
143
+ "gaps_fixed": 0,
144
+ "gaps_skipped": 0,
145
+ "intentional_omissions": [],
146
+ "re_research_done": false,
147
+ "gap_analysis_shown": false,
148
+ "user_question_asked": false,
149
+ "user_decided": false,
150
+ "user_decision": null,
151
+ "phase_exit_confirmed": false,
152
+ "last_question_type": null,
153
+ "description": "Re-research after Green to verify implementation matches docs"
154
+ },
155
+ "tdd_refactor": {
156
+ "status": "not_started",
157
+ "phase_exit_confirmed": false,
158
+ "last_question_type": null,
159
+ "description": "Code cleanup while keeping tests green"
160
+ },
161
+ "documentation": {
162
+ "status": "not_started",
163
+ "files_updated": [],
164
+ "manifest_updated": false,
165
+ "openapi_updated": false,
166
+ "research_cached": false,
167
+ "checklist_shown": false,
168
+ "user_question_asked": false,
169
+ "user_confirmed": false,
170
+ "phase_exit_confirmed": false,
171
+ "last_question_type": null,
172
+ "description": "Update manifests, OpenAPI, cache research"
173
+ },
174
+ "completion": {
175
+ "status": "not_started",
176
+ "all_tests_passing": false,
177
+ "coverage_100_percent": false,
178
+ "typescript_compiles": false,
179
+ "docs_updated": false,
180
+ "commit_ready": false,
181
+ "files_created": [],
182
+ "files_modified": [],
183
+ "phase_exit_confirmed": false,
184
+ "last_question_type": null,
185
+ "description": "Final verification - all tests pass, docs complete, ready for commit"
186
+ }
187
+ },
188
+ "verification": {
189
+ "all_sources_fetched": false,
190
+ "schema_matches_docs": false,
191
+ "tests_cover_params": false,
192
+ "all_tests_passing": false,
193
+ "coverage_percent": null,
194
+ "post_green_verification": false
195
+ }
196
+ }
179
197
  }
@@ -0,0 +1,153 @@
1
+ 'use client';
2
+
3
+ interface RegistryAPI {
4
+ name: string;
5
+ description?: string;
6
+ route: string;
7
+ schemas?: string;
8
+ tests?: string;
9
+ methods?: string[];
10
+ created_at?: string;
11
+ status?: string;
12
+ combines?: string[];
13
+ flow_type?: string;
14
+ }
15
+
16
+ interface APICardProps {
17
+ id: string;
18
+ type: 'api' | 'combined';
19
+ data: RegistryAPI;
20
+ onClick: () => void;
21
+ }
22
+
23
+ /**
24
+ * API Card Component
25
+ *
26
+ * Displays a preview card for an API in the showcase grid.
27
+ * Hustle Together branding with boxy 90s style.
28
+ * Hover: Solid red shadow (4px 4px 0 #BA0C2F), no border change.
29
+ *
30
+ * Created with Hustle API Dev Tools (v3.9.2)
31
+ */
32
+ export function APICard({ id, type, data, onClick }: APICardProps) {
33
+ // Method badge colors
34
+ const methodColors: Record<string, string> = {
35
+ GET: 'border-green-600 bg-green-50 text-green-700 dark:bg-green-900/30 dark:text-green-400',
36
+ POST: 'border-blue-600 bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400',
37
+ PUT: 'border-yellow-600 bg-yellow-50 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400',
38
+ PATCH: 'border-orange-600 bg-orange-50 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400',
39
+ DELETE: 'border-red-600 bg-red-50 text-red-700 dark:bg-red-900/30 dark:text-red-400',
40
+ };
41
+
42
+ // Status colors
43
+ const statusColors: Record<string, string> = {
44
+ complete: 'bg-green-500',
45
+ 'in-progress': 'bg-yellow-500',
46
+ error: 'bg-red-500',
47
+ };
48
+
49
+ const methods = data.methods || ['POST'];
50
+ const status = data.status || 'complete';
51
+
52
+ return (
53
+ <button
54
+ onClick={onClick}
55
+ className="group relative flex flex-col overflow-hidden border-2 border-black bg-white text-left transition-all hover:shadow-[4px_4px_0_#BA0C2F] focus:outline-none focus:ring-2 focus:ring-[#BA0C2F] focus:ring-offset-2 dark:border-gray-700 dark:bg-gray-900"
56
+ >
57
+ {/* Header */}
58
+ <div className="flex items-start justify-between border-b-2 border-black p-4 dark:border-gray-700">
59
+ <div className="flex-1">
60
+ {/* Type Badge */}
61
+ <div className="mb-2 flex items-center gap-2">
62
+ {type === 'combined' ? (
63
+ <span className="border border-purple-600 bg-purple-50 px-2 py-0.5 text-xs font-bold uppercase tracking-wide text-purple-700 dark:bg-purple-900/30 dark:text-purple-400">
64
+ Combined API
65
+ </span>
66
+ ) : (
67
+ <span className="border border-black bg-gray-100 px-2 py-0.5 text-xs font-bold uppercase tracking-wide text-black dark:border-gray-600 dark:bg-gray-800 dark:text-white">
68
+ API Endpoint
69
+ </span>
70
+ )}
71
+ {/* Status Dot */}
72
+ <span
73
+ className={`h-2.5 w-2.5 rounded-full ${statusColors[status] || 'bg-gray-400'}`}
74
+ title={status}
75
+ />
76
+ </div>
77
+
78
+ {/* Name */}
79
+ <h3 className="font-bold text-black group-hover:text-[#BA0C2F] dark:text-white">
80
+ {data.name || id}
81
+ </h3>
82
+ </div>
83
+
84
+ {/* Arrow Icon */}
85
+ <svg
86
+ xmlns="http://www.w3.org/2000/svg"
87
+ width="20"
88
+ height="20"
89
+ viewBox="0 0 24 24"
90
+ fill="none"
91
+ stroke="currentColor"
92
+ strokeWidth="2.5"
93
+ strokeLinecap="round"
94
+ strokeLinejoin="round"
95
+ className="text-gray-400 transition-all group-hover:translate-x-1 group-hover:text-[#BA0C2F]"
96
+ >
97
+ <path d="M5 12h14" />
98
+ <path d="m12 5 7 7-7 7" />
99
+ </svg>
100
+ </div>
101
+
102
+ {/* Body */}
103
+ <div className="flex flex-1 flex-col p-4">
104
+ {/* Description */}
105
+ <p className="mb-3 line-clamp-2 text-sm text-gray-600 dark:text-gray-400">
106
+ {data.description || `API endpoint for ${id}`}
107
+ </p>
108
+
109
+ {/* Route */}
110
+ <div className="mb-3 border border-gray-300 bg-gray-50 px-2 py-1 dark:border-gray-600 dark:bg-gray-800">
111
+ <code className="font-mono text-xs text-gray-700 dark:text-gray-300">
112
+ /api/v2/{id}
113
+ </code>
114
+ </div>
115
+
116
+ {/* Methods */}
117
+ <div className="mt-auto flex flex-wrap gap-1">
118
+ {methods.map((method) => (
119
+ <span
120
+ key={method}
121
+ className={`border px-2 py-0.5 font-mono text-xs font-bold ${
122
+ methodColors[method] || 'border-gray-400 bg-gray-100 text-gray-700'
123
+ }`}
124
+ >
125
+ {method}
126
+ </span>
127
+ ))}
128
+ </div>
129
+
130
+ {/* Combined Info */}
131
+ {type === 'combined' && data.combines && (
132
+ <div className="mt-3 border-t border-gray-200 pt-3 dark:border-gray-700">
133
+ <p className="text-xs text-gray-500 dark:text-gray-400">
134
+ <span className="font-semibold">Combines:</span> {data.combines.join(', ')}
135
+ </p>
136
+ {data.flow_type && (
137
+ <p className="text-xs text-gray-500 dark:text-gray-400">
138
+ <span className="font-semibold">Flow:</span> {data.flow_type}
139
+ </p>
140
+ )}
141
+ </div>
142
+ )}
143
+ </div>
144
+
145
+ {/* Footer */}
146
+ <div className="border-t border-gray-200 bg-gray-50 px-4 py-2 dark:border-gray-700 dark:bg-gray-800">
147
+ <p className="text-xs text-gray-500 dark:text-gray-400">
148
+ {data.created_at ? `Created ${data.created_at}` : 'Click to test'}
149
+ </p>
150
+ </div>
151
+ </button>
152
+ );
153
+ }