@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
@@ -1,21 +1,37 @@
1
- ## Hustle API Development Workflow (v3.7.0)
1
+ ## Hustle API Development Workflow (v4.0.0)
2
2
 
3
- This project uses **@hustle-together/api-dev-tools** for interview-driven, research-first API development.
3
+ This project uses **@hustle-together/api-dev-tools** for interview-driven, research-first development.
4
+
5
+ ### Project Context
6
+
7
+ <!-- INSTALLER: Replace these with actual project values -->
8
+ **Tech Stack:** [Framework] + [Language] + [Database]
9
+ **UI Library:** [UI framework or component library]
10
+ **Testing:** [Test framework] + [E2E framework]
11
+
12
+ ### Existing Elements
13
+
14
+ <!-- AUTO-POPULATED: Updated by registry hooks -->
15
+ **APIs:** (check `.claude/registry.json`)
16
+ **Components:** (check `.claude/registry.json`)
17
+ **Pages:** (check `.claude/registry.json`)
4
18
 
5
19
  ### Available Commands
6
20
 
7
21
  | Command | Purpose |
8
22
  | ---------------------------------- | ------------------------------------- |
9
- | `/hustle-api-create [endpoint]` | Complete 13-phase workflow |
10
- | `/hustle-api-interview [endpoint]` | Questions FROM research findings |
11
- | `/hustle-api-research [library]` | Adaptive propose-approve research |
12
- | `/hustle-api-verify [endpoint]` | Re-research and verify implementation |
13
- | `/hustle-api-env [endpoint]` | Check API keys |
14
- | `/hustle-api-status [endpoint]` | Track progress |
15
- | `/hustle-api-continue [endpoint]` | Resume interrupted workflow |
16
- | `/hustle-api-sessions` | Browse saved session logs |
17
-
18
- ### 13-Phase Flow
23
+ | `/hustle-build [description]` | Orchestrated multi-workflow build |
24
+ | `/api-create [endpoint]` | Complete 14-phase API workflow |
25
+ | `/hustle-ui-create [component]` | Component with Storybook |
26
+ | `/hustle-ui-create-page [page]` | Page with Playwright E2E |
27
+ | `/hustle-combine [name]` | Combine multiple APIs |
28
+ | `/api-research [library]` | Adaptive propose-approve research |
29
+ | `/api-interview [endpoint]` | Questions FROM research findings |
30
+ | `/api-verify [endpoint]` | Re-research and verify implementation |
31
+ | `/api-env [endpoint]` | Check API keys |
32
+ | `/api-status [endpoint]` | Track progress |
33
+
34
+ ### 14-Phase Flow
19
35
 
20
36
  ```
21
37
  Phase 1: DISAMBIGUATION - Clarify ambiguous terms before research
@@ -28,18 +44,20 @@ Phase 7: ENVIRONMENT - Verify API keys exist
28
44
  Phase 8: TDD RED - Write failing tests from schema
29
45
  Phase 9: TDD GREEN - Minimal implementation to pass tests
30
46
  Phase 10: VERIFY - Re-research docs, compare to implementation
31
- Phase 11: TDD REFACTOR - Clean up code while tests pass
32
- Phase 12: DOCUMENTATION - Update manifests, cache research
33
- Phase 13: COMPLETION - Final verification, commit
47
+ Phase 11: CODE REVIEW - AI review (bugs, security, performance)
48
+ Phase 12: TDD REFACTOR - Fix review issues + clean up code
49
+ Phase 13: DOCUMENTATION - Update manifests, cache research
50
+ Phase 14: COMPLETION - Final verification, commit
34
51
  ```
35
52
 
36
53
  ### Key Principles
37
54
 
38
- 1. **Loop Until Green** - Every verification phase loops back if not successful
55
+ 1. **Research-First** - Never write code from memory, always verify docs
39
56
  2. **Questions FROM Research** - Never use generic template questions
40
- 3. **Adaptive Research** - Propose searches based on context, not shotgun
57
+ 3. **Loop Until Green** - Every verification phase loops back if not successful
41
58
  4. **7-Turn Re-grounding** - Context injected every 7 turns to prevent dilution
42
59
  5. **Verify After Green** - Re-research to catch memory-based implementation errors
