create-openclaw-bot 5.3.0 → 5.3.4
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/CHANGELOG.md +36 -0
- package/CHANGELOG.vi.md +36 -0
- package/README.md +11 -11
- package/README.vi.md +12 -4
- package/cli.js +426 -7
- package/package.json +1 -1
- package/patch-tray.js +7 -0
- package/setup.js +725 -77
- package/test-path.bat +4 -0
- package/tests/smoke-cli-logic.mjs +24 -15
- package/node_modules/color-convert/CHANGELOG.md +0 -54
package/cli.js
CHANGED
|
@@ -188,10 +188,12 @@ function spawnBackgroundProcess(command, args, options = {}) {
|
|
|
188
188
|
|
|
189
189
|
function resolveNative9RouterDesktopLaunch() {
|
|
190
190
|
// Use installed 9router CLI directly (more reliable than finding server.js in npm dirs)
|
|
191
|
+
// NOTE: -l (stdin listen mode) is intentionally omitted — it causes hangs when there is
|
|
192
|
+
// no interactive TTY (background spawned process, wizard-generated bat, etc.)
|
|
191
193
|
const routerBin = resolveCommandOnPath('9router') || '9router';
|
|
192
194
|
return {
|
|
193
195
|
command: routerBin,
|
|
194
|
-
args: ['-n', '-
|
|
196
|
+
args: ['-n', '-H', '0.0.0.0', '-p', '20128', '--skip-update'],
|
|
195
197
|
env: {
|
|
196
198
|
PORT: '20128',
|
|
197
199
|
HOSTNAME: '0.0.0.0'
|
|
@@ -449,31 +451,57 @@ const sync = async () => {
|
|
|
449
451
|
let db = {};
|
|
450
452
|
try { db = JSON.parse(fs.readFileSync(p, 'utf8')); } catch(e) {}
|
|
451
453
|
if (!db.combos) db.combos = [];
|
|
452
|
-
const
|
|
454
|
+
const resCombo = await fetch(ROUTER + '/api/combos').catch(() => null);
|
|
455
|
+
let memoryCombos = [];
|
|
456
|
+
if (resCombo && resCombo.ok) {
|
|
457
|
+
const cData = await resCombo.json();
|
|
458
|
+
memoryCombos = cData.combos || [];
|
|
459
|
+
}
|
|
460
|
+
const removeSmartRoute = async () => {
|
|
453
461
|
const next = db.combos.filter(x => x.id !== 'smart-route');
|
|
454
462
|
if (next.length !== db.combos.length) {
|
|
455
463
|
db.combos = next;
|
|
456
464
|
fs.writeFileSync(p, JSON.stringify(db, null, 2));
|
|
457
465
|
console.log('[sync-combo] Removed smart-route (no active providers)');
|
|
458
466
|
}
|
|
467
|
+
if (memoryCombos.find(x => x.id === 'smart-route')) {
|
|
468
|
+
await fetch(ROUTER + '/api/combos/smart-route', { method: 'DELETE' }).catch(()=>{});
|
|
469
|
+
console.log('[sync-combo] Removed smart-route from 9Router memory');
|
|
470
|
+
}
|
|
459
471
|
};
|
|
460
|
-
if (!a.length) { removeSmartRoute(); return; }
|
|
472
|
+
if (!a.length) { await removeSmartRoute(); return; }
|
|
461
473
|
const PREF = ['openai','anthropic','claude-code','codex','cursor','github','cline','kimi','minimax','deepseek','glm','alicode','xai','mistral','kilo','kiro','iflow','qwen','gemini-cli','ollama'];
|
|
462
474
|
a.sort((x, y) => (PREF.indexOf(x) === -1 ? 99 : PREF.indexOf(x)) - (PREF.indexOf(y) === -1 ? 99 : PREF.indexOf(y)));
|
|
463
475
|
const m = a.flatMap(pv => PM[pv] || []);
|
|
464
|
-
if (!m.length) { removeSmartRoute(); return; }
|
|
476
|
+
if (!m.length) { await removeSmartRoute(); return; }
|
|
465
477
|
const c = { id: 'smart-route', name: 'smart-route', alias: 'smart-route', models: m };
|
|
466
478
|
const i = db.combos.findIndex(x => x.id === 'smart-route');
|
|
479
|
+
let dbUpdated = false;
|
|
467
480
|
if (i >= 0) {
|
|
468
481
|
if (JSON.stringify(db.combos[i].models) !== JSON.stringify(c.models)) {
|
|
469
482
|
db.combos[i] = c;
|
|
470
483
|
fs.writeFileSync(p, JSON.stringify(db, null, 2));
|
|
471
|
-
|
|
484
|
+
dbUpdated = true;
|
|
472
485
|
}
|
|
473
486
|
} else {
|
|
474
487
|
db.combos.push(c);
|
|
475
488
|
fs.writeFileSync(p, JSON.stringify(db, null, 2));
|
|
476
|
-
|
|
489
|
+
dbUpdated = true;
|
|
490
|
+
}
|
|
491
|
+
const inMemory = memoryCombos.find(x => x.id === 'smart-route');
|
|
492
|
+
let memUpdated = false;
|
|
493
|
+
if (inMemory) {
|
|
494
|
+
if (JSON.stringify(inMemory.models) !== JSON.stringify(c.models)) {
|
|
495
|
+
await fetch(ROUTER + '/api/combos/smart-route', { method: 'DELETE' }).catch(()=>{});
|
|
496
|
+
await fetch(ROUTER + '/api/combos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(c) }).catch(()=>{});
|
|
497
|
+
memUpdated = true;
|
|
498
|
+
}
|
|
499
|
+
} else {
|
|
500
|
+
await fetch(ROUTER + '/api/combos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(c) }).catch(()=>{});
|
|
501
|
+
memUpdated = true;
|
|
502
|
+
}
|
|
503
|
+
if (dbUpdated || memUpdated) {
|
|
504
|
+
console.log('[sync-combo] Synced smart-route (Memory+Disk): ' + c.models.length + ' models from: ' + a.join(','));
|
|
477
505
|
}
|
|
478
506
|
} catch(e) { console.log('[sync-combo] Error:', e.message); }
|
|
479
507
|
};
|
|
@@ -576,7 +604,9 @@ function build9RouterComposeEntrypointScript(syncScriptBase64) {
|
|
|
576
604
|
}
|
|
577
605
|
|
|
578
606
|
async function writeNative9RouterSyncScript(projectDir) {
|
|
579
|
-
|
|
607
|
+
// Write to .9router/ (DATA_DIR) so 9router's own data dir has the sync helper,
|
|
608
|
+
// keeping .openclaw/ focused on openclaw configs only.
|
|
609
|
+
const syncScriptPath = path.join(projectDir, '.9router', '9router-smart-route-sync.js');
|
|
580
610
|
await fs.ensureDir(path.dirname(syncScriptPath));
|
|
581
611
|
await fs.writeFile(syncScriptPath, build9RouterSmartRouteSyncScript(path.join(getProject9RouterDataDir(projectDir), 'db.json')));
|
|
582
612
|
return syncScriptPath;
|
|
@@ -2537,6 +2567,357 @@ const { chromium } = require('playwright');
|
|
|
2537
2567
|
} // END FOR LOOP
|
|
2538
2568
|
}
|
|
2539
2569
|
|
|
2570
|
+
// ── Uninstall scripts — generated per OS / deploy mode ─────────────────────
|
|
2571
|
+
{
|
|
2572
|
+
const absProjectDir = projectDir.replace(/\\/g, '\\\\');
|
|
2573
|
+
const unixProjectDir = projectDir.replace(/\\/g, '/');
|
|
2574
|
+
|
|
2575
|
+
if (deployMode === 'native') {
|
|
2576
|
+
// ── Windows .bat uninstall ──────────────────────────────────────────────
|
|
2577
|
+
if (osChoice === 'windows') {
|
|
2578
|
+
const winUninstall = `@echo off
|
|
2579
|
+
setlocal EnableExtensions
|
|
2580
|
+
chcp 65001 >nul
|
|
2581
|
+
echo.
|
|
2582
|
+
echo ============================================================
|
|
2583
|
+
echo OpenClaw Uninstaller - Windows Native
|
|
2584
|
+
echo Project: ${absProjectDir}
|
|
2585
|
+
echo ============================================================
|
|
2586
|
+
echo.
|
|
2587
|
+
echo [WARNING] This will:
|
|
2588
|
+
echo 1. Kill openclaw and 9router background processes
|
|
2589
|
+
echo 2. Uninstall global npm packages (openclaw, 9router, pm2)
|
|
2590
|
+
echo 3. Delete the project folder and all its data
|
|
2591
|
+
echo.
|
|
2592
|
+
set /p CONFIRM=Nhap YES de xac nhan xoa toan bo:
|
|
2593
|
+
if /i not "%CONFIRM%"=="YES" (
|
|
2594
|
+
echo Huy bo. Khong xoa gi ca.
|
|
2595
|
+
pause
|
|
2596
|
+
exit /b 0
|
|
2597
|
+
)
|
|
2598
|
+
echo.
|
|
2599
|
+
echo [1/4] Dang dung cac tien trinh openclaw va 9router...
|
|
2600
|
+
taskkill /F /IM openclaw.exe >nul 2>&1
|
|
2601
|
+
taskkill /F /IM 9router.exe >nul 2>&1
|
|
2602
|
+
:: Kill Node.js processes spawned from project dir
|
|
2603
|
+
powershell -NoProfile -Command "Get-Process node -ErrorAction SilentlyContinue | Where-Object { $_.Path -like '*${absProjectDir}*' } | Stop-Process -Force" >nul 2>&1
|
|
2604
|
+
:: Kill processes listening on ports 18791 and 20128
|
|
2605
|
+
powershell -NoProfile -Command "& { $p=@(18791,20128); foreach($port in $p){ $id=(netstat -ano | Select-String \":$port \").Line -split ' +' | Select-Object -Last 1; if($id -and $id -ne '0'){ Stop-Process -Id $id -Force -ErrorAction SilentlyContinue } } }" >nul 2>&1
|
|
2606
|
+
echo OK: Tien trinh da dung.
|
|
2607
|
+
echo.
|
|
2608
|
+
echo [2/4] Dang go cai npm packages toan cau...
|
|
2609
|
+
set "PATH=%APPDATA%\\npm;%PATH%"
|
|
2610
|
+
call npm uninstall -g openclaw 9router grammy @grammyjs/runner @grammyjs/transformer-throttler @buape/carbon @larksuiteoapi/node-sdk @slack/web-api 2>nul
|
|
2611
|
+
echo OK: npm packages da duoc go cai.
|
|
2612
|
+
echo.
|
|
2613
|
+
echo [3/4] Xoa thu muc project...
|
|
2614
|
+
set "TARGET=${absProjectDir}"
|
|
2615
|
+
if exist "%TARGET%" (
|
|
2616
|
+
rd /s /q "%TARGET%"
|
|
2617
|
+
echo OK: Da xoa %TARGET%
|
|
2618
|
+
) else (
|
|
2619
|
+
echo INFO: Thu muc khong ton tai: %TARGET%
|
|
2620
|
+
)
|
|
2621
|
+
echo.
|
|
2622
|
+
echo [4/4] Xoa thu muc .9router va .openclaw trong Home (neu co)...
|
|
2623
|
+
if exist "%USERPROFILE%\\.9router" (
|
|
2624
|
+
set /p CLEAN_HOME=Xoa ca %USERPROFILE%\\.9router? [YES/no]:
|
|
2625
|
+
if /i "%CLEAN_HOME%"=="YES" rd /s /q "%USERPROFILE%\\.9router" >nul 2>&1
|
|
2626
|
+
)
|
|
2627
|
+
echo.
|
|
2628
|
+
echo ============================================================
|
|
2629
|
+
echo Go cai hoan tat!
|
|
2630
|
+
echo De cai lai: chay lai file setup hoac npx create-openclaw-bot
|
|
2631
|
+
echo ============================================================
|
|
2632
|
+
pause
|
|
2633
|
+
`;
|
|
2634
|
+
await fs.writeFile(path.join(projectDir, 'uninstall-openclaw-win.bat'), winUninstall);
|
|
2635
|
+
console.log(chalk.gray(isVi
|
|
2636
|
+
? ` 📄 File go cai: ${path.join(projectDir, 'uninstall-openclaw-win.bat')}`
|
|
2637
|
+
: ` 📄 Uninstall script: ${path.join(projectDir, 'uninstall-openclaw-win.bat')}`));
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
// ── Linux/macOS desktop .sh uninstall ──────────────────────────────────
|
|
2641
|
+
if (osChoice === 'macos' || osChoice === 'ubuntu') {
|
|
2642
|
+
const desktopUninstall = `#!/usr/bin/env bash
|
|
2643
|
+
# ====== OpenClaw Uninstaller — macOS / Linux Desktop ======
|
|
2644
|
+
set -e
|
|
2645
|
+
PROJECT_DIR="${unixProjectDir}"
|
|
2646
|
+
|
|
2647
|
+
echo ""
|
|
2648
|
+
echo "============================================================"
|
|
2649
|
+
echo " OpenClaw Uninstaller — Native (macOS/Linux Desktop)"
|
|
2650
|
+
echo " Project: $PROJECT_DIR"
|
|
2651
|
+
echo "============================================================"
|
|
2652
|
+
echo ""
|
|
2653
|
+
echo "WARNING: This will:"
|
|
2654
|
+
echo " 1. Kill openclaw and 9router processes"
|
|
2655
|
+
echo " 2. Uninstall global npm packages (openclaw, 9router)"
|
|
2656
|
+
echo " 3. Delete the project folder and all its data"
|
|
2657
|
+
echo ""
|
|
2658
|
+
read -rp "Type YES to confirm full removal: " CONFIRM
|
|
2659
|
+
if [ "$CONFIRM" != "YES" ]; then
|
|
2660
|
+
echo "Cancelled. Nothing was deleted."
|
|
2661
|
+
exit 0
|
|
2662
|
+
fi
|
|
2663
|
+
|
|
2664
|
+
echo ""
|
|
2665
|
+
echo "[1/4] Stopping openclaw and 9router processes..."
|
|
2666
|
+
pkill -f "openclaw gateway run" 2>/dev/null || true
|
|
2667
|
+
pkill -f "9router.*20128" 2>/dev/null || true
|
|
2668
|
+
pkill -f "9router-smart-route" 2>/dev/null || true
|
|
2669
|
+
# Kill any node process inside the project dir
|
|
2670
|
+
pkill -f "$PROJECT_DIR" 2>/dev/null || true
|
|
2671
|
+
# Kill processes on port 18791 and 20128
|
|
2672
|
+
for port in 18791 20128; do
|
|
2673
|
+
pid=$(lsof -ti tcp:$port 2>/dev/null || true)
|
|
2674
|
+
[ -n "$pid" ] && kill -9 $pid 2>/dev/null || true
|
|
2675
|
+
done
|
|
2676
|
+
echo " OK: Processes stopped."
|
|
2677
|
+
|
|
2678
|
+
echo ""
|
|
2679
|
+
echo "[2/4] Uninstalling global npm packages..."
|
|
2680
|
+
npm uninstall -g openclaw 9router grammy @grammyjs/runner @grammyjs/transformer-throttler @buape/carbon @larksuiteoapi/node-sdk @slack/web-api 2>/dev/null || true
|
|
2681
|
+
# Also try with sudo if the above fails (system npm prefix)
|
|
2682
|
+
sudo npm uninstall -g openclaw 9router 2>/dev/null || true
|
|
2683
|
+
echo " OK: npm packages removed."
|
|
2684
|
+
|
|
2685
|
+
echo ""
|
|
2686
|
+
echo "[3/4] Removing project directory..."
|
|
2687
|
+
if [ -d "$PROJECT_DIR" ]; then
|
|
2688
|
+
rm -rf "$PROJECT_DIR"
|
|
2689
|
+
echo " OK: Deleted $PROJECT_DIR"
|
|
2690
|
+
else
|
|
2691
|
+
echo " INFO: Directory not found: $PROJECT_DIR"
|
|
2692
|
+
fi
|
|
2693
|
+
|
|
2694
|
+
echo ""
|
|
2695
|
+
echo "[4/4] Checking for home-level .9router / .openclaw..."
|
|
2696
|
+
for dir in "$HOME/.9router" "$HOME/.openclaw"; do
|
|
2697
|
+
if [ -d "$dir" ]; then
|
|
2698
|
+
read -rp "Delete $dir ? [YES/no]: " CLEAN
|
|
2699
|
+
if [ "$CLEAN" = "YES" ]; then
|
|
2700
|
+
rm -rf "$dir"
|
|
2701
|
+
echo " OK: Deleted $dir"
|
|
2702
|
+
else
|
|
2703
|
+
echo " Kept: $dir"
|
|
2704
|
+
fi
|
|
2705
|
+
fi
|
|
2706
|
+
done
|
|
2707
|
+
|
|
2708
|
+
echo ""
|
|
2709
|
+
echo "============================================================"
|
|
2710
|
+
echo " Uninstall complete!"
|
|
2711
|
+
echo " To reinstall: run the setup script or npx create-openclaw-bot"
|
|
2712
|
+
echo "============================================================"
|
|
2713
|
+
`;
|
|
2714
|
+
const desktopShPath = path.join(projectDir, 'uninstall-openclaw.sh');
|
|
2715
|
+
await fs.writeFile(desktopShPath, desktopUninstall);
|
|
2716
|
+
try { await fs.chmod(desktopShPath, 0o755); } catch (_) {}
|
|
2717
|
+
console.log(chalk.gray(isVi
|
|
2718
|
+
? ` 📄 File go cai: ${desktopShPath}`
|
|
2719
|
+
: ` 📄 Uninstall script: ${desktopShPath}`));
|
|
2720
|
+
}
|
|
2721
|
+
|
|
2722
|
+
// ── VPS / PM2 .sh uninstall ─────────────────────────────────────────────
|
|
2723
|
+
if (osChoice === 'vps') {
|
|
2724
|
+
const vpsUninstall = `#!/usr/bin/env bash
|
|
2725
|
+
# ====== OpenClaw Uninstaller — VPS / Ubuntu Server (PM2) ======
|
|
2726
|
+
set -e
|
|
2727
|
+
PROJECT_DIR="${unixProjectDir}"
|
|
2728
|
+
APP_NAME="${(botName || 'openclaw').toLowerCase().replace(/[^a-z0-9]+/g, '-')}"
|
|
2729
|
+
|
|
2730
|
+
echo ""
|
|
2731
|
+
echo "============================================================"
|
|
2732
|
+
echo " OpenClaw Uninstaller — VPS / Ubuntu Server"
|
|
2733
|
+
echo " Project: $PROJECT_DIR"
|
|
2734
|
+
echo " PM2 app: $APP_NAME"
|
|
2735
|
+
echo "============================================================"
|
|
2736
|
+
echo ""
|
|
2737
|
+
echo "WARNING: This will:"
|
|
2738
|
+
echo " 1. Stop and delete all PM2 processes for this bot"
|
|
2739
|
+
echo " 2. Uninstall global npm packages (openclaw, 9router, pm2)"
|
|
2740
|
+
echo " 3. Delete the project folder and all its data"
|
|
2741
|
+
echo ""
|
|
2742
|
+
read -rp "Type YES to confirm full removal: " CONFIRM
|
|
2743
|
+
if [ "$CONFIRM" != "YES" ]; then
|
|
2744
|
+
echo "Cancelled. Nothing was deleted."
|
|
2745
|
+
exit 0
|
|
2746
|
+
fi
|
|
2747
|
+
|
|
2748
|
+
echo ""
|
|
2749
|
+
echo "[1/5] Stopping and deleting PM2 processes..."
|
|
2750
|
+
if command -v pm2 &>/dev/null; then
|
|
2751
|
+
pm2 delete "$APP_NAME" 2>/dev/null || true
|
|
2752
|
+
pm2 delete "$APP_NAME-9router" 2>/dev/null || true
|
|
2753
|
+
pm2 delete "$APP_NAME-9router-sync" 2>/dev/null || true
|
|
2754
|
+
pm2 delete "openclaw" 2>/dev/null || true
|
|
2755
|
+
pm2 delete "openclaw-multibot" 2>/dev/null || true
|
|
2756
|
+
pm2 save --force 2>/dev/null || true
|
|
2757
|
+
echo " OK: PM2 processes removed."
|
|
2758
|
+
else
|
|
2759
|
+
echo " INFO: PM2 not found — skipping."
|
|
2760
|
+
fi
|
|
2761
|
+
|
|
2762
|
+
echo ""
|
|
2763
|
+
echo "[2/5] Killing any remaining processes on port 18791 / 20128..."
|
|
2764
|
+
for port in 18791 20128; do
|
|
2765
|
+
pid=$(lsof -ti tcp:$port 2>/dev/null || true)
|
|
2766
|
+
[ -n "$pid" ] && kill -9 $pid 2>/dev/null || true
|
|
2767
|
+
done
|
|
2768
|
+
echo " OK: Ports cleared."
|
|
2769
|
+
|
|
2770
|
+
echo ""
|
|
2771
|
+
echo "[3/5] Uninstalling global npm packages..."
|
|
2772
|
+
npm uninstall -g openclaw 9router pm2 grammy @grammyjs/runner @grammyjs/transformer-throttler @buape/carbon @larksuiteoapi/node-sdk @slack/web-api 2>/dev/null || true
|
|
2773
|
+
echo " OK: npm packages removed."
|
|
2774
|
+
|
|
2775
|
+
echo ""
|
|
2776
|
+
echo "[4/5] Removing project directory..."
|
|
2777
|
+
if [ -d "$PROJECT_DIR" ]; then
|
|
2778
|
+
rm -rf "$PROJECT_DIR"
|
|
2779
|
+
echo " OK: Deleted $PROJECT_DIR"
|
|
2780
|
+
else
|
|
2781
|
+
echo " INFO: Directory not found: $PROJECT_DIR"
|
|
2782
|
+
fi
|
|
2783
|
+
|
|
2784
|
+
echo ""
|
|
2785
|
+
echo "[5/5] Checking for home-level .9router / .openclaw..."
|
|
2786
|
+
for dir in "$HOME/.9router" "$HOME/.openclaw"; do
|
|
2787
|
+
if [ -d "$dir" ]; then
|
|
2788
|
+
read -rp "Delete $dir ? [YES/no]: " CLEAN
|
|
2789
|
+
if [ "$CLEAN" = "YES" ]; then
|
|
2790
|
+
rm -rf "$dir"
|
|
2791
|
+
echo " OK: Deleted $dir"
|
|
2792
|
+
else
|
|
2793
|
+
echo " Kept: $dir"
|
|
2794
|
+
fi
|
|
2795
|
+
fi
|
|
2796
|
+
done
|
|
2797
|
+
|
|
2798
|
+
echo ""
|
|
2799
|
+
echo "============================================================"
|
|
2800
|
+
echo " Uninstall complete!"
|
|
2801
|
+
echo " To reinstall: npx create-openclaw-bot@latest"
|
|
2802
|
+
echo "============================================================"
|
|
2803
|
+
`;
|
|
2804
|
+
const vpsShPath = path.join(projectDir, 'uninstall-openclaw-vps.sh');
|
|
2805
|
+
await fs.writeFile(vpsShPath, vpsUninstall);
|
|
2806
|
+
try { await fs.chmod(vpsShPath, 0o755); } catch (_) {}
|
|
2807
|
+
console.log(chalk.gray(isVi
|
|
2808
|
+
? ` 📄 File go cai VPS: ${vpsShPath}`
|
|
2809
|
+
: ` 📄 VPS uninstall script: ${vpsShPath}`));
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2812
|
+
} else {
|
|
2813
|
+
// ── Docker uninstall .sh ────────────────────────────────────────────────
|
|
2814
|
+
const dockerUninstall = `#!/usr/bin/env bash
|
|
2815
|
+
# ====== OpenClaw Uninstaller — Docker ======
|
|
2816
|
+
set -e
|
|
2817
|
+
PROJECT_DIR="${unixProjectDir}"
|
|
2818
|
+
DOCKER_DIR="$PROJECT_DIR/docker/openclaw"
|
|
2819
|
+
|
|
2820
|
+
echo ""
|
|
2821
|
+
echo "============================================================"
|
|
2822
|
+
echo " OpenClaw Uninstaller — Docker"
|
|
2823
|
+
echo " Project: $PROJECT_DIR"
|
|
2824
|
+
echo "============================================================"
|
|
2825
|
+
echo ""
|
|
2826
|
+
echo "WARNING: This will:"
|
|
2827
|
+
echo " 1. Stop and remove all Docker containers + volumes"
|
|
2828
|
+
echo " 2. Delete the project folder and all its data"
|
|
2829
|
+
echo ""
|
|
2830
|
+
read -rp "Type YES to confirm full removal: " CONFIRM
|
|
2831
|
+
if [ "$CONFIRM" != "YES" ]; then
|
|
2832
|
+
echo "Cancelled. Nothing was deleted."
|
|
2833
|
+
exit 0
|
|
2834
|
+
fi
|
|
2835
|
+
|
|
2836
|
+
echo ""
|
|
2837
|
+
echo "[1/3] Stopping Docker containers and removing volumes..."
|
|
2838
|
+
if [ -d "$DOCKER_DIR" ] && command -v docker &>/dev/null; then
|
|
2839
|
+
cd "$DOCKER_DIR"
|
|
2840
|
+
docker compose down --volumes --remove-orphans 2>/dev/null || docker-compose down --volumes --remove-orphans 2>/dev/null || true
|
|
2841
|
+
echo " OK: Containers + volumes removed."
|
|
2842
|
+
else
|
|
2843
|
+
echo " INFO: Docker dir not found or docker not installed — skipping."
|
|
2844
|
+
fi
|
|
2845
|
+
|
|
2846
|
+
echo ""
|
|
2847
|
+
echo "[2/3] Removing project directory..."
|
|
2848
|
+
if [ -d "$PROJECT_DIR" ]; then
|
|
2849
|
+
rm -rf "$PROJECT_DIR"
|
|
2850
|
+
echo " OK: Deleted $PROJECT_DIR"
|
|
2851
|
+
else
|
|
2852
|
+
echo " INFO: Directory not found: $PROJECT_DIR"
|
|
2853
|
+
fi
|
|
2854
|
+
|
|
2855
|
+
echo ""
|
|
2856
|
+
echo "[3/3] Checking for home-level .openclaw..."
|
|
2857
|
+
if [ -d "$HOME/.openclaw" ]; then
|
|
2858
|
+
read -rp "Delete $HOME/.openclaw? [YES/no]: " CLEAN
|
|
2859
|
+
if [ "$CLEAN" = "YES" ]; then
|
|
2860
|
+
rm -rf "$HOME/.openclaw"
|
|
2861
|
+
echo " OK: Deleted $HOME/.openclaw"
|
|
2862
|
+
else
|
|
2863
|
+
echo " Kept: $HOME/.openclaw"
|
|
2864
|
+
fi
|
|
2865
|
+
fi
|
|
2866
|
+
|
|
2867
|
+
echo ""
|
|
2868
|
+
echo "============================================================"
|
|
2869
|
+
echo " Uninstall complete!"
|
|
2870
|
+
echo " To reinstall: npx create-openclaw-bot@latest"
|
|
2871
|
+
echo "============================================================"
|
|
2872
|
+
`;
|
|
2873
|
+
const dockerShPath = path.join(projectDir, 'uninstall-openclaw-docker.sh');
|
|
2874
|
+
await fs.writeFile(dockerShPath, dockerUninstall);
|
|
2875
|
+
try { await fs.chmod(dockerShPath, 0o755); } catch (_) {}
|
|
2876
|
+
|
|
2877
|
+
// Windows .bat for docker uninstall
|
|
2878
|
+
const dockerWinUninstall = `@echo off
|
|
2879
|
+
setlocal EnableExtensions
|
|
2880
|
+
chcp 65001 >nul
|
|
2881
|
+
echo.
|
|
2882
|
+
echo ============================================================
|
|
2883
|
+
echo OpenClaw Uninstaller - Docker (Windows)
|
|
2884
|
+
echo Project: ${absProjectDir}
|
|
2885
|
+
echo ============================================================
|
|
2886
|
+
echo.
|
|
2887
|
+
echo [WARNING] This will stop Docker containers and delete the project folder.
|
|
2888
|
+
echo.
|
|
2889
|
+
set /p CONFIRM=Nhap YES de xac nhan xoa toan bo:
|
|
2890
|
+
if /i not "%CONFIRM%"=="YES" (
|
|
2891
|
+
echo Huy bo. Khong xoa gi ca.
|
|
2892
|
+
pause
|
|
2893
|
+
exit /b 0
|
|
2894
|
+
)
|
|
2895
|
+
echo.
|
|
2896
|
+
echo [1/2] Dang dung Docker containers...
|
|
2897
|
+
cd /d "${absProjectDir}\\docker\\openclaw" 2>nul && (
|
|
2898
|
+
docker compose down --volumes --remove-orphans 2>nul || docker-compose down --volumes --remove-orphans 2>nul
|
|
2899
|
+
echo OK: Containers da dung.
|
|
2900
|
+
) || echo INFO: Khong tim thay docker compose.
|
|
2901
|
+
echo.
|
|
2902
|
+
echo [2/2] Xoa thu muc project...
|
|
2903
|
+
cd /d "%USERPROFILE%"
|
|
2904
|
+
if exist "${absProjectDir}" (
|
|
2905
|
+
rd /s /q "${absProjectDir}"
|
|
2906
|
+
echo OK: Da xoa ${absProjectDir}
|
|
2907
|
+
)
|
|
2908
|
+
echo.
|
|
2909
|
+
echo ============================================================
|
|
2910
|
+
echo Go cai hoan tat! De cai lai: npx create-openclaw-bot@latest
|
|
2911
|
+
echo ============================================================
|
|
2912
|
+
pause
|
|
2913
|
+
`;
|
|
2914
|
+
await fs.writeFile(path.join(projectDir, 'uninstall-openclaw-docker.bat'), dockerWinUninstall);
|
|
2915
|
+
console.log(chalk.gray(isVi
|
|
2916
|
+
? ` 📄 File go cai Docker: ${dockerShPath}`
|
|
2917
|
+
: ` 📄 Docker uninstall script: ${dockerShPath}`));
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2540
2921
|
// ── Chrome Debug scripts — always created (user may need browser later)
|
|
2541
2922
|
const batPath = path.join(projectDir, 'start-chrome-debug.bat');
|
|
2542
2923
|
await fs.writeFile(batPath, `@echo off
|
|
@@ -2817,6 +3198,44 @@ fi
|
|
|
2817
3198
|
} else {
|
|
2818
3199
|
if (providerKey === '9router') {
|
|
2819
3200
|
console.log(chalk.yellow(`\n${isVi ? 'Khoi dong 9Router native (background)...' : 'Starting native 9Router (background)...'}`));
|
|
3201
|
+
|
|
3202
|
+
// ── Pre-seed DATA_DIR + db.json BEFORE launching 9Router ──────────────
|
|
3203
|
+
// 9Router reads DATA_DIR on startup to find its db. If we don't set this
|
|
3204
|
+
// first it falls back to its own default (~/.9router) and requireLogin
|
|
3205
|
+
// defaults to true, causing the dashboard login wall.
|
|
3206
|
+
const routerDataDir = getProject9RouterDataDir(projectDir);
|
|
3207
|
+
try {
|
|
3208
|
+
await fs.ensureDir(routerDataDir);
|
|
3209
|
+
const dbPath = path.join(routerDataDir, 'db.json');
|
|
3210
|
+
if (!fs.existsSync(dbPath)) {
|
|
3211
|
+
await fs.writeJson(dbPath, {
|
|
3212
|
+
providerConnections: [],
|
|
3213
|
+
providerNodes: [],
|
|
3214
|
+
proxyPools: [],
|
|
3215
|
+
modelAliases: {},
|
|
3216
|
+
mitmAlias: {},
|
|
3217
|
+
combos: [],
|
|
3218
|
+
apiKeys: [],
|
|
3219
|
+
settings: {
|
|
3220
|
+
requireLogin: false,
|
|
3221
|
+
cloudEnabled: false,
|
|
3222
|
+
tunnelEnabled: false,
|
|
3223
|
+
comboStrategy: 'fallback',
|
|
3224
|
+
mitmRouterBaseUrl: 'http://localhost:20128'
|
|
3225
|
+
},
|
|
3226
|
+
pricing: {}
|
|
3227
|
+
}, { spaces: 2 });
|
|
3228
|
+
console.log(chalk.gray(isVi
|
|
3229
|
+
? ` ✅ Pre-seeded db.json (requireLogin: false) tại: ${dbPath}`
|
|
3230
|
+
: ` ✅ Pre-seeded db.json (requireLogin: false) at: ${dbPath}`));
|
|
3231
|
+
}
|
|
3232
|
+
} catch (err) {
|
|
3233
|
+
console.log(chalk.yellow(isVi
|
|
3234
|
+
? ` ⚠️ Khong the pre-seed db.json: ${err?.message}. 9Router van se khoi dong.`
|
|
3235
|
+
: ` ⚠️ Could not pre-seed db.json: ${err?.message}. 9Router will still start.`));
|
|
3236
|
+
}
|
|
3237
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
3238
|
+
|
|
2820
3239
|
const native9RouterLaunch = resolveNative9RouterDesktopLaunch();
|
|
2821
3240
|
spawnBackgroundProcess(native9RouterLaunch.command, native9RouterLaunch.args, {
|
|
2822
3241
|
cwd: projectDir,
|
package/package.json
CHANGED
package/patch-tray.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
let b = fs.readFileSync('C:/Users/Admin/Downloads/setup-openclaw-win.bat', 'utf8');
|
|
3
|
+
const before = '9router -n -H 0.0.0.0 -p 20128 --skip-update"';
|
|
4
|
+
const after = '9router -n -H 0.0.0.0 -p 20128 --skip-update --tray"';
|
|
5
|
+
b = b.split(before).join(after);
|
|
6
|
+
fs.writeFileSync('C:/Users/Admin/Downloads/setup-openclaw-win.bat', b);
|
|
7
|
+
console.log('Fixed! Has --tray:', b.includes('--tray'));
|