rax-flow 0.1.8 → 0.2.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 (224) hide show
  1. package/dist/bin.js +8 -6
  2. package/dist/bin.js.map +1 -1
  3. package/dist/hub/commands/index.d.ts.map +1 -1
  4. package/dist/hub/commands/index.js +7 -4
  5. package/dist/hub/commands/index.js.map +1 -1
  6. package/dist/hub/event-listener.d.ts +6 -0
  7. package/dist/hub/event-listener.d.ts.map +1 -1
  8. package/dist/hub/event-listener.js +10 -6
  9. package/dist/hub/event-listener.js.map +1 -1
  10. package/dist/hub/index.d.ts.map +1 -1
  11. package/dist/hub/index.js +12 -0
  12. package/dist/hub/index.js.map +1 -1
  13. package/dist/setup/components/ApiKeyInput.d.ts +25 -0
  14. package/dist/setup/components/ApiKeyInput.d.ts.map +1 -0
  15. package/dist/setup/components/ApiKeyInput.js +54 -0
  16. package/dist/setup/components/ApiKeyInput.js.map +1 -0
  17. package/dist/setup/components/AsciiBanner.d.ts +22 -0
  18. package/dist/setup/components/AsciiBanner.d.ts.map +1 -0
  19. package/dist/setup/components/AsciiBanner.js +55 -0
  20. package/dist/setup/components/AsciiBanner.js.map +1 -0
  21. package/dist/setup/components/CliDetector.d.ts +17 -0
  22. package/dist/setup/components/CliDetector.d.ts.map +1 -0
  23. package/dist/setup/components/CliDetector.js +79 -0
  24. package/dist/setup/components/CliDetector.js.map +1 -0
  25. package/dist/setup/components/ModeSelector.d.ts +8 -0
  26. package/dist/setup/components/ModeSelector.d.ts.map +1 -0
  27. package/dist/setup/components/ModeSelector.js +76 -0
  28. package/dist/setup/components/ModeSelector.js.map +1 -0
  29. package/dist/setup/components/ProviderSelector.d.ts +18 -0
  30. package/dist/setup/components/ProviderSelector.d.ts.map +1 -0
  31. package/dist/setup/components/ProviderSelector.js +97 -0
  32. package/dist/setup/components/ProviderSelector.js.map +1 -0
  33. package/dist/setup/components/SetupWizard.d.ts +2 -0
  34. package/dist/setup/components/SetupWizard.d.ts.map +1 -0
  35. package/dist/setup/components/SetupWizard.js +212 -0
  36. package/dist/setup/components/SetupWizard.js.map +1 -0
  37. package/dist/setup/components/StepIndicator.d.ts +13 -0
  38. package/dist/setup/components/StepIndicator.d.ts.map +1 -0
  39. package/dist/setup/components/StepIndicator.js +18 -0
  40. package/dist/setup/components/StepIndicator.js.map +1 -0
  41. package/dist/setup/components/SuccessScreen.d.ts +18 -0
  42. package/dist/setup/components/SuccessScreen.d.ts.map +1 -0
  43. package/dist/setup/components/SuccessScreen.js +38 -0
  44. package/dist/setup/components/SuccessScreen.js.map +1 -0
  45. package/dist/setup/index.d.ts +12 -0
  46. package/dist/setup/index.d.ts.map +1 -0
  47. package/dist/setup/index.js +29 -0
  48. package/dist/setup/index.js.map +1 -0
  49. package/dist/setup/utils/cli-detection.d.ts +12 -0
  50. package/dist/setup/utils/cli-detection.d.ts.map +1 -0
  51. package/dist/setup/utils/cli-detection.js +83 -0
  52. package/dist/setup/utils/cli-detection.js.map +1 -0
  53. package/dist/setup/utils/config-writer.d.ts +43 -0
  54. package/dist/setup/utils/config-writer.d.ts.map +1 -0
  55. package/dist/setup/utils/config-writer.js +180 -0
  56. package/dist/setup/utils/config-writer.js.map +1 -0
  57. package/dist/tui/App.d.ts +2 -1
  58. package/dist/tui/App.d.ts.map +1 -1
  59. package/dist/tui/App.js +88 -20
  60. package/dist/tui/App.js.map +1 -1
  61. package/dist/tui/components/AgentStateIcon.d.ts +18 -0
  62. package/dist/tui/components/AgentStateIcon.d.ts.map +1 -0
  63. package/dist/tui/components/AgentStateIcon.js +57 -0
  64. package/dist/tui/components/AgentStateIcon.js.map +1 -0
  65. package/dist/tui/components/AnimatedBranch.d.ts +39 -0
  66. package/dist/tui/components/AnimatedBranch.d.ts.map +1 -0
  67. package/dist/tui/components/AnimatedBranch.js +64 -0
  68. package/dist/tui/components/AnimatedBranch.js.map +1 -0
  69. package/dist/tui/components/ChatPanel.d.ts +2 -1
  70. package/dist/tui/components/ChatPanel.d.ts.map +1 -1
  71. package/dist/tui/components/ChatPanel.js +47 -28
  72. package/dist/tui/components/ChatPanel.js.map +1 -1
  73. package/dist/tui/components/DAGPanel.d.ts +14 -2
  74. package/dist/tui/components/DAGPanel.d.ts.map +1 -1
  75. package/dist/tui/components/DAGPanel.js +48 -27
  76. package/dist/tui/components/DAGPanel.js.map +1 -1
  77. package/dist/tui/components/ExecutionTimeline.d.ts +34 -0
  78. package/dist/tui/components/ExecutionTimeline.d.ts.map +1 -0
  79. package/dist/tui/components/ExecutionTimeline.js +67 -0
  80. package/dist/tui/components/ExecutionTimeline.js.map +1 -0
  81. package/dist/tui/components/Header.d.ts +2 -1
  82. package/dist/tui/components/Header.d.ts.map +1 -1
  83. package/dist/tui/components/Header.js +26 -19
  84. package/dist/tui/components/Header.js.map +1 -1
  85. package/dist/tui/components/HelpOverlay.d.ts +2 -1
  86. package/dist/tui/components/HelpOverlay.d.ts.map +1 -1
  87. package/dist/tui/components/HelpOverlay.js +59 -41
  88. package/dist/tui/components/HelpOverlay.js.map +1 -1
  89. package/dist/tui/components/InputBar.d.ts +3 -1
  90. package/dist/tui/components/InputBar.d.ts.map +1 -1
  91. package/dist/tui/components/InputBar.js +12 -7
  92. package/dist/tui/components/InputBar.js.map +1 -1
  93. package/dist/tui/components/LogsPanel.d.ts +9 -0
  94. package/dist/tui/components/LogsPanel.d.ts.map +1 -0
  95. package/dist/tui/components/LogsPanel.js +56 -0
  96. package/dist/tui/components/LogsPanel.js.map +1 -0
  97. package/dist/tui/components/MemoryPanel.d.ts +21 -0
  98. package/dist/tui/components/MemoryPanel.d.ts.map +1 -0
  99. package/dist/tui/components/MemoryPanel.js +51 -0
  100. package/dist/tui/components/MemoryPanel.js.map +1 -0
  101. package/dist/tui/components/MetricsPanel.d.ts +18 -0
  102. package/dist/tui/components/MetricsPanel.d.ts.map +1 -0
  103. package/dist/tui/components/MetricsPanel.js +27 -0
  104. package/dist/tui/components/MetricsPanel.js.map +1 -0
  105. package/dist/tui/components/StatusPanel.d.ts +3 -1
  106. package/dist/tui/components/StatusPanel.d.ts.map +1 -1
  107. package/dist/tui/components/StatusPanel.js +20 -18
  108. package/dist/tui/components/StatusPanel.js.map +1 -1
  109. package/dist/tui/components/TaskTree.d.ts +28 -0
  110. package/dist/tui/components/TaskTree.d.ts.map +1 -0
  111. package/dist/tui/components/TaskTree.js +29 -0
  112. package/dist/tui/components/TaskTree.js.map +1 -0
  113. package/dist/tui/components/animations/ProgressBar.d.ts +39 -0
  114. package/dist/tui/components/animations/ProgressBar.d.ts.map +1 -0
  115. package/dist/tui/components/animations/ProgressBar.js +39 -0
  116. package/dist/tui/components/animations/ProgressBar.js.map +1 -0
  117. package/dist/tui/components/animations/Pulse.d.ts +17 -0
  118. package/dist/tui/components/animations/Pulse.d.ts.map +1 -0
  119. package/dist/tui/components/animations/Pulse.js +47 -0
  120. package/dist/tui/components/animations/Pulse.js.map +1 -0
  121. package/dist/tui/components/animations/Spinner.d.ts +13 -0
  122. package/dist/tui/components/animations/Spinner.d.ts.map +1 -0
  123. package/dist/tui/components/animations/Spinner.js +36 -0
  124. package/dist/tui/components/animations/Spinner.js.map +1 -0
  125. package/dist/tui/components/animations/StatusAnimator.d.ts +27 -0
  126. package/dist/tui/components/animations/StatusAnimator.d.ts.map +1 -0
  127. package/dist/tui/components/animations/StatusAnimator.js +85 -0
  128. package/dist/tui/components/animations/StatusAnimator.js.map +1 -0
  129. package/dist/tui/components/animations/TypingEffect.d.ts +26 -0
  130. package/dist/tui/components/animations/TypingEffect.d.ts.map +1 -0
  131. package/dist/tui/components/animations/TypingEffect.js +59 -0
  132. package/dist/tui/components/animations/TypingEffect.js.map +1 -0
  133. package/dist/tui/components/animations/index.d.ts +8 -0
  134. package/dist/tui/components/animations/index.d.ts.map +1 -0
  135. package/dist/tui/components/animations/index.js +6 -0
  136. package/dist/tui/components/animations/index.js.map +1 -0
  137. package/dist/tui/hooks/useAnimation.d.ts +42 -0
  138. package/dist/tui/hooks/useAnimation.d.ts.map +1 -0
  139. package/dist/tui/hooks/useAnimation.js +212 -0
  140. package/dist/tui/hooks/useAnimation.js.map +1 -0
  141. package/dist/tui/hooks/useAppState.d.ts +10 -0
  142. package/dist/tui/hooks/useAppState.d.ts.map +1 -1
  143. package/dist/tui/hooks/useAppState.js +178 -75
  144. package/dist/tui/hooks/useAppState.js.map +1 -1
  145. package/dist/tui/services/orchestrator.d.ts +16 -0
  146. package/dist/tui/services/orchestrator.d.ts.map +1 -0
  147. package/dist/tui/services/orchestrator.js +152 -0
  148. package/dist/tui/services/orchestrator.js.map +1 -0
  149. package/dist/tui/styles/borders.d.ts +31 -0
  150. package/dist/tui/styles/borders.d.ts.map +1 -0
  151. package/dist/tui/styles/borders.js +47 -0
  152. package/dist/tui/styles/borders.js.map +1 -0
  153. package/dist/tui/styles/colors.d.ts +18 -0
  154. package/dist/tui/styles/colors.d.ts.map +1 -0
  155. package/dist/tui/styles/colors.js +18 -0
  156. package/dist/tui/styles/colors.js.map +1 -0
  157. package/dist/tui/styles/index.d.ts +6 -0
  158. package/dist/tui/styles/index.d.ts.map +1 -0
  159. package/dist/tui/styles/index.js +6 -0
  160. package/dist/tui/styles/index.js.map +1 -0
  161. package/dist/tui/styles/indicators.d.ts +67 -0
  162. package/dist/tui/styles/indicators.d.ts.map +1 -0
  163. package/dist/tui/styles/indicators.js +42 -0
  164. package/dist/tui/styles/indicators.js.map +1 -0
  165. package/dist/tui/styles/layout.d.ts +21 -0
  166. package/dist/tui/styles/layout.d.ts.map +1 -0
  167. package/dist/tui/styles/layout.js +42 -0
  168. package/dist/tui/styles/layout.js.map +1 -0
  169. package/dist/tui/styles/providers.d.ts +77 -0
  170. package/dist/tui/styles/providers.d.ts.map +1 -0
  171. package/dist/tui/styles/providers.js +31 -0
  172. package/dist/tui/styles/providers.js.map +1 -0
  173. package/dist/tui/utils/animation.d.ts +44 -0
  174. package/dist/tui/utils/animation.d.ts.map +1 -0
  175. package/dist/tui/utils/animation.js +107 -0
  176. package/dist/tui/utils/animation.js.map +1 -0
  177. package/package.json +8 -8
  178. package/src/bin.ts +8 -5
  179. package/src/hub/commands/index.ts +7 -4
  180. package/src/hub/event-listener.ts +14 -10
  181. package/src/hub/index.ts +14 -2
  182. package/src/setup/components/ApiKeyInput.tsx +158 -0
  183. package/src/setup/components/AsciiBanner.tsx +125 -0
  184. package/src/setup/components/CliDetector.tsx +230 -0
  185. package/src/setup/components/ModeSelector.tsx +137 -0
  186. package/src/setup/components/ProviderSelector.tsx +174 -0
  187. package/src/setup/components/SetupWizard.tsx +368 -0
  188. package/src/setup/components/StepIndicator.tsx +74 -0
  189. package/src/setup/components/SuccessScreen.tsx +229 -0
  190. package/src/setup/index.ts +34 -0
  191. package/src/setup/utils/cli-detection.ts +99 -0
  192. package/src/setup/utils/config-writer.ts +249 -0
  193. package/src/tui/App.tsx +117 -53
  194. package/src/tui/components/AgentStateIcon.tsx +84 -0
  195. package/src/tui/components/AnimatedBranch.tsx +134 -0
  196. package/src/tui/components/ChatPanel.tsx +85 -43
  197. package/src/tui/components/DAGPanel.tsx +150 -58
  198. package/src/tui/components/ExecutionTimeline.tsx +225 -0
  199. package/src/tui/components/Header.tsx +76 -43
  200. package/src/tui/components/HelpOverlay.tsx +118 -61
  201. package/src/tui/components/InputBar.tsx +33 -19
  202. package/src/tui/components/LogsPanel.tsx +129 -0
  203. package/src/tui/components/MemoryPanel.tsx +163 -0
  204. package/src/tui/components/MetricsPanel.tsx +149 -0
  205. package/src/tui/components/StatusPanel.tsx +84 -37
  206. package/src/tui/components/TaskTree.tsx +159 -0
  207. package/src/tui/components/animations/ProgressBar.tsx +160 -0
  208. package/src/tui/components/animations/Pulse.tsx +73 -0
  209. package/src/tui/components/animations/Spinner.tsx +54 -0
  210. package/src/tui/components/animations/StatusAnimator.tsx +153 -0
  211. package/src/tui/components/animations/TypingEffect.tsx +119 -0
  212. package/src/tui/components/animations/index.ts +16 -0
  213. package/src/tui/hooks/useAnimation.ts +290 -0
  214. package/src/tui/hooks/useAppState.ts +206 -67
  215. package/src/tui/services/orchestrator.ts +195 -0
  216. package/src/tui/styles/borders.ts +51 -0
  217. package/src/tui/styles/colors.ts +19 -0
  218. package/src/tui/styles/index.ts +20 -0
  219. package/src/tui/styles/indicators.ts +54 -0
  220. package/src/tui/styles/layout.ts +44 -0
  221. package/src/tui/styles/providers.ts +32 -0
  222. package/src/tui/utils/animation.ts +124 -0
  223. package/LICENSE +0 -21
  224. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,74 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+
