@hustle-together/api-dev-tools 2.0.6 → 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 +1054 -544
  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
@@ -11,7 +11,7 @@
11
11
  <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script>
12
12
  <style>
13
13
  /* ============================================
14
- HUSTLE TOGETHER - RETRO TERMINAL AESTHETIC
14
+ HUSTLE TOGETHER - 90s BOXY AESTHETIC
15
15
  Light/Dark Mode Support
16
16
  ============================================ */
17
17
 
@@ -24,28 +24,32 @@
24
24
  :root {
25
25
  /* Dark Mode (default) - Bulls/Nike colorway: Red, White, Black */
26
26
  --bg: #0a0a0a;
27
- --bg-secondary: #111;
28
- --text: #e0e0e0;
29
- --text-muted: #888;
30
- --text-dim: #444;
27
+ --bg-secondary: #121212;
28
+ --bg-card: #1a1a1a;
29
+ --text: #e8e8e8;
30
+ --text-muted: #999;
31
+ --text-dim: #555;
31
32
  --accent: #fff;
32
33
  --accent-red: #BA0C2F;
33
34
  --accent-red-glow: rgba(186, 12, 47, 0.4);
34
35
  --border: #333;
36
+ --border-strong: #444;
35
37
  --glow: rgba(255, 255, 255, 0.3);
36
38
  --pattern-opacity: 0.03;
37
39
  }
38
40
 
39
41
  [data-theme="light"] {
40
- --bg: #f5f5f5;
42
+ --bg: #f0f0f0;
41
43
  --bg-secondary: #fff;
44
+ --bg-card: #fafafa;
42
45
  --text: #1a1a1a;
43
46
  --text-muted: #666;
44
47
  --text-dim: #aaa;
45
48
  --accent: #000;
46
49
  --accent-red: #BA0C2F;
47
50
  --accent-red-glow: rgba(186, 12, 47, 0.3);
48
- --border: #ccc;
51
+ --border: #ddd;
52
+ --border-strong: #ccc;
49
53
  --glow: rgba(0, 0, 0, 0.15);
50
54
  --pattern-opacity: 0.05;
51
55
  }
@@ -82,23 +86,23 @@
82
86
  fill: none;
83
87
  }
84
88
 
85
- /* Navigation */
89
+ /* Navigation - clean boxy style */
86
90
  nav {
87
91
  position: fixed;
88
92
  top: 0;
89
93
  left: 0;
90
94
  right: 0;
91
95
  z-index: 1000;
92
- padding: 20px 40px;
96
+ padding: 15px 40px;
93
97
  display: flex;
94
98
  justify-content: space-between;
95
99
  align-items: center;
96
100
  background: var(--bg);
97
- border-bottom: 1px dashed var(--border);
101
+ border-bottom: 2px solid var(--border);
98
102
  }
99
103
 
100
104
  .logo {
101
- font-size: 1.2rem;
105
+ font-size: 1.1rem;
102
106
  font-family: 'Fredoka', 'Bungee', sans-serif;
103
107
  font-weight: 700;
104
108
  letter-spacing: 2px;
@@ -108,50 +112,57 @@
108
112
  }
109
113
 
110
114
  .logo-icon {
111
- width: 30px;
112
- height: 30px;
113
- border: 2px solid var(--text);
115
+ width: 32px;
116
+ height: 32px;
117
+ border: 2px solid var(--accent-red);
118
+ background: var(--accent-red);
119
+ color: var(--bg);
114
120
  display: flex;
115
121
  align-items: center;
116
122
  justify-content: center;
117
- font-size: 0.8rem;
123
+ font-size: 0.85rem;
124
+ font-weight: bold;
118
125
  }
119
126
 
120
127
  .nav-links {
121
128
  display: flex;
122
- gap: 30px;
129
+ gap: 25px;
123
130
  align-items: center;
124
131
  }
125
132
 
126
133
  .nav-links a {
127
134
  color: var(--text-muted);
128
135
  text-decoration: none;
129
- font-size: 0.85rem;
136
+ font-size: 0.8rem;
130
137
  letter-spacing: 1px;
131
- transition: all 0.3s;
132
- padding: 8px 0;
133
- border-bottom: 1px solid transparent;
138
+ text-transform: uppercase;
139
+ transition: all 0.2s;
140
+ padding: 8px 12px;
141
+ border: 2px solid transparent;
134
142
  }
