vibecodingmachine-core 2025.12.6-1702 → 2025.12.24-2348

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.
@@ -2,6 +2,7 @@
2
2
  // Handles AppleScript-based interactions with IDEs that don't support CDP
3
3
 
4
4
  const { execSync } = require('child_process');
5
+ const { t } = require('../localization');
5
6
 
6
7
  /**
7
8
  * AppleScript Manager for IDE interactions
@@ -182,11 +183,43 @@ class AppleScriptManager {
182
183
  set frontmost to true
183
184
  delay 0.8
184
185
 
185
- -- Try to find and click "Select another model" button
186
+ -- Try to find model selection button with multiple possible texts
186
187
  try
187
- set modelButtons to buttons of window 1 whose name contains "Select another model"
188
- if (count of modelButtons) > 0 then
189
- click item 1 of modelButtons
188
+ set buttonTexts to {"Select another model", "Switch model", "Change model", "Select model", "Try another model", "Choose model"}
189
+ set foundButton to missing value
190
+
191
+ -- Search for button in window 1
192
+ repeat with buttonText in buttonTexts
193
+ try
194
+ set matchingButtons to buttons of window 1 whose name contains buttonText
195
+ if (count of matchingButtons) > 0 then
196
+ set foundButton to item 1 of matchingButtons
197
+ exit repeat
198
+ end if
199
+ end try
200
+ end repeat
201
+
202
+ -- Also search in groups within window 1
203
+ if foundButton is missing value then
204
+ repeat with buttonText in buttonTexts
205
+ try
206
+ set allGroups to groups of window 1
207
+ repeat with grp in allGroups
208
+ try
209
+ set matchingButtons to buttons of grp whose name contains buttonText
210
+ if (count of matchingButtons) > 0 then
211
+ set foundButton to item 1 of matchingButtons
212
+ exit repeat
213
+ end if
214
+ end try
215
+ end repeat
216
+ if foundButton is not missing value then exit repeat
217
+ end try
218
+ end repeat
219
+ end if
220
+
221
+ if foundButton is not missing value then
222
+ click foundButton
190
223
  delay 1.5
191
224
 
192
225
  -- Look for model dropdown/menu items
@@ -195,20 +228,38 @@ class AppleScriptManager {
195
228
 
196
229
  repeat with modelName in modelNames
197
230
  try
198
- -- Try to find and click this model option
199
- set modelItems to menu items of menu 1 of window 1 whose name is modelName
231
+ -- Try to find and click this model option in various locations
232
+ set modelItems to {}
233
+
234
+ -- Try menu items
235
+ try
236
+ set modelItems to menu items of menu 1 of window 1 whose name is modelName
237
+ end try
238
+
239
+ -- Try buttons if no menu items found
240
+ if (count of modelItems) = 0 then
241
+ try
242
+ set modelItems to buttons of window 1 whose name contains modelName
243
+ end try
244
+ end if
245
+
200
246
  if (count of modelItems) > 0 then
201
247
  click item 1 of modelItems
202
248
  delay 0.8
203
249
 
204
250
  -- Click "Accept all" or similar confirmation button
205
251
  try
206
- set acceptButtons to buttons of window 1 whose name contains "Accept"
207
- if (count of acceptButtons) > 0 then
208
- click item 1 of acceptButtons
209
- delay 0.5
210
- return "success:" & modelName
211
- end if
252
+ set acceptTexts to {"Accept", "OK", "Confirm", "Continue"}
253
+ repeat with acceptText in acceptTexts
254
+ try
255
+ set acceptButtons to buttons of window 1 whose name contains acceptText
256
+ if (count of acceptButtons) > 0 then
257
+ click item 1 of acceptButtons
258
+ delay 0.5
259
+ return "success:" & modelName
260
+ end if
261
+ end try
262
+ end repeat
212
263
  end try
213
264
 
214
265
  return "success:" & modelName
@@ -286,7 +337,7 @@ class AppleScriptManager {
286
337
 
287
338
  const ideName = ide === 'windsurf' ? 'Windsurf' : ide === 'cursor' ? 'Cursor' : ide === 'antigravity' ? 'Antigravity' : ide === 'kiro' ? 'AWS Kiro' : 'Unknown IDE';
288
339
 
289
- this.logger.log(`${ideName} detected - using AppleScript for reliable text sending`);
340
+ this.logger.log(t('auto.direct.ide.detected', { ide: ideName }));
290
341
 
291
342
  try {
292
343
  let appleScript;
@@ -340,118 +391,14 @@ class AppleScriptManager {
340
391
  end tell
341
392
  `;
342
393
  } else if (ide === 'cursor') {
343
- // AppleScript for Cursor - proven to work (from commit 3403c17)
394
+ // AppleScript for Cursor - Using working shortcuts
344
395
  appleScript = `
345
396
  tell application "System Events"
346
397
  tell process "Cursor"
347
398
  set frontmost to true
348
- delay 1
349
-
350
- -- DYNAMIC SCREENSHOT-BASED CHAT INPUT TARGETING
351
- -- Method 1: Take screenshot of the monitor where Cursor is running
352
- try
353
- -- Get the bounds of the Cursor window to determine which monitor it's on
354
- set cursorBounds to bounds of window 1
355
- set cursorX to item 1 of cursorBounds
356
- set cursorY to item 2 of cursorBounds
357
-
358
- -- Take a screenshot of the specific monitor where Cursor is located
359
- set screenshotPath to (path to desktop as string) & "cursor_screenshot.png"
360
-
361
- -- Use screencapture with display selection based on Cursor window position
362
- -- If Cursor is on the right side (aux monitor), use display 2
363
- if cursorX > 1000 then
364
- do shell script "screencapture -D 2 -x " & quoted form of POSIX path of screenshotPath
365
- else
366
- do shell script "screencapture -D 1 -x " & quoted form of POSIX path of screenshotPath
367
- end if
368
- delay 0.5
369
-
370
- -- Use Python with PIL to analyze the screenshot and find text input area
371
- set pythonScript to "
372
- import sys
373
- import os
374
- from PIL import Image, ImageDraw
375
- import subprocess
376
-
377
- try:
378
- # Read the screenshot
379
- img = Image.open('" & POSIX path of screenshotPath & "')
380
- width, height = img.size
381
-
382
- # Convert to grayscale for analysis
383
- gray = img.convert('L')
384
-
385
- # Get screen dimensions to calculate relative positions
386
- screen_width = width
387
- screen_height = height
388
-
389
- # Determine if this is the auxiliary monitor based on Cursor window position
390
- cursor_x = " & cursorX & "
391
- is_aux_monitor = cursor_x > 1000
392
-
393
- if is_aux_monitor:
394
- # For auxiliary monitor, adjust coordinates
395
- # Chat input is typically in the right side of the aux monitor
396
- candidates = [
397
- (int(screen_width * 0.8), int(screen_height * 0.85)), # Bottom-right
398
- (int(screen_width * 0.75), int(screen_height * 0.8)), # Slightly up
399
- (int(screen_width * 0.85), int(screen_height * 0.8)), # More right
400
- (int(screen_width * 0.7), int(screen_height * 0.9)), # Bottom-left of right area
401
- ]
402
- else:
403
- # For main monitor, use standard coordinates
404
- candidates = [
405
- (int(screen_width * 0.8), int(screen_height * 0.85)), # Bottom-right
406
- (int(screen_width * 0.75), int(screen_height * 0.8)), # Slightly up
407
- (int(screen_width * 0.85), int(screen_height * 0.8)), # More right
408
- (int(screen_width * 0.7), int(screen_height * 0.9)), # Bottom-left of right area
409
- ]
410
-
411
- # Use the first candidate (bottom-right area)
412
- x, y = candidates[0]
413
- print(f'{x},{y}')
414
-
415
- except Exception as e:
416
- # Fallback to estimated coordinates based on monitor
417
- if " & cursorX & " > 1000:
418
- print('1000,600') # Aux monitor fallback
419
- else:
420
- print('800,500') # Main monitor fallback
421
- "
422
-
423
- -- Execute Python script to find coordinates
424
- set coordinates to do shell script "python3 -c " & quoted form of pythonScript
425
- delay 0.3
426
-
427
- -- Click at the detected coordinates
428
- do shell script "/usr/local/bin/cliclick c:" & coordinates
429
- delay 0.5
430
-
431
- -- Clean up screenshot
432
- do shell script "rm " & quoted form of POSIX path of screenshotPath
433
-
434
- on error
435
- -- Fallback: Use estimated coordinates if screenshot analysis fails
436
- try
437
- -- Click in the main editor area to escape terminal
438
- do shell script "/usr/local/bin/cliclick c:600,400"
439
- delay 0.3
440
-
441
- -- Click in the chat panel area to focus it
442
- do shell script "/usr/local/bin/cliclick c:1200,500"
443
- delay 0.3
444
-
445
- -- Click in the chat input area specifically
446
- do shell script "/usr/local/bin/cliclick c:1100,700"
447
- delay 0.3
448
-
449
- on error
450
- delay 0.3
451
- end try
452
- end try
399
+ delay 1.0
453
400
 
454
- -- Open new chat session with Cmd+T to prevent crashes
401
+ -- Open new chat session with Cmd+T (proven to work)
455
402
  key code 17 using {command down} -- Cmd+T
456
403
  delay 1.0
457
404
 
@@ -462,8 +409,8 @@ except Exception as e:
462
409
  delay 0.5
463
410
 
464
411
  -- Press Cmd+Enter to send (more reliable than just Enter)
465
- key code 36 using {command down}
466
- delay 1
412
+ key code 36 using {command down} -- Cmd+Enter
413
+ delay 1.0
467
414
 
468
415
  return "Message sent via AppleScript"
469
416
  end tell
@@ -543,7 +490,7 @@ except Exception as e:
543
490
 
544
491
  execSync(`osascript -e '${appleScript}'`, { stdio: 'pipe' });
545
492
 
546
- this.logger.log(`Successfully sent message to ${ideName} via AppleScript`);
493
+ this.logger.log(t('auto.direct.ide.sent.applescript', { ide: ideName }));
547
494
  return {
548
495
  success: true,
549
496
  method: 'applescript',
@@ -552,14 +499,14 @@ except Exception as e:
552
499
  };
553
500
 
554
501
  } catch (error) {
555
- this.logger.log('AppleScript interaction failed, falling back to simulated response:', error.message);
502
+ this.logger.log(`❌ AppleScript interaction failed for ${ideName}:`, error.message);
556
503
 
557
- // Fallback to simulated response if AppleScript fails
504
+ // Return failure - DO NOT fallback to simulation
558
505
  return {
559
- success: true,
560
- method: 'simulated',
561
- message: `Simulated ${ideName} response: ${text}`,
562
- note: `${ideName} AppleScript automation failed. Using simulated response for testing.`
506
+ success: false,
507
+ error: error.message,
508
+ message: `Failed to send message to ${ideName}`,
509
+ note: `AppleScript automation failed. Error: ${error.message}`
563
510
  };
564
511
  }
565
512
  }
@@ -576,11 +576,43 @@ class AppleScriptManager {
576
576
  set frontmost to true
577
577
  delay 0.8
578
578
 
579
- -- Try to find and click "Select another model" button
579
+ -- Try to find model selection button with multiple possible texts
580
580
  try
581
- set modelButtons to buttons of window 1 whose name contains "Select another model"
582
- if (count of modelButtons) > 0 then
583
- click item 1 of modelButtons
581
+ set buttonTexts to {"Select another model", "Switch model", "Change model", "Select model", "Try another model", "Choose model"}
582
+ set foundButton to missing value
583
+
584
+ -- Search for button in window 1
585
+ repeat with buttonText in buttonTexts
586
+ try
587
+ set matchingButtons to buttons of window 1 whose name contains buttonText
588
+ if (count of matchingButtons) > 0 then
589
+ set foundButton to item 1 of matchingButtons
590
+ exit repeat
591
+ end if
592
+ end try
593
+ end repeat
594
+
595
+ -- Also search in groups within window 1
596
+ if foundButton is missing value then
597
+ repeat with buttonText in buttonTexts
598
+ try
599
+ set allGroups to groups of window 1
600
+ repeat with grp in allGroups
601
+ try
602
+ set matchingButtons to buttons of grp whose name contains buttonText
603
+ if (count of matchingButtons) > 0 then
604
+ set foundButton to item 1 of matchingButtons
605
+ exit repeat
606
+ end if
607
+ end try
608
+ end repeat
609
+ if foundButton is not missing value then exit repeat
610
+ end try
611
+ end repeat
612
+ end if
613
+
614
+ if foundButton is not missing value then
615
+ click foundButton
584
616
  delay 1.5
585
617
 
586
618
  -- Look for model dropdown/menu items
@@ -589,20 +621,38 @@ class AppleScriptManager {
589
621
 
590
622
  repeat with modelName in modelNames
591
623
  try
592
- -- Try to find and click this model option
593
- set modelItems to menu items of menu 1 of window 1 whose name is modelName
624
+ -- Try to find and click this model option in various locations
625
+ set modelItems to {}
626
+
627
+ -- Try menu items
628
+ try
629
+ set modelItems to menu items of menu 1 of window 1 whose name is modelName
630
+ end try
631
+
632
+ -- Try buttons if no menu items found
633
+ if (count of modelItems) = 0 then
634
+ try
635
+ set modelItems to buttons of window 1 whose name contains modelName
636
+ end try
637
+ end if
638
+
594
639
  if (count of modelItems) > 0 then
595
640
  click item 1 of modelItems
596
641
  delay 0.8
597
642
 
598
643
  -- Click "Accept all" or similar confirmation button
599
644
  try
600
- set acceptButtons to buttons of window 1 whose name contains "Accept"
601
- if (count of acceptButtons) > 0 then
602
- click item 1 of acceptButtons
603
- delay 0.5
604
- return "success:" & modelName
605
- end if
645
+ set acceptTexts to {"Accept", "OK", "Confirm", "Continue"}
646
+ repeat with acceptText in acceptTexts
647
+ try
648
+ set acceptButtons to buttons of window 1 whose name contains acceptText
649
+ if (count of acceptButtons) > 0 then
650
+ click item 1 of acceptButtons
651
+ delay 0.5
652
+ return "success:" & modelName
653
+ end if
654
+ end try
655
+ end repeat
606
656
  end try
607
657
 
608
658
  return "success:" & modelName
@@ -3,6 +3,25 @@ const { execSync, spawn } = require('child_process');
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const os = require('os');
6
+ const chalk = require('chalk');
7
+
8
+ // Rate limit patterns for Claude Code
9
+ const RATE_LIMIT_PATTERNS = [
10
+ /quota limit/i,
11
+ /rate limit/i,
12
+ /too many requests/i,
13
+ /limit exceeded/i,
14
+ /quota: \d+\/\d+/i,
15
+ /you'?ve hit your limit/i,
16
+ /resets? (?:at )?\d+[a-z]{2} \(/i,
17
+ /rate limit reached/i,
18
+ /quota exceeded/i,
19
+ /usage limit reached/i,
20
+ /try again in \d+[mh]\d*[ms]?/i,
21
+ /please try again in/i,
22
+ /session limit reached/i,
23
+ /account limit reached/i
24
+ ];
6
25
 
7
26
  // Helper function for timestamps
8
27
  function getTimestamp() {
@@ -18,6 +37,7 @@ class ClaudeCodeCLIManager {
18
37
  constructor() {
19
38
  this.logger = console;
20
39
  this.runningProcesses = [];
40
+ this.rateLimitInfo = null;
21
41
  }
22
42
 
23
43
  /**
@@ -124,6 +144,14 @@ class ClaudeCodeCLIManager {
124
144
  this.runningProcesses = [];
125
145
  }
126
146
 
147
+ /**
148
+ * Get rate limit information if the last operation was rate limited
149
+ * @returns {{isRateLimited: boolean, resetTime?: Date, message?: string} | null}
150
+ */
151
+ getRateLimitInfo() {
152
+ return this.rateLimitInfo || null;
153
+ }
154
+
127
155
  /**
128
156
  * Send a prompt to Claude Code and wait for completion
129
157
  * @param {string} text - The message/prompt to send
@@ -134,6 +162,61 @@ class ClaudeCodeCLIManager {
134
162
  * @param {number} options.timeoutMs - Timeout in milliseconds (default 300000 = 5 minutes)
135
163
  * @returns {Promise<{success: boolean, output: string, error?: string}>}
136
164
  */
