everydaytok commited on
Commit
b76f93b
·
verified ·
1 Parent(s): 519d9a1

Delete stateManager.js

Browse files
Files changed (1) hide show
  1. stateManager.js +0 -214
stateManager.js DELETED
@@ -1,214 +0,0 @@
1
- // stateManager.js
2
- let db = null;
3
-
4
- export const initDB = (firebaseDB) => {
5
- db = firebaseDB;
6
- };
7
-
8
- const activeProjects = new Map();
9
-
10
-
11
-
12
- export const StateManager = {
13
- /**
14
- * GET PROJECT
15
- * Hydrates from DB if not in memory.
16
- * Flattens { info, thumbnail, state } into a usable Memory Object.
17
- */
18
- getProject: async (projectId) => {
19
- // 1. Try Memory
20
- if (activeProjects.has(projectId)) {
21
- return activeProjects.get(projectId);
22
- }
23
-
24
- // 2. Try Firebase (Hydration)
25
- if (db) {
26
- try {
27
- console.log(`[StateManager] 🟡 Hydrating project ${projectId} from DB...`);
28
- // We fetch the root because the Server AI needs EVERYTHING (context, history) to function.
29
- // If this was a client-side Dashboard, we would only fetch /info.
30
- const snapshot = await db.ref(`projects/${projectId}`).once('value');
31
-
32
- if (snapshot.exists()) {
33
- const dbData = snapshot.val();
34
-
35
- // FLATTEN DB STRUCTURE -> MEMORY STRUCTURE
36
- const memoryObject = {
37
- ...dbData.info, // Title, stats, description
38
- thumbnail: dbData.thumbnail?.url || null,
39
- // State might be undefined if just created, so default it
40
- commandQueue: dbData.state?.commandQueue || [],
41
- workerHistory: dbData.state?.workerHistory || [],
42
- pmHistory: dbData.state?.pmHistory || [],
43
- failureCount: dbData.state?.failureCount || 0,
44
- gdd: dbData.state?.gdd || null,
45
- // CRITICAL: Initialize lastActive to NOW so it doesn't expire immediately
46
- lastActive: Date.now(),
47
- lastUpdated: Date.now()
48
- };
49
-
50
- // Load into Memory
51
- activeProjects.set(projectId, memoryObject);
52
- console.log(`[StateManager] 🟢 Project ${projectId} hydrated.`);
53
- return memoryObject;
54
- }
55
- } catch (err) {
56
- console.error(`[StateManager] Error reading DB for ${projectId}:`, err);
57
- }
58
- }
59
-
60
- return null;
61
- },
62
-
63
- /**
64
- * UPDATE PROJECT
65
- * Updates Memory immediately.
66
- * Performs granular updates to DB (separating Info vs State).
67
- */
68
- updateProject: async (projectId, data) => {
69
- let current = activeProjects.get(projectId);
70
-
71
- // Safety check: ensure we have base state
72
- if (!current) {
73
- current = await StateManager.getProject(projectId) || {
74
- commandQueue: [], workerHistory: [], pmHistory: [], failureCount: 0
75
- };
76
- }
77
-
78
- const timestamp = Date.now();
79
-
80
- // 1. Update Memory (Flat Merge)
81
- const newData = {
82
- ...current,
83
- ...data,
84
- // CRITICAL: Initialize lastActive to NOW so it doesn't expire immediately
85
- lastActive: Date.now(),
86
- lastUpdated: Date.now()
87
- };
88
- activeProjects.set(projectId, newData);
89
-
90
- // 2. Update Firebase (Nested Split)
91
- if (db) {
92
- const updates = {};
93
-
94
- // We assume 'data' contains the specific fields that changed.
95
- // However, to be safe and robust, we map the current state to the correct buckets.
96
-
97
- // Bucket: Info
98
- if (data.status || data.stats || data.title) {
99
- updates[`projects/${projectId}/info/status`] = newData.status;
100
- if (newData.lastUpdated) updates[`projects/${projectId}/info/lastUpdated`] = newData.lastUpdated;
101
- // Add other info fields if they are mutable
102
- }
103
-
104
- // Bucket: State (History, Queue, GDD) - This is the most frequent update
105
- if (data.workerHistory || data.pmHistory || data.commandQueue || data.failureCount || data.gdd) {
106
- updates[`projects/${projectId}/state/workerHistory`] = newData.workerHistory;
107
- updates[`projects/${projectId}/state/pmHistory`] = newData.pmHistory;
108
- updates[`projects/${projectId}/state/commandQueue`] = newData.commandQueue;
109
- updates[`projects/${projectId}/state/failureCount`] = newData.failureCount;
110
- if (newData.gdd) updates[`projects/${projectId}/state/gdd`] = newData.gdd;
111
- }
112
-
113
- // Bucket: Thumbnail (Only update if explicitly passed in 'data', avoiding re-upload of massive string)
114
- if (data.thumbnail) {
115
- updates[`projects/${projectId}/thumbnail`] = {url: data.thumbnail};
116
- }
117
-
118
- // Perform the update
119
- if (Object.keys(updates).length > 0) {
120
- db.ref().update(updates).catch(err => {
121
- console.error(`[StateManager] 🔴 DB Write Failed for ${projectId}:`, err);
122
- });
123
- }
124
- }
125
-
126
- return newData;
127
- },
128
-
129
- queueCommand: async (projectId, input) => {
130
- const project = await StateManager.getProject(projectId);
131
- if (!project) return;
132
-
133
- let command = null;
134
-
135
- if (typeof input === 'object' && input.type && input.payload) {
136
- command = input;
137
- }
138
- else if (typeof input === 'string') {
139
- const rawResponse = input;
140
- if (rawResponse.includes("[ASK_PM:")) return;
141
- if (rawResponse.includes("[GENERATE_IMAGE:") && !rawResponse.includes("```")) return;
142
-
143
- const codeMatch = rawResponse.match(/```(?:lua|luau)?([\s\S]*?)```/i);
144
- const readScriptMatch = rawResponse.match(/\[READ_SCRIPT:\s*(.*?)\]/);
145
- const readHierarchyMatch = rawResponse.match(/\[READ_HIERARCHY:\s*(.*?)\]/);
146
- const readLogsMatch = rawResponse.includes("[READ_LOGS]");
147
-
148
- if (codeMatch) command = { type: "EXECUTE", payload: codeMatch[1].trim() };
149
- else if (readScriptMatch) command = { type: "READ_SCRIPT", payload: readScriptMatch[1].trim() };
150
- else if (readHierarchyMatch) command = { type: "READ_HIERARCHY", payload: readHierarchyMatch[1].trim() };
151
- else if (readLogsMatch) command = { type: "READ_LOGS", payload: null };
152
- }
153
-
154
- if (command) {
155
- project.commandQueue.push(command);
156
- console.log(`[${projectId}] Queued Action: ${command.type}`);
157
- // Sync queue to DB
158
- await StateManager.updateProject(projectId, { commandQueue: project.commandQueue });
159
- }
160
- },
161
-
162
- popCommand: async (projectId) => {
163
- const project = await StateManager.getProject(projectId);
164
- if (!project || !project.commandQueue.length) return null;
165
-
166
- const command = project.commandQueue.shift();
167
- // Sync queue to DB
168
- await StateManager.updateProject(projectId, { commandQueue: project.commandQueue });
169
-
170
- return command;
171
- },
172
-
173
- cleanupMemory: () => {
174
- const now = Date.now();
175
- const FOUR_HOURS = 4 * 60 * 60 * 1000;
176
- let count = 0;
177
-
178
- for (const [id, data] of activeProjects.entries()) {
179
- // FIX: If lastActive is missing/undefined/0, reset it to NOW.
180
- // This prevents the "54 year old project" bug where (now - 0) > 4 hours.
181
- if (!data.lastActive) {
182
- console.warn(`[StateManager] ⚠️ Project ${id} missing timestamp. Healing data...`);
183
- data.lastActive = now;
184
- continue; // Skip deleting this round
185
- }
186
-
187
- if (now - data.lastActive > FOUR_HOURS) {
188
- console.log(`[StateManager] 🧹 Removing expired project: ${id}`);
189
- activeProjects.delete(id);
190
- count++;
191
- }
192
- }
193
-
194
- if (count > 0) {
195
- console.log(`[StateManager] 🗑️ Cleaned ${count} projects from memory.`);
196
- }
197
- return count;
198
- }
199
-
200
- /* cleanupMemory: () => {
201
- const now = Date.now();
202
- const FOUR_HOURS = 4 * 60 * 60 * 1000;
203
- let count = 0;
204
-
205
- for (const [id, data] of activeProjects.entries()) {
206
- if (now - (data.lastActive || 0) > FOUR_HOURS) {
207
- activeProjects.delete(id);
208
- count++;
209
- }
210
- }
211
- console.log(`[StateManager] 🧹 Memory Cleanup: Removed ${count} inactive projects.`);
212
- return count;
213
- } */
214
- };