@hustle-together/api-dev-tools 3.12.3 → 4.5.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 (159) hide show
  1. package/.claude/adr-requests/.gitkeep +10 -0
  2. package/.claude/agents/adr-researcher.md +109 -0
  3. package/.claude/agents/visual-analyzer.md +183 -0
  4. package/.claude/api-dev-state.json +7 -463
  5. package/.claude/documentation-audit.json +114 -0
  6. package/.claude/registry.json +289 -0
  7. package/.claude/settings.json +45 -1
  8. package/.claude/workflow-logs/None.json +49 -0
  9. package/.claude/workflow-logs/session-20251230-143727.json +106 -0
  10. package/.skills/adr-deep-research/SKILL.md +351 -0
  11. package/.skills/api-create/SKILL.md +116 -17
  12. package/.skills/api-research/SKILL.md +130 -0
  13. package/.skills/docs-sync/SKILL.md +260 -0
  14. package/.skills/docs-update/SKILL.md +205 -0
  15. package/.skills/hustle-brand/SKILL.md +368 -0
  16. package/.skills/hustle-build/SKILL.md +786 -0
  17. package/.skills/hustle-build-review/SKILL.md +518 -0
  18. package/.skills/parallel-spawn/SKILL.md +212 -0
  19. package/.skills/ralph-continue/SKILL.md +151 -0
  20. package/.skills/ralph-loop/SKILL.md +341 -0
  21. package/.skills/ralph-status/SKILL.md +87 -0
  22. package/.skills/refactor/SKILL.md +59 -0
  23. package/.skills/shadcn/SKILL.md +522 -0
  24. package/.skills/test-all/SKILL.md +210 -0
  25. package/.skills/test-builds/SKILL.md +208 -0
  26. package/.skills/test-debug/SKILL.md +212 -0
  27. package/.skills/test-e2e/SKILL.md +168 -0
  28. package/.skills/test-review/SKILL.md +707 -0
  29. package/.skills/test-unit/SKILL.md +143 -0
  30. package/.skills/test-visual/SKILL.md +301 -0
  31. package/.skills/token-report/SKILL.md +132 -0
  32. package/CHANGELOG.md +575 -0
  33. package/README.md +426 -56
  34. package/bin/cli.js +1538 -88
  35. package/commands/hustle-api-create.md +22 -0
  36. package/commands/hustle-build.md +259 -0
  37. package/commands/hustle-combine.md +81 -2
  38. package/commands/hustle-ui-create-page.md +84 -2
  39. package/commands/hustle-ui-create.md +82 -2
  40. package/hooks/__pycache__/api-workflow-check.cpython-314.pyc +0 -0
  41. package/hooks/__pycache__/auto-answer.cpython-314.pyc +0 -0
  42. package/hooks/__pycache__/cache-research.cpython-314.pyc +0 -0
  43. package/hooks/__pycache__/check-api-routes.cpython-314.pyc +0 -0
  44. package/hooks/__pycache__/check-playwright-setup.cpython-314.pyc +0 -0
  45. package/hooks/__pycache__/check-storybook-setup.cpython-314.pyc +0 -0
  46. package/hooks/__pycache__/check-update.cpython-314.pyc +0 -0
  47. package/hooks/__pycache__/completion-promise-detector.cpython-314.pyc +0 -0
  48. package/hooks/__pycache__/context-capacity-warning.cpython-314.pyc +0 -0
  49. package/hooks/__pycache__/detect-interruption.cpython-314.pyc +0 -0
  50. package/hooks/__pycache__/docs-update-check.cpython-314.pyc +0 -0
  51. package/hooks/__pycache__/enforce-a11y-audit.cpython-314.pyc +0 -0
  52. package/hooks/__pycache__/enforce-brand-guide.cpython-314.pyc +0 -0
  53. package/hooks/__pycache__/enforce-component-type-confirm.cpython-314.pyc +0 -0
  54. package/hooks/__pycache__/enforce-deep-research.cpython-314.pyc +0 -0
  55. package/hooks/__pycache__/enforce-disambiguation.cpython-314.pyc +0 -0
  56. package/hooks/__pycache__/enforce-documentation.cpython-314.pyc +0 -0
  57. package/hooks/__pycache__/enforce-dry-run.cpython-314.pyc +0 -0
  58. package/hooks/__pycache__/enforce-environment.cpython-314.pyc +0 -0
  59. package/hooks/__pycache__/enforce-external-research.cpython-314.pyc +0 -0
  60. package/hooks/__pycache__/enforce-freshness.cpython-314.pyc +0 -0
  61. package/hooks/__pycache__/enforce-interview.cpython-314.pyc +0 -0
  62. package/hooks/__pycache__/enforce-page-components.cpython-314.pyc +0 -0
  63. package/hooks/__pycache__/enforce-page-data-schema.cpython-314.pyc +0 -0
  64. package/hooks/__pycache__/enforce-questions-sourced.cpython-314.pyc +0 -0
  65. package/hooks/__pycache__/enforce-refactor.cpython-314.pyc +0 -0
  66. package/hooks/__pycache__/enforce-research.cpython-314.pyc +0 -0
  67. package/hooks/__pycache__/enforce-schema-from-interview.cpython-314.pyc +0 -0
  68. package/hooks/__pycache__/enforce-schema.cpython-314.pyc +0 -0
  69. package/hooks/__pycache__/enforce-scope.cpython-314.pyc +0 -0
  70. package/hooks/__pycache__/enforce-tdd-red.cpython-314.pyc +0 -0
  71. package/hooks/__pycache__/enforce-ui-disambiguation.cpython-314.pyc +0 -0
  72. package/hooks/__pycache__/enforce-ui-interview.cpython-314.pyc +0 -0
  73. package/hooks/__pycache__/enforce-verify.cpython-314.pyc +0 -0
  74. package/hooks/__pycache__/generate-adr-options.cpython-314.pyc +0 -0
  75. package/hooks/__pycache__/generate-manifest-entry.cpython-314.pyc +0 -0
  76. package/hooks/__pycache__/hook_utils.cpython-314.pyc +0 -0
  77. package/hooks/__pycache__/notify-input-needed.cpython-314.pyc +0 -0
  78. package/hooks/__pycache__/notify-phase-complete.cpython-314.pyc +0 -0
  79. package/hooks/__pycache__/ntfy-on-question.cpython-314.pyc +0 -0
  80. package/hooks/__pycache__/orchestrator-completion.cpython-314.pyc +0 -0
  81. package/hooks/__pycache__/orchestrator-handoff.cpython-314.pyc +0 -0
  82. package/hooks/__pycache__/orchestrator-session-startup.cpython-314.pyc +0 -0
  83. package/hooks/__pycache__/parallel-orchestrator.cpython-314.pyc +0 -0
  84. package/hooks/__pycache__/periodic-reground.cpython-314.pyc +0 -0
  85. package/hooks/__pycache__/project-document-prompt.cpython-314.pyc +0 -0
  86. package/hooks/__pycache__/remote-question-proxy.cpython-314.pyc +0 -0
  87. package/hooks/__pycache__/remote-question-server.cpython-314.pyc +0 -0
  88. package/hooks/__pycache__/run-code-review.cpython-314.pyc +0 -0
  89. package/hooks/__pycache__/run-visual-qa.cpython-314.pyc +0 -0
  90. package/hooks/__pycache__/session-logger.cpython-314.pyc +0 -0
  91. package/hooks/__pycache__/session-startup.cpython-314.pyc +0 -0
  92. package/hooks/__pycache__/track-scope-coverage.cpython-314.pyc +0 -0
  93. package/hooks/__pycache__/track-token-usage.cpython-314.pyc +0 -0
  94. package/hooks/__pycache__/track-tool-use.cpython-314.pyc +0 -0
  95. package/hooks/__pycache__/update-adr-decision.cpython-314.pyc +0 -0
  96. package/hooks/__pycache__/update-api-showcase.cpython-314.pyc +0 -0
  97. package/hooks/__pycache__/update-registry.cpython-314.pyc +0 -0
  98. package/hooks/__pycache__/update-ui-showcase.cpython-314.pyc +0 -0
  99. package/hooks/__pycache__/verify-after-green.cpython-314.pyc +0 -0
  100. package/hooks/__pycache__/verify-implementation.cpython-314.pyc +0 -0
  101. package/hooks/api-workflow-check.py +34 -0
  102. package/hooks/auto-answer.py +305 -0
  103. package/hooks/check-update.py +132 -0
  104. package/hooks/completion-promise-detector.py +293 -0
  105. package/hooks/context-capacity-warning.py +171 -0
  106. package/hooks/docs-update-check.py +120 -0
  107. package/hooks/enforce-dry-run.py +134 -0
  108. package/hooks/enforce-external-research.py +25 -0
  109. package/hooks/enforce-interview.py +20 -0
  110. package/hooks/generate-adr-options.py +282 -0
  111. package/hooks/hook_utils.py +609 -0
  112. package/hooks/lib/__pycache__/__init__.cpython-314.pyc +0 -0
  113. package/hooks/lib/__pycache__/greptile.cpython-314.pyc +0 -0
  114. package/hooks/lib/__pycache__/ntfy.cpython-314.pyc +0 -0
  115. package/hooks/ntfy-on-question.py +240 -0
  116. package/hooks/orchestrator-completion.py +313 -0
  117. package/hooks/orchestrator-handoff.py +267 -0
  118. package/hooks/orchestrator-session-startup.py +146 -0
  119. package/hooks/parallel-orchestrator.py +451 -0
  120. package/hooks/periodic-reground.py +270 -67
  121. package/hooks/project-document-prompt.py +302 -0
  122. package/hooks/remote-question-proxy.py +284 -0
  123. package/hooks/remote-question-server.py +1224 -0
  124. package/hooks/run-code-review.py +176 -29
  125. package/hooks/run-visual-qa.py +338 -0
  126. package/hooks/session-logger.py +27 -1
  127. package/hooks/session-startup.py +113 -0
  128. package/hooks/update-adr-decision.py +236 -0
  129. package/hooks/update-api-showcase.py +13 -1
  130. package/hooks/update-testing-checklist.py +195 -0
  131. package/hooks/update-ui-showcase.py +13 -1
  132. package/package.json +7 -3
  133. package/scripts/extract-schema-docs.cjs +322 -0
  134. package/templates/.skills/hustle-interview/SKILL.md +174 -0
  135. package/templates/CLAUDE-SECTION.md +89 -64
  136. package/templates/adr-viewer/_components/ADRViewer.tsx +326 -0
  137. package/templates/api-dev-state.json +33 -1
  138. package/templates/api-showcase/_components/APIModal.tsx +100 -8
  139. package/templates/api-showcase/_components/APIShowcase.tsx +36 -4
  140. package/templates/api-showcase/_components/APITester.tsx +367 -58
  141. package/templates/brand-page/page.tsx +645 -0
  142. package/templates/component/Component.visual.spec.ts +30 -24
  143. package/templates/docs/page.tsx +230 -0
  144. package/templates/eslint-plugin-zod-schema/index.js +446 -0
  145. package/templates/eslint-plugin-zod-schema/package.json +26 -0
  146. package/templates/github-workflows/security.yml +274 -0
  147. package/templates/hustle-build-defaults.json +136 -0
  148. package/templates/hustle-dev-dashboard/page.tsx +365 -0
  149. package/templates/page/page.e2e.test.ts +30 -26
  150. package/templates/performance-budgets.json +63 -5
  151. package/templates/playwright-report/page.tsx +258 -0
  152. package/templates/registry.json +279 -3
  153. package/templates/review-dashboard/page.tsx +510 -0
  154. package/templates/settings.json +155 -7
  155. package/templates/test-results/page.tsx +237 -0
  156. package/templates/typedoc.json +19 -0
  157. package/templates/ui-showcase/_components/UIShowcase.tsx +48 -1
  158. package/templates/ui-showcase/_components/VisualTestingDashboard.tsx +579 -0
  159. package/templates/ui-showcase/page.tsx +1 -1
