@hustle-together/api-dev-tools 3.6.5 → 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.
- package/README.md +5307 -258
- package/bin/cli.js +348 -20
- package/commands/README.md +459 -71
- package/commands/hustle-api-continue.md +158 -0
- package/commands/{api-create.md → hustle-api-create.md} +22 -2
- package/commands/{api-env.md → hustle-api-env.md} +4 -4
- package/commands/{api-interview.md → hustle-api-interview.md} +1 -1
- package/commands/{api-research.md → hustle-api-research.md} +3 -3
- package/commands/hustle-api-sessions.md +149 -0
- package/commands/{api-status.md → hustle-api-status.md} +16 -16
- package/commands/{api-verify.md → hustle-api-verify.md} +2 -2
- package/commands/hustle-combine.md +763 -0
- package/commands/hustle-ui-create.md +825 -0
- package/hooks/api-workflow-check.py +385 -19
- package/hooks/cache-research.py +337 -0
- package/hooks/check-playwright-setup.py +103 -0
- package/hooks/check-storybook-setup.py +81 -0
- package/hooks/detect-interruption.py +165 -0
- package/hooks/enforce-brand-guide.py +131 -0
- package/hooks/enforce-documentation.py +60 -8
- package/hooks/enforce-freshness.py +184 -0
- package/hooks/enforce-questions-sourced.py +146 -0
- package/hooks/enforce-schema-from-interview.py +248 -0
- package/hooks/enforce-ui-disambiguation.py +108 -0
- package/hooks/enforce-ui-interview.py +130 -0
- package/hooks/generate-manifest-entry.py +981 -0
- package/hooks/session-logger.py +297 -0
- package/hooks/session-startup.py +65 -10
- package/hooks/track-scope-coverage.py +220 -0
- package/hooks/track-tool-use.py +81 -1
- package/hooks/update-api-showcase.py +149 -0
- package/hooks/update-registry.py +352 -0
- package/hooks/update-ui-showcase.py +148 -0
- package/package.json +8 -2
- package/templates/BRAND_GUIDE.md +299 -0
- package/templates/CLAUDE-SECTION.md +56 -24
- package/templates/SPEC.json +640 -0
- package/templates/api-dev-state.json +179 -161
- package/templates/api-showcase/APICard.tsx +153 -0
- package/templates/api-showcase/APIModal.tsx +375 -0
- package/templates/api-showcase/APIShowcase.tsx +231 -0
- package/templates/api-showcase/APITester.tsx +522 -0
- package/templates/api-showcase/page.tsx +41 -0
- package/templates/component/Component.stories.tsx +172 -0
- package/templates/component/Component.test.tsx +237 -0
- package/templates/component/Component.tsx +86 -0
- package/templates/component/Component.types.ts +55 -0
- package/templates/component/index.ts +15 -0
- package/templates/dev-tools/_components/DevToolsLanding.tsx +320 -0
- package/templates/dev-tools/page.tsx +10 -0
- package/templates/page/page.e2e.test.ts +218 -0
- package/templates/page/page.tsx +42 -0
- package/templates/performance-budgets.json +58 -0
- package/templates/registry.json +13 -0
- package/templates/settings.json +74 -0
- package/templates/shared/HeroHeader.tsx +261 -0
- package/templates/shared/index.ts +1 -0
- package/templates/ui-showcase/PreviewCard.tsx +315 -0
- package/templates/ui-showcase/PreviewModal.tsx +676 -0
- package/templates/ui-showcase/UIShowcase.tsx +262 -0
- package/templates/ui-showcase/page.tsx +26 -0
|
@@ -0,0 +1,763 @@
|
|
|
1
|
+
# Hustle Combine - API and UI Orchestration Workflow v3.8.0
|
|
2
|
+
|
|
3
|
+
**Usage:** `/hustle-combine [api|ui]`
|
|
4
|
+
|
|
5
|
+
**Purpose:** Combines existing APIs or UI elements from the registry into new orchestration endpoints or composed components.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
This command reads from `.claude/registry.json` to present available elements for combination. It creates NEW orchestration layers using EXISTING, tested components.
|
|
10
|
+
|
|
11
|
+
**Key Principle:** We're not creating new APIs from scratch - we're combining existing, working APIs into orchestration endpoints.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## CRITICAL: MANDATORY USER INTERACTION
|
|
16
|
+
|
|
17
|
+
**YOU MUST USE THE `AskUserQuestion` TOOL AT EVERY CHECKPOINT.**
|
|
18
|
+
|
|
19
|
+
This workflow requires REAL user input at each phase. You are **FORBIDDEN** from:
|
|
20
|
+
- Self-answering questions
|
|
21
|
+
- Assuming user responses
|
|
22
|
+
- Proceeding without explicit user confirmation
|
|
23
|
+
- Making decisions on behalf of the user
|
|
24
|
+
|
|
25
|
+
### How to Ask Questions Correctly
|
|
26
|
+
|
|
27
|
+
At every prompt in this workflow, you MUST call the `AskUserQuestion` tool with this EXACT schema:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"questions": [
|
|
32
|
+
{
|
|
33
|
+
"question": "Your question here? (must end with ?)",
|
|
34
|
+
"header": "Phase",
|
|
35
|
+
"multiSelect": false,
|
|
36
|
+
"options": [
|
|
37
|
+
{"label": "Option A", "description": "What this option means"},
|
|
38
|
+
{"label": "Option B", "description": "What this option means"},
|
|
39
|
+
{"label": "Other", "description": "I'll type my own answer"}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**CRITICAL REQUIREMENTS:**
|
|
47
|
+
- `header`: Max 12 characters (e.g., "Mode", "Select", "Order")
|
|
48
|
+
- `options`: 2-4 options, each with `label` (1-5 words) and `description`
|
|
49
|
+
- `multiSelect`: Required boolean (true for checkboxes, false for radio)
|
|
50
|
+
- `question`: Must end with a question mark
|
|
51
|
+
|
|
52
|
+
**WAIT for the user's response before proceeding.** Do NOT continue until you receive the response.
|
|
53
|
+
|
|
54
|
+
### Phase Exit Confirmation
|
|
55
|
+
|
|
56
|
+
**Every phase requires an EXIT CONFIRMATION question** before proceeding to the next phase.
|
|
57
|
+
|
|
58
|
+
Example:
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"questions": [{
|
|
62
|
+
"question": "Phase complete. Ready to proceed to next phase?",
|
|
63
|
+
"header": "Proceed",
|
|
64
|
+
"multiSelect": false,
|
|
65
|
+
"options": [
|
|
66
|
+
{"label": "Yes, proceed", "description": "Move to next phase"},
|
|
67
|
+
{"label": "No, make changes", "description": "I need to modify something"}
|
|
68
|
+
]
|
|
69
|
+
}]
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Mode Selection
|
|
76
|
+
|
|
77
|
+
When running `/hustle-combine`, first determine the mode:
|
|
78
|
+
|
|
79
|
+
Use AskUserQuestion:
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"questions": [{
|
|
83
|
+
"question": "What would you like to combine?",
|
|
84
|
+
"header": "Mode",
|
|
85
|
+
"multiSelect": false,
|
|
86
|
+
"options": [
|
|
87
|
+
{"label": "APIs", "description": "Combine existing API endpoints into orchestration layer"},
|
|
88
|
+
{"label": "UI", "description": "Combine existing components/pages (coming soon)"}
|
|
89
|
+
]
|
|
90
|
+
}]
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Mode A: Combine APIs
|
|
97
|
+
|
|
98
|
+
### 13 Phases for API Combination
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
Phase 1: SELECTION - Present checkboxes from registry, user selects 2+ APIs
|
|
102
|
+
Phase 2: SCOPE - "What should this combined endpoint do?"
|
|
103
|
+
Phase 3: INITIAL RESEARCH - Orchestration patterns (lighter - APIs already researched)
|
|
104
|
+
Phase 4: INTERVIEW - Flow order, error handling, caching, naming
|
|
105
|
+
Phase 5: DEEP RESEARCH - Edge cases between APIs (optional/lighter)
|
|
106
|
+
Phase 6: COMBINED SCHEMA - Zod types composing existing schemas
|
|
107
|
+
Phase 7: ENVIRONMENT - Verify all required API keys exist
|
|
108
|
+
Phase 8: TDD RED - Integration tests for combined flow
|
|
109
|
+
Phase 9: TDD GREEN - Orchestration route implementation
|
|
110
|
+
Phase 10: VERIFY - Full flow works end-to-end
|
|
111
|
+
Phase 11: REFACTOR - Clean up, optimize
|
|
112
|
+
Phase 12: DOCUMENTATION - Update manifest, document combined endpoint
|
|
113
|
+
Phase 13: COMPLETE - Update registry with new combined API
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### Phase 1: SELECTION (Programmatic from Registry)
|
|
119
|
+
|
|
120
|
+
Read `.claude/registry.json` and present available APIs.
|
|
121
|
+
|
|
122
|
+
**IMPORTANT:** Options are dynamically generated from registry.json. Only show APIs with `status: "complete"`.
|
|
123
|
+
|
|
124
|
+
Use AskUserQuestion with multiSelect:
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"questions": [{
|
|
128
|
+
"question": "Select APIs to combine (choose 2 or more):",
|
|
129
|
+
"header": "Select",
|
|
130
|
+
"multiSelect": true,
|
|
131
|
+
"options": [
|
|
132
|
+
{"label": "[api-name]", "description": "[api-description from registry]"}
|
|
133
|
+
]
|
|
134
|
+
}]
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**After selection, store in state:**
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"workflow": "combine-api",
|
|
142
|
+
"combine_config": {
|
|
143
|
+
"mode": "api",
|
|
144
|
+
"source_elements": [
|
|
145
|
+
{ "type": "api", "name": "api1" },
|
|
146
|
+
{ "type": "api", "name": "api2" }
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Phase Exit:**
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"questions": [{
|
|
156
|
+
"question": "Selected [N] APIs. Ready to define the purpose?",
|
|
157
|
+
"header": "Proceed",
|
|
158
|
+
"multiSelect": false,
|
|
159
|
+
"options": [
|
|
160
|
+
{"label": "Yes, proceed", "description": "Move to Scope phase"},
|
|
161
|
+
{"label": "Change selection", "description": "I want to select different APIs"}
|
|
162
|
+
]
|
|
163
|
+
}]
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
### Phase 2: SCOPE
|
|
170
|
+
|
|
171
|
+
Ask what the combined endpoint should do:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"questions": [{
|
|
176
|
+
"question": "What should this combined endpoint do? Describe the purpose:",
|
|
177
|
+
"header": "Purpose",
|
|
178
|
+
"multiSelect": false,
|
|
179
|
+
"options": [
|
|
180
|
+
{"label": "Describe it", "description": "I'll type the purpose"}
|
|
181
|
+
]
|
|
182
|
+
}]
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Store the purpose in state for later use in schema and tests.
|
|
187
|
+
|
|
188
|
+
**Phase Exit:**
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"questions": [{
|
|
192
|
+
"question": "Purpose defined. Ready to research orchestration patterns?",
|
|
193
|
+
"header": "Proceed",
|
|
194
|
+
"multiSelect": false,
|
|
195
|
+
"options": [
|
|
196
|
+
{"label": "Yes, proceed", "description": "Move to Research phase"},
|
|
197
|
+
{"label": "Refine purpose", "description": "I want to clarify the purpose"}
|
|
198
|
+
]
|
|
199
|
+
}]
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
### Phase 3: INITIAL RESEARCH (Lighter)
|
|
206
|
+
|
|
207
|
+
Since APIs already exist, focus ONLY on orchestration patterns:
|
|
208
|
+
- Gateway aggregation patterns
|
|
209
|
+
- Error propagation between services
|
|
210
|
+
- Response composition strategies
|
|
211
|
+
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"questions": [{
|
|
215
|
+
"question": "Research focus: I'll look up orchestration patterns for combining [API1] + [API2]. Proceed?",
|
|
216
|
+
"header": "Research",
|
|
217
|
+
"multiSelect": false,
|
|
218
|
+
"options": [
|
|
219
|
+
{"label": "Yes, proceed", "description": "Research orchestration patterns"},
|
|
220
|
+
{"label": "Skip research", "description": "I know how I want to combine them"}
|
|
221
|
+
]
|
|
222
|
+
}]
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
If user chooses to research, use WebSearch and Context7 for:
|
|
227
|
+
- "API gateway aggregation patterns"
|
|
228
|
+
- "Service composition error handling"
|
|
229
|
+
- "Response aggregation TypeScript patterns"
|
|
230
|
+
|
|
231
|
+
**Phase Exit:**
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"questions": [{
|
|
235
|
+
"question": "Research complete. Ready for interview questions?",
|
|
236
|
+
"header": "Proceed",
|
|
237
|
+
"multiSelect": false,
|
|
238
|
+
"options": [
|
|
239
|
+
{"label": "Yes, interview", "description": "Move to Interview phase"},
|
|
240
|
+
{"label": "More research", "description": "I need to research [topic]"}
|
|
241
|
+
]
|
|
242
|
+
}]
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
### Phase 4: INTERVIEW
|
|
249
|
+
|
|
250
|
+
Key questions for API combination (ask one at a time):
|
|
251
|
+
|
|
252
|
+
**Q1: Endpoint Name**
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"questions": [{
|
|
256
|
+
"question": "What should the combined endpoint be called?",
|
|
257
|
+
"header": "Name",
|
|
258
|
+
"multiSelect": false,
|
|
259
|
+
"options": [
|
|
260
|
+
{"label": "[suggested-name]", "description": "Suggested: /api/v2/[suggested-name]"},
|
|
261
|
+
{"label": "Custom name", "description": "I'll type my own"}
|
|
262
|
+
]
|
|
263
|
+
}]
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Q2: Execution Order**
|
|
268
|
+
```json
|
|
269
|
+
{
|
|
270
|
+
"questions": [{
|
|
271
|
+
"question": "How should the APIs execute?",
|
|
272
|
+
"header": "Order",
|
|
273
|
+
"multiSelect": false,
|
|
274
|
+
"options": [
|
|
275
|
+
{"label": "Parallel", "description": "All at once, combine results"},
|
|
276
|
+
{"label": "Sequential", "description": "One after another, pass data between"},
|
|
277
|
+
{"label": "Conditional", "description": "Second API depends on first result"}
|
|
278
|
+
]
|
|
279
|
+
}]
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**Q3: Error Handling**
|
|
284
|
+
```json
|
|
285
|
+
{
|
|
286
|
+
"questions": [{
|
|
287
|
+
"question": "If the first API fails, what should happen?",
|
|
288
|
+
"header": "Errors",
|
|
289
|
+
"multiSelect": false,
|
|
290
|
+
"options": [
|
|
291
|
+
{"label": "Fail entire request", "description": "Return error, don't call other APIs"},
|
|
292
|
+
{"label": "Continue with partial", "description": "Return what succeeded"},
|
|
293
|
+
{"label": "Retry once", "description": "Retry failed API, then fail if still failing"}
|
|
294
|
+
]
|
|
295
|
+
}]
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Q4: Data Transformation**
|
|
300
|
+
```json
|
|
301
|
+
{
|
|
302
|
+
"questions": [{
|
|
303
|
+
"question": "Do you need to transform data between APIs?",
|
|
304
|
+
"header": "Transform",
|
|
305
|
+
"multiSelect": false,
|
|
306
|
+
"options": [
|
|
307
|
+
{"label": "No", "description": "Use responses as-is"},
|
|
308
|
+
{"label": "Yes", "description": "I'll describe the transformation"}
|
|
309
|
+
]
|
|
310
|
+
}]
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Q5: Caching**
|
|
315
|
+
```json
|
|
316
|
+
{
|
|
317
|
+
"questions": [{
|
|
318
|
+
"question": "Caching strategy?",
|
|
319
|
+
"header": "Cache",
|
|
320
|
+
"multiSelect": false,
|
|
321
|
+
"options": [
|
|
322
|
+
{"label": "No caching", "description": "Always fetch fresh"},
|
|
323
|
+
{"label": "Cache combined result", "description": "Cache the final response"},
|
|
324
|
+
{"label": "Cache individual APIs", "description": "Cache each API's response separately"}
|
|
325
|
+
]
|
|
326
|
+
}]
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Store all decisions in state:**
|
|
331
|
+
```json
|
|
332
|
+
{
|
|
333
|
+
"phases": {
|
|
334
|
+
"interview": {
|
|
335
|
+
"status": "complete",
|
|
336
|
+
"decisions": {
|
|
337
|
+
"endpoint_name": "brand-voice",
|
|
338
|
+
"execution_order": "sequential",
|
|
339
|
+
"error_strategy": "fail-fast",
|
|
340
|
+
"data_transformation": false,
|
|
341
|
+
"caching_strategy": "none"
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**Phase Exit:**
|
|
349
|
+
```json
|
|
350
|
+
{
|
|
351
|
+
"questions": [{
|
|
352
|
+
"question": "Interview complete. Ready for deep research?",
|
|
353
|
+
"header": "Proceed",
|
|
354
|
+
"multiSelect": false,
|
|
355
|
+
"options": [
|
|
356
|
+
{"label": "Yes, proceed", "description": "Move to Deep Research phase"},
|
|
357
|
+
{"label": "Change answers", "description": "I want to modify my answers"}
|
|
358
|
+
]
|
|
359
|
+
}]
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
### Phase 5: DEEP RESEARCH (Optional)
|
|
366
|
+
|
|
367
|
+
Based on interview answers, propose targeted research:
|
|
368
|
+
|
|
369
|
+
```json
|
|
370
|
+
{
|
|
371
|
+
"questions": [{
|
|
372
|
+
"question": "Based on your answers, should I research: [specific topics based on interview]?",
|
|
373
|
+
"header": "Deep",
|
|
374
|
+
"multiSelect": false,
|
|
375
|
+
"options": [
|
|
376
|
+
{"label": "Yes, research these", "description": "Run the searches"},
|
|
377
|
+
{"label": "Add more topics", "description": "I need [something specific]"},
|
|
378
|
+
{"label": "Skip to schema", "description": "I have enough info"}
|
|
379
|
+
]
|
|
380
|
+
}]
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Topics to propose based on interview:
|
|
385
|
+
- If sequential: "data passing between API calls"
|
|
386
|
+
- If parallel: "Promise.all error handling patterns"
|
|
387
|
+
- If retry: "exponential backoff strategies"
|
|
388
|
+
- If caching: "response caching with invalidation"
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
### Phase 6: COMBINED SCHEMA
|
|
393
|
+
|
|
394
|
+
Create Zod schema that COMPOSES existing schemas:
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
// src/app/api/v2/[combined-name]/schemas.ts
|
|
398
|
+
import { z } from 'zod';
|
|
399
|
+
import { Api1ResponseSchema } from '../api1/schemas';
|
|
400
|
+
import { Api2ResponseSchema } from '../api2/schemas';
|
|
401
|
+
|
|
402
|
+
// Combined request schema
|
|
403
|
+
export const CombinedRequestSchema = z.object({
|
|
404
|
+
// Fields needed by both APIs
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// Combined response schema
|
|
408
|
+
export const CombinedResponseSchema = z.object({
|
|
409
|
+
api1: Api1ResponseSchema,
|
|
410
|
+
api2: Api2ResponseSchema,
|
|
411
|
+
combined_at: z.string(),
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
export type CombinedRequest = z.infer<typeof CombinedRequestSchema>;
|
|
415
|
+
export type CombinedResponse = z.infer<typeof CombinedResponseSchema>;
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
**Ask for approval:**
|
|
419
|
+
```json
|
|
420
|
+
{
|
|
421
|
+
"questions": [{
|
|
422
|
+
"question": "Combined schema created. It imports from [API1] and [API2] schemas. Approve?",
|
|
423
|
+
"header": "Schema",
|
|
424
|
+
"multiSelect": false,
|
|
425
|
+
"options": [
|
|
426
|
+
{"label": "Yes, approved", "description": "Schema looks correct"},
|
|
427
|
+
{"label": "Make changes", "description": "I need to modify something"}
|
|
428
|
+
]
|
|
429
|
+
}]
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
### Phase 7: ENVIRONMENT CHECK
|
|
436
|
+
|
|
437
|
+
Verify all API keys from combined APIs are available.
|
|
438
|
+
|
|
439
|
+
Read the source API entries in registry.json to determine required environment variables.
|
|
440
|
+
|
|
441
|
+
Report:
|
|
442
|
+
```
|
|
443
|
+
Environment Check:
|
|
444
|
+
[checkmark] API1_KEY - Found
|
|
445
|
+
[checkmark] API2_KEY - Found
|
|
446
|
+
|
|
447
|
+
All required keys available.
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
```json
|
|
451
|
+
{
|
|
452
|
+
"questions": [{
|
|
453
|
+
"question": "Environment check passed. All [N] API keys found. Ready for TDD?",
|
|
454
|
+
"header": "Env",
|
|
455
|
+
"multiSelect": false,
|
|
456
|
+
"options": [
|
|
457
|
+
{"label": "Yes, write tests", "description": "Proceed to TDD Red"},
|
|
458
|
+
{"label": "No, need setup", "description": "I need to configure something"}
|
|
459
|
+
]
|
|
460
|
+
}]
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
### Phase 8: TDD RED (Integration Tests)
|
|
467
|
+
|
|
468
|
+
Write tests for the combined flow:
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
// src/app/api/v2/[combined-name]/__tests__/[combined-name].api.test.ts
|
|
472
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
473
|
+
|
|
474
|
+
describe('[Combined Name] API', () => {
|
|
475
|
+
describe('POST /api/v2/[combined-name]', () => {
|
|
476
|
+
it('should call both APIs and combine results', async () => {
|
|
477
|
+
// Test combined flow
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
it('should handle first API failure correctly', async () => {
|
|
481
|
+
// Test error handling based on interview decisions
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
// More tests based on interview decisions...
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
Run tests - they should FAIL (Red phase).
|
|
490
|
+
|
|
491
|
+
**Phase Exit:**
|
|
492
|
+
```json
|
|
493
|
+
{
|
|
494
|
+
"questions": [{
|
|
495
|
+
"question": "Failing tests written. Ready to implement?",
|
|
496
|
+
"header": "Proceed",
|
|
497
|
+
"multiSelect": false,
|
|
498
|
+
"options": [
|
|
499
|
+
{"label": "Yes, implement", "description": "Move to TDD Green phase"},
|
|
500
|
+
{"label": "Add more tests", "description": "I need to test more scenarios"}
|
|
501
|
+
]
|
|
502
|
+
}]
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
508
|
+
### Phase 9: TDD GREEN (Orchestration Route)
|
|
509
|
+
|
|
510
|
+
Implement the orchestration logic:
|
|
511
|
+
|
|
512
|
+
```typescript
|
|
513
|
+
// src/app/api/v2/[combined-name]/route.ts
|
|
514
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
515
|
+
import { CombinedRequestSchema } from './schemas';
|
|
516
|
+
|
|
517
|
+
export async function POST(request: NextRequest) {
|
|
518
|
+
try {
|
|
519
|
+
const body = await request.json();
|
|
520
|
+
const validated = CombinedRequestSchema.parse(body);
|
|
521
|
+
|
|
522
|
+
// Implementation based on interview decisions:
|
|
523
|
+
// - Sequential/Parallel/Conditional execution
|
|
524
|
+
// - Error handling strategy
|
|
525
|
+
// - Data transformation
|
|
526
|
+
// - Caching
|
|
527
|
+
|
|
528
|
+
return NextResponse.json({
|
|
529
|
+
// Combined response
|
|
530
|
+
combined_at: new Date().toISOString(),
|
|
531
|
+
});
|
|
532
|
+
} catch (error) {
|
|
533
|
+
return NextResponse.json(
|
|
534
|
+
{ error: error.message },
|
|
535
|
+
{ status: 500 }
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
Run tests - all must pass (Green phase).
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
### Phase 10: VERIFY
|
|
546
|
+
|
|
547
|
+
Test the full flow end-to-end:
|
|
548
|
+
|
|
549
|
+
```json
|
|
550
|
+
{
|
|
551
|
+
"questions": [{
|
|
552
|
+
"question": "Integration tests pass. Should I verify the full flow manually with real API calls?",
|
|
553
|
+
"header": "Verify",
|
|
554
|
+
"multiSelect": false,
|
|
555
|
+
"options": [
|
|
556
|
+
{"label": "Yes, test real flow", "description": "Make actual API calls"},
|
|
557
|
+
{"label": "Skip, tests sufficient", "description": "Proceed to refactor"}
|
|
558
|
+
]
|
|
559
|
+
}]
|
|
560
|
+
}
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
If verifying, make actual requests and report results.
|
|
564
|
+
|
|
565
|
+
---
|
|
566
|
+
|
|
567
|
+
### Phase 11: REFACTOR
|
|
568
|
+
|
|
569
|
+
Clean up the orchestration code:
|
|
570
|
+
- Extract reusable patterns
|
|
571
|
+
- Add error logging
|
|
572
|
+
- Optimize parallel calls if applicable
|
|
573
|
+
- Add JSDoc comments
|
|
574
|
+
|
|
575
|
+
Run tests after each change to ensure they still pass.
|
|
576
|
+
|
|
577
|
+
**Phase Exit:**
|
|
578
|
+
```json
|
|
579
|
+
{
|
|
580
|
+
"questions": [{
|
|
581
|
+
"question": "Refactoring complete. Tests still pass. Ready to document?",
|
|
582
|
+
"header": "Proceed",
|
|
583
|
+
"multiSelect": false,
|
|
584
|
+
"options": [
|
|
585
|
+
{"label": "Yes, document", "description": "Move to Documentation phase"},
|
|
586
|
+
{"label": "More refactoring", "description": "I want to clean up more"}
|
|
587
|
+
]
|
|
588
|
+
}]
|
|
589
|
+
}
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
---
|
|
593
|
+
|
|
594
|
+
### Phase 12: DOCUMENTATION
|
|
595
|
+
|
|
596
|
+
Update:
|
|
597
|
+
1. `api-tests-manifest.json` - Add new combined endpoint
|
|
598
|
+
2. `registry.json` - Add to `combined` section
|
|
599
|
+
3. Any project docs as needed
|
|
600
|
+
|
|
601
|
+
```json
|
|
602
|
+
{
|
|
603
|
+
"questions": [{
|
|
604
|
+
"question": "Documentation updated. Ready to complete?",
|
|
605
|
+
"header": "Docs",
|
|
606
|
+
"multiSelect": false,
|
|
607
|
+
"options": [
|
|
608
|
+
{"label": "Yes, complete", "description": "Finalize and update registry"},
|
|
609
|
+
{"label": "Need more docs", "description": "I want to add something"}
|
|
610
|
+
]
|
|
611
|
+
}]
|
|
612
|
+
}
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
---
|
|
616
|
+
|
|
617
|
+
### Phase 13: COMPLETION
|
|
618
|
+
|
|
619
|
+
Update registry.json with the new combined API:
|
|
620
|
+
|
|
621
|
+
```json
|
|
622
|
+
{
|
|
623
|
+
"combined": {
|
|
624
|
+
"[combined-name]": {
|
|
625
|
+
"name": "[Display Name]",
|
|
626
|
+
"type": "api",
|
|
627
|
+
"description": "[Purpose from interview]",
|
|
628
|
+
"combines": ["api1", "api2"],
|
|
629
|
+
"route": "src/app/api/v2/[combined-name]/route.ts",
|
|
630
|
+
"schemas": "src/app/api/v2/[combined-name]/schemas.ts",
|
|
631
|
+
"tests": "src/app/api/v2/[combined-name]/__tests__/",
|
|
632
|
+
"flow_type": "[sequential|parallel|conditional]",
|
|
633
|
+
"created_at": "[date]",
|
|
634
|
+
"status": "complete"
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
**Final confirmation:**
|
|
641
|
+
```json
|
|
642
|
+
{
|
|
643
|
+
"questions": [{
|
|
644
|
+
"question": "Combined API complete. Registry updated. Anything else?",
|
|
645
|
+
"header": "Complete",
|
|
646
|
+
"multiSelect": false,
|
|
647
|
+
"options": [
|
|
648
|
+
{"label": "Done", "description": "Workflow complete"},
|
|
649
|
+
{"label": "Create another", "description": "Start new combine workflow"}
|
|
650
|
+
]
|
|
651
|
+
}]
|
|
652
|
+
}
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
## Mode B: Combine UI (Coming Soon)
|
|
658
|
+
|
|
659
|
+
UI combination requires `/hustle-ui-create` to be implemented first.
|
|
660
|
+
|
|
661
|
+
Three sub-modes planned:
|
|
662
|
+
- **A) Composed Component** - Combine existing components
|
|
663
|
+
- **B) Page with Components** - Create page using components
|
|
664
|
+
- **C) Page with Components + API** - Create page with data fetching
|
|
665
|
+
|
|
666
|
+
---
|
|
667
|
+
|
|
668
|
+
## State File Structure
|
|
669
|
+
|
|
670
|
+
```json
|
|
671
|
+
{
|
|
672
|
+
"version": "3.8.0",
|
|
673
|
+
"workflow": "combine-api",
|
|
674
|
+
"element_name": "brand-voice",
|
|
675
|
+
"element_type": "combined",
|
|
676
|
+
|
|
677
|
+
"combine_config": {
|
|
678
|
+
"mode": "api",
|
|
679
|
+
"source_elements": [
|
|
680
|
+
{ "type": "api", "name": "brandfetch" },
|
|
681
|
+
{ "type": "api", "name": "elevenlabs" }
|
|
682
|
+
],
|
|
683
|
+
"flow_type": "sequential",
|
|
684
|
+
"error_strategy": "fail-fast"
|
|
685
|
+
},
|
|
686
|
+
|
|
687
|
+
"phases": {
|
|
688
|
+
"selection": { "status": "complete", "apis_selected": 2, "user_question_asked": true, "phase_exit_confirmed": true },
|
|
689
|
+
"scope": { "status": "complete", "purpose": "...", "user_question_asked": true, "phase_exit_confirmed": true },
|
|
690
|
+
"research_initial": { "status": "complete", "user_question_asked": true, "phase_exit_confirmed": true },
|
|
691
|
+
"interview": { "status": "complete", "decisions": {}, "user_question_asked": true, "phase_exit_confirmed": true },
|
|
692
|
+
"research_deep": { "status": "skipped", "user_question_asked": true, "phase_exit_confirmed": true },
|
|
693
|
+
"schema_creation": { "status": "complete", "user_question_asked": true, "phase_exit_confirmed": true },
|
|
694
|
+
"environment_check": { "status": "complete", "user_question_asked": true, "phase_exit_confirmed": true },
|
|
695
|
+
"tdd_red": { "status": "complete", "user_question_asked": true, "phase_exit_confirmed": true },
|
|
696
|
+
"tdd_green": { "status": "complete", "user_question_asked": true, "phase_exit_confirmed": true },
|
|
697
|
+
"verify": { "status": "complete", "user_question_asked": true, "phase_exit_confirmed": true },
|
|
698
|
+
"tdd_refactor": { "status": "complete", "user_question_asked": true, "phase_exit_confirmed": true },
|
|
699
|
+
"documentation": { "status": "complete", "user_question_asked": true, "phase_exit_confirmed": true },
|
|
700
|
+
"completion": { "status": "complete", "user_question_asked": true, "phase_exit_confirmed": true }
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
---
|
|
706
|
+
|
|
707
|
+
## Output Artifacts
|
|
708
|
+
|
|
709
|
+
1. **Route Handler**: `/src/app/api/v2/[combined-name]/route.ts`
|
|
710
|
+
2. **Schema File**: `/src/app/api/v2/[combined-name]/schemas.ts`
|
|
711
|
+
3. **Test Suite**: `/src/app/api/v2/[combined-name]/__tests__/`
|
|
712
|
+
4. **Updated Registry**: `.claude/registry.json` (combined section)
|
|
713
|
+
5. **Updated Manifest**: `api-tests-manifest.json`
|
|
714
|
+
|
|
715
|
+
---
|
|
716
|
+
|
|
717
|
+
## Example: WordPress + Elementor
|
|
718
|
+
|
|
719
|
+
```
|
|
720
|
+
/hustle-combine api
|
|
721
|
+
|
|
722
|
+
Available APIs:
|
|
723
|
+
[checkbox] wordpress - WordPress REST API
|
|
724
|
+
[checkbox] elementor - Elementor widget API
|
|
725
|
+
[checkbox] brandfetch - Brand data extraction
|
|
726
|
+
|
|
727
|
+
> wordpress, elementor
|
|
728
|
+
|
|
729
|
+
Purpose: "Log into WordPress, then create Elementor template"
|
|
730
|
+
|
|
731
|
+
Interview:
|
|
732
|
+
- Order: Sequential (WordPress auth first)
|
|
733
|
+
- Errors: Fail if WordPress auth fails
|
|
734
|
+
- Name: wp-elementor-sync
|
|
735
|
+
|
|
736
|
+
Creates:
|
|
737
|
+
src/app/api/v2/wp-elementor-sync/
|
|
738
|
+
├── route.ts
|
|
739
|
+
├── schemas.ts
|
|
740
|
+
└── __tests__/
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
<claude-commands-template>
|
|
744
|
+
## Project Rules
|
|
745
|
+
|
|
746
|
+
1. **Registry Required**: Only combine APIs that exist in registry.json with `status: "complete"`
|
|
747
|
+
2. **No Skipping Selection**: User MUST select from available APIs
|
|
748
|
+
3. **Interview Required**: All decisions must come from user, not assumptions
|
|
749
|
+
4. **Lighter Research**: Since APIs exist, research focuses on orchestration patterns only
|
|
750
|
+
5. **Test Integration**: Tests verify APIs work together, not individual API behavior
|
|
751
|
+
6. **Update Registry**: Always update registry.json on completion
|
|
752
|
+
|
|
753
|
+
## Never Skip
|
|
754
|
+
|
|
755
|
+
- Phase 1 (Selection) - Must read from registry
|
|
756
|
+
- Phase 4 (Interview) - All orchestration decisions from user
|
|
757
|
+
- Phase 8 (TDD Red) - Integration tests first
|
|
758
|
+
- Phase 13 (Complete) - Registry update required
|
|
759
|
+
|
|
760
|
+
## User Interaction Required
|
|
761
|
+
|
|
762
|
+
Every phase MUST use `AskUserQuestion` tool. Self-answering is FORBIDDEN.
|
|
763
|
+
</claude-commands-template>
|