@hustle-together/api-dev-tools 2.0.7 → 3.1.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 (55) hide show
  1. package/README.md +343 -467
  2. package/bin/cli.js +229 -15
  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 +581 -0
  9. package/demo/audio/generate-narration.js +120 -56
  10. package/demo/audio/generate-voice-previews.js +140 -0
  11. package/demo/audio/narration-adam-timing.json +4675 -0
  12. package/demo/audio/narration-adam.mp3 +0 -0
  13. package/demo/audio/narration-creature-timing.json +4675 -0
  14. package/demo/audio/narration-creature.mp3 +0 -0
  15. package/demo/audio/narration-gaming-timing.json +4675 -0
  16. package/demo/audio/narration-gaming.mp3 +0 -0
  17. package/demo/audio/narration-hope-timing.json +4675 -0
  18. package/demo/audio/narration-hope.mp3 +0 -0
  19. package/demo/audio/narration-mark-timing.json +4675 -0
  20. package/demo/audio/narration-mark.mp3 +0 -0
  21. package/demo/audio/previews/manifest.json +30 -0
  22. package/demo/audio/previews/preview-creature.mp3 +0 -0
  23. package/demo/audio/previews/preview-gaming.mp3 +0 -0
  24. package/demo/audio/previews/preview-hope.mp3 +0 -0
  25. package/demo/audio/previews/preview-mark.mp3 +0 -0
  26. package/demo/audio/voices-manifest.json +50 -0
  27. package/demo/hustle-together/blog/gemini-vs-claude-widgets.html +30 -28
  28. package/demo/hustle-together/blog/interview-driven-api-development.html +37 -23
  29. package/demo/hustle-together/index.html +142 -109
  30. package/demo/workflow-demo.html +2618 -1036
  31. package/hooks/api-workflow-check.py +2 -0
  32. package/hooks/enforce-deep-research.py +180 -0
  33. package/hooks/enforce-disambiguation.py +149 -0
  34. package/hooks/enforce-documentation.py +187 -0
  35. package/hooks/enforce-environment.py +249 -0
  36. package/hooks/enforce-refactor.py +187 -0
  37. package/hooks/enforce-research.py +93 -46
  38. package/hooks/enforce-schema.py +186 -0
  39. package/hooks/enforce-scope.py +156 -0
  40. package/hooks/enforce-tdd-red.py +246 -0
  41. package/hooks/enforce-verify.py +186 -0
  42. package/hooks/periodic-reground.py +154 -0
  43. package/hooks/session-startup.py +151 -0
  44. package/hooks/track-tool-use.py +109 -17
  45. package/hooks/verify-after-green.py +282 -0
  46. package/package.json +3 -2
  47. package/scripts/collect-test-results.ts +404 -0
  48. package/scripts/extract-parameters.ts +483 -0
  49. package/scripts/generate-test-manifest.ts +520 -0
  50. package/templates/CLAUDE-SECTION.md +84 -0
  51. package/templates/api-dev-state.json +83 -8
  52. package/templates/api-test/page.tsx +315 -0
  53. package/templates/api-test/test-structure/route.ts +269 -0
  54. package/templates/research-index.json +6 -0
  55. package/templates/settings.json +59 -0
package/bin/cli.js CHANGED
@@ -65,14 +65,33 @@ function verifyInstallation(claudeDir, hooksDir) {
65
65
  { path: path.join(claudeDir, 'commands'), name: 'Commands directory' },
66
66
  { path: path.join(claudeDir, 'settings.json'), name: 'Settings file' },
67
67
  { path: path.join(claudeDir, 'api-dev-state.json'), name: 'State file' },
68
+ { path: path.join(claudeDir, 'research'), name: 'Research cache directory' },
69
+ { path: path.join(claudeDir, 'research', 'index.json'), name: 'Research index' },
68
70
  ];
69
71
 
