From 24999d8fa266c8936330e70af7eb2580f8c9d496 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 26 Feb 2026 16:38:42 +0400 Subject: [PATCH] v1.5.1: Set QwenClaw as Default Agent for Qwen Code --- .qwen/mcp.json | 122 ++++++++++++++ .qwen/settings.example.json | 59 +++++++ README.md | 15 ++ hooks/qwen-code-startup.js | 204 +++++++++++++++++++++++ package.json | 8 +- scripts/install-qwenclaw.js | 313 ++++++++++++++++++++++++++++++++++++ 6 files changed, 718 insertions(+), 3 deletions(-) create mode 100644 .qwen/mcp.json create mode 100644 .qwen/settings.example.json create mode 100644 hooks/qwen-code-startup.js create mode 100644 scripts/install-qwenclaw.js diff --git a/.qwen/mcp.json b/.qwen/mcp.json new file mode 100644 index 0000000..8efe8f4 --- /dev/null +++ b/.qwen/mcp.json @@ -0,0 +1,122 @@ +# QwenClaw MCP Server Configuration + +This directory contains MCP (Model Context Protocol) server configurations for integrating QwenClaw with Qwen Code and other AI assistants. + +## Installation + +### 1. Copy MCP Config to Qwen Code + +```bash +# Windows (PowerShell) +Copy-Item .qwen\mcp.json $env:USERPROFILE\.qwen\mcp.json -Force + +# Linux/macOS +cp .qwen/mcp.json ~/.qwen/mcp.json +``` + +### 2. Restart Qwen Code + +Close and reopen Qwen Code for the changes to take effect. + +## Configuration + +### mcp.json + +```json +{ + "mcpServers": { + "qwenclaw": { + "command": "bun", + "args": ["run", "start", "--web"], + "cwd": "~/qwenclaw", + "env": { + "QWENCLAW_AUTO_START": "true" + } + } + } +} +``` + +### Settings + +| Setting | Description | Default | +|---------|-------------|---------| +| `command` | Command to run QwenClaw | `bun` | +| `args` | Arguments for the command | `["run", "start", "--web"]` | +| `cwd` | Working directory | `~/qwenclaw` | +| `env.QWENCLAW_AUTO_START` | Auto-start daemon | `true` | + +## Usage + +Once configured, QwenClaw will: + +1. **Auto-start** when Qwen Code launches +2. **Set as default agent** for all interactions +3. **Enable skills** automatically: + - qwenclaw-integration + - gui-automation + - qwenbot-integration + +## Verification + +Check if QwenClaw MCP server is connected: + +``` +/qwenclaw status +``` + +Should show: +``` +āœ… QwenClaw daemon is running + PID: 12345 + Web UI: http://127.0.0.1:4632 +``` + +## Troubleshooting + +### Issue: "MCP server not found" + +**Solution:** +```bash +# Verify config location +ls ~/.qwen/mcp.json + +# Check QwenClaw installation +ls ~/qwenclaw +``` + +### Issue: "Failed to start daemon" + +**Solution:** +```bash +# Check if port is in use +lsof -i :4632 + +# Manually start QwenClaw +cd ~/qwenclaw +bun run start --web +``` + +### Issue: "Skills not enabled" + +**Solution:** +```bash +# Update Qwen Code settings +# Add to ~/.qwen/settings.json: +{ + "skills": { + "enabled": [ + "qwenclaw-integration", + "gui-automation", + "qwenbot-integration" + ], + "default": "qwenclaw-integration" + } +} +``` + +## Resources + +- **QwenClaw Docs:** `README.md` in qwenclaw directory +- **MCP Protocol:** https://modelcontextprotocol.io/ +- **Qwen Code:** https://github.com/QwenLM/Qwen-Code diff --git a/.qwen/settings.example.json b/.qwen/settings.example.json new file mode 100644 index 0000000..e3c042f --- /dev/null +++ b/.qwen/settings.example.json @@ -0,0 +1,59 @@ +{ + "mcpServers": { + "playwright-vision": { + "command": "npx", + "args": [ + "@playwright/mcp@latest", + "--caps=vision" + ] + }, + "qwenclaw": { + "command": "bun", + "args": [ + "run", + "start", + "--web" + ], + "cwd": "~/qwenclaw", + "env": { + "QWENCLAW_AUTO_START": "true" + } + } + }, + "security": { + "auth": { + "selectedType": "qwen-oauth" + } + }, + "$version": 3, + "context": { + "loadMemoryFromIncludeDirectories": true + }, + "tools": { + "approvalMode": "yolo" + }, + "ui": { + "feedbackLastShownTimestamp": 1769071256658 + }, + "skills": { + "enabled": [ + "qwenclaw-integration", + "gui-automation", + "qwenbot-integration" + ], + "default": "qwenclaw-integration" + }, + "agents": { + "default": "qwenclaw", + "qwenclaw": { + "name": "QwenClaw", + "description": "Persistent AI assistant daemon with automation capabilities", + "autoStart": true, + "skills": [ + "qwenclaw-integration", + "gui-automation", + "qwenbot-integration" + ] + } + } +} diff --git a/README.md b/README.md index 499866c..42f0997 100644 --- a/README.md +++ b/README.md @@ -480,6 +480,21 @@ rm -rf QwenClaw-with-Auth QwenClaw follows [Semantic Versioning](https://semver.org/) (MAJOR.MINOR.PATCH). +### [1.5.1] - 2026-02-26 + +#### Added +- **QwenClaw as Default Agent** - Auto-start with Qwen Code: + - MCP server configuration (`.qwen/mcp.json`) + - Startup hook (`hooks/qwen-code-startup.js`) + - Auto-configuration script (`scripts/install-qwenclaw.js`) + - Default agent settings in Qwen Code + - Skills auto-enabled on install + +#### Changed +- Updated package.json with `setup` script +- Added `install-qwenclaw` binary command +- Updated version to 1.5.1 + ### [1.5.0] - 2026-02-26 #### Added diff --git a/hooks/qwen-code-startup.js b/hooks/qwen-code-startup.js new file mode 100644 index 0000000..72c0108 --- /dev/null +++ b/hooks/qwen-code-startup.js @@ -0,0 +1,204 @@ +#!/usr/bin/env node +/** + * Qwen Code Startup Hook for QwenClaw + * + * This script is automatically executed when Qwen Code starts. + * It ensures QwenClaw daemon is running and sets it as the default agent. + */ + +import { spawn } from "child_process"; +import { join } from "path"; +import { existsSync, readFileSync, writeFile } 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 QWENCLAW_PID_FILE = join(QWEN_DIR, "qwenclaw", "daemon.pid"); + +const COLORS = { + cyan: "\x1b[36m", + green: "\x1b[32m", + yellow: "\x1b[33m", + red: "\x1b[31m", + reset: "\x1b[0m", +}; + +function log(message, color = "reset") { + console.log(`${COLORS[color]}${message}${COLORS.reset}`); +} + +/** + * Check if QwenClaw daemon is running + */ +function isQwenClawRunning() { + if (!existsSync(QWENCLAW_PID_FILE)) { + return false; + } + + try { + const pid = parseInt(readFileSync(QWENCLAW_PID_FILE, "utf-8").trim(), 10); + if (isNaN(pid)) { + return false; + } + + // Check if process exists + process.kill(pid, 0); + return true; + } catch { + return false; + } +} + +/** + * Start QwenClaw daemon in background + */ +function startQwenClaw() { + log("\n🐾 QwenClaw: Starting daemon...", "cyan"); + + const qwenclawProcess = spawn("bun", ["run", "start", "--web"], { + cwd: QWENCLAW_DIR, + detached: true, + stdio: "ignore", + windowsHide: true, + }); + + qwenclawProcess.unref(); + + log("āœ… QwenClaw daemon started in background", "green"); + log(" Web Dashboard: http://127.0.0.1:4632", "cyan"); +} + +/** + * Update Qwen Code settings to enable QwenClaw as default + */ +function updateQwenSettings() { + log("\nāš™ļø QwenClaw: Updating Qwen Code settings...", "cyan"); + + let settings = {}; + + if (existsSync(QWEN_SETTINGS_FILE)) { + try { + const content = readFileSync(QWEN_SETTINGS_FILE, "utf-8"); + settings = JSON.parse(content); + } catch (err) { + log(`āš ļø Warning: Could not parse settings.json: ${err.message}`, "yellow"); + } + } + + // Enable QwenClaw 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"); + } + } + + // Set QwenClaw as default skill + settings.skills.default = "qwenclaw-integration"; + + // Set QwenClaw as default agent + if (!settings.agents) { + settings.agents = {}; + } + + settings.agents.default = "qwenclaw"; + + if (!settings.agents.qwenclaw) { + settings.agents.qwenclaw = { + name: "QwenClaw", + description: "Persistent AI assistant daemon with automation capabilities", + autoStart: true, + skills: ["qwenclaw-integration", "gui-automation", "qwenbot-integration"], + }; + log(" + Created default agent: qwenclaw", "green"); + } else { + settings.agents.qwenclaw.autoStart = true; + log(" āœ“ Updated agent: qwenclaw", "green"); + } + + // Add QwenClaw MCP server + if (!settings.mcpServers) { + settings.mcpServers = {}; + } + + if (!settings.mcpServers.qwenclaw) { + 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 updated", "green"); + } catch (err) { + log(`āŒ Error saving settings: ${err.message}`, "red"); + } +} + +/** + * Main startup hook + */ +async function main() { + log("\n" + "═".repeat(50), "cyan"); + log(" 🐾 QWENCLAW - Qwen Code Startup Hook", "cyan"); + log("═".repeat(50), "cyan"); + + // Check if QwenClaw is installed + if (!existsSync(QWENCLAW_DIR)) { + log("\nāŒ QwenClaw not found at: " + QWENCLAW_DIR, "red"); + log(" Please install QwenClaw first:", "yellow"); + log(" git clone https://github.rommark.dev/admin/QwenClaw-with-Auth.git", "cyan"); + return; + } + + // Check if daemon is running + if (isQwenClawRunning()) { + log("\nāœ… QwenClaw daemon is already running", "green"); + } else { + startQwenClaw(); + + // Wait for daemon to start + await new Promise((resolve) => setTimeout(resolve, 3000)); + } + + // Update Qwen Code settings + updateQwenSettings(); + + // Show status + log("\n" + "═".repeat(50), "cyan"); + log(" āœ… QwenClaw is ready!", "green"); + log("═".repeat(50), "cyan"); + log("\nšŸ“Œ Quick Commands:", "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("\n🌐 Web Dashboard: http://127.0.0.1:4632", "cyan"); + log("\n"); +} + +// Run startup hook +main().catch((err) => { + log(`\nāŒ Startup hook error: ${err.message}`, "red"); +}); diff --git a/package.json b/package.json index 998f201..47cc59a 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,10 @@ { "name": "qwenclaw", - "version": "1.5.0", + "version": "1.5.1", "type": "module", "bin": { - "qwenclaw": "./bin/qwenclaw.js" + "qwenclaw": "./bin/qwenclaw.js", + "install-qwenclaw": "./scripts/install-qwenclaw.js" }, "scripts": { "start": "bun run src/index.ts", @@ -16,7 +17,8 @@ "start:all": "bun run src/index.ts start --web --with-rig", "test": "bun test", "test:rig": "bun test tests/rig-integration.test.ts", - "postinstall": "chmod +x bin/qwenclaw.js 2>/dev/null || true && npx playwright install chromium 2>/dev/null || true" + "postinstall": "chmod +x bin/qwenclaw.js 2>/dev/null || true && npx playwright install chromium 2>/dev/null || true", + "setup": "bun run scripts/install-qwenclaw.js" }, "devDependencies": { "@types/bun": "^1.3.9" diff --git a/scripts/install-qwenclaw.js b/scripts/install-qwenclaw.js new file mode 100644 index 0000000..06d30d4 --- /dev/null +++ b/scripts/install-qwenclaw.js @@ -0,0 +1,313 @@ +#!/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();