vibecodingmachine-core 2026.3.9-907 → 2026.3.10-1548

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.
Files changed (42) hide show
  1. package/package.json +1 -1
  2. package/src/auth/access-denied.html +119 -119
  3. package/src/auth/shared-auth-storage.js +267 -267
  4. package/src/autonomous-mode/feature-implementer.cjs +70 -70
  5. package/src/autonomous-mode/feature-implementer.js +425 -425
  6. package/src/beta-request.js +160 -160
  7. package/src/chat-management/chat-manager.cjs +71 -71
  8. package/src/chat-management/chat-manager.js +342 -342
  9. package/src/compliance/compliance-prompt.js +183 -183
  10. package/src/ide-integration/aider-cli-manager.cjs +850 -850
  11. package/src/ide-integration/applescript-manager.cjs +3215 -3215
  12. package/src/ide-integration/applescript-utils.js +314 -314
  13. package/src/ide-integration/cdp-manager.cjs +221 -221
  14. package/src/ide-integration/claude-code-cli-manager.cjs +456 -456
  15. package/src/ide-integration/cline-cli-manager.cjs +2252 -2252
  16. package/src/ide-integration/continue-cli-manager.js +431 -431
  17. package/src/ide-integration/provider-manager.cjs +595 -595
  18. package/src/ide-integration/quota-detector.cjs +399 -399
  19. package/src/ide-integration/windows-automation-manager.js +532 -4
  20. package/src/ide-integration/windows-ide-manager.js +12 -3
  21. package/src/index.cjs +142 -142
  22. package/src/llm/direct-llm-manager.cjs +1299 -1299
  23. package/src/localization/index.js +147 -147
  24. package/src/quota-management/index.js +108 -108
  25. package/src/requirement-numbering.js +164 -164
  26. package/src/sync/aws-setup.js +445 -445
  27. package/src/ui/ButtonComponents.js +247 -247
  28. package/src/ui/ChatInterface.js +499 -499
  29. package/src/ui/StateManager.js +259 -259
  30. package/src/utils/audit-logger.cjs +116 -116
  31. package/src/utils/config-helpers.cjs +94 -94
  32. package/src/utils/config-helpers.js +94 -94
  33. package/src/utils/env-helpers.js +54 -54
  34. package/src/utils/error-reporter.js +117 -117
  35. package/src/utils/gcloud-auth.cjs +394 -394
  36. package/src/utils/git-branch-manager.js +278 -278
  37. package/src/utils/logger.cjs +193 -193
  38. package/src/utils/logger.js +191 -191
  39. package/src/utils/repo-helpers.cjs +120 -120
  40. package/src/utils/repo-helpers.js +120 -120
  41. package/src/utils/update-checker.js +246 -246
  42. package/src/utils/version-checker.js +170 -170
