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,194 @@
1
+ /**
2
+ * TRUI Main Menu Handlers
3
+ *
4
+ * Extracted from trui-navigation.js to reduce file size
5
+ */
6
+
7
+ const chalk = require('chalk');
8
+ const inquirer = require('inquirer');
9
+ const { showQuickMenu } = require('./trui-quick-menu');
10
+ const { showProviderManagerMenu } = require('./provider-manager');
11
+ const { initializeWindsurfIntegration, getWindsurfStatus } = require('./trui-windsurf');
12
+ const { debugLogger, perfMonitor, stateTracker } = require('./trui-debug');
13
+
14
+ // Import section modules
15
+ const {
16
+ handleRequirementSelection,
17
+ handleRequirementMove,
18
+ } = require('./trui-nav-requirements');
19
+
20
+ const {
21
+ handleSettingSelection,
22
+ showSettings,
23
+ } = require('./trui-nav-settings');
24
+
25
+ const {
26
+ handleSpecificationSelection,
27
+ addSpecificationFlow,
28
+ } = require('./trui-nav-specifications');
29
+
30
+ const {
31
+ handleAgentSelection,
32
+ handleAgentAction,
33
+ createAgentNavigationHandler,
34
+ } = require('./trui-nav-agents');
35
+
36
+ /**
37
+ * Handle main menu selection
38
+ */
39
+ async function handleMainMenuSelection(result, expandedSections, navigation) {
40
+ const value = result.value;
41
+
42
+ if (value === '__cancel__' || value === 'exit') {
43
+ return { shouldExit: true };
44
+ }
45
+
46
+ if (value.startsWith('section:')) {
47
+ const sectionName = value.substring(8);
48
+ expandedSections[sectionName] = !expandedSections[sectionName];
49
+ return { shouldContinue: true };
50
+ }
51
+
52
+ // Handle section-specific selections
53
+ if (value.startsWith('requirements:')) {
54
+ await handleRequirementSelection(value, navigation);
55
+ return { shouldContinue: true };
56
+ }
57
+
58
+ if (value.startsWith('settings:')) {
59
+ await handleSettingSelection(value, navigation);
60
+ return { shouldContinue: true };
61
+ }
62
+
63
+ if (value.startsWith('specifications:')) {
64
+ await handleSpecificationSelection(value, navigation);
65
+ return { shouldContinue: true };
66
+ }
67
+
68
+ if (value.startsWith('agents:')) {
69
+ await handleAgentSelection(value, navigation);
70
+ return { shouldContinue: true };
71
+ }
72
+
73
+ // Handle tool selections
74
+ if (value === 'provider-manager') {
75
+ await showProviderManagerMenu(navigation);
76
+ return { shouldContinue: true };
77
+ }
78
+
79
+ if (value === 'windsurf') {
80
+ await handleWindsurfSelection();
81
+ return { shouldContinue: true };
82
+ }
83
+
84
+ if (value === 'debug-info') {
85
+ await showDebugInfo();
86
+ return { shouldContinue: true };
87
+ }
88
+
89
+ return { shouldContinue: true };
90
+ }
91
+
92
+ /**
93
+ * Handle Windsurf selection
94
+ */
95
+ async function handleWindsurfSelection() {
96
+ console.clear();
97
+ console.log(chalk.bold.cyan('🌊 Windsurf Integration\n'));
98
+
99
+ try {
100
+ await initializeWindsurfIntegration();
101
+ const status = await getWindsurfStatus();
102
+
103
+ console.log(`Status: ${status.connected ? chalk.green('Connected') : chalk.red('Disconnected')}`);
104
+ console.log(`Workspace: ${status.workspace || 'None'}`);
105
+ console.log(`Version: ${status.version || 'Unknown'}`);
106
+
107
+ } catch (error) {
108
+ console.log(chalk.red('Error: ' + error.message));
109
+ }
110
+
111
+ console.log(chalk.gray('\nPress Enter to continue...'));
112
+ await inquirer.prompt([{ type: 'input', name: 'c', message: '' }]);
113
+ }
114
+
115
+ /**
116
+ * Show debug information
117
+ */
118
+ async function showDebugInfo() {
119
+ console.clear();
120
+ console.log(chalk.bold.cyan('📊 Debug Information\n'));
121
+
122
+ try {
123
+ // Show performance stats
124
+ const perfStats = perfMonitor.getStats();
125
+ console.log(chalk.yellow('Performance Stats:'));
126
+ console.log(` Menu renders: ${perfStats.menuRenders}`);
127
+ console.log(` Avg render time: ${perfStats.avgRenderTime.toFixed(2)}ms`);
128
+ console.log(` Total render time: ${perfStats.totalRenderTime.toFixed(2)}ms`);
129
+
130
+ // Show state tracking
131
+ const stateHistory = stateTracker.getHistory();
132
+ console.log(chalk.yellow('\nState History:'));
133
+ stateHistory.slice(-5).forEach(entry => {
134
+ console.log(` ${entry.timestamp}: ${entry.action} - ${entry.details}`);
135
+ });
136
+
137
+ // Show debug log status
138
+ console.log(chalk.yellow('\nDebug Logging:'));
139
+ console.log(` Enabled: ${debugLogger.enabled ? 'Yes' : 'No'}`);
140
+ console.log(` Log file: ${debugLogger.logFile}`);
141
+
142
+ } catch (error) {
143
+ console.log(chalk.red('Error getting debug info: ' + error.message));
144
+ }
145
+
146
+ console.log(chalk.gray('\nPress Enter to continue...'));
147
+ await inquirer.prompt([{ type: 'input', name: 'c', message: '' }]);
148
+ }
149
+
150
+ /**
151
+ * Setup extra keyboard handlers for main menu
152
+ */
153
+ function setupMainMenuExtraKeys(items) {
154
+ return (str, key, selectedIndex, context) => {
155
+ const currentItem = items[selectedIndex];
156
+
157
+ // Handle section expansion with space
158
+ if (key.name === 'space' && currentItem && currentItem.value && currentItem.value.startsWith('section:')) {
159
+ const sectionName = currentItem.value.substring(8);
160
+ context.resolveWith(`section:${sectionName}`);
161
+ return true;
162
+ }
163
+
164
+ // Handle quick access keys
165
+ if (str === 'r' || str === 'R') {
166
+ context.resolveWith('section:requirements');
167
+ return true;
168
+ }
169
+
170
+ if (str === 's' || str === 'S') {
171
+ context.resolveWith('section:settings');
172
+ return true;
173
+ }
174
+
175
+ if (str === 'p' || str === 'P') {
176
+ context.resolveWith('provider-manager');
177
+ return true;
178
+ }
179
+
180
+ if (str === 'q' || str === 'Q') {
181
+ context.resolveWith('exit');
182
+ return true;
183
+ }
184
+
185
+ return false;
186
+ };
187
+ }
188
+
189
+ module.exports = {
190
+ handleMainMenuSelection,
191
+ handleWindsurfSelection,
192
+ showDebugInfo,
193
+ setupMainMenuExtraKeys
194
+ };
@@ -0,0 +1,235 @@
1
+ /**
2
+ * TRUI Main Menu Builders
3
+ *
4
+ * Extracted from trui-navigation.js to reduce file size
5
+ */
6
+
7
+ const chalk = require('chalk');
8
+ const { showProviderManagerMenu } = require('./provider-manager');
9
+ const { getWindsurfStatus } = require('./trui-windsurf');
10
+
11
+ // Import section modules
12
+ const {
13
+ loadRequirementsData,
14
+ buildRequirementChoices,
15
+ } = require('./trui-nav-requirements');
16
+
17
+ const {
18
+ loadSettingsData,
19
+ buildSettingChoices,
20
+ } = require('./trui-nav-settings');
21
+
22
+ const {
23
+ loadSpecificationsData,
24
+ buildSpecificationChoices,
25
+ } = require('./trui-nav-specifications');
26
+
27
+ const {
28
+ loadAgentsData,
29
+ buildAgentChoices,
30
+ } = require('./trui-nav-agents');
31
+
32
+ /**
33
+ * Build main-menu items array with live status at top + inline accordion sections
34
+ */
35
+ async function buildMainMenuItems(expandedSections) {
36
+ const items = [];
37
+
38
+ // Status section at top
39
+ const statusItems = await buildStatusSection();
40
+ items.push(...statusItems);
41
+
42
+ // Add blank separator
43
+ items.push({ type: 'blank', name: '', value: 'blank' });
44
+
45
+ // Requirements section (always present)
46
+ const requirementsData = await loadRequirementsData();
47
+ const requirementsItems = await buildRequirementsSection(requirementsData, expandedSections);
48
+ items.push(...requirementsItems);
49
+
50
+ // Settings section
51
+ const settingsData = await loadSettingsData();
52
+ const settingsItems = buildSettingsSection(settingsData);
53
+ items.push(...settingsItems);
54
+
55
+ // Specifications section
56
+ const specificationsData = await loadSpecificationsData();
57
+ const specificationsItems = buildSpecificationsSection(specificationsData, expandedSections);
58
+ items.push(...specificationsItems);
59
+
60
+ // Agents section
61
+ const agentsData = await loadAgentsData();
62
+ const agentsItems = buildAgentsSection(agentsData, expandedSections);
63
+ items.push(...agentsItems);
64
+
65
+ // Additional sections
66
+ items.push({ type: 'separator', name: chalk.gray(' ── Tools ──'), value: 'separator-tools' });
67
+ items.push({ type: 'action', name: '[🔧 Provider Manager]', value: 'provider-manager' });
68
+ items.push({ type: 'action', name: '[🌊 Windsurf]', value: 'windsurf' });
69
+ items.push({ type: 'action', name: '[📊 Debug Info]', value: 'debug-info' });
70
+ items.push({ type: 'action', name: '[❌ Exit]', value: 'exit' });
71
+
72
+ return items;
73
+ }
74
+
75
+ /**
76
+ * Build status section with live data
77
+ */
78
+ async function buildStatusSection() {
79
+ const items = [];
80
+
81
+ // Auto mode status
82
+ const autoModeStatus = await getAutoModeStatus();
83
+ items.push({
84
+ type: 'status',
85
+ name: chalk.gray(`Auto-mode: ${autoModeStatus}`),
86
+ value: 'status:auto-mode'
87
+ });
88
+
89
+ // Requirements counts
90
+ const requirementsData = await loadRequirementsData();
91
+ if (requirementsData) {
92
+ const { todo = 0, verify = 0, verified = 0 } = requirementsData.sections || {};
93
+ const total = todo + verify + verified;
94
+ const progress = total > 0 ? Math.round((verified / total) * 100) : 0;
95
+
96
+ items.push({
97
+ type: 'status',
98
+ name: chalk.gray(`Requirements: ${verified}✓ ${verify}⏳ ${todo}📋 (${progress}%)`),
99
+ value: 'status:requirements'
100
+ });
101
+ }
102
+
103
+ // Current agent/provider
104
+ const agentStatus = await getCurrentAgentStatus();
105
+ if (agentStatus) {
106
+ items.push({
107
+ type: 'status',
108
+ name: chalk.gray(`Agent: ${agentStatus}`),
109
+ value: 'status:agent'
110
+ });
111
+ }
112
+
113
+ return items;
114
+ }
115
+
116
+ /**
117
+ * Build requirements section
118
+ */
119
+ async function buildRequirementsSection(requirementsData, expandedSections) {
120
+ const items = [];
121
+ const isExpanded = expandedSections.requirements || false;
122
+ const icon = isExpanded ? '▼' : '▶';
123
+
124
+ items.push({
125
+ type: 'section',
126
+ name: `${icon} 📋 Requirements`,
127
+ value: 'section:requirements'
128
+ });
129
+
130
+ if (isExpanded && requirementsData) {
131
+ const reqChoices = await buildRequirementChoices(requirementsData);
132
+ items.push(...reqChoices);
133
+ }
134
+
135
+ return items;
136
+ }
137
+
138
+ /**
139
+ * Build settings section
140
+ */
141
+ function buildSettingsSection(settingsData) {
142
+ const items = [];
143
+
144
+ items.push({
145
+ type: 'section',
146
+ name: '⚙️ Settings',
147
+ value: 'section:settings'
148
+ });
149
+
150
+ const settingChoices = buildSettingChoices(settingsData);
151
+ items.push(...settingChoices);
152
+
153
+ return items;
154
+ }
155
+
156
+ /**
157
+ * Build specifications section
158
+ */
159
+ function buildSpecificationsSection(specificationsData, expandedSections) {
160
+ const items = [];
161
+ const isExpanded = expandedSections.specifications || false;
162
+ const icon = isExpanded ? '▼' : '▶';
163
+
164
+ items.push({
165
+ type: 'section',
166
+ name: `${icon} 📄 Specifications`,
167
+ value: 'section:specifications'
168
+ });
169
+
170
+ if (isExpanded && specificationsData) {
171
+ const specChoices = buildSpecificationChoices(specificationsData);
172
+ items.push(...specChoices);
173
+ }
174
+
175
+ return items;
176
+ }
177
+
178
+ /**
179
+ * Build agents section
180
+ */
181
+ function buildAgentsSection(agentsData, expandedSections) {
182
+ const items = [];
183
+ const isExpanded = expandedSections.agents || false;
184
+ const icon = isExpanded ? '▼' : '▶';
185
+
186
+ items.push({
187
+ type: 'section',
188
+ name: `${icon} 🤖 Agents`,
189
+ value: 'section:agents'
190
+ });
191
+
192
+ if (isExpanded && agentsData) {
193
+ const agentChoices = buildAgentChoices(agentsData);
194
+ items.push(...agentChoices);
195
+ }
196
+
197
+ return items;
198
+ }
199
+
200
+ /**
201
+ * Get auto mode status
202
+ */
203
+ async function getAutoModeStatus() {
204
+ try {
205
+ const { checkAutoModeStatus } = require('./auto-mode');
206
+ const status = await checkAutoModeStatus();
207
+ return status.active ? `${status.agent} (${status.chats} chats)` : 'Inactive';
208
+ } catch (error) {
209
+ return 'Unknown';
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Get current agent status
215
+ */
216
+ async function getCurrentAgentStatus() {
217
+ try {
218
+ const { getCurrentAIProvider } = require('./interactive/core-ui');
219
+ const provider = getCurrentAIProvider();
220
+ return provider ? `${provider.name} (${provider.type})` : 'None';
221
+ } catch (error) {
222
+ return 'Unknown';
223
+ }
224
+ }
225
+
226
+ module.exports = {
227
+ buildMainMenuItems,
228
+ buildStatusSection,
229
+ buildRequirementsSection,
230
+ buildSettingsSection,
231
+ buildSpecificationsSection,
232
+ buildAgentsSection,
233
+ getAutoModeStatus,
234
+ getCurrentAgentStatus
235
+ };
@@ -7,6 +7,9 @@
7
7
  const inquirer = require('inquirer');
8
8
  const chalk = require('chalk');
9
9
 
10
+ // Track expanded agent indices
11
+ const expandedAgents = new Set();
12
+
10
13
  /**
11
14
  * Load agents data via the RUI command resolver + provider preferences
12
15
  * @param {Object} navigation - TRUINavigation instance
@@ -46,19 +49,49 @@ function buildAgentChoices(data) {
46
49
  ];
47
50
  }
48
51
 
49
- return data.agents.map((agent, index) => {
52
+ const choices = [];
53
+
54
+ data.agents.forEach((agent, index) => {
50
55
  const isEnabled = data.enabledMap[agent.id] !== false;
51
56
  const icon = isEnabled ? '🟢' : '🔴';
52
57
  const label = agent.name || agent.type || agent.id || 'Unknown';
53
- return {
54
- name: ` ${icon} ${chalk.white(label)}`,
58
+ const isExpanded = expandedAgents.has(index);
59
+ const expandIcon = isExpanded ? '▼' : '▶';
60
+
61
+ choices.push({
62
+ name: ` ${icon} ${expandIcon} ${chalk.white(label)}`,
55
63
  value: `agent:${index}`,
56
- };
64
+ });
65
+
66
+ // If expanded, add full details inline
67
+ if (isExpanded) {
68
+ const details = [];
69
+ if (agent.description) {
70
+ details.push(chalk.gray(` Description: ${agent.description}`));
71
+ }
72
+ if (agent.id) {
73
+ details.push(chalk.gray(` ID: ${agent.id}`));
74
+ }
75
+ if (agent.type) {
76
+ details.push(chalk.gray(` Type: ${agent.type}`));
77
+ }
78
+ const status = isEnabled ? chalk.green('ENABLED') : chalk.red('DISABLED');
79
+ details.push(chalk.gray(` Status: ${status}`));
80
+
81
+ if (details.length > 0) {
82
+ details.forEach(detail => {
83
+ const Separator = require('inquirer').Separator;
84
+ choices.push(new Separator(detail));
85
+ });
86
+ }
87
+ }
57
88
  });
89
+
90
+ return choices;
58
91
  }
59
92
 
60
93
  /**
61
- * Handle selection of an agent item — shows an enable/disable sub-prompt
94
+ * Handle selection of an agent item — toggles inline expand/collapse
62
95
  * @param {number} index - Index into data.agents
63
96
  * @param {{agents: Array, enabledMap: Object, prefs: Object}} data
64
97
  * @param {Object} navigation - TRUINavigation instance
@@ -67,31 +100,64 @@ function buildAgentChoices(data) {
67
100
  async function handleAgentSelection(index, data, navigation) {
68
101
  if (!data || !data.agents || !data.agents[index]) return false;
69
102
 
103
+ const agent = data.agents[index];
104
+
105
+ // Check if currently expanded - if so, collapse and return
106
+ if (expandedAgents.has(index)) {
107
+ expandedAgents.delete(index);
108
+ return true; // Refresh to show collapsed state
109
+ }
110
+
111
+ // First press expands inline
112
+ expandedAgents.add(index);
113
+ return true; // Refresh to show expanded state
114
+ }
115
+
116
+ /**
117
+ * Handle action menu for an agent (enable/disable)
118
+ * @param {number} index - Index into data.agents
119
+ * @param {{agents: Array, enabledMap: Object, prefs: Object}} data
120
+ * @param {Object} navigation - TRUINavigation instance
121
+ * @param {string} directAction - Optional direct action: 'enable' or 'disable' (bypasses prompt)
122
+ * @returns {Promise<boolean>} true if prefs were changed
123
+ */
124
+ async function handleAgentAction(index, data, navigation, directAction = null) {
125
+ if (!data || !data.agents || !data.agents[index]) return false;
126
+
70
127
  const agent = data.agents[index];
71
128
  const isEnabled = data.enabledMap[agent.id] !== false;
72
129
  const label = agent.name || agent.type || agent.id || 'Unknown';
73
130
  const statusText = isEnabled ? chalk.green('ENABLED') : chalk.red('DISABLED');
74
131
 
75
- if (agent.description) {
76
- console.log(chalk.gray(`\n ${label}: ${agent.description}`));
132
+ // If direct action is provided, use it without prompting
133
+ let shouldToggle = false;
134
+ if (directAction) {
135
+ shouldToggle = (directAction === 'enable' && !isEnabled) || (directAction === 'disable' && isEnabled);
136
+ } else {
137
+ // Show prompt for interactive use
138
+ if (agent.description) {
139
+ console.log(chalk.gray(`\n ${label}: ${agent.description}`));
140
+ }
141
+
142
+ const { agentAction } = await inquirer.prompt([
143
+ {
144
+ type: 'list',
145
+ name: 'agentAction',
146
+ message: `${label} [${statusText}]`,
147
+ choices: [
148
+ {
149
+ name: isEnabled ? chalk.red('Disable') : chalk.green('Enable'),
150
+ value: 'toggle',
151
+ },
152
+ { name: chalk.gray('Cancel'), value: 'cancel' },
153
+ ],
154
+ },
155
+ ]);
156
+
157
+ shouldToggle = agentAction === 'toggle';
77
158
  }
78
159
 
79
- const { agentAction } = await inquirer.prompt([
80
- {
81
- type: 'list',
82
- name: 'agentAction',
83
- message: `${label} [${statusText}]`,
84
- choices: [
85
- {
86
- name: isEnabled ? chalk.red('Disable') : chalk.green('Enable'),
87
- value: 'toggle',
88
- },
89
- { name: chalk.gray('Cancel'), value: 'cancel' },
90
- ],
91
- },
92
- ]);
93
-
94
- if (agentAction !== 'toggle') return false;
160
+ if (!shouldToggle) return false;
95
161
 
96
162
  try {
97
163
  const { getProviderPreferences, saveProviderPreferences } = require('./provider-registry');
@@ -103,17 +169,104 @@ async function handleAgentSelection(index, data, navigation) {
103
169
  const verb = !isEnabled ? 'enable' : 'disable';
104
170
  console.log(chalk.green(`\n✓ ${label} ${verb}d`));
105
171
  console.log(chalk.gray(` Equivalent: app agents ${label} ${verb}`));
106
- await navigation.promptContinue();
172
+
173
+ if (!directAction) {
174
+ await navigation.promptContinue();
175
+ }
107
176
  return true;
108
177
  } catch (err) {
109
178
  console.log(chalk.red(`Error: ${err.message}`));
110
- await navigation.promptContinue();
179
+ if (!directAction) {
180
+ await navigation.promptContinue();
181
+ }
111
182
  return false;
112
183
  }
113
184
  }
114
185
 
186
+ /**
187
+ * Create extraKeys handler for arrow-key navigation between agent items
188
+ * Enables arrow-up/arrow-down to navigate between selectable agent items in the list
189
+ * @param {{agents: Array, enabledMap: Object, prefs: Object}} data
190
+ * @param {Array} choices - The full choice array (may include separators) from buildAgentChoices
191
+ * @returns {Function} Handler for showQuickMenu's extraKeys option
192
+ */
193
+ function createAgentNavigationHandler(data, choices) {
194
+ return (str, key, selectedIndex, context) => {
195
+ if (!key) return false;
196
+ if (key.name !== 'up' && key.name !== 'down') return false;
197
+
198
+ if (!data || !data.agents || !Array.isArray(data.agents)) return false;
199
+ if (!choices || !Array.isArray(choices)) return false;
200
+
201
+ // Get the current item's value to extract agent index if it's an agent item
202
+ const currentChoice = choices[selectedIndex];
203
+ const currentValue = currentChoice?.value;
204
+
205
+ // Only navigate if currently on an agent item (value format: "agent:N")
206
+ if (!currentValue || !currentValue.startsWith('agent:')) {
207
+ return false;
208
+ }
209
+
210
+ // Find the next selectable agent index (skipping separators)
211
+ let nextIndex = selectedIndex;
212
+ if (key.name === 'up') {
213
+ nextIndex = selectedIndex - 1;
214
+ while (nextIndex >= 0 && !isAgentItemSelectable(choices, nextIndex)) {
215
+ nextIndex--;
216
+ }
217
+ if (nextIndex < 0) {
218
+ // Wrap to bottom - find last selectable agent item
219
+ nextIndex = choices.length - 1;
220
+ while (nextIndex >= 0 && !isAgentItemSelectable(choices, nextIndex)) {
221
+ nextIndex--;
222
+ }
223
+ }
224
+ } else if (key.name === 'down') {
225
+ nextIndex = selectedIndex + 1;
226
+ while (nextIndex < choices.length && !isAgentItemSelectable(choices, nextIndex)) {
227
+ nextIndex++;
228
+ }
229
+ if (nextIndex >= choices.length) {
230
+ // Wrap to top - find first selectable agent item
231
+ nextIndex = 0;
232
+ while (nextIndex < choices.length && !isAgentItemSelectable(choices, nextIndex)) {
233
+ nextIndex++;
234
+ }
235
+ }
236
+ }
237
+
238
+ if (nextIndex >= 0 && nextIndex < choices.length && isAgentItemSelectable(choices, nextIndex)) {
239
+ context.setSelectedIndex(nextIndex);
240
+ context.display();
241
+ return true;
242
+ }
243
+
244
+ return false;
245
+ };
246
+ }
247
+
248
+ /**
249
+ * Check if a choice item is selectable (an agent item, not a separator or placeholder)
250
+ * @param {Array} choices - The full choice array from buildAgentChoices
251
+ * @param {number} itemIndex - Index in the choices array
252
+ * @returns {boolean}
253
+ */
254
+ function isAgentItemSelectable(choices, itemIndex) {
255
+ if (!choices || !Array.isArray(choices)) return false;
256
+ if (itemIndex < 0 || itemIndex >= choices.length) return false;
257
+
258
+ const choice = choices[itemIndex];
259
+ // Agent items have a value property that starts with "agent:"
260
+ // Separators are instances of inquirer.Separator
261
+ return choice && typeof choice.value === 'string' && choice.value.startsWith('agent:');
262
+ }
263
+
115
264
  module.exports = {
116
265
  loadAgentsData,
117
266
  buildAgentChoices,
118
267
  handleAgentSelection,
268
+ handleAgentAction,
269
+ createAgentNavigationHandler,
270
+ isAgentItemSelectable,
271
+ expandedAgents,
119
272
  };