brainrot-cli 0.1.0 → 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 (180) hide show
  1. package/dist/AchievementNotification.d.ts.map +1 -1
  2. package/dist/AchievementNotification.js.map +1 -1
  3. package/dist/AppNew.d.ts +11 -0
  4. package/dist/AppNew.d.ts.map +1 -0
  5. package/dist/AppNew.js +437 -0
  6. package/dist/AppNew.js.map +1 -0
  7. package/dist/AttentionOverlay.d.ts +28 -0
  8. package/dist/AttentionOverlay.d.ts.map +1 -0
  9. package/dist/AttentionOverlay.js +92 -0
  10. package/dist/AttentionOverlay.js.map +1 -0
  11. package/dist/ClaudeChat.d.ts +38 -0
  12. package/dist/ClaudeChat.d.ts.map +1 -0
  13. package/dist/ClaudeChat.js +81 -0
  14. package/dist/ClaudeChat.js.map +1 -0
  15. package/dist/DynamicInterviewFlow.d.ts +66 -0
  16. package/dist/DynamicInterviewFlow.d.ts.map +1 -0
  17. package/dist/DynamicInterviewFlow.js +352 -0
  18. package/dist/DynamicInterviewFlow.js.map +1 -0
  19. package/dist/FeatureInput.d.ts +20 -0
  20. package/dist/FeatureInput.d.ts.map +1 -0
  21. package/dist/FeatureInput.js +66 -0
  22. package/dist/FeatureInput.js.map +1 -0
  23. package/dist/FeaturePromptScreen.d.ts +24 -0
  24. package/dist/FeaturePromptScreen.d.ts.map +1 -0
  25. package/dist/FeaturePromptScreen.js +117 -0
  26. package/dist/FeaturePromptScreen.js.map +1 -0
  27. package/dist/GameSelectScreen.d.ts +24 -0
  28. package/dist/GameSelectScreen.d.ts.map +1 -0
  29. package/dist/GameSelectScreen.js +78 -0
  30. package/dist/GameSelectScreen.js.map +1 -0
  31. package/dist/GameSelector.d.ts +9 -1
  32. package/dist/GameSelector.d.ts.map +1 -1
  33. package/dist/GameSelector.js +116 -19
  34. package/dist/GameSelector.js.map +1 -1
  35. package/dist/GameSelectorOverlay.d.ts +21 -0
  36. package/dist/GameSelectorOverlay.d.ts.map +1 -0
  37. package/dist/GameSelectorOverlay.js +98 -0
  38. package/dist/GameSelectorOverlay.js.map +1 -0
  39. package/dist/HelpOverlay.d.ts.map +1 -1
  40. package/dist/HelpOverlay.js +5 -2
  41. package/dist/HelpOverlay.js.map +1 -1
  42. package/dist/InterviewQuestion.d.ts +36 -0
  43. package/dist/InterviewQuestion.d.ts.map +1 -0
  44. package/dist/InterviewQuestion.js +148 -0
  45. package/dist/InterviewQuestion.js.map +1 -0
  46. package/dist/Layout.d.ts +1 -1
  47. package/dist/Layout.d.ts.map +1 -1
  48. package/dist/Layout.js +4 -4
  49. package/dist/Layout.js.map +1 -1
  50. package/dist/LogViewer.d.ts.map +1 -1
  51. package/dist/LogViewer.js +2 -2
  52. package/dist/LogViewer.js.map +1 -1
  53. package/dist/LoopAlertOverlay.d.ts +1 -1
  54. package/dist/LoopAlertOverlay.d.ts.map +1 -1
  55. package/dist/LoopAlertOverlay.js +1 -1
  56. package/dist/LoopAlertOverlay.js.map +1 -1
  57. package/dist/LoopComplete.d.ts +42 -0
  58. package/dist/LoopComplete.d.ts.map +1 -0
  59. package/dist/LoopComplete.js +69 -0
  60. package/dist/LoopComplete.js.map +1 -0
  61. package/dist/LoopManagementPanel.d.ts.map +1 -1
  62. package/dist/LoopManagementPanel.js.map +1 -1
  63. package/dist/OnboardingTutorial.d.ts +23 -0
  64. package/dist/OnboardingTutorial.d.ts.map +1 -0
  65. package/dist/OnboardingTutorial.js +165 -0
  66. package/dist/OnboardingTutorial.js.map +1 -0
  67. package/dist/PrdGenerationScreen.d.ts +43 -0
  68. package/dist/PrdGenerationScreen.d.ts.map +1 -0
  69. package/dist/PrdGenerationScreen.js +411 -0
  70. package/dist/PrdGenerationScreen.js.map +1 -0
  71. package/dist/PrdOverlay.d.ts +29 -0
  72. package/dist/PrdOverlay.d.ts.map +1 -0
  73. package/dist/PrdOverlay.js +174 -0
  74. package/dist/PrdOverlay.js.map +1 -0
  75. package/dist/PreStartReviewScreen.d.ts +29 -0
  76. package/dist/PreStartReviewScreen.d.ts.map +1 -0
  77. package/dist/PreStartReviewScreen.js +161 -0
  78. package/dist/PreStartReviewScreen.js.map +1 -0
  79. package/dist/ResumeOverlay.d.ts +26 -0
  80. package/dist/ResumeOverlay.d.ts.map +1 -0
  81. package/dist/ResumeOverlay.js +163 -0
  82. package/dist/ResumeOverlay.js.map +1 -0
  83. package/dist/ResumePrompt.d.ts +32 -0
  84. package/dist/ResumePrompt.d.ts.map +1 -0
  85. package/dist/ResumePrompt.js +65 -0
  86. package/dist/ResumePrompt.js.map +1 -0
  87. package/dist/SettingsMenu.d.ts.map +1 -1
  88. package/dist/SettingsMenu.js +14 -7
  89. package/dist/SettingsMenu.js.map +1 -1
  90. package/dist/SetupWizard.d.ts +41 -0
  91. package/dist/SetupWizard.d.ts.map +1 -0
  92. package/dist/SetupWizard.js +167 -0
  93. package/dist/SetupWizard.js.map +1 -0
  94. package/dist/SidePanel.d.ts +26 -0
  95. package/dist/SidePanel.d.ts.map +1 -0
  96. package/dist/SidePanel.js +90 -0
  97. package/dist/SidePanel.js.map +1 -0
  98. package/dist/SplitPane.d.ts.map +1 -1
  99. package/dist/SplitPane.js +6 -2
  100. package/dist/SplitPane.js.map +1 -1
  101. package/dist/StatsMenu.d.ts.map +1 -1
  102. package/dist/StatsMenu.js +24 -6
  103. package/dist/StatsMenu.js.map +1 -1
  104. package/dist/StatusBar.d.ts +45 -2
  105. package/dist/StatusBar.d.ts.map +1 -1
  106. package/dist/StatusBar.js +193 -23
  107. package/dist/StatusBar.js.map +1 -1
  108. package/dist/StatusBarMinimal.d.ts +26 -0
  109. package/dist/StatusBarMinimal.d.ts.map +1 -0
  110. package/dist/StatusBarMinimal.js +111 -0
  111. package/dist/StatusBarMinimal.js.map +1 -0
  112. package/dist/TaskBreakdownScreen.d.ts +27 -0
  113. package/dist/TaskBreakdownScreen.d.ts.map +1 -0
  114. package/dist/TaskBreakdownScreen.js +96 -0
  115. package/dist/TaskBreakdownScreen.js.map +1 -0
  116. package/dist/cli.d.ts.map +1 -1
  117. package/dist/cli.js +3 -1
  118. package/dist/cli.js.map +1 -1
  119. package/dist/config.d.ts +11 -0
  120. package/dist/config.d.ts.map +1 -1
  121. package/dist/config.js +12 -0
  122. package/dist/config.js.map +1 -1
  123. package/dist/games/MinesweeperGame.d.ts +1 -1
  124. package/dist/games/MinesweeperGame.d.ts.map +1 -1
  125. package/dist/games/MinesweeperGame.js +30 -10
  126. package/dist/games/MinesweeperGame.js.map +1 -1
  127. package/dist/games/PongGame.d.ts +1 -1
  128. package/dist/games/PongGame.d.ts.map +1 -1
  129. package/dist/games/PongGame.js +7 -2
  130. package/dist/games/PongGame.js.map +1 -1
  131. package/dist/games/SnakeGame.d.ts +1 -1
  132. package/dist/games/SnakeGame.d.ts.map +1 -1
  133. package/dist/games/SnakeGame.js +12 -4
  134. package/dist/games/SnakeGame.js.map +1 -1
  135. package/dist/games/TetrisGame.d.ts +1 -1
  136. package/dist/games/TetrisGame.d.ts.map +1 -1
  137. package/dist/games/TetrisGame.js +22 -5
  138. package/dist/games/TetrisGame.js.map +1 -1
  139. package/dist/high-scores.d.ts.map +1 -1
  140. package/dist/high-scores.js.map +1 -1
  141. package/dist/index.d.ts +6 -0
  142. package/dist/index.d.ts.map +1 -1
  143. package/dist/index.js +10 -236
  144. package/dist/index.js.map +1 -1
  145. package/dist/loop-state.d.ts +137 -0
  146. package/dist/loop-state.d.ts.map +1 -0
  147. package/dist/loop-state.js +228 -0
  148. package/dist/loop-state.js.map +1 -0
  149. package/dist/ralph-loop-parser.d.ts.map +1 -1
  150. package/dist/ralph-loop-parser.js +4 -2
  151. package/dist/ralph-loop-parser.js.map +1 -1
  152. package/dist/stats.d.ts.map +1 -1
  153. package/dist/stats.js.map +1 -1
  154. package/dist/styled-components.d.ts +1 -1
  155. package/dist/styled-components.d.ts.map +1 -1
  156. package/dist/styled-components.js +5 -3
  157. package/dist/styled-components.js.map +1 -1
  158. package/dist/theme.d.ts.map +1 -1
  159. package/dist/theme.js +15 -2
  160. package/dist/theme.js.map +1 -1
  161. package/dist/themes.d.ts.map +1 -1
  162. package/dist/themes.js.map +1 -1
  163. package/dist/use-claude-code.d.ts.map +1 -1
  164. package/dist/use-claude-code.js +7 -1
  165. package/dist/use-claude-code.js.map +1 -1
  166. package/dist/use-config.d.ts.map +1 -1
  167. package/dist/use-config.js.map +1 -1
  168. package/dist/use-loop-state.d.ts +55 -0
  169. package/dist/use-loop-state.d.ts.map +1 -0
  170. package/dist/use-loop-state.js +208 -0
  171. package/dist/use-loop-state.js.map +1 -0
  172. package/dist/use-stats.d.ts.map +1 -1
  173. package/dist/use-stats.js.map +1 -1
  174. package/dist/useTheme.d.ts.map +1 -1
  175. package/dist/useTheme.js.map +1 -1
  176. package/package.json +3 -2
  177. package/dist/__tests__/ralph-loop-parser.test.d.ts +0 -2
  178. package/dist/__tests__/ralph-loop-parser.test.d.ts.map +0 -1
  179. package/dist/__tests__/ralph-loop-parser.test.js +0 -143
  180. package/dist/__tests__/ralph-loop-parser.test.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,3 +1,9 @@