60
+ 6. **Registry Awareness** - Don't recreate existing elements
43
61
 
44
62
  ### State Tracking
45
63
 
@@ -49,7 +67,17 @@ All progress is tracked in `.claude/api-dev-state.json`:
49
67
  - Interview decisions (injected during implementation)
50
68
  - Research sources with freshness tracking
51
69
  - Turn count for re-grounding
52
- - Multi-API support with active endpoint pointer
70
+ - Deferred features list
71
+ - Test run history
72
+
73
+ ### Registry
74
+
75
+ `.claude/registry.json` tracks all created elements:
76
+
77
+ - APIs with endpoints, schemas, and examples
78
+ - Components with props and variants
79
+ - Pages with routes and data requirements
80
+ - Combined APIs with orchestration patterns
53
81
 
54
82
  ### Research Cache
55
83
 
@@ -59,61 +87,58 @@ Research is cached in `.claude/research/` with 7-day freshness:
59
87
  - `[api-name]/CURRENT.md` - Latest research
60
88
  - `[api-name]/sources.json` - Research sources
61
89
  - `[api-name]/interview.json` - Interview decisions
62
- - `[api-name]/schema.json` - Schema snapshot
63
90
  - Stale research (>7 days) triggers re-research prompt
64
91
 
65
- ### Hooks (25 Total - Automatic Enforcement)
66
-
67
- | Hook | Event | Action |
68
- | ---------------------------------- | ---------------- | ------------------------------------ |
69
- | `session-startup.py` | SessionStart | Inject state context |
70
- | `detect-interruption.py` | SessionStart | Detect interrupted workflows |
71
- | `enforce-external-research.py` | UserPromptSubmit | Require research first |
72
- | `enforce-disambiguation.py` | PreToolUse | Phase 1 enforcement |
73
- | `enforce-scope.py` | PreToolUse | Phase 2 enforcement |
74
- | `enforce-research.py` | PreToolUse | Phase 3 enforcement |
75
- | `enforce-interview.py` | PreToolUse | Phase 4 - inject decisions |
76
- | `enforce-deep-research.py` | PreToolUse | Phase 5 enforcement |
77
- | `enforce-schema.py` | PreToolUse | Phase 6 enforcement |
78
- | `enforce-environment.py` | PreToolUse | Phase 7 enforcement |
79
- | `enforce-tdd-red.py` | PreToolUse | Phase 8 enforcement |
80
- | `verify-implementation.py` | PreToolUse | Phase 9 helper |
81
- | `enforce-verify.py` | PreToolUse | Phase 10 enforcement |
82
- | `enforce-refactor.py` | PreToolUse | Phase 11 enforcement |
83
- | `enforce-documentation.py` | PreToolUse | Phase 12 enforcement |
84
- | `enforce-questions-sourced.py` | PreToolUse | Validate questions from research |
85
- | `enforce-schema-from-interview.py` | PreToolUse | Validate schema from interview |
86
- | `track-tool-use.py` | PostToolUse | Log research, count turns |
87
- | `periodic-reground.py` | PostToolUse | Re-inject context every 7 turns |
88
- | `track-scope-coverage.py` | PostToolUse | Track implemented vs deferred |
89
- | `verify-after-green.py` | PostToolUse | Trigger Phase 10 after tests pass |
90
- | `cache-research.py` | PostToolUse | Create research cache files |
91
- | `generate-manifest-entry.py` | PostToolUse | Auto-generate API documentation |
92
- | `api-workflow-check.py` | Stop | Block if incomplete, generate output |
93
- | `session-logger.py` | Stop | Save session to api-sessions |
94
-
95
- ### Auto-Generated Documentation
96
-
97
- When Phase 12 completes, `generate-manifest-entry.py` automatically creates:
98
-
99
- - **Comprehensive curl examples** (minimal, full, auth, enum variations, boundary values)
100
- - **Complete test cases** (success, validation, required fields, types, boundaries, arrays)
101
- - **Parameter documentation** with all possible values
102
- - **Ready-to-use entries** for `api-tests-manifest.json`
92
+ ### Re-grounding System
93
+
94
+ Every 7 turns, the system injects a reminder with:
95
+
96
+ - Current endpoint and phase progress
97
+ - Key interview decisions
98
+ - Existing registry elements (don't recreate)
99
+ - Deferred features (don't re-suggest)
100
+ - Last test status (GREEN/RED)
101
+ - Brand guide status
102
+ - Research freshness warnings
103
+ - Orchestrator progress (if in /hustle-build)
104
+
105
+ See: [docs/REGROUNDING.md](./docs/REGROUNDING.md)
106
+
107
+ ### Brand Guide
108
+
109
+ If `.claude/BRAND_GUIDE.md` exists:
110
+
111
+ - All UI components use brand colors/fonts
112
+ - Enforce hook checks before component creation
113
+ - Re-grounding reminds about brand guide
114
+
115
+ ### Hooks (45+ Automatic Enforcement)
116
+
117
+ | Category | Hooks | Purpose |
118
+ | -------- | ----- | ------- |
119
+ | SessionStart | 4 | Inject state, detect interruptions, check updates |
120
+ | UserPromptSubmit | 1 | Require research before API questions |
121
+ | PreToolUse | 22 | Phase enforcement, schema validation |
122
+ | PostToolUse | 12 | Tracking, re-grounding, registry updates |
123
+ | Stop | 2 | Workflow completion, session logging |
103
124
 
104
125
  ### Usage
105
126
 
106
127
  ```bash
107
- # Full automated workflow
108
- /hustle-api-create my-endpoint
128
+ # Orchestrated build (recommended for features)
129
+ /hustle-build dashboard with user stats and activity charts
109
130
 
110
- # Manual step-by-step
111
- /hustle-api-research [library]
112
- /hustle-api-interview [endpoint]
113
- /hustle-api-env [endpoint]
131
+ # Individual workflows
132
+ /api-create stripe-checkout
133
+ /hustle-ui-create StatCard
134
+ /hustle-ui-create-page Dashboard
135
+
136
+ # TDD cycle
114
137
  /red
115
138
  /green
116
- /hustle-api-verify [endpoint]
117
139
  /refactor
140
+
141
+ # Git
118
142
  /commit
143
+ /pr
119
144
  ```
@@ -0,0 +1,326 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+
5
+ interface ADR {
6
+ number: number;
7
+ title: string;
8
+ status: 'proposed' | 'accepted' | 'deprecated' | 'superseded';
9
+ date: string;
10
+ phase: 'initial_research' | 'interview' | 'deep_research';
11
+ endpoint: string;
12
+ file: string;
13
+ supersededBy?: number;
14
+ }
15
+
16
+ interface ADRIndex {
17
+ adrs: ADR[];
18
+ }
19
+
20
+ const statusColors: Record<ADR['status'], string> = {
21
+ proposed: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200',
22
+ accepted: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200',
23
+ deprecated: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200',
24
+ superseded: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-200',
25
+ };
26
+
27
+ const phaseLabels: Record<ADR['phase'], string> = {
28
+ initial_research: 'Initial Research',
29
+ interview: 'Interview',
30
+ deep_research: 'Deep Research',
31
+ };
32
+
33
+ function StatusBadge({ status }: { status: ADR['status'] }) {
34
+ return (
35
+ <span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${statusColors[status]}`}>
36
+ {status.charAt(0).toUpperCase() + status.slice(1)}
37
+ </span>
38
+ );
39
+ }
40
+
41
+ function PhaseBadge({ phase }: { phase: ADR['phase'] }) {
42
+ const phaseColors: Record<ADR['phase'], string> = {
43
+ initial_research: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200',
44
+ interview: 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200',
45
+ deep_research: 'bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-200',
46
+ };
47
+
48
+ return (
49
+ <span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${phaseColors[phase]}`}>
50
+ {phaseLabels[phase]}
51
+ </span>
52
+ );
53
+ }
54
+
55
+ function ADRCard({ adr, onClick }: { adr: ADR; onClick: () => void }) {
56
+ return (
57
+ <div
58
+ onClick={onClick}
59
+ className="p-4 border rounded-lg cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
60
+ >
61
+ <div className="flex items-start justify-between">
62
+ <div>
63
+ <div className="flex items-center gap-2 mb-1">
64
+ <span className="text-sm font-mono text-gray-500">
65
+ ADR-{adr.number.toString().padStart(4, '0')}
66
+ </span>
67
+ <StatusBadge status={adr.status} />
68
+ </div>
69
+ <h3 className="text-lg font-semibold">{adr.title}</h3>
70
+ </div>
71
+ <span className="text-sm text-gray-500">{adr.date}</span>
72
+ </div>
73
+
74
+ <div className="mt-2 flex items-center gap-2">
75
+ <PhaseBadge phase={adr.phase} />
76
+ <span className="text-sm text-gray-500">→</span>
77
+ <span className="text-sm font-medium text-blue-600 dark:text-blue-400">
78
+ {adr.endpoint}
79
+ </span>
80
+ </div>
81
+
82
+ {adr.supersededBy && (
83
+ <div className="mt-2 text-sm text-gray-500">
84
+ Superseded by ADR-{adr.supersededBy.toString().padStart(4, '0')}
85
+ </div>
86
+ )}
87
+ </div>
88
+ );
89
+ }
90
+
91
+ function ADRDetail({ adr, content, onBack }: { adr: ADR; content: string; onBack: () => void }) {
92
+ return (
93
+ <div>
94
+ <button
95
+ onClick={onBack}
96
+ className="mb-4 flex items-center gap-1 text-sm text-gray-500 hover:text-gray-700 dark:hover:text-gray-300"
97
+ >
98
+ <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
99
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
100
+ </svg>
101
+ Back to list
102
+ </button>
103
+
104
+ <div className="flex items-center gap-4 mb-4">
105
+ <span className="text-lg font-mono text-gray-500">
106
+ ADR-{adr.number.toString().padStart(4, '0')}
107
+ </span>
108
+ <StatusBadge status={adr.status} />
109
+ <PhaseBadge phase={adr.phase} />
110
+ </div>
111
+
112
+ <h1 className="text-2xl font-bold mb-2">{adr.title}</h1>
113
+
114
+ <div className="text-sm text-gray-500 mb-6">
115
+ {adr.date} • {adr.endpoint}
116
+ </div>
117
+
118
+ <div
119
+ className="prose dark:prose-invert max-w-none"
120
+ dangerouslySetInnerHTML={{ __html: content }}
121
+ />
122
+ </div>
123
+ );
124
+ }
125
+
126
+ function EmptyState() {
127
+ return (
128
+ <div className="text-center py-12">
129
+ <svg className="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
130
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
131
+ </svg>
132
+ <h3 className="mt-2 text-sm font-medium text-gray-900 dark:text-gray-100">No ADRs yet</h3>
133
+ <p className="mt-1 text-sm text-gray-500">
134
+ ADRs are created during Interview and Deep Research phases.
135
+ </p>
136
+ <p className="mt-2 text-xs text-gray-400">
137
+ Run <code className="bg-gray-100 dark:bg-gray-800 px-1 rounded">/api-create</code> to generate your first ADR.
138
+ </p>
139
+ </div>
140
+ );
141
+ }
142
+
143
+ function FilterBar({
144
+ statusFilter,
145
+ setStatusFilter,
146
+ phaseFilter,
147
+ setPhaseFilter,
148
+ searchQuery,
149
+ setSearchQuery,
150
+ }: {
151
+ statusFilter: ADR['status'] | 'all';
152
+ setStatusFilter: (v: ADR['status'] | 'all') => void;
153
+ phaseFilter: ADR['phase'] | 'all';
154
+ setPhaseFilter: (v: ADR['phase'] | 'all') => void;
155
+ searchQuery: string;
156
+ setSearchQuery: (v: string) => void;
157
+ }) {
158
+ return (
159
+ <div className="flex flex-wrap gap-4 mb-6">
160
+ <input
161
+ type="text"
162
+ placeholder="Search ADRs..."
163
+ value={searchQuery}
164
+ onChange={(e) => setSearchQuery(e.target.value)}
165
+ className="flex-1 min-w-[200px] px-3 py-2 border rounded-lg bg-white dark:bg-gray-800 focus:ring-2 focus:ring-blue-500 outline-none"
166
+ />
167
+
168
+ <select
169
+ value={statusFilter}
170
+ onChange={(e) => setStatusFilter(e.target.value as ADR['status'] | 'all')}
171
+ className="px-3 py-2 border rounded-lg bg-white dark:bg-gray-800"
172
+ >
173
+ <option value="all">All Statuses</option>
174
+ <option value="proposed">Proposed</option>
175
+ <option value="accepted">Accepted</option>
176
+ <option value="deprecated">Deprecated</option>
177
+ <option value="superseded">Superseded</option>
178
+ </select>
179
+
180
+ <select
181
+ value={phaseFilter}
182
+ onChange={(e) => setPhaseFilter(e.target.value as ADR['phase'] | 'all')}
183
+ className="px-3 py-2 border rounded-lg bg-white dark:bg-gray-800"
184
+ >
185
+ <option value="all">All Phases</option>
186
+ <option value="initial_research">Initial Research</option>
187
+ <option value="interview">Interview</option>
188
+ <option value="deep_research">Deep Research</option>
189
+ </select>
190
+ </div>
191
+ );
192
+ }
193
+
194
+ export default function ADRViewer() {
195
+ const [adrs, setAdrs] = useState<ADR[]>([]);
196
+ const [selectedAdr, setSelectedAdr] = useState<ADR | null>(null);
197
+ const [adrContent, setAdrContent] = useState<string>('');
198
+ const [loading, setLoading] = useState(true);
199
+ const [statusFilter, setStatusFilter] = useState<ADR['status'] | 'all'>('all');
200
+ const [phaseFilter, setPhaseFilter] = useState<ADR['phase'] | 'all'>('all');
201
+ const [searchQuery, setSearchQuery] = useState('');
202
+
203
+ useEffect(() => {
204
+ // In production, fetch from .claude/adrs/index.json
205
+ // For now, use mock data or empty state
206
+ const fetchADRs = async () => {
207
+ try {
208
+ const res = await fetch('/.claude/adrs/index.json');
209
+ if (res.ok) {
210
+ const data: ADRIndex = await res.json();
211
+ setAdrs(data.adrs);
212
+ }
213
+ } catch {
214
+ // No ADRs yet - show empty state
215
+ setAdrs([]);
216
+ } finally {
217
+ setLoading(false);
218
+ }
219
+ };
220
+
221
+ fetchADRs();
222
+ }, []);
223
+
224
+ const handleSelectAdr = async (adr: ADR) => {
225
+ setSelectedAdr(adr);
226
+ try {
227
+ const res = await fetch(`/.claude/adrs/${adr.file}`);
228
+ if (res.ok) {
229
+ const text = await res.text();
230
+ // Basic markdown to HTML (in production, use a proper markdown parser)
231
+ const html = text
232
+ .replace(/^### (.+)$/gm, '<h3>$1</h3>')
233
+ .replace(/^## (.+)$/gm, '<h2>$1</h2>')
234
+ .replace(/^# (.+)$/gm, '<h1>$1</h1>')
235
+ .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
236
+ .replace(/\n\n/g, '</p><p>')
237
+ .replace(/^- (.+)$/gm, '<li>$1</li>');
238
+ setAdrContent(`<p>${html}</p>`);
239
+ }
240
+ } catch {
241
+ setAdrContent('<p>Failed to load ADR content.</p>');
242
+ }
243
+ };
244
+
245
+ const filteredAdrs = adrs.filter((adr) => {
246
+ if (statusFilter !== 'all' && adr.status !== statusFilter) return false;
247
+ if (phaseFilter !== 'all' && adr.phase !== phaseFilter) return false;
248
+ if (searchQuery) {
249
+ const query = searchQuery.toLowerCase();
250
+ return (
251
+ adr.title.toLowerCase().includes(query) ||
252
+ adr.endpoint.toLowerCase().includes(query) ||
253
+ `adr-${adr.number}`.includes(query)
254
+ );
255
+ }
256
+ return true;
257
+ });
258
+
259
+ if (loading) {
260
+ return (
261
+ <div className="flex items-center justify-center py-12">
262
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600" />
263
+ </div>
264
+ );
265
+ }
266
+
267
+ if (selectedAdr) {
268
+ return (
269
+ <ADRDetail
270
+ adr={selectedAdr}
271
+ content={adrContent}
272
+ onBack={() => setSelectedAdr(null)}
273
+ />
274
+ );
275
+ }
276
+
277
+ return (
278
+ <div>
279
+ <div className="mb-6">
280
+ <h1 className="text-2xl font-bold">Architecture Decision Records</h1>
281
+ <p className="text-gray-500 mt-1">
282
+ Significant decisions made during research and interview phases
283
+ </p>
284
+ </div>
285
+
286
+ {adrs.length > 0 && (
287
+ <FilterBar
288
+ statusFilter={statusFilter}
289
+ setStatusFilter={setStatusFilter}
290
+ phaseFilter={phaseFilter}
291
+ setPhaseFilter={setPhaseFilter}
292
+ searchQuery={searchQuery}
293
+ setSearchQuery={setSearchQuery}
294
+ />
295
+ )}
296
+
297
+ {filteredAdrs.length === 0 ? (
298
+ adrs.length === 0 ? (
299
+ <EmptyState />
300
+ ) : (
301
+ <div className="text-center py-8 text-gray-500">
302
+ No ADRs match your filters
303
+ </div>
304
+ )
305
+ ) : (
306
+ <div className="space-y-4">
307
+ {filteredAdrs.map((adr) => (
308
+ <ADRCard key={adr.number} adr={adr} onClick={() => handleSelectAdr(adr)} />
309
+ ))}
310
+ </div>
311
+ )}
312
+
313
+ <div className="mt-8 p-4 bg-gray-50 dark:bg-gray-800 rounded-lg">
314
+ <h3 className="font-medium mb-2">About ADRs</h3>
315
+ <p className="text-sm text-gray-600 dark:text-gray-400">
316
+ Architecture Decision Records capture significant decisions made during the development workflow.
317
+ They are created automatically during Interview (Phase 4) and Deep Research (Phase 5)
318
+ when you make choices about authentication, error handling, caching, and other architectural concerns.
319
+ </p>
320
+ <p className="text-sm text-gray-500 mt-2">
321
+ See <code className="bg-gray-200 dark:bg-gray-700 px-1 rounded">docs/ARCHITECTURE_DECISION_RECORDS.md</code> for details.
322
+ </p>
323
+ </div>
324
+ </div>
325
+ );
326
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.10.0",
2
+ "version": "3.11.0",
3
3
  "created_at": null,
4
4
  "workflow": null,
5
5
  "_workflow_options": [
@@ -12,6 +12,38 @@
12
12
  "active_element": null,
13
13
  "endpoints": {},
14
14
  "elements": {},
15
+
16
+ "session_archives": {
17
+ "_description": "Completed workflow sessions archived for reference and learning",
18
+ "_archive_policy": "Sessions archived on workflow completion or manual archival",
19
+ "completed": [],
20
+ "interrupted": [],
21
+ "_archive_template": {
22
+ "id": "uuid",
23
+ "workflow": "api-create",
24
+ "element_name": "stripe-subscriptions",
25
+ "status": "completed",
26
+ "started_at": "2025-12-29T10:00:00Z",
27
+ "completed_at": "2025-12-29T14:30:00Z",
28
+ "duration_minutes": 270,
29
+ "phases_completed": 14,
30
+ "total_turns": 45,
31
+ "research_sources_count": 8,
32
+ "interview_decisions_count": 5,
33
+ "files_created": ["src/app/api/stripe/route.ts", "src/lib/stripe.ts"],
34
+ "files_modified": ["registry.json"],
35
+ "test_coverage": 92,
36
+ "learnings": ["stripe webhooks require idempotency keys", "always validate signature first"],
37
+ "archived_at": "2025-12-29T14:31:00Z",
38
+ "archive_reason": "workflow_completed"
39
+ },
40
+ "_learnings_aggregated": {
41
+ "_description": "Patterns learned across all archived sessions - used for re-grounding",
42
+ "common_pitfalls": [],
43
+ "successful_patterns": [],
44
+ "service_specific": {}
45
+ }
46
+ },
15
47
  "combine_config": {
16
48
  "_comment": "Configuration for combine-api workflow",
17
49
  "mode": null,