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
@@ -0,0 +1,66 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Feature Input Screen
4
+ *
5
+ * Clean, minimal first screen that asks the user for a feature description.
6
+ * This is the entry point for the new simplified UI flow.
7
+ */
8
+ import { Box, Text, useInput } from "ink";
9
+ import { useState, useCallback, useMemo } from "react";
10
+ import { useThemeColors } from "./useTheme.js";
11
+ import { navIcons } from "./theme.js";
12
+ // ============================================================================
13
+ // CONSTANTS
14
+ // ============================================================================
15
+ const MIN_CHARS = 10;
16
+ const EXAMPLES = [
17
+ "Create a REST API for user management",
18
+ "Fix the login bug on mobile",
19
+ "Add unit tests for the payment module",
20
+ ];
21
+ // ============================================================================
22
+ // COMPONENT
23
+ // ============================================================================
24
+ export function FeatureInput({ onSubmit, hasFocus, dimensions, }) {
25
+ const [inputValue, setInputValue] = useState("");
26
+ const [showError, setShowError] = useState(false);
27
+ const colors = useThemeColors();
28
+ const isValid = inputValue.length >= MIN_CHARS;
29
+ const handleSubmit = useCallback(() => {
30
+ if (isValid) {
31
+ onSubmit(inputValue.trim());
32
+ }
33
+ else {
34
+ setShowError(true);
35
+ }
36
+ }, [inputValue, isValid, onSubmit]);
37
+ // Handle keyboard input
38
+ useInput((input, key) => {
39
+ if (!hasFocus)
40
+ return;
41
+ // Enter to submit
42
+ if (key.return) {
43
+ handleSubmit();
44
+ return;
45
+ }
46
+ // Backspace/Delete to remove characters
47
+ if (key.backspace || key.delete) {
48
+ setInputValue((prev) => prev.slice(0, -1));
49
+ setShowError(false);
50
+ return;
51
+ }
52
+ // Printable characters (ignore control keys)
53
+ if (input && !key.ctrl && !key.meta && !key.escape) {
54
+ setInputValue((prev) => prev + input);
55
+ setShowError(false);
56
+ }
57
+ }, { isActive: hasFocus });
58
+ // Calculate input box width
59
+ const inputWidth = useMemo(() => {
60
+ return Math.min(55, dimensions.width - 8);
61
+ }, [dimensions.width]);
62
+ const cursorChar = "\u258c";
63
+ return (_jsxs(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", children: [_jsx(Box, { marginBottom: 2, children: _jsx(Text, { bold: true, color: colors.primary, children: "BRAINROT" }) }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: colors.border, paddingX: 2, paddingY: 1, width: inputWidth, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: colors.text, children: "What do you want to build?" }) }), _jsx(Box, { borderStyle: "single", borderColor: hasFocus ? colors.borderFocus : colors.border, paddingX: 1, minHeight: 3, children: inputValue ? (_jsxs(Text, { children: [_jsx(Text, { color: colors.text, children: inputValue }), _jsx(Text, { color: colors.primary, children: cursorChar })] })) : (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, italic: true, children: "Add dark mode support to the app" }), _jsx(Text, { color: colors.primary, children: cursorChar })] })) }), showError && !isValid && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.error, children: [navIcons.arrowRight, " Minimum ", MIN_CHARS, " characters required"] }) }))] }), _jsxs(Box, { flexDirection: "column", marginTop: 2, paddingX: 2, children: [_jsx(Text, { dimColor: true, children: "Examples:" }), EXAMPLES.map((example, i) => (_jsx(Box, { paddingLeft: 2, children: _jsxs(Text, { dimColor: true, children: [navIcons.bullet, " ", example] }) }, i)))] }), _jsx(Box, { position: "absolute", marginTop: dimensions.height - 2, borderStyle: "single", borderColor: colors.border, paddingX: 2, width: dimensions.width - 4, children: _jsxs(Text, { dimColor: true, children: [_jsx(Text, { color: colors.primary, children: "Enter" }), ": Submit |", " ", _jsx(Text, { color: colors.primary, children: "Ctrl+C" }), ": Quit |", " ", _jsx(Text, { color: colors.primary, children: "?" }), ": Help"] }) })] }));
64
+ }
65
+ export default FeatureInput;
66
+ //# sourceMappingURL=FeatureInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeatureInput.js","sourceRoot":"","sources":["../src/FeatureInput.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Feature Prompt Screen Component
3
+ *
4
+ * Full-screen modal that asks the user for a feature description.
5
+ * Part of the setup wizard flow after onboarding tutorial.
6
+ */
7
+ export interface FeaturePromptScreenProps {
8
+ /** Whether the screen is visible */
9
+ isVisible: boolean;
10
+ /** Callback when feature prompt is submitted */
11
+ onComplete: (prompt: string) => void;
12
+ /** Callback when user wants to go back */
13
+ onBack?: () => void;
14
+ /** Whether the component has focus */
15
+ hasFocus: boolean;
16
+ /** Terminal dimensions for centering */
17
+ dimensions?: {
18
+ width: number;
19
+ height: number;
20
+ };
21
+ }
22
+ export declare function FeaturePromptScreen({ isVisible, onComplete, onBack, hasFocus, dimensions, }: FeaturePromptScreenProps): import("react/jsx-runtime").JSX.Element | null;
23
+ export default FeaturePromptScreen;
24
+ //# sourceMappingURL=FeaturePromptScreen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeaturePromptScreen.d.ts","sourceRoot":"","sources":["../src/FeaturePromptScreen.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,WAAW,wBAAwB;IACvC,oCAAoC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,sCAAsC;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,wCAAwC;IACxC,UAAU,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD;AA2JD,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,UAAU,EACV,MAAM,EACN,QAAQ,EACR,UAAU,GACX,EAAE,wBAAwB,kDA+H1B;AAED,eAAe,mBAAmB,CAAC"}
@@ -0,0 +1,117 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Feature Prompt Screen Component
4
+ *
5
+ * Full-screen modal that asks the user for a feature description.
6
+ * Part of the setup wizard flow after onboarding tutorial.
7
+ */
8
+ import { Box, Text, useInput } from "ink";
9
+ import { useState, useCallback, useMemo } from "react";
10
+ import { useThemeColors } from "./useTheme.js";
11
+ import { navIcons, decorChars } from "./theme.js";
12
+ // ============================================================================
13
+ // CONSTANTS
14
+ // ============================================================================
15
+ const MIN_CHARS = 10;
16
+ const PLACEHOLDER_EXAMPLES = [
17
+ "Build a user authentication system with JWT",
18
+ "Create a REST API for task management",
19
+ "Implement a real-time chat feature",
20
+ "Add dark mode support to the UI",
21
+ ];
22
+ function InputDisplay({ value, colors, width }) {
23
+ const displayWidth = Math.max(width - 4, 30);
24
+ const cursorChar = "▌";
25
+ // Show placeholder when empty
26
+ if (!value) {
27
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { borderStyle: "single", borderColor: colors.borderFocus, paddingX: 1, width: displayWidth, children: [_jsx(Text, { dimColor: true, italic: true, children: PLACEHOLDER_EXAMPLES[0] }), _jsx(Text, { color: colors.primary, children: cursorChar })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, italic: true, children: "Examples:" }) }), PLACEHOLDER_EXAMPLES.slice(1).map((example, i) => (_jsx(Box, { paddingLeft: 2, children: _jsxs(Text, { dimColor: true, children: [navIcons.bullet, " ", example] }) }, i)))] }));
28
+ }
29
+ // Show input with cursor
30
+ // Wrap text if it exceeds display width
31
+ const maxTextWidth = displayWidth - 4; // Account for padding and cursor
32
+ const lines = [];
33
+ let remaining = value;
34
+ while (remaining.length > 0) {
35
+ if (remaining.length <= maxTextWidth) {
36
+ lines.push(remaining);
37
+ remaining = "";
38
+ }
39
+ else {
40
+ // Find a good break point (space) or just cut
41
+ const breakPoint = remaining.lastIndexOf(" ", maxTextWidth);
42
+ const cutPoint = breakPoint > maxTextWidth / 2 ? breakPoint : maxTextWidth;
43
+ lines.push(remaining.slice(0, cutPoint));
44
+ remaining = remaining.slice(cutPoint).trimStart();
45
+ }
46
+ }
47
+ return (_jsx(Box, { borderStyle: "single", borderColor: colors.borderFocus, paddingX: 1, width: displayWidth, flexDirection: "column", children: lines.map((line, i) => (_jsxs(Box, { children: [_jsx(Text, { color: colors.text, children: line }), i === lines.length - 1 && (_jsx(Text, { color: colors.primary, children: cursorChar }))] }, i))) }));
48
+ }
49
+ function ValidationMessage({ charCount, colors, showError, }) {
50
+ const remaining = MIN_CHARS - charCount;
51
+ const isValid = charCount >= MIN_CHARS;
52
+ return (_jsxs(Box, { marginTop: 1, justifyContent: "space-between", width: "100%", children: [_jsx(Box, { children: showError && !isValid && (_jsxs(Text, { color: colors.error, children: [navIcons.arrowRight, " Minimum ", MIN_CHARS, " characters required"] })) }), _jsx(Box, { children: _jsxs(Text, { color: isValid ? colors.success : colors.textMuted, children: [charCount, " / ", MIN_CHARS, isValid && " ✓", !isValid && ` (${remaining} more)`] }) })] }));
53
+ }
54
+ function NavigationHints({ colors, canSubmit, hasBack }) {
55
+ return (_jsxs(Box, { justifyContent: "center", marginTop: 2, children: [hasBack && _jsx(Text, { color: colors.textMuted, children: "Esc: Go Back | " }), _jsxs(Text, { color: canSubmit ? colors.primary : colors.textMuted, children: ["Enter: ", canSubmit ? "Submit" : "Need more text", " ", navIcons.arrowRight] })] }));
56
+ }
57
+ // ============================================================================
58
+ // MAIN COMPONENT
59
+ // ============================================================================
60
+ export function FeaturePromptScreen({ isVisible, onComplete, onBack, hasFocus, dimensions, }) {
61
+ const [inputValue, setInputValue] = useState("");
62
+ const [showError, setShowError] = useState(false);
63
+ const colors = useThemeColors();
64
+ const isValid = inputValue.length >= MIN_CHARS;
65
+ const handleSubmit = useCallback(() => {
66
+ if (isValid) {
67
+ onComplete(inputValue.trim());
68
+ }
69
+ else {
70
+ setShowError(true);
71
+ }
72
+ }, [inputValue, isValid, onComplete]);
73
+ const handleBack = useCallback(() => {
74
+ if (onBack) {
75
+ onBack();
76
+ }
77
+ }, [onBack]);
78
+ // Handle keyboard input
79
+ useInput((input, key) => {
80
+ if (!hasFocus || !isVisible)
81
+ return;
82
+ // Enter to submit
83
+ if (key.return) {
84
+ handleSubmit();
85
+ return;
86
+ }
87
+ // Escape to go back
88
+ if (key.escape) {
89
+ handleBack();
90
+ return;
91
+ }
92
+ // Backspace/Delete to remove characters
93
+ if (key.backspace || key.delete) {
94
+ setInputValue((prev) => prev.slice(0, -1));
95
+ setShowError(false);
96
+ return;
97
+ }
98
+ // Printable characters (ignore control keys)
99
+ if (input && !key.ctrl && !key.meta) {
100
+ setInputValue((prev) => prev + input);
101
+ setShowError(false);
102
+ }
103
+ }, { isActive: hasFocus && isVisible });
104
+ // Calculate box dimensions
105
+ const boxWidth = useMemo(() => {
106
+ if (dimensions?.width) {
107
+ return Math.min(70, dimensions.width - 4);
108
+ }
109
+ return 70;
110
+ }, [dimensions?.width]);
111
+ if (!isVisible) {
112
+ return null;
113
+ }
114
+ return (_jsxs(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", children: [_jsxs(Box, { flexDirection: "column", borderStyle: "double", borderColor: colors.primary, paddingX: 2, paddingY: 1, width: boxWidth, children: [_jsx(Box, { justifyContent: "center", marginBottom: 1, children: _jsxs(Text, { color: colors.secondary, bold: true, children: [decorChars.sparkle, " NEW FEATURE ", decorChars.sparkle] }) }), _jsx(Box, { justifyContent: "center", marginBottom: 2, children: _jsx(Text, { color: colors.primary, bold: true, children: "What feature do you want to build?" }) }), _jsx(Box, { flexDirection: "column", alignItems: "center", children: _jsx(InputDisplay, { value: inputValue, colors: colors, width: boxWidth }) }), _jsx(Box, { paddingX: 2, children: _jsx(ValidationMessage, { charCount: inputValue.length, colors: colors, showError: showError }) }), _jsx(NavigationHints, { colors: colors, canSubmit: isValid, hasBack: !!onBack })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, italic: true, children: "Be specific about what you want to achieve" }) })] }));
115
+ }
116
+ export default FeaturePromptScreen;
117
+ //# sourceMappingURL=FeaturePromptScreen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeaturePromptScreen.js","sourceRoot":"","sources":["../src/FeaturePromptScreen.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Game Select Screen
3
+ *
4
+ * Full-screen game picker that appears after Claude finishes planning.
5
+ * User selects a game, then the loop starts and they begin playing.
6
+ */
7
+ export interface GameSelectScreenProps {
8
+ /** Feature being built */
9
+ featureDescription: string;
10
+ /** Number of tasks planned */
11
+ taskCount: number;
12
+ /** Callback when user selects a game and starts the loop */
13
+ onSelectGame: (gameId: string) => void;
14
+ /** Whether the component has focus */
15
+ hasFocus: boolean;
16
+ /** Terminal dimensions */
17
+ dimensions: {
18
+ width: number;
19
+ height: number;
20
+ };
21
+ }
22
+ export declare function GameSelectScreen({ featureDescription, taskCount, onSelectGame, hasFocus, dimensions, }: GameSelectScreenProps): import("react/jsx-runtime").JSX.Element;
23
+ export default GameSelectScreen;
24
+ //# sourceMappingURL=GameSelectScreen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GameSelectScreen.d.ts","sourceRoot":"","sources":["../src/GameSelectScreen.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,MAAM,WAAW,qBAAqB;IACpC,0BAA0B;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,sCAAsC;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,0BAA0B;IAC1B,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAgDD,wBAAgB,gBAAgB,CAAC,EAC/B,kBAAkB,EAClB,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,UAAU,GACX,EAAE,qBAAqB,2CAsHvB;AAED,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,78 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * Game Select Screen
4
+ *
5
+ * Full-screen game picker that appears after Claude finishes planning.
6
+ * User selects a game, then the loop starts and they begin playing.
7
+ */
8
+ import { Box, Text, useInput } from "ink";
9
+ import { useState, useCallback, useMemo } from "react";
10
+ import { useThemeColors } from "./useTheme.js";
11
+ import { navIcons } from "./theme.js";
12
+ import { getGameList } from "./games/index.js";
13
+ function GameItem({ game, isSelected, colors }) {
14
+ const icon = getGameIcon(game.id);
15
+ return (_jsxs(Box, { flexDirection: "column", paddingY: 0, children: [_jsx(Box, { children: _jsxs(Text, { color: isSelected ? colors.primary : colors.text, bold: isSelected, children: [isSelected ? navIcons.arrowRight : " ", " ", icon, " ", game.name] }) }), _jsx(Box, { paddingLeft: 4, children: _jsx(Text, { dimColor: true, children: game.description }) })] }));
16
+ }
17
+ function getGameIcon(gameId) {
18
+ switch (gameId) {
19
+ case "snake":
20
+ return "\u{1F40D}"; // snake emoji
21
+ case "pong":
22
+ return "\u{1F3D3}"; // ping pong emoji
23
+ case "tetris":
24
+ return "\u{1F9F1}"; // brick emoji
25
+ case "minesweeper":
26
+ return "\u{1F4A3}"; // bomb emoji
27
+ default:
28
+ return "\u{1F3AE}"; // video game emoji
29
+ }
30
+ }
31
+ // ============================================================================
32
+ // MAIN COMPONENT
33
+ // ============================================================================
34
+ export function GameSelectScreen({ featureDescription, taskCount, onSelectGame, hasFocus, dimensions, }) {
35
+ const colors = useThemeColors();
36
+ const games = useMemo(() => getGameList(), []);
37
+ const [selectedIndex, setSelectedIndex] = useState(0);
38
+ const handleSelect = useCallback(() => {
39
+ const selectedGame = games[selectedIndex];
40
+ if (selectedGame) {
41
+ onSelectGame(selectedGame.id);
42
+ }
43
+ }, [games, selectedIndex, onSelectGame]);
44
+ // Handle keyboard input
45
+ useInput((input, key) => {
46
+ if (!hasFocus)
47
+ return;
48
+ // Arrow keys or j/k to navigate
49
+ if (key.upArrow || input === "k" || input === "K") {
50
+ setSelectedIndex((prev) => (prev > 0 ? prev - 1 : games.length - 1));
51
+ return;
52
+ }
53
+ if (key.downArrow || input === "j" || input === "J") {
54
+ setSelectedIndex((prev) => (prev < games.length - 1 ? prev + 1 : 0));
55
+ return;
56
+ }
57
+ // Enter or Space to select
58
+ if (key.return || input === " ") {
59
+ handleSelect();
60
+ return;
61
+ }
62
+ // Number keys for quick selection
63
+ const num = parseInt(input, 10);
64
+ if (num >= 1 && num <= games.length) {
65
+ setSelectedIndex(num - 1);
66
+ handleSelect();
67
+ }
68
+ }, { isActive: hasFocus });
69
+ // Calculate content width
70
+ const contentWidth = useMemo(() => {
71
+ return Math.min(55, dimensions.width - 8);
72
+ }, [dimensions.width]);
73
+ return (_jsxs(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: colors.primary, children: "BRAINROT" }) }), _jsxs(Box, { flexDirection: "column", alignItems: "center", marginBottom: 2, children: [_jsx(Text, { color: colors.success, children: "Claude is ready to start working!" }), _jsx(Text, { dimColor: true, children: "Pick a game to play while you wait." })] }), _jsx(Box, { flexDirection: "column", borderStyle: "round", borderColor: colors.border, paddingX: 2, paddingY: 1, width: contentWidth, children: games.map((game, index) => (_jsx(GameItem, { game: game, isSelected: index === selectedIndex, colors: colors }, game.id))) }), _jsxs(Box, { flexDirection: "column", alignItems: "center", marginTop: 2, children: [_jsxs(Text, { dimColor: true, children: ["Task: \"", featureDescription.length > 35
74
+ ? featureDescription.slice(0, 35) + "..."
75
+ : featureDescription, "\""] }), _jsxs(Text, { dimColor: true, children: [taskCount, " task", taskCount !== 1 ? "s" : "", " planned ", navIcons.bullet, " Ready to start"] })] }), _jsx(Box, { position: "absolute", marginTop: dimensions.height - 2, borderStyle: "single", borderColor: colors.border, paddingX: 2, width: dimensions.width - 4, children: _jsxs(Text, { dimColor: true, children: [_jsx(Text, { color: colors.primary, children: "\u2191\u2193" }), ": Navigate |", " ", _jsx(Text, { color: colors.primary, children: "Enter" }), ": Start Loop & Play |", " ", _jsx(Text, { color: colors.primary, children: "?" }), ": Help"] }) })] }));
76
+ }
77
+ export default GameSelectScreen;
78
+ //# sourceMappingURL=GameSelectScreen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GameSelectScreen.js","sourceRoot":"","sources":["../src/GameSelectScreen.tsx"],"names":[],"mappings":"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"}
@@ -16,10 +16,18 @@ export interface GameSelectorProps {
16
16
  onSelectGame: (gameId: string) => void;
17
17
  /** Callback when stats menu is requested */
18
18
  onOpenStats?: () => void;
19
+ /** Whether games are enabled (unlocked after loop start) */
20
+ gamesEnabled?: boolean;
21
+ /** Whether a loop is currently active */
22
+ hasActiveLoop?: boolean;
23
+ /** Callback when Start New Loop is selected */
24
+ onStartNewLoop?: () => void;
25
+ /** Callback when View Current Loop is selected */
26
+ onViewCurrentLoop?: () => void;
19
27
  }
