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.
- package/bin/auth/auth-compliance.js +7 -1
- package/bin/commands/agent-commands.js +150 -228
- package/bin/commands/command-aliases.js +68 -0
- package/bin/vibecodingmachine.js +1 -2
- package/package.json +2 -2
- package/src/commands/agents/list.js +71 -115
- package/src/commands/agents-check.js +16 -4
- package/src/commands/analyze-file-sizes.js +1 -1
- package/src/commands/auto-direct/auto-provider-manager.js +290 -0
- package/src/commands/auto-direct/auto-status-display.js +331 -0
- package/src/commands/auto-direct/auto-utils.js +439 -0
- package/src/commands/auto-direct/file-operations.js +110 -0
- package/src/commands/auto-direct/provider-config.js +1 -1
- package/src/commands/auto-direct/provider-manager.js +1 -1
- package/src/commands/auto-direct/status-display.js +1 -1
- package/src/commands/auto-direct/utils.js +24 -18
- package/src/commands/auto-direct-refactored.js +413 -0
- package/src/commands/auto-direct.js +594 -188
- package/src/commands/requirements/commands.js +353 -0
- package/src/commands/requirements/default-handlers.js +272 -0
- package/src/commands/requirements/disable.js +97 -0
- package/src/commands/requirements/enable.js +97 -0
- package/src/commands/requirements/utils.js +194 -0
- package/src/commands/requirements-refactored.js +60 -0
- package/src/commands/requirements.js +38 -771
- package/src/commands/specs/disable.js +96 -0
- package/src/commands/specs/enable.js +96 -0
- package/src/trui/TruiInterface.js +5 -11
- package/src/trui/agents/AgentInterface.js +24 -396
- package/src/trui/agents/handlers/CommandHandler.js +93 -0
- package/src/trui/agents/handlers/ContextManager.js +117 -0
- package/src/trui/agents/handlers/DisplayHandler.js +243 -0
- package/src/trui/agents/handlers/HelpHandler.js +51 -0
- package/src/utils/auth.js +13 -111
- package/src/utils/config.js +4 -0
- package/src/utils/interactive/requirements-navigation.js +17 -15
- package/src/utils/interactive-broken.js +2 -2
- package/src/utils/provider-checker/agent-runner.js +15 -1
- package/src/utils/provider-checker/cli-installer.js +149 -7
- package/src/utils/provider-checker/opencode-checker.js +588 -0
- package/src/utils/provider-checker/provider-validator.js +88 -3
- package/src/utils/provider-checker/time-formatter.js +3 -2
- package/src/utils/provider-manager.js +28 -20
- package/src/utils/provider-registry.js +35 -3
- package/src/utils/requirements-navigator/index.js +94 -0
- package/src/utils/requirements-navigator/input-handler.js +217 -0
- package/src/utils/requirements-navigator/section-loader.js +188 -0
- package/src/utils/requirements-navigator/tree-builder.js +105 -0
- package/src/utils/requirements-navigator/tree-renderer.js +50 -0
- package/src/utils/requirements-navigator.js +2 -583
- package/src/utils/trui-clarifications.js +188 -0
- package/src/utils/trui-feedback.js +54 -1
- package/src/utils/trui-kiro-integration.js +398 -0
- package/src/utils/trui-main-handlers.js +194 -0
- package/src/utils/trui-main-menu.js +235 -0
- package/src/utils/trui-nav-agents.js +178 -25
- package/src/utils/trui-nav-requirements.js +203 -27
- package/src/utils/trui-nav-settings.js +114 -1
- package/src/utils/trui-nav-specifications.js +44 -3
- package/src/utils/trui-navigation-backup.js +603 -0
- package/src/utils/trui-navigation.js +70 -228
- package/src/utils/trui-provider-health.js +274 -0
- package/src/utils/trui-provider-manager.js +376 -0
- package/src/utils/trui-quick-menu.js +25 -1
- package/src/utils/trui-req-actions-backup.js +507 -0
- package/src/utils/trui-req-actions.js +148 -216
- package/src/utils/trui-req-editor.js +170 -0
- package/src/utils/trui-req-file-ops.js +278 -0
- package/src/utils/trui-req-tree-old.js +719 -0
- package/src/utils/trui-req-tree.js +348 -627
- package/src/utils/trui-specifications.js +25 -7
- package/src/utils/trui-windsurf.js +231 -10
- package/src/utils/welcome-screen-extracted.js +2 -2
- 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
|
-
|
|
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
|
-
|
|
54
|
-
|
|
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 —
|
|
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
|
-
|
|
76
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
};
|