1
1
  #!/usr/bin/env node
2
+ /**
3
+ * BrainRot CLI Entry Point
4
+ *
5
+ * A terminal-native CLI that wraps Claude Code with built-in games
6
+ * to play while agents work.
7
+ */
2
8
  export {};
3
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":";AACA;;;;;GAKG"}
package/dist/index.js CHANGED
@@ -1,240 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { render, Box, Text, useInput, useApp } from "ink";
4
- import { useState, useCallback, useMemo, useEffect, createContext, useContext } from "react";
5
- import { useClaudeCode } from "./use-claude-code.js";
6
- import { useRalphLoopWithClaudeOutput } from "./use-ralph-loop.js";
7
- import { Layout, useTerminalSize } from "./Layout.js";
8
- import { LoopManagementPanel } from "./LoopManagementPanel.js";
9
- import { LogViewer } from "./LogViewer.js";
10
- import { GameSelector } from "./GameSelector.js";
11
- import { SettingsMenu } from "./SettingsMenu.js";
12
- import { StatsMenu } from "./StatsMenu.js";
13
- import { useAchievementNotifications } from "./AchievementNotification.js";
14
- import { getGameList, getGameById } from "./games/index.js";
15
- import { useConfig } from "./use-config.js";
16
- import { getLayoutOptions, getClaudeCodeOptions, deepMerge, saveConfig } from "./config.js";
17
- import { parseCLI, printHelp, printVersion, printError } from "./cli.js";
18
- import { recordSessionStart } from "./stats.js";
19
- import { ThemeProvider, useThemeColors } from "./useTheme.js";
20
- import { StatusBar, GameStatusProvider, useGameStatus } from "./StatusBar.js";
21
- import { HelpOverlay } from "./HelpOverlay.js";
22
- // ============================================================================
23
- // CLI OVERRIDE CONTEXT
24
- // ============================================================================
25
- /**
26
- * Context for passing CLI overrides to the app
27
- */
28
- const CLIOverridesContext = createContext({});
2
+ import { jsx as _jsx } from "react/jsx-runtime";
29
3
  /**
30
- * Hook to access CLI overrides
4
+ * BrainRot CLI Entry Point
5
+ *
6
+ * A terminal-native CLI that wraps Claude Code with built-in games
7
+ * to play while agents work.
31
8
  */