70
- // Add hook checks if hooks directory exists
72
+ // Add hook checks if hooks directory exists (v3.0 has 18 hooks for 100% phase enforcement with user checkpoints)
71
73
  if (fs.existsSync(hooksDir)) {
72
74
  checks.push(
73
- { path: path.join(hooksDir, 'enforce-research.py'), name: 'enforce-research.py' },
75
+ // Core utility hooks (5)
76
+ { path: path.join(hooksDir, 'session-startup.py'), name: 'session-startup.py' },
77
+ { path: path.join(hooksDir, 'enforce-external-research.py'), name: 'enforce-external-research.py' },
74
78
  { path: path.join(hooksDir, 'track-tool-use.py'), name: 'track-tool-use.py' },
75
- { path: path.join(hooksDir, 'api-workflow-check.py'), name: 'api-workflow-check.py' }
79
+ { path: path.join(hooksDir, 'periodic-reground.py'), name: 'periodic-reground.py' },
80
+ { path: path.join(hooksDir, 'api-workflow-check.py'), name: 'api-workflow-check.py' },
81
+ // Phase enforcement hooks with user checkpoints (12 - one per phase)
82
+ { path: path.join(hooksDir, 'enforce-disambiguation.py'), name: 'enforce-disambiguation.py' },
83
+ { path: path.join(hooksDir, 'enforce-scope.py'), name: 'enforce-scope.py' },
84
+ { path: path.join(hooksDir, 'enforce-research.py'), name: 'enforce-research.py' },
85
+ { path: path.join(hooksDir, 'enforce-interview.py'), name: 'enforce-interview.py' },
86
+ { path: path.join(hooksDir, 'enforce-deep-research.py'), name: 'enforce-deep-research.py' },
87
+ { path: path.join(hooksDir, 'enforce-schema.py'), name: 'enforce-schema.py' },
88
+ { path: path.join(hooksDir, 'enforce-environment.py'), name: 'enforce-environment.py' },
89
+ { path: path.join(hooksDir, 'enforce-tdd-red.py'), name: 'enforce-tdd-red.py' },
90
+ { path: path.join(hooksDir, 'verify-implementation.py'), name: 'verify-implementation.py' },
91
+ { path: path.join(hooksDir, 'verify-after-green.py'), name: 'verify-after-green.py' },
92
+ { path: path.join(hooksDir, 'enforce-verify.py'), name: 'enforce-verify.py' },
93
+ { path: path.join(hooksDir, 'enforce-refactor.py'), name: 'enforce-refactor.py' },
94
+ { path: path.join(hooksDir, 'enforce-documentation.py'), name: 'enforce-documentation.py' }
76
95
  );
77
96
  }
78
97
 
@@ -233,6 +252,147 @@ function main() {
233
252
  }
234
253
  }
235
254
 
