vibecodingmachine-cli 2026.3.9-850 → 2026.3.10-1547
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/README.md +85 -85
- package/bin/commands/agent-commands.js +295 -28
- package/bin/vibecodingmachine.js +0 -0
- package/package.json +2 -2
- package/scripts/postinstall.js +161 -161
- package/src/commands/auth.js +100 -100
- package/src/commands/auto-execution.js +120 -32
- package/src/commands/auto-requirement-management.js +9 -9
- package/src/commands/auto-status-helpers.js +6 -12
- package/src/commands/computers.js +318 -318
- package/src/commands/feature.js +123 -123
- package/src/commands/locale.js +72 -72
- package/src/commands/repo.js +163 -163
- package/src/commands/setup.js +93 -93
- package/src/commands/sync.js +287 -287
- package/src/index.js +5 -5
- package/src/utils/agent-selector.js +50 -50
- package/src/utils/asset-cleanup.js +60 -60
- package/src/utils/auth.js +6 -0
- package/src/utils/auto-mode-ansi-ui.js +237 -237
- package/src/utils/auto-mode-simple-ui.js +141 -141
- package/src/utils/copy-with-progress.js +167 -167
- package/src/utils/download-with-progress.js +84 -84
- package/src/utils/keyboard-handler.js +153 -153
- package/src/utils/kiro-installer.js +178 -178
- package/src/utils/logger.js +4 -4
- package/src/utils/persistent-header.js +114 -114
- package/src/utils/prompt-helper.js +63 -63
- package/src/utils/provider-checker/agent-runner.js +110 -31
- package/src/utils/provider-checker/ide-manager.js +37 -8
- package/src/utils/provider-checker/provider-validator.js +50 -0
- package/src/utils/provider-checker/requirements-manager.js +21 -6
- package/src/utils/status-card.js +121 -121
- package/src/utils/stdout-interceptor.js +127 -127
- package/src/utils/trui-main-handlers.js +41 -8
- package/src/utils/trui-main-menu.js +10 -3
- package/src/utils/trui-nav-agents.js +23 -33
- package/src/utils/trui-navigation.js +2 -2
- package/src/utils/user-tracking.js +299 -299
package/src/commands/repo.js
CHANGED
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const fs = require('fs-extra');
|
|
3
|
-
const chalk = require('chalk');
|
|
4
|
-
const inquirer = require('inquirer');
|
|
5
|
-
const { getRepoPath, setRepoPath } = require('../utils/config');
|
|
6
|
-
const {
|
|
7
|
-
getHostname,
|
|
8
|
-
getRequirementsFilename,
|
|
9
|
-
isComputerNameEnabled
|
|
10
|
-
} = require('vibecodingmachine-core');
|
|
11
|
-
|
|
12
|
-
async function setRepo(repoPath) {
|
|
13
|
-
try {
|
|
14
|
-
const absolutePath = path.resolve(repoPath);
|
|
15
|
-
|
|
16
|
-
if (!await fs.pathExists(absolutePath)) {
|
|
17
|
-
console.error(chalk.red(`Error: Directory does not exist: ${absolutePath}`));
|
|
18
|
-
process.exit(1);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
await setRepoPath(absolutePath);
|
|
22
|
-
console.log(chalk.green('✓'), `Repository path set to: ${chalk.cyan(absolutePath)}`);
|
|
23
|
-
} catch (error) {
|
|
24
|
-
console.error(chalk.red('Error setting repository path:'), error.message);
|
|
25
|
-
process.exit(1);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function getRepo() {
|
|
30
|
-
try {
|
|
31
|
-
const repoPath = await getRepoPath();
|
|
32
|
-
|
|
33
|
-
if (!repoPath) {
|
|
34
|
-
console.log(chalk.yellow('No repository path configured'));
|
|
35
|
-
console.log(chalk.gray('Use'), chalk.cyan('vcm repo:set <path>'), chalk.gray('to set repository path'));
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
console.log(chalk.cyan(repoPath));
|
|
40
|
-
} catch (error) {
|
|
41
|
-
console.error(chalk.red('Error getting repository path:'), error.message);
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async function initRepo(options = {}) {
|
|
47
|
-
try {
|
|
48
|
-
const cwd = process.cwd();
|
|
49
|
-
const repoName = path.basename(cwd);
|
|
50
|
-
const insideDir = path.join(cwd, '.vibecodingmachine');
|
|
51
|
-
const siblingDir = path.join(path.dirname(cwd), `.vibecodingmachine-${repoName}`);
|
|
52
|
-
|
|
53
|
-
let location = options.location;
|
|
54
|
-
|
|
55
|
-
if (location !== 'inside' && location !== 'sibling') {
|
|
56
|
-
// Ask user where to create the directory
|
|
57
|
-
const answer = await inquirer.prompt([
|
|
58
|
-
{
|
|
59
|
-
type: 'list',
|
|
60
|
-
name: 'location',
|
|
61
|
-
message: 'Where would you like to create the VibeCodingMachine directory?',
|
|
62
|
-
choices: [
|
|
63
|
-
{
|
|
64
|
-
name: `Inside this repository (${chalk.cyan('.vibecodingmachine')}) - suggested`,
|
|
65
|
-
value: 'inside',
|
|
66
|
-
short: 'Inside repository'
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
name: `As a sibling directory (${chalk.cyan(`../.vibecodingmachine-${repoName}`)}) - keeps configs separate from code`,
|
|
70
|
-
value: 'sibling',
|
|
71
|
-
short: 'Sibling directory'
|
|
72
|
-
}
|
|
73
|
-
],
|
|
74
|
-
default: 'inside'
|
|
75
|
-
}
|
|
76
|
-
]);
|
|
77
|
-
location = answer.location;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const allnightDir = location === 'inside' ? insideDir : siblingDir;
|
|
81
|
-
|
|
82
|
-
console.log(chalk.blue('\nInitializing VibeCodingMachine in:'), chalk.cyan(allnightDir));
|
|
83
|
-
|
|
84
|
-
await fs.ensureDir(allnightDir);
|
|
85
|
-
await fs.ensureDir(path.join(allnightDir, 'temp'));
|
|
86
|
-
await fs.ensureDir(path.join(allnightDir, 'temp', 'screenshots'));
|
|
87
|
-
|
|
88
|
-
// Check if computer name is enabled and use appropriate filename
|
|
89
|
-
const useHostname = await isComputerNameEnabled();
|
|
90
|
-
const hostname = getHostname();
|
|
91
|
-
const requirementsFilename = await getRequirementsFilename();
|
|
92
|
-
const requirementsPath = path.join(allnightDir, requirementsFilename);
|
|
93
|
-
|
|
94
|
-
if (!await fs.pathExists(requirementsPath)) {
|
|
95
|
-
const titleSuffix = useHostname ? ` (${hostname})` : '';
|
|
96
|
-
const requirementsTemplate = `# VibeCodingMachine Requirements${titleSuffix}
|
|
97
|
-
|
|
98
|
-
## 🚦 Current Status
|
|
99
|
-
PREPARE
|
|
100
|
-
|
|
101
|
-
## ⏳ Requirements not yet completed
|
|
102
|
-
|
|
103
|
-
### Example Requirement
|
|
104
|
-
Add your requirements here...
|
|
105
|
-
|
|
106
|
-
## ✅ Verified by AI
|
|
107
|
-
|
|
108
|
-
## ⚠️ Issues Found
|
|
109
|
-
`;
|
|
110
|
-
await fs.writeFile(requirementsPath, requirementsTemplate);
|
|
111
|
-
console.log(chalk.green('✓'), `Created ${requirementsFilename}`);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const instructionsPath = path.join(allnightDir, 'INSTRUCTIONS.md');
|
|
115
|
-
if (!await fs.pathExists(instructionsPath)) {
|
|
116
|
-
const fileNote = useHostname
|
|
117
|
-
? `**ALWAYS** use the hostname-specific requirements file:
|
|
118
|
-
- File: \`${requirementsFilename}\`
|
|
119
|
-
- This ensures each computer has its own requirements and progress tracking`
|
|
120
|
-
: `**Requirements file:** \`REQUIREMENTS.md\``;
|
|
121
|
-
|
|
122
|
-
const instructionsTemplate = `# Development Instructions
|
|
123
|
-
|
|
124
|
-
## Important: Requirements File
|
|
125
|
-
|
|
126
|
-
${fileNote}
|
|
127
|
-
|
|
128
|
-
## Guidelines
|
|
129
|
-
- Follow the status progression: PREPARE → ACT → CLEAN UP → VERIFY → DONE
|
|
130
|
-
- Update status in ${requirementsFilename} at each stage
|
|
131
|
-
- Take screenshots during VERIFY phase
|
|
132
|
-
- Mark requirement as DONE when complete
|
|
133
|
-
|
|
134
|
-
## Code Standards
|
|
135
|
-
- Keep files under 250 lines
|
|
136
|
-
- Follow DRY principles
|
|
137
|
-
- Keep it simple (KISS)
|
|
138
|
-
- No placeholder code
|
|
139
|
-
- Prefix temporary files with TEMP_
|
|
140
|
-
`;
|
|
141
|
-
await fs.writeFile(instructionsPath, instructionsTemplate);
|
|
142
|
-
console.log(chalk.green('✓'), 'Created INSTRUCTIONS.md');
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
await setRepoPath(cwd);
|
|
146
|
-
console.log(chalk.green('✓'), 'Set repository path to current directory');
|
|
147
|
-
|
|
148
|
-
console.log(chalk.green('\n✓ VibeCodingMachine initialized successfully!'));
|
|
149
|
-
console.log(chalk.gray('\nNext steps:'));
|
|
150
|
-
const configPath = location === 'inside' ? `.vibecodingmachine/${requirementsFilename}` : `../.vibecodingmachine-${repoName}/${requirementsFilename}`;
|
|
151
|
-
console.log(chalk.gray(' 1. Edit'), chalk.cyan(configPath), chalk.gray('with your requirements'));
|
|
152
|
-
console.log(chalk.gray(' 2. Run'), chalk.cyan('vcm auto:start'), chalk.gray('to begin autonomous development'));
|
|
153
|
-
} catch (error) {
|
|
154
|
-
console.error(chalk.red('Error initializing repository:'), error.message);
|
|
155
|
-
process.exit(1);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
module.exports = {
|
|
160
|
-
setRepo,
|
|
161
|
-
getRepo,
|
|
162
|
-
initRepo
|
|
163
|
-
};
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const inquirer = require('inquirer');
|
|
5
|
+
const { getRepoPath, setRepoPath } = require('../utils/config');
|
|
6
|
+
const {
|
|
7
|
+
getHostname,
|
|
8
|
+
getRequirementsFilename,
|
|
9
|
+
isComputerNameEnabled
|
|
10
|
+
} = require('vibecodingmachine-core');
|
|
11
|
+
|
|
12
|
+
async function setRepo(repoPath) {
|
|
13
|
+
try {
|
|
14
|
+
const absolutePath = path.resolve(repoPath);
|
|
15
|
+
|
|
16
|
+
if (!await fs.pathExists(absolutePath)) {
|
|
17
|
+
console.error(chalk.red(`Error: Directory does not exist: ${absolutePath}`));
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
await setRepoPath(absolutePath);
|
|
22
|
+
console.log(chalk.green('✓'), `Repository path set to: ${chalk.cyan(absolutePath)}`);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error(chalk.red('Error setting repository path:'), error.message);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function getRepo() {
|
|
30
|
+
try {
|
|
31
|
+
const repoPath = await getRepoPath();
|
|
32
|
+
|
|
33
|
+
if (!repoPath) {
|
|
34
|
+
console.log(chalk.yellow('No repository path configured'));
|
|
35
|
+
console.log(chalk.gray('Use'), chalk.cyan('vcm repo:set <path>'), chalk.gray('to set repository path'));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
console.log(chalk.cyan(repoPath));
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error(chalk.red('Error getting repository path:'), error.message);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function initRepo(options = {}) {
|
|
47
|
+
try {
|
|
48
|
+
const cwd = process.cwd();
|
|
49
|
+
const repoName = path.basename(cwd);
|
|
50
|
+
const insideDir = path.join(cwd, '.vibecodingmachine');
|
|
51
|
+
const siblingDir = path.join(path.dirname(cwd), `.vibecodingmachine-${repoName}`);
|
|
52
|
+
|
|
53
|
+
let location = options.location;
|
|
54
|
+
|
|
55
|
+
if (location !== 'inside' && location !== 'sibling') {
|
|
56
|
+
// Ask user where to create the directory
|
|
57
|
+
const answer = await inquirer.prompt([
|
|
58
|
+
{
|
|
59
|
+
type: 'list',
|
|
60
|
+
name: 'location',
|
|
61
|
+
message: 'Where would you like to create the VibeCodingMachine directory?',
|
|
62
|
+
choices: [
|
|
63
|
+
{
|
|
64
|
+
name: `Inside this repository (${chalk.cyan('.vibecodingmachine')}) - suggested`,
|
|
65
|
+
value: 'inside',
|
|
66
|
+
short: 'Inside repository'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: `As a sibling directory (${chalk.cyan(`../.vibecodingmachine-${repoName}`)}) - keeps configs separate from code`,
|
|
70
|
+
value: 'sibling',
|
|
71
|
+
short: 'Sibling directory'
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
default: 'inside'
|
|
75
|
+
}
|
|
76
|
+
]);
|
|
77
|
+
location = answer.location;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const allnightDir = location === 'inside' ? insideDir : siblingDir;
|
|
81
|
+
|
|
82
|
+
console.log(chalk.blue('\nInitializing VibeCodingMachine in:'), chalk.cyan(allnightDir));
|
|
83
|
+
|
|
84
|
+
await fs.ensureDir(allnightDir);
|
|
85
|
+
await fs.ensureDir(path.join(allnightDir, 'temp'));
|
|
86
|
+
await fs.ensureDir(path.join(allnightDir, 'temp', 'screenshots'));
|
|
87
|
+
|
|
88
|
+
// Check if computer name is enabled and use appropriate filename
|
|
89
|
+
const useHostname = await isComputerNameEnabled();
|
|
90
|
+
const hostname = getHostname();
|
|
91
|
+
const requirementsFilename = await getRequirementsFilename();
|
|
92
|
+
const requirementsPath = path.join(allnightDir, requirementsFilename);
|
|
93
|
+
|
|
94
|
+
if (!await fs.pathExists(requirementsPath)) {
|
|
95
|
+
const titleSuffix = useHostname ? ` (${hostname})` : '';
|
|
96
|
+
const requirementsTemplate = `# VibeCodingMachine Requirements${titleSuffix}
|
|
97
|
+
|
|
98
|
+
## 🚦 Current Status
|
|
99
|
+
PREPARE
|
|
100
|
+
|
|
101
|
+
## ⏳ Requirements not yet completed
|
|
102
|
+
|
|
103
|
+
### Example Requirement
|
|
104
|
+
Add your requirements here...
|
|
105
|
+
|
|
106
|
+
## ✅ Verified by AI
|
|
107
|
+
|
|
108
|
+
## ⚠️ Issues Found
|
|
109
|
+
`;
|
|
110
|
+
await fs.writeFile(requirementsPath, requirementsTemplate);
|
|
111
|
+
console.log(chalk.green('✓'), `Created ${requirementsFilename}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const instructionsPath = path.join(allnightDir, 'INSTRUCTIONS.md');
|
|
115
|
+
if (!await fs.pathExists(instructionsPath)) {
|
|
116
|
+
const fileNote = useHostname
|
|
117
|
+
? `**ALWAYS** use the hostname-specific requirements file:
|
|
118
|
+
- File: \`${requirementsFilename}\`
|
|
119
|
+
- This ensures each computer has its own requirements and progress tracking`
|
|
120
|
+
: `**Requirements file:** \`REQUIREMENTS.md\``;
|
|
121
|
+
|
|
122
|
+
const instructionsTemplate = `# Development Instructions
|
|
123
|
+
|
|
124
|
+
## Important: Requirements File
|
|
125
|
+
|
|
126
|
+
${fileNote}
|
|
127
|
+
|
|
128
|
+
## Guidelines
|
|
129
|
+
- Follow the status progression: PREPARE → ACT → CLEAN UP → VERIFY → DONE
|
|
130
|
+
- Update status in ${requirementsFilename} at each stage
|
|
131
|
+
- Take screenshots during VERIFY phase
|
|
132
|
+
- Mark requirement as DONE when complete
|
|
133
|
+
|
|
134
|
+
## Code Standards
|
|
135
|
+
- Keep files under 250 lines
|
|
136
|
+
- Follow DRY principles
|
|
137
|
+
- Keep it simple (KISS)
|
|
138
|
+
- No placeholder code
|
|
139
|
+
- Prefix temporary files with TEMP_
|
|
140
|
+
`;
|
|
141
|
+
await fs.writeFile(instructionsPath, instructionsTemplate);
|
|
142
|
+
console.log(chalk.green('✓'), 'Created INSTRUCTIONS.md');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
await setRepoPath(cwd);
|
|
146
|
+
console.log(chalk.green('✓'), 'Set repository path to current directory');
|
|
147
|
+
|
|
148
|
+
console.log(chalk.green('\n✓ VibeCodingMachine initialized successfully!'));
|
|
149
|
+
console.log(chalk.gray('\nNext steps:'));
|
|
150
|
+
const configPath = location === 'inside' ? `.vibecodingmachine/${requirementsFilename}` : `../.vibecodingmachine-${repoName}/${requirementsFilename}`;
|
|
151
|
+
console.log(chalk.gray(' 1. Edit'), chalk.cyan(configPath), chalk.gray('with your requirements'));
|
|
152
|
+
console.log(chalk.gray(' 2. Run'), chalk.cyan('vcm auto:start'), chalk.gray('to begin autonomous development'));
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error(chalk.red('Error initializing repository:'), error.message);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
module.exports = {
|
|
160
|
+
setRepo,
|
|
161
|
+
getRepo,
|
|
162
|
+
initRepo
|
|
163
|
+
};
|
package/src/commands/setup.js
CHANGED
|
@@ -1,93 +1,93 @@
|
|
|
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
|
-
const { t } = require('vibecodingmachine-core');
|
|
7
|
-
const { promptWithDefaultsOnce } = require('../utils/prompt-helper');
|
|
8
|
-
|
|
9
|
-
async function setupAlias() {
|
|
10
|
-
console.log(chalk.bold.cyan(`\n🛠️ ${t('setup.alias.title')}\n`));
|
|
11
|
-
|
|
12
|
-
// Detect shell
|
|
13
|
-
const shell = process.env.SHELL;
|
|
14
|
-
let configFile = '';
|
|
15
|
-
let shellName = '';
|
|
16
|
-
|
|
17
|
-
if (shell.includes('zsh')) {
|
|
18
|
-
shellName = 'zsh';
|
|
19
|
-
configFile = path.join(os.homedir(), '.zshrc');
|
|
20
|
-
} else if (shell.includes('bash')) {
|
|
21
|
-
shellName = 'bash';
|
|
22
|
-
configFile = path.join(os.homedir(), '.bashrc');
|
|
23
|
-
// On Mac, .bash_profile is often used instead of .bashrc for login shells
|
|
24
|
-
if (process.platform === 'darwin' && !fs.existsSync(configFile)) {
|
|
25
|
-
const profile = path.join(os.homedir(), '.bash_profile');
|
|
26
|
-
if (fs.existsSync(profile)) {
|
|
27
|
-
configFile = profile;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
} else if (shell.includes('fish')) {
|
|
31
|
-
shellName = 'fish';
|
|
32
|
-
configFile = path.join(os.homedir(), '.config', 'fish', 'config.fish');
|
|
33
|
-
} else {
|
|
34
|
-
console.log(chalk.yellow(`⚠️ ${t('setup.shell.unsupported', { shell })}`));
|
|
35
|
-
console.log(chalk.gray(`${t('setup.manual.alias')}\n`));
|
|
36
|
-
console.log(chalk.cyan(` ${t('cli.alias.manual')}`));
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
console.log(chalk.gray(t('setup.alias.detected', { shell: chalk.cyan(shellName) })));
|
|
41
|
-
console.log(chalk.gray(t('setup.alias.config', { file: chalk.cyan(configFile) })));
|
|
42
|
-
|
|
43
|
-
// Check if config file exists
|
|
44
|
-
if (!fs.existsSync(configFile)) {
|
|
45
|
-
// For fish, ensure directory exists
|
|
46
|
-
if (shellName === 'fish') {
|
|
47
|
-
const configDir = path.dirname(configFile);
|
|
48
|
-
if (!fs.existsSync(configDir)) {
|
|
49
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
// Create empty file if it doesn't exist
|
|
53
|
-
fs.writeFileSync(configFile, '', 'utf8');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Read config file
|
|
57
|
-
let content = fs.readFileSync(configFile, 'utf8');
|
|
58
|
-
|
|
59
|
-
// Check if alias already exists
|
|
60
|
-
if (content.includes('alias vcm="vibecodingmachine"') || content.includes("alias vcm='vibecodingmachine'")) {
|
|
61
|
-
console.log(chalk.green(`\n✓ ${t('setup.alias.exists')}`));
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Confirm with user
|
|
66
|
-
const { confirm } = await promptWithDefaultsOnce([
|
|
67
|
-
{
|
|
68
|
-
type: 'confirm',
|
|
69
|
-
name: 'confirm',
|
|
70
|
-
message: t('setup.alias.confirm', { file: path.basename(configFile) }),
|
|
71
|
-
default: true
|
|
72
|
-
}
|
|
73
|
-
]);
|
|
74
|
-
|
|
75
|
-
if (!confirm) {
|
|
76
|
-
console.log(chalk.yellow(`\n${t('setup.alias.cancelled')}`));
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Add alias
|
|
81
|
-
const aliasCommand = '\n# Vibe Coding Machine Alias\nalias vcm="vibecodingmachine"\n';
|
|
82
|
-
|
|
83
|
-
try {
|
|
84
|
-
fs.appendFileSync(configFile, aliasCommand, 'utf8');
|
|
85
|
-
console.log(chalk.green(`\n✓ ${t('setup.alias.added', { file: path.basename(configFile) })}`));
|
|
86
|
-
console.log(chalk.gray(`\n${t('setup.alias.restart')}`));
|
|
87
|
-
console.log(chalk.cyan(` ${t('setup.alias.source', { file: configFile })}`));
|
|
88
|
-
} catch (error) {
|
|
89
|
-
console.log(chalk.red(`\n✗ ${t('setup.alias.error', { error: error.message })}`));
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
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
|
+
const { t } = require('vibecodingmachine-core');
|
|
7
|
+
const { promptWithDefaultsOnce } = require('../utils/prompt-helper');
|
|
8
|
+
|
|
9
|
+
async function setupAlias() {
|
|
10
|
+
console.log(chalk.bold.cyan(`\n🛠️ ${t('setup.alias.title')}\n`));
|
|
11
|
+
|
|
12
|
+
// Detect shell
|
|
13
|
+
const shell = process.env.SHELL;
|
|
14
|
+
let configFile = '';
|
|
15
|
+
let shellName = '';
|
|
16
|
+
|
|
17
|
+
if (shell.includes('zsh')) {
|
|
18
|
+
shellName = 'zsh';
|
|
19
|
+
configFile = path.join(os.homedir(), '.zshrc');
|
|
20
|
+
} else if (shell.includes('bash')) {
|
|
21
|
+
shellName = 'bash';
|
|
22
|
+
configFile = path.join(os.homedir(), '.bashrc');
|
|
23
|
+
// On Mac, .bash_profile is often used instead of .bashrc for login shells
|
|
24
|
+
if (process.platform === 'darwin' && !fs.existsSync(configFile)) {
|
|
25
|
+
const profile = path.join(os.homedir(), '.bash_profile');
|
|
26
|
+
if (fs.existsSync(profile)) {
|
|
27
|
+
configFile = profile;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
} else if (shell.includes('fish')) {
|
|
31
|
+
shellName = 'fish';
|
|
32
|
+
configFile = path.join(os.homedir(), '.config', 'fish', 'config.fish');
|
|
33
|
+
} else {
|
|
34
|
+
console.log(chalk.yellow(`⚠️ ${t('setup.shell.unsupported', { shell })}`));
|
|
35
|
+
console.log(chalk.gray(`${t('setup.manual.alias')}\n`));
|
|
36
|
+
console.log(chalk.cyan(` ${t('cli.alias.manual')}`));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
console.log(chalk.gray(t('setup.alias.detected', { shell: chalk.cyan(shellName) })));
|
|
41
|
+
console.log(chalk.gray(t('setup.alias.config', { file: chalk.cyan(configFile) })));
|
|
42
|
+
|
|
43
|
+
// Check if config file exists
|
|
44
|
+
if (!fs.existsSync(configFile)) {
|
|
45
|
+
// For fish, ensure directory exists
|
|
46
|
+
if (shellName === 'fish') {
|
|
47
|
+
const configDir = path.dirname(configFile);
|
|
48
|
+
if (!fs.existsSync(configDir)) {
|
|
49
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Create empty file if it doesn't exist
|
|
53
|
+
fs.writeFileSync(configFile, '', 'utf8');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Read config file
|
|
57
|
+
let content = fs.readFileSync(configFile, 'utf8');
|
|
58
|
+
|
|
59
|
+
// Check if alias already exists
|
|
60
|
+
if (content.includes('alias vcm="vibecodingmachine"') || content.includes("alias vcm='vibecodingmachine'")) {
|
|
61
|
+
console.log(chalk.green(`\n✓ ${t('setup.alias.exists')}`));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Confirm with user
|
|
66
|
+
const { confirm } = await promptWithDefaultsOnce([
|
|
67
|
+
{
|
|
68
|
+
type: 'confirm',
|
|
69
|
+
name: 'confirm',
|
|
70
|
+
message: t('setup.alias.confirm', { file: path.basename(configFile) }),
|
|
71
|
+
default: true
|
|
72
|
+
}
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
if (!confirm) {
|
|
76
|
+
console.log(chalk.yellow(`\n${t('setup.alias.cancelled')}`));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Add alias
|
|
81
|
+
const aliasCommand = '\n# Vibe Coding Machine Alias\nalias vcm="vibecodingmachine"\n';
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
fs.appendFileSync(configFile, aliasCommand, 'utf8');
|
|
85
|
+
console.log(chalk.green(`\n✓ ${t('setup.alias.added', { file: path.basename(configFile) })}`));
|
|
86
|
+
console.log(chalk.gray(`\n${t('setup.alias.restart')}`));
|
|
87
|
+
console.log(chalk.cyan(` ${t('setup.alias.source', { file: configFile })}`));
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.log(chalk.red(`\n✗ ${t('setup.alias.error', { error: error.message })}`));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = { setupAlias };
|