create-openclaw-bot 5.5.0 → 5.6.0
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 +18 -17
- package/README.vi.md +18 -17
- package/{cli.js → dist/cli.js} +295 -224
- package/dist/setup/shared/install-gen.js +485 -0
- package/{setup/shared/scaffold-gen.js → dist/setup/shared/workspace-gen.js} +247 -25
- package/{setup.js → dist/setup.js} +771 -1158
- package/package.json +10 -7
- package/.github/workflows/check-openclaw-update.yml +0 -106
- package/CHANGELOG.md +0 -602
- package/CHANGELOG.vi.md +0 -588
- package/docs/SETUP.md +0 -532
- package/docs/SETUP.vi.md +0 -439
- package/docs/ai-providers.md +0 -144
- package/docs/ai-providers.vi.md +0 -144
- package/docs/browser-automation-guide.md +0 -207
- package/docs/faq.md +0 -63
- package/docs/faq.vi.md +0 -63
- package/docs/hardware-guide.md +0 -55
- package/docs/hardware-guide.vi.md +0 -55
- package/docs/install-docker.md +0 -161
- package/docs/install-docker.vi.md +0 -161
- package/docs/install-native.md +0 -96
- package/docs/install-native.vi.md +0 -96
- package/docs/preview.png +0 -0
- package/docs/skills-plugins-guide.md +0 -126
- package/index.html +0 -589
- package/old_v510.js +0 -0
- package/setup/shared/runtime-gen.js +0 -710
- package/style.css +0 -1653
- package/upgrade.ps1 +0 -90
- package/upgrade.sh +0 -93
- /package/{setup → dist/setup}/data/channels.js +0 -0
- /package/{setup → dist/setup}/data/header.js +0 -0
- /package/{setup → dist/setup}/data/index.js +0 -0
- /package/{setup → dist/setup}/data/plugins.js +0 -0
- /package/{setup → dist/setup}/data/providers.js +0 -0
- /package/{setup → dist/setup}/data/skills.js +0 -0
- /package/{setup → dist/setup}/shared/common-gen.js +0 -0
- /package/{setup → dist/setup}/shared/docker-gen.js +0 -0
package/{cli.js → dist/cli.js}
RENAMED
|
@@ -9,91 +9,50 @@ import { spawn, execSync, execFileSync } from 'child_process';
|
|
|
9
9
|
import { createRequire } from 'module';
|
|
10
10
|
|
|
11
11
|
// ─── Shared generators (dual-mode IIFE + CJS) ────────────────────────────────
|
|
12
|
-
// These modules export via module.exports when required from Node.js
|
|
13
|
-
const _require = createRequire(import.meta.url);
|
|
14
|
-
const {
|
|
15
|
-
OPENCLAW_NPM_SPEC,
|
|
16
|
-
OPENCLAW_RUNTIME_PACKAGES,
|
|
17
|
-
TELEGRAM_RELAY_PLUGIN_SPEC,
|
|
18
|
-
buildRelayPluginInstallCommand,
|
|
19
|
-
buildRelayPluginInstallCommandWin,
|
|
20
|
-
buildTelegramPostInstallChecklist,
|
|
21
|
-
buildAuthProfilesString,
|
|
22
|
-
buildAuthProfilesJson,
|
|
23
|
-
} = _require('./setup/shared/common-gen.js');
|
|
24
|
-
|
|
25
|
-
const {
|
|
26
|
-
build9RouterSmartRouteSyncScript: build9RouterSmartRouteSyncScriptShared,
|
|
27
|
-
build9RouterComposeEntrypointScript,
|
|
28
|
-
buildGatewayPatchCmd,
|
|
29
|
-
indentBlock,
|
|
30
|
-
buildDockerArtifacts,
|
|
31
|
-
encodeBase64Utf8,
|
|
32
|
-
} = _require('./setup/shared/docker-gen.js');
|
|
33
|
-
|
|
34
|
-
const {
|
|
35
|
-
buildIdentityDoc,
|
|
36
|
-
buildSoulDoc,
|
|
37
|
-
buildTeamDoc,
|
|
38
|
-
buildUserDoc,
|
|
39
|
-
buildMemoryDoc,
|
|
40
|
-
buildBrowserToolJs,
|
|
41
|
-
buildBrowserDoc,
|
|
42
|
-
buildSecurityRules,
|
|
43
|
-
buildAgentsDoc,
|
|
44
|
-
buildToolsDoc,
|
|
45
|
-
buildRelayDoc,
|
|
46
|
-
} = _require('./setup/shared/scaffold-gen.js');
|
|
12
|
+
// These modules export via module.exports when required from Node.js
|
|
13
|
+
const _require = createRequire(import.meta.url);
|
|
47
14
|
|
|
48
|
-
|
|
49
|
-
|
|
15
|
+
function loadSharedModule(modulePath, globalName) {
|
|
16
|
+
const loaded = _require(modulePath);
|
|
17
|
+
if (loaded && Object.keys(loaded).length > 0) {
|
|
18
|
+
return loaded;
|
|
19
|
+
}
|
|
20
|
+
return globalThis[globalName] || loaded || {};
|
|
21
|
+
}
|
|
50
22
|
|
|
51
23
|
const {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
24
|
+
OPENCLAW_NPM_SPEC,
|
|
25
|
+
OPENCLAW_RUNTIME_PACKAGES,
|
|
26
|
+
TELEGRAM_RELAY_PLUGIN_SPEC,
|
|
27
|
+
buildRelayPluginInstallCommand,
|
|
28
|
+
buildTelegramPostInstallChecklist,
|
|
29
|
+
} = loadSharedModule('./setup/shared/common-gen.js', '__openclawCommon');
|
|
57
30
|
|
|
58
31
|
const {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
} = _require('./setup/shared/runtime-gen.js');
|
|
32
|
+
buildDockerArtifacts,
|
|
33
|
+
} = loadSharedModule('./setup/shared/docker-gen.js', '__openclawDockerGen');
|
|
62
34
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
content: `@echo off\r\nsetlocal EnableExtensions\r\nchcp 65001 >nul\r\necho.\r\necho ============================================================\r\necho OpenClaw Uninstaller - Docker (Windows)\r\necho Project: ${absWin}\r\necho ============================================================\r\necho.\r\nset /p CONFIRM=Nhap YES de xac nhan xoa toan bo: \r\nif /i not "%CONFIRM%"=="YES" ( echo Huy bo. & pause & exit /b 0 )\r\necho.\r\necho [1/2] Dang dung Docker containers...\r\ncd /d "${absWin}\\docker\\openclaw" 2>nul && ( docker compose down --volumes --remove-orphans 2>nul || docker-compose down --volumes --remove-orphans 2>nul )\r\necho [2/2] Xoa thu muc project...\r\ncd /d "%USERPROFILE%"\r\nif exist "${absWin}" rd /s /q "${absWin}"\r\necho.\r\necho Go cai hoan tat! De cai lai: npx create-openclaw-bot@latest\r\npause\r\nendlocal\r\n`,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
// macOS / Linux
|
|
79
|
-
const label = os === 'linux' ? 'macOS' : 'Linux Desktop';
|
|
80
|
-
const scriptName = isDocker ? 'uninstall-openclaw-docker.sh' : 'uninstall-openclaw.sh';
|
|
81
|
-
if (!isDocker) {
|
|
82
|
-
return {
|
|
83
|
-
name: scriptName,
|
|
84
|
-
content: `#!/usr/bin/env bash\n# ====== OpenClaw Uninstaller — ${label} (Native) ======\nset -e\nPROJECT_DIR="${absUnix}"\necho ""\necho "============================================================"\necho " OpenClaw Uninstaller — ${label} Native"\necho " Project: $PROJECT_DIR"\necho "============================================================"\necho ""\nread -rp "Type YES to confirm full removal: " CONFIRM\nif [ "$CONFIRM" != "YES" ]; then echo "Cancelled."; exit 0; fi\necho "[1/4] Stopping openclaw and 9router..."\nopenclaw gateway stop 2>/dev/null || true\npkill -f "9router" 2>/dev/null || true\nfor port in 18791 20128; do\n pid=$(lsof -ti tcp:$port 2>/dev/null || true)\n [ -n "$pid" ] && kill -9 $pid 2>/dev/null || true\ndone\necho "[2/4] Uninstalling npm packages..."\nnpm uninstall -g openclaw 9router grammy @grammyjs/runner @grammyjs/transformer-throttler @buape/carbon @larksuiteoapi/node-sdk @slack/web-api 2>/dev/null || true\nsudo npm uninstall -g openclaw 9router 2>/dev/null || true\necho "[3/4] Removing project directory..."\n[ -d "$PROJECT_DIR" ] && rm -rf "$PROJECT_DIR" && echo " OK: Deleted $PROJECT_DIR" || echo " INFO: Not found."\necho "[4/4] Checking home-level dirs..."\nfor dir in "$HOME/.9router" "$HOME/.openclaw"; do\n if [ -d "$dir" ]; then\n read -rp "Delete $dir? [YES/no]: " CLEAN\n [ "$CLEAN" = "YES" ] && rm -rf "$dir" && echo " OK." || echo " Kept."\n fi\ndone\necho ""\necho "============================================================"\necho " Uninstall complete! Re-install: run setup or npx create-openclaw-bot"\necho "============================================================"\n`,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
return {
|
|
88
|
-
name: scriptName,
|
|
89
|
-
content: `#!/usr/bin/env bash\n# ====== OpenClaw Uninstaller — Docker ======\nset -e\nPROJECT_DIR="${absUnix}"\nread -rp "Type YES to confirm: " CONFIRM\n[ "$CONFIRM" = "YES" ] || exit 0\ncd "$PROJECT_DIR/docker/openclaw" 2>/dev/null && docker compose down --volumes --remove-orphans 2>/dev/null || true\nrm -rf "$PROJECT_DIR"\necho "Uninstall complete!"\n`,
|
|
90
|
-
};
|
|
91
|
-
}
|
|
35
|
+
const {
|
|
36
|
+
buildWorkspaceFileMap,
|
|
37
|
+
} = loadSharedModule('./setup/shared/workspace-gen.js', '__openclawWorkspace');
|
|
38
|
+
|
|
39
|
+
const dataExport = loadSharedModule('./setup/data/index.js', '__openclawData');
|
|
40
|
+
|
|
41
|
+
const {
|
|
42
|
+
PROVIDERS: _PROVIDERS,
|
|
43
|
+
SKILLS: _SKILLS,
|
|
44
|
+
CHANNELS: _CHANNELS,
|
|
45
|
+
OLLAMA_MODELS,
|
|
46
|
+
} = dataExport;
|
|
92
47
|
|
|
93
|
-
|
|
94
|
-
|
|
48
|
+
const {
|
|
49
|
+
buildCliChromeDebugArtifacts,
|
|
50
|
+
buildCliUninstallArtifacts,
|
|
51
|
+
buildCliUpgradeArtifacts,
|
|
52
|
+
buildCliStartBotArtifacts,
|
|
53
|
+
} = loadSharedModule('./setup/shared/install-gen.js', '__openclawInstall');
|
|
95
54
|
|
|
96
|
-
function installRelayPluginForProject(projectDir, isVi) {
|
|
55
|
+
function installRelayPluginForProject(projectDir, isVi) {
|
|
97
56
|
try {
|
|
98
57
|
execSync(`openclaw plugins install ${TELEGRAM_RELAY_PLUGIN_SPEC}`, { cwd: projectDir, stdio: 'ignore' });
|
|
99
58
|
return true;
|
|
@@ -598,18 +557,28 @@ function printZaloPersonalLoginInfo({ isVi, deployMode, projectDir }) {
|
|
|
598
557
|
: ` → If needed, copy the QR into the project folder with: ${copyCmd}`));
|
|
599
558
|
}
|
|
600
559
|
|
|
601
|
-
async function waitForFile(filePath, timeoutMs = 15000, intervalMs = 500) {
|
|
602
|
-
const deadline = Date.now() + timeoutMs;
|
|
603
|
-
while (Date.now() < deadline) {
|
|
604
|
-
if (await fs.pathExists(filePath)) {
|
|
605
|
-
return true;
|
|
560
|
+
async function waitForFile(filePath, timeoutMs = 15000, intervalMs = 500) {
|
|
561
|
+
const deadline = Date.now() + timeoutMs;
|
|
562
|
+
while (Date.now() < deadline) {
|
|
563
|
+
if (await fs.pathExists(filePath)) {
|
|
564
|
+
return true;
|
|
606
565
|
}
|
|
607
566
|
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
608
|
-
}
|
|
609
|
-
return fs.pathExists(filePath);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
function
|
|
567
|
+
}
|
|
568
|
+
return fs.pathExists(filePath);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
async function writeGeneratedArtifacts(targetDir, artifacts = []) {
|
|
572
|
+
for (const artifact of artifacts.filter(Boolean)) {
|
|
573
|
+
const artifactPath = path.join(targetDir, artifact.name);
|
|
574
|
+
await fs.writeFile(artifactPath, artifact.content, 'utf8');
|
|
575
|
+
if (artifact.executable || artifact.name.endsWith('.sh')) {
|
|
576
|
+
try { await fs.chmod(artifactPath, 0o755); } catch (_) {}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function extractZaloPairingCode(text) {
|
|
613
582
|
const value = String(text || '');
|
|
614
583
|
const explicitCommandMatch = value.match(/openclaw pairing approve zalouser\s+([A-Z0-9-]+)/i);
|
|
615
584
|
if (explicitCommandMatch) {
|
|
@@ -729,10 +698,10 @@ async function runNativeZaloPersonalLoginFlow({ isVi, projectDir }) {
|
|
|
729
698
|
}
|
|
730
699
|
}
|
|
731
700
|
|
|
732
|
-
function runPm2Save({ projectDir, isVi }) {
|
|
733
|
-
try {
|
|
734
|
-
execSync('pm2 save', {
|
|
735
|
-
cwd: projectDir,
|
|
701
|
+
function runPm2Save({ projectDir, isVi }) {
|
|
702
|
+
try {
|
|
703
|
+
execSync('pm2 save', {
|
|
704
|
+
cwd: projectDir,
|
|
736
705
|
stdio: 'inherit',
|
|
737
706
|
shell: true,
|
|
738
707
|
env: process.env
|
|
@@ -741,10 +710,138 @@ function runPm2Save({ projectDir, isVi }) {
|
|
|
741
710
|
console.log(chalk.yellow(isVi
|
|
742
711
|
? '⚠️ PM2 save khong hoan tat. Bot van co the dang chay, nhung hay thu chay lai `pm2 save` sau.'
|
|
743
712
|
: '⚠️ PM2 save did not complete. The app may still be running, but try `pm2 save` again afterwards.'));
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
function
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function getDetectedOsChoice() {
|
|
717
|
+
const detectedPlatform = process.platform;
|
|
718
|
+
return detectedPlatform === 'win32' ? 'windows'
|
|
719
|
+
: detectedPlatform === 'darwin' ? 'macos'
|
|
720
|
+
: 'vps';
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
function getCliSubcommand() {
|
|
724
|
+
return String(process.argv[2] || '').trim().toLowerCase();
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
function findProjectDir(startDir = process.cwd()) {
|
|
728
|
+
let currentDir = path.resolve(startDir);
|
|
729
|
+
|
|
730
|
+
while (true) {
|
|
731
|
+
if (
|
|
732
|
+
fs.existsSync(path.join(currentDir, '.openclaw'))
|
|
733
|
+
|| fs.existsSync(path.join(currentDir, 'docker', 'openclaw'))
|
|
734
|
+
) {
|
|
735
|
+
return currentDir;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const isDockerOpenClawDir =
|
|
739
|
+
path.basename(currentDir).toLowerCase() === 'openclaw'
|
|
740
|
+
&& path.basename(path.dirname(currentDir)).toLowerCase() === 'docker';
|
|
741
|
+
if (isDockerOpenClawDir) {
|
|
742
|
+
const projectDir = path.dirname(path.dirname(currentDir));
|
|
743
|
+
if (
|
|
744
|
+
fs.existsSync(path.join(projectDir, '.openclaw'))
|
|
745
|
+
|| fs.existsSync(path.join(currentDir, 'docker-compose.yml'))
|
|
746
|
+
) {
|
|
747
|
+
return projectDir;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const parentDir = path.dirname(currentDir);
|
|
752
|
+
if (parentDir === currentDir) {
|
|
753
|
+
return null;
|
|
754
|
+
}
|
|
755
|
+
currentDir = parentDir;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
function detectProjectDeployMode(projectDir) {
|
|
760
|
+
const dockerDir = path.join(projectDir, 'docker', 'openclaw');
|
|
761
|
+
if (
|
|
762
|
+
fs.existsSync(path.join(dockerDir, 'docker-compose.yml'))
|
|
763
|
+
|| fs.existsSync(path.join(dockerDir, '.env'))
|
|
764
|
+
) {
|
|
765
|
+
return 'docker';
|
|
766
|
+
}
|
|
767
|
+
return 'native';
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
function detectProjectBotName(projectDir) {
|
|
771
|
+
try {
|
|
772
|
+
const configPath = path.join(projectDir, '.openclaw', 'openclaw.json');
|
|
773
|
+
if (fs.existsSync(configPath)) {
|
|
774
|
+
const config = fs.readJsonSync(configPath);
|
|
775
|
+
const firstAgentId = config?.agents?.list?.[0]?.id;
|
|
776
|
+
if (firstAgentId) {
|
|
777
|
+
return firstAgentId;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
} catch {
|
|
781
|
+
// fallback below
|
|
782
|
+
}
|
|
783
|
+
return path.basename(projectDir);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
function detectProjectUses9Router(projectDir) {
|
|
787
|
+
try {
|
|
788
|
+
const configPath = path.join(projectDir, '.openclaw', 'openclaw.json');
|
|
789
|
+
if (fs.existsSync(configPath)) {
|
|
790
|
+
const config = fs.readJsonSync(configPath);
|
|
791
|
+
if (config?.models?.providers?.['9router']) {
|
|
792
|
+
return true;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
} catch {
|
|
796
|
+
// fallback below
|
|
797
|
+
}
|
|
798
|
+
return fs.existsSync(path.join(projectDir, '.9router'));
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
async function runUpgradeCommand() {
|
|
802
|
+
const projectDir = findProjectDir();
|
|
803
|
+
if (!projectDir) {
|
|
804
|
+
console.error(chalk.red('Error: no OpenClaw project found in the current directory tree.'));
|
|
805
|
+
console.error(chalk.yellow('Run this inside the bot project folder that contains .openclaw or docker/openclaw.'));
|
|
806
|
+
process.exit(1);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
const deployMode = detectProjectDeployMode(projectDir);
|
|
810
|
+
const osChoice = getDetectedOsChoice();
|
|
811
|
+
const botName = detectProjectBotName(projectDir);
|
|
812
|
+
const is9Router = detectProjectUses9Router(projectDir);
|
|
813
|
+
|
|
814
|
+
console.log(chalk.cyan('\nRefreshing generated OpenClaw project artifacts...'));
|
|
815
|
+
console.log(chalk.gray(` Project: ${projectDir}`));
|
|
816
|
+
console.log(chalk.gray(` Mode: ${deployMode}`));
|
|
817
|
+
|
|
818
|
+
await writeGeneratedArtifacts(projectDir, buildCliChromeDebugArtifacts());
|
|
819
|
+
await writeGeneratedArtifacts(projectDir, buildCliUninstallArtifacts({
|
|
820
|
+
deployMode,
|
|
821
|
+
osChoice,
|
|
822
|
+
projectDir,
|
|
823
|
+
botName,
|
|
824
|
+
}));
|
|
825
|
+
await writeGeneratedArtifacts(projectDir, buildCliUpgradeArtifacts());
|
|
826
|
+
|
|
827
|
+
if (deployMode !== 'docker') {
|
|
828
|
+
await writeGeneratedArtifacts(projectDir, buildCliStartBotArtifacts({
|
|
829
|
+
projectDir,
|
|
830
|
+
openclawHome: path.join(projectDir, '.openclaw'),
|
|
831
|
+
is9Router,
|
|
832
|
+
isVi: false,
|
|
833
|
+
}));
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
console.log(chalk.green('\nUpgrade artifacts refreshed successfully.'));
|
|
837
|
+
if (deployMode === 'docker') {
|
|
838
|
+
console.log(chalk.white(` Next: cd ${path.join(projectDir, 'docker', 'openclaw')} && docker compose up -d --build`));
|
|
839
|
+
} else {
|
|
840
|
+
console.log(chalk.white(` Next: run ${process.platform === 'win32' ? '.\\start-bot.bat' : './start-bot.sh'} from ${projectDir}`));
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
function startNative9RouterPm2({ isVi, projectDir, appName, syncScriptPath }) {
|
|
748
845
|
const routerAppName = `${appName}-9router`;
|
|
749
846
|
const routerLaunch = resolveNative9RouterDesktopLaunch();
|
|
750
847
|
const normalizedProjectDir = projectDir.replace(/\\/g, '/');
|
|
@@ -874,10 +971,11 @@ async function writeWorkspaceFiles({
|
|
|
874
971
|
ownAliases = [],
|
|
875
972
|
otherAgents = [], // [{ name, agentId }]
|
|
876
973
|
teamRoster = [],
|
|
877
|
-
userInfo = '',
|
|
878
|
-
agentWorkspaceDir = 'workspace',
|
|
879
|
-
isRelayBot = false,
|
|
880
|
-
|
|
974
|
+
userInfo = '',
|
|
975
|
+
agentWorkspaceDir = 'workspace',
|
|
976
|
+
isRelayBot = false,
|
|
977
|
+
replyToDirectMessages = true,
|
|
978
|
+
}) {
|
|
881
979
|
const skillListStr = SKILLS
|
|
882
980
|
.filter((s) => selectedSkills.includes(s.value))
|
|
883
981
|
.map((s) => {
|
|
@@ -888,58 +986,58 @@ async function writeWorkspaceFiles({
|
|
|
888
986
|
})
|
|
889
987
|
.join('\n') || (isVi ? '- _(Chưa có skill nào)_' : '- _(No skills installed)_');
|
|
890
988
|
|
|
891
|
-
const workspacePath =
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
isVi, skillListStr, workspacePath,
|
|
989
|
+
const workspacePath = `.openclaw/${agentWorkspaceDir}/`;
|
|
990
|
+
const teamRosterFormatted = teamRoster
|
|
991
|
+
.map((peer, idx) => {
|
|
992
|
+
const agentId = peer.agentId || String(peer.name || `Bot ${idx + 1}`).toLowerCase().replace(/[^a-z0-9]+/g, '-');
|
|
993
|
+
const desc = peer.desc || (isVi ? 'Tro ly AI ca nhan' : 'Personal AI assistant');
|
|
994
|
+
const accountId = peer.accountId ? `, accountId: ${peer.accountId}` : '';
|
|
995
|
+
const slashCmd = peer.slashCmd ? `, slash: ${peer.slashCmd}` : '';
|
|
996
|
+
return `- \`${agentId}\`: ${peer.name || `Bot ${idx + 1}`} - ${desc}${accountId}${slashCmd}`;
|
|
997
|
+
})
|
|
998
|
+
.join('\n');
|
|
999
|
+
|
|
1000
|
+
const files = buildWorkspaceFileMap({
|
|
1001
|
+
isVi,
|
|
905
1002
|
variant: isRelayBot ? 'relay' : 'single',
|
|
1003
|
+
botName,
|
|
1004
|
+
botDesc,
|
|
1005
|
+
ownAliases,
|
|
1006
|
+
otherAgents,
|
|
1007
|
+
replyToDirectMessages,
|
|
1008
|
+
skillListStr,
|
|
1009
|
+
workspacePath,
|
|
906
1010
|
agentWorkspaceDir,
|
|
1011
|
+
persona,
|
|
1012
|
+
userInfo,
|
|
1013
|
+
hasBrowser: isDesktop || isServer,
|
|
1014
|
+
soulVariant: isRelayBot ? 'cli-simple' : 'cli-rich',
|
|
1015
|
+
userVariant: isRelayBot ? 'cli-multi' : 'cli-single',
|
|
1016
|
+
memoryVariant: isRelayBot ? 'cli-multi' : 'cli-single',
|
|
1017
|
+
browserDocVariant: isServer ? 'cli-server' : 'cli-desktop',
|
|
1018
|
+
browserToolVariant: 'cli',
|
|
1019
|
+
includeBrowserTool: isDesktop,
|
|
1020
|
+
teamRosterFormatted,
|
|
1021
|
+
hasScheduler: selectedSkills.includes('scheduler'),
|
|
907
1022
|
});
|
|
908
|
-
const teamSection = teamRoster.length > 0
|
|
909
|
-
? `\n\n${buildTeamDoc({
|
|
910
|
-
isVi,
|
|
911
|
-
teamRoster,
|
|
912
|
-
includeAgentIds: isRelayBot,
|
|
913
|
-
includeAccountIds: isRelayBot && teamRoster.some((p) => p.accountId),
|
|
914
|
-
relayMode: isRelayBot && otherAgents.length > 0,
|
|
915
|
-
})}`
|
|
916
|
-
: '';
|
|
917
|
-
const relaySection = isRelayBot
|
|
918
|
-
? `\n\n${buildRelayDoc(isVi)}`
|
|
919
|
-
: '';
|
|
920
1023
|
|
|
921
1024
|
await fs.ensureDir(workspaceDir);
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1025
|
+
for (const [name, content] of Object.entries(files)) {
|
|
1026
|
+
await fs.writeFile(path.join(workspaceDir, name), content, 'utf8');
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
|
|
1031
|
+
async function main() {
|
|
1032
|
+
const cliSubcommand = getCliSubcommand();
|
|
1033
|
+
if (cliSubcommand === 'upgrade') {
|
|
1034
|
+
await runUpgradeCommand();
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
928
1037
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
await fs.writeFile(path.join(workspaceDir, 'BROWSER.md'), buildBrowserDoc({ isVi, variant: 'cli-desktop', workspaceRoot: '/root/.openclaw' }));
|
|
933
|
-
} else if (isServer) {
|
|
934
|
-
await fs.writeFile(path.join(workspaceDir, 'BROWSER.md'), buildBrowserDoc({ isVi, variant: 'cli-server' }));
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
async function main() {
|
|
940
|
-
console.log(chalk.red('\n=================================='));
|
|
941
|
-
console.log(chalk.redBright(LOGO));
|
|
942
|
-
console.log(chalk.greenBright(' OpenClaw Auto Setup CLI '));
|
|
1038
|
+
console.log(chalk.red('\n=================================='));
|
|
1039
|
+
console.log(chalk.redBright(LOGO));
|
|
1040
|
+
console.log(chalk.greenBright(' OpenClaw Auto Setup CLI '));
|
|
943
1041
|
console.log(chalk.red('==================================\n'));
|
|
944
1042
|
|
|
945
1043
|
// 1. Language
|
|
@@ -1458,7 +1556,7 @@ async function main() {
|
|
|
1458
1556
|
[groupId || '*']: { enabled: true, requireMention: false },
|
|
1459
1557
|
},
|
|
1460
1558
|
replyToMode: 'first',
|
|
1461
|
-
reactionLevel: '
|
|
1559
|
+
reactionLevel: 'minimal',
|
|
1462
1560
|
actions: {
|
|
1463
1561
|
sendMessage: true,
|
|
1464
1562
|
reactions: true,
|
|
@@ -1481,13 +1579,13 @@ async function main() {
|
|
|
1481
1579
|
timeoutSeconds: provider.isLocal ? 900 : 120,
|
|
1482
1580
|
...(provider.isLocal ? { llm: { idleTimeoutSeconds: 300 } } : {}),
|
|
1483
1581
|
},
|
|
1484
|
-
list: agentMetas.map((meta) => ({
|
|
1485
|
-
id: meta.agentId,
|
|
1486
|
-
name: meta.name,
|
|
1487
|
-
workspace:
|
|
1488
|
-
agentDir:
|
|
1489
|
-
model: { primary: modelsPrimary, fallbacks: [] },
|
|
1490
|
-
})),
|
|
1582
|
+
list: agentMetas.map((meta) => ({
|
|
1583
|
+
id: meta.agentId,
|
|
1584
|
+
name: meta.name,
|
|
1585
|
+
workspace: `.openclaw/${meta.workspaceDir}`,
|
|
1586
|
+
agentDir: `agents/${meta.agentId}/agent`,
|
|
1587
|
+
model: { primary: modelsPrimary, fallbacks: [] },
|
|
1588
|
+
})),
|
|
1491
1589
|
},
|
|
1492
1590
|
...(providerKey === '9router' ? {
|
|
1493
1591
|
models: {
|
|
@@ -1543,11 +1641,7 @@ async function main() {
|
|
|
1543
1641
|
auth: { mode: 'token', token: 'cli-dummy-token-xyz123' },
|
|
1544
1642
|
},
|
|
1545
1643
|
};
|
|
1546
|
-
sharedConfig.plugins = {
|
|
1547
|
-
entries: {
|
|
1548
|
-
[TELEGRAM_RELAY_PLUGIN_ID]: { enabled: true },
|
|
1549
|
-
},
|
|
1550
|
-
};
|
|
1644
|
+
sharedConfig.plugins = { entries: {} };
|
|
1551
1645
|
|
|
1552
1646
|
if (hasBrowserDesktop) {
|
|
1553
1647
|
sharedConfig.browser = {
|
|
@@ -1621,8 +1715,7 @@ async function main() {
|
|
|
1621
1715
|
.map((peer) => ({ name: peer.name, agentId: peer.agentId }));
|
|
1622
1716
|
|
|
1623
1717
|
// agentYaml & auth still needed, keep non-workspace writes here
|
|
1624
|
-
|
|
1625
|
-
await fs.writeFile(path.join(rootClawDir, 'agents', `${meta.agentId}.yaml`), agentYaml);
|
|
1718
|
+
// .yaml removed — OpenClaw reads config exclusively from openclaw.json
|
|
1626
1719
|
if (Object.keys(authProfilesJson).length > 0) {
|
|
1627
1720
|
await fs.writeJson(path.join(rootClawDir, 'agents', meta.agentId, 'agent', 'auth-profiles.json'), authProfilesJson, { spaces: 2 });
|
|
1628
1721
|
}
|
|
@@ -1634,10 +1727,11 @@ async function main() {
|
|
|
1634
1727
|
selectedSkills, deployMode,
|
|
1635
1728
|
isDesktop: hasBrowserDesktop, isServer: hasBrowserServer,
|
|
1636
1729
|
isMultiBot: true, ownAliases, otherAgents,
|
|
1637
|
-
teamRoster: teamMdRoster, userInfo,
|
|
1638
|
-
agentWorkspaceDir: meta.workspaceDir,
|
|
1639
|
-
isRelayBot: true,
|
|
1640
|
-
|
|
1730
|
+
teamRoster: teamMdRoster, userInfo,
|
|
1731
|
+
agentWorkspaceDir: meta.workspaceDir,
|
|
1732
|
+
isRelayBot: true,
|
|
1733
|
+
replyToDirectMessages: true,
|
|
1734
|
+
});
|
|
1641
1735
|
}
|
|
1642
1736
|
} else {
|
|
1643
1737
|
const numBotsToConfigure = 1;
|
|
@@ -1654,8 +1748,9 @@ async function main() {
|
|
|
1654
1748
|
}));
|
|
1655
1749
|
const ownAliases = [loopBotName, bots[bIndex]?.slashCmd || '', `bot ${bIndex + 1}`].filter(Boolean);
|
|
1656
1750
|
const otherBotNames = teamRoster.filter((peer) => peer.idx !== bIndex).map((peer) => peer.name);
|
|
1657
|
-
const loopAgentId = loopBotName.replace(
|
|
1658
|
-
const
|
|
1751
|
+
const loopAgentId = loopBotName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || `bot${bIndex + 1}`;
|
|
1752
|
+
const loopWorkspaceDir = `workspace-${loopAgentId}`;
|
|
1753
|
+
const loopBotDir = isMultiBot ? path.join(projectDir, `bot${bIndex+1}`) : projectDir;
|
|
1659
1754
|
|
|
1660
1755
|
await fs.ensureDir(path.join(loopBotDir, '.openclaw', 'agents', loopAgentId, 'agent'));
|
|
1661
1756
|
if (Object.keys(authProfilesJson).length > 0) {
|
|
@@ -1672,11 +1767,13 @@ async function main() {
|
|
|
1672
1767
|
compaction: { mode: 'safeguard' },
|
|
1673
1768
|
timeoutSeconds: provider.isLocal ? 900 : 120,
|
|
1674
1769
|
...(provider.isLocal ? { llm: { idleTimeoutSeconds: 300 } } : {}),
|
|
1675
|
-
},
|
|
1676
|
-
list: [{
|
|
1677
|
-
id: loopAgentId,
|
|
1678
|
-
|
|
1679
|
-
|
|
1770
|
+
},
|
|
1771
|
+
list: [{
|
|
1772
|
+
id: loopAgentId,
|
|
1773
|
+
workspace: `.openclaw/${loopWorkspaceDir}`,
|
|
1774
|
+
agentDir: `agents/${loopAgentId}/agent`,
|
|
1775
|
+
model: { primary: modelsPrimary, fallbacks: [] }
|
|
1776
|
+
}]
|
|
1680
1777
|
},
|
|
1681
1778
|
...(providerKey === '9router' ? {
|
|
1682
1779
|
models: {
|
|
@@ -1760,7 +1857,7 @@ async function main() {
|
|
|
1760
1857
|
await fs.writeJson(path.join(loopBotDir, '.openclaw', 'openclaw.json'), botConfig, { spaces: 2 });
|
|
1761
1858
|
|
|
1762
1859
|
// ── Workspace files: use shared writeWorkspaceFiles() ──────────────────────
|
|
1763
|
-
const dockerWorkspaceDir = path.join(loopBotDir, '.openclaw',
|
|
1860
|
+
const dockerWorkspaceDir = path.join(loopBotDir, '.openclaw', loopWorkspaceDir);
|
|
1764
1861
|
const dockerOwnAliases = [loopBotName, bots[bIndex]?.slashCmd || '', `bot ${bIndex + 1}`].filter(Boolean);
|
|
1765
1862
|
const dockerOtherAgents = teamRoster
|
|
1766
1863
|
.filter((peer) => peer.idx !== bIndex)
|
|
@@ -1779,70 +1876,44 @@ async function main() {
|
|
|
1779
1876
|
isMultiBot,
|
|
1780
1877
|
ownAliases: dockerOwnAliases,
|
|
1781
1878
|
otherAgents: dockerOtherAgents,
|
|
1782
|
-
teamRoster,
|
|
1783
|
-
userInfo,
|
|
1784
|
-
agentWorkspaceDir:
|
|
1785
|
-
isRelayBot: isMultiBot,
|
|
1786
|
-
|
|
1879
|
+
teamRoster,
|
|
1880
|
+
userInfo,
|
|
1881
|
+
agentWorkspaceDir: loopWorkspaceDir,
|
|
1882
|
+
isRelayBot: isMultiBot,
|
|
1883
|
+
replyToDirectMessages: true,
|
|
1884
|
+
});
|
|
1787
1885
|
|
|
1788
1886
|
if (isMultiBot) {
|
|
1789
1887
|
// Append per-bot reply rules to AGENTS.md
|
|
1790
1888
|
const otherBotNames = teamRoster.filter((p) => p.idx !== bIndex).map((p) => p.name);
|
|
1791
1889
|
const extraAgentsMd = isVi
|
|
1792
|
-
? `\n\n## Khi nao nen tra loi\n- Trong group, chi tra loi khi tin nhan co alias cua ban: ${dockerOwnAliases.map((a) => `\`${a}\``).join(', ')} hoac username Telegram cua ban.\n-
|
|
1793
|
-
: `\n\n## When To Reply\n- In group chats, only reply when the message contains one of your aliases: ${dockerOwnAliases.map((a) => `\`${a}\``).join(', ')} or your Telegram username.\n-
|
|
1890
|
+
? `\n\n## Khi nao nen tra loi\n- Neu metadata khong noi ro day la group/supergroup, mac dinh xem la chat rieng/DM va tra loi binh thuong.\n- Trong group, chi tra loi khi tin nhan co alias cua ban: ${dockerOwnAliases.map((a) => `\`${a}\``).join(', ')} hoac username Telegram cua ban.\n- Quy tac im lang khi tin nhan khong goi ban chi ap dung cho group chat, khong ap dung cho DM/chat rieng.\n- Neu group message chi goi ro bot khac ${otherBotNames.length ? otherBotNames.map((n) => `\`${n}\``).join(', ') : '`bot khac`'} thi khong cuop loi.\n- Gateway tu dong tha ack reaction; khong goi action react thu cong tru khi user yeu cau.\n- Khi can phoi hop noi bo, dung dung agent id ky thuat trong \`AGENTS.md\`, khong dung ten hien thi.\n- Khi hoi ve vai tro cac bot, dung \`AGENTS.md\` lam nguon su that.`
|
|
1891
|
+
: `\n\n## When To Reply\n- If metadata does not clearly say this is a group/supergroup, treat it as a private DM and reply normally.\n- In group chats, only reply when the message contains one of your aliases: ${dockerOwnAliases.map((a) => `\`${a}\``).join(', ')} or your Telegram username.\n- The stay-silent rule for messages not addressed to you applies only to group chats, never to DMs/private chats.\n- If a group message is clearly calling another bot such as ${otherBotNames.length ? otherBotNames.map((n) => `\`${n}\``).join(', ') : '`another bot`'}, do not hijack it.\n- The gateway automatically sends ack reactions; do not call react manually unless the user asks.\n- When you need internal coordination, use the exact technical agent id from \`AGENTS.md\`, not the display name.\n- Use \`AGENTS.md\` as the source of truth for team roles.`;
|
|
1794
1892
|
await fs.appendFile(path.join(dockerWorkspaceDir, 'AGENTS.md'), extraAgentsMd);
|
|
1795
1893
|
}
|
|
1796
1894
|
} // END FOR LOOP
|
|
1797
1895
|
}
|
|
1798
1896
|
|
|
1799
1897
|
// ── Chrome Debug scripts — via shared builder (same content as wizard ZIP) ─
|
|
1800
|
-
|
|
1801
|
-
await fs.writeFile(batPath, buildChromeDebugBat(), 'utf8');
|
|
1802
|
-
const shPath = path.join(projectDir, 'start-chrome-debug.sh');
|
|
1803
|
-
await fs.writeFile(shPath, buildChromeDebugSh(), 'utf8');
|
|
1804
|
-
try { await fs.chmod(shPath, 0o755); } catch (_) {}
|
|
1805
|
-
|
|
1806
|
-
// ── Uninstall script — write to project dir (native only) ─────────────────
|
|
1807
|
-
if (deployMode !== 'docker') {
|
|
1808
|
-
const _nativeOs = process.platform === 'win32' ? 'win'
|
|
1809
|
-
: process.platform === 'darwin' ? 'linux'
|
|
1810
|
-
: 'linux-desktop';
|
|
1811
|
-
const _uninstallScript = buildCLIUninstallScript({
|
|
1812
|
-
os: _nativeOs, projectDir, botName, isDocker: false,
|
|
1813
|
-
});
|
|
1814
|
-
if (_uninstallScript) {
|
|
1815
|
-
await fs.writeFile(path.join(projectDir, _uninstallScript.name), _uninstallScript.content, 'utf8');
|
|
1816
|
-
if (_uninstallScript.name.endsWith('.sh')) {
|
|
1817
|
-
try { await fs.chmod(path.join(projectDir, _uninstallScript.name), 0o755); } catch (_) {}
|
|
1818
|
-
}
|
|
1819
|
-
}
|
|
1820
|
-
}
|
|
1898
|
+
await writeGeneratedArtifacts(projectDir, buildCliChromeDebugArtifacts());
|
|
1821
1899
|
|
|
1822
|
-
// ──
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
const startBotBatContent = generateStartBotBat({
|
|
1830
|
-
projectDir,
|
|
1831
|
-
openclawHome: path.join(projectDir, '.openclaw'),
|
|
1832
|
-
is9Router: providerKey === '9router',
|
|
1833
|
-
isVi,
|
|
1834
|
-
});
|
|
1835
|
-
await fs.writeFile(startBotBatPath, startBotBatContent, 'utf8');
|
|
1900
|
+
// ── Uninstall scripts ───────────────────────────────────────────────────────
|
|
1901
|
+
await writeGeneratedArtifacts(projectDir, buildCliUninstallArtifacts({
|
|
1902
|
+
deployMode, osChoice: detectedOS, projectDir, botName,
|
|
1903
|
+
}));
|
|
1904
|
+
|
|
1905
|
+
// ── Upgrade scripts ─────────────────────────────────────────────────────────
|
|
1906
|
+
await writeGeneratedArtifacts(projectDir, buildCliUpgradeArtifacts());
|
|
1836
1907
|
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1908
|
+
// ── start-bot.bat / start-bot.sh — one-click restart scripts ─────────────
|
|
1909
|
+
// Generated for native deployments only (docker has docker compose up)
|
|
1910
|
+
if (deployMode !== 'docker') {
|
|
1911
|
+
await writeGeneratedArtifacts(projectDir, buildCliStartBotArtifacts({
|
|
1912
|
+
projectDir,
|
|
1913
|
+
openclawHome: path.join(projectDir, '.openclaw'),
|
|
1914
|
+
is9Router: providerKey === '9router',
|
|
1915
|
+
isVi,
|
|
1916
|
+
}));
|
|
1846
1917
|
|
|
1847
1918
|
console.log(chalk.cyan(
|
|
1848
1919
|
isVi
|
|
@@ -1993,7 +2064,7 @@ async function main() {
|
|
|
1993
2064
|
native9RouterSyncScriptPath = await writeNative9RouterSyncScript(projectDir);
|
|
1994
2065
|
}
|
|
1995
2066
|
|
|
1996
|
-
await ensureProjectRuntimeDirs(projectDir, isVi);
|
|
2067
|
+
await ensureProjectRuntimeDirs(projectDir, isVi);
|
|
1997
2068
|
|
|
1998
2069
|
if (isMultiBot && channelKey === 'telegram') {
|
|
1999
2070
|
installRelayPluginForProject(projectDir, isVi);
|