@@ -1,499 +1,499 @@
1
- /**
2
- * Shared Chat Interface Component
3
- * Provides a consistent UI across electron app and VSCode extension
4
- */
5
-
6
- import { stateManager } from './StateManager.js';
7
- import {
8
- createAutonomousButton,
9
- createPauseButton,
10
- createStopButton,
11
- createCheckQuotaButton,
12
- createOpenIdeButton,
13
- createIdeButton,
14
- createControlButtonContainer,
15
- updateAutonomousButton,
16
- updatePauseButton,
17
- updateStopButton,
18
- updateCheckQuotaButton,
19
- updateOpenIdeButton
20
- } from './ButtonComponents.js';
21
-
22
- export class ChatInterface {
23
- constructor(container, options = {}) {
24
- this.container = container;
25
- this.options = {
26
- showIdeSelector: true,
27
- showChatMessages: true,
28
- showInput: true,
29
- showControls: true,
30
- theme: 'default', // 'default', 'vscode', 'electron'
31
- ...options
32
- };
33
-
34
- this.elements = {};
35
- this.state = stateManager.getState();
36
- this.unsubscribe = null;
37
-
38
- this.init();
39
- }
40
-
41
- init() {
42
- this.render();
43
- this.bindEvents();
44
- this.subscribeToState();
45
- }
46
-
47
- render() {
48
- this.container.innerHTML = '';
49
-
50
- // Create header
51
- const header = this.createHeader();
52
- this.container.appendChild(header);
53
-
54
- // Create IDE selector
55
- if (this.options.showIdeSelector) {
56
- const ideSelector = this.createIdeSelector();
57
- this.container.appendChild(ideSelector);
58
- }
59
-
60
- // Create status
61
- const status = this.createStatus();
62
- this.container.appendChild(status);
63
-
64
- // Create chat messages
65
- if (this.options.showChatMessages) {
66
- const messages = this.createMessages();
67
- this.container.appendChild(messages);
68
- }
69
-
70
- // Create input area
71
- if (this.options.showInput) {
72
- const input = this.createInput();
73
- this.container.appendChild(input);
74
- }
75
-
76
- // Create autonomous button
77
- const autonomousButton = this.createAutonomousButton();
78
- this.container.appendChild(autonomousButton);
79
-
80
- // Create control buttons
81
- if (this.options.showControls) {
82
- const controls = this.createControlButtons();
83
- this.container.appendChild(controls);
84
- }
85
- }
86
-
87
- createHeader() {
88
- const header = document.createElement('div');
89
- header.className = 'chat-header';
90
- header.innerHTML = `
91
- <h1>🤖 VibeCodingMachine Chat</h1>
92
- `;
93
-
94
- Object.assign(header.style, {
95
- textAlign: 'center',
96
- marginBottom: '20px'
97
- });
98
-
99
- const title = header.querySelector('h1');
100
- Object.assign(title.style, {
101
- color: this.getThemeColor('primary'),
102
- margin: '0',
103
- fontSize: '24px',
104
- fontWeight: '600'
105
- });
106
-
107
- this.elements.header = header;
108
- return header;
109
- }
110
-
111
- createIdeSelector() {
112
- const container = document.createElement('div');
113
- container.className = 'ide-selector';
114
-
115
- Object.assign(container.style, {
116
- marginBottom: '20px',
117
- textAlign: 'center'
118
- });
119
-
120
- const ides = ['vscode', 'cursor', 'windsurf'];
121
-
122
- ides.forEach(ide => {
123
- const button = createIdeButton({
124
- ide,
125
- isActive: this.state.currentIde === ide,
126
- onClick: () => this.onIdeSelect(ide)
127
- });
128
- container.appendChild(button);
129
- });
130
-
131
- const openIdeButton = createOpenIdeButton({
132
- isOpeningIde: this.state.isOpeningIde,
133
- onClick: () => this.onOpenIde()
134
- });
135
- container.appendChild(openIdeButton);
136
-
137
- this.elements.ideSelector = container;
138
- this.elements.ideButtons = container.querySelectorAll('.ide-button');
139
- this.elements.openIdeButton = openIdeButton;
140
- return container;
141
- }
142
-
143
- createStatus() {
144
- const status = document.createElement('div');
145
- status.className = 'status';
146
- status.textContent = this.state.status;
147
-
148
- Object.assign(status.style, {
149
- textAlign: 'center',
150
- margin: '10px 0',
151
- fontStyle: 'italic',
152
- color: this.getThemeColor('secondary')
153
- });
154
-
155
- this.elements.status = status;
156
- return status;
157
- }
158
-
159
- createMessages() {
160
- const container = document.createElement('div');
161
- container.className = 'chat-messages';
162
-
163
- Object.assign(container.style, {
164
- height: '400px',
165
- overflowY: 'auto',
166
- border: `1px solid ${this.getThemeColor('border')}`,
167
- borderRadius: '4px',
168
- padding: '10px',
169
- marginBottom: '20px',
170
- backgroundColor: this.getThemeColor('background')
171
- });
172
-
173
- // Add welcome message
174
- const welcome = document.createElement('div');
175
- welcome.className = 'message assistant';
176
- welcome.textContent = 'Welcome to VibeCodingMachine! Select an IDE and start chatting.';
177
-
178
- Object.assign(welcome.style, {
179
- marginBottom: '15px',
180
- padding: '10px',
181
- borderRadius: '4px',
182
- backgroundColor: this.getThemeColor('messageBackground'),
183
- border: `1px solid ${this.getThemeColor('border')}`,
184
- marginRight: '20%'
185
- });
186
-
187
- container.appendChild(welcome);
188
-
189
- this.elements.messages = container;
190
- return container;
191
- }
192
-
193
- createInput() {
194
- const container = document.createElement('div');
195
- container.className = 'input-container';
196
-
197
- Object.assign(container.style, {
198
- display: 'flex',
199
- gap: '10px',
200
- marginBottom: '10px'
201
- });
202
-
203
- const input = document.createElement('input');
204
- input.type = 'text';
205
- input.className = 'message-input';
206
- input.placeholder = 'Type your message...';
207
-
208
- Object.assign(input.style, {
209
- flex: '1',
210
- padding: '10px',
211
- border: `1px solid ${this.getThemeColor('border')}`,
212
- borderRadius: '4px',
213
- backgroundColor: this.getThemeColor('background'),
214
- color: this.getThemeColor('text')
215
- });
216
-
217
- const sendButton = document.createElement('button');
218
- sendButton.className = 'send-button';
219
- sendButton.textContent = 'Send';
220
-
221
- Object.assign(sendButton.style, {
222
- background: this.getThemeColor('primary'),
223
- color: 'white',
224
- border: 'none',
225
- padding: '10px 20px',
226
- borderRadius: '4px',
227
- cursor: 'pointer'
228
- });
229
-
230
- container.appendChild(input);
231
- container.appendChild(sendButton);
232
-
233
- this.elements.input = input;
234
- this.elements.sendButton = sendButton;
235
- return container;
236
- }
237
-
238
- createAutonomousButton() {
239
- const button = createAutonomousButton({
240
- autonomousMode: this.state.autonomousMode,
241
- isPaused: this.state.isPaused,
242
- onClick: () => this.onAutonomousToggle()
243
- });
244
-
245
- Object.assign(button.style, {
246
- width: '100%',
247
- marginTop: '10px'
248
- });
249
-
250
- this.elements.autonomousButton = button;
251
- return button;
252
- }
253
-
254
- createControlButtons() {
255
- const container = createControlButtonContainer();
256
-
257
- const pauseButton = createPauseButton({
258
- isPaused: this.state.isPaused,
259
- onClick: () => this.onPauseToggle()
260
- });
261
-
262
- const stopButton = createStopButton({
263
- autonomousMode: this.state.autonomousMode,
264
- onClick: () => this.onStop()
265
- });
266
-
267
- const checkQuotaButton = createCheckQuotaButton({
268
- isCheckingQuota: this.state.isCheckingQuota,
269
- onClick: () => this.onCheckQuota()
270
- });
271
-
272
- container.appendChild(pauseButton);
273
- container.appendChild(stopButton);
274
- container.appendChild(checkQuotaButton);
275
-
276
- this.elements.pauseButton = pauseButton;
277
- this.elements.stopButton = stopButton;
278
- this.elements.checkQuotaButton = checkQuotaButton;
279
- this.elements.controlContainer = container;
280
-
281
- return container;
282
- }
283
-
284
- bindEvents() {
285
- // Input events
286
- if (this.elements.input) {
287
- this.elements.input.addEventListener('keypress', (e) => {
288
- if (e.key === 'Enter') {
289
- this.onSendMessage();
290
- }
291
- });
292
- }
293
-
294
- if (this.elements.sendButton) {
295
- this.elements.sendButton.addEventListener('click', () => {
296
- this.onSendMessage();
297
- });
298
- }
299
- }
300
-
301
- subscribeToState() {
302
- this.unsubscribe = stateManager.subscribe((newState, oldState) => {
303
- this.updateUI(newState, oldState);
304
- });
305
- }
306
-
307
- updateUI(newState, oldState) {
308
- this.state = newState;
309
-
310
- // Update status
311
- if (this.elements.status) {
312
- this.elements.status.textContent = newState.status;
313
- }
314
-
315
- // Update autonomous button
316
- if (this.elements.autonomousButton) {
317
- updateAutonomousButton(
318
- this.elements.autonomousButton,
319
- newState.autonomousMode,
320
- newState.isPaused
321
- );
322
- }
323
-
324
- // Update pause button
325
- if (this.elements.pauseButton) {
326
- updatePauseButton(this.elements.pauseButton, newState.isPaused);
327
- }
328
-
329
- // Update stop button
330
- if (this.elements.stopButton) {
331
- updateStopButton(this.elements.stopButton, newState.autonomousMode);
332
- }
333
-
334
- // Update check quota button
335
- if (this.elements.checkQuotaButton) {
336
- updateCheckQuotaButton(this.elements.checkQuotaButton, newState.isCheckingQuota);
337
- }
338
-
339
- // Update open IDE button
340
- if (this.elements.openIdeButton) {
341
- updateOpenIdeButton(this.elements.openIdeButton, newState.isOpeningIde);
342
- }
343
-
344
- // Update IDE buttons
345
- if (this.elements.ideButtons) {
346
- this.elements.ideButtons.forEach(button => {
347
- const ide = button.dataset.ide;
348
- button.classList.toggle('active', ide === newState.currentIde);
349
- button.style.backgroundColor = ide === newState.currentIde ?
350
- this.getThemeColor('primary') : this.getThemeColor('secondary');
351
- });
352
- }
353
-
354
- // Update messages
355
- if (this.elements.messages && newState.messages.length !== oldState.messages.length) {
356
- this.updateMessages(newState.messages);
357
- }
358
- }
359
-
360
- updateMessages(messages) {
361
- // Clear existing messages except welcome
362
- const welcome = this.elements.messages.querySelector('.message.assistant');
363
- this.elements.messages.innerHTML = '';
364
- if (welcome) {
365
- this.elements.messages.appendChild(welcome);
366
- }
367
-
368
- // Add new messages
369
- messages.forEach(message => {
370
- const messageEl = document.createElement('div');
371
- messageEl.className = `message ${message.role}`;
372
- messageEl.textContent = message.text;
373
-
374
- Object.assign(messageEl.style, {
375
- marginBottom: '15px',
376
- padding: '10px',
377
- borderRadius: '4px',
378
- backgroundColor: message.role === 'user' ?
379
- this.getThemeColor('primary') : this.getThemeColor('messageBackground'),
380
- color: message.role === 'user' ? 'white' : this.getThemeColor('text'),
381
- marginLeft: message.role === 'user' ? '20%' : '0',
382
- marginRight: message.role === 'user' ? '0' : '20%'
383
- });
384
-
385
- this.elements.messages.appendChild(messageEl);
386
- });
387
-
388
- // Scroll to bottom
389
- this.elements.messages.scrollTop = this.elements.messages.scrollHeight;
390
- }
391
-
392
- getThemeColor(type) {
393
- const themes = {
394
- default: {
395
- primary: '#68217a',
396
- secondary: '#007acc',
397
- background: '#ffffff',
398
- text: '#333333',
399
- border: '#cccccc',
400
- messageBackground: '#f8f9fa'
401
- },
402
- vscode: {
403
- primary: 'var(--vscode-textLink-foreground)',
404
- secondary: 'var(--vscode-button-secondaryBackground)',
405
- background: 'var(--vscode-editor-background)',
406
- text: 'var(--vscode-editor-foreground)',
407
- border: 'var(--vscode-input-border)',
408
- messageBackground: 'var(--vscode-input-background)'
409
- },
410
- electron: {
411
- primary: '#68217a',
412
- secondary: '#007acc',
413
- background: '#ffffff',
414
- text: '#333333',
415
- border: '#cccccc',
416
- messageBackground: '#f8f9fa'
417
- }
418
- };
419
-
420
- return themes[this.options.theme]?.[type] || themes.default[type];
421
- }
422
-
423
- // Event handlers
424
- onIdeSelect(ide) {
425
- stateManager.setState({ currentIde: ide });
426
- if (this.options.onIdeSelect) {
427
- this.options.onIdeSelect(ide);
428
- }
429
- }
430
-
431
- onOpenIde() {
432
- if (this.options.onOpenIde) {
433
- this.options.onOpenIde(this.state.currentIde);
434
- }
435
- }
436
-
437
- onSendMessage() {
438
- const text = this.elements.input?.value?.trim();
439
- if (!text) return;
440
-
441
- stateManager.addMessage('user', text);
442
- this.elements.input.value = '';
443
-
444
- if (this.options.onSendMessage) {
445
- this.options.onSendMessage(text, this.state.currentIde);
446
- }
447
- }
448
-
449
- onAutonomousToggle() {
450
- if (this.state.autonomousMode) {
451
- stateManager.stopAutonomousMode();
452
- } else {
453
- stateManager.startAutonomousMode(this.state.currentIde);
454
- }
455
-
456
- if (this.options.onAutonomousToggle) {
457
- this.options.onAutonomousToggle(this.state.autonomousMode);
458
- }
459
- }
460
-
461
- onPauseToggle() {
462
- stateManager.togglePause();
463
-
464
- if (this.options.onPauseToggle) {
465
- this.options.onPauseToggle(this.state.isPaused);
466
- }
467
- }
468
-
469
- onStop() {
470
- stateManager.stopAutonomousMode();
471
-
472
- if (this.options.onStop) {
473
- this.options.onStop();
474
- }
475
- }
476
-
477
- onCheckQuota() {
478
- stateManager.startQuotaCheck();
479
-
480
- if (this.options.onCheckQuota) {
481
- this.options.onCheckQuota(this.state.currentIde);
482
- }
483
- }
484
-
485
- // Public methods
486
- addMessage(role, text) {
487
- stateManager.addMessage(role, text);
488
- }
489
-
490
- updateStatus(status) {
491
- stateManager.updateStatus(status);
492
- }
493
-
494
- destroy() {
495
- if (this.unsubscribe) {
496
- this.unsubscribe();
497
- }
498
- }
499
- }
1
+ /**
2
+ * Shared Chat Interface Component
3
+ * Provides a consistent UI across electron app and VSCode extension
4
+ */
5
+
6
+ import { stateManager } from './StateManager.js';
7
+ import {
8
+ createAutonomousButton,
9
+ createPauseButton,
10
+ createStopButton,
11
+ createCheckQuotaButton,
12
+ createOpenIdeButton,
13
+ createIdeButton,
14
+ createControlButtonContainer,
15
+ updateAutonomousButton,
16
+ updatePauseButton,
17
+ updateStopButton,
18
+ updateCheckQuotaButton,
19
+ updateOpenIdeButton
20
+ } from './ButtonComponents.js';
21
+
22
+ export class ChatInterface {
23
+ constructor(container, options = {}) {
24
+ this.container = container;
25
+ this.options = {
26
+ showIdeSelector: true,
27
+ showChatMessages: true,
28
+ showInput: true,
29
+ showControls: true,
30
+ theme: 'default', // 'default', 'vscode', 'electron'
31
+ ...options
32
+ };
33
+
34
+ this.elements = {};
35
+ this.state = stateManager.getState();
36
+ this.unsubscribe = null;
37
+
38
+ this.init();
39
+ }
40
+
41
+ init() {
42
+ this.render();
43
+ this.bindEvents();
44
+ this.subscribeToState();
45
+ }
46
+
47
+ render() {
48
+ this.container.innerHTML = '';
49
+
50
+ // Create header
51
+ const header = this.createHeader();
52
+ this.container.appendChild(header);
53
+
54
+ // Create IDE selector
55
+ if (this.options.showIdeSelector) {
56
+ const ideSelector = this.createIdeSelector();
57
+ this.container.appendChild(ideSelector);
58
+ }
59
+
60
+ // Create status
61
+ const status = this.createStatus();
62
+ this.container.appendChild(status);
63
+
64
+ // Create chat messages
65
+ if (this.options.showChatMessages) {
66
+ const messages = this.createMessages();
67
+ this.container.appendChild(messages);
68
+ }
69
+
70
+ // Create input area
71
+ if (this.options.showInput) {
72
+ const input = this.createInput();
73
+ this.container.appendChild(input);
74
+ }
75
+
76
+ // Create autonomous button
77
+ const autonomousButton = this.createAutonomousButton();
78
+ this.container.appendChild(autonomousButton);
79
+
80
+ // Create control buttons
81
+ if (this.options.showControls) {
82
+ const controls = this.createControlButtons();
83
+ this.container.appendChild(controls);
84
+ }
85
+ }
86
+
87
+ createHeader() {
88
+ const header = document.createElement('div');
89
+ header.className = 'chat-header';
90
+ header.innerHTML = `
91
+ <h1>🤖 VibeCodingMachine Chat</h1>
92
+ `;
93
+
94
+ Object.assign(header.style, {
95
+ textAlign: 'center',
96
+ marginBottom: '20px'
97
+ });
98
+
99
+ const title = header.querySelector('h1');
100
+ Object.assign(title.style, {
101
+ color: this.getThemeColor('primary'),
102
+ margin: '0',
103
+ fontSize: '24px',
104
+ fontWeight: '600'
105
+ });
106
+
107
+ this.elements.header = header;
108
+ return header;
109
+ }
110
+
111
+ createIdeSelector() {
112
+ const container = document.createElement('div');
113
+ container.className = 'ide-selector';
114
+
115
+ Object.assign(container.style, {
116
+ marginBottom: '20px',
117
+ textAlign: 'center'
118
+ });
119
+
120
+ const ides = ['vscode', 'cursor', 'windsurf'];
121
+
122
+ ides.forEach(ide => {
123
+ const button = createIdeButton({
124
+ ide,
125
+ isActive: this.state.currentIde === ide,
126
+ onClick: () => this.onIdeSelect(ide)
127
+ });
128
+ container.appendChild(button);
129
+ });
130
+
131
+ const openIdeButton = createOpenIdeButton({
132
+ isOpeningIde: this.state.isOpeningIde,
133
+ onClick: () => this.onOpenIde()
134
+ });
135
+ container.appendChild(openIdeButton);
136
+
137
+ this.elements.ideSelector = container;
138
+ this.elements.ideButtons = container.querySelectorAll('.ide-button');
139
+ this.elements.openIdeButton = openIdeButton;
140
+ return container;
141
+ }
142
+
143
+ createStatus() {
144
+ const status = document.createElement('div');
145
+ status.className = 'status';
146
+ status.textContent = this.state.status;
147
+
148
+ Object.assign(status.style, {
149
+ textAlign: 'center',
150
+ margin: '10px 0',
151
+ fontStyle: 'italic',
152
+ color: this.getThemeColor('secondary')
153
+ });
154
+
155
+ this.elements.status = status;
156
+ return status;
157
+ }
158
+
159
+ createMessages() {
160
+ const container = document.createElement('div');
161
+ container.className = 'chat-messages';
162
+
163
+ Object.assign(container.style, {
164
+ height: '400px',
165
+ overflowY: 'auto',
166
+ border: `1px solid ${this.getThemeColor('border')}`,
167
+ borderRadius: '4px',
168
+ padding: '10px',
169
+ marginBottom: '20px',
170
+ backgroundColor: this.getThemeColor('background')
171
+ });
172
+
173
+ // Add welcome message
174
+ const welcome = document.createElement('div');
175
+ welcome.className = 'message assistant';
176
+ welcome.textContent = 'Welcome to VibeCodingMachine! Select an IDE and start chatting.';
177
+
178
+ Object.assign(welcome.style, {
179
+ marginBottom: '15px',
180
+ padding: '10px',
181
+ borderRadius: '4px',
182
+ backgroundColor: this.getThemeColor('messageBackground'),
183
+ border: `1px solid ${this.getThemeColor('border')}`,
184
+ marginRight: '20%'
185
+ });
186
+
187
+ container.appendChild(welcome);
188
+
189
+ this.elements.messages = container;
190
+ return container;
191
+ }
192
+
193
+ createInput() {
194
+ const container = document.createElement('div');
195
+ container.className = 'input-container';
196
+
197
+ Object.assign(container.style, {
198
+ display: 'flex',
199
+ gap: '10px',
200
+ marginBottom: '10px'
201
+ });
202
+
203
+ const input = document.createElement('input');
204
+ input.type = 'text';
205
+ input.className = 'message-input';
206
+ input.placeholder = 'Type your message...';
207
+
208
+ Object.assign(input.style, {
209
+ flex: '1',
210
+ padding: '10px',
211
+ border: `1px solid ${this.getThemeColor('border')}`,
212
+ borderRadius: '4px',
213
+ backgroundColor: this.getThemeColor('background'),
214
+ color: this.getThemeColor('text')
215
+ });
216
+
217
+ const sendButton = document.createElement('button');
218
+ sendButton.className = 'send-button';
219
+ sendButton.textContent = 'Send';
220
+
221
+ Object.assign(sendButton.style, {
222
+ background: this.getThemeColor('primary'),
223
+ color: 'white',
224
+ border: 'none',
225
+ padding: '10px 20px',
226
+ borderRadius: '4px',
227
+ cursor: 'pointer'
228
+ });
229
+
230
+ container.appendChild(input);
231
+ container.appendChild(sendButton);
232
+
233
+ this.elements.input = input;
234
+ this.elements.sendButton = sendButton;
235
+ return container;
236
+ }
237
+
238
+ createAutonomousButton() {
239
+ const button = createAutonomousButton({
240
+ autonomousMode: this.state.autonomousMode,
241
+ isPaused: this.state.isPaused,
242
+ onClick: () => this.onAutonomousToggle()
243
+ });
244
+
245
+ Object.assign(button.style, {
246
+ width: '100%',
247
+ marginTop: '10px'
248
+ });
249
+
250
+ this.elements.autonomousButton = button;
251
+ return button;
252
+ }
253
+
254
+ createControlButtons() {
255
+ const container = createControlButtonContainer();
256
+
257
+ const pauseButton = createPauseButton({
258
+ isPaused: this.state.isPaused,
259
+ onClick: () => this.onPauseToggle()
260
+ });
261
+
262
+ const stopButton = createStopButton({
263
+ autonomousMode: this.state.autonomousMode,
264
+ onClick: () => this.onStop()
265
+ });
266
+
267
+ const checkQuotaButton = createCheckQuotaButton({
268
+ isCheckingQuota: this.state.isCheckingQuota,
269
+ onClick: () => this.onCheckQuota()
270
+ });
271
+
272
+ container.appendChild(pauseButton);
273
+ container.appendChild(stopButton);
274
+ container.appendChild(checkQuotaButton);
275
+
276
+ this.elements.pauseButton = pauseButton;
277
+ this.elements.stopButton = stopButton;
278
+ this.elements.checkQuotaButton = checkQuotaButton;
279
+ this.elements.controlContainer = container;
280
+
281
+ return container;
282
+ }
283
+
284
+ bindEvents() {
285
+ // Input events
286
+ if (this.elements.input) {
287
+ this.elements.input.addEventListener('keypress', (e) => {
288
+ if (e.key === 'Enter') {
289
+ this.onSendMessage();
290
+ }
291
+ });
292
+ }
293
+
294
+ if (this.elements.sendButton) {
295
+ this.elements.sendButton.addEventListener('click', () => {
296
+ this.onSendMessage();
297
+ });
298
+ }
299
+ }
300
+
301
+ subscribeToState() {
302
+ this.unsubscribe = stateManager.subscribe((newState, oldState) => {
303
+ this.updateUI(newState, oldState);
304
+ });
305
+ }
306
+
307
+ updateUI(newState, oldState) {
308
+ this.state = newState;
309
+
310
+ // Update status
311
+ if (this.elements.status) {
312
+ this.elements.status.textContent = newState.status;
313
+ }
314
+
315
+ // Update autonomous button
316
+ if (this.elements.autonomousButton) {
317
+ updateAutonomousButton(
318
+ this.elements.autonomousButton,
319
+ newState.autonomousMode,
320
+ newState.isPaused
321
+ );
322
+ }
323
+
324
+ // Update pause button
325
+ if (this.elements.pauseButton) {
326
+ updatePauseButton(this.elements.pauseButton, newState.isPaused);
327
+ }
328
+
329
+ // Update stop button
330
+ if (this.elements.stopButton) {
331
+ updateStopButton(this.elements.stopButton, newState.autonomousMode);
332
+ }
333
+
334
+ // Update check quota button
335
+ if (this.elements.checkQuotaButton) {
336
+ updateCheckQuotaButton(this.elements.checkQuotaButton, newState.isCheckingQuota);
337
+ }
338
+
339
+ // Update open IDE button
340
+ if (this.elements.openIdeButton) {
341
+ updateOpenIdeButton(this.elements.openIdeButton, newState.isOpeningIde);
342
+ }
343
+
344
+ // Update IDE buttons
345
+ if (this.elements.ideButtons) {
346
+ this.elements.ideButtons.forEach(button => {
347
+ const ide = button.dataset.ide;
348
+ button.classList.toggle('active', ide === newState.currentIde);
349
+ button.style.backgroundColor = ide === newState.currentIde ?
350
+ this.getThemeColor('primary') : this.getThemeColor('secondary');
351
+ });
352
+ }
353
+
354
+ // Update messages
355
+ if (this.elements.messages && newState.messages.length !== oldState.messages.length) {
356
+ this.updateMessages(newState.messages);
357
+ }
358
+ }
359
+
360
+ updateMessages(messages) {
361
+ // Clear existing messages except welcome
362
+ const welcome = this.elements.messages.querySelector('.message.assistant');
363
+ this.elements.messages.innerHTML = '';
364
+ if (welcome) {
365
+ this.elements.messages.appendChild(welcome);
366
+ }
367
+
368
+ // Add new messages
369
+ messages.forEach(message => {
370
+ const messageEl = document.createElement('div');
371
+ messageEl.className = `message ${message.role}`;
372
+ messageEl.textContent = message.text;
373
+
374
+ Object.assign(messageEl.style, {
375
+ marginBottom: '15px',
376
+ padding: '10px',
377
+ borderRadius: '4px',
378
+ backgroundColor: message.role === 'user' ?
379
+ this.getThemeColor('primary') : this.getThemeColor('messageBackground'),
380
+ color: message.role === 'user' ? 'white' : this.getThemeColor('text'),
381
+ marginLeft: message.role === 'user' ? '20%' : '0',
382
+ marginRight: message.role === 'user' ? '0' : '20%'
383
+ });
384
+
385
+ this.elements.messages.appendChild(messageEl);
386
+ });
387
+
388
+ // Scroll to bottom
389
+ this.elements.messages.scrollTop = this.elements.messages.scrollHeight;
390
+ }
391
+
392
+ getThemeColor(type) {
393
+ const themes = {
394
+ default: {
395
+ primary: '#68217a',
396
+ secondary: '#007acc',
397
+ background: '#ffffff',
398
+ text: '#333333',
399
+ border: '#cccccc',
400
+ messageBackground: '#f8f9fa'
401
+ },
402
+ vscode: {
403
+ primary: 'var(--vscode-textLink-foreground)',
404
+ secondary: 'var(--vscode-button-secondaryBackground)',
405
+ background: 'var(--vscode-editor-background)',
406
+ text: 'var(--vscode-editor-foreground)',
407
+ border: 'var(--vscode-input-border)',
408
+ messageBackground: 'var(--vscode-input-background)'
409
+ },
410
+ electron: {
411
+ primary: '#68217a',
412
+ secondary: '#007acc',
413
+ background: '#ffffff',
414
+ text: '#333333',
415
+ border: '#cccccc',
416
+ messageBackground: '#f8f9fa'
417
+ }
418
+ };
419
+
420
+ return themes[this.options.theme]?.[type] || themes.default[type];
421
+ }
422
+
423
+ // Event handlers
424
+ onIdeSelect(ide) {
425
+ stateManager.setState({ currentIde: ide });
426
+ if (this.options.onIdeSelect) {
427
+ this.options.onIdeSelect(ide);
428
+ }
429
+ }
430
+
431
+ onOpenIde() {
432
+ if (this.options.onOpenIde) {
433
+ this.options.onOpenIde(this.state.currentIde);
434
+ }
435
+ }
436
+
437
+ onSendMessage() {
438
+ const text = this.elements.input?.value?.trim();
439
+ if (!text) return;
440
+
441
+ stateManager.addMessage('user', text);
442
+ this.elements.input.value = '';
443
+
444
+ if (this.options.onSendMessage) {
445
+ this.options.onSendMessage(text, this.state.currentIde);
446
+ }
447
+ }
448
+
449
+ onAutonomousToggle() {
450
+ if (this.state.autonomousMode) {
451
+ stateManager.stopAutonomousMode();
452
+ } else {
453
+ stateManager.startAutonomousMode(this.state.currentIde);
454
+ }
455
+
456
+ if (this.options.onAutonomousToggle) {
457
+ this.options.onAutonomousToggle(this.state.autonomousMode);
458
+ }
459
+ }
460
+
461
+ onPauseToggle() {
462
+ stateManager.togglePause();
463
+
464
+ if (this.options.onPauseToggle) {
465
+ this.options.onPauseToggle(this.state.isPaused);
466
+ }
467
+ }
468
+
469
+ onStop() {
470
+ stateManager.stopAutonomousMode();
471
+
472
+ if (this.options.onStop) {
473
+ this.options.onStop();
474
+ }
475
+ }
476
+
477
+ onCheckQuota() {
478
+ stateManager.startQuotaCheck();
479
+
480
+ if (this.options.onCheckQuota) {
481
+ this.options.onCheckQuota(this.state.currentIde);
482
+ }
483
+ }
484
+
485
+ // Public methods
486
+ addMessage(role, text) {
487
+ stateManager.addMessage(role, text);
488
+ }
489
+
490
+ updateStatus(status) {
491
+ stateManager.updateStatus(status);
492
+ }
493
+
494
+ destroy() {
495
+ if (this.unsubscribe) {
496
+ this.unsubscribe();
497
+ }
498
+ }
499
+ }