135
143
 
136
144
  .nav-links a:hover {
137
145
  color: var(--accent-red);
138
- border-bottom-color: var(--accent-red);
146
+ border-color: var(--accent-red);
139
147
  }
140
148
 
141
149
  .theme-toggle {
142
- background: transparent;
143
- border: 1px dashed var(--border);
150
+ background: var(--bg-card);
151
+ border: 2px solid var(--border);
144
152
  color: var(--text);
145
- padding: 8px 12px;
153
+ padding: 8px 14px;
146
154
  cursor: pointer;
147
155
  font-family: inherit;
148
- font-size: 0.8rem;
149
- transition: all 0.3s;
156
+ font-size: 0.75rem;
157
+ transition: all 0.2s;
158
+ text-transform: uppercase;
159
+ letter-spacing: 1px;
150
160
  }
151
161
 
152
162
  .theme-toggle:hover {
153
- background: var(--text);
154
- color: var(--bg);
163
+ background: var(--accent-red);
164
+ color: #fff;
165
+ border-color: var(--accent-red);
155
166
  }
156
167
 
157
168
  /* Main Content */
@@ -181,13 +192,15 @@
181
192
 
182
193
  .hero-badge {
183
194
  display: inline-block;
184
- border: 1px dashed var(--border);
185
- padding: 8px 20px;
186
- font-size: 0.75rem;
195
+ border: 2px solid var(--border);
196
+ background: var(--bg-card);
197
+ padding: 10px 25px;
198
+ font-size: 0.7rem;
187
199
  letter-spacing: 3px;
188
200
  color: var(--text-muted);
189
201
  margin-bottom: 40px;
190
202
  opacity: 0;
203
+ text-transform: uppercase;
191
204
  }
192
205
 
193
206
  h1 {
@@ -248,12 +261,13 @@
248
261
  .btn {
249
262
  display: inline-block;
250
263
  padding: 15px 40px;
251
- border: 1px solid var(--text);
264
+ border: 2px solid var(--text);
252
265
  color: var(--text);
253
266
  text-decoration: none;
254
- font-size: 0.9rem;
267
+ font-size: 0.85rem;
255
268
  letter-spacing: 2px;
256
- transition: all 0.3s;
269
+ text-transform: uppercase;
270
+ transition: all 0.2s;
257
271
  background: transparent;
258
272
  cursor: pointer;
259
273
  font-family: inherit;
@@ -262,7 +276,6 @@
262
276
  .btn:hover {
263
277
  background: var(--text);
264
278
  color: var(--bg);
265
- box-shadow: 0 0 30px var(--glow);
266
279
  }
267
280
 
268
281
  .btn-primary {
@@ -272,9 +285,9 @@
272
285
  }
273
286
 
274
287
  .btn-primary:hover {
275
- background: transparent;
288
+ background: #fff;
276
289
  color: var(--accent-red);
277
- box-shadow: 0 0 30px var(--accent-red-glow);
290
+ border-color: var(--accent-red);
278
291
  }
279
292
 
280
293
  /* Section Headers */
@@ -302,7 +315,7 @@
302
315
  color: var(--accent);
303
316
  }
304
317
 
305
- /* Philosophy Section */
318
+ /* Philosophy Section - boxy cards */
306
319
  #philosophy {
307
320
  background: var(--bg-secondary);
308
321
  }
@@ -310,61 +323,65 @@
310
323
  .philosophy-grid {
311
324
  display: grid;
312
325
  grid-template-columns: repeat(3, 1fr);
313
- gap: 30px;
326
+ gap: 25px;
314
327
  max-width: 1000px;
315
328
  }
316
329
 
317
330
  .philosophy-card {
318
- border: 1px dashed var(--border);
331
+ border: 2px solid var(--border);
332
+ background: var(--bg-card);
319
333
  padding: 40px 30px;
320
334
  text-align: center;
321
- transition: all 0.3s;
335
+ transition: all 0.2s;
322
336
  opacity: 0;
323
337
  transform: translateY(20px);
324
338
  }
325
339
 
326
340
  .philosophy-card:hover {
327
341
  border-color: var(--accent-red);
328
- box-shadow: 0 0 30px var(--accent-red-glow);
342
+ transform: translateY(-3px);
329
343
  }
