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.
- package/dist/AchievementNotification.d.ts.map +1 -1
- package/dist/AchievementNotification.js.map +1 -1
- package/dist/AppNew.d.ts +11 -0
- package/dist/AppNew.d.ts.map +1 -0
- package/dist/AppNew.js +437 -0
- package/dist/AppNew.js.map +1 -0
- package/dist/AttentionOverlay.d.ts +28 -0
- package/dist/AttentionOverlay.d.ts.map +1 -0
- package/dist/AttentionOverlay.js +92 -0
- package/dist/AttentionOverlay.js.map +1 -0
- package/dist/ClaudeChat.d.ts +38 -0
- package/dist/ClaudeChat.d.ts.map +1 -0
- package/dist/ClaudeChat.js +81 -0
- package/dist/ClaudeChat.js.map +1 -0
- package/dist/DynamicInterviewFlow.d.ts +66 -0
- package/dist/DynamicInterviewFlow.d.ts.map +1 -0
- package/dist/DynamicInterviewFlow.js +352 -0
- package/dist/DynamicInterviewFlow.js.map +1 -0
- package/dist/FeatureInput.d.ts +20 -0
- package/dist/FeatureInput.d.ts.map +1 -0
- package/dist/FeatureInput.js +66 -0
- package/dist/FeatureInput.js.map +1 -0
- package/dist/FeaturePromptScreen.d.ts +24 -0
- package/dist/FeaturePromptScreen.d.ts.map +1 -0
- package/dist/FeaturePromptScreen.js +117 -0
- package/dist/FeaturePromptScreen.js.map +1 -0
- package/dist/GameSelectScreen.d.ts +24 -0
- package/dist/GameSelectScreen.d.ts.map +1 -0
- package/dist/GameSelectScreen.js +78 -0
- package/dist/GameSelectScreen.js.map +1 -0
- package/dist/GameSelector.d.ts +9 -1
- package/dist/GameSelector.d.ts.map +1 -1
- package/dist/GameSelector.js +116 -19
- package/dist/GameSelector.js.map +1 -1
- package/dist/GameSelectorOverlay.d.ts +21 -0
- package/dist/GameSelectorOverlay.d.ts.map +1 -0
- package/dist/GameSelectorOverlay.js +98 -0
- package/dist/GameSelectorOverlay.js.map +1 -0
- package/dist/HelpOverlay.d.ts.map +1 -1
- package/dist/HelpOverlay.js +5 -2
- package/dist/HelpOverlay.js.map +1 -1
- package/dist/InterviewQuestion.d.ts +36 -0
- package/dist/InterviewQuestion.d.ts.map +1 -0
- package/dist/InterviewQuestion.js +148 -0
- package/dist/InterviewQuestion.js.map +1 -0
- package/dist/Layout.d.ts +1 -1
- package/dist/Layout.d.ts.map +1 -1
- package/dist/Layout.js +4 -4
- package/dist/Layout.js.map +1 -1
- package/dist/LogViewer.d.ts.map +1 -1
- package/dist/LogViewer.js +2 -2
- package/dist/LogViewer.js.map +1 -1
- package/dist/LoopAlertOverlay.d.ts +1 -1
- package/dist/LoopAlertOverlay.d.ts.map +1 -1
- package/dist/LoopAlertOverlay.js +1 -1
- package/dist/LoopAlertOverlay.js.map +1 -1
- package/dist/LoopComplete.d.ts +42 -0
- package/dist/LoopComplete.d.ts.map +1 -0
- package/dist/LoopComplete.js +69 -0
- package/dist/LoopComplete.js.map +1 -0
- package/dist/LoopManagementPanel.d.ts.map +1 -1
- package/dist/LoopManagementPanel.js.map +1 -1
- package/dist/OnboardingTutorial.d.ts +23 -0
- package/dist/OnboardingTutorial.d.ts.map +1 -0
- package/dist/OnboardingTutorial.js +165 -0
- package/dist/OnboardingTutorial.js.map +1 -0
- package/dist/PrdGenerationScreen.d.ts +43 -0
- package/dist/PrdGenerationScreen.d.ts.map +1 -0
- package/dist/PrdGenerationScreen.js +411 -0
- package/dist/PrdGenerationScreen.js.map +1 -0
- package/dist/PrdOverlay.d.ts +29 -0
- package/dist/PrdOverlay.d.ts.map +1 -0
- package/dist/PrdOverlay.js +174 -0
- package/dist/PrdOverlay.js.map +1 -0
- package/dist/PreStartReviewScreen.d.ts +29 -0
- package/dist/PreStartReviewScreen.d.ts.map +1 -0
- package/dist/PreStartReviewScreen.js +161 -0
- package/dist/PreStartReviewScreen.js.map +1 -0
- package/dist/ResumeOverlay.d.ts +26 -0
- package/dist/ResumeOverlay.d.ts.map +1 -0
- package/dist/ResumeOverlay.js +163 -0
- package/dist/ResumeOverlay.js.map +1 -0
- package/dist/ResumePrompt.d.ts +32 -0
- package/dist/ResumePrompt.d.ts.map +1 -0
- package/dist/ResumePrompt.js +65 -0
- package/dist/ResumePrompt.js.map +1 -0
- package/dist/SettingsMenu.d.ts.map +1 -1
- package/dist/SettingsMenu.js +14 -7
- package/dist/SettingsMenu.js.map +1 -1
- package/dist/SetupWizard.d.ts +41 -0
- package/dist/SetupWizard.d.ts.map +1 -0
- package/dist/SetupWizard.js +167 -0
- package/dist/SetupWizard.js.map +1 -0
- package/dist/SidePanel.d.ts +26 -0
- package/dist/SidePanel.d.ts.map +1 -0
- package/dist/SidePanel.js +90 -0
- package/dist/SidePanel.js.map +1 -0
- package/dist/SplitPane.d.ts.map +1 -1
- package/dist/SplitPane.js +6 -2
- package/dist/SplitPane.js.map +1 -1
- package/dist/StatsMenu.d.ts.map +1 -1
- package/dist/StatsMenu.js +24 -6
- package/dist/StatsMenu.js.map +1 -1
- package/dist/StatusBar.d.ts +45 -2
- package/dist/StatusBar.d.ts.map +1 -1
- package/dist/StatusBar.js +193 -23
- package/dist/StatusBar.js.map +1 -1
- package/dist/StatusBarMinimal.d.ts +26 -0
- package/dist/StatusBarMinimal.d.ts.map +1 -0
- package/dist/StatusBarMinimal.js +111 -0
- package/dist/StatusBarMinimal.js.map +1 -0
- package/dist/TaskBreakdownScreen.d.ts +27 -0
- package/dist/TaskBreakdownScreen.d.ts.map +1 -0
- package/dist/TaskBreakdownScreen.js +96 -0
- package/dist/TaskBreakdownScreen.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -1
- package/dist/games/MinesweeperGame.d.ts +1 -1
- package/dist/games/MinesweeperGame.d.ts.map +1 -1
- package/dist/games/MinesweeperGame.js +30 -10
- package/dist/games/MinesweeperGame.js.map +1 -1
- package/dist/games/PongGame.d.ts +1 -1
- package/dist/games/PongGame.d.ts.map +1 -1
- package/dist/games/PongGame.js +7 -2
- package/dist/games/PongGame.js.map +1 -1
- package/dist/games/SnakeGame.d.ts +1 -1
- package/dist/games/SnakeGame.d.ts.map +1 -1
- package/dist/games/SnakeGame.js +12 -4
- package/dist/games/SnakeGame.js.map +1 -1
- package/dist/games/TetrisGame.d.ts +1 -1
- package/dist/games/TetrisGame.d.ts.map +1 -1
- package/dist/games/TetrisGame.js +22 -5
- package/dist/games/TetrisGame.js.map +1 -1
- package/dist/high-scores.d.ts.map +1 -1
- package/dist/high-scores.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -236
- package/dist/index.js.map +1 -1
- package/dist/loop-state.d.ts +137 -0
- package/dist/loop-state.d.ts.map +1 -0
- package/dist/loop-state.js +228 -0
- package/dist/loop-state.js.map +1 -0
- package/dist/ralph-loop-parser.d.ts.map +1 -1
- package/dist/ralph-loop-parser.js +4 -2
- package/dist/ralph-loop-parser.js.map +1 -1
- package/dist/stats.d.ts.map +1 -1
- package/dist/stats.js.map +1 -1
- package/dist/styled-components.d.ts +1 -1
- package/dist/styled-components.d.ts.map +1 -1
- package/dist/styled-components.js +5 -3
- package/dist/styled-components.js.map +1 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +15 -2
- package/dist/theme.js.map +1 -1
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js.map +1 -1
- package/dist/use-claude-code.d.ts.map +1 -1
- package/dist/use-claude-code.js +7 -1
- package/dist/use-claude-code.js.map +1 -1
- package/dist/use-config.d.ts.map +1 -1
- package/dist/use-config.js.map +1 -1
- package/dist/use-loop-state.d.ts +55 -0
- package/dist/use-loop-state.d.ts.map +1 -0
- package/dist/use-loop-state.js +208 -0
- package/dist/use-loop-state.js.map +1 -0
- package/dist/use-stats.d.ts.map +1 -1
- package/dist/use-stats.js.map +1 -1
- package/dist/useTheme.d.ts.map +1 -1
- package/dist/useTheme.js.map +1 -1
- package/package.json +3 -2
- package/dist/__tests__/ralph-loop-parser.test.d.ts +0 -2
- package/dist/__tests__/ralph-loop-parser.test.d.ts.map +0 -1
- package/dist/__tests__/ralph-loop-parser.test.js +0 -143
- package/dist/__tests__/ralph-loop-parser.test.js.map +0 -1
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -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
|
|
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
|
-
*
|
|
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
|
-
|
|
33
|
-
|
|
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
|
|
260
|
-
render(_jsx(
|
|
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
|