255
+ // ========================================
256
+ // 4b. Install Research Cache Structure (v3.0)
257
+ // ========================================
258
+ const researchDir = path.join(claudeDir, 'research');
259
+ const researchIndexSource = path.join(sourceTemplatesDir, 'research-index.json');
260
+ const researchIndexDest = path.join(researchDir, 'index.json');
261
+
262
+ log('\nšŸ“š Setting up research cache:', 'cyan');
263
+
264
+ if (!fs.existsSync(researchDir)) {
265
+ try {
266
+ fs.mkdirSync(researchDir, { recursive: true });
267
+ log(' āœ… Created .claude/research/ directory', 'green');
268
+ } catch (error) {
269
+ log(` āŒ Failed to create research directory: ${error.message}`, 'red');
270
+ }
271
+ }
272
+
273
+ if (fs.existsSync(researchIndexSource) && !fs.existsSync(researchIndexDest)) {
274
+ try {
275
+ fs.copyFileSync(researchIndexSource, researchIndexDest);
276
+ log(' āœ… Created research/index.json for freshness tracking', 'green');
277
+ } catch (error) {
278
+ log(` āŒ Failed to create research index: ${error.message}`, 'red');
279
+ }
280
+ } else if (fs.existsSync(researchIndexDest)) {
281
+ log(' ā„¹ļø Research index already exists (preserved)', 'blue');
282
+ }
283
+
284
+ // ========================================
285
+ // 4c. Install Test UI (Parser API + Page)
286
+ // ========================================
287
+ log('\n🧪 Setting up Test UI:', 'cyan');
288
+
289
+ const testUiSourceDir = path.join(sourceTemplatesDir, 'api-test');
290
+ const hasNextJs = fs.existsSync(path.join(targetDir, 'next.config.js')) ||
291
+ fs.existsSync(path.join(targetDir, 'next.config.mjs')) ||
292
+ fs.existsSync(path.join(targetDir, 'next.config.ts'));
293
+
294
+ if (!hasNextJs) {
295
+ log(' āš ļø Next.js not detected - skipping Test UI installation', 'yellow');
296
+ log(' šŸ’” Test UI requires Next.js App Router', 'yellow');
297
+ } else if (fs.existsSync(testUiSourceDir)) {
298
+ // Detect App Router structure
299
+ const appDir = fs.existsSync(path.join(targetDir, 'src', 'app'))
300
+ ? path.join(targetDir, 'src', 'app')
301
+ : fs.existsSync(path.join(targetDir, 'app'))
302
+ ? path.join(targetDir, 'app')
303
+ : null;
304
+
305
+ if (!appDir) {
306
+ log(' āš ļø App Router not detected - skipping Test UI installation', 'yellow');
307
+ log(' šŸ’” Test UI requires Next.js App Router (app/ or src/app/)', 'yellow');
308
+ } else {
309
+ // Install test-structure API route
310
+ const apiTestStructureDir = path.join(appDir, 'api', 'test-structure');
311
+ const apiTestStructureSource = path.join(testUiSourceDir, 'test-structure', 'route.ts');
312
+ const apiTestStructureDest = path.join(apiTestStructureDir, 'route.ts');
313
+
314
+ if (!fs.existsSync(apiTestStructureDir)) {
315
+ fs.mkdirSync(apiTestStructureDir, { recursive: true });
316
+ }
317
+
318
+ if (!fs.existsSync(apiTestStructureDest)) {
319
+ try {
320
+ fs.copyFileSync(apiTestStructureSource, apiTestStructureDest);
321
+ log(' āœ… Created /api/test-structure route (parses Vitest files)', 'green');
322
+ } catch (error) {
323
+ log(` āŒ Failed to create test-structure API: ${error.message}`, 'red');
324
+ }
325
+ } else {
326
+ log(' ā„¹ļø /api/test-structure already exists (preserved)', 'blue');
327
+ }
328
+
329
+ // Install test UI page
330
+ const apiTestPageDir = path.join(appDir, 'api-test');
331
+ const apiTestPageSource = path.join(testUiSourceDir, 'page.tsx');
332
+ const apiTestPageDest = path.join(apiTestPageDir, 'page.tsx');
333
+
334
+ if (!fs.existsSync(apiTestPageDir)) {
335
+ fs.mkdirSync(apiTestPageDir, { recursive: true });
336
+ }
337
+
338
+ if (!fs.existsSync(apiTestPageDest)) {
339
+ try {
340
+ fs.copyFileSync(apiTestPageSource, apiTestPageDest);
341
+ log(' āœ… Created /api-test page (displays test structure)', 'green');
342
+ } catch (error) {
343
+ log(` āŒ Failed to create test UI page: ${error.message}`, 'red');
344
+ }
345
+ } else {
346
+ log(' ā„¹ļø /api-test page already exists (preserved)', 'blue');
347
+ }
348
+
349
+ log(' šŸ’” Test UI available at http://localhost:3000/api-test', 'yellow');
350
+ }
351
+ } else {
352
+ log(' āš ļø Test UI templates not found in package', 'yellow');
353
+ }
354
+
355
+ // ========================================
356
+ // 4d. Install Manifest Generation Scripts
357
+ // ========================================
358
+ log('\nšŸ“Š Setting up manifest generation scripts:', 'cyan');
359
+
360
+ const sourceScriptsDir = path.join(packageDir, 'scripts');
361
+ const targetScriptsDir = path.join(targetDir, 'scripts', 'api-dev-tools');
362
+
363
+ if (fs.existsSync(sourceScriptsDir)) {
364
+ if (!fs.existsSync(targetScriptsDir)) {
365
+ fs.mkdirSync(targetScriptsDir, { recursive: true });
366
+ }
367
+
368
+ const scriptFiles = fs.readdirSync(sourceScriptsDir).filter(file =>
369
+ file.endsWith('.ts')
370
+ );
371
+
372
+ if (scriptFiles.length > 0) {
373
+ scriptFiles.forEach(file => {
374
+ const source = path.join(sourceScriptsDir, file);
375
+ const dest = path.join(targetScriptsDir, file);
376
+
377
+ try {
378
+ fs.copyFileSync(source, dest);
379
+ log(` āœ… ${file}`, 'green');
380
+ } catch (error) {
381
+ log(` āŒ Failed to copy ${file}: ${error.message}`, 'red');
382
+ }
383
+ });
384
+
385
+ log('\n Script purposes:', 'blue');
386
+ log(' • generate-test-manifest.ts - Parses tests → manifest (NO LLM)', 'blue');
387
+ log(' • extract-parameters.ts - Extracts Zod params → matrix', 'blue');
388
+ log(' • collect-test-results.ts - Runs Vitest → results JSON', 'blue');
389
+ log('\n šŸ’” Scripts run automatically after tests pass (Phase 8 → 9)', 'yellow');
390
+ log(' šŸ’” Manual: npx tsx scripts/api-dev-tools/generate-test-manifest.ts', 'yellow');
391
+ }
392
+ } else {
393
+ log(' āš ļø Scripts directory not found in package', 'yellow');
394
+ }
395
+
236
396
  // ========================================
