vibecodingmachine-core 1.0.0

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 (54) hide show
  1. package/.babelrc +13 -0
  2. package/README.md +28 -0
  3. package/__tests__/applescript-manager-claude-fix.test.js +286 -0
  4. package/__tests__/requirement-2-auto-start-looping.test.js +69 -0
  5. package/__tests__/requirement-3-auto-start-looping.test.js +69 -0
  6. package/__tests__/requirement-4-auto-start-looping.test.js +69 -0
  7. package/__tests__/requirement-6-auto-start-looping.test.js +73 -0
  8. package/__tests__/requirement-7-status-tracking.test.js +332 -0
  9. package/jest.config.js +18 -0
  10. package/jest.setup.js +12 -0
  11. package/package.json +46 -0
  12. package/src/auth/access-denied.html +119 -0
  13. package/src/auth/shared-auth-storage.js +230 -0
  14. package/src/autonomous-mode/feature-implementer.cjs +70 -0
  15. package/src/autonomous-mode/feature-implementer.js +425 -0
  16. package/src/chat-management/chat-manager.cjs +71 -0
  17. package/src/chat-management/chat-manager.js +342 -0
  18. package/src/ide-integration/__tests__/applescript-manager-thread-closure.test.js +227 -0
  19. package/src/ide-integration/aider-cli-manager.cjs +850 -0
  20. package/src/ide-integration/applescript-diagnostics.js +0 -0
  21. package/src/ide-integration/applescript-manager.cjs +1088 -0
  22. package/src/ide-integration/applescript-manager.js +2803 -0
  23. package/src/ide-integration/applescript-open-apps.js +0 -0
  24. package/src/ide-integration/applescript-read-response.js +0 -0
  25. package/src/ide-integration/applescript-send-text.js +0 -0
  26. package/src/ide-integration/applescript-thread-closure.js +0 -0
  27. package/src/ide-integration/applescript-utils.js +306 -0
  28. package/src/ide-integration/cdp-manager.cjs +221 -0
  29. package/src/ide-integration/cdp-manager.js +321 -0
  30. package/src/ide-integration/claude-code-cli-manager.cjs +301 -0
  31. package/src/ide-integration/cline-cli-manager.cjs +2252 -0
  32. package/src/ide-integration/continue-cli-manager.js +431 -0
  33. package/src/ide-integration/provider-manager.cjs +354 -0
  34. package/src/ide-integration/quota-detector.cjs +34 -0
  35. package/src/ide-integration/quota-detector.js +349 -0
  36. package/src/ide-integration/windows-automation-manager.js +262 -0
  37. package/src/index.cjs +43 -0
  38. package/src/index.js +17 -0
  39. package/src/llm/direct-llm-manager.cjs +609 -0
  40. package/src/ui/ButtonComponents.js +247 -0
  41. package/src/ui/ChatInterface.js +499 -0
  42. package/src/ui/StateManager.js +259 -0
  43. package/src/ui/StateManager.test.js +0 -0
  44. package/src/utils/audit-logger.cjs +116 -0
  45. package/src/utils/config-helpers.cjs +94 -0
  46. package/src/utils/config-helpers.js +94 -0
  47. package/src/utils/electron-update-checker.js +78 -0
  48. package/src/utils/gcloud-auth.cjs +394 -0
  49. package/src/utils/logger.cjs +193 -0
  50. package/src/utils/logger.js +191 -0
  51. package/src/utils/repo-helpers.cjs +120 -0
  52. package/src/utils/repo-helpers.js +120 -0
  53. package/src/utils/requirement-helpers.js +432 -0
  54. package/src/utils/update-checker.js +167 -0
@@ -0,0 +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
+ }