vibecodingmachine-cli 2026.2.26-1752 → 2026.3.9-1621

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 (74) hide show
  1. package/bin/auth/auth-compliance.js +7 -1
  2. package/bin/commands/agent-commands.js +150 -228
  3. package/bin/commands/command-aliases.js +68 -0
  4. package/bin/vibecodingmachine.js +1 -2
  5. package/package.json +2 -2
  6. package/src/commands/agents/list.js +71 -115
  7. package/src/commands/agents-check.js +16 -4
  8. package/src/commands/analyze-file-sizes.js +1 -1
  9. package/src/commands/auto-direct/auto-provider-manager.js +290 -0
  10. package/src/commands/auto-direct/auto-status-display.js +331 -0
  11. package/src/commands/auto-direct/auto-utils.js +439 -0
  12. package/src/commands/auto-direct/file-operations.js +110 -0
  13. package/src/commands/auto-direct/provider-config.js +1 -1
  14. package/src/commands/auto-direct/provider-manager.js +1 -1
  15. package/src/commands/auto-direct/status-display.js +1 -1
  16. package/src/commands/auto-direct/utils.js +24 -18
  17. package/src/commands/auto-direct-refactored.js +413 -0
  18. package/src/commands/auto-direct.js +594 -188
  19. package/src/commands/requirements/commands.js +353 -0
  20. package/src/commands/requirements/default-handlers.js +272 -0
  21. package/src/commands/requirements/disable.js +97 -0
  22. package/src/commands/requirements/enable.js +97 -0
  23. package/src/commands/requirements/utils.js +194 -0
  24. package/src/commands/requirements-refactored.js +60 -0
  25. package/src/commands/requirements.js +38 -771
  26. package/src/commands/specs/disable.js +96 -0
  27. package/src/commands/specs/enable.js +96 -0
  28. package/src/trui/TruiInterface.js +5 -11
  29. package/src/trui/agents/AgentInterface.js +24 -396
  30. package/src/trui/agents/handlers/CommandHandler.js +93 -0
  31. package/src/trui/agents/handlers/ContextManager.js +117 -0
  32. package/src/trui/agents/handlers/DisplayHandler.js +243 -0
  33. package/src/trui/agents/handlers/HelpHandler.js +51 -0
  34. package/src/utils/auth.js +13 -111
  35. package/src/utils/config.js +4 -0
  36. package/src/utils/interactive/requirements-navigation.js +17 -15
  37. package/src/utils/interactive-broken.js +2 -2
  38. package/src/utils/provider-checker/agent-runner.js +15 -1
  39. package/src/utils/provider-checker/cli-installer.js +149 -7
  40. package/src/utils/provider-checker/opencode-checker.js +588 -0
  41. package/src/utils/provider-checker/provider-validator.js +88 -3
  42. package/src/utils/provider-checker/time-formatter.js +3 -2
  43. package/src/utils/provider-manager.js +28 -20
  44. package/src/utils/provider-registry.js +35 -3
  45. package/src/utils/requirements-navigator/index.js +94 -0
  46. package/src/utils/requirements-navigator/input-handler.js +217 -0
  47. package/src/utils/requirements-navigator/section-loader.js +188 -0
  48. package/src/utils/requirements-navigator/tree-builder.js +105 -0
  49. package/src/utils/requirements-navigator/tree-renderer.js +50 -0
  50. package/src/utils/requirements-navigator.js +2 -583
  51. package/src/utils/trui-clarifications.js +188 -0
  52. package/src/utils/trui-feedback.js +54 -1
  53. package/src/utils/trui-kiro-integration.js +398 -0
  54. package/src/utils/trui-main-handlers.js +194 -0
  55. package/src/utils/trui-main-menu.js +235 -0
  56. package/src/utils/trui-nav-agents.js +178 -25
  57. package/src/utils/trui-nav-requirements.js +203 -27
  58. package/src/utils/trui-nav-settings.js +114 -1
  59. package/src/utils/trui-nav-specifications.js +44 -3
  60. package/src/utils/trui-navigation-backup.js +603 -0
  61. package/src/utils/trui-navigation.js +70 -228
  62. package/src/utils/trui-provider-health.js +274 -0
  63. package/src/utils/trui-provider-manager.js +376 -0
  64. package/src/utils/trui-quick-menu.js +25 -1
  65. package/src/utils/trui-req-actions-backup.js +507 -0
  66. package/src/utils/trui-req-actions.js +148 -216
  67. package/src/utils/trui-req-editor.js +170 -0
  68. package/src/utils/trui-req-file-ops.js +278 -0
  69. package/src/utils/trui-req-tree-old.js +719 -0
  70. package/src/utils/trui-req-tree.js +348 -627
  71. package/src/utils/trui-specifications.js +25 -7
  72. package/src/utils/trui-windsurf.js +231 -10
  73. package/src/utils/welcome-screen-extracted.js +2 -2
  74. package/src/utils/welcome-screen.js +2 -2