237
397
  // 5. Install MCP Servers via CLI (Context7, GitHub)
238
398
  // ========================================
@@ -268,32 +428,86 @@ function main() {
268
428
  log('\n āš ļø GitHub MCP requires GITHUB_PERSONAL_ACCESS_TOKEN in env', 'yellow');
269
429
  log(' šŸ’” Restart Claude Code for MCP tools to be available', 'yellow');
270
430
 
431
+ // ========================================
432
+ // 6. Update CLAUDE.md with workflow documentation
433
+ // ========================================
434
+ const claudeMdSection = path.join(sourceTemplatesDir, 'CLAUDE-SECTION.md');
435
+ const projectClaudeMd = path.join(targetDir, 'CLAUDE.md');
436
+
437
+ if (fs.existsSync(claudeMdSection)) {
438
+ log('\nšŸ“ CLAUDE.md workflow documentation:', 'cyan');
439
+
440
+ const sectionContent = fs.readFileSync(claudeMdSection, 'utf8');
441
+ const sectionMarker = '## API Development Workflow (v3.0)';
442
+
443
+ if (fs.existsSync(projectClaudeMd)) {
444
+ const existingContent = fs.readFileSync(projectClaudeMd, 'utf8');
445
+
446
+ if (existingContent.includes(sectionMarker)) {
447
+ // Update existing section
448
+ const beforeSection = existingContent.split(sectionMarker)[0];
449
+ // Find the next ## heading or end of file
450
+ const afterMatch = existingContent.match(/## API Development Workflow[\s\S]*?((?=\n## )|$)/);
451
+ const afterSection = afterMatch ? existingContent.substring(existingContent.indexOf(afterMatch[0]) + afterMatch[0].length) : '';
452
+
453
+ fs.writeFileSync(projectClaudeMd, beforeSection + sectionContent + afterSection);
454
+ log(' āœ… Updated API Development Workflow section in CLAUDE.md', 'green');
455
+ } else {
456
+ // Append section
457
+ fs.appendFileSync(projectClaudeMd, '\n\n' + sectionContent);
458
+ log(' āœ… Added API Development Workflow section to CLAUDE.md', 'green');
459
+ }
460
+ } else {
461
+ // Create new CLAUDE.md with section
462
+ fs.writeFileSync(projectClaudeMd, '# Project Instructions\n\n' + sectionContent);
463
+ log(' āœ… Created CLAUDE.md with API Development Workflow section', 'green');
464
+ }
465
+ }
466
+
271
467
  // ========================================
272
468
  // Success Summary
273
469
  // ========================================
274
470
  log('\n' + '═'.repeat(60), 'green');
275
- log('šŸŽ‰ API Development Tools installed successfully!', 'green');
471
+ log('šŸŽ‰ API Development Tools v3.0 installed successfully!', 'green');
276
472
  log('═'.repeat(60) + '\n', 'green');
277
473
 
278
474
  log('šŸ“‹ What was installed:', 'bright');
279
475
  log(' Commands: .claude/commands/*.md', 'blue');
280
- log(' Hooks: .claude/hooks/*.py', 'blue');
476
+ log(' Hooks: .claude/hooks/*.py (18 hooks for 100% enforcement + user checkpoints)', 'blue');
281
477
  log(' Settings: .claude/settings.json', 'blue');
282
478
  log(' State: .claude/api-dev-state.json', 'blue');
479
+ log(' Research: .claude/research/ (with freshness tracking)', 'blue');
480
+ log(' Scripts: scripts/api-dev-tools/*.ts (manifest generation)', 'blue');
283
481
  log(' MCP: context7, github (via claude mcp add)', 'blue');
284
-
285
- log('\nšŸ”’ Enforcement Features:', 'bright');
286
- log(' • Research MUST happen before code writing', 'cyan');
287
- log(' • All research activity is logged to state file', 'cyan');
288
- log(' • Workflow completion is verified before stopping', 'cyan');
289
- log(' • Progress is tracked and visible in state file', 'cyan');
482
+ log(' Test UI: /api-test page + /api/test-structure API (if Next.js)', 'blue');
483
+
484
+ log('\nšŸ†• New in v3.0:', 'bright');
485
+ log(' • 12 phases, each with mandatory user checkpoint', 'cyan');
486
+ log(' • AskUserQuestion required at EVERY phase transition', 'cyan');
487
+ log(' • Loop-back support when user wants changes', 'cyan');
488
+ log(' • Adaptive research (propose-approve, not shotgun)', 'cyan');
489
+ log(' • 7-turn re-grounding (prevents context dilution)', 'cyan');
490
+ log(' • Research freshness (7-day cache validity)', 'cyan');
491
+
492
+ log('\nšŸ”’ User Checkpoint Enforcement:', 'bright');
493
+ log(' • Phase 0: "Which interpretation?" (disambiguation)', 'cyan');
494
+ log(' • Phase 1: "Scope correct?" (scope confirmation)', 'cyan');
495
+ log(' • Phase 2: "Proceed to interview?" (research summary)', 'cyan');
496
+ log(' • Phase 3: "Interview complete?" (all questions answered)', 'cyan');
497
+ log(' • Phase 4: "Approve searches?" (deep research proposal)', 'cyan');
498
+ log(' • Phase 5: "Schema matches interview?" (schema review)', 'cyan');
499
+ log(' • Phase 6: "Ready for testing?" (environment check)', 'cyan');
500
+ log(' • Phase 7: "Test plan looks good?" (test matrix)', 'cyan');
501
+ log(' • Phase 9: "Fix gaps?" (verification decision)', 'cyan');
502
+ log(' • Phase 11: "Documentation complete?" (final checklist)', 'cyan');
290
503
 
291
504
  log('\nšŸ“š Available Commands:', 'bright');
292
- log(' /api-create [endpoint] - Complete API development workflow', 'blue');
293
- log(' /api-interview [endpoint] - Structured interview about endpoint', 'blue');
294
- log(' /api-research [library] - Deep research of external APIs/SDKs', 'blue');
505
+ log(' /api-create [endpoint] - Complete 12-phase workflow', 'blue');
506
+ log(' /api-interview [endpoint] - Questions FROM research', 'blue');
507
+ log(' /api-research [library] - Adaptive propose-approve research', 'blue');
508
+ log(' /api-verify [endpoint] - Manual Phase 9 verification', 'blue');
295
509
  log(' /api-env [endpoint] - Check API keys and environment', 'blue');
296
- log(' /api-status [endpoint] - Track implementation progress', 'blue');
510
+ log(' /api-status [endpoint] - Track 12-phase progress', 'blue');
297
511
 
298
512
  log('\nšŸš€ Quick Start:', 'bright');
299
513
  log(' /api-create my-endpoint', 'blue');