@hustle-together/api-dev-tools 2.0.7 → 3.0.0

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 (37) hide show
  1. package/README.md +283 -478
  2. package/bin/cli.js +55 -11
  3. package/commands/README.md +124 -251
  4. package/commands/api-create.md +318 -136
  5. package/commands/api-interview.md +252 -256
  6. package/commands/api-research.md +209 -234
  7. package/commands/api-verify.md +231 -0
  8. package/demo/audio/generate-all-narrations.js +516 -0
  9. package/demo/audio/generate-voice-previews.js +140 -0
  10. package/demo/audio/narration-adam-timing.json +3666 -0
  11. package/demo/audio/narration-adam.mp3 +0 -0
  12. package/demo/audio/narration-creature-timing.json +3666 -0
  13. package/demo/audio/narration-creature.mp3 +0 -0
  14. package/demo/audio/narration-gaming-timing.json +3666 -0
  15. package/demo/audio/narration-gaming.mp3 +0 -0
  16. package/demo/audio/narration-hope-timing.json +3666 -0
  17. package/demo/audio/narration-hope.mp3 +0 -0
  18. package/demo/audio/narration-mark-timing.json +3666 -0
  19. package/demo/audio/narration-mark.mp3 +0 -0
  20. package/demo/audio/previews/manifest.json +30 -0
  21. package/demo/audio/previews/preview-creature.mp3 +0 -0
  22. package/demo/audio/previews/preview-gaming.mp3 +0 -0
  23. package/demo/audio/previews/preview-hope.mp3 +0 -0
  24. package/demo/audio/previews/preview-mark.mp3 +0 -0
  25. package/demo/audio/voices-manifest.json +50 -0
  26. package/demo/hustle-together/blog/gemini-vs-claude-widgets.html +30 -28
  27. package/demo/hustle-together/blog/interview-driven-api-development.html +37 -23
  28. package/demo/hustle-together/index.html +142 -109
  29. package/demo/workflow-demo.html +1023 -558
  30. package/hooks/periodic-reground.py +154 -0
  31. package/hooks/session-startup.py +151 -0
  32. package/hooks/track-tool-use.py +109 -17
  33. package/hooks/verify-after-green.py +152 -0
  34. package/package.json +2 -2
  35. package/templates/api-dev-state.json +42 -7
  36. package/templates/research-index.json +6 -0
  37. package/templates/settings.json +23 -0
Binary file
@@ -0,0 +1,30 @@
1
+ {
2
+ "generated": "2025-12-08T06:50:32.727Z",
3
+ "text": "Welcome to Hustle API Dev Tools. Build APIs the right way. Research first. Interview second. Test before code. Document everything.",
4
+ "voices": [
5
+ {
6
+ "voice": "Mark",
7
+ "id": "UgBBYS2sOqTuMpoF3BR0",
8
+ "file": "preview-mark.mp3",
9
+ "size": 164302
10
+ },
11
+ {
12
+ "voice": "Hope",
13
+ "id": "tnSpp4vdxKPjI9w0GnoV",
14
+ "file": "preview-hope.mp3",
15
+ "size": 135881
16
+ },
17
+ {
18
+ "voice": "Creature",
19
+ "id": "Z7RrOqZFTyLpIlzCgfsp",
20
+ "file": "preview-creature.mp3",
21
+ "size": 288018
22
+ },
23
+ {
24
+ "voice": "Gaming",
25
+ "id": "YOq2y2Up4RgXP2HyXjE5",
26
+ "file": "preview-gaming.mp3",
27
+ "size": 329814
28
+ }
29
+ ]
30
+ }
@@ -0,0 +1,50 @@
1
+ {
2
+ "generated": "2025-12-08T07:05:05.916Z",
3
+ "voices": [
4
+ {
5
+ "voice": "Adam",
6
+ "name": "adam",
7
+ "audioFile": "narration-adam.mp3",
8
+ "timingFile": "narration-adam-timing.json",
9
+ "duration": 370.777,
10
+ "wordCount": 694,
11
+ "audioSize": 5932975
12
+ },
13
+ {
14
+ "voice": "Mark",
15
+ "name": "mark",
16
+ "audioFile": "narration-mark.mp3",
17
+ "timingFile": "narration-mark-timing.json",
18
+ "duration": 338.688,
19
+ "wordCount": 694,
20
+ "audioSize": 5419721
21
+ },
22
+ {
23
+ "voice": "Hope",
24
+ "name": "hope",
25
+ "audioFile": "narration-hope.mp3",
26
+ "timingFile": "narration-hope-timing.json",
27
+ "duration": 305.202,
28
+ "wordCount": 694,
29
+ "audioSize": 4883898
30
+ },
31
+ {
32
+ "voice": "Creature",
33
+ "name": "creature",
34
+ "audioFile": "narration-creature.mp3",
35
+ "timingFile": "narration-creature-timing.json",
36
+ "duration": 466.627,
37
+ "wordCount": 694,
38
+ "audioSize": 7466885
39
+ },
40
+ {
41
+ "voice": "Gaming",
42
+ "name": "gaming",
43
+ "audioFile": "narration-gaming.mp3",
44
+ "timingFile": "narration-gaming-timing.json",
45
+ "duration": 644.121,
46
+ "wordCount": 694,
47
+ "audioSize": 10306500
48
+ }
49
+ ]
50
+ }
@@ -13,15 +13,17 @@
13
13
 