32
- function useCLIOverrides() {
33
- return useContext(CLIOverridesContext);
34
- }
35
- /** Game area with mode switching between menu, logs, settings, stats, and active game */
36
- function GameArea({ logs, hasFocus, dimensions, loopAttention, onLoopAlertDismiss, config, onConfigChange, onConfigSave, onAchievementUnlock: _onAchievementUnlock, onGameStateChange, }) {
37
- const [mode, setMode] = useState("menu");
38
- const [selectedGameId, setSelectedGameId] = useState(null);
39
- const colors = useThemeColors();
40
- const { setGameState, clearGameState } = useGameStatus();
41
- const games = useMemo(() => getGameList(), []);
42
- const handleSelectGame = useCallback((gameId) => {
43
- setSelectedGameId(gameId);
44
- setMode("game");
45
- // Set game name in status bar
46
- const gameInfo = getGameById(gameId);
47
- if (gameInfo) {
48
- setGameState({ gameId, gameName: gameInfo.info.name });
49
- }
50
- }, [setGameState]);
51
- const handleExitGame = useCallback(() => {
52
- setSelectedGameId(null);
53
- setMode("menu");
54
- // Clear game state from status bar
55
- clearGameState();
56
- }, [clearGameState]);
57
- const handleCloseSettings = useCallback(() => {
58
- setMode("menu");
59
- }, []);
60
- const handleOpenStats = useCallback(() => {
61
- setMode("stats");
62
- }, []);
63
- const handleCloseStats = useCallback(() => {
64
- setMode("menu");
65
- }, []);
66
- // Handle mode switching with keyboard
67
- useInput((input, key) => {
68
- if (!hasFocus)
69
- return;
70
- // Ctrl+, to open settings (from menu only)
71
- if (key.ctrl && input === "," && mode === "menu") {
72
- setMode("settings");
73
- return;
74
- }
75
- // 'L' to switch to logs view
76
- if ((input === "l" || input === "L") && mode !== "game" && mode !== "settings" && mode !== "stats") {
77
- setMode(mode === "logs" ? "menu" : "logs");
78
- return;
79
- }
80
- // 'Q' or Escape to go back to menu from logs
81
- if ((input === "q" || input === "Q") && mode === "logs") {
82
- setMode("menu");
83
- return;
84
- }
85
- }, { isActive: hasFocus && mode !== "game" && mode !== "settings" && mode !== "stats" });
86
- // Render based on current mode
87
- if (mode === "logs") {
88
- return (_jsxs(Box, { flexDirection: "column", height: "100%", children: [_jsxs(Box, { paddingX: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: colors.primary, children: "Live Logs" }), _jsx(Text, { dimColor: true, children: " | L: Back to Games | Q: Menu" })] }), _jsx(LogViewer, { logs: logs, hasFocus: hasFocus, initialViewMode: "condensed" })] }));
89
- }
90
- if (mode === "settings") {
91
- return (_jsx(SettingsMenu, { config: config, hasFocus: hasFocus, onConfigChange: onConfigChange, onSave: onConfigSave, onClose: handleCloseSettings }));
92
- }
93
- if (mode === "stats") {
94
- return (_jsx(StatsMenu, { hasFocus: hasFocus, onClose: handleCloseStats }));
95
- }
96
- if (mode === "game" && selectedGameId) {
97
- const gameEntry = getGameById(selectedGameId);
98
- if (gameEntry) {
99
- const GameComponent = gameEntry.component;
100
- return (_jsx(GameComponent, { hasFocus: hasFocus, dimensions: dimensions, onExit: handleExitGame, loopAttention: loopAttention, onLoopAlertDismiss: onLoopAlertDismiss, onGameStateChange: onGameStateChange }));
101
- }
102
- }
103
- // Default: show game selector menu
104
- return (_jsxs(Box, { flexDirection: "column", height: "100%", children: [_jsx(GameSelector, { games: games, hasFocus: hasFocus, dimensions: dimensions, onSelectGame: handleSelectGame, onOpenStats: handleOpenStats }), _jsx(Box, { paddingX: 1, children: _jsx(Text, { dimColor: true, children: "L: View Logs | Ctrl+,: Settings" }) })] }));
105
- }
106
- /** Header component */
107
- function Header() {
108
- const colors = useThemeColors();
109
- return (_jsxs(Box, { borderStyle: "round", borderColor: colors.primary, paddingX: 2, children: [_jsx(Text, { bold: true, color: colors.primary, children: "BRAINROT CLI" }), _jsx(Text, { children: " - " }), _jsx(Text, { children: "Play games while Claude Code works" })] }));
110
- }
111
- /** Status bar footer - needs to be inside GameStatusProvider */
112
- function StatusBarFooter({ loopStatus, needsAttention }) {
113
- return (_jsx(StatusBar, { loopStatus: loopStatus, needsAttention: needsAttention, condensed: true }));
114
- }
115
- function AppContent() {
116
- const { exit } = useApp();
117
- const { config: fileConfig } = useConfig();
118
- const cliOverrides = useCLIOverrides();
119
- const { addAchievements, NotificationComponent, hasNotifications } = useAchievementNotifications();
120
- // Local config state for live preview (before saving)
121
- const [localConfigOverrides, setLocalConfigOverrides] = useState({});
122
- // Record session start on mount
123
- useEffect(() => {
124
- void recordSessionStart();
125
- }, []);
126
- // Merge: file config -> local overrides -> CLI overrides (CLI takes precedence)
127
- const config = useMemo(() => deepMerge(deepMerge(fileConfig, localConfigOverrides), cliOverrides), [fileConfig, localConfigOverrides, cliOverrides]);
128
- // Handle config changes from settings menu (immediate preview)
129
- const handleConfigChange = useCallback((updates) => {
130
- setLocalConfigOverrides((prev) => deepMerge(prev, updates));
131
- }, []);
132
- // Handle saving config to disk
133
- const handleConfigSave = useCallback(async () => {
134
- // Merge current file config with local overrides and save
135
- const configToSave = deepMerge(fileConfig, localConfigOverrides);
136
- await saveConfig(configToSave);
137
- // Clear local overrides since they're now persisted
138
- setLocalConfigOverrides({});
139
- }, [fileConfig, localConfigOverrides]);
140
- // Get config-derived options
141
- const layoutOptions = useMemo(() => getLayoutOptions(config), [config]);
142
- const claudeCodeOptions = useMemo(() => getClaudeCodeOptions(config), [config]);
143
- const { status, output, spawn, stop } = useClaudeCode(claudeCodeOptions);
144
- const [focusedPane, setFocusedPane] = useState(0);
145
- const [loopAlertDismissed, setLoopAlertDismissed] = useState(false);
146
- const [showHelpOverlay, setShowHelpOverlay] = useState(false);
147
- const terminalSize = useTerminalSize();
148
- // Use Ralph loop parsing for the output
149
- const ralphLoop = useRalphLoopWithClaudeOutput(output);
150
- // Calculate game area dimensions (accounting for layout chrome)
151
- const gameDimensions = useMemo(() => {
152
- // Account for header (3), footer (2), help (1), borders, and split pane divider
153
- const availableHeight = Math.max(terminalSize.height - 8, 10);
154
- const availableWidth = Math.max(Math.floor(terminalSize.width * 0.5) - 4, 20);
155
- return { width: availableWidth, height: availableHeight };
156
- }, [terminalSize.width, terminalSize.height]);
157
- // Create loop attention object for games
158
- const loopAttention = useMemo(() => ({
159
- needsAttention: ralphLoop.needsAttention && !loopAlertDismissed,
160
- reason: ralphLoop.state.userAttention.reason,
161
- type: ralphLoop.state.userAttention.type,
162
- prompt: ralphLoop.state.userAttention.prompt,
163
- }), [ralphLoop.needsAttention, ralphLoop.state.userAttention, loopAlertDismissed]);
164
- // Reset dismiss state when attention changes
165
- const handleLoopAlertDismiss = useCallback(() => {
166
- setLoopAlertDismissed(true);
167
- }, []);
168
- // Toggle help overlay
169
- const handleToggleHelp = useCallback(() => {
170
- setShowHelpOverlay((prev) => !prev);
171
- }, []);
172
- // Close help overlay
173
- const handleCloseHelp = useCallback(() => {
174
- setShowHelpOverlay(false);
175
- }, []);
176
- // Reset dismiss state when a new attention request comes in
177
- useEffect(() => {
178
- if (ralphLoop.needsAttention) {
179
- setLoopAlertDismissed(false);
180
- }
181
- }, [ralphLoop.needsAttention, ralphLoop.state.userAttention.reason, ralphLoop.state.userAttention.prompt]);
182
- useInput((input, key) => {
183
- // Ctrl+C always works to exit
184
- if (key.ctrl && input === "c") {
185
- void stop().then(() => exit());
186
- return;
187
- }
188
- // Help overlay toggle with ? key (works globally)
189
- if (input === "?") {
190
- handleToggleHelp();
191
- return;
192
- }
193
- // When help overlay is shown, only handle escape and ? to close
194
- if (showHelpOverlay) {
195
- if (key.escape) {
196
- handleCloseHelp();
197
- }
198
- return;
199
- }
200
- if (key.ctrl && input === "s") {
201
- // Toggle start/stop with Ctrl+S
202
- if (status === "idle" || status === "stopped" || status === "crashed") {
203
- spawn();
204
- }
205
- else if (status === "running") {
206
- void stop();
207
- }
208
- return;
209
- }
210
- // Track focus changes via Tab key
211
- if (key.tab) {
212
- setFocusedPane((current) => (current === 0 ? 1 : 0));
213
- return;
214
- }
215
- });
216
- // Handler for game state updates from games
217
- const { setGameState } = useGameStatus();
218
- const handleGameStateChange = useCallback((update) => {
219
- setGameState(update);
220
- }, [setGameState]);
221
- // Determine effective loop status for status bar
222
- const effectiveLoopStatus = useMemo(() => {
223
- // If process is running, use ralph loop status, otherwise use process status
224
- if (status === "running") {
225
- return ralphLoop.state.status;
226
- }
227
- return status;
228
- }, [status, ralphLoop.state.status]);
229
- return (_jsxs(ThemeProvider, { config: config, children: [showHelpOverlay && (_jsx(Box, { position: "absolute", marginTop: 1, marginLeft: 2, children: _jsx(HelpOverlay, { hasFocus: showHelpOverlay, onClose: handleCloseHelp }) })), hasNotifications && (_jsx(Box, { position: "absolute", marginTop: 3, marginLeft: 5, children: NotificationComponent })), _jsx(Layout, { gameArea: _jsx(GameArea, { logs: output, hasFocus: focusedPane === 0 && !showHelpOverlay, dimensions: gameDimensions, loopAttention: loopAttention, onLoopAlertDismiss: handleLoopAlertDismiss, config: config, onConfigChange: handleConfigChange, onConfigSave: handleConfigSave, onAchievementUnlock: addAchievements, onGameStateChange: handleGameStateChange }), managementArea: _jsx(LoopManagementPanel, { loopState: ralphLoop.state, needsAttention: ralphLoop.needsAttention, statusMessage: ralphLoop.statusMessage, progressString: ralphLoop.progressString, processStatus: status, onStart: spawn, onStop: () => void stop() }), gameTitle: "Games", managementTitle: "Loop Management", header: _jsx(Header, {}), footer: _jsx(StatusBarFooter, { loopStatus: effectiveLoopStatus, needsAttention: ralphLoop.needsAttention }), layoutOptions: layoutOptions, handleInput: !showHelpOverlay })] }));
230
- }
231
- /** App wrapper that provides GameStatusProvider context */
232
- function App() {
233
- return (_jsx(GameStatusProvider, { children: _jsx(AppContent, {}) }));
234
- }
235
- // ============================================================================
236
- // CLI PARSING AND STARTUP
237
- // ============================================================================
9
+ import { render } from "ink";
10
+ import { parseCLI, printHelp, printVersion, printError } from "./cli.js";
11
+ import { AppNew } from "./AppNew.js";
238
12
  /**
239
13
  * Main entry point - parses CLI args and renders the app
240
14
  */