@@ -0,0 +1,588 @@
1
+ 'use strict';
2
+
3
+ const { spawn } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const os = require('os');
7
+
8
+ /**
9
+ * OpenCode Agent Checker - Handles OpenCode CLI specific checks and configuration
10
+ *
11
+ * This module provides specialized checking for OpenCode CLI agent:
12
+ * 1. First attempts a simple ping test (1+1 or "ping")
13
+ * 2. If configuration errors occur, attempts to pre-configure with working model
14
+ * 3. If still stuck, attempts to automate initial configuration prompts
15
+ */
16
+
17
+ class OpenCodeChecker {
18
+ constructor() {
19
+ this.configPath = path.join(os.homedir(), '.config', 'opencode');
20
+ this.globalConfigFile = path.join(this.configPath, 'opencode.json');
21
+ }
22
+
23
+ /**
24
+ * Check if OpenCode CLI is available in PATH
25
+ * @returns {boolean}
26
+ */
27
+ isAvailable() {
28
+ try {
29
+ const { execSync } = require('child_process');
30
+ execSync('which opencode', { stdio: 'ignore', timeout: 5000 });
31
+ return true;
32
+ } catch {
33
+ return false;
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Attempt a simple ping test to check if OpenCode is responsive
39
+ * @returns {Promise<{responsive: boolean, error?: string, needsConfig?: boolean}>}
40
+ */
41
+ async pingTest(configOverride = null) {
42
+ console.log('[OPENCODE CHECK] Starting ping test...');
43
+
44
+ return new Promise((resolve) => {
45
+ const env = { ...process.env };
46
+ if (configOverride) {
47
+ env.OPENCODE_CONFIG_CONTENT = configOverride;
48
+ console.log('[OPENCODE CHECK] Using config override:', configOverride);
49
+ }
50
+
51
+ const proc = spawn('opencode', ['-p', '1+1', '-q'], {
52
+ stdio: ['ignore', 'pipe', 'pipe'],
53
+ timeout: 30000,
54
+ env
55
+ });
56
+
57
+ let stdout = '';
58
+ let stderr = '';
59
+
60
+ proc.stdout.on('data', (data) => {
61
+ const chunk = data.toString();
62
+ stdout += chunk;
63
+ console.log('[OPENCODE CHECK] STDOUT:', chunk.trim());
64
+ });
65
+
66
+ proc.stderr.on('data', (data) => {
67
+ const chunk = data.toString();
68
+ stderr += chunk;
69
+ console.log('[OPENCODE CHECK] STDERR:', chunk.trim());
70
+ });
71
+
72
+ proc.on('close', (code) => {
73
+ const output = stdout + stderr;
74
+ console.log(`[OPENCODE CHECK] Process exited with code: ${code}`);
75
+ console.log(`[OPENCODE CHECK] Full output: ${output.substring(0, 500)}`);
76
+
77
+ // Check for successful response
78
+ if (code === 0 && (output.includes('2') || output.includes('2\n'))) {
79
+ console.log('[OPENCODE CHECK] ✓ Ping test successful');
80
+ resolve({ responsive: true });
81
+ return;
82
+ }
83
+
84
+ // Check for configuration errors
85
+ const needsConfig =
86
+ output.includes('model') && output.includes('decommissioned') ||
87
+ output.includes('API key') ||
88
+ output.includes('configuration') ||
89
+ output.includes('configure') ||
90
+ output.includes('failed to process events') ||
91
+ output.includes('LSP Configuration') || // Add LSP configuration detection
92
+ output.includes('Unknown request URL') || // Add API endpoint detection
93
+ output.includes('unknown_url'); // Add API endpoint detection
94
+
95
+ if (needsConfig) {
96
+ console.log('[OPENCODE CHECK] ⚠ Configuration needed detected');
97
+
98
+ // Provide specific error details
99
+ let errorDetails = 'OpenCode needs configuration';
100
+ if (output.includes('Unknown request URL') || output.includes('unknown_url')) {
101
+ errorDetails = 'OpenCode has incorrect API endpoint configuration';
102
+ } else if (output.includes('max_tokens')) {
103
+ errorDetails = 'OpenCode has max_tokens configuration issue';
104
+ }
105
+
106
+ resolve({
107
+ responsive: false,
108
+ error: errorDetails,
109
+ needsConfig: true,
110
+ details: output.substring(0, 200)
111
+ });
112
+ } else {
113
+ console.log('[OPENCODE CHECK] ✗ Ping test failed for unknown reason');
114
+ resolve({
115
+ responsive: false,
116
+ error: `OpenCode ping failed (exit code: ${code})`,
117
+ details: output.substring(0, 200)
118
+ });
119
+ }
120
+ });
121
+
122
+ proc.on('error', (error) => {
123
+ console.log(`[OPENCODE CHECK] ✗ Process error: ${error.message}`);
124
+ resolve({
125
+ responsive: false,
126
+ error: `Failed to run OpenCode: ${error.message}`
127
+ });
128
+ });
129
+ });
130
+ }
131
+
132
+ /**
133
+ * Create a basic configuration with a working model
134
+ * @returns {Promise<{success: boolean, error?: string}>}
135
+ */
136
+ async createBasicConfig() {
137
+ console.log('[OPENCODE CHECK] Attempting to create basic configuration...');
138
+
139
+ try {
140
+ // Ensure config directory exists
141
+ fs.mkdirSync(this.configPath, { recursive: true });
142
+ console.log(`[OPENCODE CHECK] Config directory ensured: ${this.configPath}`);
143
+
144
+ // Try to detect available API keys from environment
145
+ const availableProviders = this.detectAvailableProviders();
146
+ console.log(`[OPENCODE CHECK] Available providers detected: ${availableProviders.join(', ')}`);
147
+
148
+ // Create config with the first available provider and a working model
149
+ const model = this.selectWorkingModel(availableProviders);
150
+ console.log(`[OPENCODE CHECK] Selected model: ${model}`);
151
+
152
+ const config = {
153
+ "$schema": "https://opencode.ai/config.json",
154
+ "model": model,
155
+ "autoupdate": false,
156
+ "server": {
157
+ "port": 4096
158
+ }
159
+ };
160
+
161
+ // Write the configuration
162
+ const configJson = JSON.stringify(config, null, 2);
163
+ fs.writeFileSync(this.globalConfigFile, configJson);
164
+ console.log(`[OPENCODE CHECK] Configuration written to: ${this.globalConfigFile}`);
165
+ console.log(`[OPENCODE CHECK] Config content: ${configJson}`);
166
+
167
+ return { success: true };
168
+ } catch (error) {
169
+ console.log(`[OPENCODE CHECK] ✗ Failed to create config: ${error.message}`);
170
+ return { success: false, error: error.message };
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Detect available API providers from environment variables
176
+ * @returns {string[]}
177
+ */
178
+ detectAvailableProviders() {
179
+ const providers = [];
180
+
181
+ if (process.env.OPENAI_API_KEY) providers.push('openai');
182
+ if (process.env.ANTHROPIC_API_KEY) providers.push('anthropic');
183
+ if (process.env.GEMINI_API_KEY) providers.push('google');
184
+ if (process.env.GROQ_API_KEY) providers.push('groq');
185
+
186
+ return providers;
187
+ }
188
+
189
+ /**
190
+ * Select a working model based on available providers
191
+ * @param {string[]} providers
192
+ * @returns {string}
193
+ */
194
+ selectWorkingModel(providers) {
195
+ const modelMap = {
196
+ 'openai': 'gpt-4o-mini',
197
+ 'anthropic': 'claude-3-haiku-20240307',
198
+ 'google': 'gemini-flash-1.5',
199
+ 'groq': 'Llama3_3_70BVersatile' // Use the model shown in OpenCode's UI
200
+ };
201
+
202
+ // Try providers in order of preference
203
+ for (const provider of ['anthropic', 'openai', 'google', 'groq']) {
204
+ if (providers.includes(provider)) {
205
+ return modelMap[provider];
206
+ }
207
+ }
208
+
209
+ // Fallback to a common model (may fail but worth trying)
210
+ return 'Llama3_3_70BVersatile';
211
+ }
212
+
213
+ /**
214
+ * Attempt to automatically configure OpenCode using keyboard shortcuts
215
+ * @returns {Promise<{success: boolean, message: string}>}
216
+ */
217
+ async attemptKeyboardConfiguration() {
218
+ console.log('[OPENCODE CHECK] Attempting keyboard-based configuration...');
219
+
220
+ return new Promise((resolve) => {
221
+ // Try to use expect or node-pty to send keyboard shortcuts
222
+ let pty;
223
+ try {
224
+ pty = require('node-pty');
225
+ } catch (error) {
226
+ console.log('[OPENCODE CHECK] node-pty not available for keyboard automation');
227
+ resolve({ success: false, message: 'node-pty not available for keyboard automation' });
228
+ return;
229
+ }
230
+
231
+ const proc = pty.spawn('opencode', [], {
232
+ name: 'xterm-color',
233
+ cols: 120,
234
+ rows: 30,
235
+ cwd: process.cwd(),
236
+ env: process.env
237
+ });
238
+
239
+ let output = '';
240
+ let configured = false;
241
+
242
+ proc.on('data', (data) => {
243
+ output += data;
244
+ console.log('[OPENCODE CHECK] KEYBOARD STDOUT:', data.trim());
245
+
246
+ // Wait for OpenCode to fully load
247
+ if (output.includes('OpenCode') && output.includes('press enter to send')) {
248
+ console.log('[OPENCODE CHECK] OpenCode ready, attempting model selection...');
249
+
250
+ // Send ctrl+o to open model selection
251
+ proc.write('\x0f'); // ctrl+o
252
+
253
+ setTimeout(() => {
254
+ // Try to select a working model by typing and entering
255
+ proc.write('Llama3_3_70BVersatile\r');
256
+
257
+ setTimeout(() => {
258
+ // Try to send a test message
259
+ proc.write('1+1\r');
260
+
261
+ setTimeout(() => {
262
+ if (output.includes('2') || output.includes('2\n')) {
263
+ configured = true;
264
+ console.log('[OPENCODE CHECK] ✓ Keyboard configuration successful');
265
+ }
266
+
267
+ proc.write('\x03'); // ctrl+c to quit
268
+ setTimeout(() => proc.destroy(), 1000);
269
+ }, 3000);
270
+ }, 2000);
271
+ }, 1000);
272
+ }
273
+ });
274
+
275
+ proc.on('exit', () => {
276
+ resolve({
277
+ success: configured,
278
+ message: configured ? 'Keyboard configuration successful' : 'Keyboard configuration failed - manual intervention required'
279
+ });
280
+ });
281
+
282
+ // Timeout after 15 seconds
283
+ setTimeout(() => {
284
+ if (!proc.destroyed) {
285
+ proc.destroy();
286
+ resolve({
287
+ success: false,
288
+ message: 'Keyboard configuration timed out'
289
+ });
290
+ }
291
+ }, 15000);
292
+ });
293
+ }
294
+
295
+ /**
296
+ * Attempt to automatically respond to LSP Configuration prompt
297
+ * @returns {Promise<{success: boolean, message: string}>}
298
+ */
299
+ async attemptLSPConfiguration() {
300
+ console.log('[OPENCODE CHECK] Attempting to bypass LSP Configuration...');
301
+
302
+ return new Promise((resolve) => {
303
+ // Try to send a message to skip LSP configuration
304
+ const proc = spawn('opencode', ['-p', 'skip', '-q'], {
305
+ stdio: ['pipe', 'pipe', 'pipe'],
306
+ timeout: 15000
307
+ });
308
+
309
+ let stdout = '';
310
+ let stderr = '';
311
+
312
+ proc.stdout.on('data', (data) => {
313
+ const chunk = data.toString();
314
+ stdout += chunk;
315
+ console.log('[OPENCODE CHECK] LSP-CONFIG STDOUT:', chunk.trim());
316
+ });
317
+
318
+ proc.stderr.on('data', (data) => {
319
+ const chunk = data.toString();
320
+ stderr += chunk;
321
+ console.log('[OPENCODE CHECK] LSP-CONFIG STDERR:', chunk.trim());
322
+ });
323
+
324
+ proc.on('close', (code) => {
325
+ const output = stdout + stderr;
326
+ console.log(`[OPENCODE CHECK] LSP config process exited with code: ${code}`);
327
+
328
+ // If we get a successful response or it moves past the LSP config
329
+ if (code === 0 && !output.includes('LSP Configuration')) {
330
+ console.log('[OPENCODE CHECK] ✓ LSP Configuration bypassed');
331
+ resolve({ success: true, message: 'LSP Configuration bypassed successfully' });
332
+ } else {
333
+ console.log('[OPENCODE CHECK] ✗ LSP Configuration still blocking');
334
+ resolve({ success: false, message: 'LSP Configuration still requires manual intervention' });
335
+ }
336
+ });
337
+
338
+ proc.on('error', (error) => {
339
+ console.log(`[OPENCODE CHECK] LSP config error: ${error.message}`);
340
+ resolve({ success: false, message: `LSP config error: ${error.message}` });
341
+ });
342
+ });
343
+ }
344
+
345
+ /**
346
+ * Test if OpenCode interactive mode works (to detect configuration mismatch)
347
+ * @returns {Promise<{interactiveWorks: boolean, error?: string}>}
348
+ */
349
+ async testInteractiveMode() {
350
+ console.log('[OPENCODE CHECK] Testing interactive mode vs non-interactive mode...');
351
+
352
+ return new Promise((resolve) => {
353
+ const proc = spawn('opencode', ['-d'], {
354
+ stdio: ['pipe', 'pipe', 'pipe'],
355
+ timeout: 5000
356
+ });
357
+
358
+ let stdout = '';
359
+ let stderr = '';
360
+ let interactiveReady = false;
361
+
362
+ proc.stdout.on('data', (data) => {
363
+ const chunk = data.toString();
364
+ stdout += chunk;
365
+ console.log('[OPENCODE CHECK] INTERACTIVE STDOUT:', chunk.trim());
366
+
367
+ // Check if interactive mode loads successfully and has the correct model
368
+ if (stdout.includes('OpenCode') && (stdout.includes('press enter to send') || stdout.includes('ctrl+? help'))) {
369
+ interactiveReady = true;
370
+ console.log('[OPENCODE CHECK] ✓ Interactive mode ready');
371
+ if (stdout.includes('Llama3_3_70BVersatile')) {
372
+ console.log('[OPENCODE CHECK] ✓ Correct model detected in interactive mode');
373
+ }
374
+ proc.kill('SIGTERM');
375
+ }
376
+ });
377
+
378
+ proc.stderr.on('data', (data) => {
379
+ const chunk = data.toString();
380
+ stderr += chunk;
381
+ console.log('[OPENCODE CHECK] INTERACTIVE STDERR:', chunk.trim());
382
+ });
383
+
384
+ const timeout = setTimeout(() => {
385
+ proc.kill('SIGTERM');
386
+ }, 4000);
387
+
388
+ proc.on('close', (code) => {
389
+ clearTimeout(timeout);
390
+
391
+ if (interactiveReady) {
392
+ resolve({ interactiveWorks: true });
393
+ } else {
394
+ resolve({
395
+ interactiveWorks: false,
396
+ error: 'Interactive mode failed to load properly'
397
+ });
398
+ }
399
+ });
400
+
401
+ proc.on('error', (error) => {
402
+ clearTimeout(timeout);
403
+ resolve({
404
+ interactiveWorks: false,
405
+ error: `Failed to start interactive mode: ${error.message}`
406
+ });
407
+ });
408
+ });
409
+ }
410
+
411
+ /**
412
+ * Attempt to run OpenCode in interactive mode and detect configuration prompts
413
+ * @returns {Promise<{success: boolean, configured: boolean, error?: string}>}
414
+ */
415
+ async attemptAutoConfiguration() {
416
+ console.log('[OPENCODE CHECK] Attempting to detect auto-configuration prompts...');
417
+
418
+ return new Promise((resolve) => {
419
+ const proc = spawn('opencode', ['-d'], {
420
+ stdio: ['pipe', 'pipe', 'pipe'],
421
+ timeout: 10000
422
+ });
423
+
424
+ let stdout = '';
425
+ let stderr = '';
426
+ let detectedPrompt = false;
427
+
428
+ proc.stdout.on('data', (data) => {
429
+ const chunk = data.toString();
430
+ stdout += chunk;
431
+ console.log('[OPENCODE CHECK] AUTO-CONFIG STDOUT:', chunk.trim());
432
+
433
+ // Detect common configuration prompts
434
+ if (stdout.includes('Select a model') ||
435
+ stdout.includes('Choose a provider') ||
436
+ stdout.includes('API key') ||
437
+ stdout.includes('Configure') ||
438
+ stdout.includes('LSP Configuration')) {
439
+ detectedPrompt = true;
440
+ console.log('[OPENCODE CHECK] ⚠ Configuration prompt detected');
441
+ }
442
+ });
443
+
444
+ proc.stderr.on('data', (data) => {
445
+ const chunk = data.toString();
446
+ stderr += chunk;
447
+ console.log('[OPENCODE CHECK] AUTO-CONFIG STDERR:', chunk.trim());
448
+ });
449
+
450
+ // Kill the process after timeout or when prompt is detected
451
+ const timeout = setTimeout(() => {
452
+ console.log('[OPENCODE CHECK] Timeout reached, killing process...');
453
+ proc.kill('SIGTERM');
454
+ }, 8000);
455
+
456
+ proc.on('close', (code) => {
457
+ clearTimeout(timeout);
458
+
459
+ if (detectedPrompt) {
460
+ resolve({
461
+ success: false,
462
+ configured: false,
463
+ error: 'OpenCode is waiting for initial configuration. Please run `opencode` interactively to complete setup.',
464
+ needsManualConfig: true
465
+ });
466
+ } else if (stdout.includes('Error') || stderr.includes('Error')) {
467
+ resolve({
468
+ success: false,
469
+ configured: false,
470
+ error: 'OpenCode configuration error detected'
471
+ });
472
+ } else {
473
+ resolve({
474
+ success: true,
475
+ configured: true
476
+ });
477
+ }
478
+ });
479
+
480
+ proc.on('error', (error) => {
481
+ clearTimeout(timeout);
482
+ resolve({
483
+ success: false,
484
+ configured: false,
485
+ error: `Failed to start OpenCode: ${error.message}`
486
+ });
487
+ });
488
+ });
489
+ }
490
+
491
+ /**
492
+ * Run the complete OpenCode check flow
493
+ * @returns {Promise<{status: string, message: string, checkedAt: string}>}
494
+ */
495
+ async check() {
496
+ const checkedAt = new Date().toISOString();
497
+
498
+ // 1. Check if OpenCode is available
499
+ if (!this.isAvailable()) {
500
+ return {
501
+ status: 'error',
502
+ message: 'OpenCode CLI not installed. Install from https://opencode.ai',
503
+ checkedAt
504
+ };
505
+ }
506
+
507
+ // 2. Try ping test first
508
+ const pingResult = await this.pingTest();
509
+ if (pingResult.responsive) {
510
+ return {
511
+ status: 'success',
512
+ message: 'OpenCode is responsive and configured',
513
+ checkedAt
514
+ };
515
+ }
516
+
517
+ // 3. If ping failed due to configuration, try to create basic config
518
+ if (pingResult.needsConfig) {
519
+ console.log('🔧 OpenCode needs configuration, attempting to setup...');
520
+
521
+ const configResult = await this.createBasicConfig();
522
+ if (configResult.success) {
523
+ // Create config override string
524
+ const availableProviders = this.detectAvailableProviders();
525
+ const model = this.selectWorkingModel(availableProviders);
526
+ const configOverride = JSON.stringify({
527
+ "$schema": "https://opencode.ai/config.json",
528
+ "model": model,
529
+ "autoupdate": false,
530
+ "server": { "port": 4096 }
531
+ });
532
+
533
+ console.log('[OPENCODE CHECK] Trying with config override...');
534
+ const retryPing = await this.pingTest(configOverride);
535
+ if (retryPing.responsive) {
536
+ return {
537
+ status: 'success',
538
+ message: 'OpenCode configured and responsive (with config override)',
539
+ checkedAt
540
+ };
541
+ } else if (retryPing.needsConfig) {
542
+ // Still needs config - provide specific guidance based on what we know
543
+ console.log('🔧 Non-interactive mode has max_tokens issues, but interactive mode may work...');
544
+
545
+ return {
546
+ status: 'error',
547
+ message: 'OpenCode has max_tokens configuration issues with the selected Groq model. Both interactive and non-interactive modes are affected. Please try: 1) Select a different model with Ctrl+o, 2) Check your GROQ_API_KEY quota, 3) Update OpenCode, or 4) Use a different provider.',
548
+ checkedAt
549
+ };
550
+ } else {
551
+ // Configuration created but still not working
552
+ return {
553
+ status: 'error',
554
+ message: `OpenCode configured but still not responding: ${retryPing.error}`,
555
+ checkedAt
556
+ };
557
+ }
558
+ } else {
559
+ return {
560
+ status: 'error',
561
+ message: `Failed to configure OpenCode: ${configResult.error}`,
562
+ checkedAt
563
+ };
564
+ }
565
+ }
566
+
567
+ // 4. If we get here, try to detect if it's stuck in initial setup
568
+ const autoConfigResult = await this.attemptAutoConfiguration();
569
+ if (autoConfigResult.needsManualConfig) {
570
+ return {
571
+ status: 'error',
572
+ message: 'OpenCode requires manual configuration. Interactive mode works but non-interactive mode has max_tokens issues. Please run "opencode" interactively to complete setup, then try the agent check again.',
573
+ checkedAt
574
+ };
575
+ }
576
+
577
+ // 5. Generic failure
578
+ return {
579
+ status: 'error',
580
+ message: pingResult.error || 'OpenCode check failed',
581
+ checkedAt
582
+ };
583
+ }
584
+ }
585
+
586
+ module.exports = {
587
+ OpenCodeChecker
588
+ };
@@ -77,9 +77,67 @@ async function checkProvider(providerId, config = {}, repoPath, onProgress = nul
77
77
 
78
78
  const resultFile = getResultFilePath(repoPath);
79
79
 
80
+ // Special handling: VS Code Copilot CLI is often installed but not authenticated.
81
+ // Detect that case explicitly so the UI can prompt for configuration instead of showing rate limit.
82
+ if (providerId === 'vscode-copilot-cli') {
83
+ try {
84
+ if (onProgress) onProgress(providerId, 'configuring', null, 'Checking configuration...');
85
+ const DirectLLMManager = require('vibecodingmachine-core/src/llm/direct-llm-manager.cjs');
86
+ const mgr = new DirectLLMManager();
87
+ const availability = await mgr.isVSCodeCopilotCLIAvailable();
88
+
89
+ if (!availability || !availability.available) {
90
+ return {
91
+ status: 'error',
92
+ message: `${def.name} is not installed or not in PATH. Install GitHub Copilot CLI and try again.`,
93
+ checkedAt: new Date().toISOString(),
94
+ requirementLeftPending: false,
95
+ needsConfiguration: true
96
+ };
97
+ }
98
+
99
+ if (availability.needsAuth) {
100
+ return {
101
+ status: 'error',
102
+ message: `${def.name} is installed but not authenticated. Run 'copilot login' (or authenticate GitHub CLI and restart) then try again.`,
103
+ checkedAt: new Date().toISOString(),
104
+ requirementLeftPending: false,
105
+ needsConfiguration: true
106
+ };
107
+ }
108
+
109
+ // Check if rate limited
110
+ if (availability.rateLimited) {
111
+ return {
112
+ status: 'error',
113
+ message: `${def.name} is rate limited. Quota reset should happen soon.`,
114
+ checkedAt: new Date().toISOString(),
115
+ requirementLeftPending: false,
116
+ rateLimited: true
117
+ };
118
+ }
119
+
120
+ // Copilot CLI is available and authenticated - return success immediately
121
+ return {
122
+ status: 'success',
123
+ message: `${def.name} is working correctly (tested with copilot -p "Reply with OK" -s --no-ask-user)`,
124
+ checkedAt: new Date().toISOString(),
125
+ requirementLeftPending: false
126
+ };
127
+ } catch (err) {
128
+ return {
129
+ status: 'error',
130
+ message: `${def.name} configuration check failed: ${err.message}`,
131
+ checkedAt: new Date().toISOString(),
132
+ requirementLeftPending: false,
133
+ needsConfiguration: true
134
+ };
135
+ }
136
+ }
137
+
80
138
  // Ensure the config has repoPath set for the child process
81
139
  try {
82
- const { getRepoPath, setRepoPath } = require('./config');
140
+ const { getRepoPath, setRepoPath } = require('../config');
83
141
  const currentRepoPath = await getRepoPath();
84
142
  if (currentRepoPath !== repoPath) {
85
143
  console.log(`[AGENT CHECK] Setting main config repoPath to: ${repoPath}`);
@@ -96,11 +154,38 @@ async function checkProvider(providerId, config = {}, repoPath, onProgress = nul
96
154
  // For direct CLI providers: auto-install if missing
97
155
  const cliInfo = CLI_AUTO_INSTALL[providerId];
98
156
  if (cliInfo && !isCLIAvailable(cliInfo.cmd, providerId)) {
99
- if (onProgress) onProgress(providerId, 'installing');
157
+ if (onProgress) {
158
+ onProgress(providerId, 'installing');
159
+ }
160
+
100
161
  const { installed, note } = await installCLI(providerId);
101
162
  if (!installed) {
102
163
  return { status: 'error', message: `${def.name} not installed and auto-install failed: ${note}`, checkedAt: new Date().toISOString(), requirementLeftPending: false };
103
164
  }
165
+
166
+ if (onProgress) {
167
+ onProgress(providerId, 'installing', null, 'Installation complete, configuring...');
168
+ }
169
+ }
170
+
171
+ // Special handling for OpenCode - use specialized checker
172
+ if (providerId === 'opencode') {
173
+ const { OpenCodeChecker } = require('./opencode-checker');
174
+ const checker = new OpenCodeChecker();
175
+ const result = await checker.check();
176
+
177
+ if (result.status === 'success') {
178
+ // OpenCode is responsive, create the result file to indicate success
179
+ try {
180
+ fs.writeFileSync(resultFile, 'VCM_CHECK_OK', 'utf8');
181
+ } catch (err) {
182
+ console.warn(`[AGENT CHECK] Could not write result file: ${err.message}`);
183
+ }
184
+ return { ...result, requirementLeftPending: false };
185
+ } else {
186
+ // OpenCode failed - leave requirement pending for other agents
187
+ return { ...result, requirementLeftPending: true };
188
+ }
104
189
  }
105
190
 
106
191
  // Add test requirement (idempotent — safe to call even if already present from a prior failed agent)
@@ -137,7 +222,7 @@ async function checkAllProviders(providerIds, config = {}, repoPath, onProgress
137
222
  if (signal && signal.cancelled) break;
138
223
  if (onProgress) onProgress(id, 'checking');
139
224
  results[id] = await checkProvider(id, config, repoPath, onProgress, signal);
140
- if (onProgress) onProgress(id, 'done', results[id]);
225
+ if (onProgress) onProgress(id, 'done', results[id].status === 'error' ? results[id].message : null);
141
226
  }
142
227
 
143
228
  // Final cleanup — remove requirement if still pending (all agents failed or skipped)