File size: 6,899 Bytes
34450be
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import re

with open("App.tsx", "r") as f:
    content = f.read()

# 1. Add Timer State
state_search = "const [templateQueue, setTemplateQueue] = useState<Record<string, string[]>>({});"
state_replace = """const [templateQueue, setTemplateQueue] = useState<Record<string, string[]>>({});
  const [hfTimerQueue, setHfTimerQueue] = useState<Record<string, { templates: string[], nextExecutionTime: number }>>(() => {
      const stored = localStorage.getItem('jules_hf_timer_queue');
      return stored ? JSON.parse(stored) : {};
  });
  const [hfWizardOpen, setHfWizardOpen] = useState(false);"""
content = content.replace(state_search, state_replace)

# 2. Add Timer logic & persist effect
effect_search = """  // --- Message Sending & Event Streaming ---"""
effect_replace = """  // Persist timer queue
  useEffect(() => {
      localStorage.setItem('jules_hf_timer_queue', JSON.stringify(hfTimerQueue));
  }, [hfTimerQueue]);

  // Timer interval to process HF Deployment Cues every 10 seconds
  useEffect(() => {
      const interval = setInterval(() => {
          setHfTimerQueue(prevQueue => {
              const now = Date.now();
              const newQueue = { ...prevQueue };
              let hasChanges = false;

              for (const [sessionId, queueData] of Object.entries(newQueue)) {
                  if (queueData.templates.length > 0 && now >= queueData.nextExecutionTime) {
                      // Time to fire the next template
                      const templateToFire = queueData.templates[0];
                      const remainingTemplates = queueData.templates.slice(1);

                      // Check if we are currently loading or recording, maybe skip this tick?
                      // Actually, let's just fire it anyway.
                      console.log(`[TimerQueue] Firing template for session ${sessionId}`);

                      // Fire it by creating a synthetic local message and calling sendMessage
                      const fakeUserMessage = {
                          id: `local-timer-${Date.now()}`,
                          name: `local-msg-${Date.now()}`,
                          createTime: new Date().toISOString(),
                          originator: 'user' as const,
                          text: templateToFire
                      };

                      // We can't update localHistory cleanly inside a setState, but we can do a side-effect.
                      // Since we don't have direct access to setLocalHistory here cleanly, we will call _sendText out of band.
                      // Wait, let's handle the side effect via a setTimeout to break out of the setState context.
                      setTimeout(() => {
                         // Send the message
                         _sendText(sessionId, templateToFire).catch(e => console.error("Timer send failed", e));
                      }, 0);

                      if (remainingTemplates.length > 0) {
                          newQueue[sessionId] = {
                              templates: remainingTemplates,
                              // 30 minutes = 30 * 60 * 1000
                              nextExecutionTime: now + 30 * 60 * 1000
                          };
                      } else {
                          delete newQueue[sessionId];
                      }
                      hasChanges = true;
                  }
              }

              return hasChanges ? newQueue : prevQueue;
          });
      }, 10000); // check every 10 seconds

      return () => clearInterval(interval);
  }, []);

  // --- Message Sending & Event Streaming ---"""
content = content.replace(effect_search, effect_replace)

# 3. Add handler for HF Wizard
handler_search = """  const handleHuggingFaceCue = async () => {
      if (!currentSessionId) return;

      const templates = [
          "Please perform a deep investigation of the codebase to understand its current state and architecture. Look for dependencies, main entry points, and service patterns. READY",
          "Based on the investigation, create a detailed project vision and implementation plan. Outline the necessary changes and new components. READY",
          "Implement the changes according to the plan and prepare for deployment. Ensure all tests pass and documentation is updated. READY"
      ];

      // Send the first template immediately if queue is empty and we aren't currently loading.
      // Otherwise, add everything to the queue.
      const currentQueue = templateQueue[currentSessionId] || [];
      if (currentQueue.length === 0 && !isLoading) {
          const first = templates[0];
          const rest = templates.slice(1);
          setTemplateQueue(prev => ({
              ...prev,
              [currentSessionId]: rest
          }));
          await _sendText(currentSessionId, first);
      } else {
          setTemplateQueue(prev => ({
              ...prev,
              [currentSessionId]: [...currentQueue, ...templates]
          }));
      }
  };"""
handler_replace = """  const handleHuggingFaceCue = () => {
      setHfWizardOpen(true);
  };

  const handleStartHfTimer = async (config: any) => {
      if (config.targetType === 'new') {
          try {
              setIsLoading(true);
              const session = await julesService.current.createSession(
                  config.githubRepoId.split('/')[1] || config.githubRepoId,
                  config.templates[0],
                  config.sourceId,
                  'AUTO_CREATE_PR'
              );
              setSessionAgentMap(prev => ({ ...prev, [session.id]: currentAgent.id }));
              setSessions(prev => [session, ...prev]);
              setCurrentSessionId(session.id);

              if (config.templates.length > 1) {
                  setHfTimerQueue(prev => ({
                      ...prev,
                      [session.id]: {
                          templates: config.templates.slice(1),
                          nextExecutionTime: Date.now() + 30 * 60 * 1000
                      }
                  }));
              }
              setIsLoading(false);
          } catch (e) {
              alert("Failed to create session: " + e);
              setIsLoading(false);
          }
      } else if (config.targetType === 'current' && currentSessionId) {
          // Immediately send the first template
          await _sendText(currentSessionId, config.templates[0]);
          if (config.templates.length > 1) {
              setHfTimerQueue(prev => ({
                  ...prev,
                  [currentSessionId]: {
                      templates: config.templates.slice(1),
                      nextExecutionTime: Date.now() + 30 * 60 * 1000
                  }
              }));
          }
      }
  };"""
content = content.replace(handler_search, handler_replace)

with open("App.tsx", "w") as f:
    f.write(content)