@@ -3,10 +3,29 @@
3
3
  import { useEffect, useCallback, useState } from "react";
4
4
  import { APITester } from "./APITester";
5
5
 
6
+ interface EndpointParam {
7
+ name: string;
8
+ type: string;
9
+ description?: string;
10
+ required?: boolean;
11
+ default?: string | number | boolean;
12
+ enum?: string[];
13
+ example?: string;
14
+ min?: number;
15
+ max?: number;
16
+ }
17
+
18
+ interface EndpointExample {
19
+ description: string;
20
+ query: string;
21
+ curl: string;
22
+ }
23
+
6
24
  interface RegistryAPI {
7
25
  name: string;
8
26
  description?: string;
9
27
  route: string;
28
+ routeFile?: string;
10
29
  schemas?: string;
11
30
  tests?: string;
12
31
  methods?: string[];
@@ -17,8 +36,11 @@ interface RegistryAPI {
17
36
  endpoints?: Record<
18
37
  string,
19
38
  {
20
- methods: string[];
39
+ methods?: string[];
40
+ method?: string;
21
41
  description?: string;
42
+ params?: EndpointParam[];
43
+ examples?: Record<string, EndpointExample>;
22
44
  }
23
45
  >;
24
46
  }
@@ -41,13 +63,15 @@ interface APIModalProps {
41
63
  * - Request/response display
42
64
  * - Curl example generation
43
65
  *
44
- * Created with Hustle API Dev Tools (v3.9.2)
66
+ * Created with Hustle API Dev Tools (v3.12.10)
45
67
  */
46
68
  export function APIModal({ id, type, data, onClose }: APIModalProps) {
47
69
  const [activeTab, setActiveTab] = useState<"try-it" | "docs" | "curl">(
48
70
  "try-it",
49
71
  );
50
72
  const [selectedEndpoint, setSelectedEndpoint] = useState<string | null>(null);
73
+ const [submitRequest, setSubmitRequest] = useState<(() => Promise<void>) | null>(null);
74
+ const [isLoading, setIsLoading] = useState(false);
51
75
 
52
76
  // Close on Escape key
53
77
  const handleKeyDown = useCallback(
@@ -86,14 +110,26 @@ export function APIModal({ id, type, data, onClose }: APIModalProps) {
86
110
  const currentEndpoint = selectedEndpoint
87
111
  ? endpoints[selectedEndpoint]
88
112
  : endpoints[endpointKeys[0]];
89
- const methods = currentEndpoint?.methods || data.methods || ["POST"];
113
+ // Handle both methods array and single method string
114
+ const methods = currentEndpoint?.methods ||
115
+ (currentEndpoint?.method ? [currentEndpoint.method] : null) ||
116
+ data.methods ||
117
+ ["POST"];
90
118
  const baseUrl =
91
119
  typeof window !== "undefined"
92
120
  ? window.location.origin
93
121
  : "http://localhost:3000";
94
122
 
95
- // Build endpoint path
123
+ // Build endpoint path - always use base path for action-based APIs
124
+ // Actions are passed as query parameters, not sub-paths
96
125
  const getEndpointPath = () => {
126
+ // Check if this API uses action-based routing (has params with action)
127
+ const hasActionParam = currentEndpoint?.params?.some(p => p.name === "action");
128
+ if (hasActionParam) {
129
+ // Action-based APIs use query params, not path segments
130
+ return `/api/v2/${id}`;
131
+ }
132
+ // For true sub-endpoint APIs, include the path
97
133
  if (selectedEndpoint && selectedEndpoint !== "default") {
98
134
  return `/api/v2/${id}/${selectedEndpoint}`;
99
135
  }
@@ -102,10 +138,26 @@ export function APIModal({ id, type, data, onClose }: APIModalProps) {
102
138
 
103
139
  const endpoint = getEndpointPath();
104
140
 
105
- // Generate curl example
141
+ // Generate curl example with proper query params
106
142
  const generateCurl = (method: string) => {
143
+ // Build example query string from params
144
+ const params = currentEndpoint?.params || [];
145
+ const queryParts: string[] = [];
146
+
147
+ for (const param of params) {
148
+ if (param.name === "action" && selectedEndpoint) {
149
+ queryParts.push(`action=${selectedEndpoint}`);
150
+ } else if (param.required && param.example) {
151
+ queryParts.push(`${param.name}=${encodeURIComponent(param.example)}`);
152
+ } else if (param.example) {
153
+ queryParts.push(`${param.name}=${encodeURIComponent(param.example)}`);
154
+ }
155
+ }
156
+
157
+ const queryString = queryParts.length > 0 ? `?${queryParts.join("&")}` : "";
158
+
107
159
  if (method === "GET") {
108
- return `curl -X GET "${baseUrl}${endpoint}"`;
160
+ return `curl -X GET "${baseUrl}${endpoint}${queryString}"`;
109
161
  }
110
162
  return `curl -X ${method} "${baseUrl}${endpoint}" \\
111
163
  -H "Content-Type: application/json" \\
@@ -129,7 +181,7 @@ export function APIModal({ id, type, data, onClose }: APIModalProps) {
129
181
  />
130
182
 
131
183
  {/* Modal Content */}
132
- <div className="relative z-10 flex max-h-[90vh] w-full max-w-5xl flex-col overflow-hidden border-2 border-black bg-white shadow-xl dark:border-gray-600 dark:bg-gray-900">
184
+ <div className="relative z-10 flex max-h-[90vh] w-full max-w-7xl flex-col overflow-hidden border-2 border-black bg-white shadow-xl dark:border-gray-600 dark:bg-gray-900">
133
185
  {/* Header */}
134
186
  <header className="flex items-center justify-between border-b-2 border-black px-6 py-4 dark:border-gray-600">
135
187
  <div className="flex items-center gap-4">
@@ -271,6 +323,11 @@ export function APIModal({ id, type, data, onClose }: APIModalProps) {
271
323
  methods={methods}
272
324
  selectedEndpoint={selectedEndpoint}
273
325
  schemaPath={data.schemas}
326
+ endpointParams={data.endpoints?.[selectedEndpoint || "default"]?.params || data.endpoints?.[Object.keys(data.endpoints || {})[0]]?.params}
327
+ apiRoute={data.routeFile || data.route}
328
+ examples={data.endpoints?.[selectedEndpoint || "default"]?.examples || data.endpoints?.[Object.keys(data.endpoints || {})[0]]?.examples}
329
+ onSubmitRef={(fn) => setSubmitRequest(() => fn)}
330
+ onLoadingChange={setIsLoading}
274
331
  />
275
332
  )}
276
333
 
@@ -408,10 +465,45 @@ export function APIModal({ id, type, data, onClose }: APIModalProps) {
408
465
  );
409
466
  }
410
467
  }}
411
- className="border-2 border-black bg-[#BA0C2F] px-3 py-1.5 text-sm font-medium text-white hover:bg-[#8a0923]"
468
+ className="border-2 border-black px-3 py-1.5 text-sm font-medium hover:bg-gray-100 dark:border-gray-600 dark:hover:bg-gray-800"
412
469
  >
413
470
  Copy Schema Import
414
471
  </button>
472
+ {activeTab === "try-it" && submitRequest && (
473
+ <button
474
+ onClick={() => submitRequest()}
475
+ disabled={isLoading}
476
+ className="border-2 border-black bg-[#BA0C2F] px-4 py-1.5 text-sm font-bold text-white transition-colors hover:bg-[#8a0923] disabled:opacity-50"
477
+ >
478
+ {isLoading ? (
479
+ <span className="flex items-center gap-2">
480
+ <svg
481
+ className="h-4 w-4 animate-spin"
482
+ xmlns="http://www.w3.org/2000/svg"
483
+ fill="none"
484
+ viewBox="0 0 24 24"
485
+ >
486
+ <circle
487
+ className="opacity-25"
488
+ cx="12"
489
+ cy="12"
490
+ r="10"
491
+ stroke="currentColor"
492
+ strokeWidth="4"
493
+ />
494
+ <path
495
+ className="opacity-75"
496
+ fill="currentColor"
497
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
498
+ />
499
+ </svg>
500
+ Sending...
501
+ </span>
502
+ ) : (
503
+ "Send Request"
504
+ )}
505
+ </button>
506
+ )}
415
507
  </div>
416
508
  </div>
417
509
  </footer>
@@ -4,6 +4,33 @@ import { useState, useMemo } from "react";
4
4
  import { APICard } from "./APICard";
5
5
  import { APIModal } from "./APIModal";
6
6
 
7
+ // Import registry - this will be updated by the CLI when APIs are created
8
+ import registryData from "@/../.claude/registry.json";
9
+
10
+ /**
11
+ * Parameter documentation from registry.json
12
+ */
13
+ interface EndpointParam {
14
+ name: string;
15
+ type: string;
16
+ description?: string;
17
+ required?: boolean;
18
+ default?: string | number | boolean;
19
+ enum?: string[];
20
+ example?: string;
21
+ min?: number;
22
+ max?: number;
23
+ }
24
+
25
+ /**
26
+ * Example request from registry.json
27
+ */
28
+ interface EndpointExample {
29
+ description: string;
30
+ query: string;
31
+ curl: string;
32
+ }
33
+
7
34
  /**
8
35
  * Registry structure from .claude/registry.json
9
36
  */
@@ -11,16 +38,21 @@ interface RegistryAPI {
11
38
  name: string;
12
39
  description?: string;
13
40
  route: string;
41
+ routeFile?: string;
14
42
  schemas?: string;
15
43
  tests?: string;
16
44
  methods?: string[];
17
45
  created_at?: string;
18
46
  status?: string;
47
+ actions?: string[];
19
48
  endpoints?: Record<
20
49
  string,
21
50
  {
22
- methods: string[];
51
+ methods?: string[];
52
+ method?: string;
23
53
  description?: string;
54
+ params?: EndpointParam[];
55
+ examples?: Record<string, EndpointExample>;
24
56
  }
25
57
  >;
26
58
  }
@@ -46,7 +78,7 @@ interface APIShowcaseProps {
46
78
  *
47
79
  * Data source: .claude/registry.json (apis + combined sections)
48
80
  *
49
- * Created with Hustle API Dev Tools (v3.9.2)
81
+ * Created with Hustle API Dev Tools (v3.12.10)
50
82
  */
51
83
  export function APIShowcase({ registry: propRegistry }: APIShowcaseProps) {
52
84
  const [selectedAPI, setSelectedAPI] = useState<{
@@ -57,8 +89,8 @@ export function APIShowcase({ registry: propRegistry }: APIShowcaseProps) {
57
89
  const [filter, setFilter] = useState<"all" | "api" | "combined">("all");
58
90
  const [search, setSearch] = useState("");
59
91
 
60
- // Use prop registry or default empty structure
61
- const registry: Registry = propRegistry || {
92
+ // Use prop registry, imported registry, or default empty structure
93
+ const registry: Registry = propRegistry || registryData || {
62
94
  version: "1.0.0",
63
95
  apis: {},
64
96
  combined: {},