20
28
  /**
21
29
  * Game selector menu component
22
30
  */
23
- export declare function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpenStats, }: GameSelectorProps): import("react/jsx-runtime").JSX.Element;
31
+ export declare function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpenStats, gamesEnabled, hasActiveLoop, onStartNewLoop, onViewCurrentLoop, }: GameSelectorProps): import("react/jsx-runtime").JSX.Element;
24
32
  export default GameSelector;
25
33
  //# sourceMappingURL=GameSelector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GameSelector.d.ts","sourceRoot":"","sources":["../src/GameSelector.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKhE,MAAM,WAAW,iBAAiB;IAChC,qCAAqC;IACrC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,EAAE,OAAO,CAAC;IAClB,2BAA2B;IAC3B,UAAU,EAAE,cAAc,CAAC;IAC3B,uCAAuC;IACvC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAgHD;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,WAAW,GACZ,EAAE,iBAAiB,2CA8GnB;AAED,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"GameSelector.d.ts","sourceRoot":"","sources":["../src/GameSelector.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKhE,MAAM,WAAW,iBAAiB;IAChC,qCAAqC;IACrC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,EAAE,OAAO,CAAC;IAClB,2BAA2B;IAC3B,UAAU,EAAE,cAAc,CAAC;IAC3B,uCAAuC;IACvC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,yCAAyC;IACzC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,kDAAkD;IAClD,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;CAChC;AAuLD;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAmB,EACnB,aAAqB,EACrB,cAAc,EACd,iBAAiB,GAClB,EAAE,iBAAiB,2CAsMnB;AAED,eAAe,YAAY,CAAC"}
