vibecodingmachine-cli 1.0.3 → 1.0.5
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/.allnightai/REQUIREMENTS.md +11 -11
- package/.eslintrc.js +16 -16
- package/README.md +85 -85
- package/bin/vibecodingmachine.js +274 -274
- package/jest.config.js +8 -8
- package/logs/audit/2025-11-07.jsonl +2 -2
- package/package.json +62 -66
- package/scripts/README.md +128 -128
- package/scripts/auto-start-wrapper.sh +92 -92
- package/scripts/postinstall.js +81 -81
- package/src/commands/auth.js +96 -96
- package/src/commands/auto-direct.js +1748 -1748
- package/src/commands/auto.js +4692 -4692
- package/src/commands/auto.js.bak +710 -710
- package/src/commands/ide.js +70 -70
- package/src/commands/repo.js +159 -159
- package/src/commands/requirements.js +161 -161
- package/src/commands/setup.js +91 -91
- package/src/commands/status.js +88 -88
- package/src/index.js +5 -5
- package/src/utils/auth.js +577 -577
- package/src/utils/auto-mode-ansi-ui.js +238 -238
- package/src/utils/auto-mode-simple-ui.js +161 -161
- package/src/utils/auto-mode-ui.js.bak.blessed +207 -207
- package/src/utils/auto-mode.js +65 -65
- package/src/utils/config.js +64 -64
- package/src/utils/interactive.js +3616 -3616
- package/src/utils/keyboard-handler.js +152 -152
- package/src/utils/logger.js +4 -4
- package/src/utils/persistent-header.js +116 -116
- package/src/utils/provider-registry.js +128 -128
- package/src/utils/status-card.js +120 -120
- package/src/utils/stdout-interceptor.js +127 -127
- package/tests/auto-mode.test.js +37 -37
- package/tests/config.test.js +34 -34
- package/.allnightai/temp/auto-status.json +0 -6
- package/.env +0 -7
|
@@ -1,161 +1,161 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const fs = require('fs-extra');
|
|
3
|
-
const chalk = require('chalk');
|
|
4
|
-
const chokidar = require('chokidar');
|
|
5
|
-
const { getRepoPath } = require('../utils/config');
|
|
6
|
-
const { getRequirementsPath } = require('vibecodingmachine-core');
|
|
7
|
-
|
|
8
|
-
async function getReqPathOrExit() {
|
|
9
|
-
const repoPath = await getRepoPath();
|
|
10
|
-
if (!repoPath) {
|
|
11
|
-
console.log(chalk.yellow('No repository path configured'));
|
|
12
|
-
console.log(chalk.gray('Use'), chalk.cyan('vcm repo:init'), chalk.gray('or'), chalk.cyan('vcm repo:set <path>'));
|
|
13
|
-
process.exit(1);
|
|
14
|
-
}
|
|
15
|
-
// Use getRequirementsPath which handles hostname-specific files
|
|
16
|
-
const reqPath = await getRequirementsPath(repoPath);
|
|
17
|
-
return { repoPath, reqPath };
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async function list(options) {
|
|
21
|
-
try {
|
|
22
|
-
const { reqPath } = await getReqPathOrExit();
|
|
23
|
-
if (!await fs.pathExists(reqPath)) {
|
|
24
|
-
console.log(chalk.yellow('No REQUIREMENTS.md found.'));
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const content = await fs.readFile(reqPath, 'utf8');
|
|
28
|
-
const lines = content.split('\n');
|
|
29
|
-
const filter = options && options.status ? String(options.status).toLowerCase() : null;
|
|
30
|
-
for (const line of lines) {
|
|
31
|
-
if (line.startsWith('### ') || line.startsWith('## ')) {
|
|
32
|
-
if (!filter || line.toLowerCase().includes(filter)) {
|
|
33
|
-
console.log(line);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
} catch (error) {
|
|
38
|
-
console.error(chalk.red('Error listing requirements:'), error.message);
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function add(name) {
|
|
44
|
-
try {
|
|
45
|
-
const { reqPath } = await getReqPathOrExit();
|
|
46
|
-
await fs.ensureFile(reqPath);
|
|
47
|
-
let content = await fs.readFile(reqPath, 'utf8').catch(() => '');
|
|
48
|
-
|
|
49
|
-
// Find the TODO section
|
|
50
|
-
const todoSectionHeader = '## ⏳ Requirements not yet completed';
|
|
51
|
-
if (!content.includes(todoSectionHeader)) {
|
|
52
|
-
content += '\n\n' + todoSectionHeader + '\n';
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Insert at the top of the TODO section (right after the header)
|
|
56
|
-
const lines = content.split('\n');
|
|
57
|
-
const newLines = [];
|
|
58
|
-
let inserted = false;
|
|
59
|
-
|
|
60
|
-
for (let i = 0; i < lines.length; i++) {
|
|
61
|
-
newLines.push(lines[i]);
|
|
62
|
-
|
|
63
|
-
// Insert right after the TODO section header (new header format)
|
|
64
|
-
if (!inserted && lines[i].includes(todoSectionHeader)) {
|
|
65
|
-
// Add requirement header
|
|
66
|
-
newLines.push(`### ${name}`);
|
|
67
|
-
// Add blank line after requirement
|
|
68
|
-
newLines.push('');
|
|
69
|
-
inserted = true;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
content = newLines.join('\n');
|
|
74
|
-
await fs.writeFile(reqPath, content);
|
|
75
|
-
console.log(chalk.green('✓ Requirement added'));
|
|
76
|
-
} catch (error) {
|
|
77
|
-
console.error(chalk.red('Error adding requirement:'), error.message);
|
|
78
|
-
process.exit(1);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async function current() {
|
|
83
|
-
try {
|
|
84
|
-
const { reqPath } = await getReqPathOrExit();
|
|
85
|
-
if (!await fs.pathExists(reqPath)) {
|
|
86
|
-
console.log(chalk.yellow('No REQUIREMENTS.md found.'));
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
const content = await fs.readFile(reqPath, 'utf8');
|
|
90
|
-
const match = content.match(/## \uD83D\uDEA6 Current Status\n([A-Z_]+)/);
|
|
91
|
-
console.log(chalk.cyan(match ? match[1] : 'UNKNOWN'));
|
|
92
|
-
} catch (error) {
|
|
93
|
-
console.error(chalk.red('Error reading current status:'), error.message);
|
|
94
|
-
process.exit(1);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async function next() {
|
|
99
|
-
try {
|
|
100
|
-
const { reqPath } = await getReqPathOrExit();
|
|
101
|
-
if (!await fs.pathExists(reqPath)) {
|
|
102
|
-
console.log(chalk.yellow('No REQUIREMENTS.md found.'));
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
const content = await fs.readFile(reqPath, 'utf8');
|
|
106
|
-
const order = ['PREPARE', 'ACT', 'CLEAN UP', 'VERIFY', 'DONE'];
|
|
107
|
-
const currentMatch = content.match(/## \uD83D\uDEA6 Current Status\n([A-Z_ ]+)/);
|
|
108
|
-
const current = currentMatch ? currentMatch[1] : 'PREPARE';
|
|
109
|
-
const idx = Math.min(order.indexOf(current) + 1, order.length - 1);
|
|
110
|
-
const nextStatus = order[idx];
|
|
111
|
-
const updated = content.replace(/(## \uD83D\uDEA6 Current Status\n)([A-Z_ ]+)/, `$1${nextStatus}`);
|
|
112
|
-
await fs.writeFile(reqPath, updated);
|
|
113
|
-
console.log(chalk.green('✓ Moved to next status:'), chalk.cyan(nextStatus));
|
|
114
|
-
} catch (error) {
|
|
115
|
-
console.error(chalk.red('Error updating status:'), error.message);
|
|
116
|
-
process.exit(1);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async function edit() {
|
|
121
|
-
try {
|
|
122
|
-
const { reqPath } = await getReqPathOrExit();
|
|
123
|
-
const opener = process.env.EDITOR ? null : 'open';
|
|
124
|
-
if (process.env.EDITOR) {
|
|
125
|
-
const { spawn } = require('child_process');
|
|
126
|
-
const child = spawn(process.env.EDITOR, [reqPath], { stdio: 'inherit' });
|
|
127
|
-
child.on('exit', (code) => process.exit(code || 0));
|
|
128
|
-
} else {
|
|
129
|
-
const { execSync } = require('child_process');
|
|
130
|
-
execSync(`${opener} ${JSON.stringify(reqPath)}`);
|
|
131
|
-
}
|
|
132
|
-
} catch (error) {
|
|
133
|
-
console.error(chalk.red('Error opening file:'), error.message);
|
|
134
|
-
process.exit(1);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async function watch() {
|
|
139
|
-
try {
|
|
140
|
-
const { reqPath } = await getReqPathOrExit();
|
|
141
|
-
console.log(chalk.gray('Watching:'), chalk.cyan(reqPath));
|
|
142
|
-
chokidar.watch(reqPath, { ignoreInitial: true })
|
|
143
|
-
.on('change', () => console.log(chalk.green('✓ REQUIREMENTS.md changed')))
|
|
144
|
-
.on('error', (err) => console.error(chalk.red('Watcher error:'), err.message));
|
|
145
|
-
} catch (error) {
|
|
146
|
-
console.error(chalk.red('Error watching requirements:'), error.message);
|
|
147
|
-
process.exit(1);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
module.exports = {
|
|
152
|
-
list,
|
|
153
|
-
add,
|
|
154
|
-
current,
|
|
155
|
-
next,
|
|
156
|
-
edit,
|
|
157
|
-
watch
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const chokidar = require('chokidar');
|
|
5
|
+
const { getRepoPath } = require('../utils/config');
|
|
6
|
+
const { getRequirementsPath } = require('vibecodingmachine-core');
|
|
7
|
+
|
|
8
|
+
async function getReqPathOrExit() {
|
|
9
|
+
const repoPath = await getRepoPath();
|
|
10
|
+
if (!repoPath) {
|
|
11
|
+
console.log(chalk.yellow('No repository path configured'));
|
|
12
|
+
console.log(chalk.gray('Use'), chalk.cyan('vcm repo:init'), chalk.gray('or'), chalk.cyan('vcm repo:set <path>'));
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
// Use getRequirementsPath which handles hostname-specific files
|
|
16
|
+
const reqPath = await getRequirementsPath(repoPath);
|
|
17
|
+
return { repoPath, reqPath };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function list(options) {
|
|
21
|
+
try {
|
|
22
|
+
const { reqPath } = await getReqPathOrExit();
|
|
23
|
+
if (!await fs.pathExists(reqPath)) {
|
|
24
|
+
console.log(chalk.yellow('No REQUIREMENTS.md found.'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const content = await fs.readFile(reqPath, 'utf8');
|
|
28
|
+
const lines = content.split('\n');
|
|
29
|
+
const filter = options && options.status ? String(options.status).toLowerCase() : null;
|
|
30
|
+
for (const line of lines) {
|
|
31
|
+
if (line.startsWith('### ') || line.startsWith('## ')) {
|
|
32
|
+
if (!filter || line.toLowerCase().includes(filter)) {
|
|
33
|
+
console.log(line);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error(chalk.red('Error listing requirements:'), error.message);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function add(name) {
|
|
44
|
+
try {
|
|
45
|
+
const { reqPath } = await getReqPathOrExit();
|
|
46
|
+
await fs.ensureFile(reqPath);
|
|
47
|
+
let content = await fs.readFile(reqPath, 'utf8').catch(() => '');
|
|
48
|
+
|
|
49
|
+
// Find the TODO section
|
|
50
|
+
const todoSectionHeader = '## ⏳ Requirements not yet completed';
|
|
51
|
+
if (!content.includes(todoSectionHeader)) {
|
|
52
|
+
content += '\n\n' + todoSectionHeader + '\n';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Insert at the top of the TODO section (right after the header)
|
|
56
|
+
const lines = content.split('\n');
|
|
57
|
+
const newLines = [];
|
|
58
|
+
let inserted = false;
|
|
59
|
+
|
|
60
|
+
for (let i = 0; i < lines.length; i++) {
|
|
61
|
+
newLines.push(lines[i]);
|
|
62
|
+
|
|
63
|
+
// Insert right after the TODO section header (new header format)
|
|
64
|
+
if (!inserted && lines[i].includes(todoSectionHeader)) {
|
|
65
|
+
// Add requirement header
|
|
66
|
+
newLines.push(`### ${name}`);
|
|
67
|
+
// Add blank line after requirement
|
|
68
|
+
newLines.push('');
|
|
69
|
+
inserted = true;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
content = newLines.join('\n');
|
|
74
|
+
await fs.writeFile(reqPath, content);
|
|
75
|
+
console.log(chalk.green('✓ Requirement added'));
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error(chalk.red('Error adding requirement:'), error.message);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function current() {
|
|
83
|
+
try {
|
|
84
|
+
const { reqPath } = await getReqPathOrExit();
|
|
85
|
+
if (!await fs.pathExists(reqPath)) {
|
|
86
|
+
console.log(chalk.yellow('No REQUIREMENTS.md found.'));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const content = await fs.readFile(reqPath, 'utf8');
|
|
90
|
+
const match = content.match(/## \uD83D\uDEA6 Current Status\n([A-Z_]+)/);
|
|
91
|
+
console.log(chalk.cyan(match ? match[1] : 'UNKNOWN'));
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error(chalk.red('Error reading current status:'), error.message);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function next() {
|
|
99
|
+
try {
|
|
100
|
+
const { reqPath } = await getReqPathOrExit();
|
|
101
|
+
if (!await fs.pathExists(reqPath)) {
|
|
102
|
+
console.log(chalk.yellow('No REQUIREMENTS.md found.'));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const content = await fs.readFile(reqPath, 'utf8');
|
|
106
|
+
const order = ['PREPARE', 'ACT', 'CLEAN UP', 'VERIFY', 'DONE'];
|
|
107
|
+
const currentMatch = content.match(/## \uD83D\uDEA6 Current Status\n([A-Z_ ]+)/);
|
|
108
|
+
const current = currentMatch ? currentMatch[1] : 'PREPARE';
|
|
109
|
+
const idx = Math.min(order.indexOf(current) + 1, order.length - 1);
|
|
110
|
+
const nextStatus = order[idx];
|
|
111
|
+
const updated = content.replace(/(## \uD83D\uDEA6 Current Status\n)([A-Z_ ]+)/, `$1${nextStatus}`);
|
|
112
|
+
await fs.writeFile(reqPath, updated);
|
|
113
|
+
console.log(chalk.green('✓ Moved to next status:'), chalk.cyan(nextStatus));
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error(chalk.red('Error updating status:'), error.message);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function edit() {
|
|
121
|
+
try {
|
|
122
|
+
const { reqPath } = await getReqPathOrExit();
|
|
123
|
+
const opener = process.env.EDITOR ? null : 'open';
|
|
124
|
+
if (process.env.EDITOR) {
|
|
125
|
+
const { spawn } = require('child_process');
|
|
126
|
+
const child = spawn(process.env.EDITOR, [reqPath], { stdio: 'inherit' });
|
|
127
|
+
child.on('exit', (code) => process.exit(code || 0));
|
|
128
|
+
} else {
|
|
129
|
+
const { execSync } = require('child_process');
|
|
130
|
+
execSync(`${opener} ${JSON.stringify(reqPath)}`);
|
|
131
|
+
}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error(chalk.red('Error opening file:'), error.message);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function watch() {
|
|
139
|
+
try {
|
|
140
|
+
const { reqPath } = await getReqPathOrExit();
|
|
141
|
+
console.log(chalk.gray('Watching:'), chalk.cyan(reqPath));
|
|
142
|
+
chokidar.watch(reqPath, { ignoreInitial: true })
|
|
143
|
+
.on('change', () => console.log(chalk.green('✓ REQUIREMENTS.md changed')))
|
|
144
|
+
.on('error', (err) => console.error(chalk.red('Watcher error:'), err.message));
|
|
145
|
+
} catch (error) {
|
|
146
|
+
console.error(chalk.red('Error watching requirements:'), error.message);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = {
|
|
152
|
+
list,
|
|
153
|
+
add,
|
|
154
|
+
current,
|
|
155
|
+
next,
|
|
156
|
+
edit,
|
|
157
|
+
watch
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
package/src/commands/setup.js
CHANGED
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const os = require('os');
|
|
4
|
-
const chalk = require('chalk');
|
|
5
|
-
const inquirer = require('inquirer');
|
|
6
|
-
|
|
7
|
-
async function setupAlias() {
|
|
8
|
-
console.log(chalk.bold.cyan('\n🛠️ Setup Vibe Coding Machine Alias\n'));
|
|
9
|
-
|
|
10
|
-
// Detect shell
|
|
11
|
-
const shell = process.env.SHELL;
|
|
12
|
-
let configFile = '';
|
|
13
|
-
let shellName = '';
|
|
14
|
-
|
|
15
|
-
if (shell.includes('zsh')) {
|
|
16
|
-
shellName = 'zsh';
|
|
17
|
-
configFile = path.join(os.homedir(), '.zshrc');
|
|
18
|
-
} else if (shell.includes('bash')) {
|
|
19
|
-
shellName = 'bash';
|
|
20
|
-
configFile = path.join(os.homedir(), '.bashrc');
|
|
21
|
-
// On Mac, .bash_profile is often used instead of .bashrc for login shells
|
|
22
|
-
if (process.platform === 'darwin' && !fs.existsSync(configFile)) {
|
|
23
|
-
const profile = path.join(os.homedir(), '.bash_profile');
|
|
24
|
-
if (fs.existsSync(profile)) {
|
|
25
|
-
configFile = profile;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
} else if (shell.includes('fish')) {
|
|
29
|
-
shellName = 'fish';
|
|
30
|
-
configFile = path.join(os.homedir(), '.config', 'fish', 'config.fish');
|
|
31
|
-
} else {
|
|
32
|
-
console.log(chalk.yellow(`⚠️ Could not detect supported shell (zsh, bash, fish). Current shell: ${shell}`));
|
|
33
|
-
console.log(chalk.gray('You can manually add the alias:\n'));
|
|
34
|
-
console.log(chalk.cyan(' alias vcm="vibecodingmachine"'));
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
console.log(chalk.gray(`Detected shell: ${chalk.cyan(shellName)}`));
|
|
39
|
-
console.log(chalk.gray(`Config file: ${chalk.cyan(configFile)}`));
|
|
40
|
-
|
|
41
|
-
// Check if config file exists
|
|
42
|
-
if (!fs.existsSync(configFile)) {
|
|
43
|
-
// For fish, ensure directory exists
|
|
44
|
-
if (shellName === 'fish') {
|
|
45
|
-
const configDir = path.dirname(configFile);
|
|
46
|
-
if (!fs.existsSync(configDir)) {
|
|
47
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
// Create empty file if it doesn't exist
|
|
51
|
-
fs.writeFileSync(configFile, '', 'utf8');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Read config file
|
|
55
|
-
let content = fs.readFileSync(configFile, 'utf8');
|
|
56
|
-
|
|
57
|
-
// Check if alias already exists
|
|
58
|
-
if (content.includes('alias vcm="vibecodingmachine"') || content.includes("alias vcm='vibecodingmachine'")) {
|
|
59
|
-
console.log(chalk.green('\n✓ "vcm" alias is already configured!'));
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Confirm with user
|
|
64
|
-
const { confirm } = await inquirer.prompt([
|
|
65
|
-
{
|
|
66
|
-
type: 'confirm',
|
|
67
|
-
name: 'confirm',
|
|
68
|
-
message: `Add 'vcm' alias to ${path.basename(configFile)}?`,
|
|
69
|
-
default: true
|
|
70
|
-
}
|
|
71
|
-
]);
|
|
72
|
-
|
|
73
|
-
if (!confirm) {
|
|
74
|
-
console.log(chalk.yellow('\nCancelled.'));
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Add alias
|
|
79
|
-
const aliasCommand = '\n# Vibe Coding Machine Alias\nalias vcm="vibecodingmachine"\n';
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
fs.appendFileSync(configFile, aliasCommand, 'utf8');
|
|
83
|
-
console.log(chalk.green(`\n✓ Added alias to ${path.basename(configFile)}`));
|
|
84
|
-
console.log(chalk.gray('\nYou may need to restart your terminal or run:'));
|
|
85
|
-
console.log(chalk.cyan(` source ${configFile}`));
|
|
86
|
-
} catch (error) {
|
|
87
|
-
console.log(chalk.red(`\n✗ Error writing to config file: ${error.message}`));
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
module.exports = { setupAlias };
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const inquirer = require('inquirer');
|
|
6
|
+
|
|
7
|
+
async function setupAlias() {
|
|
8
|
+
console.log(chalk.bold.cyan('\n🛠️ Setup Vibe Coding Machine Alias\n'));
|
|
9
|
+
|
|
10
|
+
// Detect shell
|
|
11
|
+
const shell = process.env.SHELL;
|
|
12
|
+
let configFile = '';
|
|
13
|
+
let shellName = '';
|
|
14
|
+
|
|
15
|
+
if (shell.includes('zsh')) {
|
|
16
|
+
shellName = 'zsh';
|
|
17
|
+
configFile = path.join(os.homedir(), '.zshrc');
|
|
18
|
+
} else if (shell.includes('bash')) {
|
|
19
|
+
shellName = 'bash';
|
|
20
|
+
configFile = path.join(os.homedir(), '.bashrc');
|
|
21
|
+
// On Mac, .bash_profile is often used instead of .bashrc for login shells
|
|
22
|
+
if (process.platform === 'darwin' && !fs.existsSync(configFile)) {
|
|
23
|
+
const profile = path.join(os.homedir(), '.bash_profile');
|
|
24
|
+
if (fs.existsSync(profile)) {
|
|
25
|
+
configFile = profile;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
} else if (shell.includes('fish')) {
|
|
29
|
+
shellName = 'fish';
|
|
30
|
+
configFile = path.join(os.homedir(), '.config', 'fish', 'config.fish');
|
|
31
|
+
} else {
|
|
32
|
+
console.log(chalk.yellow(`⚠️ Could not detect supported shell (zsh, bash, fish). Current shell: ${shell}`));
|
|
33
|
+
console.log(chalk.gray('You can manually add the alias:\n'));
|
|
34
|
+
console.log(chalk.cyan(' alias vcm="vibecodingmachine"'));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log(chalk.gray(`Detected shell: ${chalk.cyan(shellName)}`));
|
|
39
|
+
console.log(chalk.gray(`Config file: ${chalk.cyan(configFile)}`));
|
|
40
|
+
|
|
41
|
+
// Check if config file exists
|
|
42
|
+
if (!fs.existsSync(configFile)) {
|
|
43
|
+
// For fish, ensure directory exists
|
|
44
|
+
if (shellName === 'fish') {
|
|
45
|
+
const configDir = path.dirname(configFile);
|
|
46
|
+
if (!fs.existsSync(configDir)) {
|
|
47
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Create empty file if it doesn't exist
|
|
51
|
+
fs.writeFileSync(configFile, '', 'utf8');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Read config file
|
|
55
|
+
let content = fs.readFileSync(configFile, 'utf8');
|
|
56
|
+
|
|
57
|
+
// Check if alias already exists
|
|
58
|
+
if (content.includes('alias vcm="vibecodingmachine"') || content.includes("alias vcm='vibecodingmachine'")) {
|
|
59
|
+
console.log(chalk.green('\n✓ "vcm" alias is already configured!'));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Confirm with user
|
|
64
|
+
const { confirm } = await inquirer.prompt([
|
|
65
|
+
{
|
|
66
|
+
type: 'confirm',
|
|
67
|
+
name: 'confirm',
|
|
68
|
+
message: `Add 'vcm' alias to ${path.basename(configFile)}?`,
|
|
69
|
+
default: true
|
|
70
|
+
}
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
if (!confirm) {
|
|
74
|
+
console.log(chalk.yellow('\nCancelled.'));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Add alias
|
|
79
|
+
const aliasCommand = '\n# Vibe Coding Machine Alias\nalias vcm="vibecodingmachine"\n';
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
fs.appendFileSync(configFile, aliasCommand, 'utf8');
|
|
83
|
+
console.log(chalk.green(`\n✓ Added alias to ${path.basename(configFile)}`));
|
|
84
|
+
console.log(chalk.gray('\nYou may need to restart your terminal or run:'));
|
|
85
|
+
console.log(chalk.cyan(` source ${configFile}`));
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.log(chalk.red(`\n✗ Error writing to config file: ${error.message}`));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = { setupAlias };
|