14
14
  :root {
15
15
  --bg: #0a0a0a;
16
- --bg-secondary: #111;
16
+ --bg-secondary: #121212;
17
17
  --bg-tertiary: #1a1a1a;
18
- --text: #e0e0e0;
19
- --text-muted: #888;
20
- --text-dim: #444;
18
+ --text: #e8e8e8;
19
+ --text-muted: #999;
20
+ --text-dim: #555;
21
21
  --accent: #fff;
22
22
  --accent-red: #BA0C2F;
23
23
  --accent-red-glow: rgba(186, 12, 47, 0.4);
24
24
  --border: #333;
25
+ --border-strong: #444;
26
+ --bg-card: #1a1a1a;
25
27
  --glow: rgba(255, 255, 255, 0.3);
26
28
  }
27
29
 
@@ -57,7 +59,7 @@
57
59
  justify-content: space-between;
58
60
  align-items: center;
59
61
  background: var(--bg);
60
- border-bottom: 1px dashed var(--border);
62
+ border-bottom: 2px solid var(--border);
61
63
  }
62
64
 
63
65
  .logo {
@@ -100,7 +102,7 @@
100
102
 
101
103
  .theme-toggle {
102
104
  background: transparent;
103
- border: 1px dashed var(--border);
105
+ border: 2px solid var(--border);
104
106
  color: var(--text);
105
107
  padding: 6px 12px;
106
108
  cursor: pointer;
@@ -164,7 +166,7 @@
164
166
 
165
167
  .audio-player {
166
168
  background: var(--bg-secondary);
167
- border: 1px dashed var(--border);
169
+ border: 2px solid var(--border);
168
170
  padding: 25px;
169
171
  margin: 40px 0;
170
172
  opacity: 0;
@@ -236,7 +238,7 @@
236
238
 
237
239
  .comparison-table {
238
240
  margin: 40px 0;
239
- border: 1px dashed var(--border);
241
+ border: 2px solid var(--border);
240
242
  opacity: 0;
241
243
  }
242
244
 
@@ -244,7 +246,7 @@
244
246
  display: grid;
245
247
  grid-template-columns: 1fr 1fr 1fr;
246
248
  background: var(--bg-secondary);
247
- border-bottom: 1px dashed var(--border);
249
+ border-bottom: 2px solid var(--border);
248
250
  }
249
251
 
250
252
  .comparison-header div {
@@ -256,13 +258,13 @@
256
258
  }
257
259
 
258
260
  .comparison-header div:not(:last-child) {
259
- border-right: 1px dashed var(--border);
261
+ border-right: 2px solid var(--border);
260
262
  }
261
263
 
262
264
  .comparison-row {
263
265
  display: grid;
264
266
  grid-template-columns: 1fr 1fr 1fr;
265
- border-bottom: 1px dashed var(--border);
267
+ border-bottom: 2px solid var(--border);
266
268
  }
267
269
 
268
270
  .comparison-row:last-child { border-bottom: none; }
@@ -274,7 +276,7 @@
274
276
  }
275
277
 
276
278
  .comparison-row div:not(:last-child) {
277
- border-right: 1px dashed var(--border);
279
+ border-right: 2px solid var(--border);
278
280
  }
279
281
 
280
282
  .comparison-row div:first-child {
@@ -286,7 +288,7 @@
286
288
 
287
289
  .featured-media {
288
290
  margin: 40px 0;
289
- border: 1px dashed var(--border);
291
+ border: 2px solid var(--border);
290
292
  opacity: 0;
291
293
  }
292
294
 
@@ -313,7 +315,7 @@
313
315
  padding: 15px;
314
316
  font-size: 0.8rem;
315
317
  color: var(--text-muted);
316
- border-top: 1px dashed var(--border);
318
+ border-top: 2px solid var(--border);
317
319
  }
318
320
 
319
321
  .article-content { opacity: 0; }
@@ -337,13 +339,13 @@
337
339
  .article-content code {
338
340
  background: var(--bg-secondary);
339
341
  padding: 2px 8px;
340
- border: 1px dashed var(--border);
342
+ border: 2px solid var(--border);
341
343
  font-size: 0.9em;
342
344
  }
343
345
 
344
346
  .article-content pre {
345
347
  background: var(--bg-secondary);
346
- border: 1px dashed var(--border);
348
+ border: 2px solid var(--border);
347
349
  padding: 20px;
348
350
  margin: 25px 0;
349
351
  overflow-x: auto;
@@ -361,7 +363,7 @@
361
363
 
362
364
  .callout {
363
365
  background: var(--bg-secondary);
364
- border: 1px dashed var(--border);
366
+ border: 2px solid var(--border);
365
367
  border-left: 3px solid var(--text);
366
368
  padding: 25px;
367
369
  margin: 30px 0;
@@ -390,14 +392,14 @@
390
392
 
391
393
  .ai-chat {
392
394
  background: var(--bg-secondary);
393
- border: 1px dashed var(--border);
395
+ border: 2px solid var(--border);
394
396
  margin: 50px 0;
395
397
  opacity: 0;
396
398
  }
397
399
 
398
400
  .ai-chat-header {
399
401
  padding: 20px;
400
- border-bottom: 1px dashed var(--border);
402
+ border-bottom: 2px solid var(--border);
401
403
  display: flex;
402
404
  align-items: center;
403
405
  gap: 15px;
@@ -432,7 +434,7 @@
432
434
  .chat-avatar {
433
435
  width: 30px;
434
436
  height: 30px;
435
- border: 1px dashed var(--border);
437
+ border: 2px solid var(--border);
436
438
  display: flex;
437
439
  align-items: center;
438
440
  justify-content: center;
@@ -442,7 +444,7 @@
442
444
 
443
445
  .chat-bubble {
444
446
  background: var(--bg-tertiary);
445
- border: 1px dashed var(--border);
447
+ border: 2px solid var(--border);
446
448
  padding: 12px 16px;
447
449
  max-width: 80%;
448
450
  font-size: 0.9rem;
@@ -465,7 +467,7 @@
465
467
 
466
468
  .quick-btn {
467
469
  background: transparent;
468
- border: 1px dashed var(--border);
470
+ border: 2px solid var(--border);
469
471
  color: var(--text);
470
472
  padding: 8px 16px;
471
473
  font-family: inherit;
@@ -480,13 +482,13 @@
480
482
  display: flex;
481
483
  gap: 10px;
482
484
  padding: 15px 20px;
483
- border-top: 1px dashed var(--border);
485
+ border-top: 2px solid var(--border);
484
486
  }
485
487
 
486
488
  .ai-chat-input input {
487
489
  flex: 1;
488
490
  background: transparent;
489
- border: 1px dashed var(--border);
491
+ border: 2px solid var(--border);
490
492
  color: var(--text);
491
493
  padding: 12px 15px;
492
494
  font-family: inherit;
@@ -509,7 +511,7 @@
509
511
 
510
512
  .feedback-section {
511
513
  background: var(--bg-secondary);
512
- border: 1px dashed var(--border);
514
+ border: 2px solid var(--border);
513
515
  padding: 30px;
514
516
  margin: 50px 0;
515
517
  text-align: center;
@@ -562,7 +564,7 @@
562
564
  }
563
565
 
564
566
  .related-card {
565
- border: 1px dashed var(--border);
567
+ border: 2px solid var(--border);
566
568
  padding: 25px;
567
569
  text-decoration: none;
568
570
  color: var(--text);
@@ -588,7 +590,7 @@
588
590
  }
589
591
 
590
592
  footer {
591
- border-top: 1px dashed var(--border);
593
+ border-top: 2px solid var(--border);
592
594
  padding: 40px;
593
595
  text-align: center;
594
596
  margin-top: 60px;
@@ -623,7 +625,7 @@
623
625
  .article-title { font-size: 2rem; }
624
626
  .comparison-header, .comparison-row { grid-template-columns: 1fr; }
625
627
  .comparison-header div:not(:last-child),
626
- .comparison-row div:not(:last-child) { border-right: none; border-bottom: 1px dashed var(--border); }
628
+ .comparison-row div:not(:last-child) { border-right: none; border-bottom: 2px solid var(--border); }
627
629
  .related-grid { grid-template-columns: 1fr; }
628
630
  nav { padding: 15px 20px; }
629
631
  .nav-links { display: none; }
@@ -17,31 +17,35 @@
17
17
 
18
18
  :root {
19
19
  --bg: #0a0a0a;
20
- --bg-secondary: #111;
20
+ --bg-secondary: #121212;
21
21
  --bg-tertiary: #1a1a1a;
22
- --text: #e0e0e0;
23
- --text-muted: #888;
24
- --text-dim: #444;
22
+ --bg-card: #1a1a1a;
23
+ --text: #e8e8e8;
24
+ --text-muted: #999;
25
+ --text-dim: #555;
25
26
  --accent: #fff;
26
27
  --accent-red: #BA0C2F;
27
28
  --accent-red-glow: rgba(186, 12, 47, 0.4);
28
29
  --border: #333;
30
+ --border-strong: #444;
29
31
  --glow: rgba(255, 255, 255, 0.3);
30
32
  --success: #4ade80;
31
33
  --warning: #fbbf24;
32
34
  }
33
35
 
34
36
  [data-theme="light"] {
35
- --bg: #f5f5f5;
37
+ --bg: #f0f0f0;
36
38
  --bg-secondary: #fff;
37
- --bg-tertiary: #e5e5e5;
39
+ --bg-tertiary: #f5f5f5;
40
+ --bg-card: #fafafa;
38
41
  --text: #1a1a1a;
39
42
  --text-muted: #666;
40
43
  --text-dim: #aaa;
41
44
  --accent: #000;
42
45
  --accent-red: #BA0C2F;
43
46
  --accent-red-glow: rgba(186, 12, 47, 0.3);
44
- --border: #ccc;
47
+ --border: #ddd;
48
+ --border-strong: #ccc;
45
49
  --glow: rgba(0, 0, 0, 0.15);
46
50
  }
47
51
 
@@ -53,19 +57,19 @@
53
57
  overflow-x: hidden;
54
58
  }
55
59
 
56
- /* Navigation */
60
+ /* Navigation - boxy style */
57
61
  nav {
58
62
  position: fixed;
59
63
  top: 0;
60
64
  left: 0;
61
65
  right: 0;
62
66
  z-index: 1000;
63
- padding: 20px 40px;
67
+ padding: 15px 40px;
64
68
  display: flex;
65
69
  justify-content: space-between;
66
70
  align-items: center;
67
71
  background: var(--bg);
68
- border-bottom: 1px dashed var(--border);
72
+ border-bottom: 2px solid var(--border);
69
73
  }
70
74
 
71
75
  .logo {
@@ -81,13 +85,16 @@
81
85
  }
82
86
 
83
87
  .logo-icon {
84
- width: 28px;
85
- height: 28px;
86
- border: 2px solid var(--text);
88
+ width: 30px;
89
+ height: 30px;
90
+ border: 2px solid var(--accent-red);
91
+ background: var(--accent-red);
92
+ color: #fff;
87
93
  display: flex;
88
94
  align-items: center;
89
95
  justify-content: center;
90
- font-size: 0.7rem;
96
+ font-size: 0.75rem;
97
+ font-weight: bold;
91
98
  }
92
99
 
93
100
  .nav-links {
@@ -99,29 +106,36 @@
99
106
  .nav-links a {
100
107
  color: var(--text-muted);
101
108
  text-decoration: none;
102
- font-size: 0.8rem;
109
+ font-size: 0.75rem;
103
110
  letter-spacing: 1px;
104
- transition: color 0.3s;
111
+ text-transform: uppercase;
112
+ padding: 8px 12px;
113
+ border: 2px solid transparent;
114
+ transition: all 0.2s;
105
115
  }
106
116
 
107
117
  .nav-links a:hover {
108
118
  color: var(--accent-red);
119
+ border-color: var(--accent-red);
109
120
  }
110
121
 
111
122
  .theme-toggle {
112
- background: transparent;
113
- border: 1px dashed var(--border);
123
+ background: var(--bg-card);
124
+ border: 2px solid var(--border);
114
125
  color: var(--text);
115
- padding: 6px 12px;
126
+ padding: 8px 14px;
116
127
  cursor: pointer;
117
128
  font-family: inherit;
118
- font-size: 0.75rem;
119
- transition: all 0.3s;
129
+ font-size: 0.7rem;
130
+ text-transform: uppercase;
131
+ letter-spacing: 1px;
132
+ transition: all 0.2s;
120
133
  }
121
134
 
122
135
  .theme-toggle:hover {
123
- background: var(--text);
124
- color: var(--bg);
136
+ background: var(--accent-red);
137
+ color: #fff;
138
+ border-color: var(--accent-red);
125
139
  }
126
140
 
127
141
  /* Main Content */