@@ -1,4 +1,4 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  /**
3
3
  * GameSelector Component
4
4
  *
@@ -10,13 +10,26 @@ import { useState, useCallback, useEffect } from "react";
10
10
  import { navIcons } from "./theme.js";
11
11
  import { useThemeColors } from "./useTheme.js";
12
12
  import { getAchievementCount } from "./stats.js";
13
- function GameCard({ game, isSelected, isHighlighted, dimensions }) {
13
+ function GameCard({ game, isSelected, isHighlighted, dimensions, isDisabled = false, }) {
14
14
  const colors = useThemeColors();
15
- const borderColor = isHighlighted ? colors.primary : isSelected ? colors.accent : colors.border;
16
- const titleColor = isHighlighted ? colors.primary : isSelected ? colors.accent : colors.text;
15
+ // When disabled, use muted colors; otherwise use normal highlight colors
16
+ const borderColor = isDisabled
17
+ ? colors.border
18
+ : isHighlighted
19
+ ? colors.primary
20
+ : isSelected
21
+ ? colors.accent
22
+ : colors.border;
23
+ const titleColor = isDisabled
24
+ ? colors.textMuted
25
+ : isHighlighted
26
+ ? colors.primary
27
+ : isSelected
28
+ ? colors.accent
29
+ : colors.text;
17
30
  // Calculate card width based on available space
18
31
  const cardWidth = Math.min(Math.max(dimensions.width - 4, 30), 50);
19
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: borderColor, paddingX: 1, width: cardWidth, children: [_jsx(Box, { children: _jsxs(Text, { bold: true, color: titleColor, children: [isHighlighted ? `${navIcons.arrowRight} ` : " ", game.name] }) }), _jsx(Text, { dimColor: true, wrap: "truncate", children: game.description }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.textMuted, children: "Controls: " }), _jsx(Text, { dimColor: true, children: game.controls })] }), game.minWidth && game.minHeight && (_jsxs(Text, { dimColor: true, children: ["Min size: ", game.minWidth, "x", game.minHeight] }))] }));
32
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: borderColor, paddingX: 1, width: cardWidth, children: [_jsx(Box, { children: _jsxs(Text, { bold: true, color: titleColor, children: [isHighlighted ? `${navIcons.arrowRight} ` : " ", isDisabled ? "🔒 " : "", game.name] }) }), _jsx(Text, { dimColor: true, wrap: "truncate", children: game.description }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.textMuted, children: "Controls: " }), _jsx(Text, { dimColor: true, children: game.controls })] }), game.minWidth && game.minHeight && (_jsxs(Text, { dimColor: true, children: ["Min size: ", game.minWidth, "x", game.minHeight] }))] }));
20
33
  }
21
34
  function SelectorHeader({ hasFocus }) {
22
35
  const colors = useThemeColors();
@@ -24,13 +37,25 @@ function SelectorHeader({ hasFocus }) {
24
37
  ? "↑/↓: Navigate | Enter: Select | S: Stats | Q: Back"
25
38
  : "Press Tab to focus game selector" })] }));
26
39
  }
27
- function StatsMenuCard({ isHighlighted, dimensions, achievementCount }) {
40
+ function StatsMenuCard({ isHighlighted, dimensions, achievementCount, }) {
28
41
  const colors = useThemeColors();
29
42
  const borderColor = isHighlighted ? colors.warning : colors.border;
30
43
  const titleColor = isHighlighted ? colors.warning : colors.textMuted;
31
44
  const cardWidth = Math.min(Math.max(dimensions.width - 4, 30), 50);
32
45
  return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: borderColor, paddingX: 1, width: cardWidth, children: [_jsx(Box, { children: _jsxs(Text, { bold: true, color: titleColor, children: [isHighlighted ? `${navIcons.arrowRight} ` : " ", "Stats & Achievements"] }) }), _jsx(Text, { dimColor: true, children: "View your gameplay statistics and unlock achievements" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.textMuted, children: "Progress: " }), _jsxs(Text, { color: colors.success, children: [achievementCount.unlocked, "/", achievementCount.total, " achievements"] })] })] }));
33
46
  }
47
+ function LoopMenuCard({ isHighlighted, dimensions, hasActiveLoop, }) {
48
+ const colors = useThemeColors();
49
+ const borderColor = isHighlighted ? colors.success : colors.border;
50
+ const titleColor = isHighlighted ? colors.success : colors.text;
51
+ const cardWidth = Math.min(Math.max(dimensions.width - 4, 30), 50);
52
+ const title = hasActiveLoop ? "View Current Loop" : "Start New Loop";
53
+ const description = hasActiveLoop
54
+ ? "View progress on your current feature development loop"
55
+ : "Begin a new feature development loop with Claude";
56
+ const icon = hasActiveLoop ? "📋" : "🚀";
57
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: borderColor, paddingX: 1, width: cardWidth, children: [_jsx(Box, { children: _jsxs(Text, { bold: true, color: titleColor, children: [isHighlighted ? `${navIcons.arrowRight} ` : " ", icon, " ", title] }) }), _jsx(Text, { dimColor: true, children: description }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.textMuted, children: "Shortcut: " }), _jsx(Text, { dimColor: true, children: "N" })] })] }));
58
+ }
34
59
  function EmptyState() {
35
60
  const colors = useThemeColors();
36
61
  return (_jsxs(Box, { flexDirection: "column", padding: 2, children: [_jsx(Text, { color: colors.accent, children: "No games available" }), _jsx(Text, { dimColor: true, children: "Check back later for new games!" })] }));
@@ -38,12 +63,20 @@ function EmptyState() {
38
63
  /**
39
64
  * Game selector menu component
40
65
  */