4
+ interface StepIndicatorProps {
5
+ currentStep: number;
6
+ totalSteps: number;
7
+ steps: string[];
8
+ }
9
+
10
+ export function StepIndicator({ currentStep, totalSteps, steps }: StepIndicatorProps) {
11
+ const PRIMARY = "#f97316";
12
+ const SECONDARY = "#a1a1aa";
13
+ const BORDER = "#27272a";
14
+
15
+ return (
16
+ <Box flexDirection="column" marginBottom={1}>
17
+ <Box>
18
+ <Text color={SECONDARY}>╭</Text>
19
+ <Text color={BORDER}>{"─".repeat(58)}</Text>
20
+ <Text color={SECONDARY}>╮</Text>
21
+ </Box>
22
+
23
+ <Box>
24
+ <Text color={SECONDARY}>│</Text>
25
+ <Box width={58} flexDirection="row">
26
+ {steps.map((step, index) => {
27
+ const stepNum = index + 1;
28
+ const isActive = stepNum === currentStep;
29
+ const isCompleted = stepNum < currentStep;
30
+
31
+ return (
32
+ <Box key={index} marginRight={1}>
33
+ {isCompleted ? (
34
+ <Text color="#22c55e">✓</Text>
35
+ ) : isActive ? (
36
+ <Text color={PRIMARY} bold>{`[${stepNum}]`}</Text>
37
+ ) : (
38
+ <Text color={SECONDARY}>{` ${stepNum} `}</Text>
39
+ )}
40
+ <Text color={isActive ? PRIMARY : SECONDARY}> {step}</Text>
41
+ </Box>
42
+ );
43
+ })}
44
+ </Box>
45
+ <Text color={SECONDARY}>│</Text>
46
+ </Box>
47
+
48
+ <Box>
49
+ <Text color={SECONDARY}>╰</Text>
50
+ <Text color={BORDER}>{"─".repeat(58)}</Text>
51
+ <Text color={SECONDARY}>╯</Text>
52
+ </Box>
53
+ </Box>
54
+ );
55
+ }
56
+
57
+ interface CompactStepIndicatorProps {
58
+ currentStep: number;
59
+ totalSteps: number;
60
+ }
61
+
62
+ export function CompactStepIndicator({ currentStep, totalSteps }: CompactStepIndicatorProps) {
63
+ const PRIMARY = "#f97316";
64
+
65
+ return (
66
+ <Box>
67
+ <Text color={PRIMARY} bold>
68
+ STEP {currentStep}/{totalSteps}
69
+ </Text>
70
+ <Text color="#27272a"> │ </Text>
71
+ <Text color="#a1a1aa">{"●".repeat(currentStep)}{"○".repeat(totalSteps - currentStep)}</Text>
72
+ </Box>
73
+ );
74
+ }
@@ -0,0 +1,229 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import { Box, Text } from "ink";
3
+
4
+ interface SuccessScreenProps {
5
+ summary: {
6
+ mode: "hub" | "standalone" | "both";
7
+ providers: string[];
8
+ hubTargets?: string[];
9
+ filesCreated: string[];
10
+ warnings?: string[];
11
+ };
12
+ onExit: () => void;
13
+ }
14
+
15
+ const CHECKMARK_ANIMATION = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
16
+ const SUCCESS_FRAMES = ["✓", "✓", "✓"];
17
+
18
+ export function SuccessScreen({ summary, onExit }: SuccessScreenProps) {
19
+ const [animFrame, setAnimFrame] = useState(0);
20
+ const [showContent, setShowContent] = useState(false);
21
+ const PRIMARY = "#f97316";
22
+
23
+ useEffect(() => {
24
+ const animInterval = setInterval(() => {
25
+ setAnimFrame((prev) => {
26
+ if (prev < CHECKMARK_ANIMATION.length - 1) {
27
+ return prev + 1;
28
+ } else {
29
+ setShowContent(true);
30
+ clearInterval(animInterval);
31
+ return prev;
32
+ }
33
+ });
34
+ }, 80);
35
+
36
+ return () => clearInterval(animInterval);
37
+ }, []);
38
+
39
+ useEffect(() => {
40
+ if (showContent) {
41
+ const timer = setTimeout(() => {
42
+ // Auto-close after showing content
43
+ }, 5000);
44
+ return () => clearTimeout(timer);
45
+ }
46
+ }, [showContent]);
47
+
48
+ return (
49
+ <Box flexDirection="column" alignItems="center">
50
+ {!showContent ? (
51
+ <Box>
52
+ <Text color="#22c55e">{CHECKMARK_ANIMATION[animFrame]}</Text>
53
+ <Text color="#a1a1aa"> Finalizing setup...</Text>
54
+ </Box>
55
+ ) : (
56
+ <>
57
+ <Box marginBottom={1}>
58
+ <Text color="#22c55e" bold>
59
+ ╔═══════════════════════════════════════════════════════╗
60
+ </Text>
61
+ </Box>
62
+
63
+ <Box>
64
+ <Text color="#22c55e" bold>
65
+
66
+ </Text>
67
+ <Text color="#22c55e" bold>
68
+ {" ✓ SETUP COMPLETE "}
69
+ </Text>
70
+ <Text color="#22c55e" bold>
71
+
72
+ </Text>
73
+ </Box>
74
+
75
+ <Box>
76
+ <Text color="#27272a" bold>
77
+ ╚═══════════════════════════════════════════════════════╝
78
+ </Text>
79
+ </Box>
80
+
81
+ <Box marginTop={2} flexDirection="column">
82
+ <Box marginBottom={1}>
83
+ <Text color={PRIMARY} bold>
84
+ CONFIGURATION SUMMARY
85
+ </Text>
86
+ </Box>
87
+
88
+ <Box>
89
+ <Text color="#a1a1aa">Mode: </Text>
90
+ <Text color="#ffffff" bold>
91
+ {summary.mode.toUpperCase()}
92
+ </Text>
93
+ </Box>
94
+
95
+ <Box>
96
+ <Text color="#a1a1aa">Providers: </Text>
97
+ <Text color="#22c55e">{summary.providers.join(", ")}</Text>
98
+ </Box>
99
+
100
+ {summary.hubTargets && summary.hubTargets.length > 0 && (
101
+ <Box>
102
+ <Text color="#a1a1aa">Hub Integration: </Text>
103
+ <Text color="#f59e0b">{summary.hubTargets.join(", ")}</Text>
104
+ </Box>
105
+ )}
106
+
107
+ <Box marginTop={1}>
108
+ <Text color={PRIMARY} bold>
109
+ FILES CREATED
110
+ </Text>
111
+ </Box>
112
+
113
+ {summary.filesCreated.map((file, index) => (
114
+ <Box key={index}>
115
+ <Text color="#22c55e"> ● </Text>
116
+ <Text color="#a1a1aa">{file}</Text>
117
+ </Box>
118
+ ))}
119
+
120
+ {summary.warnings && summary.warnings.length > 0 && (
121
+ <>
122
+ <Box marginTop={1}>
123
+ <Text color="#f59e0b" bold>
124
+ WARNINGS
125
+ </Text>
126
+ </Box>
127
+ {summary.warnings.map((warning, index) => (
128
+ <Box key={index}>
129
+ <Text color="#f59e0b"> ⚠ </Text>
130
+ <Text color="#a1a1aa">{warning}</Text>
131
+ </Box>
132
+ ))}
133
+ </>
134
+ )}
135
+ </Box>
136
+
137
+ <Box marginTop={2} flexDirection="column">
138
+ <Box marginBottom={1}>
139
+ <Text color={PRIMARY} bold>
140
+ NEXT STEPS
141
+ </Text>
142
+ </Box>
143
+
144
+ <Box>
145
+ <Text color="#71717a">1. Run </Text>
146
+ <Text color="#f59e0b">rax-flow doctor</Text>
147
+ <Text color="#71717a"> to verify setup</Text>
148
+ </Box>
149
+
150
+ <Box>
151
+ <Text color="#71717a">2. Try </Text>
152
+ <Text color="#f59e0b">rax-flow</Text>
153
+ <Text color="#71717a"> to launch the hub</Text>
154
+ </Box>
155
+
156
+ <Box>
157
+ <Text color="#71717a">3. Run </Text>
158
+ <Text color="#f59e0b">rax-flow run --prompt "..." --stream</Text>
159
+ <Text color="#71717a"> to execute</Text>
160
+ </Box>
161
+ </Box>
162
+
163
+ <Box marginTop={2}>
164
+ <Text color="#27272a">{"─".repeat(55)}</Text>
165
+ </Box>
166
+
167
+ <Box marginTop={1}>
168
+ <Text color={PRIMARY}>
169
+ RAX-FLOW is now the operational backbone of your CLI workflow.
170
+ </Text>
171
+ </Box>
172
+
173
+ <Box marginTop={1}>
174
+ <Text color="#71717a" dimColor>
175
+ Press any key to exit...
176
+ </Text>
177
+ </Box>
178
+ </>
179
+ )}
180
+ </Box>
181
+ );
182
+ }
183
+
184
+ export function ErrorScreen({
185
+ error,
186
+ onRetry,
187
+ onExit,
188
+ }: {
189
+ error: string;
190
+ onRetry?: () => void;
191
+ onExit: () => void;
192
+ }) {
193
+ return (
194
+ <Box flexDirection="column" alignItems="center">
195
+ <Box marginBottom={1}>
196
+ <Text color="#ef4444" bold>
197
+ ╔═══════════════════════════════════════════════════════╗
198
+ </Text>
199
+ </Box>
200
+
201
+ <Box>
202
+ <Text color="#ef4444" bold>
203
+
204
+ </Text>
205
+ <Text color="#ef4444" bold>
206
+ {" ✗ SETUP FAILED "}
207
+ </Text>
208
+ <Text color="#ef4444" bold>
209
+
210
+ </Text>
211
+ </Box>
212
+
213
+ <Box>
214
+ <Text color="#27272a" bold>
215
+ ╚═══════════════════════════════════════════════════════╝
216
+ </Text>
217
+ </Box>
218
+
219
+ <Box marginTop={1}>
220
+ <Text color="#ef4444">{error}</Text>
221
+ </Box>
222
+
223
+ <Box marginTop={2}>
224
+ {onRetry && <Text color="#f59e0b">[R] Retry</Text>}
225
+ <Text color="#71717a"> [E] Exit</Text>
226
+ </Box>
227
+ </Box>
228
+ );
229
+ }
@@ -0,0 +1,34 @@
1
+ import { render } from "ink";
2
+ import React from "react";
3
+ import { SetupWizard } from "./components/SetupWizard.js";
4
+
5
+ export async function runSetup(): Promise<number> {
6
+ return new Promise((resolve) => {
7
+ const { unmount } = render(
8
+ React.createElement(SetupWizard)
9
+ );
10
+
11
+ // Handle process termination
12
+ const handleExit = () => {
13
+ unmount();
14
+ resolve(0);
15
+ };
16
+
17
+ process.on("exit", handleExit);
18
+ process.on("SIGINT", () => {
19
+ unmount();
20
+ resolve(0);
21
+ });
22
+ });
23
+ }
24
+
25
+ export { SetupWizard } from "./components/SetupWizard.js";
26
+ export { AsciiBanner, IndustrialDivider, IndustrialBox, StatusIndicator } from "./components/AsciiBanner.js";
27
+ export { StepIndicator, CompactStepIndicator } from "./components/StepIndicator.js";
28
+ export { ProviderSelector, PROVIDERS } from "./components/ProviderSelector.js";
29
+ export { ApiKeyInput, ApiKeyCollector } from "./components/ApiKeyInput.js";
30
+ export { CliDetector, CliSelector } from "./components/CliDetector.js";
31
+ export { ModeSelector } from "./components/ModeSelector.js";
32
+ export { SuccessScreen, ErrorScreen } from "./components/SuccessScreen.js";
33
+ export * from "./utils/cli-detection.js";
34
+ export * from "./utils/config-writer.js";
@@ -0,0 +1,99 @@
1
+ import { execSync } from "node:child_process";
2
+ import { access } from "node:fs/promises";
3
+ import { constants } from "node:fs";
4
+ import path from "node:path";
5
+ import os from "node:os";
6
+
7
+ export interface DetectedCli {
8
+ id: string;
9
+ name: string;
10
+ detected: boolean;
11
+ configPath?: string;
12
+ version?: string;
13
+ }
14
+
15
+ const CLI_CONFIG_PATHS: Record<string, string[]> = {
16
+ "claude-code": [
17
+ path.join(os.homedir(), ".claude"),
18
+ path.join(os.homedir(), ".config", "claude-code"),
19
+ ],
20
+ codex: [
21
+ path.join(os.homedir(), ".codex"),
22
+ path.join(os.homedir(), ".config", "codex"),
23
+ ],
24
+ opencode: [
25
+ path.join(os.homedir(), ".opencode"),
26
+ path.join(os.homedir(), ".config", "opencode"),
27
+ ],
28
+ kilo: [
29
+ path.join(os.homedir(), ".kilo"),
30
+ path.join(os.homedir(), ".config", "kilo"),
31
+ ],
32
+ };
33
+
34
+ const CLI_BOOTSTRAP_FILES: Record<string, string> = {
35
+ "claude-code": "CLAUDE.md",
36
+ codex: "CODEX.md",
37
+ opencode: "OPENCODE.md",
38
+ kilo: "KILO.md",
39
+ };
40
+
41
+ export function getCliBootstrapFile(cliId: string): string {
42
+ return CLI_BOOTSTRAP_FILES[cliId] || "README.md";
43
+ }
44
+
45
+ export async function detectInstalledClis(): Promise<DetectedCli[]> {
46
+ const candidates = [
47
+ { id: "claude-code", name: "Claude Code", cmd: "claude-code --version" },
48
+ { id: "codex", name: "Codex", cmd: "codex --version" },
49
+ { id: "opencode", name: "OpenCode", cmd: "opencode --version" },
50
+ { id: "kilo", name: "Kilo", cmd: "kilo --version" },
51
+ ];
52
+
53
+ const results: DetectedCli[] = [];
54
+
55
+ for (const cli of candidates) {
56
+ let detected = false;
57
+ let version: string | undefined;
58
+ let configPath: string | undefined;
59
+
60
+ try {
61
+ const output = execSync(cli.cmd, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
62
+ detected = true;
63
+ version = output.trim().split("\n")[0];
64
+ } catch {
65
+ // Not in PATH, check config directories
66
+ }
67
+
68
+ // Check for config directories even if not in PATH
69
+ const configPaths = CLI_CONFIG_PATHS[cli.id] || [];
70
+ for (const p of configPaths) {
71
+ try {
72
+ await access(p, constants.F_OK);
73
+ configPath = p;
74
+ if (!detected) detected = true;
75
+ break;
76
+ } catch {
77
+ // Directory doesn't exist
78
+ }
79
+ }
80
+
81
+ results.push({
82
+ id: cli.id,
83
+ name: cli.name,
84
+ detected,
85
+ configPath,
86
+ version,
87
+ });
88
+ }
89
+
90
+ return results;
91
+ }
92
+
93
+ export async function detectInstalledClisFast(): Promise<DetectedCli[]> {
94
+ return detectInstalledClis();
95
+ }
96
+
97
+ export function getCliConfigPath(cliId: string): string | undefined {
98
+ return (CLI_CONFIG_PATHS[cliId] || [])[0];
99
+ }
@@ -0,0 +1,249 @@
1
+ import { mkdir, writeFile, access } from "node:fs/promises";
2
+ import { constants } from "node:fs";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+
6
+ export interface ProviderConfig {
7
+ id: string;
8
+ name: string;
9
+ apiKey?: string;
10
+ model?: string;
11
+ apiKeyEnv?: string;
12
+ }
13
+
14
+ export interface SetupConfig {
15
+ mode: "hub" | "standalone" | "both";
16
+ providers: ProviderConfig[];
17
+ defaultProvider: string;
18
+ hubTargets: string[];
19
+ projectPath: string;
20
+ }
21
+
22
+ export interface RaxrcConfig {
23
+ version: number;
24
+ defaultProvider: string;
25
+ strongProvider?: string;
26
+ providers: Record<string, {
27
+ model?: string;
28
+ apiKeyEnv?: string;
29
+ apiKey?: string;
30
+ mode?: string;
31
+ bridgeCommand?: string;
32
+ bridgeCommandEnv?: string;
33
+ }>;
34
+ privacyMode: boolean;
35
+ verifyFixLoops: number;
36
+ }
37
+
38
+ const ENV_VAR_MAP: Record<string, string> = {
39
+ anthropic: "ANTHROPIC_API_KEY",
40
+ openai: "OPENAI_API_KEY",
41
+ gemini: "GOOGLE_API_KEY",
42
+ mistral: "MISTRAL_API_KEY",
43
+ groq: "GROQ_API_KEY",
44
+ };
45
+
46
+ const MODEL_MAP: Record<string, string> = {
47
+ anthropic: "claude-3-5-sonnet-latest",
48
+ openai: "gpt-4o",
49
+ gemini: "gemini-2.0-flash",
50
+ mistral: "mistral-large-latest",
51
+ groq: "llama-3.3-70b-versatile",
52
+ };
53
+
54
+ export async function ensureDirectory(dir: string): Promise<void> {
55
+ try {
56
+ await access(dir, constants.F_OK);
57
+ } catch {
58
+ await mkdir(dir, { recursive: true });
59
+ }
60
+ }
61
+
62
+ export async function writeRaxrc(targetDir: string, config: SetupConfig): Promise<string> {
63
+ const raxrc: RaxrcConfig = {
64
+ version: 1,
65
+ defaultProvider: config.defaultProvider,
66
+ providers: {},
67
+ privacyMode: true,
68
+ verifyFixLoops: 3,
69
+ };
70
+
71
+ // Add host provider if hub mode
72
+ if (config.mode === "hub" || config.mode === "both") {
73
+ const primaryTarget = config.hubTargets[0] || "claude-code";
74
+ raxrc.providers.host = {
75
+ model: primaryTarget,
76
+ mode: "auto",
77
+ bridgeCommand: primaryTarget,
78
+ bridgeCommandEnv: "RAX_HOST_BRIDGE_COMMAND",
79
+ };
80
+ }
81
+
82
+ // Add configured providers
83
+ for (const provider of config.providers) {
84
+ if (provider.id === "host") continue;
85
+
86
+ raxrc.providers[provider.id] = {
87
+ model: provider.model || MODEL_MAP[provider.id] || "unknown",
88
+ apiKeyEnv: ENV_VAR_MAP[provider.id] || `${provider.id.toUpperCase()}_API_KEY`,
89
+ };
90
+
91
+ if (provider.apiKey) {
92
+ raxrc.providers[provider.id].apiKey = provider.apiKey;
93
+ }
94
+ }
95
+
96
+ // Ensure at least one fallback
97
+ if (!raxrc.providers.openai) {
98
+ raxrc.providers.openai = {
99
+ model: "gpt-4o",
100
+ apiKeyEnv: "OPENAI_API_KEY",
101
+ };
102
+ }
103
+
104
+ if (!raxrc.providers.anthropic) {
105
+ raxrc.providers.anthropic = {
106
+ model: "claude-3-5-sonnet-latest",
107
+ apiKeyEnv: "ANTHROPIC_API_KEY",
108
+ };
109
+ }
110
+
111
+ const filePath = path.join(targetDir, ".raxrc");
112
+ await writeFile(filePath, JSON.stringify(raxrc, null, 2) + "\n", "utf-8");
113
+ return filePath;
114
+ }
115
+
116
+ export async function writeHubBootstrap(
117
+ targetCli: string,
118
+ configPath: string,
119
+ projectPath: string
120
+ ): Promise<string> {
121
+ const bootstrapFileName = getBootstrapFileName(targetCli);
122
+ const raxFlowDir = path.join(configPath, ".rax-flow");
123
+
124
+ await ensureDirectory(raxFlowDir);
125
+ await ensureDirectory(path.join(raxFlowDir, "workflows"));
126
+
127
+ const bootstrapContent = generateBootstrapContent(targetCli, projectPath);
128
+ const bootstrapPath = path.join(configPath, bootstrapFileName);
129
+
130
+ await writeFile(bootstrapPath, bootstrapContent, "utf-8");
131
+
132
+ // Create example workflow
133
+ const exampleWorkflow = {
134
+ id: "default-workflow",
135
+ nodes: [
136
+ { id: "analyze", agent: "IntentClassifierAgent", dependsOn: [] },
137
+ { id: "spec", agent: "SpecAgent", dependsOn: ["analyze"] },
138
+ { id: "implement", agent: "CodeGeneratorAgent", dependsOn: ["spec"] },
139
+ { id: "verify", agent: "ValidatorAgent", dependsOn: ["implement"] },
140
+ ],
141
+ };
142
+
143
+ const workflowPath = path.join(raxFlowDir, "workflows", "default.json");
144
+ await writeFile(workflowPath, JSON.stringify(exampleWorkflow, null, 2) + "\n", "utf-8");
145
+
146
+ return bootstrapPath;
147
+ }
148
+
149
+ function getBootstrapFileName(cliId: string): string {
150
+ const map: Record<string, string> = {
151
+ "claude-code": "CLAUDE.md",
152
+ codex: "CODEX.md",
153
+ opencode: "OPENCODE.md",
154
+ kilo: "KILO.md",
155
+ };
156
+ return map[cliId] || "RAXFLOW.md";
157
+ }
158
+
159
+ function generateBootstrapContent(cliId: string, projectPath: string): string {
160
+ return `# RAX-FLOW Bootstrap Configuration
161
+
162
+ This project is configured to work with RAX-FLOW orchestration.
163
+
164
+ ## Project Context
165
+ - Path: ${projectPath}
166
+ - CLI: ${cliId}
167
+
168
+ ## Available Commands
169
+ - \`rax-flow run --prompt "..." --stream\` - Execute orchestrated workflow
170
+ - \`rax-flow doctor\` - Check system health
171
+ - \`rax-flow status\` - View current state
172
+
173
+ ## Workflows
174
+ Workflows are stored in \`.rax-flow/workflows/\` directory.
175
+
176
+ ## Provider Configuration
177
+ See \`.raxrc\` in the project root for provider settings.
178
+ `;
179
+ }
180
+
181
+ export async function writeStandaloneConfig(projectPath: string): Promise<{
182
+ raxFlowDir: string;
183
+ workflowsDir: string;
184
+ globalDir: string;
185
+ }> {
186
+ const raxFlowDir = path.join(projectPath, ".rax-flow");
187
+ const workflowsDir = path.join(raxFlowDir, "workflows");
188
+ const globalDir = path.join(os.homedir(), ".rax-flow");
189
+
190
+ await ensureDirectory(raxFlowDir);
191
+ await ensureDirectory(workflowsDir);
192
+ await ensureDirectory(globalDir);
193
+
194
+ // Create default workflow
195
+ const defaultWorkflow = {
196
+ id: "default",
197
+ name: "Default Workflow",
198
+ nodes: [
199
+ { id: "classify", agent: "IntentClassifierAgent", dependsOn: [] },
200
+ { id: "plan", agent: "TaskPlannerAgent", dependsOn: ["classify"] },
201
+ { id: "code", agent: "CodeGeneratorAgent", dependsOn: ["plan"] },
202
+ { id: "test", agent: "TestAgent", dependsOn: ["code"] },
203
+ { id: "fix", agent: "FixAgent", dependsOn: ["test"] },
204
+ ],
205
+ };
206
+
207
+ const workflowPath = path.join(workflowsDir, "default.json");
208
+ await writeFile(workflowPath, JSON.stringify(defaultWorkflow, null, 2) + "\n", "utf-8");
209
+
210
+ // Create global config
211
+ const globalConfigPath = path.join(globalDir, "config.json");
212
+ const globalConfig = {
213
+ version: 1,
214
+ createdAt: new Date().toISOString(),
215
+ lastUsed: new Date().toISOString(),
216
+ };
217
+ await writeFile(globalConfigPath, JSON.stringify(globalConfig, null, 2) + "\n", "utf-8");
218
+
219
+ return { raxFlowDir, workflowsDir, globalDir };
220
+ }
221
+
222
+ export async function validateSetup(projectPath: string): Promise<{
223
+ valid: boolean;
224
+ errors: string[];
225
+ warnings: string[];
226
+ }> {
227
+ const errors: string[] = [];
228
+ const warnings: string[] = [];
229
+
230
+ // Check .raxrc exists
231
+ try {
232
+ await access(path.join(projectPath, ".raxrc"), constants.F_OK);
233
+ } catch {
234
+ errors.push(".raxrc configuration file not found");
235
+ }
236
+
237
+ // Check .rax-flow directory
238
+ try {
239
+ await access(path.join(projectPath, ".rax-flow"), constants.F_OK);
240
+ } catch {
241
+ warnings.push(".rax-flow directory not found (optional for hub mode)");
242
+ }
243
+
244
+ return {
245
+ valid: errors.length === 0,
246
+ errors,
247
+ warnings,
248
+ };
249
+ }