165
+ /**
166
+ * Check if the error indicates a rate limit
167
+ * @param {string} error - The error message
168
+ * @returns {{isRateLimited: boolean, resetTime?: Date, message?: string}}
169
+ */
170
+ checkRateLimit(error) {
171
+ if (!error) return { isRateLimited: false };
172
+
173
+ const lowerError = error.toLowerCase();
174
+
175
+ // Check for rate limit patterns
176
+ const isRateLimited = RATE_LIMIT_PATTERNS.some(pattern =>
177
+ pattern.test(error)
178
+ );
179
+
180
+ if (!isRateLimited) {
181
+ return { isRateLimited: false };
182
+ }
183
+
184
+ // Try to extract reset time if available
185
+ let resetTime;
186
+ // Match patterns like "resets 6am (America/Buenos_Aires)" or "resets at 6am (America/Buenos_Aires)"
187
+ const resetMatch = error.match(/resets? (?:at )?(\d+)(?::(\d+))?\s*([ap]m)?\s*(\([^)]+\))?/i);
188
+ if (resetMatch) {
189
+ try {
190
+ const now = new Date();
191
+ let hours = parseInt(resetMatch[1]);
192
+ const minutes = resetMatch[2] ? parseInt(resetMatch[2]) : 0;
193
+ const period = resetMatch[3] ? resetMatch[3].toLowerCase() : null;
194
+
195
+ // Convert to 24-hour format if period is specified
196
+ if (period === 'pm' && hours < 12) hours += 12;
197
+ if (period === 'am' && hours === 12) hours = 0;
198
+
199
+ // Create reset time
200
+ resetTime = new Date(now);
201
+ resetTime.setHours(hours, minutes, 0, 0);
202
+
203
+ // If reset time is in the past, assume it's for tomorrow
204
+ if (resetTime <= now) {
205
+ resetTime.setDate(resetTime.getDate() + 1);
206
+ }
207
+ } catch (e) {
208
+ console.error('Error parsing reset time:', e);
209
+ resetTime = null;
210
+ }
211
+ }
212
+
213
+ return {
214
+ isRateLimited: true,
215
+ resetTime,
216
+ message: `Rate limit reached${resetTime ? `, resets at ${resetTime.toLocaleString()}` : ''}`
217
+ };
218
+ }
219
+
137
220
  async sendText(text, cwd = process.cwd(), options = {}) {
138
221
  if (!this.isInstalled()) {
139
222
  return {
@@ -220,6 +303,24 @@ class ClaudeCodeCLIManager {
220
303
  const chunkText = chunk.toString();
221
304
  stderr += chunkText;
222
305
 
306
+ // Check for rate limits in stderr
307
+ const rateLimitInfo = this.checkRateLimit(chunkText);
308
+ if (rateLimitInfo.isRateLimited) {
309
+ this.rateLimitInfo = rateLimitInfo;
310
+ console.error(chalk.yellow(`\n⚠️ ${rateLimitInfo.message}`));
311
+
312
+ // If we have a reset time, update the provider manager
313
+ if (rateLimitInfo.resetTime) {
314
+ try {
315
+ const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
316
+ const providerManager = new ProviderManager();
317
+ providerManager.markRateLimited('claude-code', 'claude-code-cli', rateLimitInfo.message);
318
+ } catch (e) {
319
+ console.error('Failed to update rate limit status:', e);
320
+ }
321
+ }
322
+ }
323
+
223
324
  // Only show actual errors
224
325
  if (chunkText.includes('Error:') || chunkText.includes('Failed:') || chunkText.includes('error')) {
225
326
  if (onError) {
@@ -290,9 +391,27 @@ class ClaudeCodeCLIManager {
290
391
  });
291
392
  });
292
393
  } catch (error) {
394
+ // Check if this is a rate limit error
395
+ const rateLimitInfo = this.checkRateLimit(error.message);
396
+ if (rateLimitInfo.isRateLimited) {
397
+ this.rateLimitInfo = rateLimitInfo;
398
+ console.error(chalk.yellow(`\n⚠️ ${rateLimitInfo.message}`));
399
+
400
+ // Update provider manager with rate limit info
401
+ try {
402
+ const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
403
+ const providerManager = new ProviderManager();
404
+ providerManager.markRateLimited('claude-code', 'claude-code-cli', rateLimitInfo.message);
405
+ } catch (e) {
406
+ console.error('Failed to update rate limit status:', e);
407
+ }
408
+ }
409
+
293
410
  return {
294
411
  success: false,
295
- error: error.message
412
+ error: error.message,
413
+ rateLimited: rateLimitInfo.isRateLimited,
414
+ rateLimitInfo: rateLimitInfo.isRateLimited ? rateLimitInfo : undefined
296
415
  };
297
416
  }
298
417
  }
@@ -175,10 +175,24 @@ class ProviderManager {
175
175
  /**
176
176
  * Check if a provider is currently rate limited
177
177
  * @param {string} provider - Provider name
178
- * @param {string} model - Model name
178
+ * @param {string} model - Model name (optional, will check all models if not provided)
179
179
  * @returns {boolean}
180
180
  */
181
181
  isRateLimited(provider, model) {
182
+ if (!model) {
183
+ // Check if ANY model for this provider is rate limited
184
+ const providerPrefix = `${provider}:`;
185
+ for (const key in this.rateLimits) {
186
+ if (key.startsWith(providerPrefix)) {
187
+ const limit = this.rateLimits[key];
188
+ if (limit && Date.now() < limit.resetTime) {
189
+ return true;
190
+ }
191
+ }
192
+ }
193
+ return false;
194
+ }
195
+
182
196
  const key = `${provider}:${model}`;
183
197
  const limit = this.rateLimits[key];
184
198
 
@@ -195,6 +209,58 @@ class ProviderManager {
195
209
  return true;
196
210
  }
197
211
 
212
+ /**
213
+ * Get rate limit information for a provider
214
+ * @param {string} provider - Provider name
215
+ * @param {string} model - Model name (optional)
216
+ * @returns {Object} - {isRateLimited: boolean, resetTime: number, reason: string}
217
+ */
218
+ getRateLimitInfo(provider, model) {
219
+ // If model not specified, check all models for this provider
220
+ if (!model) {
221
+ const providerPrefix = `${provider}:`;
222
+ let earliestReset = null;
223
+ let reason = null;
224
+
225
+ for (const key in this.rateLimits) {
226
+ if (key.startsWith(providerPrefix)) {
227
+ const limit = this.rateLimits[key];
228
+ if (limit && Date.now() < limit.resetTime) {
229
+ if (!earliestReset || limit.resetTime < earliestReset) {
230
+ earliestReset = limit.resetTime;
231
+ reason = limit.reason;
232
+ }
233
+ }
234
+ }
235
+ }
236
+
237
+ if (earliestReset) {
238
+ return {
239
+ isRateLimited: true,
240
+ resetTime: earliestReset,
241
+ reason: reason
242
+ };
243
+ }
244
+ } else {
245
+ const key = `${provider}:${model}`;
246
+ const limit = this.rateLimits[key];
247
+
248
+ if (limit && Date.now() < limit.resetTime) {
249
+ return {
250
+ isRateLimited: true,
251
+ resetTime: limit.resetTime,
252
+ reason: limit.reason
253
+ };
254
+ }
255
+ }
256
+
257
+ return {
258
+ isRateLimited: false,
259
+ resetTime: null,
260
+ reason: null
261
+ };
262
+ }
263
+
198
264
  /**
199
265
  * Get available provider (not rate limited)
200
266
  * @param {Array} providers - Array of {provider, model, apiKey} objects
package/src/index.cjs CHANGED
@@ -22,6 +22,7 @@ const requirementHelpers = require('./utils/requirement-helpers.js');
22
22
  const requirementsParser = require('./utils/requirements-parser.js');
23
23
  const updateChecker = require('./utils/update-checker.js');
24
24
  const electronUpdateChecker = require('./utils/electron-update-checker.js');
25
+ const localization = require('./localization/index.js');
25
26
 
26
27
  module.exports = {
27
28
  CDPManager,
@@ -45,5 +46,6 @@ module.exports = {
45
46
  ...requirementHelpers,
46
47
  ...requirementsParser,
47
48
  ...updateChecker,
48
- ...electronUpdateChecker
49
+ ...electronUpdateChecker,
50
+ ...localization
49
51
  };
package/src/index.js CHANGED
@@ -13,7 +13,14 @@ export * from './utils/config-helpers.js';
13
13
  export * from './utils/requirement-helpers.js';
14
14
  export * from './utils/requirements-parser.js';
15
15
 
16
+ // Compliance
17
+ const CompliancePrompt = require('./compliance/compliance-prompt.js');
18
+ export { CompliancePrompt };
19
+
16
20
  // UI Components
17
21
  export * from './ui/ButtonComponents.js';
18
22
  export * from './ui/StateManager.js';
19
23
  export { ChatInterface } from './ui/ChatInterface.js';
24
+
25
+ // Localization
26
+ export * from './localization/index.js';