330
344
 
331
345
  .philosophy-icon {
332
- width: 60px;
333
- height: 60px;
346
+ width: 55px;
347
+ height: 55px;
334
348
  border: 2px solid var(--accent-red);
335
- color: var(--accent-red);
349
+ background: var(--accent-red);
350
+ color: #fff;
336
351
  margin: 0 auto 25px;
337
352
  display: flex;
338
353
  align-items: center;
339
354
  justify-content: center;
340
- font-size: 1.5rem;
355
+ font-size: 1.3rem;
341
356
  }
342
357
 
343
358
  .philosophy-title {
344
- font-size: 1.1rem;
359
+ font-size: 1rem;
345
360
  letter-spacing: 2px;
346
361
  margin-bottom: 15px;
362
+ text-transform: uppercase;
347
363
  }
348
364
 
349
365
  .philosophy-desc {
350
- font-size: 0.9rem;
366
+ font-size: 0.85rem;
351
367
  color: var(--text-muted);
352
368
  line-height: 1.8;
353
369
  }
354
370
 
355
- /* Tools Section */
371
+ /* Tools Section - boxy cards */
356
372
  .tools-grid {
357
373
  display: grid;
358
374
  grid-template-columns: repeat(2, 1fr);
359
- gap: 40px;
375
+ gap: 30px;
360
376
  max-width: 1000px;
361
377
  width: 100%;
362
378
  }
363
379
 
364
380
  .tool-card {
365
- border: 1px dashed var(--border);
381
+ border: 2px solid var(--border);
382
+ background: var(--bg-card);
366
383
  padding: 40px;
367
- transition: all 0.3s;
384
+ transition: all 0.2s;
368
385
  opacity: 0;
369
386
  transform: translateY(20px);
370
387
  position: relative;
@@ -376,34 +393,35 @@
376
393
  position: absolute;
377
394
  top: 0;
378
395
  left: 0;
379
- width: 100%;
380
- height: 3px;
396
+ width: 4px;
397
+ height: 100%;
381
398
  background: var(--accent-red);
382
- transform: scaleX(0);
383
- transition: transform 0.3s;
399
+ transition: width 0.2s;
384
400
  }
385
401
 
386
402
  .tool-card:hover {
387
403
  border-color: var(--accent-red);
388
- box-shadow: 0 0 40px var(--accent-red-glow);
389
404
  }
390
405
 
391
406
  .tool-card:hover::before {
392
- transform: scaleX(1);
407
+ width: 100%;
408
+ opacity: 0.1;
393
409
  }
394
410
 
395
411
  .tool-badge {
396
412
  display: inline-block;
397
- font-size: 0.7rem;
413
+ font-size: 0.65rem;
398
414
  letter-spacing: 2px;
399
- color: var(--text-muted);
400
- border: 1px dashed var(--border);
401
- padding: 5px 12px;
415
+ color: var(--accent-red);
416
+ border: 2px solid var(--accent-red);
417
+ padding: 6px 14px;
402
418
  margin-bottom: 20px;
419
+ text-transform: uppercase;
420
+ font-weight: bold;
403
421
  }
404
422
 
