create-openclaw-bot 5.0.5 → 5.0.6
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/cli.js +90 -9
- package/package.json +1 -1
- package/setup.js +40 -25
- package/tests/smoke-cli-logic.mjs +11 -5
package/cli.js
CHANGED
|
@@ -50,14 +50,95 @@ function isPm2Installed() {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
function getUserNpmPrefixInfo() {
|
|
54
|
+
if (process.platform === 'win32') {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const prefixDir = path.join(os.homedir(), '.local');
|
|
59
|
+
return {
|
|
60
|
+
prefixDir,
|
|
61
|
+
binDir: path.join(prefixDir, 'bin')
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function ensureBinDirOnPath(binDir) {
|
|
66
|
+
const delimiter = path.delimiter;
|
|
67
|
+
const pathParts = String(process.env.PATH || '').split(delimiter).filter(Boolean);
|
|
68
|
+
if (!pathParts.includes(binDir)) {
|
|
69
|
+
process.env.PATH = [binDir, ...pathParts].join(delimiter);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function appendLineIfMissing(filePath, line) {
|
|
74
|
+
let content = '';
|
|
75
|
+
if (fs.existsSync(filePath)) {
|
|
76
|
+
content = fs.readFileSync(filePath, 'utf8');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!content.includes(line)) {
|
|
80
|
+
const prefix = content && !content.endsWith('\n') ? '\n' : '';
|
|
81
|
+
fs.appendFileSync(filePath, `${prefix}${line}\n`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function ensureUserWritableGlobalNpm({ isVi, osChoice }) {
|
|
86
|
+
if (process.platform === 'win32') {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const npmInfo = getUserNpmPrefixInfo();
|
|
91
|
+
if (!npmInfo) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
fs.ensureDirSync(npmInfo.binDir);
|
|
97
|
+
process.env.npm_config_prefix = npmInfo.prefixDir;
|
|
98
|
+
ensureBinDirOnPath(npmInfo.binDir);
|
|
99
|
+
|
|
100
|
+
execSync(`npm config set prefix "${npmInfo.prefixDir.replace(/"/g, '\\"')}"`, {
|
|
101
|
+
stdio: 'ignore',
|
|
102
|
+
shell: true,
|
|
103
|
+
env: process.env
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
appendLineIfMissing(path.join(os.homedir(), '.profile'), 'export PATH="$HOME/.local/bin:$PATH"');
|
|
107
|
+
appendLineIfMissing(
|
|
108
|
+
path.join(os.homedir(), osChoice === 'macos' ? '.zshrc' : '.bashrc'),
|
|
109
|
+
'export PATH="$HOME/.local/bin:$PATH"'
|
|
110
|
+
);
|
|
111
|
+
return true;
|
|
112
|
+
} catch {
|
|
113
|
+
console.log(chalk.yellow(isVi
|
|
114
|
+
? '⚠️ Không thể cấu hình npm global prefix trong ~/.local. Tiếp tục thử cài đặt trực tiếp.'
|
|
115
|
+
: '⚠️ Could not configure npm global prefix in ~/.local. Falling back to direct install.'));
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const userNpmInfo = getUserNpmPrefixInfo();
|
|
121
|
+
if (userNpmInfo) {
|
|
122
|
+
ensureBinDirOnPath(userNpmInfo.binDir);
|
|
123
|
+
}
|
|
124
|
+
|
|
53
125
|
function installGlobalPackage(pkg, { isVi, osChoice, displayName }) {
|
|
54
|
-
const installCommands =
|
|
55
|
-
|
|
56
|
-
|
|
126
|
+
const installCommands = [];
|
|
127
|
+
|
|
128
|
+
if (osChoice === 'windows') {
|
|
129
|
+
installCommands.push(`npm install -g ${pkg}`);
|
|
130
|
+
} else {
|
|
131
|
+
ensureUserWritableGlobalNpm({ isVi, osChoice });
|
|
132
|
+
installCommands.push(`npm install -g ${pkg}`);
|
|
133
|
+
const npmInfo = getUserNpmPrefixInfo();
|
|
134
|
+
if (npmInfo) {
|
|
135
|
+
installCommands.push(`npm install -g --prefix "${npmInfo.prefixDir.replace(/"/g, '\\"')}" ${pkg}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
57
138
|
|
|
58
139
|
for (const cmd of installCommands) {
|
|
59
140
|
try {
|
|
60
|
-
execSync(cmd, { stdio: 'inherit', shell: true });
|
|
141
|
+
execSync(cmd, { stdio: 'inherit', shell: true, env: process.env });
|
|
61
142
|
return true;
|
|
62
143
|
} catch {
|
|
63
144
|
// try next candidate
|
|
@@ -65,8 +146,8 @@ function installGlobalPackage(pkg, { isVi, osChoice, displayName }) {
|
|
|
65
146
|
}
|
|
66
147
|
|
|
67
148
|
console.log(chalk.yellow(isVi
|
|
68
|
-
? `⚠️ Không thể tự cài ${displayName}. Chạy thủ công: ${osChoice === 'windows' ? `npm install -g ${pkg}` : `
|
|
69
|
-
: `⚠️ Could not auto-install ${displayName}. Run manually: ${osChoice === 'windows' ? `npm install -g ${pkg}` : `
|
|
149
|
+
? `⚠️ Không thể tự cài ${displayName}. Chạy thủ công: ${osChoice === 'windows' ? `npm install -g ${pkg}` : `npm config set prefix ~/.local && npm install -g ${pkg}`}`
|
|
150
|
+
: `⚠️ Could not auto-install ${displayName}. Run manually: ${osChoice === 'windows' ? `npm install -g ${pkg}` : `npm config set prefix ~/.local && npm install -g ${pkg}`}`));
|
|
70
151
|
return false;
|
|
71
152
|
}
|
|
72
153
|
|
|
@@ -1712,7 +1793,7 @@ fi
|
|
|
1712
1793
|
: `Could not auto-sync config. Run manually:\n cp -rn ${localClawDir}/. ${globalClawDir}/`}`));
|
|
1713
1794
|
}
|
|
1714
1795
|
|
|
1715
|
-
console.log(chalk.cyan(`\n👉 ${isVi ? 'Đã tạo xong file cấu hình
|
|
1796
|
+
console.log(chalk.cyan(`\n👉 ${isVi ? 'Đã tạo xong file cấu hình Docker.' : 'Docker config files are ready.'}`));
|
|
1716
1797
|
console.log(chalk.gray(isVi
|
|
1717
1798
|
? ` Cấu trúc config: ${isMultiBot && channelKey === 'telegram' ? '.openclaw/ dùng chung + agents/workspace-*' : (isMultiBot ? 'bot1/, bot2/, ...' : '.openclaw/')}`
|
|
1718
1799
|
: ` Config layout: ${isMultiBot && channelKey === 'telegram' ? 'shared .openclaw/ with agents/workspace-*' : (isMultiBot ? 'bot1/, bot2/, ...' : '.openclaw/')}`));
|
|
@@ -1736,7 +1817,7 @@ fi
|
|
|
1736
1817
|
console.log(chalk.cyan(isVi
|
|
1737
1818
|
? '\n📦 Dang cai openclaw binary (npm install -g openclaw)...'
|
|
1738
1819
|
: '\n📦 Installing openclaw binary (npm install -g openclaw)...'));
|
|
1739
|
-
if (!installGlobalPackage('openclaw', { isVi, osChoice, displayName: 'openclaw' })) {
|
|
1820
|
+
if (!installGlobalPackage('openclaw@latest', { isVi, osChoice, displayName: 'openclaw' })) {
|
|
1740
1821
|
process.exit(1);
|
|
1741
1822
|
}
|
|
1742
1823
|
console.log(chalk.green(isVi ? '✅ openclaw da cai xong!' : '✅ openclaw installed!'));
|
|
@@ -1751,7 +1832,7 @@ fi
|
|
|
1751
1832
|
if (osChoice === 'vps') {
|
|
1752
1833
|
if (!isPm2Installed()) {
|
|
1753
1834
|
console.log(chalk.cyan(isVi ? '\n📦 Dang cai PM2...' : '\n📦 Installing PM2...'));
|
|
1754
|
-
if (!installGlobalPackage('pm2', { isVi, osChoice, displayName: 'PM2' })) {
|
|
1835
|
+
if (!installGlobalPackage('pm2@latest', { isVi, osChoice, displayName: 'PM2' })) {
|
|
1755
1836
|
process.exit(1);
|
|
1756
1837
|
}
|
|
1757
1838
|
}
|
package/package.json
CHANGED
package/setup.js
CHANGED
|
@@ -3452,12 +3452,17 @@ ${selectedSkillNames.length ? selectedSkillNames.join('\n') : '- _(No skills ins
|
|
|
3452
3452
|
} else if (state.nativeOs === 'linux') {
|
|
3453
3453
|
const isDocker = state.deployMode === 'docker';
|
|
3454
3454
|
scriptName = isDocker ? 'setup-openclaw-docker-macos.sh' : 'setup-openclaw-macos.sh';
|
|
3455
|
-
const sh = [
|
|
3456
|
-
'#!/usr/bin/env bash', 'set -e',
|
|
3457
|
-
`echo "=== OpenClaw Setup — macOS${isDocker ? ' Docker' : ' Native'} ==="`,
|
|
3458
|
-
'command -v node > /dev/null 2>&1 || { echo "ERROR: Node.js chua cai! https://nodejs.org"; exit 1; }',
|
|
3459
|
-
'
|
|
3460
|
-
|
|
3455
|
+
const sh = [
|
|
3456
|
+
'#!/usr/bin/env bash', 'set -e',
|
|
3457
|
+
`echo "=== OpenClaw Setup — macOS${isDocker ? ' Docker' : ' Native'} ==="`,
|
|
3458
|
+
'command -v node > /dev/null 2>&1 || { echo "ERROR: Node.js chua cai! https://nodejs.org"; exit 1; }',
|
|
3459
|
+
'mkdir -p "$HOME/.local/bin"',
|
|
3460
|
+
'npm config set prefix "$HOME/.local"',
|
|
3461
|
+
'export PATH="$HOME/.local/bin:$PATH"',
|
|
3462
|
+
'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.zshrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.zshrc"',
|
|
3463
|
+
'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
|
|
3464
|
+
'npm install -g openclaw@latest',
|
|
3465
|
+
];
|
|
3461
3466
|
providerLines(sh, 'sh');
|
|
3462
3467
|
if (pluginCmd) sh.push(pluginCmd);
|
|
3463
3468
|
|
|
@@ -3474,16 +3479,21 @@ ${selectedSkillNames.length ? selectedSkillNames.join('\n') : '- _(No skills ins
|
|
|
3474
3479
|
// ─── VPS/Ubuntu PM2 .SH ──────────────────────────────────────────────────
|
|
3475
3480
|
} else if (state.nativeOs === 'vps') {
|
|
3476
3481
|
scriptName = 'setup-openclaw-vps.sh';
|
|
3477
|
-
const vps = [
|
|
3478
|
-
'#!/usr/bin/env bash', 'set -e',
|
|
3479
|
-
`echo "=== OpenClaw Setup — Ubuntu/VPS${isMultiBot ? ` Multi-Bot (${state.botCount} bots)` : ''} ==="`,
|
|
3480
|
-
'# Auto-install Node.js 20 LTS if missing',
|
|
3481
|
-
'if ! command -v node > /dev/null 2>&1; then',
|
|
3482
|
-
' curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -',
|
|
3483
|
-
' sudo apt-get install -y nodejs',
|
|
3484
|
-
'fi',
|
|
3485
|
-
'
|
|
3486
|
-
|
|
3482
|
+
const vps = [
|
|
3483
|
+
'#!/usr/bin/env bash', 'set -e',
|
|
3484
|
+
`echo "=== OpenClaw Setup — Ubuntu/VPS${isMultiBot ? ` Multi-Bot (${state.botCount} bots)` : ''} ==="`,
|
|
3485
|
+
'# Auto-install Node.js 20 LTS if missing',
|
|
3486
|
+
'if ! command -v node > /dev/null 2>&1; then',
|
|
3487
|
+
' curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -',
|
|
3488
|
+
' sudo apt-get install -y nodejs',
|
|
3489
|
+
'fi',
|
|
3490
|
+
'mkdir -p "$HOME/.local/bin"',
|
|
3491
|
+
'npm config set prefix "$HOME/.local"',
|
|
3492
|
+
'export PATH="$HOME/.local/bin:$PATH"',
|
|
3493
|
+
'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.bashrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.bashrc"',
|
|
3494
|
+
'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
|
|
3495
|
+
'npm install -g openclaw@latest pm2@latest',
|
|
3496
|
+
];
|
|
3487
3497
|
providerLines(vps, 'sh');
|
|
3488
3498
|
if (pluginCmd) vps.push(pluginCmd);
|
|
3489
3499
|
|
|
@@ -3509,15 +3519,20 @@ ${selectedSkillNames.length ? selectedSkillNames.join('\n') : '- _(No skills ins
|
|
|
3509
3519
|
// ─── Linux Desktop .SH ───────────────────────────────────────────────────
|
|
3510
3520
|
} else if (state.nativeOs === 'linux-desktop') {
|
|
3511
3521
|
scriptName = 'setup-openclaw-linux.sh';
|
|
3512
|
-
const lnx = [
|
|
3513
|
-
'#!/usr/bin/env bash', 'set -e',
|
|
3514
|
-
`echo "=== OpenClaw Setup — Linux Desktop${isMultiBot ? ' Multi-Bot' : ''} ==="`,
|
|
3515
|
-
'if ! command -v node > /dev/null 2>&1; then',
|
|
3516
|
-
' curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -',
|
|
3517
|
-
' sudo apt-get install -y nodejs',
|
|
3518
|
-
'fi',
|
|
3519
|
-
'
|
|
3520
|
-
|
|
3522
|
+
const lnx = [
|
|
3523
|
+
'#!/usr/bin/env bash', 'set -e',
|
|
3524
|
+
`echo "=== OpenClaw Setup — Linux Desktop${isMultiBot ? ' Multi-Bot' : ''} ==="`,
|
|
3525
|
+
'if ! command -v node > /dev/null 2>&1; then',
|
|
3526
|
+
' curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -',
|
|
3527
|
+
' sudo apt-get install -y nodejs',
|
|
3528
|
+
'fi',
|
|
3529
|
+
'mkdir -p "$HOME/.local/bin"',
|
|
3530
|
+
'npm config set prefix "$HOME/.local"',
|
|
3531
|
+
'export PATH="$HOME/.local/bin:$PATH"',
|
|
3532
|
+
'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.bashrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.bashrc"',
|
|
3533
|
+
'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
|
|
3534
|
+
'npm install -g openclaw@latest',
|
|
3535
|
+
];
|
|
3521
3536
|
providerLines(lnx, 'sh');
|
|
3522
3537
|
if (pluginCmd) lnx.push(pluginCmd);
|
|
3523
3538
|
|
|
@@ -40,16 +40,22 @@ checks.push(() => expectMatch(
|
|
|
40
40
|
|
|
41
41
|
checks.push(() => expectMatch(
|
|
42
42
|
cli,
|
|
43
|
-
/if \(!isOpenClawInstalled\(\)\) \{[\s\S]*installGlobalPackage\('openclaw', \{ isVi, osChoice, displayName: 'openclaw' \}\)/,
|
|
43
|
+
/if \(!isOpenClawInstalled\(\)\) \{[\s\S]*installGlobalPackage\('openclaw@latest', \{ isVi, osChoice, displayName: 'openclaw' \}\)/,
|
|
44
44
|
'Native branch must auto-install openclaw'
|
|
45
45
|
));
|
|
46
46
|
|
|
47
47
|
checks.push(() => expectMatch(
|
|
48
48
|
cli,
|
|
49
|
-
/if \(osChoice === 'vps'\) \{[\s\S]*installGlobalPackage\('pm2', \{ isVi, osChoice, displayName: 'PM2' \}\)/,
|
|
49
|
+
/if \(osChoice === 'vps'\) \{[\s\S]*installGlobalPackage\('pm2@latest', \{ isVi, osChoice, displayName: 'PM2' \}\)/,
|
|
50
50
|
'VPS native branch must auto-install PM2'
|
|
51
51
|
));
|
|
52
52
|
|
|
53
|
+
checks.push(() => expectMatch(
|
|
54
|
+
cli,
|
|
55
|
+
/function ensureUserWritableGlobalNpm\(\{ isVi, osChoice \}\) \{[\s\S]*process\.env\.npm_config_prefix = npmInfo\.prefixDir[\s\S]*npm config set prefix "\$\{npmInfo\.prefixDir\.replace/s,
|
|
56
|
+
'Native CLI must configure a user-writable npm global prefix for non-Windows installs'
|
|
57
|
+
));
|
|
58
|
+
|
|
53
59
|
checks.push(() => expectMatch(
|
|
54
60
|
cli,
|
|
55
61
|
/execSync\('pm2 start ecosystem\.config\.js && pm2 save'/,
|
|
@@ -107,13 +113,13 @@ checks.push(() => expectMatch(
|
|
|
107
113
|
|
|
108
114
|
checks.push(() => expectMatch(
|
|
109
115
|
setup,
|
|
110
|
-
/else if \(state\.nativeOs === 'linux'\) \{[\s\S]*scriptName = isDocker \? 'setup-openclaw-docker-macos\.sh' : 'setup-openclaw-macos\.sh';[\s\S]*npm install -g openclaw@latest[\s\S]*openclaw gateway run/s,
|
|
116
|
+
/else if \(state\.nativeOs === 'linux'\) \{[\s\S]*scriptName = isDocker \? 'setup-openclaw-docker-macos\.sh' : 'setup-openclaw-macos\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@latest[\s\S]*openclaw gateway run/s,
|
|
111
117
|
'macOS script generation must use the correct file name and start command'
|
|
112
118
|
));
|
|
113
119
|
|
|
114
120
|
checks.push(() => expectMatch(
|
|
115
121
|
setup,
|
|
116
|
-
/else if \(state\.nativeOs === 'vps'\) \{[\s\S]*scriptName = 'setup-openclaw-vps\.sh';[\s\S]*npm install -g openclaw@latest pm2[\s\S]*pm2 save && pm2 startup/s,
|
|
122
|
+
/else if \(state\.nativeOs === 'vps'\) \{[\s\S]*scriptName = 'setup-openclaw-vps\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@latest pm2@latest[\s\S]*pm2 save && pm2 startup/s,
|
|
117
123
|
'VPS native script generation must install openclaw+pm2 and persist PM2 startup'
|
|
118
124
|
));
|
|
119
125
|
|
|
@@ -131,7 +137,7 @@ checks.push(() => expectMatch(
|
|
|
131
137
|
|
|
132
138
|
checks.push(() => expectMatch(
|
|
133
139
|
setup,
|
|
134
|
-
/else if \(state\.nativeOs === 'linux-desktop'\) \{[\s\S]*scriptName = 'setup-openclaw-linux\.sh';[\s\S]*npm install -g openclaw@latest[\s\S]*openclaw gateway run/s,
|
|
140
|
+
/else if \(state\.nativeOs === 'linux-desktop'\) \{[\s\S]*scriptName = 'setup-openclaw-linux\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@latest[\s\S]*openclaw gateway run/s,
|
|
135
141
|
'Linux Desktop native script generation must install openclaw and run the gateway'
|
|
136
142
|
));
|
|
137
143
|
|