@@ -256,8 +30,8 @@ function main() {
256
30
  printVersion();
257
31
  process.exit(0);
258
32
  }
259
- // Render the app with CLI overrides
260
- render(_jsx(CLIOverridesContext.Provider, { value: args.overrides, children: _jsx(App, {}) }));
33
+ // Render the app
34
+ render(_jsx(AppNew, {}));
261
35
  }
262
36
  // Run main
263
37
  main();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":";;AACA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;GAEG;AACH,SAAS,IAAI;IACX,sBAAsB;IACtB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,CAAC;IAEnC,wBAAwB;IACxB,IAAI,KAAK,EAAE,CAAC;QACV,UAAU,CAAC,KAAK,CAAC,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,qBAAqB;IACrB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,wBAAwB;IACxB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,YAAY,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,iBAAiB;IACjB,MAAM,CAAC,KAAC,MAAM,KAAG,CAAC,CAAC;AACrB,CAAC;AAED,WAAW;AACX,IAAI,EAAE,CAAC"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Loop State Persistence
3
+ *
4
+ * Provides persistent storage for loop state including PRD content, tasks, and progress.
5
+ * State is stored in `.ralph-tui/loop-state.json` in the current working directory.
6
+ */
7
+ import type { RalphLoopStatus } from "./ralph-loop-parser.js";
8
+ /**
9
+ * Task status within the loop
10
+ */
11
+ export type TaskStatus = "pending" | "in_progress" | "completed" | "skipped";
12
+ /**
13
+ * Individual task in the loop
14
+ */
15
+ export interface LoopTask {
16
+ /** Unique task identifier */
17
+ id: string;
18
+ /** Task title */
19
+ title: string;
20
+ /** Task description */
21
+ description?: string;
22
+ /** Current task status */
23
+ status: TaskStatus;
24
+ /** ISO timestamp when task was completed */
25
+ completedAt?: string;
26
+ /** Task complexity */
27
+ complexity?: "small" | "medium" | "large";
28
+ /** Task dependencies (other task IDs) */
29
+ dependsOn?: string[];
30
+ }
31
+ /**
32
+ * PRD content structure
33
+ */
34
+ export interface PrdContent {
35
+ /** Feature/PRD name */
36
+ name: string;
37
+ /** Feature description */
38
+ description?: string;
39
+ /** Branch name for the feature */
40
+ branchName?: string;
41
+ /** Full PRD text content if available */
42
+ content?: string;
43
+ /** Raw PRD data */
44
+ raw?: unknown;
45
+ }
46
+ /**
47
+ * Loop progress tracking
48
+ */
49
+ export interface LoopProgress {
50
+ /** Total number of tasks */
51
+ totalTasks: number;
52
+ /** Number of completed tasks */
53
+ completedTasks: number;
54
+ /** Current task ID being worked on */
55
+ currentTaskId?: string;
56
+ /** Progress percentage (0-100) */
57
+ percentage: number;
58
+ }
59
+ /**
60
+ * Complete loop state structure
61
+ */
62
+ export interface LoopState {
63
+ /** State format version for migrations */
64
+ version: number;
65
+ /** Unique session identifier */
66
+ sessionId: string;
67
+ /** PRD content */
68
+ prd: PrdContent | null;
69
+ /** All tasks in the loop */
70
+ tasks: LoopTask[];
71
+ /** Loop progress summary */
72
+ progress: LoopProgress;
73
+ /** Current loop status */
74
+ loopStatus: RalphLoopStatus;
75
+ /** ISO timestamp when loop was started */
76
+ startedAt: string;
77
+ /** ISO timestamp of last update */
78
+ updatedAt: string;
79
+ /** Whether the loop is paused */
80
+ isPaused: boolean;
81
+ /** Working directory for the loop */
82
+ cwd: string;
83
+ }
84
+ /**
85
+ * Get the ralph-tui directory path
86
+ */
87
+ export declare function getLoopStateDir(cwd?: string): string;
88
+ /**
89
+ * Get the loop state file path
90
+ */
91
+ export declare function getLoopStateFilePath(cwd?: string): string;
92
+ /**
93
+ * Create a default/initial loop state
94
+ */
95
+ export declare function createDefaultLoopState(cwd?: string): LoopState;
96
+ /**
97
+ * Check if loop state file exists
98
+ */
99
+ export declare function loopStateExists(cwd?: string): boolean;
100
+ /**
101
+ * Load loop state from disk
102
+ * Returns default state if file doesn't exist or is invalid
103
+ */
104
+ export declare function loadLoopState(cwd?: string): Promise<LoopState>;
105
+ /**
106
+ * Save loop state to disk
107
+ */
108
+ export declare function saveLoopState(state: LoopState, cwd?: string): Promise<void>;
109
+ /**
110
+ * Update specific fields in loop state and save
111
+ */
112
+ export declare function updateLoopState(updates: Partial<Omit<LoopState, "version">>, cwd?: string): Promise<LoopState>;
113
+ /**
114
+ * Calculate progress from tasks
115
+ */
116
+ export declare function calculateProgress(tasks: LoopTask[]): LoopProgress;
117
+ /**
118
+ * Update a specific task's status and recalculate progress
119
+ */
120
+ export declare function updateTaskStatus(taskId: string, status: TaskStatus, cwd?: string): Promise<LoopState>;
121
+ /**
122
+ * Set PRD content and initialize tasks
123
+ */
124
+ export declare function setPrdAndTasks(prd: PrdContent, tasks: LoopTask[], cwd?: string): Promise<LoopState>;
125
+ /**
126
+ * Clear/reset loop state
127
+ */
128
+ export declare function clearLoopState(cwd?: string): Promise<LoopState>;
129
+ /**
130
+ * Check if there's an active loop (has tasks or PRD)
131
+ */
132
+ export declare function hasActiveLoop(state: LoopState): boolean;
133
+ /**
134
+ * Get a human-readable summary of loop progress
135
+ */
136
+ export declare function getProgressSummary(state: LoopState): string;
137
+ //# sourceMappingURL=loop-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop-state.d.ts","sourceRoot":"","sources":["../src/loop-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Loop State Persistence
3
+ *
4
+ * Provides persistent storage for loop state including PRD content, tasks, and progress.
5
+ * State is stored in `.ralph-tui/loop-state.json` in the current working directory.
6
+ */
7
+ import { join } from "node:path";
8
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
9
+ import { existsSync } from "node:fs";
10
+ // ============================================================================
11
+ // CONSTANTS
12
+ // ============================================================================
13
+ /** Directory for ralph-tui state files */
14
+ const RALPH_TUI_DIR = ".ralph-tui";
15
+ /** Loop state file name */
16
+ const LOOP_STATE_FILE = "loop-state.json";
17
+ /** Current state format version */
18
+ const STATE_VERSION = 1;
19
+ // ============================================================================
20
+ // PATH HELPERS
21
+ // ============================================================================
22
+ /**
23
+ * Get the ralph-tui directory path
24
+ */
25
+ export function getLoopStateDir(cwd = process.cwd()) {
26
+ return join(cwd, RALPH_TUI_DIR);
27
+ }
28
+ /**
29
+ * Get the loop state file path
30
+ */
31
+ export function getLoopStateFilePath(cwd = process.cwd()) {
32
+ return join(getLoopStateDir(cwd), LOOP_STATE_FILE);
33
+ }
34
+ // ============================================================================
35
+ // DEFAULT STATE
36
+ // ============================================================================
37
+ /**
38
+ * Generate a unique session ID
39
+ */
40
+ function generateSessionId() {
41
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
42
+ }
43
+ /**
44
+ * Create a default/initial loop state
45
+ */
46
+ export function createDefaultLoopState(cwd = process.cwd()) {
47
+ return {
48
+ version: STATE_VERSION,
49
+ sessionId: generateSessionId(),
50
+ prd: null,
51
+ tasks: [],
52
+ progress: {
53
+ totalTasks: 0,
54
+ completedTasks: 0,
55
+ percentage: 0,
56
+ },
57
+ loopStatus: "idle",
58
+ startedAt: new Date().toISOString(),
59
+ updatedAt: new Date().toISOString(),
60
+ isPaused: false,
61
+ cwd,
62
+ };
63
+ }
64
+ // ============================================================================
65
+ // FILE OPERATIONS
66
+ // ============================================================================
67
+ /**
68
+ * Ensure the ralph-tui directory exists
69
+ */
70
+ async function ensureLoopStateDir(cwd = process.cwd()) {
71
+ const dir = getLoopStateDir(cwd);
72
+ if (!existsSync(dir)) {
73
+ await mkdir(dir, { recursive: true });
74
+ }
75
+ }
76
+ /**
77
+ * Check if loop state file exists
78
+ */
79
+ export function loopStateExists(cwd = process.cwd()) {
80
+ return existsSync(getLoopStateFilePath(cwd));
81
+ }
82
+ /**
83
+ * Load loop state from disk
84
+ * Returns default state if file doesn't exist or is invalid
85
+ */
86
+ export async function loadLoopState(cwd = process.cwd()) {
87
+ const filePath = getLoopStateFilePath(cwd);
88
+ try {
89
+ if (!existsSync(filePath)) {
90
+ return createDefaultLoopState(cwd);
91
+ }
92
+ const content = await readFile(filePath, "utf-8");
93
+ const state = JSON.parse(content);
94
+ // Validate and migrate if needed
95
+ if (!state.version || state.version < STATE_VERSION) {
96
+ // Future: add migration logic here
97
+ // For now, merge with defaults
98
+ }
99
+ // Ensure all required fields are present
100
+ const defaultState = createDefaultLoopState(cwd);
101
+ return {
102
+ ...defaultState,
103
+ ...state,
104
+ // Ensure nested objects are properly merged
105
+ progress: {
106
+ ...defaultState.progress,
107
+ ...state.progress,
108
+ },
109
+ // Update the cwd to current
110
+ cwd,
111
+ };
112
+ }
113
+ catch {
114
+ // If file is corrupted or unreadable, return defaults
115
+ return createDefaultLoopState(cwd);
116
+ }
117
+ }
118
+ /**
119
+ * Save loop state to disk
120
+ */
121
+ export async function saveLoopState(state, cwd = process.cwd()) {
122
+ try {
123
+ await ensureLoopStateDir(cwd);
124
+ const stateToSave = {
125
+ ...state,
126
+ version: STATE_VERSION,
127
+ updatedAt: new Date().toISOString(),
128
+ };
129
+ const filePath = getLoopStateFilePath(cwd);
130
+ await writeFile(filePath, JSON.stringify(stateToSave, null, 2), "utf-8");
131
+ }
132
+ catch (error) {
133
+ // Log error but don't throw - state saving should be non-blocking
134
+ console.error("Failed to save loop state:", error);
135
+ }
136
+ }
137
+ /**
138
+ * Update specific fields in loop state and save
139
+ */
140
+ export async function updateLoopState(updates, cwd = process.cwd()) {
141
+ const current = await loadLoopState(cwd);
142
+ const updated = {
143
+ ...current,
144
+ ...updates,
145
+ // Deep merge progress if provided
146
+ progress: updates.progress
147
+ ? { ...current.progress, ...updates.progress }
148
+ : current.progress,
149
+ updatedAt: new Date().toISOString(),
150
+ };
151
+ await saveLoopState(updated, cwd);
152
+ return updated;
153
+ }
154
+ // ============================================================================
155
+ // STATE HELPERS
156
+ // ============================================================================
157
+ /**
158
+ * Calculate progress from tasks
159
+ */
160
+ export function calculateProgress(tasks) {
161
+ const totalTasks = tasks.length;
162
+ const completedTasks = tasks.filter((t) => t.status === "completed").length;
163
+ const currentTask = tasks.find((t) => t.status === "in_progress");
164
+ return {
165
+ totalTasks,
166
+ completedTasks,
167
+ currentTaskId: currentTask?.id,
168
+ percentage: totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0,
169
+ };
170
+ }
171
+ /**
172
+ * Update a specific task's status and recalculate progress
173
+ */
174
+ export async function updateTaskStatus(taskId, status, cwd = process.cwd()) {
175
+ const state = await loadLoopState(cwd);
176
+ const updatedTasks = state.tasks.map((task) => task.id === taskId
177
+ ? {
178
+ ...task,
179
+ status,
180
+ completedAt: status === "completed"
181
+ ? new Date().toISOString()
182
+ : task.completedAt,
183
+ }
184
+ : task);
185
+ return updateLoopState({
186
+ tasks: updatedTasks,
187
+ progress: calculateProgress(updatedTasks),
188
+ }, cwd);
189
+ }
190
+ /**
191
+ * Set PRD content and initialize tasks
192
+ */
193
+ export async function setPrdAndTasks(prd, tasks, cwd = process.cwd()) {
194
+ return updateLoopState({
195
+ prd,
196
+ tasks,
197
+ progress: calculateProgress(tasks),
198
+ }, cwd);
199
+ }
200
+ /**
201
+ * Clear/reset loop state
202
+ */
203
+ export async function clearLoopState(cwd = process.cwd()) {
204
+ const newState = createDefaultLoopState(cwd);
205
+ await saveLoopState(newState, cwd);
206
+ return newState;
207
+ }
208
+ /**
209
+ * Check if there's an active loop (has tasks or PRD)
210
+ */
211
+ export function hasActiveLoop(state) {
212
+ return state.prd !== null || state.tasks.length > 0;
213
+ }
214
+ /**
215
+ * Get a human-readable summary of loop progress
216
+ */
217
+ export function getProgressSummary(state) {
218
+ const { progress, prd } = state;
219
+ if (!prd && progress.totalTasks === 0) {
220
+ return "No active loop";
221
+ }
222
+ const taskProgress = progress.totalTasks > 0
223
+ ? `${progress.completedTasks}/${progress.totalTasks} tasks`
224
+ : "No tasks";
225
+ const percentage = progress.totalTasks > 0 ? ` (${progress.percentage}%)` : "";
226
+ return `${taskProgress}${percentage}`;
227
+ }
228
+ //# sourceMappingURL=loop-state.js.map