405
423
  .tool-name {
406
- font-size: 1.5rem;
424
+ font-size: 1.4rem;
407
425
  letter-spacing: 2px;
408
426
  margin-bottom: 15px;
409
427
  display: flex;
@@ -414,7 +432,9 @@
414
432
  .tool-name .icon {
415
433
  width: 40px;
416
434
  height: 40px;
417
- border: 1px solid var(--text);
435
+ border: 2px solid var(--accent-red);
436
+ background: var(--accent-red);
437
+ color: #fff;
418
438
  display: flex;
419
439
  align-items: center;
420
440
  justify-content: center;
@@ -423,7 +443,7 @@
423
443
 
424
444
  .tool-desc {
425
445
  color: var(--text-muted);
426
- font-size: 0.95rem;
446
+ font-size: 0.9rem;
427
447
  line-height: 1.8;
428
448
  margin-bottom: 25px;
429
449
  }
@@ -434,10 +454,10 @@
434
454
  }
435
455
 
436
456
  .tool-features li {
437
- font-size: 0.85rem;
457
+ font-size: 0.8rem;
438
458
  color: var(--text-muted);
439
- padding: 8px 0;
440
- border-bottom: 1px dashed var(--border);
459
+ padding: 10px 0;
460
+ border-bottom: 1px solid var(--border);
441
461
  display: flex;
442
462
  align-items: center;
443
463
  gap: 10px;
@@ -446,20 +466,23 @@
446
466
  .tool-features li::before {
447
467
  content: '+';
448
468
  color: var(--accent-red);
469
+ font-weight: bold;
449
470
  }
450
471
 
451
472
  .tool-links {
452
473
  display: flex;
453
- gap: 15px;
474
+ gap: 12px;
454
475
  }
455
476
 
456
477
  .tool-link {
457
- font-size: 0.8rem;
478
+ font-size: 0.75rem;
458
479
  color: var(--text);
459
480
  text-decoration: none;
460
- border: 1px dashed var(--border);
481
+ border: 2px solid var(--border);
461
482
  padding: 10px 20px;
462
- transition: all 0.3s;
483
+ transition: all 0.2s;
484
+ text-transform: uppercase;
485
+ letter-spacing: 1px;
463
486
  }
464
487
 
465
488
  .tool-link:hover {
@@ -468,7 +491,7 @@
468
491
  border-color: var(--accent-red);
469
492
  }
470
493
 
471
- /* Shop Section */
494
+ /* Shop Section - boxy style */
472
495
  #shop {
473
496
  background: var(--bg-secondary);
474
497
  }
@@ -479,7 +502,8 @@
479
502
  }
480
503
 
481
504
  .coming-soon-box {
482
- border: 2px dashed var(--border);
505
+ border: 2px solid var(--border);
506
+ background: var(--bg-card);
483
507
  padding: 80px 60px;
484
508
  margin-top: 40px;
485
509
  position: relative;
@@ -492,34 +516,35 @@
492
516
  top: -12px;
493
517
  left: 50%;
494
518
  transform: translateX(-50%);
495
- background: var(--bg-secondary);
496
- padding: 0 20px;
497
- font-size: 0.75rem;
519
+ background: var(--accent-red);
520
+ color: #fff;
521
+ padding: 5px 20px;
522
+ font-size: 0.7rem;
498
523
  letter-spacing: 3px;
499
- color: var(--text-muted);
500
524
  }
501
525
 
502
526
  .merch-grid {
503
527
  display: grid;
504
528
  grid-template-columns: repeat(3, 1fr);
505
- gap: 30px;
529
+ gap: 25px;
506
530
  margin-top: 40px;
507
531
  }
508
532
 
509
533
  .merch-placeholder {
510
534
  aspect-ratio: 1;
511
- border: 1px dashed var(--border);
535
+ border: 2px solid var(--border);
536
+ background: var(--bg);
512
537
  display: flex;
513
538
  flex-direction: column;
514
539
  align-items: center;
515
540
  justify-content: center;
516
541
  color: var(--text-dim);
517
- font-size: 0.8rem;
518
- transition: all 0.3s;
542
+ font-size: 0.75rem;
543
+ transition: all 0.2s;
519
544
  }
520
545
 
521
546
  .merch-placeholder:hover {
522
- border-color: var(--text-muted);
547
+ border-color: var(--accent-red);
523
548
  }
524
549
 
