vibecodingmachine-cli 2026.2.26-1739 → 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 +5 -1
  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,603 @@
1
+ /**
2
+ * TRUI Navigation — Main Menu
3
+ *
4
+ * Renders the status-rich main menu using showQuickMenu (raw keypress).
5
+ * Status/settings lines shown in gray at top; action items in white below.
6
+ * Uses inline accordion expansion for sections.
7
+ * Now using RUI pattern for consistent command structure.
8
+ */
9
+
10
+ const chalk = require('chalk');
11
+ const inquirer = require('inquirer');
12
+ const { showQuickMenu } = require('./trui-quick-menu');
13
+ const { showProviderManagerMenu } = require('./provider-manager');
14
+ const { initializeWindsurfIntegration, getWindsurfStatus } = require('./trui-windsurf');
15
+ const { debugLogger, perfMonitor, stateTracker } = require('./trui-debug');
16
+ const RUITRUIAdapter = require('./rui-trui-adapter');
17
+
18
+ // Import section modules
19
+ const {
20
+ loadRequirementsData,
21
+ buildRequirementChoices,
22
+ handleRequirementSelection,
23
+ handleRequirementMove,
24
+ } = require('./trui-nav-requirements');
25
+
26
+ const {
27
+ loadSettingsData,
28
+ buildSettingChoices,
29
+ handleSettingSelection,
30
+ showSettings,
31
+ } = require('./trui-nav-settings');
32
+
33
+ const {
34
+ loadSpecificationsData,
35
+ buildSpecificationChoices,
36
+ handleSpecificationSelection,
37
+ addSpecificationFlow,
38
+ } = require('./trui-nav-specifications');
39
+
40
+ const {
41
+ loadAgentsData,
42
+ buildAgentChoices,
43
+ handleAgentSelection,
44
+ handleAgentAction,
45
+ createAgentNavigationHandler,
46
+ } = require('./trui-nav-agents');
47
+
48
+ /**
49
+ * Build main-menu items array with live status at top + inline accordion sections
50
+ * @param {Object} expandedSections - Map of section names to expanded state
51
+ * @param {Object} navigation - TRUINavigation instance for loading section data
52
+ */
53
+ async function buildMainMenuItems(expandedSections = {}, navigation = null) {
54
+ const items = [];
55
+
56
+ // Auto Mode status
57
+ let autoStatus = { running: false };
58
+ try {
59
+ const { checkAutoModeStatus } = require('./auto-mode');
60
+ autoStatus = await checkAutoModeStatus();
61
+ } catch (_) {}
62
+
63
+ items.push({
64
+ type: 'setting',
65
+ name: `Auto Mode: ${autoStatus.running ? chalk.green('Running ✓') : chalk.yellow('Stopped ○')}`,
66
+ value: 'setting:auto',
67
+ });
68
+
69
+ // Requirements summary (only show when requirements section is not expanded)
70
+ if (!expandedSections.requirements) {
71
+ try {
72
+ const { countRequirements } = require('./status-helpers-extracted');
73
+ const counts = await countRequirements();
74
+ if (counts) {
75
+ const total = (counts.todoCount || 0) + (counts.toVerifyCount || 0) + (counts.verifiedCount || 0);
76
+ const pct = n => total > 0 ? Math.round((n / total) * 100) : 0;
77
+ items.push({
78
+ type: 'setting',
79
+ name: `Requirements: ${chalk.yellow(counts.todoCount + ' todo')}, ${chalk.cyan(counts.toVerifyCount + ' verify')}, ${chalk.green(counts.verifiedCount + ' done')} (${pct(counts.verifiedCount)}% complete)`,
80
+ value: 'setting:requirements',
81
+ });
82
+ }
83
+ } catch (_) {}
84
+ }
85
+
86
+ // Current agent display with rate-limit warning
87
+ try {
88
+ const { getProviderPreferences } = require('./provider-registry');
89
+ const prefs = await getProviderPreferences();
90
+ const { getProviderCache } = require('./config');
91
+ const cache = await getProviderCache();
92
+
93
+ // Find first enabled provider
94
+ let currentAgent = null;
95
+ let rateLimitWarning = '';
96
+ for (const agentId of (prefs.order || [])) {
97
+ if (prefs.enabled[agentId] !== false) {
98
+ currentAgent = agentId;
99
+ const agentCache = cache[agentId];
100
+ if (agentCache && agentCache.rateLimitRemaining !== undefined) {
101
+ if (agentCache.rateLimitRemaining < 10) {
102
+ rateLimitWarning = chalk.red(` (${agentCache.rateLimitRemaining} left)`);
103
+ } else if (agentCache.rateLimitRemaining < 50) {
104
+ rateLimitWarning = chalk.yellow(` (${agentCache.rateLimitRemaining} left)`);
105
+ }
106
+ }
107
+ break;
108
+ }
109
+ }
110
+
111
+ if (currentAgent) {
112
+ const { getProviderDisplayName } = require('./provider-registry');
113
+ const displayName = getProviderDisplayName(currentAgent);
114
+ items.push({
115
+ type: 'setting',
116
+ name: `Agent: ${chalk.cyan(displayName)}${rateLimitWarning}`,
117
+ value: 'setting:agent',
118
+ });
119
+ }
120
+ } catch (_) {}
121
+
122
+ items.push({ type: 'blank', name: '', value: 'blank' });
123
+
124
+ // Requirements section with inline accordion
125
+ const reqExpanded = expandedSections.requirements || false;
126
+ const reqIcon = reqExpanded ? '▼' : '▶';
127
+ items.push({ type: 'action', name: `${reqIcon} 📋 Requirements`, value: 'requirements' });
128
+ if (reqExpanded && navigation) {
129
+ const reqData = await loadRequirementsData(navigation);
130
+ const reqChoices = buildRequirementChoices(reqData);
131
+ reqChoices.forEach(choice => {
132
+ if (choice instanceof inquirer.Separator) {
133
+ items.push({ type: 'separator', name: choice.line, value: 'separator' });
134
+ } else {
135
+ items.push({ type: 'sub-item', name: choice.name, value: choice.value });
136
+ }
137
+ });
138
+ }
139
+
140
+ // Agents section with inline accordion
141
+ const agentsExpanded = expandedSections.agents || false;
142
+ const agentsIcon = agentsExpanded ? '▼' : '▶';
143
+ items.push({ type: 'action', name: `${agentsIcon} 🤖 Agents`, value: 'agents' });
144
+ if (agentsExpanded && navigation) {
145
+ const agentsData = await loadAgentsData(navigation);
146
+ const agentsChoices = buildAgentChoices(agentsData);
147
+ agentsChoices.forEach(choice => {
148
+ if (choice instanceof inquirer.Separator) {
149
+ items.push({ type: 'separator', name: choice.line, value: 'separator' });
150
+ } else {
151
+ items.push({ type: 'sub-item', name: choice.name, value: choice.value });
152
+ }
153
+ });
154
+ }
155
+
156
+ // Specifications section with inline accordion
157
+ const specsExpanded = expandedSections.specifications || false;
158
+ const specsIcon = specsExpanded ? '▼' : '▶';
159
+ items.push({ type: 'action', name: `${specsIcon} 📐 Specifications`, value: 'specifications' });
160
+ if (specsExpanded) {
161
+ const specsData = await loadSpecificationsData();
162
+ const specsChoices = buildSpecificationChoices(specsData);
163
+ specsChoices.forEach(choice => {
164
+ items.push({ type: 'sub-item', name: choice.name, value: choice.value });
165
+ });
166
+ }
167
+
168
+ // Settings (non-accordion, opens separate view)
169
+ items.push({ type: 'action', name: '⚙️ Settings', value: 'settings' });
170
+
171
+ // Action shortcuts
172
+ items.push({ type: 'blank', name: '', value: 'blank' });
173
+ items.push({ type: 'action', name: '[+ Add Requirement]', value: 'add-req' });
174
+ items.push({ type: 'action', name: '[+ Add Specification]', value: 'add-spec' });
175
+ items.push({ type: 'action', name: '💬 Send Continue to Windsurf', value: 'continue-windsurf' });
176
+ items.push({ type: 'action', name: '🔄 Sync Now', value: 'sync' });
177
+ items.push({ type: 'action', name: 'Exit', value: 'exit' });
178
+
179
+ return items;
180
+ }
181
+
182
+ /**
183
+ * TRUINavigation — main menu loop
184
+ */
185
+ class TRUINavigation {
186
+ constructor() {
187
+ this._lastIndex = 0;
188
+ this.ruiAdapter = new RUITRUIAdapter();
189
+ }
190
+
191
+ get resolver() {
192
+ if (!this.ruiAdapter.resolver) {
193
+ this.ruiAdapter.initialize();
194
+ }
195
+ return this.ruiAdapter.resolver;
196
+ }
197
+
198
+ async start() {
199
+ perfMonitor.start('TRUINavigation.start');
200
+ stateTracker.push({ type: 'navigation', phase: 'start' });
201
+
202
+ const { showWelcomeScreen } = require('./welcome-screen-extracted');
203
+
204
+ console.clear();
205
+ try { await showWelcomeScreen(); } catch (_) {}
206
+
207
+ // Initialize Windsurf integration with error handling
208
+ try {
209
+ initializeWindsurfIntegration();
210
+ } catch (error) {
211
+ console.log(chalk.yellow('⚠ Windsurf integration disabled: ' + error.message));
212
+ }
213
+
214
+ await this._loop();
215
+
216
+ perfMonitor.end('TRUINavigation.start');
217
+ stateTracker.pop();
218
+ }
219
+
220
+ async _loop() {
221
+ perfMonitor.start('TRUINavigation.loop');
222
+ stateTracker.push({ type: 'navigation', phase: 'loop' });
223
+
224
+ const { sendContinueToWindsurf } = require('./trui-windsurf');
225
+
226
+ // Track expanded sections state
227
+ const expandedSections = {
228
+ requirements: false,
229
+ agents: false,
230
+ specifications: false,
231
+ };
232
+
233
+ // Track data cache for sections
234
+ let requirementsData = null;
235
+ let agentsData = null;
236
+ let specificationsData = null;
237
+
238
+ while (true) {
239
+ try {
240
+ const items = await buildMainMenuItems(expandedSections, this);
241
+
242
+ // Force screen clear when menu content changes (like when sections expand/collapse)
243
+ if (process.stdout.isTTY) {
244
+ console.clear();
245
+ }
246
+
247
+ // Extra keys handler for special commands and agent actions
248
+ const extraKeys = (str, key, selectedIndex, context) => {
249
+ if (str === '!' || str === '1') {
250
+ // Run agents check command
251
+ context.resolveWith('agents-check');
252
+ return true;
253
+ }
254
+ if (str === 'n' || str === 'N') {
255
+ // Add requirement shortcut
256
+ context.resolveWith('add-requirement');
257
+ return true;
258
+ }
259
+
260
+ // Handle agent enable/disable keys when agents section is expanded
261
+ if ((str === 'e' || str === 'E' || str === 'd' || str === 'D') && expandedSections.agents && agentsData) {
262
+ const currentItem = items[selectedIndex];
263
+ if (currentItem && currentItem.type === 'sub-item' && currentItem.value && currentItem.value.startsWith('agent:')) {
264
+ const agentIndex = parseInt(currentItem.value.substring(6), 10);
265
+ const agent = agentsData.agents[agentIndex];
266
+ if (agent) {
267
+ const action = str.toLowerCase() === 'e' ? 'enable' : 'disable';
268
+ context.resolveWith(`agent-${action}:${agentIndex}`);
269
+ return true;
270
+ }
271
+ }
272
+ }
273
+
274
+ // Arrow key navigation for agents
275
+ if (expandedSections.agents && agentsData && (key.name === 'up' || key.name === 'down')) {
276
+ const choices = items.filter(item => item.type === 'sub-item' && item.value && item.value.startsWith('agent:'));
277
+ const agentNavHandler = createAgentNavigationHandler(agentsData, choices);
278
+ return agentNavHandler(str, key, selectedIndex, context);
279
+ }
280
+
281
+ return false;
282
+ };
283
+
284
+ const result = await showQuickMenu(items, this._lastIndex, extraKeys);
285
+ this._lastIndex = result.selectedIndex;
286
+ const action = result.value;
287
+
288
+ if (action === '__cancel__' || action === 'exit') {
289
+ await this._confirmExit();
290
+ continue;
291
+ }
292
+
293
+ // Handle section accordion toggles
294
+ if (action === 'requirements') {
295
+ expandedSections.requirements = !expandedSections.requirements;
296
+ if (expandedSections.requirements) {
297
+ requirementsData = await loadRequirementsData(this);
298
+ }
299
+ continue;
300
+ }
301
+
302
+ if (action === 'agents') {
303
+ expandedSections.agents = !expandedSections.agents;
304
+ if (expandedSections.agents) {
305
+ agentsData = await loadAgentsData(this);
306
+ }
307
+ continue;
308
+ }
309
+
310
+ if (action === 'specifications') {
311
+ expandedSections.specifications = !expandedSections.specifications;
312
+ if (expandedSections.specifications) {
313
+ specificationsData = await loadSpecificationsData();
314
+ }
315
+ continue;
316
+ }
317
+
318
+ // Handle requirement sub-item selections
319
+ if (action.startsWith('req:')) {
320
+ const reqIndex = parseInt(action.substring(4), 10);
321
+ const changed = await handleRequirementSelection(reqIndex, requirementsData, this);
322
+ if (changed) {
323
+ requirementsData = await loadRequirementsData(this);
324
+ }
325
+ console.clear();
326
+ continue;
327
+ }
328
+
329
+ // Handle requirement move up
330
+ if (action.startsWith('req-move-up:')) {
331
+ const reqIndex = parseInt(action.substring(12), 10);
332
+ const changed = await handleRequirementMove(reqIndex, requirementsData, 'up');
333
+ if (changed) {
334
+ requirementsData = await loadRequirementsData(this);
335
+ }
336
+ console.clear();
337
+ continue;
338
+ }
339
+
340
+ // Handle requirement move down
341
+ if (action.startsWith('req-move-down:')) {
342
+ const reqIndex = parseInt(action.substring(14), 10);
343
+ const changed = await handleRequirementMove(reqIndex, requirementsData, 'down');
344
+ if (changed) {
345
+ requirementsData = await loadRequirementsData(this);
346
+ }
347
+ console.clear();
348
+ continue;
349
+ }
350
+
351
+ // Handle agent sub-item selections
352
+ if (action.startsWith('agent:')) {
353
+ const agentIndex = parseInt(action.substring(6), 10);
354
+ const changed = await handleAgentSelection(agentIndex, agentsData, this);
355
+ if (changed) {
356
+ agentsData = await loadAgentsData(this);
357
+ }
358
+ console.clear();
359
+ continue;
360
+ }
361
+
362
+ // Handle agent enable action
363
+ if (action.startsWith('agent-enable:')) {
364
+ const agentIndex = parseInt(action.substring(13), 10);
365
+ const changed = await handleAgentAction(agentIndex, agentsData, this, 'enable');
366
+ if (changed) {
367
+ agentsData = await loadAgentsData(this);
368
+ }
369
+ console.clear();
370
+ continue;
371
+ }
372
+
373
+ // Handle agent disable action
374
+ if (action.startsWith('agent-disable:')) {
375
+ const agentIndex = parseInt(action.substring(14), 10);
376
+ const changed = await handleAgentAction(agentIndex, agentsData, this, 'disable');
377
+ if (changed) {
378
+ agentsData = await loadAgentsData(this);
379
+ }
380
+ console.clear();
381
+ continue;
382
+ }
383
+
384
+
385
+ // Handle specification sub-item selections
386
+ if (action.startsWith('spec:')) {
387
+ const specDir = action.substring(5);
388
+ await handleSpecificationSelection(specDir, specificationsData, this);
389
+ console.clear();
390
+ continue;
391
+ }
392
+
393
+ // Dispatch to sub-modules
394
+ try {
395
+ if (action === 'setting:auto') {
396
+ try {
397
+ const { checkAutoModeStatus, stopAutoMode } = require('./auto-mode');
398
+ const s = await checkAutoModeStatus();
399
+ if (s.running) {
400
+ await stopAutoMode('manual');
401
+ console.log(chalk.yellow('\n⏹ Auto mode stopped\n'));
402
+ await this._pause();
403
+ console.clear();
404
+ } else {
405
+ console.log(chalk.bold.cyan('\n▶ Starting Auto Mode...\n'));
406
+ try {
407
+ const { getAutoConfig } = require('./config');
408
+ const currentConfig = await getAutoConfig();
409
+ // Pick first enabled provider
410
+ const { getProviderPreferences } = require('./provider-registry');
411
+ const prefs = await getProviderPreferences();
412
+ let agentToUse = currentConfig.ide || currentConfig.agent || 'cline';
413
+ for (const agentId of (prefs.order || [])) {
414
+ if (prefs.enabled[agentId] !== false) { agentToUse = agentId; break; }
415
+ }
416
+ // Release raw mode before running auto (so Ctrl+C works)
417
+ if (process.stdin.isTTY && process.stdin.setRawMode) {
418
+ process.stdin.setRawMode(false);
419
+ }
420
+ const options = { ide: agentToUse };
421
+ if (currentConfig.neverStop) {
422
+ options.neverStop = true;
423
+ } else if (currentConfig.maxChats) {
424
+ options.maxChats = currentConfig.maxChats;
425
+ } else {
426
+ options.neverStop = true;
427
+ }
428
+ const { handleAutoStart } = require('../commands/auto-direct');
429
+ await handleAutoStart(options);
430
+ } catch (startErr) {
431
+ if (startErr.message && startErr.message.includes('User force closed')) {
432
+ console.log(chalk.yellow('\nCancelled\n'));
433
+ } else {
434
+ console.log(chalk.red(`\n✗ Error: ${startErr.message}`));
435
+ if (startErr.stack) console.log(chalk.gray(startErr.stack.split('\n').slice(0, 8).join('\n')));
436
+ console.log(chalk.yellow('\nReturning to menu in 5 seconds...'));
437
+ await new Promise(r => setTimeout(r, 5000));
438
+ }
439
+ }
440
+ await this._pause();
441
+ console.clear();
442
+ }
443
+ } catch (err) { console.log(chalk.red('Error: ' + err.message)); await this._pause(); console.clear(); }
444
+ continue;
445
+ }
446
+
447
+ if (action === 'agents-check') {
448
+ try {
449
+ const { checkAgents } = require('../commands/agents-check');
450
+ console.clear();
451
+ console.log(chalk.bold.cyan('🔍 Checking agents...\n'));
452
+ await checkAgents();
453
+ await this._pause();
454
+ } catch (err) {
455
+ console.log(chalk.red('Agents check error: ' + err.message));
456
+ await this._pause();
457
+ }
458
+ console.clear();
459
+ continue;
460
+ }
461
+
462
+ if (action === 'settings') {
463
+ try { await showSettings(); } catch (err) { console.log(chalk.red('Settings error: ' + err.message)); await this._pause(); }
464
+ console.clear();
465
+ continue;
466
+ }
467
+
468
+ if (action === 'add-req' || action === 'add-requirement') {
469
+ try { await addRequirementFlow(this); } catch (err) { console.log(chalk.red('Error: ' + err.message)); await this._pause(); }
470
+ console.clear();
471
+ // Refresh requirements data if section is expanded
472
+ if (expandedSections.requirements) {
473
+ requirementsData = await loadRequirementsData(this);
474
+ }
475
+ continue;
476
+ }
477
+
478
+ if (action === 'add-spec') {
479
+ try { await addSpecificationFlow(this); } catch (err) { console.log(chalk.red('Error: ' + err.message)); await this._pause(); }
480
+ console.clear();
481
+ // Refresh specifications data if section is expanded
482
+ if (expandedSections.specifications) {
483
+ specificationsData = await loadSpecificationsData();
484
+ }
485
+ continue;
486
+ }
487
+
488
+ if (action === 'continue-windsurf') {
489
+ try {
490
+ await sendContinueToWindsurf();
491
+ console.log(chalk.green('\n✓ Continue message sent to Windsurf Cascade\n'));
492
+ } catch (err) { console.log(chalk.red('Error: ' + err.message)); }
493
+ await this._pause();
494
+ console.clear();
495
+ continue;
496
+ }
497
+
498
+ if (action === 'sync') {
499
+ try {
500
+ const { execSync } = require('child_process');
501
+ console.log(chalk.cyan('\n🔄 Syncing...\n'));
502
+ execSync('vcm sync:now', { stdio: 'inherit' });
503
+ } catch (_) { console.log(chalk.gray('vcm sync:now: command unavailable')); }
504
+ await this._pause();
505
+ console.clear();
506
+ continue;
507
+ }
508
+
509
+ // Unknown action — skip noop/blank/separator
510
+ if (action === 'noop' || action === 'blank' || action === 'separator') {
511
+ continue;
512
+ }
513
+
514
+ // Unknown action — show error
515
+ console.log(chalk.yellow('Unknown action: ' + action));
516
+ await this._pause();
517
+ console.clear();
518
+ continue;
519
+ } catch (err) {
520
+ console.log(chalk.red('Action error: ' + err.message));
521
+ await this._pause();
522
+ console.clear();
523
+ continue;
524
+ }
525
+
526
+ } catch (error) {
527
+ debugLogger.error('Menu loop error', { error: error.message, stack: error.stack });
528
+ console.log(chalk.red('Menu error: ' + error.message));
529
+ await this._pause();
530
+ continue;
531
+ }
532
+ }
533
+
534
+ perfMonitor.end('TRUINavigation.loop');
535
+ stateTracker.pop();
536
+ }
537
+
538
+ async _confirmExit() {
539
+ console.clear();
540
+ console.log(chalk.yellow('\nExit Vibe Coding Machine? (Y/n/x)\n'));
541
+
542
+ return new Promise((resolve) => {
543
+ const readline = require('readline');
544
+
545
+ // Set up raw keypress handling
546
+ readline.emitKeypressEvents(process.stdin);
547
+ if (process.stdin.isTTY && process.stdin.setRawMode) {
548
+ process.stdin.setRawMode(true);
549
+ }
550
+
551
+ const onKeypress = (str, key) => {
552
+ // Handle left arrow - exit without confirmation
553
+ if (key && key.name === 'left') {
554
+ cleanup();
555
+ console.log(chalk.yellow('\nGoodbye!\n'));
556
+ process.exit(0);
557
+ return;
558
+ }
559
+
560
+ // Handle Enter or 'y' or 'Y' or 'x' - confirm exit
561
+ if (key && (key.name === 'return' || (str && (str === 'y' || str === 'Y' || str === 'x' || str === 'X')))) {
562
+ cleanup();
563
+ console.log(chalk.yellow('\nGoodbye!\n'));
564
+ process.exit(0);
565
+ return;
566
+ }
567
+
568
+ // Handle 'n' or 'N' or ESC or right arrow - cancel exit
569
+ if (key && (key.name === 'escape' || key.name === 'right' || (str && (str === 'n' || str === 'N')))) {
570
+ cleanup();
571
+ resolve();
572
+ return;
573
+ }
574
+ };
575
+
576
+ const cleanup = () => {
577
+ if (process.stdin.isTTY && process.stdin.setRawMode) {
578
+ process.stdin.setRawMode(false);
579
+ }
580
+ process.stdin.removeListener('keypress', onKeypress);
581
+ process.stdin.pause();
582
+ };
583
+
584
+ process.stdin.on('keypress', onKeypress);
585
+ process.stdin.resume();
586
+ });
587
+ }
588
+
589
+ async _pause() {
590
+ const inquirer = require('inquirer');
591
+ await inquirer.prompt([{ type: 'input', name: 'c', message: chalk.gray('Press Enter to continue...') }]);
592
+ }
593
+
594
+ async promptContinue() {
595
+ await this._pause();
596
+ }
597
+ }
598
+
599
+ module.exports = { TRUINavigation, buildMainMenuItems };
600
+
601
+ // Export a singleton instance for use by other modules
602
+ const navigationInstance = new TRUINavigation();
603
+ module.exports.promptContinue = () => navigationInstance.promptContinue();