vg-coder-cli 2.0.40 → 2.0.42

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.
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Chat History Manager
3
+ * Manages chat sessions in localStorage
4
+ */
5
+
6
+ const STORAGE_PREFIX = 'vg-dashboard-chat-';
7
+ const METADATA_KEY = 'vg-dashboard-chat-metadata';
8
+ const MAX_CHAT_AGE_DAYS = 30;
9
+ const MAX_TITLE_LENGTH = 50;
10
+
11
+ /**
12
+ * Generate unique chat ID
13
+ * @returns {string} Chat ID
14
+ */
15
+ export function generateChatId() {
16
+ const timestamp = Date.now().toString(36);
17
+ const random = Math.random().toString(36).substring(2, 15) +
18
+ Math.random().toString(36).substring(2, 15);
19
+ return `${timestamp}${random}`;
20
+ }
21
+
22
+ /**
23
+ * Generate chat title from messages
24
+ * @param {Array} messages - Chat messages
25
+ * @returns {string} Chat title
26
+ */
27
+ function generateTitle(messages) {
28
+ if (!messages || messages.length === 0) return 'New Chat';
29
+ const firstUserMsg = messages.find(m => m.role === 'user');
30
+ if (!firstUserMsg) return 'New Chat';
31
+
32
+ let title = firstUserMsg.content.trim();
33
+ if (title.length > MAX_TITLE_LENGTH) {
34
+ title = title.substring(0, MAX_TITLE_LENGTH) + '...';
35
+ }
36
+ return title;
37
+ }
38
+
39
+ /**
40
+ * Get metadata
41
+ * @returns {object} Metadata object
42
+ */
43
+ function getMetadata() {
44
+ try {
45
+ const data = localStorage.getItem(METADATA_KEY);
46
+ return data ? JSON.parse(data) : { allChatIds: [], lastAccessedChatId: null };
47
+ } catch (error) {
48
+ console.error('[ChatHistory] Failed to get metadata:', error);
49
+ return { allChatIds: [], lastAccessedChatId: null };
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Update metadata
55
+ * @param {object} updates - Updates to apply
56
+ */
57
+ function updateMetadata(updates) {
58
+ const metadata = getMetadata();
59
+ Object.assign(metadata, updates);
60
+ try {
61
+ localStorage.setItem(METADATA_KEY, JSON.stringify(metadata));
62
+ } catch (error) {
63
+ console.error('[ChatHistory] Failed to update metadata:', error);
64
+ handleStorageError(error);
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Handle storage errors
70
+ * @param {Error} error - Error object
71
+ */
72
+ function handleStorageError(error) {
73
+ if (error.name === 'QuotaExceededError') {
74
+ console.warn('[ChatHistory] Storage quota exceeded, cleaning up...');
75
+ const deletedCount = cleanupOldChats(7);
76
+ if (deletedCount > 0) {
77
+ console.log(`[ChatHistory] Cleaned up ${deletedCount} old chats`);
78
+ } else {
79
+ console.error('[ChatHistory] Storage full and no old chats to cleanup!');
80
+ alert('⚠️ Bộ nhớ đã đầy! Vui lòng xóa bớt lịch sử chat cũ.');
81
+ }
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Save chat to localStorage
87
+ * @param {string} chatId - Chat ID
88
+ * @param {Array} messages - Messages array
89
+ * @param {object} options - Additional options
90
+ * @returns {boolean} Success status
91
+ */
92
+ export function saveChat(chatId, messages, options = {}) {
93
+ if (!chatId) {
94
+ console.error('[ChatHistory] Cannot save chat without ID');
95
+ return false;
96
+ }
97
+
98
+ const now = Date.now();
99
+ const key = STORAGE_PREFIX + chatId;
100
+
101
+ let chatData;
102
+ try {
103
+ const existing = localStorage.getItem(key);
104
+ chatData = existing ? JSON.parse(existing) : { id: chatId, createdAt: now };
105
+ } catch (error) {
106
+ console.error('[ChatHistory] Failed to load existing chat:', error);
107
+ chatData = { id: chatId, createdAt: now };
108
+ }
109
+
110
+ chatData.messages = messages;
111
+ chatData.updatedAt = now;
112
+ chatData.title = options.title || generateTitle(messages);
113
+
114
+ try {
115
+ localStorage.setItem(key, JSON.stringify(chatData));
116
+ const metadata = getMetadata();
117
+ if (!metadata.allChatIds.includes(chatId)) {
118
+ metadata.allChatIds.push(chatId);
119
+ }
120
+ metadata.lastAccessedChatId = chatId;
121
+ updateMetadata(metadata);
122
+ return true;
123
+ } catch (error) {
124
+ console.error('[ChatHistory] Failed to save chat:', error);
125
+ handleStorageError(error);
126
+ return false;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Load chat from localStorage
132
+ * @param {string} chatId - Chat ID
133
+ * @returns {object|null} Chat data
134
+ */
135
+ export function loadChat(chatId) {
136
+ if (!chatId) return null;
137
+
138
+ const key = STORAGE_PREFIX + chatId;
139
+ try {
140
+ const data = localStorage.getItem(key);
141
+ if (!data) {
142
+ console.warn(`[ChatHistory] Chat not found: ${chatId}`);
143
+ return null;
144
+ }
145
+
146
+ const chatData = JSON.parse(data);
147
+ if (!chatData.messages || !Array.isArray(chatData.messages)) {
148
+ console.error('[ChatHistory] Invalid chat data structure');
149
+ return null;
150
+ }
151
+
152
+ updateMetadata({ lastAccessedChatId: chatId });
153
+
154
+ return {
155
+ messages: chatData.messages,
156
+ metadata: {
157
+ title: chatData.title,
158
+ createdAt: chatData.createdAt,
159
+ updatedAt: chatData.updatedAt,
160
+ }
161
+ };
162
+ } catch (error) {
163
+ console.error('[ChatHistory] Failed to load chat:', error);
164
+ return null;
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Delete chat from localStorage
170
+ * @param {string} chatId - Chat ID
171
+ * @returns {boolean} Success status
172
+ */
173
+ export function deleteChat(chatId) {
174
+ if (!chatId) return false;
175
+
176
+ const key = STORAGE_PREFIX + chatId;
177
+ try {
178
+ localStorage.removeItem(key);
179
+ const metadata = getMetadata();
180
+ metadata.allChatIds = metadata.allChatIds.filter(id => id !== chatId);
181
+ if (metadata.lastAccessedChatId === chatId) {
182
+ metadata.lastAccessedChatId = null;
183
+ }
184
+ updateMetadata(metadata);
185
+ return true;
186
+ } catch (error) {
187
+ console.error('[ChatHistory] Failed to delete chat:', error);
188
+ return false;
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Cleanup old chats
194
+ * @param {number} maxAgeDays - Max age in days
195
+ * @returns {number} Number of chats deleted
196
+ */
197
+ export function cleanupOldChats(maxAgeDays = MAX_CHAT_AGE_DAYS) {
198
+ const cutoffTime = Date.now() - (maxAgeDays * 24 * 60 * 60 * 1000);
199
+ const metadata = getMetadata();
200
+ let deletedCount = 0;
201
+
202
+ for (const chatId of [...metadata.allChatIds]) {
203
+ const key = STORAGE_PREFIX + chatId;
204
+ try {
205
+ const data = localStorage.getItem(key);
206
+ if (data) {
207
+ const chatData = JSON.parse(data);
208
+ if (chatData.updatedAt < cutoffTime) {
209
+ deleteChat(chatId);
210
+ deletedCount++;
211
+ }
212
+ }
213
+ } catch (error) {
214
+ console.error(`[ChatHistory] Failed to check chat ${chatId}:`, error);
215
+ }
216
+ }
217
+
218
+ return deletedCount;
219
+ }
220
+
221
+ /**
222
+ * Get all chat IDs
223
+ * @returns {Array<string>} Array of chat IDs
224
+ */
225
+ export function getAllChatIds() {
226
+ const metadata = getMetadata();
227
+ return metadata.allChatIds;
228
+ }
229
+
230
+ /**
231
+ * Get last accessed chat ID
232
+ * @returns {string|null} Last chat ID
233
+ */
234
+ export function getLastChatId() {
235
+ const metadata = getMetadata();
236
+ return metadata.lastAccessedChatId;
237
+ }