525
550
  .merch-placeholder .icon {
@@ -542,11 +567,11 @@
542
567
  .email-input {
543
568
  flex: 1;
544
569
  padding: 12px 20px;
545
- border: 1px dashed var(--border);
546
- background: transparent;
570
+ border: 2px solid var(--border);
571
+ background: var(--bg);
547
572
  color: var(--text);
548
573
  font-family: inherit;
549
- font-size: 0.9rem;
574
+ font-size: 0.85rem;
550
575
  }
551
576
 
552
577
  .email-input::placeholder {
@@ -555,21 +580,22 @@
555
580
 
556
581
  .email-input:focus {
557
582
  outline: none;
558
- border-color: var(--text);
583
+ border-color: var(--accent-red);
559
584
  }
560
585
 
561
- /* Blog Section */
586
+ /* Blog Section - boxy cards */
562
587
  .blog-grid {
563
588
  display: grid;
564
589
  grid-template-columns: repeat(3, 1fr);
565
- gap: 30px;
590
+ gap: 25px;
566
591
  max-width: 1100px;
567
592
  width: 100%;
568
593
  }
569
594
 
570
595
  .blog-card {
571
- border: 1px dashed var(--border);
572
- transition: all 0.3s;
596
+ border: 2px solid var(--border);
597
+ background: var(--bg-card);
598
+ transition: all 0.2s;
573
599
  opacity: 0;
574
600
  transform: translateY(20px);
575
601
  overflow: hidden;
@@ -577,26 +603,25 @@
577
603
 
578
604
  .blog-card:hover {
579
605
  border-color: var(--accent-red);
580
- box-shadow: 0 0 40px var(--accent-red-glow);
581
606
  }
582
607
 
583
608
  .blog-card-image {
584
609
  width: 100%;
585
610
  aspect-ratio: 16/9;
586
- background: var(--bg-secondary);
587
- border-bottom: 1px dashed var(--border);
611
+ background: var(--bg);
612
+ border-bottom: 2px solid var(--border);
588
613
  display: flex;
589
614
  align-items: center;
590
615
  justify-content: center;
591
616
  font-size: 3rem;
592
617
  color: var(--text-dim);
593
618
  text-decoration: none;
594
- transition: all 0.3s;
619
+ transition: all 0.2s;
595
620
  }
596
621
 
597
622
  .blog-card-image:hover {
598
- background: var(--bg);
599
- color: var(--text);
623
+ background: var(--accent-red);
624
+ color: #fff;
600
625
  }
601
626
 
602
627
  .blog-card-content {
@@ -610,12 +635,14 @@
610
635
  }
611
636
 
612
637
  .blog-tag {
613
- font-size: 0.65rem;
638
+ font-size: 0.6rem;
614
639
  letter-spacing: 2px;
615
- color: var(--accent-red);
616
- border: 1px dashed var(--accent-red);
617
- padding: 4px 10px;
640
+ color: #fff;
641
+ background: var(--accent-red);
642
+ border: 2px solid var(--accent-red);
643
+ padding: 4px 12px;
618
644
  text-transform: uppercase;
645
+ font-weight: bold;
619
646
  }
620
647
 
621
648
  .blog-date {
@@ -688,15 +715,16 @@
688
715
  }
689
716
  }
690
717
 
691
- /* Footer */
718
+ /* Footer - boxy style */
692
719
  footer {
693
- border-top: 1px dashed var(--border);
720
+ border-top: 2px solid var(--border);
694
721
  padding: 60px 40px;
695
722
  text-align: center;
723
+ background: var(--bg-secondary);
696
724
  }
697
725
 
698
726
  .footer-logo {
699
- font-size: 1.5rem;
727
+ font-size: 1.4rem;
700
728
  font-family: 'Fredoka', 'Bungee', sans-serif;
701
729
  font-weight: 700;
702
730
  letter-spacing: 3px;
@@ -705,7 +733,7 @@
705
733
 
706
734
  .footer-links {
707
735
  display: flex;
708
- gap: 30px;
736
+ gap: 25px;
709
737
  justify-content: center;
710
738
  margin-bottom: 30px;
711
739
  }
@@ -713,23 +741,28 @@
713
741
  .footer-links a {
714
742
  color: var(--text-muted);
715
743
  text-decoration: none;
716
- font-size: 0.85rem;
717
- transition: color 0.3s;
744
+ font-size: 0.8rem;
745
+ letter-spacing: 1px;
746
+ text-transform: uppercase;
747
+ padding: 8px 12px;
748
+ border: 2px solid transparent;
749
+ transition: all 0.2s;
718
750
  }
719
751
 
720
752
  .footer-links a:hover {
721
753
  color: var(--accent-red);
754
+ border-color: var(--accent-red);
722
755
  }
723
756
 
724
757
  .footer-copy {
725
758
  color: var(--text-dim);
726
- font-size: 0.8rem;
759
+ font-size: 0.75rem;
727
760
  }
728
761
 
729
762
  /* Animated Elements */
730
763
  .float-element {
731
764
  position: absolute;
732
- border: 1px dashed var(--border);
765
+ border: 2px solid var(--border);
733
766
  opacity: 0.3;
734
767
  pointer-events: none;
735
768
  }