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.
- package/dist/vg-coder-bundle.js +4 -4
- package/package.json +2 -4
- package/src/index.js +5 -11
- package/src/server/api-server.js +14 -1
- package/src/server/views/css/agent-panel.css +358 -0
- package/src/server/views/css/browser-panel.css +97 -0
- package/src/server/views/css/tool-window.css +70 -0
- package/src/server/views/dashboard.css +3 -0
- package/src/server/views/dashboard.html +53 -0
- package/src/server/views/js/features/agent-panel.js +586 -0
- package/src/server/views/js/features/browser-panel.js +130 -0
- package/src/server/views/js/features/git-view.js +1 -1
- package/src/server/views/js/features/keyboard-shortcuts.js +1 -1
- package/src/server/views/js/features/resize.js +102 -0
- package/src/server/views/js/features/tool-window.js +176 -14
- package/src/server/views/js/main.js +4 -0
- package/src/server/views/js/utils/chat-history-manager.js +237 -0
- package/src/server/views/vg-coder/background.js +163 -3
- package/src/server/views/vg-coder/controller.js +26 -3
- package/src/server/views/vg-coder/manifest.json +3 -1
|
@@ -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
|
+
}
|