Files
QwenClaw-with-Auth/scripts/install-qwenclaw.js

314 lines
8.3 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* QwenClaw Installer for Qwen Code
*
* This script installs and configures QwenClaw as the default agent for Qwen Code.
*
* Usage: bun run install-qwenclaw.js
*/
import { spawn, execSync } from "child_process";
import { join } from "path";
import { existsSync, readFileSync, writeFile, mkdirSync } from "fs";
const QWENCLAW_DIR = join(process.env.HOME || process.env.USERPROFILE || "", "qwenclaw");
const QWEN_DIR = join(process.env.HOME || process.env.USERPROFILE || "", ".qwen");
const QWEN_SETTINGS_FILE = join(QWEN_DIR, "settings.json");
const QWEN_MCP_FILE = join(QWEN_DIR, "mcp.json");
const COLORS = {
cyan: "\x1b[36m",
green: "\x1b[32m",
yellow: "\x1b[33m",
red: "\x1b[31m",
magenta: "\x1b[35m",
reset: "\x1b[0m",
};
function log(message, color = "reset") {
console.log(`${COLORS[color]}${message}${COLORS.reset}`);
}
function showBanner() {
log("\n" + "═".repeat(60), "cyan");
log(" 🐾 QWENCLAW INSTALLER FOR QWEN CODE", "cyan");
log("═".repeat(60), "cyan");
}
/**
* Check if QwenClaw is installed
*/
function checkInstallation() {
log("\n📦 Checking QwenClaw installation...", "cyan");
if (!existsSync(QWENCLAW_DIR)) {
log("❌ QwenClaw not found at: " + QWENCLAW_DIR, "red");
log("\n📥 Installing QwenClaw...", "yellow");
try {
const repoUrl = "https://github.rommark.dev/admin/QwenClaw-with-Auth.git";
execSync(`git clone ${repoUrl} "${QWENCLAW_DIR}"`, { stdio: "inherit" });
log("✅ QwenClaw cloned successfully", "green");
} catch (err) {
log(`❌ Failed to clone: ${err.message}`, "red");
process.exit(1);
}
} else {
log("✅ QwenClaw found at: " + QWENCLAW_DIR, "green");
}
// Install dependencies
log("\n📦 Installing dependencies...", "cyan");
try {
execSync(`cd "${QWENCLAW_DIR}" && bun install`, { stdio: "inherit" });
log("✅ Dependencies installed", "green");
} catch (err) {
log(`❌ Failed to install dependencies: ${err.message}`, "red");
process.exit(1);
}
// Install Playwright browsers
log("\n🌐 Installing Playwright browsers...", "cyan");
try {
execSync(`cd "${QWENCLAW_DIR}" && npx playwright install chromium`, { stdio: "inherit" });
log("✅ Playwright browsers installed", "green");
} catch (err) {
log(`⚠️ Playwright installation skipped: ${err.message}`, "yellow");
}
}
/**
* Create Qwen directory if needed
*/
function ensureQwenDir() {
log("\n📁 Ensuring Qwen directory exists...", "cyan");
if (!existsSync(QWEN_DIR)) {
mkdirSync(QWEN_DIR, { recursive: true });
log("✅ Created Qwen directory: " + QWEN_DIR, "green");
} else {
log("✅ Qwen directory exists", "green");
}
// Create qwenclaw subdirectory
const qwenclawDataDir = join(QWEN_DIR, "qwenclaw");
if (!existsSync(qwenclawDataDir)) {
mkdirSync(qwenclawDataDir, { recursive: true });
log("✅ Created QwenClaw data directory", "green");
}
}
/**
* Update Qwen Code settings
*/
function updateSettings() {
log("\n⚙ Configuring Qwen Code settings...", "cyan");
let settings = {};
if (existsSync(QWEN_SETTINGS_FILE)) {
try {
const content = readFileSync(QWEN_SETTINGS_FILE, "utf-8");
settings = JSON.parse(content);
log("✅ Loaded existing settings", "green");
} catch (err) {
log(`⚠️ Warning: Could not parse settings.json`, "yellow");
}
}
// Configure skills
if (!settings.skills) {
settings.skills = {};
}
if (!settings.skills.enabled) {
settings.skills.enabled = [];
}
const requiredSkills = [
"qwenclaw-integration",
"gui-automation",
"qwenbot-integration",
];
for (const skill of requiredSkills) {
if (!settings.skills.enabled.includes(skill)) {
settings.skills.enabled.push(skill);
log(` + Enabled skill: ${skill}`, "green");
}
}
settings.skills.default = "qwenclaw-integration";
log(" ✓ Set default skill: qwenclaw-integration", "green");
// Configure agents
if (!settings.agents) {
settings.agents = {};
}
settings.agents.default = "qwenclaw";
settings.agents.qwenclaw = {
name: "QwenClaw",
description: "Persistent AI assistant daemon with automation capabilities",
autoStart: true,
skills: ["qwenclaw-integration", "gui-automation", "qwenbot-integration"],
};
log(" ✓ Set default agent: qwenclaw", "green");
// Configure MCP servers
if (!settings.mcpServers) {
settings.mcpServers = {};
}
settings.mcpServers.qwenclaw = {
command: "bun",
args: ["run", "start", "--web"],
cwd: QWENCLAW_DIR,
env: {
QWENCLAW_AUTO_START: "true",
},
};
log(" ✓ Added MCP server: qwenclaw", "green");
// Save settings
try {
writeFile(QWEN_SETTINGS_FILE, JSON.stringify(settings, null, 2) + "\n", "utf-8");
log("✅ Qwen Code settings saved", "green");
} catch (err) {
log(`❌ Error saving settings: ${err.message}`, "red");
}
}
/**
* Create MCP config file
*/
function createMCPConfig() {
log("\n📝 Creating MCP configuration...", "cyan");
const mcpConfig = {
mcpServers: {
qwenclaw: {
command: "bun",
args: ["run", "start", "--web"],
cwd: QWENCLAW_DIR,
env: {
QWENCLAW_AUTO_START: "true",
},
},
},
};
try {
writeFile(QWEN_MCP_FILE, JSON.stringify(mcpConfig, null, 2) + "\n", "utf-8");
log("✅ MCP configuration created: " + QWEN_MCP_FILE, "green");
} catch (err) {
log(`⚠️ Could not create MCP config: ${err.message}`, "yellow");
}
}
/**
* Copy startup hook
*/
function installStartupHook() {
log("\n🪝 Installing startup hook...", "cyan");
const startupHookSrc = join(QWENCLAW_DIR, "hooks", "qwen-code-startup.js");
const startupHookDest = join(QWEN_DIR, "hooks", "startup.js");
if (existsSync(startupHookSrc)) {
try {
const hookDir = join(QWEN_DIR, "hooks");
if (!existsSync(hookDir)) {
mkdirSync(hookDir, { recursive: true });
}
const hookContent = readFileSync(startupHookSrc, "utf-8");
writeFile(startupHookDest, hookContent, "utf-8");
log("✅ Startup hook installed", "green");
} catch (err) {
log(`⚠️ Could not install startup hook: ${err.message}`, "yellow");
}
} else {
log("⚠️ Startup hook not found", "yellow");
}
}
/**
* Start QwenClaw daemon
*/
function startDaemon() {
log("\n🚀 Starting QwenClaw daemon...", "cyan");
const daemonProcess = spawn("bun", ["run", "start", "--web"], {
cwd: QWENCLAW_DIR,
detached: true,
stdio: "ignore",
windowsHide: true,
});
daemonProcess.unref();
// Wait for daemon to start
setTimeout(() => {
log("✅ QwenClaw daemon started", "green");
log(" Web Dashboard: http://127.0.0.1:4632", "cyan");
}, 3000);
}
/**
* Show completion message
*/
function showCompletion() {
log("\n" + "═".repeat(60), "cyan");
log(" ✅ QWENCLAW INSTALLATION COMPLETE!", "green");
log("═".repeat(60), "cyan");
log("\n📌 Configuration Summary:", "yellow");
log(" • QwenClaw Directory: " + QWENCLAW_DIR, "cyan");
log(" • Qwen Settings: " + QWEN_SETTINGS_FILE, "cyan");
log(" • MCP Config: " + QWEN_MCP_FILE, "cyan");
log(" • Default Agent: qwenclaw", "cyan");
log(" • Default Skill: qwenclaw-integration", "cyan");
log("\n🎯 Next Steps:", "yellow");
log(" 1. Restart Qwen Code", "cyan");
log(" 2. QwenClaw will auto-start automatically", "cyan");
log(" 3. Use /qwenclaw commands in Qwen Code chat", "cyan");
log("\n📚 Quick Reference:", "yellow");
log(" /qwenclaw start - Start daemon", "cyan");
log(" /qwenclaw status - Check status", "cyan");
log(" /qwenclaw send - Send message", "cyan");
log(" /qwenclaw skills - List skills", "cyan");
log(" /qwenclaw help - Show help", "cyan");
log("\n🌐 Web Dashboard: http://127.0.0.1:4632", "cyan");
log("\n📖 Documentation: " + QWENCLAW_DIR + "/README.md", "cyan");
log("\n");
}
/**
* Main installation function
*/
async function main() {
showBanner();
try {
checkInstallation();
ensureQwenDir();
updateSettings();
createMCPConfig();
installStartupHook();
startDaemon();
showCompletion();
} catch (err) {
log(`\n❌ Installation failed: ${err.message}`, "red");
log("\nPlease check the error above and try again.", "yellow");
process.exit(1);
}
}
// Run installer
main();