TypeScript · 3134 bytes Raw Blame History
1 import { useState, useCallback } from 'react';
2 import { gameApi, CommandResponse, TreeNode } from '@/lib/api';
3
4 interface CommandExecutionState {
5 executing: boolean;
6 commandHistory: CommandHistoryEntry[];
7 }
8
9 interface CommandHistoryEntry {
10 command: string;
11 output: string;
12 success: boolean;
13 }
14
15 export const useCommandExecution = (
16 gameTreeId: number | null,
17 sessionId: number | null,
18 onLocationChange?: (newPath: string) => void,
19 onMoleKilled?: (response: CommandResponse) => void,
20 onTreeUpdate?: (updater: (tree: TreeNode) => TreeNode) => void
21 ) => {
22 const [state, setState] = useState<CommandExecutionState>({
23 executing: false,
24 commandHistory: [],
25 });
26
27 const addToHistory = useCallback((entry: CommandHistoryEntry) => {
28 setState(prev => ({
29 ...prev,
30 commandHistory: [...prev.commandHistory, entry],
31 }));
32 }, []);
33
34 const clearHistory = useCallback(() => {
35 setState(prev => ({
36 ...prev,
37 commandHistory: [],
38 }));
39 }, []);
40
41 const executeCommand = useCallback(async (cmd: string) => {
42 if (!gameTreeId || !cmd.trim() || state.executing) return;
43
44 setState(prev => ({ ...prev, executing: true }));
45
46 try {
47 const response = await gameApi.executeCommand(
48 gameTreeId,
49 cmd,
50 sessionId || undefined
51 );
52
53 // Build output with timer warnings
54 let fullOutput = response.output;
55
56 // Add timer warnings if present
57 if (response.timer_warnings && response.timer_warnings.length > 0) {
58 const warnings = response.timer_warnings.map(w =>
59 `⚠️ ${w.level}: ${w.message}`
60 ).join('\n');
61 fullOutput = warnings + (fullOutput ? '\n' + fullOutput : '');
62 }
63
64 // Add to command history
65 addToHistory({
66 command: cmd,
67 output: fullOutput,
68 success: response.success,
69 });
70
71 // Handle location change
72 if (response.current_path && onLocationChange) {
73 onLocationChange(response.current_path);
74 }
75
76 // Handle mole spawning
77 if (response.mole_spawned && onMoleKilled) {
78 // Format the output to include timer info on new line
79 if (response.timer_reason && !response.output.includes('New mole detected')) {
80 response.output += `\nNew mole detected ${response.timer_reason}!`;
81 }
82 onMoleKilled(response);
83 }
84
85 // Legacy: Handle game won
86 if (response.game_won && !response.mole_spawned && onTreeUpdate) {
87 onTreeUpdate((tree) => ({
88 ...tree,
89 has_mole: true,
90 }));
91 }
92
93 return response;
94 } catch {
95 addToHistory({
96 command: cmd,
97 output: 'Error: Failed to execute command. Check your connection.',
98 success: false,
99 });
100 return null;
101 } finally {
102 setState(prev => ({ ...prev, executing: false }));
103 }
104 }, [gameTreeId, sessionId, state.executing, addToHistory, onLocationChange, onMoleKilled, onTreeUpdate]);
105
106 return {
107 executing: state.executing,
108 commandHistory: state.commandHistory,
109 executeCommand,
110 addToHistory,
111 clearHistory,
112 };
113 };