vibesurf 0.1.9a5__py3-none-any.whl → 0.1.10__py3-none-any.whl
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.
- vibe_surf/_version.py +2 -2
- vibe_surf/agents/vibe_surf_agent.py +25 -15
- vibe_surf/backend/api/browser.py +66 -0
- vibe_surf/backend/api/task.py +2 -1
- vibe_surf/backend/main.py +76 -1
- vibe_surf/backend/shared_state.py +2 -0
- vibe_surf/browser/agent_browser_session.py +312 -62
- vibe_surf/browser/browser_manager.py +57 -92
- vibe_surf/browser/watchdogs/dom_watchdog.py +43 -43
- vibe_surf/chrome_extension/background.js +84 -0
- vibe_surf/chrome_extension/manifest.json +3 -1
- vibe_surf/chrome_extension/scripts/file-manager.js +526 -0
- vibe_surf/chrome_extension/scripts/history-manager.js +658 -0
- vibe_surf/chrome_extension/scripts/modal-manager.js +487 -0
- vibe_surf/chrome_extension/scripts/session-manager.js +31 -8
- vibe_surf/chrome_extension/scripts/settings-manager.js +1214 -0
- vibe_surf/chrome_extension/scripts/ui-manager.js +770 -3186
- vibe_surf/chrome_extension/sidepanel.html +27 -4
- vibe_surf/chrome_extension/styles/activity.css +574 -0
- vibe_surf/chrome_extension/styles/base.css +76 -0
- vibe_surf/chrome_extension/styles/history-modal.css +791 -0
- vibe_surf/chrome_extension/styles/input.css +429 -0
- vibe_surf/chrome_extension/styles/layout.css +186 -0
- vibe_surf/chrome_extension/styles/responsive.css +454 -0
- vibe_surf/chrome_extension/styles/settings-environment.css +165 -0
- vibe_surf/chrome_extension/styles/settings-forms.css +389 -0
- vibe_surf/chrome_extension/styles/settings-modal.css +141 -0
- vibe_surf/chrome_extension/styles/settings-profiles.css +244 -0
- vibe_surf/chrome_extension/styles/settings-responsive.css +144 -0
- vibe_surf/chrome_extension/styles/settings-utilities.css +25 -0
- vibe_surf/chrome_extension/styles/variables.css +54 -0
- vibe_surf/cli.py +1 -0
- vibe_surf/controller/vibesurf_tools.py +0 -2
- {vibesurf-0.1.9a5.dist-info → vibesurf-0.1.10.dist-info}/METADATA +18 -2
- {vibesurf-0.1.9a5.dist-info → vibesurf-0.1.10.dist-info}/RECORD +39 -23
- vibe_surf/chrome_extension/styles/main.css +0 -2338
- vibe_surf/chrome_extension/styles/settings.css +0 -1100
- {vibesurf-0.1.9a5.dist-info → vibesurf-0.1.10.dist-info}/WHEEL +0 -0
- {vibesurf-0.1.9a5.dist-info → vibesurf-0.1.10.dist-info}/entry_points.txt +0 -0
- {vibesurf-0.1.9a5.dist-info → vibesurf-0.1.10.dist-info}/licenses/LICENSE +0 -0
- {vibesurf-0.1.9a5.dist-info → vibesurf-0.1.10.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
// Modal Manager - Handles modal dialogs and user confirmations
|
|
2
|
+
// Manages warning modals, confirmation dialogs, and generic modal utilities
|
|
3
|
+
|
|
4
|
+
class VibeSurfModalManager {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.state = {
|
|
7
|
+
activeModals: new Set(),
|
|
8
|
+
modalCounter: 0
|
|
9
|
+
};
|
|
10
|
+
this.eventListeners = new Map();
|
|
11
|
+
|
|
12
|
+
this.bindGlobalEvents();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
bindGlobalEvents() {
|
|
16
|
+
// Handle escape key to close modals
|
|
17
|
+
document.addEventListener('keydown', (e) => {
|
|
18
|
+
if (e.key === 'Escape') {
|
|
19
|
+
this.closeTopModal();
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Handle background clicks to close modals
|
|
24
|
+
document.addEventListener('click', (e) => {
|
|
25
|
+
if (e.target.classList.contains('modal-overlay')) {
|
|
26
|
+
this.closeModal(e.target.querySelector('.modal'));
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Event system for communicating with main UI manager
|
|
32
|
+
on(event, callback) {
|
|
33
|
+
if (!this.eventListeners.has(event)) {
|
|
34
|
+
this.eventListeners.set(event, []);
|
|
35
|
+
}
|
|
36
|
+
this.eventListeners.get(event).push(callback);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
emit(event, data) {
|
|
40
|
+
if (this.eventListeners.has(event)) {
|
|
41
|
+
this.eventListeners.get(event).forEach(callback => {
|
|
42
|
+
try {
|
|
43
|
+
callback(data);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(`[ModalManager] Event callback error for ${event}:`, error);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Warning Modal
|
|
52
|
+
showWarningModal(title, message, options = {}) {
|
|
53
|
+
const {
|
|
54
|
+
confirmText = 'OK',
|
|
55
|
+
showCancel = false,
|
|
56
|
+
cancelText = 'Cancel',
|
|
57
|
+
onConfirm = null,
|
|
58
|
+
onCancel = null,
|
|
59
|
+
className = ''
|
|
60
|
+
} = options;
|
|
61
|
+
|
|
62
|
+
const modalId = this.generateModalId();
|
|
63
|
+
|
|
64
|
+
const modalHTML = `
|
|
65
|
+
<div class="modal-overlay" id="${modalId}-overlay">
|
|
66
|
+
<div class="modal warning-modal ${className}" id="${modalId}">
|
|
67
|
+
<div class="modal-header">
|
|
68
|
+
<h3>${this.escapeHtml(title)}</h3>
|
|
69
|
+
<button class="modal-close-btn" data-modal-id="${modalId}">×</button>
|
|
70
|
+
</div>
|
|
71
|
+
<div class="modal-body">
|
|
72
|
+
<div class="warning-icon">⚠️</div>
|
|
73
|
+
<p>${this.escapeHtml(message)}</p>
|
|
74
|
+
</div>
|
|
75
|
+
<div class="modal-footer">
|
|
76
|
+
${showCancel ? `<button class="btn-secondary modal-cancel-btn" data-modal-id="${modalId}">${this.escapeHtml(cancelText)}</button>` : ''}
|
|
77
|
+
<button class="btn-primary modal-confirm-btn" data-modal-id="${modalId}">${this.escapeHtml(confirmText)}</button>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
`;
|
|
82
|
+
|
|
83
|
+
// Add to DOM
|
|
84
|
+
document.body.insertAdjacentHTML('beforeend', modalHTML);
|
|
85
|
+
|
|
86
|
+
const modal = document.getElementById(modalId);
|
|
87
|
+
const overlay = document.getElementById(`${modalId}-overlay`);
|
|
88
|
+
|
|
89
|
+
// Track active modal
|
|
90
|
+
this.state.activeModals.add(modalId);
|
|
91
|
+
|
|
92
|
+
// Add event listeners
|
|
93
|
+
this.bindModalEvents(modalId, { onConfirm, onCancel });
|
|
94
|
+
|
|
95
|
+
// Show modal
|
|
96
|
+
requestAnimationFrame(() => {
|
|
97
|
+
overlay.classList.add('show');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return modalId;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Confirmation Modal
|
|
104
|
+
showConfirmModal(title, message, options = {}) {
|
|
105
|
+
const {
|
|
106
|
+
confirmText = 'Confirm',
|
|
107
|
+
cancelText = 'Cancel',
|
|
108
|
+
onConfirm = null,
|
|
109
|
+
onCancel = null,
|
|
110
|
+
className = '',
|
|
111
|
+
type = 'question' // question, danger, info
|
|
112
|
+
} = options;
|
|
113
|
+
|
|
114
|
+
const modalId = this.generateModalId();
|
|
115
|
+
|
|
116
|
+
const iconMap = {
|
|
117
|
+
question: '❓',
|
|
118
|
+
danger: '🚨',
|
|
119
|
+
info: 'ℹ️'
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const icon = iconMap[type] || iconMap.question;
|
|
123
|
+
|
|
124
|
+
const modalHTML = `
|
|
125
|
+
<div class="modal-overlay" id="${modalId}-overlay">
|
|
126
|
+
<div class="modal confirm-modal ${className}" id="${modalId}">
|
|
127
|
+
<div class="modal-header">
|
|
128
|
+
<h3>${this.escapeHtml(title)}</h3>
|
|
129
|
+
<button class="modal-close-btn" data-modal-id="${modalId}">×</button>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="modal-body">
|
|
132
|
+
<div class="confirm-icon">${icon}</div>
|
|
133
|
+
<p>${this.escapeHtml(message)}</p>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="modal-footer">
|
|
136
|
+
<button class="btn-secondary modal-cancel-btn" data-modal-id="${modalId}">${this.escapeHtml(cancelText)}</button>
|
|
137
|
+
<button class="btn-primary modal-confirm-btn" data-modal-id="${modalId}" ${type === 'danger' ? 'data-danger="true"' : ''}>${this.escapeHtml(confirmText)}</button>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
`;
|
|
142
|
+
|
|
143
|
+
// Add to DOM
|
|
144
|
+
document.body.insertAdjacentHTML('beforeend', modalHTML);
|
|
145
|
+
|
|
146
|
+
const modal = document.getElementById(modalId);
|
|
147
|
+
const overlay = document.getElementById(`${modalId}-overlay`);
|
|
148
|
+
|
|
149
|
+
// Track active modal
|
|
150
|
+
this.state.activeModals.add(modalId);
|
|
151
|
+
|
|
152
|
+
// Add event listeners
|
|
153
|
+
this.bindModalEvents(modalId, { onConfirm, onCancel });
|
|
154
|
+
|
|
155
|
+
// Show modal
|
|
156
|
+
requestAnimationFrame(() => {
|
|
157
|
+
overlay.classList.add('show');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return modalId;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Generic Modal Creator
|
|
164
|
+
createModal(content, options = {}) {
|
|
165
|
+
const {
|
|
166
|
+
title = '',
|
|
167
|
+
className = '',
|
|
168
|
+
showCloseButton = true,
|
|
169
|
+
backdrop = true,
|
|
170
|
+
onShow = null,
|
|
171
|
+
onHide = null
|
|
172
|
+
} = options;
|
|
173
|
+
|
|
174
|
+
const modalId = this.generateModalId();
|
|
175
|
+
|
|
176
|
+
const modalHTML = `
|
|
177
|
+
<div class="modal-overlay ${backdrop ? 'backdrop' : ''}" id="${modalId}-overlay">
|
|
178
|
+
<div class="modal ${className}" id="${modalId}">
|
|
179
|
+
${title || showCloseButton ? `
|
|
180
|
+
<div class="modal-header">
|
|
181
|
+
${title ? `<h3>${this.escapeHtml(title)}</h3>` : ''}
|
|
182
|
+
${showCloseButton ? `<button class="modal-close-btn" data-modal-id="${modalId}">×</button>` : ''}
|
|
183
|
+
</div>
|
|
184
|
+
` : ''}
|
|
185
|
+
<div class="modal-body">
|
|
186
|
+
${content}
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
`;
|
|
191
|
+
|
|
192
|
+
// Add to DOM
|
|
193
|
+
document.body.insertAdjacentHTML('beforeend', modalHTML);
|
|
194
|
+
|
|
195
|
+
const modal = document.getElementById(modalId);
|
|
196
|
+
const overlay = document.getElementById(`${modalId}-overlay`);
|
|
197
|
+
|
|
198
|
+
// Track active modal
|
|
199
|
+
this.state.activeModals.add(modalId);
|
|
200
|
+
|
|
201
|
+
// Add basic event listeners
|
|
202
|
+
this.bindModalEvents(modalId, { onShow, onHide });
|
|
203
|
+
|
|
204
|
+
// Show modal
|
|
205
|
+
requestAnimationFrame(() => {
|
|
206
|
+
overlay.classList.add('show');
|
|
207
|
+
if (onShow) onShow(modal);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
modalId,
|
|
212
|
+
modal,
|
|
213
|
+
overlay,
|
|
214
|
+
close: () => this.closeModal(modal)
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Modal Event Binding
|
|
219
|
+
bindModalEvents(modalId, callbacks = {}) {
|
|
220
|
+
const { onConfirm, onCancel, onShow, onHide } = callbacks;
|
|
221
|
+
|
|
222
|
+
// Close button
|
|
223
|
+
const closeBtn = document.querySelector(`[data-modal-id="${modalId}"].modal-close-btn`);
|
|
224
|
+
if (closeBtn) {
|
|
225
|
+
closeBtn.addEventListener('click', () => {
|
|
226
|
+
this.closeModal(document.getElementById(modalId));
|
|
227
|
+
if (onCancel) onCancel();
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Confirm button
|
|
232
|
+
const confirmBtn = document.querySelector(`[data-modal-id="${modalId}"].modal-confirm-btn`);
|
|
233
|
+
if (confirmBtn) {
|
|
234
|
+
confirmBtn.addEventListener('click', () => {
|
|
235
|
+
if (onConfirm) {
|
|
236
|
+
const result = onConfirm();
|
|
237
|
+
// Only close if callback doesn't return false
|
|
238
|
+
if (result !== false) {
|
|
239
|
+
this.closeModal(document.getElementById(modalId));
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
this.closeModal(document.getElementById(modalId));
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Cancel button
|
|
248
|
+
const cancelBtn = document.querySelector(`[data-modal-id="${modalId}"].modal-cancel-btn`);
|
|
249
|
+
if (cancelBtn) {
|
|
250
|
+
cancelBtn.addEventListener('click', () => {
|
|
251
|
+
this.closeModal(document.getElementById(modalId));
|
|
252
|
+
if (onCancel) onCancel();
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Close Modal
|
|
258
|
+
closeModal(modal) {
|
|
259
|
+
if (!modal) return;
|
|
260
|
+
|
|
261
|
+
const modalId = modal.id;
|
|
262
|
+
const overlay = document.getElementById(`${modalId}-overlay`);
|
|
263
|
+
|
|
264
|
+
if (overlay) {
|
|
265
|
+
overlay.classList.remove('show');
|
|
266
|
+
|
|
267
|
+
// Remove from DOM after animation
|
|
268
|
+
setTimeout(() => {
|
|
269
|
+
if (overlay.parentNode) {
|
|
270
|
+
overlay.parentNode.removeChild(overlay);
|
|
271
|
+
}
|
|
272
|
+
this.state.activeModals.delete(modalId);
|
|
273
|
+
}, 300); // Match CSS transition duration
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Close the topmost modal
|
|
278
|
+
closeTopModal() {
|
|
279
|
+
const modalIds = Array.from(this.state.activeModals);
|
|
280
|
+
if (modalIds.length > 0) {
|
|
281
|
+
const topModalId = modalIds[modalIds.length - 1];
|
|
282
|
+
const modal = document.getElementById(topModalId);
|
|
283
|
+
if (modal) {
|
|
284
|
+
this.closeModal(modal);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Close all modals
|
|
290
|
+
closeAllModals() {
|
|
291
|
+
const modalIds = Array.from(this.state.activeModals);
|
|
292
|
+
modalIds.forEach(modalId => {
|
|
293
|
+
const modal = document.getElementById(modalId);
|
|
294
|
+
if (modal) {
|
|
295
|
+
this.closeModal(modal);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Utility Methods
|
|
301
|
+
generateModalId() {
|
|
302
|
+
return `modal-${++this.state.modalCounter}-${Date.now()}`;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
escapeHtml(text) {
|
|
306
|
+
if (typeof text !== 'string') return '';
|
|
307
|
+
const div = document.createElement('div');
|
|
308
|
+
div.textContent = text;
|
|
309
|
+
return div.innerHTML;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Promise-based modal methods
|
|
313
|
+
showWarningModalAsync(title, message, options = {}) {
|
|
314
|
+
return new Promise((resolve) => {
|
|
315
|
+
this.showWarningModal(title, message, {
|
|
316
|
+
...options,
|
|
317
|
+
onConfirm: () => {
|
|
318
|
+
if (options.onConfirm) options.onConfirm();
|
|
319
|
+
resolve(true);
|
|
320
|
+
},
|
|
321
|
+
onCancel: () => {
|
|
322
|
+
if (options.onCancel) options.onCancel();
|
|
323
|
+
resolve(false);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
showConfirmModalAsync(title, message, options = {}) {
|
|
330
|
+
return new Promise((resolve) => {
|
|
331
|
+
this.showConfirmModal(title, message, {
|
|
332
|
+
...options,
|
|
333
|
+
onConfirm: async () => {
|
|
334
|
+
try {
|
|
335
|
+
let result = true;
|
|
336
|
+
if (options.onConfirm) {
|
|
337
|
+
result = await options.onConfirm();
|
|
338
|
+
// If onConfirm returns false, don't resolve with true
|
|
339
|
+
if (result === false) {
|
|
340
|
+
resolve(false);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
resolve(true);
|
|
345
|
+
} catch (error) {
|
|
346
|
+
console.error('[ModalManager] onConfirm error:', error);
|
|
347
|
+
resolve(false);
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
onCancel: async () => {
|
|
351
|
+
try {
|
|
352
|
+
if (options.onCancel) {
|
|
353
|
+
await options.onCancel();
|
|
354
|
+
}
|
|
355
|
+
resolve(false);
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.error('[ModalManager] onCancel error:', error);
|
|
358
|
+
resolve(false);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Modal state queries
|
|
366
|
+
hasActiveModals() {
|
|
367
|
+
return this.state.activeModals.size > 0;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
getActiveModalCount() {
|
|
371
|
+
return this.state.activeModals.size;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
isModalActive(modalId) {
|
|
375
|
+
return this.state.activeModals.has(modalId);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Quick notification modal (auto-close)
|
|
379
|
+
showNotificationModal(message, type = 'info', duration = 3000) {
|
|
380
|
+
const typeIcons = {
|
|
381
|
+
success: '✅',
|
|
382
|
+
error: '❌',
|
|
383
|
+
warning: '⚠️',
|
|
384
|
+
info: 'ℹ️'
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
const icon = typeIcons[type] || typeIcons.info;
|
|
388
|
+
const typeClass = `notification-${type}`;
|
|
389
|
+
|
|
390
|
+
const modalData = this.createModal(`
|
|
391
|
+
<div class="notification-content">
|
|
392
|
+
<div class="notification-icon">${icon}</div>
|
|
393
|
+
<div class="notification-message">${this.escapeHtml(message)}</div>
|
|
394
|
+
</div>
|
|
395
|
+
`, {
|
|
396
|
+
className: `notification-modal ${typeClass}`,
|
|
397
|
+
showCloseButton: false,
|
|
398
|
+
backdrop: false
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// Auto-close after duration
|
|
402
|
+
if (duration > 0) {
|
|
403
|
+
setTimeout(() => {
|
|
404
|
+
modalData.close();
|
|
405
|
+
}, duration);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return modalData.modalId;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Quick input modal
|
|
412
|
+
showInputModal(title, placeholder = '', defaultValue = '', options = {}) {
|
|
413
|
+
const {
|
|
414
|
+
inputType = 'text',
|
|
415
|
+
confirmText = 'OK',
|
|
416
|
+
cancelText = 'Cancel',
|
|
417
|
+
onConfirm = null,
|
|
418
|
+
onCancel = null,
|
|
419
|
+
validator = null
|
|
420
|
+
} = options;
|
|
421
|
+
|
|
422
|
+
return new Promise((resolve) => {
|
|
423
|
+
const inputId = `input-${Date.now()}`;
|
|
424
|
+
|
|
425
|
+
const modalData = this.createModal(`
|
|
426
|
+
<div class="input-modal-content">
|
|
427
|
+
<label for="${inputId}" class="input-label">${title}</label>
|
|
428
|
+
<input type="${inputType}" id="${inputId}" class="modal-input"
|
|
429
|
+
placeholder="${this.escapeHtml(placeholder)}"
|
|
430
|
+
value="${this.escapeHtml(defaultValue)}">
|
|
431
|
+
<div class="modal-footer">
|
|
432
|
+
<button class="btn-secondary input-cancel-btn">${this.escapeHtml(cancelText)}</button>
|
|
433
|
+
<button class="btn-primary input-confirm-btn">${this.escapeHtml(confirmText)}</button>
|
|
434
|
+
</div>
|
|
435
|
+
</div>
|
|
436
|
+
`, {
|
|
437
|
+
className: 'input-modal',
|
|
438
|
+
showCloseButton: true
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
const input = document.getElementById(inputId);
|
|
442
|
+
const confirmBtn = modalData.modal.querySelector('.input-confirm-btn');
|
|
443
|
+
const cancelBtn = modalData.modal.querySelector('.input-cancel-btn');
|
|
444
|
+
|
|
445
|
+
// Focus input
|
|
446
|
+
setTimeout(() => input.focus(), 100);
|
|
447
|
+
|
|
448
|
+
const handleConfirm = () => {
|
|
449
|
+
const value = input.value.trim();
|
|
450
|
+
|
|
451
|
+
if (validator && !validator(value)) {
|
|
452
|
+
return; // Don't close modal if validation fails
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
modalData.close();
|
|
456
|
+
if (onConfirm) onConfirm(value);
|
|
457
|
+
resolve(value);
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
const handleCancel = () => {
|
|
461
|
+
modalData.close();
|
|
462
|
+
if (onCancel) onCancel();
|
|
463
|
+
resolve(null);
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
confirmBtn.addEventListener('click', handleConfirm);
|
|
467
|
+
cancelBtn.addEventListener('click', handleCancel);
|
|
468
|
+
|
|
469
|
+
// Enter key to confirm
|
|
470
|
+
input.addEventListener('keydown', (e) => {
|
|
471
|
+
if (e.key === 'Enter') {
|
|
472
|
+
handleConfirm();
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Get current state
|
|
479
|
+
getState() {
|
|
480
|
+
return { ...this.state };
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Export for use in other modules
|
|
485
|
+
if (typeof window !== 'undefined') {
|
|
486
|
+
window.VibeSurfModalManager = VibeSurfModalManager;
|
|
487
|
+
}
|
|
@@ -7,7 +7,7 @@ class VibeSurfSessionManager {
|
|
|
7
7
|
this.currentSession = null;
|
|
8
8
|
this.activityLogs = [];
|
|
9
9
|
this.pollingInterval = null;
|
|
10
|
-
this.pollingFrequency =
|
|
10
|
+
this.pollingFrequency = 300; // 300ms for faster response
|
|
11
11
|
this.isPolling = false;
|
|
12
12
|
this.eventListeners = new Map();
|
|
13
13
|
|
|
@@ -201,8 +201,18 @@ class VibeSurfSessionManager {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
try {
|
|
204
|
-
|
|
205
|
-
|
|
204
|
+
// Stop any existing polling before starting new task
|
|
205
|
+
this.stopActivityPolling();
|
|
206
|
+
|
|
207
|
+
// Reset activity logs for new task to ensure proper index synchronization
|
|
208
|
+
this.activityLogs = [];
|
|
209
|
+
|
|
210
|
+
// Sync with server logs to get the correct starting state
|
|
211
|
+
try {
|
|
212
|
+
await this.syncActivityLogsFromServer();
|
|
213
|
+
} catch (error) {
|
|
214
|
+
this.activityLogs = [];
|
|
215
|
+
}
|
|
206
216
|
|
|
207
217
|
const taskPayload = {
|
|
208
218
|
session_id: this.currentSession.id,
|
|
@@ -220,12 +230,12 @@ class VibeSurfSessionManager {
|
|
|
220
230
|
submittedAt: new Date().toISOString()
|
|
221
231
|
};
|
|
222
232
|
|
|
223
|
-
// Start activity polling
|
|
224
|
-
this.startActivityPolling();
|
|
225
|
-
|
|
226
233
|
// Store updated session
|
|
227
234
|
await this.storeSessionData();
|
|
228
235
|
|
|
236
|
+
// Start polling after task submission and sync
|
|
237
|
+
this.startActivityPolling();
|
|
238
|
+
|
|
229
239
|
this.emit('taskSubmitted', {
|
|
230
240
|
sessionId: this.currentSession.id,
|
|
231
241
|
task: this.currentSession.currentTask,
|
|
@@ -273,6 +283,13 @@ class VibeSurfSessionManager {
|
|
|
273
283
|
await this.storeSessionData();
|
|
274
284
|
}
|
|
275
285
|
|
|
286
|
+
// Sync activity logs before resuming polling to ensure index consistency
|
|
287
|
+
try {
|
|
288
|
+
await this.syncActivityLogsFromServer();
|
|
289
|
+
} catch (error) {
|
|
290
|
+
// Continue with existing logs if sync fails
|
|
291
|
+
}
|
|
292
|
+
|
|
276
293
|
// Restart polling when task is resumed
|
|
277
294
|
this.startActivityPolling();
|
|
278
295
|
|
|
@@ -298,6 +315,13 @@ class VibeSurfSessionManager {
|
|
|
298
315
|
|
|
299
316
|
// Stop polling when task is stopped
|
|
300
317
|
this.stopActivityPolling();
|
|
318
|
+
|
|
319
|
+
// Sync final activity logs to capture any termination messages
|
|
320
|
+
try {
|
|
321
|
+
await this.syncActivityLogsFromServer();
|
|
322
|
+
} catch (error) {
|
|
323
|
+
// Continue if sync fails
|
|
324
|
+
}
|
|
301
325
|
|
|
302
326
|
this.emit('taskStopped', { sessionId: this.currentSession?.id, response });
|
|
303
327
|
|
|
@@ -358,8 +382,7 @@ class VibeSurfSessionManager {
|
|
|
358
382
|
|
|
359
383
|
if (response && activityLog) {
|
|
360
384
|
const prevActivityLog = this.activityLogs.length > 0 ? this.activityLogs[this.activityLogs.length - 1] : null;
|
|
361
|
-
|
|
362
|
-
// 检查是否为新的、不重复的activity log
|
|
385
|
+
|
|
363
386
|
const isNewLog = !prevActivityLog || !this.areLogsEqual(prevActivityLog, activityLog);
|
|
364
387
|
|
|
365
388
|
if (isNewLog) {
|