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.
- package/bin/vibecodingmachine.js +124 -0
- package/package.json +3 -2
- package/src/commands/agents-check.js +69 -0
- package/src/commands/auto-direct.js +930 -145
- package/src/commands/auto.js +26 -4
- package/src/commands/ide.js +2 -1
- package/src/commands/requirements.js +23 -27
- package/src/utils/auto-mode.js +4 -1
- package/src/utils/cline-js-handler.js +218 -0
- package/src/utils/config.js +22 -0
- package/src/utils/display-formatters-complete.js +229 -0
- package/src/utils/display-formatters-extracted.js +219 -0
- package/src/utils/display-formatters.js +157 -0
- package/src/utils/feedback-handler.js +143 -0
- package/src/utils/ide-detection-complete.js +126 -0
- package/src/utils/ide-detection-extracted.js +116 -0
- package/src/utils/ide-detection.js +124 -0
- package/src/utils/interactive-backup.js +5664 -0
- package/src/utils/interactive-broken.js +280 -0
- package/src/utils/interactive.js +31 -5534
- package/src/utils/provider-checker.js +410 -0
- package/src/utils/provider-manager.js +251 -0
- package/src/utils/provider-registry.js +18 -9
- package/src/utils/requirement-actions.js +884 -0
- package/src/utils/requirements-navigator.js +585 -0
- package/src/utils/rui-trui-adapter.js +311 -0
- package/src/utils/simple-trui.js +204 -0
- package/src/utils/status-helpers-extracted.js +125 -0
- package/src/utils/status-helpers.js +107 -0
- package/src/utils/trui-debug.js +261 -0
- package/src/utils/trui-feedback.js +133 -0
- package/src/utils/trui-nav-agents.js +119 -0
- package/src/utils/trui-nav-requirements.js +268 -0
- package/src/utils/trui-nav-settings.js +157 -0
- package/src/utils/trui-nav-specifications.js +139 -0
- package/src/utils/trui-navigation.js +303 -0
- package/src/utils/trui-provider-manager.js +182 -0
- package/src/utils/trui-quick-menu.js +365 -0
- package/src/utils/trui-req-actions.js +372 -0
- package/src/utils/trui-req-tree.js +534 -0
- package/src/utils/trui-specifications.js +359 -0
- package/src/utils/trui-text-editor.js +350 -0
- package/src/utils/trui-windsurf.js +336 -0
- package/src/utils/welcome-screen-extracted.js +135 -0
- package/src/utils/welcome-screen.js +134 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windsurf/Cascade Detection and Integration
|
|
3
|
+
*
|
|
4
|
+
* Detects when Windsurf (Cascade) is done typing and automatically
|
|
5
|
+
* sends "continue with your best approach" messages to keep work flowing.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { execSync } = require('child_process');
|
|
11
|
+
const { debugLogger, perfMonitor } = require('./trui-debug');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Windsurf/Cascade state detector
|
|
15
|
+
*/
|
|
16
|
+
class WindsurfDetector {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.isWindsurfActive = false;
|
|
19
|
+
this.lastActivity = null;
|
|
20
|
+
this.pollInterval = null;
|
|
21
|
+
this.continueThreshold = 30000; // 30 seconds of inactivity
|
|
22
|
+
this.projectRoot = this.findProjectRoot();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Find the project root directory
|
|
27
|
+
*/
|
|
28
|
+
findProjectRoot() {
|
|
29
|
+
let currentDir = process.cwd();
|
|
30
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
31
|
+
const markerFile = path.join(currentDir, '.windsurf-workspace');
|
|
32
|
+
if (fs.existsSync(markerFile) ||
|
|
33
|
+
fs.existsSync(path.join(currentDir, '.git')) ||
|
|
34
|
+
fs.existsSync(path.join(currentDir, 'package.json'))) {
|
|
35
|
+
return currentDir;
|
|
36
|
+
}
|
|
37
|
+
currentDir = path.dirname(currentDir);
|
|
38
|
+
}
|
|
39
|
+
return process.cwd();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Check if Windsurf/Cascade is running
|
|
44
|
+
*/
|
|
45
|
+
isWindsurfRunning() {
|
|
46
|
+
try {
|
|
47
|
+
// Check for Windsurf processes
|
|
48
|
+
const result = execSync('ps aux | grep -i windsurf | grep -v grep', {
|
|
49
|
+
encoding: 'utf8',
|
|
50
|
+
timeout: 5000
|
|
51
|
+
});
|
|
52
|
+
return result.trim().length > 0;
|
|
53
|
+
} catch (error) {
|
|
54
|
+
debugLogger.warn('Windsurf process check failed', { error: error.message });
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Check if Cascade/Windsurf is actively typing/working
|
|
61
|
+
*/
|
|
62
|
+
checkWindsurfActivity() {
|
|
63
|
+
try {
|
|
64
|
+
// Check for recent file modifications in key directories
|
|
65
|
+
const checkDirs = ['src', 'components', 'pages', 'lib', 'app'];
|
|
66
|
+
let recentActivity = false;
|
|
67
|
+
|
|
68
|
+
for (const dir of checkDirs) {
|
|
69
|
+
const fullPath = path.join(this.projectRoot, dir);
|
|
70
|
+
if (fs.existsSync(fullPath)) {
|
|
71
|
+
const stats = fs.statSync(fullPath);
|
|
72
|
+
const now = Date.now();
|
|
73
|
+
const modifiedTime = stats.mtime.getTime();
|
|
74
|
+
|
|
75
|
+
// If modified in last 30 seconds, consider active
|
|
76
|
+
if (now - modifiedTime < 30000) {
|
|
77
|
+
recentActivity = true;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Also check for specific Windsurf activity files
|
|
84
|
+
const activityFile = path.join(this.projectRoot, '.windsurf-activity');
|
|
85
|
+
if (fs.existsSync(activityFile)) {
|
|
86
|
+
const activityTime = fs.statSync(activityFile).mtime.getTime();
|
|
87
|
+
if (Date.now() - activityTime < 30000) {
|
|
88
|
+
recentActivity = true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return recentActivity;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
debugLogger.warn('Windsurf activity check failed', { error: error.message });
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Detect when Windsurf completes work (stops typing)
|
|
101
|
+
*/
|
|
102
|
+
detectWorkCompletion() {
|
|
103
|
+
const wasActive = this.isWindsurfActive;
|
|
104
|
+
const isActive = this.checkWindsurfActivity();
|
|
105
|
+
|
|
106
|
+
debugLogger.info('Windsurf activity check', { wasActive, isActive });
|
|
107
|
+
|
|
108
|
+
// Transition from active to inactive = work completed
|
|
109
|
+
if (wasActive && !isActive) {
|
|
110
|
+
this.lastActivity = Date.now();
|
|
111
|
+
debugLogger.info('Windsurf work completed detected');
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this.isWindsurfActive = isActive;
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Send "continue with best approach" message
|
|
121
|
+
*/
|
|
122
|
+
async sendContinueMessage() {
|
|
123
|
+
try {
|
|
124
|
+
debugLogger.info('Sending continue message to Windsurf');
|
|
125
|
+
|
|
126
|
+
// Use AppleScript manager to actually send text to Windsurf
|
|
127
|
+
const { AppleScriptManager } = require('vibecodingmachine-core');
|
|
128
|
+
const applescriptManager = new AppleScriptManager();
|
|
129
|
+
|
|
130
|
+
debugLogger.info('Using AppleScript manager to send to Windsurf');
|
|
131
|
+
const result = await applescriptManager.sendText('continue with your best approach', 'windsurf');
|
|
132
|
+
|
|
133
|
+
debugLogger.info('AppleScript result', { success: result.success, error: result.error, method: result.method });
|
|
134
|
+
|
|
135
|
+
if (result.success) {
|
|
136
|
+
debugLogger.info('Continue message sent successfully to Windsurf');
|
|
137
|
+
return true;
|
|
138
|
+
} else {
|
|
139
|
+
debugLogger.error('Failed to send continue message to Windsurf', { error: result.error, details: result });
|
|
140
|
+
|
|
141
|
+
// Fallback: create file and notification for manual intervention
|
|
142
|
+
try {
|
|
143
|
+
const continueFile = path.join(this.projectRoot, '.windsurf-continue');
|
|
144
|
+
const message = {
|
|
145
|
+
type: 'continue',
|
|
146
|
+
message: 'continue with your best approach',
|
|
147
|
+
timestamp: Date.now(),
|
|
148
|
+
source: 'vcm-trui',
|
|
149
|
+
fallback_reason: result.error || 'Unknown error',
|
|
150
|
+
applescript_result: result
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
fs.writeFileSync(continueFile, JSON.stringify(message, null, 2));
|
|
154
|
+
debugLogger.info('Fallback: Created continue file for manual intervention');
|
|
155
|
+
} catch (fallbackError) {
|
|
156
|
+
debugLogger.error('Fallback also failed', { error: fallbackError.message });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
} catch (error) {
|
|
162
|
+
debugLogger.error('Failed to send continue message', { error: error.message, stack: error.stack });
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Start monitoring Windsurf activity
|
|
169
|
+
*/
|
|
170
|
+
startMonitoring() {
|
|
171
|
+
if (this.pollInterval) {
|
|
172
|
+
this.stopMonitoring();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
debugLogger.info('Starting Windsurf activity monitoring');
|
|
176
|
+
this.isWindsurfActive = this.checkWindsurfActivity();
|
|
177
|
+
|
|
178
|
+
this.pollInterval = setInterval(() => {
|
|
179
|
+
if (this.detectWorkCompletion()) {
|
|
180
|
+
this.sendContinueMessage();
|
|
181
|
+
}
|
|
182
|
+
}, 5000); // Check every 5 seconds
|
|
183
|
+
|
|
184
|
+
// Handle cleanup on exit
|
|
185
|
+
process.on('SIGINT', () => this.stopMonitoring());
|
|
186
|
+
process.on('SIGTERM', () => this.stopMonitoring());
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Stop monitoring Windsurf activity
|
|
191
|
+
*/
|
|
192
|
+
stopMonitoring() {
|
|
193
|
+
if (this.pollInterval) {
|
|
194
|
+
clearInterval(this.pollInterval);
|
|
195
|
+
this.pollInterval = null;
|
|
196
|
+
debugLogger.info('Windsurf monitoring stopped');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Get current status
|
|
202
|
+
*/
|
|
203
|
+
getStatus() {
|
|
204
|
+
return {
|
|
205
|
+
isRunning: this.isWindsurfRunning(),
|
|
206
|
+
isActive: this.isWindsurfActive,
|
|
207
|
+
lastActivity: this.lastActivity,
|
|
208
|
+
isMonitoring: this.pollInterval !== null
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Integration manager for VCM + Windsurf workflow
|
|
215
|
+
*/
|
|
216
|
+
class VCMWindsurfIntegration {
|
|
217
|
+
constructor() {
|
|
218
|
+
this.detector = new WindsurfDetector();
|
|
219
|
+
this.autoContinueEnabled = true;
|
|
220
|
+
this.continueDelay = 5000; // 5 seconds after completion
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Initialize the integration
|
|
225
|
+
*/
|
|
226
|
+
async initialize() {
|
|
227
|
+
debugLogger.info('Initializing VCM-Windsurf integration');
|
|
228
|
+
|
|
229
|
+
// Check if Windsurf is running
|
|
230
|
+
if (!this.detector.isWindsurfRunning()) {
|
|
231
|
+
debugLogger.info('Windsurf not detected, integration disabled');
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Start monitoring
|
|
236
|
+
this.detector.startMonitoring();
|
|
237
|
+
|
|
238
|
+
// Set up automatic continuation
|
|
239
|
+
if (this.autoContinueEnabled) {
|
|
240
|
+
this.setupAutoContinue();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
debugLogger.info('VCM-Windsurf integration initialized');
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Set up automatic continuation when work is detected as complete
|
|
249
|
+
*/
|
|
250
|
+
setupAutoContinue() {
|
|
251
|
+
// This works in conjunction with the detector's polling
|
|
252
|
+
debugLogger.info('Auto-continue enabled', { delay: this.continueDelay });
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Manually trigger continue message
|
|
257
|
+
*/
|
|
258
|
+
async manualContinue() {
|
|
259
|
+
debugLogger.info('Manual continue triggered');
|
|
260
|
+
return await this.detector.sendContinueMessage();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Disable auto-continue
|
|
265
|
+
*/
|
|
266
|
+
disableAutoContinue() {
|
|
267
|
+
this.autoContinueEnabled = false;
|
|
268
|
+
debugLogger.info('Auto-continue disabled');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Enable auto-continue
|
|
273
|
+
*/
|
|
274
|
+
enableAutoContinue() {
|
|
275
|
+
this.autoContinueEnabled = true;
|
|
276
|
+
debugLogger.info('Auto-continue enabled');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Get integration status
|
|
281
|
+
*/
|
|
282
|
+
getStatus() {
|
|
283
|
+
return {
|
|
284
|
+
...this.detector.getStatus(),
|
|
285
|
+
autoContinueEnabled: this.autoContinueEnabled,
|
|
286
|
+
continueDelay: this.continueDelay
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Cleanup resources
|
|
292
|
+
*/
|
|
293
|
+
cleanup() {
|
|
294
|
+
this.detector.stopMonitoring();
|
|
295
|
+
debugLogger.info('VCM-Windsurf integration cleaned up');
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Global integration instance
|
|
300
|
+
let windsurfIntegration = null;
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Initialize Windsurf integration (call from main menu)
|
|
304
|
+
*/
|
|
305
|
+
function initializeWindsurfIntegration() {
|
|
306
|
+
if (!windsurfIntegration) {
|
|
307
|
+
windsurfIntegration = new VCMWindsurfIntegration();
|
|
308
|
+
return windsurfIntegration.initialize();
|
|
309
|
+
}
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Get Windsurf integration status
|
|
315
|
+
*/
|
|
316
|
+
function getWindsurfStatus() {
|
|
317
|
+
return windsurfIntegration ? windsurfIntegration.getStatus() : null;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Send manual continue message
|
|
322
|
+
*/
|
|
323
|
+
async function sendContinueToWindsurf() {
|
|
324
|
+
if (windsurfIntegration) {
|
|
325
|
+
return await windsurfIntegration.manualContinue();
|
|
326
|
+
}
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
module.exports = {
|
|
331
|
+
WindsurfDetector,
|
|
332
|
+
VCMWindsurfIntegration,
|
|
333
|
+
initializeWindsurfIntegration,
|
|
334
|
+
getWindsurfStatus,
|
|
335
|
+
sendContinueToWindsurf
|
|
336
|
+
};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const boxen = require('boxen');
|
|
3
|
+
const { getHostname, requirementsExists, isGitRepo, getCurrentBranch, hasUncommittedChanges, t } = require('vibecodingmachine-core');
|
|
4
|
+
const { checkAutoModeStatus } = require('./auto-mode');
|
|
5
|
+
const { formatIDEName, getAgentDisplayName, formatPath } = require('./display-formatters-extracted');
|
|
6
|
+
const { countRequirements, getSyncStatus, getCurrentProgress } = require('./status-helpers-extracted');
|
|
7
|
+
const pkg = require('../../package.json');
|
|
8
|
+
|
|
9
|
+
async function showWelcomeScreen() {
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
const repoPath = process.cwd(); // Always use current working directory
|
|
13
|
+
const autoStatus = await checkAutoModeStatus();
|
|
14
|
+
const hostname = getHostname();
|
|
15
|
+
|
|
16
|
+
// Get current IDE from config
|
|
17
|
+
const { getAutoConfig } = require('./config');
|
|
18
|
+
const autoConfig = await getAutoConfig();
|
|
19
|
+
|
|
20
|
+
// Check for requirements file
|
|
21
|
+
const hasRequirements = await requirementsExists();
|
|
22
|
+
|
|
23
|
+
// Count requirements if file exists
|
|
24
|
+
const counts = hasRequirements ? await countRequirements() : null;
|
|
25
|
+
|
|
26
|
+
// Clear the screen using console.clear() for better cross-platform compatibility
|
|
27
|
+
// This ensures proper screen refresh and prevents text overlap
|
|
28
|
+
console.clear();
|
|
29
|
+
|
|
30
|
+
// Get version from package.json
|
|
31
|
+
const version = `v${pkg.version}`;
|
|
32
|
+
|
|
33
|
+
// Display welcome banner with version
|
|
34
|
+
console.log('\n' + boxen(
|
|
35
|
+
chalk.bold.cyan('Vibe Coding Machine!') + '\n' +
|
|
36
|
+
chalk.gray(version) + '\n' +
|
|
37
|
+
chalk.gray(t('banner.tagline')),
|
|
38
|
+
{
|
|
39
|
+
padding: 1,
|
|
40
|
+
margin: 0,
|
|
41
|
+
borderStyle: 'round',
|
|
42
|
+
borderColor: 'cyan'
|
|
43
|
+
}
|
|
44
|
+
));
|
|
45
|
+
|
|
46
|
+
// Display feedback hint at the top of every screen
|
|
47
|
+
console.log(chalk.gray('💡 Press F for feedback - Share your thoughts anytime'));
|
|
48
|
+
|
|
49
|
+
// Display repository and system info
|
|
50
|
+
console.log();
|
|
51
|
+
console.log(chalk.gray(t('system.repo').padEnd(25)), formatPath(repoPath));
|
|
52
|
+
|
|
53
|
+
// Display git branch if in a git repo
|
|
54
|
+
try {
|
|
55
|
+
const { isGitRepo, getCurrentBranch, hasUncommittedChanges } = require('vibecodingmachine-core');
|
|
56
|
+
if (isGitRepo(repoPath)) {
|
|
57
|
+
const branch = getCurrentBranch(repoPath);
|
|
58
|
+
if (branch) {
|
|
59
|
+
const isDirty = hasUncommittedChanges(repoPath);
|
|
60
|
+
const branchDisplay = isDirty ? `${chalk.cyan(branch)} ${chalk.yellow(t('system.git.status.dirty'))}` : chalk.cyan(branch);
|
|
61
|
+
console.log(chalk.gray(t('system.git.branch').padEnd(25)), branchDisplay);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
// Ignore git display errors
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log(chalk.gray(t('system.computer.name').padEnd(25)), chalk.cyan(hostname));
|
|
69
|
+
|
|
70
|
+
// Display auto mode progress if running
|
|
71
|
+
if (autoStatus.running) {
|
|
72
|
+
console.log(chalk.gray('Chats: '), chalk.cyan(autoStatus.chatCount || 0));
|
|
73
|
+
|
|
74
|
+
// Get current status and requirement from REQUIREMENTS file
|
|
75
|
+
const progress = await getCurrentProgress();
|
|
76
|
+
if (progress) {
|
|
77
|
+
console.log();
|
|
78
|
+
// Display progress in a purple/magenta box similar to UI
|
|
79
|
+
const stageIcons = {
|
|
80
|
+
'PREPARE': '🔍',
|
|
81
|
+
'ACT': '⚡',
|
|
82
|
+
'CLEAN UP': '🧹',
|
|
83
|
+
'VERIFY': '✅',
|
|
84
|
+
'DONE': '🎉'
|
|
85
|
+
};
|
|
86
|
+
const icon = stageIcons[progress.status] || '⏳';
|
|
87
|
+
const statusColor = progress.status === 'DONE' ? chalk.green : chalk.magenta;
|
|
88
|
+
|
|
89
|
+
// Truncate requirement text first, THEN apply color to fix box alignment
|
|
90
|
+
const requirementText = progress.requirement ? progress.requirement.substring(0, 60) + (progress.requirement.length > 60 ? '...' : '') : 'No requirement';
|
|
91
|
+
|
|
92
|
+
console.log(boxen(
|
|
93
|
+
statusColor.bold(`${icon} ${progress.status}`) + '\n' +
|
|
94
|
+
chalk.gray(requirementText),
|
|
95
|
+
{
|
|
96
|
+
padding: { left: 1, right: 1, top: 0, bottom: 0 },
|
|
97
|
+
margin: 0,
|
|
98
|
+
borderStyle: 'round',
|
|
99
|
+
borderColor: 'magenta',
|
|
100
|
+
width: 70
|
|
101
|
+
}
|
|
102
|
+
));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Display recent audit log entries
|
|
106
|
+
const { readAuditLog, getDateStr } = require('vibecodingmachine-core');
|
|
107
|
+
const todayStr = getDateStr();
|
|
108
|
+
const entries = readAuditLog(todayStr);
|
|
109
|
+
if (entries && entries.length > 0) {
|
|
110
|
+
console.log();
|
|
111
|
+
console.log(chalk.gray.bold('Recent Activity:'));
|
|
112
|
+
// Show last 5 entries
|
|
113
|
+
const recentEntries = entries.slice(-5);
|
|
114
|
+
recentEntries.forEach(entry => {
|
|
115
|
+
const time = new Date(entry.timestamp).toLocaleTimeString('en-US', {
|
|
116
|
+
hour: 'numeric',
|
|
117
|
+
minute: '2-digit',
|
|
118
|
+
second: '2-digit',
|
|
119
|
+
hour12: true
|
|
120
|
+
});
|
|
121
|
+
const icon = entry.type === 'auto-mode-start' ? '▶️' :
|
|
122
|
+
entry.type === 'auto-mode-stop' ? '⏹️' :
|
|
123
|
+
entry.type === 'ide-message' ? '💬' : '•';
|
|
124
|
+
console.log(chalk.gray(` ${time} ${icon}`), entry.message || '');
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = {
|
|
133
|
+
showWelcomeScreen
|
|
134
|
+
};
|
|
135
|
+
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const boxen = require('boxen');
|
|
3
|
+
const { t, getHostname, requirementsExists, isGitRepo, getCurrentBranch, hasUncommittedChanges, readAuditLog, getDateStr } = require('vibecodingmachine-core');
|
|
4
|
+
const { checkAutoModeStatus } = require('./auto-mode');
|
|
5
|
+
const { getAutoConfig } = require('./config');
|
|
6
|
+
const { formatPath } = require('./display-formatters');
|
|
7
|
+
const { countRequirements, getCurrentProgress } = require('./status-helpers');
|
|
8
|
+
|
|
9
|
+
const pkg = require('../../package.json');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Display the welcome screen with system information and current status
|
|
13
|
+
*/
|
|
14
|
+
async function showWelcomeScreen() {
|
|
15
|
+
const repoPath = process.cwd(); // Always use current working directory
|
|
16
|
+
const autoStatus = await checkAutoModeStatus();
|
|
17
|
+
const hostname = getHostname();
|
|
18
|
+
|
|
19
|
+
// Get current IDE from config
|
|
20
|
+
const autoConfig = await getAutoConfig();
|
|
21
|
+
|
|
22
|
+
// Check for requirements file
|
|
23
|
+
const hasRequirements = await requirementsExists();
|
|
24
|
+
|
|
25
|
+
// Count requirements if file exists
|
|
26
|
+
const counts = hasRequirements ? await countRequirements() : null;
|
|
27
|
+
|
|
28
|
+
// Clear the screen using console.clear() for better cross-platform compatibility
|
|
29
|
+
// This ensures proper screen refresh and prevents text overlap
|
|
30
|
+
console.clear();
|
|
31
|
+
|
|
32
|
+
// Get version from package.json
|
|
33
|
+
const version = `v${pkg.version}`;
|
|
34
|
+
|
|
35
|
+
// Display welcome banner with version
|
|
36
|
+
console.log('\n' + boxen(
|
|
37
|
+
chalk.bold.cyan('Vibe Coding Machine!') + '\n' +
|
|
38
|
+
chalk.gray(version) + '\n' +
|
|
39
|
+
chalk.gray(t('banner.tagline')),
|
|
40
|
+
{
|
|
41
|
+
padding: 1,
|
|
42
|
+
margin: 0,
|
|
43
|
+
borderStyle: 'round',
|
|
44
|
+
borderColor: 'cyan'
|
|
45
|
+
}
|
|
46
|
+
));
|
|
47
|
+
|
|
48
|
+
// Display feedback hint at the top of every screen
|
|
49
|
+
console.log(chalk.gray('💡 Press F for feedback - Share your thoughts anytime'));
|
|
50
|
+
|
|
51
|
+
// Display repository and system info
|
|
52
|
+
console.log();
|
|
53
|
+
console.log(chalk.gray(t('system.repo').padEnd(25)), formatPath(repoPath));
|
|
54
|
+
|
|
55
|
+
// Display git branch if in a git repo
|
|
56
|
+
try {
|
|
57
|
+
if (isGitRepo(repoPath)) {
|
|
58
|
+
const branch = getCurrentBranch(repoPath);
|
|
59
|
+
if (branch) {
|
|
60
|
+
const isDirty = hasUncommittedChanges(repoPath);
|
|
61
|
+
const branchDisplay = isDirty ? `${chalk.cyan(branch)} ${chalk.yellow(t('system.git.status.dirty'))}` : chalk.cyan(branch);
|
|
62
|
+
console.log(chalk.gray(t('system.git.branch').padEnd(25)), branchDisplay);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
// Ignore git display errors
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.log(chalk.gray(t('system.computer.name').padEnd(25)), chalk.cyan(hostname));
|
|
70
|
+
|
|
71
|
+
// Display auto mode progress if running
|
|
72
|
+
if (autoStatus.running) {
|
|
73
|
+
console.log(chalk.gray('Chats: '), chalk.cyan(autoStatus.chatCount || 0));
|
|
74
|
+
|
|
75
|
+
// Get current status and requirement from REQUIREMENTS file
|
|
76
|
+
const progress = await getCurrentProgress();
|
|
77
|
+
if (progress) {
|
|
78
|
+
console.log();
|
|
79
|
+
// Display progress in a purple/magenta box similar to UI
|
|
80
|
+
const stageIcons = {
|
|
81
|
+
'PREPARE': '🔍',
|
|
82
|
+
'ACT': '⚡',
|
|
83
|
+
'CLEAN UP': '🧹',
|
|
84
|
+
'VERIFY': '✅',
|
|
85
|
+
'DONE': '🎉'
|
|
86
|
+
};
|
|
87
|
+
const icon = stageIcons[progress.status] || '⏳';
|
|
88
|
+
const statusColor = progress.status === 'DONE' ? chalk.green : chalk.magenta;
|
|
89
|
+
|
|
90
|
+
// Truncate requirement text first, THEN apply color to fix box alignment
|
|
91
|
+
const requirementText = progress.requirement ? progress.requirement.substring(0, 60) + (progress.requirement.length > 60 ? '...' : '') : 'No requirement';
|
|
92
|
+
|
|
93
|
+
console.log(boxen(
|
|
94
|
+
statusColor.bold(`${icon} ${progress.status}`) + '\n' +
|
|
95
|
+
chalk.gray(requirementText),
|
|
96
|
+
{
|
|
97
|
+
padding: { left: 1, right: 1, top: 0, bottom: 0 },
|
|
98
|
+
margin: 0,
|
|
99
|
+
borderStyle: 'round',
|
|
100
|
+
borderColor: 'magenta',
|
|
101
|
+
width: 70
|
|
102
|
+
}
|
|
103
|
+
));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Display recent audit log entries
|
|
107
|
+
const todayStr = getDateStr();
|
|
108
|
+
const entries = readAuditLog(todayStr);
|
|
109
|
+
if (entries && entries.length > 0) {
|
|
110
|
+
console.log();
|
|
111
|
+
console.log(chalk.gray.bold('Recent Activity:'));
|
|
112
|
+
// Show last 5 entries
|
|
113
|
+
const recentEntries = entries.slice(-5);
|
|
114
|
+
recentEntries.forEach(entry => {
|
|
115
|
+
const time = new Date(entry.timestamp).toLocaleTimeString('en-US', {
|
|
116
|
+
hour: 'numeric',
|
|
117
|
+
minute: '2-digit',
|
|
118
|
+
second: '2-digit',
|
|
119
|
+
hour12: true
|
|
120
|
+
});
|
|
121
|
+
const icon = entry.type === 'auto-mode-start' ? '▶️' :
|
|
122
|
+
entry.type === 'auto-mode-stop' ? '⏹️' :
|
|
123
|
+
entry.type === 'ide-message' ? '💬' : '•';
|
|
124
|
+
console.log(chalk.gray(` ${time} ${icon}`), entry.message || '');
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = {
|
|
133
|
+
showWelcomeScreen
|
|
134
|
+
};
|