41
- export function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpenStats, }) {
66
+ export function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpenStats, gamesEnabled = true, hasActiveLoop = false, onStartNewLoop, onViewCurrentLoop, }) {
42
67
  const [selectedIndex, setSelectedIndex] = useState(0);
43
- const [achievementCount, setAchievementCount] = useState({ unlocked: 0, total: 0 });
44
- // Total items: games + stats menu
45
- const totalItems = games.length + 1;
46
- const statsIndex = games.length; // Stats is always last
68
+ const [achievementCount, setAchievementCount] = useState({
69
+ unlocked: 0,
70
+ total: 0,
71
+ });
72
+ const [showLockedMessage, setShowLockedMessage] = useState(false);
73
+ const colors = useThemeColors();
74
+ // Menu structure: [Loop option] + [Games] + [Stats]
75
+ // Loop option is always at index 0
76
+ const loopIndex = 0;
77
+ const firstGameIndex = 1;
78
+ const statsIndex = games.length + 1; // Stats is always last
79
+ const totalItems = games.length + 2; // Loop option + games + stats
47
80
  // Load achievement count
48
81
  useEffect(() => {
49
82
  const loadCount = async () => {
@@ -52,14 +85,53 @@ export function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpen
52
85
  };
53
86
  void loadCount();
54
87
  }, []);
88
+ // Clear the locked message after a timeout
89
+ useEffect(() => {
90
+ if (showLockedMessage) {
91
+ const timer = setTimeout(() => {
92
+ setShowLockedMessage(false);
93
+ }, 2000);
94
+ return () => clearTimeout(timer);
95
+ }
96
+ return undefined;
97
+ }, [showLockedMessage]);
55
98
  const handleSelect = useCallback(() => {
56
- if (selectedIndex === statsIndex) {
99
+ if (selectedIndex === loopIndex) {
100
+ // Loop option - first item
101
+ if (hasActiveLoop) {
102
+ onViewCurrentLoop?.();
103
+ }
104
+ else {
105
+ onStartNewLoop?.();
106
+ }
107
+ }
108
+ else if (selectedIndex === statsIndex) {
109
+ // Stats is always accessible
57
110
  onOpenStats?.();
58
111
  }
59
- else if (games.length > 0 && games[selectedIndex]) {
60
- onSelectGame(games[selectedIndex].id);
112
+ else {
113
+ // Game selection (indices are offset by 1 due to loop option)
114
+ const gameIndex = selectedIndex - firstGameIndex;
115
+ if (games.length > 0 && games[gameIndex]) {
116
+ // Check if games are enabled
117
+ if (!gamesEnabled) {
118
+ setShowLockedMessage(true);
119
+ return;
120
+ }
121
+ onSelectGame(games[gameIndex].id);
122
+ }
61
123
  }
62
- }, [games, selectedIndex, onSelectGame, onOpenStats, statsIndex]);
124
+ }, [
125
+ games,
126
+ selectedIndex,
127
+ onSelectGame,
128
+ onOpenStats,
129
+ statsIndex,
130
+ gamesEnabled,
131
+ hasActiveLoop,
132
+ onStartNewLoop,
133
+ onViewCurrentLoop,
134
+ ]);
63
135
  useInput((input, key) => {
64
136
  if (!hasFocus)
65
137
  return;
@@ -83,11 +155,29 @@ export function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpen
83
155
  onOpenStats?.();
84
156
  return;
85
157
  }
158
+ // Quick trigger loop option with N key
159
+ if (input === "n" || input === "N") {
160
+ setSelectedIndex(loopIndex);
161
+ if (hasActiveLoop) {
162
+ onViewCurrentLoop?.();
163
+ }
164
+ else {
165
+ onStartNewLoop?.();
166
+ }
167
+ return;
168
+ }
86
169
  // Quick select game by number (1-9)
87
170
  const num = parseInt(input, 10);
88
171
  if (!isNaN(num) && num >= 1 && num <= games.length) {
89
- setSelectedIndex(num - 1);
172
+ // Map number to game index (account for loop option at index 0)
173
+ const gameMenuIndex = num - 1 + firstGameIndex;
174
+ setSelectedIndex(gameMenuIndex);
90
175
  if (games[num - 1]) {
176
+ // Check if games are enabled before quick-selecting
177
+ if (!gamesEnabled) {
178
+ setShowLockedMessage(true);
179
+ return;
180
+ }
91
181
  onSelectGame(games[num - 1].id);
92
182
  }
93
183
  return;
@@ -97,9 +187,16 @@ export function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpen
97
187
  if (selectedIndex >= totalItems && totalItems > 0) {
98
188
  setSelectedIndex(totalItems - 1);
99
189
  }
100
- return (_jsxs(Box, { flexDirection: "column", padding: 1, height: "100%", children: [_jsx(SelectorHeader, { hasFocus: hasFocus }), games.length === 0 ? (_jsx(EmptyState, {})) : (_jsxs(Box, { flexDirection: "column", gap: 1, children: [games.map((game, index) => (_jsx(GameCard, { game: game, isSelected: index === selectedIndex, isHighlighted: hasFocus && index === selectedIndex, dimensions: dimensions }, game.id))), _jsx(StatsMenuCard, { isHighlighted: hasFocus && selectedIndex === statsIndex, dimensions: dimensions, achievementCount: achievementCount })] })), totalItems > 0 && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: selectedIndex === statsIndex
101
- ? "Stats & Achievements"
102
- : `Game ${selectedIndex + 1} of ${games.length}` }) }))] }));
190
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, height: "100%", children: [_jsx(SelectorHeader, { hasFocus: hasFocus }), showLockedMessage && (_jsx(Box, { marginBottom: 1, paddingX: 1, children: _jsx(Text, { color: colors.warning, children: "\uD83D\uDD12 Start a loop to unlock games!" }) })), _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(LoopMenuCard, { isHighlighted: hasFocus && selectedIndex === loopIndex, dimensions: dimensions, hasActiveLoop: hasActiveLoop }), games.length === 0 ? (_jsx(EmptyState, {})) : (_jsx(_Fragment, { children: games.map((game, index) => {
191
+ const menuIndex = index + firstGameIndex;
192
+ return (_jsx(GameCard, { game: game, isSelected: menuIndex === selectedIndex, isHighlighted: hasFocus && menuIndex === selectedIndex, dimensions: dimensions, isDisabled: !gamesEnabled }, game.id));
193
+ }) })), _jsx(StatsMenuCard, { isHighlighted: hasFocus && selectedIndex === statsIndex, dimensions: dimensions, achievementCount: achievementCount })] }), totalItems > 0 && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: selectedIndex === loopIndex
194
+ ? hasActiveLoop
195
+ ? "View Current Loop"
196
+ : "Start New Loop"
197
+ : selectedIndex === statsIndex
198
+ ? "Stats & Achievements"
199
+ : `Game ${selectedIndex - firstGameIndex + 1} of ${games.length}` }) }))] }));
103
200
  }
104
201
  export default GameSelector;
105
202
  //# sourceMappingURL=GameSelector.js.map