vibecodingmachine-cli 2026.1.29-713 → 2026.2.20-423

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 (45) hide show
  1. package/bin/vibecodingmachine.js +124 -0
  2. package/package.json +3 -2
  3. package/src/commands/agents-check.js +69 -0
  4. package/src/commands/auto-direct.js +930 -145
  5. package/src/commands/auto.js +26 -4
  6. package/src/commands/ide.js +2 -1
  7. package/src/commands/requirements.js +23 -27
  8. package/src/utils/auto-mode.js +4 -1
  9. package/src/utils/cline-js-handler.js +218 -0
  10. package/src/utils/config.js +22 -0
  11. package/src/utils/display-formatters-complete.js +229 -0
  12. package/src/utils/display-formatters-extracted.js +219 -0
  13. package/src/utils/display-formatters.js +157 -0
  14. package/src/utils/feedback-handler.js +143 -0
  15. package/src/utils/ide-detection-complete.js +126 -0
  16. package/src/utils/ide-detection-extracted.js +116 -0
  17. package/src/utils/ide-detection.js +124 -0
  18. package/src/utils/interactive-backup.js +5664 -0
  19. package/src/utils/interactive-broken.js +280 -0
  20. package/src/utils/interactive.js +31 -5534
  21. package/src/utils/provider-checker.js +410 -0
  22. package/src/utils/provider-manager.js +251 -0
  23. package/src/utils/provider-registry.js +18 -9
  24. package/src/utils/requirement-actions.js +884 -0
  25. package/src/utils/requirements-navigator.js +585 -0
  26. package/src/utils/rui-trui-adapter.js +311 -0
  27. package/src/utils/simple-trui.js +204 -0
  28. package/src/utils/status-helpers-extracted.js +125 -0
  29. package/src/utils/status-helpers.js +107 -0
  30. package/src/utils/trui-debug.js +261 -0
  31. package/src/utils/trui-feedback.js +133 -0
  32. package/src/utils/trui-nav-agents.js +119 -0
  33. package/src/utils/trui-nav-requirements.js +268 -0
  34. package/src/utils/trui-nav-settings.js +157 -0
  35. package/src/utils/trui-nav-specifications.js +139 -0
  36. package/src/utils/trui-navigation.js +303 -0
  37. package/src/utils/trui-provider-manager.js +182 -0
  38. package/src/utils/trui-quick-menu.js +365 -0
  39. package/src/utils/trui-req-actions.js +372 -0
  40. package/src/utils/trui-req-tree.js +534 -0
  41. package/src/utils/trui-specifications.js +359 -0
  42. package/src/utils/trui-text-editor.js +350 -0
  43. package/src/utils/trui-windsurf.js +336 -0
  44. package/src/utils/welcome-screen-extracted.js +135 -0
  45. package/src/utils/welcome-screen.js +134 -0
