brainrot-cli 0.1.1 → 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 (49) hide show
  1. package/dist/AppNew.d.ts +11 -0
  2. package/dist/AppNew.d.ts.map +1 -0
  3. package/dist/AppNew.js +437 -0
  4. package/dist/AppNew.js.map +1 -0
  5. package/dist/AttentionOverlay.d.ts +28 -0
  6. package/dist/AttentionOverlay.d.ts.map +1 -0
  7. package/dist/AttentionOverlay.js +92 -0
  8. package/dist/AttentionOverlay.js.map +1 -0
  9. package/dist/ClaudeChat.d.ts +38 -0
  10. package/dist/ClaudeChat.d.ts.map +1 -0
  11. package/dist/ClaudeChat.js +81 -0
  12. package/dist/ClaudeChat.js.map +1 -0
  13. package/dist/FeatureInput.d.ts +20 -0
  14. package/dist/FeatureInput.d.ts.map +1 -0
  15. package/dist/FeatureInput.js +66 -0
  16. package/dist/FeatureInput.js.map +1 -0
  17. package/dist/GameSelectScreen.d.ts +24 -0
  18. package/dist/GameSelectScreen.d.ts.map +1 -0
  19. package/dist/GameSelectScreen.js +78 -0
  20. package/dist/GameSelectScreen.js.map +1 -0
  21. package/dist/GameSelectorOverlay.d.ts +21 -0
  22. package/dist/GameSelectorOverlay.d.ts.map +1 -0
  23. package/dist/GameSelectorOverlay.js +98 -0
  24. package/dist/GameSelectorOverlay.js.map +1 -0
  25. package/dist/LoopComplete.d.ts +42 -0
  26. package/dist/LoopComplete.d.ts.map +1 -0
  27. package/dist/LoopComplete.js +69 -0
  28. package/dist/LoopComplete.js.map +1 -0
  29. package/dist/ResumePrompt.d.ts +32 -0
  30. package/dist/ResumePrompt.d.ts.map +1 -0
  31. package/dist/ResumePrompt.js +65 -0
  32. package/dist/ResumePrompt.js.map +1 -0
  33. package/dist/SidePanel.d.ts +26 -0
  34. package/dist/SidePanel.d.ts.map +1 -0
  35. package/dist/SidePanel.js +90 -0
  36. package/dist/SidePanel.js.map +1 -0
  37. package/dist/StatusBarMinimal.d.ts +26 -0
  38. package/dist/StatusBarMinimal.d.ts.map +1 -0
  39. package/dist/StatusBarMinimal.js +111 -0
  40. package/dist/StatusBarMinimal.js.map +1 -0
  41. package/dist/config.d.ts +11 -0
  42. package/dist/config.d.ts.map +1 -1
  43. package/dist/config.js +12 -0
  44. package/dist/config.js.map +1 -1
  45. package/dist/index.d.ts +6 -0
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +10 -449
  48. package/dist/index.js.map +1 -1
  49. package/package.json +3 -2
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Claude Chat Component
3
+ *
4
+ * Displays Claude's planning questions and captures user answers.
5
+ * Used during the "plan mode" phase where Claude asks clarifying questions.
6
+ */
7
+ export interface ChatMessage {
8
+ /** Message role */
9
+ role: "assistant" | "user";
10
+ /** Message content */
11
+ content: string;
12
+ /** Whether this message is waiting for user input */
13
+ isWaitingForInput?: boolean;
14
+ }
15
+ export interface ClaudeChatProps {
16
+ /** Feature being planned */
17
+ featureDescription: string;
18
+ /** Chat messages */
19
+ messages: ChatMessage[];
20
+ /** Whether Claude is currently thinking */
21
+ isThinking: boolean;
22
+ /** Progress percentage (0-100) */
23
+ progress: number;
24
+ /** Callback when user submits an answer */
25
+ onSubmitAnswer: (answer: string) => void;
26
+ /** Callback to cancel planning */
27
+ onCancel: () => void;
28
+ /** Whether the component has focus */
29
+ hasFocus: boolean;
30
+ /** Terminal dimensions */
31
+ dimensions: {
32
+ width: number;
33
+ height: number;
34
+ };
35
+ }
36
+ export declare function ClaudeChat({ featureDescription, messages, isThinking, progress, onSubmitAnswer, onCancel, hasFocus, dimensions, }: ClaudeChatProps): import("react/jsx-runtime").JSX.Element;
37
+ export default ClaudeChat;
38
+ //# sourceMappingURL=ClaudeChat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClaudeChat.d.ts","sourceRoot":"","sources":["../src/ClaudeChat.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,WAAW,WAAW;IAC1B,mBAAmB;IACnB,IAAI,EAAE,WAAW,GAAG,MAAM,CAAC;IAC3B,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,4BAA4B;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB;IACpB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,2CAA2C;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,kCAAkC;IAClC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,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;AAMD,wBAAgB,UAAU,CAAC,EACzB,kBAAkB,EAClB,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,UAAU,GACX,EAAE,eAAe,2CAkMjB;AAED,eAAe,UAAU,CAAC"}
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * Claude Chat Component
4
+ *
5
+ * Displays Claude's planning questions and captures user answers.
6
+ * Used during the "plan mode" phase where Claude asks clarifying questions.
7
+ */
8
+ import { Box, Text, useInput } from "ink";
9
+ import { useState, useCallback, useMemo, useEffect } from "react";
10
+ import { useThemeColors } from "./useTheme.js";
11
+ import { Spinner, ProgressBar } from "./styled-components.js";
12
+ // ============================================================================
13
+ // COMPONENT
14
+ // ============================================================================
15
+ export function ClaudeChat({ featureDescription, messages, isThinking, progress, onSubmitAnswer, onCancel, hasFocus, dimensions, }) {
16
+ const [inputValue, setInputValue] = useState("");
17
+ const [elapsedMs, setElapsedMs] = useState(0);
18
+ const colors = useThemeColors();
19
+ // Animate spinner
20
+ useEffect(() => {
21
+ if (!isThinking)
22
+ return;
23
+ const interval = setInterval(() => {
24
+ setElapsedMs((prev) => prev + 100);
25
+ }, 100);
26
+ return () => clearInterval(interval);
27
+ }, [isThinking]);
28
+ // Check if we're waiting for user input
29
+ const isWaitingForInput = useMemo(() => {
30
+ const lastMessage = messages[messages.length - 1];
31
+ return lastMessage?.role === "assistant" && lastMessage?.isWaitingForInput;
32
+ }, [messages]);
33
+ const handleSubmit = useCallback(() => {
34
+ if (inputValue.trim() && isWaitingForInput) {
35
+ onSubmitAnswer(inputValue.trim());
36
+ setInputValue("");
37
+ }
38
+ }, [inputValue, isWaitingForInput, onSubmitAnswer]);
39
+ // Handle keyboard input
40
+ useInput((input, key) => {
41
+ if (!hasFocus)
42
+ return;
43
+ // Escape to cancel
44
+ if (key.escape) {
45
+ onCancel();
46
+ return;
47
+ }
48
+ // Only handle input when waiting for user response
49
+ if (!isWaitingForInput)
50
+ return;
51
+ // Enter to submit
52
+ if (key.return) {
53
+ handleSubmit();
54
+ return;
55
+ }
56
+ // Backspace/Delete to remove characters
57
+ if (key.backspace || key.delete) {
58
+ setInputValue((prev) => prev.slice(0, -1));
59
+ return;
60
+ }
61
+ // Printable characters (ignore control keys)
62
+ if (input && !key.ctrl && !key.meta) {
63
+ setInputValue((prev) => prev + input);
64
+ }
65
+ }, { isActive: hasFocus });
66
+ // Calculate content width
67
+ const contentWidth = useMemo(() => {
68
+ return Math.min(70, dimensions.width - 4);
69
+ }, [dimensions.width]);
70
+ // Calculate available height for messages
71
+ const messagesHeight = useMemo(() => {
72
+ // Header (3) + Progress (2) + Input (4) + Footer (2) + margins
73
+ return Math.max(dimensions.height - 14, 5);
74
+ }, [dimensions.height]);
75
+ const cursorChar = "\u258c";
76
+ return (_jsxs(Box, { flexDirection: "column", width: "100%", height: "100%", paddingX: 1, children: [_jsxs(Box, { borderStyle: "single", borderColor: colors.primary, paddingX: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, color: colors.primary, children: "BRAINROT" }), _jsx(Text, { children: " | Planning: " }), _jsx(Text, { color: colors.text, children: featureDescription.length > 40
77
+ ? featureDescription.slice(0, 40) + "..."
78
+ : featureDescription })] }), _jsx(Box, { flexDirection: "column", borderStyle: "round", borderColor: colors.border, paddingX: 2, paddingY: 1, height: messagesHeight, width: contentWidth, overflow: "hidden", children: isThinking && messages.length === 0 ? (_jsx(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", height: "100%", children: _jsx(Spinner, { elapsedMs: elapsedMs, label: "Claude is analyzing your request..." }) })) : (_jsxs(Box, { flexDirection: "column", children: [messages.map((msg, idx) => (_jsx(Box, { flexDirection: "column", marginBottom: 1, children: msg.role === "assistant" ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.info, children: "Claude:" }), _jsx(Box, { paddingLeft: 2, children: _jsx(Text, { color: colors.text, children: msg.content }) })] })) : (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.success, children: "You:" }), _jsx(Box, { paddingLeft: 2, children: _jsx(Text, { dimColor: true, children: msg.content }) })] })) }, idx))), isThinking && messages.length > 0 && (_jsx(Box, { marginTop: 1, children: _jsx(Spinner, { elapsedMs: elapsedMs, label: "Thinking..." }) }))] })) }), isWaitingForInput && (_jsx(Box, { flexDirection: "column", marginTop: 1, width: contentWidth, children: _jsx(Box, { borderStyle: "single", borderColor: hasFocus ? colors.borderFocus : colors.border, paddingX: 1, children: _jsxs(Text, { color: colors.text, children: [inputValue, _jsx(Text, { color: colors.primary, children: cursorChar })] }) }) })), _jsxs(Box, { marginTop: 1, width: contentWidth, children: [_jsx(ProgressBar, { percentage: progress, width: contentWidth - 10, showLabel: true }), _jsx(Text, { dimColor: true, children: " Planning..." })] }), _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: [isWaitingForInput ? (_jsxs(_Fragment, { children: [_jsx(Text, { color: colors.primary, children: "Enter" }), ": Submit answer |", " "] })) : null, _jsx(Text, { color: colors.primary, children: "Ctrl+C" }), ": Cancel |", " ", _jsx(Text, { color: colors.primary, children: "?" }), ": Help"] }) })] }));
79
+ }
80
+ export default ClaudeChat;
81
+ //# sourceMappingURL=ClaudeChat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClaudeChat.js","sourceRoot":"","sources":["../src/ClaudeChat.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Feature Input Screen
3
+ *
4
+ * Clean, minimal first screen that asks the user for a feature description.
5
+ * This is the entry point for the new simplified UI flow.
6
+ */
7
+ export interface FeatureInputProps {
8
+ /** Callback when feature is submitted */
9
+ onSubmit: (feature: string) => void;
10
+ /** Whether the component has focus */
11
+ hasFocus: boolean;
12
+ /** Terminal dimensions */
13
+ dimensions: {
14
+ width: number;
15
+ height: number;
16
+ };
17
+ }
18
+ export declare function FeatureInput({ onSubmit, hasFocus, dimensions, }: FeatureInputProps): import("react/jsx-runtime").JSX.Element;
19
+ export default FeatureInput;
20
+ //# sourceMappingURL=FeatureInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeatureInput.d.ts","sourceRoot":"","sources":["../src/FeatureInput.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,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;AAkBD,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,QAAQ,EACR,UAAU,GACX,EAAE,iBAAiB,2CA2InB;AAED,eAAe,YAAY,CAAC"}
@@ -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
+ * 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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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Game Selector Overlay
3
+ *
4
+ * Modal overlay for switching games during the loop.
5
+ * Triggered by pressing G key while playing.
6
+ */
7
+ export interface GameSelectorOverlayProps {
8
+ /** Currently playing game ID */
9
+ currentGameId: string | null;
10
+ /** Callback when user selects a game */
11
+ onSelectGame: (gameId: string) => void;
12
+ /** Callback when user wants to view stats */
13
+ onViewStats: () => void;
14
+ /** Callback when overlay is closed */
15
+ onClose: () => void;
16
+ /** Whether the component has focus */
17
+ hasFocus: boolean;
18
+ }
19
+ export declare function GameSelectorOverlay({ currentGameId, onSelectGame, onViewStats, onClose, hasFocus, }: GameSelectorOverlayProps): import("react/jsx-runtime").JSX.Element;
20
+ export default GameSelectorOverlay;
21
+ //# sourceMappingURL=GameSelectorOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GameSelectorOverlay.d.ts","sourceRoot":"","sources":["../src/GameSelectorOverlay.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,MAAM,WAAW,wBAAwB;IACvC,gCAAgC;IAChC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,wCAAwC;IACxC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,6CAA6C;IAC7C,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,sCAAsC;IACtC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,sCAAsC;IACtC,QAAQ,EAAE,OAAO,CAAC;CACnB;AA+CD,wBAAgB,mBAAmB,CAAC,EAClC,aAAa,EACb,YAAY,EACZ,WAAW,EACX,OAAO,EACP,QAAQ,GACT,EAAE,wBAAwB,2CAsI1B;AAED,eAAe,mBAAmB,CAAC"}
@@ -0,0 +1,98 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Game Selector Overlay
4
+ *
5
+ * Modal overlay for switching games during the loop.
6
+ * Triggered by pressing G key while 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, isCurrent, colors }) {
14
+ const icon = getGameIcon(game.id);
15
+ return (_jsx(Box, { children: _jsxs(Text, { color: isSelected ? colors.primary : colors.text, bold: isSelected, children: [isSelected ? navIcons.arrowRight : " ", " ", icon, " ", game.name, isCurrent && (_jsx(Text, { dimColor: true, children: " (playing)" }))] }) }));
16
+ }
17
+ function getGameIcon(gameId) {
18
+ switch (gameId) {
19
+ case "snake":
20
+ return "\u{1F40D}";
21
+ case "pong":
22
+ return "\u{1F3D3}";
23
+ case "tetris":
24
+ return "\u{1F9F1}";
25
+ case "minesweeper":
26
+ return "\u{1F4A3}";
27
+ default:
28
+ return "\u{1F3AE}";
29
+ }
30
+ }
31
+ // ============================================================================
32
+ // MAIN COMPONENT
33
+ // ============================================================================
34
+ export function GameSelectorOverlay({ currentGameId, onSelectGame, onViewStats, onClose, hasFocus, }) {
35
+ const colors = useThemeColors();
36
+ const games = useMemo(() => getGameList(), []);
37
+ // Add stats option to the list
38
+ const menuItems = useMemo(() => {
39
+ return [
40
+ ...games.map((g) => ({ type: "game", game: g })),
41
+ { type: "stats" },
42
+ ];
43
+ }, [games]);
44
+ const [selectedIndex, setSelectedIndex] = useState(() => {
45
+ // Start with current game selected
46
+ if (currentGameId) {
47
+ const idx = games.findIndex((g) => g.id === currentGameId);
48
+ return idx >= 0 ? idx : 0;
49
+ }
50
+ return 0;
51
+ });
52
+ const handleSelect = useCallback(() => {
53
+ const item = menuItems[selectedIndex];
54
+ if (item.type === "game") {
55
+ onSelectGame(item.game.id);
56
+ }
57
+ else {
58
+ onViewStats();
59
+ }
60
+ }, [menuItems, selectedIndex, onSelectGame, onViewStats]);
61
+ // Handle keyboard input
62
+ useInput((input, key) => {
63
+ if (!hasFocus)
64
+ return;
65
+ // Escape to close
66
+ if (key.escape) {
67
+ onClose();
68
+ return;
69
+ }
70
+ // Arrow keys or j/k to navigate
71
+ if (key.upArrow || input === "k" || input === "K") {
72
+ setSelectedIndex((prev) => (prev > 0 ? prev - 1 : menuItems.length - 1));
73
+ return;
74
+ }
75
+ if (key.downArrow || input === "j" || input === "J") {
76
+ setSelectedIndex((prev) => (prev < menuItems.length - 1 ? prev + 1 : 0));
77
+ return;
78
+ }
79
+ // Enter or Space to select
80
+ if (key.return || input === " ") {
81
+ handleSelect();
82
+ return;
83
+ }
84
+ // Number keys for quick selection
85
+ const num = parseInt(input, 10);
86
+ if (num >= 1 && num <= games.length) {
87
+ setSelectedIndex(num - 1);
88
+ const game = games[num - 1];
89
+ if (game) {
90
+ onSelectGame(game.id);
91
+ }
92
+ }
93
+ }, { isActive: hasFocus });
94
+ const overlayWidth = 40;
95
+ return (_jsx(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", children: _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: colors.primary, paddingX: 2, paddingY: 1, width: overlayWidth, children: [_jsx(Box, { justifyContent: "center", marginBottom: 1, children: _jsx(Text, { bold: true, color: colors.primary, children: "SELECT GAME" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: "─".repeat(overlayWidth - 6) }) }), games.map((game, index) => (_jsx(GameItem, { game: game, isSelected: index === selectedIndex, isCurrent: game.id === currentGameId, colors: colors }, game.id))), _jsx(Box, { marginY: 1, children: _jsx(Text, { dimColor: true, children: "─".repeat(overlayWidth - 6) }) }), _jsx(Box, { children: _jsxs(Text, { color: selectedIndex === games.length ? colors.primary : colors.text, bold: selectedIndex === games.length, children: [selectedIndex === games.length ? navIcons.arrowRight : " ", " Stats & Achievements"] }) }), _jsx(Box, { marginTop: 1, justifyContent: "center", children: _jsxs(Text, { dimColor: true, children: ["\u2191\u2193", ": Navigate | Enter: Select | Esc: Close"] }) })] }) }));
96
+ }
97
+ export default GameSelectorOverlay;
98
+ //# sourceMappingURL=GameSelectorOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GameSelectorOverlay.js","sourceRoot":"","sources":["../src/GameSelectorOverlay.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Loop Complete Screen
3
+ *
4
+ * Summary screen shown when the loop finishes.
5
+ * Shows feature completion stats and game session stats.
6
+ */
7
+ export interface GameSessionStats {
8
+ gameId: string;
9
+ gameName: string;
10
+ gamesPlayed: number;
11
+ bestScore: number;
12
+ }
13
+ export interface LoopCompleteProps {
14
+ /** Feature name */
15
+ featureName: string;
16
+ /** Number of tasks completed */
17
+ tasksCompleted: number;
18
+ /** Total number of tasks */
19
+ totalTasks: number;
20
+ /** Loop duration in milliseconds */
21
+ durationMs: number;
22
+ /** Number of files changed */
23
+ filesChanged?: number;
24
+ /** Game stats for this session */
25
+ gameStats?: GameSessionStats[];
26
+ /** Callback for starting a new loop */
27
+ onNewLoop: () => void;
28
+ /** Callback for continuing to play games */
29
+ onKeepPlaying: () => void;
30
+ /** Callback for quitting */
31
+ onQuit: () => void;
32
+ /** Whether the component has focus */
33
+ hasFocus: boolean;
34
+ /** Terminal dimensions */
35
+ dimensions: {
36
+ width: number;
37
+ height: number;
38
+ };
39
+ }
40
+ export declare function LoopComplete({ featureName, tasksCompleted, totalTasks, durationMs, filesChanged, gameStats, onNewLoop, onKeepPlaying, onQuit, hasFocus, dimensions, }: LoopCompleteProps): import("react/jsx-runtime").JSX.Element;
41
+ export default LoopComplete;
42
+ //# sourceMappingURL=LoopComplete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoopComplete.d.ts","sourceRoot":"","sources":["../src/LoopComplete.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,4BAA4B;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC/B,uCAAuC;IACvC,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,4CAA4C;IAC5C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,4BAA4B;IAC5B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,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;AAwCD,wBAAgB,YAAY,CAAC,EAC3B,WAAW,EACX,cAAc,EACd,UAAU,EACV,UAAU,EACV,YAAY,EACZ,SAAc,EACd,SAAS,EACT,aAAa,EACb,MAAM,EACN,QAAQ,EACR,UAAU,GACX,EAAE,iBAAiB,2CAoHnB;AAED,eAAe,YAAY,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * Loop Complete Screen
4
+ *
5
+ * Summary screen shown when the loop finishes.
6
+ * Shows feature completion stats and game session stats.
7
+ */
8
+ import { Box, Text, useInput } from "ink";
9
+ import { useMemo } from "react";
10
+ import { useThemeColors } from "./useTheme.js";
11
+ // ============================================================================
12
+ // HELPER FUNCTIONS
13
+ // ============================================================================
14
+ function formatDuration(ms) {
15
+ const totalSeconds = Math.floor(ms / 1000);
16
+ const hours = Math.floor(totalSeconds / 3600);
17
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
18
+ const seconds = totalSeconds % 60;
19
+ if (hours > 0) {
20
+ return `${hours}h ${minutes}m ${seconds}s`;
21
+ }
22
+ if (minutes > 0) {
23
+ return `${minutes}m ${seconds}s`;
24
+ }
25
+ return `${seconds}s`;
26
+ }
27
+ function getGameIcon(gameId) {
28
+ switch (gameId) {
29
+ case "snake":
30
+ return "\u{1F40D}";
31
+ case "pong":
32
+ return "\u{1F3D3}";
33
+ case "tetris":
34
+ return "\u{1F9F1}";
35
+ case "minesweeper":
36
+ return "\u{1F4A3}";
37
+ default:
38
+ return "\u{1F3AE}";
39
+ }
40
+ }
41
+ // ============================================================================
42
+ // MAIN COMPONENT
43
+ // ============================================================================
44
+ export function LoopComplete({ featureName, tasksCompleted, totalTasks, durationMs, filesChanged, gameStats = [], onNewLoop, onKeepPlaying, onQuit, hasFocus, dimensions, }) {
45
+ const colors = useThemeColors();
46
+ // Handle keyboard input
47
+ useInput((input) => {
48
+ if (!hasFocus)
49
+ return;
50
+ if (input === "n" || input === "N") {
51
+ onNewLoop();
52
+ }
53
+ else if (input === "g" || input === "G") {
54
+ onKeepPlaying();
55
+ }
56
+ else if (input === "q" || input === "Q") {
57
+ onQuit();
58
+ }
59
+ }, { isActive: hasFocus });
60
+ const cardWidth = useMemo(() => {
61
+ return Math.min(55, dimensions.width - 8);
62
+ }, [dimensions.width]);
63
+ const duration = formatDuration(durationMs);
64
+ return (_jsxs(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: colors.success, bold: true, children: ["\u2705", " LOOP COMPLETE"] }) }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: colors.border, paddingX: 2, paddingY: 1, width: cardWidth, children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { bold: true, color: colors.text, children: ["Feature: ", featureName.length > cardWidth - 15
65
+ ? featureName.slice(0, cardWidth - 18) + "..."
66
+ : featureName] }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: "─".repeat(cardWidth - 6) }) }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { children: ["Tasks completed: ", _jsxs(Text, { color: colors.success, children: [tasksCompleted, "/", totalTasks] })] }), _jsxs(Text, { children: ["Duration: ", _jsx(Text, { color: colors.text, children: duration })] }), filesChanged !== undefined && (_jsxs(Text, { children: ["Files changed: ", _jsx(Text, { color: colors.text, children: filesChanged })] }))] }), gameStats.length > 0 && (_jsxs(_Fragment, { children: [_jsx(Box, { marginY: 1, children: _jsx(Text, { dimColor: true, children: "─".repeat(cardWidth - 6) }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: "Game stats this session:" }) }), gameStats.map((stat) => (_jsx(Box, { children: _jsxs(Text, { children: [getGameIcon(stat.gameId), " ", stat.gameName, ":", " ", _jsxs(Text, { dimColor: true, children: [stat.gamesPlayed, " game", stat.gamesPlayed !== 1 ? "s" : "", ", best: ", stat.bestScore] })] }) }, stat.gameId)))] }))] }), _jsx(Box, { marginTop: 2, children: _jsxs(Text, { children: [_jsx(Text, { color: colors.primary, children: "[N]" }), _jsx(Text, { children: " New Loop " }), _jsx(Text, { color: colors.primary, children: "[G]" }), _jsx(Text, { children: " Keep Playing " }), _jsx(Text, { color: colors.primary, children: "[Q]" }), _jsx(Text, { children: " Quit" })] }) })] }));
67
+ }
68
+ export default LoopComplete;
69
+ //# sourceMappingURL=LoopComplete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoopComplete.js","sourceRoot":"","sources":["../src/LoopComplete.tsx"],"names":[],"mappings":"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"}