@@ -0,0 +1,107 @@
1
+ const fs = require('fs-extra');
2
+ const { getRepoPath, getRequirementsPath } = require('./config');
3
+
4
+ /**
5
+ * Count project requirements statistics
6
+ * @returns {object|null} - Requirements stats or null if error
7
+ */
8
+ async function countRequirements() {
9
+ try {
10
+ const { getProjectRequirementStats } = require('vibecodingmachine-core');
11
+ const repoPath = await getRepoPath() || process.cwd();
12
+ return await getProjectRequirementStats(repoPath);
13
+ } catch (error) {
14
+ return null;
15
+ }
16
+ }
17
+
18
+ /**
19
+ * Get sync status for display
20
+ * @returns {string} - Formatted sync status
21
+ */
22
+ async function getSyncStatus() {
23
+ try {
24
+ const SyncEngine = require('vibecodingmachine-core/src/sync/sync-engine');
25
+ const syncEngine = new SyncEngine();
26
+ await syncEngine.initialize();
27
+ const status = syncEngine.getStatus();
28
+ syncEngine.stop();
29
+
30
+ if (!status.isOnline && status.queuedChanges > 0) {
31
+ return `[Offline: ${status.queuedChanges} queued]`;
32
+ } else if (!status.isOnline) {
33
+ return '[Offline]';
34
+ } else if (status.isSyncing) {
35
+ return '[Syncing...]';
36
+ } else if (status.lastSyncTime) {
37
+ const timeSinceSync = Date.now() - status.lastSyncTime;
38
+ const minutesAgo = Math.floor(timeSinceSync / (1000 * 60));
39
+ if (minutesAgo < 1) {
40
+ return '[Sync: ✓ just now]';
41
+ } else if (minutesAgo < 60) {
42
+ return `[Sync: ✓ ${minutesAgo}m ago]`;
43
+ } else {
44
+ const hoursAgo = Math.floor(minutesAgo / 60);
45
+ return `[Sync: ✓ ${hoursAgo}h ago]`;
46
+ }
47
+ } else {
48
+ return '[Never synced]';
49
+ }
50
+ } catch (error) {
51
+ return '[Sync unavailable]';
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Get current progress from requirements file
57
+ * @returns {object|null} - Current progress info or null if not found
58
+ */
59
+ async function getCurrentProgress() {
60
+ try {
61
+ const reqPath = await getRequirementsPath();
62
+
63
+ if (!reqPath || !await fs.pathExists(reqPath)) {
64
+ return null;
65
+ }
66
+
67
+ const content = await fs.readFile(reqPath, 'utf8');
68
+ const lines = content.split('\n');
69
+
70
+ let requirement = null;
71
+ let inTodoSection = false;
72
+
73
+ for (let i = 0; i < lines.length; i++) {
74
+ const line = lines[i];
75
+
76
+ // Find TODO section
77
+ if (line.includes('## ⏳ Requirements not yet completed') || line.includes('## Requirements not yet completed')) {
78
+ inTodoSection = true;
79
+ continue;
80
+ }
81
+
82
+ // Exit TODO section when we hit another section
83
+ if (inTodoSection && line.trim().startsWith('##')) {
84
+ break;
85
+ }
86
+
87
+ // Find first TODO requirement
88
+ if (inTodoSection) {
89
+ const trimmed = line.trim();
90
+ if (trimmed.startsWith('- ') || trimmed.startsWith('* ')) {
91
+ requirement = trimmed.substring(2); // Remove "- " or "* " prefix
92
+ break;
93
+ }
94
+ }
95
+ }
96
+
97
+ return requirement ? { status: 'PREPARE', requirement } : null;
98
+ } catch (error) {
99
+ return null;
100
+ }
101
+ }
102
+
103
+ module.exports = {
104
+ countRequirements,
105
+ getSyncStatus,
106
+ getCurrentProgress
107
+ };
@@ -0,0 +1,261 @@
1
+ /**
2
+ * TRUI Debug and State Tracking System
3
+ *
4
+ * Provides comprehensive debugging, state tracking, and performance monitoring
5
+ * for all TRUI menu operations. Used throughout the TRUI system.
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const chalk = require('chalk');
10
+
11
+ /**
12
+ * Debug logging utility with file and console output
13
+ */
14
+ class DebugLogger {
15
+ constructor() {
16
+ this.enabled = process.env.VCM_DEBUG_MENU === '1';
17
+ this.logFile = '/tmp/vcm-menu-debug.log';
18
+ }
19
+
20
+ log(message, data = null, level = 'INFO') {
21
+ if (!this.enabled) return;
22
+
23
+ const timestamp = new Date().toISOString();
24
+ const caller = this.getCaller();
25
+ const dataStr = data ? ' ' + JSON.stringify(data) : '';
26
+ const logEntry = `[${level}-MENU ${timestamp}] [${caller}] ${message}${dataStr}\n`;
27
+
28
+ // Console output with colors
29
+ const colorFn = level === 'ERROR' ? chalk.red :
30
+ level === 'WARN' ? chalk.yellow :
31
+ level === 'PERF' ? chalk.magenta : chalk.gray;
32
+ console.log(colorFn(logEntry));
33
+
34
+ // File output (no colors)
35
+ try {
36
+ fs.appendFileSync(this.logFile, logEntry.replace(/\x1b\[[0-9;]*m/g, ''));
37
+ } catch (e) {
38
+ // Ignore file write errors
39
+ }
40
+ }
41
+
42
+ getCaller() {
43
+ const stack = new Error().stack.split('\n');
44
+ // Find first TRUI-related caller
45
+ for (let i = 3; i < stack.length; i++) {
46
+ const line = stack[i];
47
+ if (line.includes('trui-') || line.includes('showQuickMenu')) {
48
+ const match = line.match(/at.*\(.*\/(.*?):(\d+):/);
49
+ return match ? `${match[1]}:${match[2]}` : 'unknown';
50
+ }
51
+ }
52
+ return 'unknown';
53
+ }
54
+
55
+ error(message, data) { this.log(message, data, 'ERROR'); }
56
+ warn(message, data) { this.log(message, data, 'WARN'); }
57
+ perf(message, data) { this.log(message, data, 'PERF'); }
58
+ info(message, data) { this.log(message, data, 'INFO'); }
59
+ }
60
+
61
+ /**
62
+ * Performance monitoring for menu operations
63
+ */
64
+ class PerformanceMonitor {
65
+ constructor() {
66
+ this.operations = new Map();
67
+ this.stack = [];
68
+ }
69
+
70
+ start(operation, context = {}) {
71
+ const startTime = process.hrtime.bigint();
72
+ this.stack.push({ operation, startTime, context });
73
+ debugLogger.perf(`Starting ${operation}`, context);
74
+ }
75
+
76
+ end(operation, result = null) {
77
+ const endTime = process.hrtime.bigint();
78
+ const lastOp = this.stack.pop();
79
+
80
+ if (!lastOp || lastOp.operation !== operation) {
81
+ debugLogger.warn(`Performance mismatch: expected ${operation}, got ${lastOp ? lastOp.operation : 'none'}`);
82
+ return 0;
83
+ }
84
+
85
+ const duration = Number(endTime - lastOp.startTime) / 1000000; // Convert to milliseconds
86
+ this.operations.set(operation, {
87
+ duration,
88
+ timestamp: Date.now(),
89
+ context: lastOp.context,
90
+ result
91
+ });
92
+
93
+ debugLogger.perf(`Completed ${operation}`, {
94
+ duration: `${duration.toFixed(2)}ms`,
95
+ context: lastOp.context
96
+ });
97
+
98
+ return duration;
99
+ }
100
+
101
+ getMetrics() {
102
+ const metrics = {};
103
+ for (const [op, data] of this.operations) {
104
+ metrics[op] = {
105
+ duration: data.duration,
106
+ timestamp: data.timestamp,
107
+ context: data.context
108
+ };
109
+ }
110
+ return metrics;
111
+ }
112
+
113
+ getAverage(operation) {
114
+ const ops = Array.from(this.operations.entries())
115
+ .filter(([op]) => op === operation)
116
+ .map(([, data]) => data.duration);
117
+
118
+ if (ops.length === 0) return 0;
119
+ return ops.reduce((sum, dur) => sum + dur, 0) / ops.length;
120
+ }
121
+
122
+ reset() {
123
+ this.operations.clear();
124
+ this.stack = [];
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Menu state tracking for debugging and recovery
130
+ */
131
+ class MenuStateTracker {
132
+ constructor() {
133
+ this.states = [];
134
+ this.currentState = null;
135
+ }
136
+
137
+ push(state) {
138
+ this.currentState = {
139
+ ...state,
140
+ timestamp: Date.now(),
141
+ id: this.states.length
142
+ };
143
+ this.states.push(this.currentState);
144
+ debugLogger.info('Menu state pushed', this.currentState);
145
+ }
146
+
147
+ pop() {
148
+ if (this.states.length > 0) {
149
+ const state = this.states.pop();
150
+ debugLogger.info('Menu state popped', state);
151
+ this.currentState = this.states.length > 0 ? this.states[this.states.length - 1] : null;
152
+ return state;
153
+ }
154
+ return null;
155
+ }
156
+
157
+ update(updates) {
158
+ if (this.currentState) {
159
+ Object.assign(this.currentState, updates);
160
+ debugLogger.info('Menu state updated', { updates, currentState: this.currentState });
161
+ }
162
+ }
163
+
164
+ getCurrent() {
165
+ return this.currentState;
166
+ }
167
+
168
+ getHistory() {
169
+ return this.states.slice();
170
+ }
171
+
172
+ reset() {
173
+ this.states = [];
174
+ this.currentState = null;
175
+ debugLogger.info('Menu state tracker reset');
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Error handling and recovery system
181
+ */
182
+ class ErrorHandler {
183
+ constructor() {
184
+ this.errors = [];
185
+ this.recoveryStrategies = new Map();
186
+ }
187
+
188
+ registerStrategy(errorType, strategy) {
189
+ this.recoveryStrategies.set(errorType, strategy);
190
+ debugLogger.info(`Recovery strategy registered for ${errorType}`);
191
+ }
192
+
193
+ handle(error, context = {}) {
194
+ const errorInfo = {
195
+ message: error.message,
196
+ stack: error.stack,
197
+ timestamp: Date.now(),
198
+ context
199
+ };
200
+
201
+ this.errors.push(errorInfo);
202
+ debugLogger.error('Error handled', errorInfo);
203
+
204
+ // Try recovery strategy
205
+ const strategy = this.recoveryStrategies.get(error.name);
206
+ if (strategy) {
207
+ debugLogger.info(`Attempting recovery for ${error.name}`);
208
+ try {
209
+ return strategy(error, context);
210
+ } catch (recoveryError) {
211
+ debugLogger.error('Recovery strategy failed', {
212
+ originalError: error.message,
213
+ recoveryError: recoveryError.message
214
+ });
215
+ }
216
+ }
217
+
218
+ // Default recovery: rethrow with context
219
+ error.context = context;
220
+ throw error;
221
+ }
222
+
223
+ getErrors() {
224
+ return this.errors.slice();
225
+ }
226
+
227
+ clearErrors() {
228
+ this.errors = [];
229
+ debugLogger.info('Error history cleared');
230
+ }
231
+ }
232
+
233
+ // Global instances
234
+ const debugLogger = new DebugLogger();
235
+ const perfMonitor = new PerformanceMonitor();
236
+ const stateTracker = new MenuStateTracker();
237
+ const errorHandler = new ErrorHandler();
238
+
239
+ // Register default recovery strategies
240
+ errorHandler.registerStrategy('TypeError', (error, context) => {
241
+ debugLogger.warn('TypeError recovery: checking for undefined/null values');
242
+ // Add recovery logic here
243
+ return null;
244
+ });
245
+
246
+ errorHandler.registerStrategy('RangeError', (error, context) => {
247
+ debugLogger.warn('RangeError recovery: checking array bounds');
248
+ // Add recovery logic here
249
+ return null;
250
+ });
251
+
252
+ module.exports = {
253
+ debugLogger,
254
+ perfMonitor,
255
+ stateTracker,
256
+ errorHandler,
257
+ DebugLogger,
258
+ PerformanceMonitor,
259
+ MenuStateTracker,
260
+ ErrorHandler
261
+ };
@@ -0,0 +1,133 @@
1
+ /**
2
+ * TRUI Feedback Submission System
3
+ *
4
+ * Handles F key feedback submission with category selection and multi-line text.
5
+ */
6
+
7
+ const chalk = require('chalk');
8
+ const inquirer = require('inquirer');
9
+ const { debugLogger } = require('./trui-debug');
10
+
11
+ /**
12
+ * Show feedback submission interface
13
+ */
14
+ async function showFeedbackSubmission() {
15
+ debugLogger.info('Opening feedback submission');
16
+
17
+ console.clear();
18
+ console.log(chalk.cyan('\n💬 Feedback Submission\n'));
19
+ console.log(chalk.gray('Help us improve VCM by sharing your feedback.\n'));
20
+
21
+ try {
22
+ // Category selection
23
+ const { category } = await inquirer.prompt([
24
+ {
25
+ type: 'list',
26
+ name: 'category',
27
+ message: 'What type of feedback would you like to share?',
28
+ choices: [
29
+ { name: '🐛 Bug Report', value: 'bug' },
30
+ { name: '💡 Feature Request', value: 'feature' },
31
+ { name: '📝 Documentation Issue', value: 'documentation' },
32
+ { name: '🎨 UI/UX Feedback', value: 'ui-ux' },
33
+ { name: '⚡ Performance Issue', value: 'performance' },
34
+ { name: '💭 General Feedback', value: 'general' }
35
+ ]
36
+ }
37
+ ]);
38
+
39
+ // Multi-line feedback text
40
+ const { feedback } = await inquirer.prompt([
41
+ {
42
+ type: 'editor',
43
+ name: 'feedback',
44
+ message: 'Please describe your feedback in detail:',
45
+ default: ''
46
+ }
47
+ ]);
48
+
49
+ if (!feedback || feedback.trim().length === 0) {
50
+ console.log(chalk.yellow('\n⚠ No feedback provided. Cancelled.'));
51
+ return;
52
+ }
53
+
54
+ // Email (optional)
55
+ const { email } = await inquirer.prompt([
56
+ {
57
+ type: 'input',
58
+ name: 'email',
59
+ message: 'Email (optional, for follow-up questions):',
60
+ validate: (input) => {
61
+ if (!input) return true;
62
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
63
+ return emailRegex.test(input) || 'Please enter a valid email address';
64
+ }
65
+ }
66
+ ]);
67
+
68
+ // Confirmation
69
+ const { confirmed } = await inquirer.prompt([
70
+ {
71
+ type: 'confirm',
72
+ name: 'confirmed',
73
+ message: 'Submit this feedback?',
74
+ default: true
75
+ }
76
+ ]);
77
+
78
+ if (!confirmed) {
79
+ console.log(chalk.yellow('\n⚠ Feedback submission cancelled.'));
80
+ return;
81
+ }
82
+
83
+ // Submit feedback
84
+ await submitFeedback({ category, feedback, email });
85
+
86
+ console.log(chalk.green('\n✓ Thank you! Your feedback has been submitted.\n'));
87
+
88
+ } catch (error) {
89
+ debugLogger.error('Feedback submission error', { error: error.message });
90
+ console.log(chalk.red('\n❌ Error submitting feedback: ' + error.message));
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Submit feedback to backend
96
+ */
97
+ async function submitFeedback(feedbackData) {
98
+ debugLogger.info('Submitting feedback', { category: feedbackData.category });
99
+
100
+ try {
101
+ // Save feedback to local file for now
102
+ const fs = require('fs');
103
+ const path = require('path');
104
+ const feedbackDir = path.join(process.cwd(), '.vcm-feedback');
105
+
106
+ if (!fs.existsSync(feedbackDir)) {
107
+ fs.mkdirSync(feedbackDir, { recursive: true });
108
+ }
109
+
110
+ const feedbackFile = path.join(feedbackDir, `feedback-${Date.now()}.json`);
111
+ const feedbackWithMeta = {
112
+ ...feedbackData,
113
+ timestamp: new Date().toISOString(),
114
+ version: require('../../../package.json').version || 'unknown'
115
+ };
116
+
117
+ fs.writeFileSync(feedbackFile, JSON.stringify(feedbackWithMeta, null, 2));
118
+ debugLogger.info('Feedback saved locally', { file: feedbackFile });
119
+
120
+ // TODO: Send to backend API when available
121
+ // const response = await fetch('/api/feedback', {
122
+ // method: 'POST',
123
+ // headers: { 'Content-Type': 'application/json' },
124
+ // body: JSON.stringify(feedbackWithMeta)
125
+ // });
126
+
127
+ } catch (error) {
128
+ debugLogger.error('Failed to submit feedback', { error: error.message });
129
+ throw error;
130
+ }
131
+ }
132
+
133
+ module.exports = { showFeedbackSubmission, submitFeedback };
@@ -0,0 +1,119 @@
1
+ /**
2
+ * TRUI Agents Section
3
+ * Exposes loadAgentsData / buildAgentChoices / handleAgentSelection
4
+ * for inline accordion display in the main navigation menu.
5
+ */
6
+
7
+ const inquirer = require('inquirer');
8
+ const chalk = require('chalk');
9
+
10
+ /**
11
+ * Load agents data via the RUI command resolver + provider preferences
12
+ * @param {Object} navigation - TRUINavigation instance
13
+ * @returns {Promise<{agents: Array, enabledMap: Object, prefs: Object}|null>}
14
+ */
15
+ async function loadAgentsData(navigation) {
16
+ try {
17
+ const result = navigation.resolver.resolve('list agents');
18
+ if (!result.success) return null;
19
+
20
+ const commandResult = await result.command.execute();
21
+ if (!commandResult.success || !commandResult.data) return null;
22
+
23
+ const { getProviderPreferences } = require('./provider-registry');
24
+ const prefs = await getProviderPreferences();
25
+ const enabledMap = { ...(prefs.enabled || {}) };
26
+
27
+ return {
28
+ agents: commandResult.data.agents || [],
29
+ enabledMap,
30
+ prefs,
31
+ };
32
+ } catch (err) {
33
+ return null;
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Build inline accordion choice objects for the agents section
39
+ * @param {{agents: Array, enabledMap: Object}} data
40
+ * @returns {Array} inquirer choice objects
41
+ */
42
+ function buildAgentChoices(data) {
43
+ if (!data || !data.agents || !data.agents.length) {
44
+ return [
45
+ { name: chalk.gray(' (no agents found)'), value: 'noop' },
46
+ ];
47
+ }
48
+
49
+ return data.agents.map((agent, index) => {
50
+ const isEnabled = data.enabledMap[agent.id] !== false;
51
+ const icon = isEnabled ? '🟢' : '🔴';
52
+ const label = agent.name || agent.type || agent.id || 'Unknown';
53
+ return {
54
+ name: ` ${icon} ${chalk.white(label)}`,
55
+ value: `agent:${index}`,
56
+ };
57
+ });
58
+ }
59
+
60
+ /**
61
+ * Handle selection of an agent item — shows an enable/disable sub-prompt
62
+ * @param {number} index - Index into data.agents
63
+ * @param {{agents: Array, enabledMap: Object, prefs: Object}} data
64
+ * @param {Object} navigation - TRUINavigation instance
65
+ * @returns {Promise<boolean>} true if prefs were changed (caller should reload)
66
+ */
67
+ async function handleAgentSelection(index, data, navigation) {
68
+ if (!data || !data.agents || !data.agents[index]) return false;
69
+
70
+ const agent = data.agents[index];
71
+ const isEnabled = data.enabledMap[agent.id] !== false;
72
+ const label = agent.name || agent.type || agent.id || 'Unknown';
73
+ const statusText = isEnabled ? chalk.green('ENABLED') : chalk.red('DISABLED');
74
+
75
+ if (agent.description) {
76
+ console.log(chalk.gray(`\n ${label}: ${agent.description}`));
77
+ }
78
+
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;
95
+
96
+ try {
97
+ const { getProviderPreferences, saveProviderPreferences } = require('./provider-registry');
98
+ const prefs = await getProviderPreferences();
99
+ prefs.enabled = prefs.enabled || {};
100
+ prefs.enabled[agent.id] = !isEnabled;
101
+ await saveProviderPreferences(prefs);
102
+
103
+ const verb = !isEnabled ? 'enable' : 'disable';
104
+ console.log(chalk.green(`\n✓ ${label} ${verb}d`));
105
+ console.log(chalk.gray(` Equivalent: app agents ${label} ${verb}`));
106
+ await navigation.promptContinue();
107
+ return true;
108
+ } catch (err) {
109
+ console.log(chalk.red(`Error: ${err.message}`));
110
+ await navigation.promptContinue();
111
+ return false;
112
+ }
113
+ }
114
+
115
+ module.exports = {
116
+ loadAgentsData,
117
+ buildAgentChoices,
118
+ handleAgentSelection,
119
+ };