diff --git a/.qwen/qwen-code-agent.json b/.qwen/qwen-code-agent.json new file mode 100644 index 0000000..d9b291b --- /dev/null +++ b/.qwen/qwen-code-agent.json @@ -0,0 +1,98 @@ +{ + "$schema": "https://raw.githubusercontent.com/QwenLM/Qwen-Code/main/schemas/settings.json", + "version": "1.0.0", + "agent": { + "default": "qwenclaw", + "enforce": true, + "agents": { + "qwenclaw": { + "name": "QwenClaw", + "description": "Persistent AI assistant daemon with full automation capabilities - ALWAYS ON", + "autoStart": true, + "alwaysOn": true, + "priority": 1, + "skills": [ + "qwenclaw-integration", + "gui-automation", + "qwenbot-integration", + "shadcn-ui-design", + "metatrader5-trading" + ], + "config": { + "daemon": { + "autoStart": true, + "webDashboard": true, + "port": 4632, + "checkInterval": 30000 + }, + "telegram": { + "enabled": false, + "forwardResponses": false + }, + "heartbeat": { + "enabled": true, + "interval": 15 + } + } + } + } + }, + "skills": { + "enforce": true, + "default": "qwenclaw-integration", + "enabled": [ + "qwenclaw-integration", + "gui-automation", + "qwenbot-integration", + "shadcn-ui-design", + "metatrader5-trading" + ], + "disabled": [] + }, + "mcpServers": { + "qwenclaw": { + "enabled": true, + "autoStart": true, + "command": "bun", + "args": [ + "run", + "start", + "--web" + ], + "cwd": "~/qwenclaw", + "env": { + "QWENCLAW_AUTO_START": "true", + "QWENCLAW_ALWAYS_ON": "true" + } + }, + "playwright-vision": { + "enabled": true, + "command": "npx", + "args": [ + "@playwright/mcp@latest", + "--caps=vision" + ] + } + }, + "context": { + "loadMemoryFromIncludeDirectories": true, + "persistentSessions": true, + "shareContextWithDaemon": true + }, + "tools": { + "approvalMode": "yolo", + "enableAll": true + }, + "ui": { + "showAgentStatus": true, + "showDaemonStatus": true, + "theme": "dark" + }, + "security": { + "auth": { + "selectedType": "qwen-oauth" + }, + "allowDaemonAutoStart": true, + "allowMcpServers": true + } +} diff --git a/README.md b/README.md index 42f0997..04c788b 100644 --- a/README.md +++ b/README.md @@ -480,6 +480,25 @@ rm -rf QwenClaw-with-Auth QwenClaw follows [Semantic Versioning](https://semver.org/) (MAJOR.MINOR.PATCH). +### [1.5.2] - 2026-02-26 + +#### Added +- **Always-ON QwenClaw Agent** - Enforced as default in Qwen Code CLI: + - Agent configuration (`.qwen/qwen-code-agent.json`) + - Set default agent script (`scripts/set-default-agent.js`) + - Enforced agent settings with `alwaysOn: true` + - Priority 1 agent (highest priority) + - Auto-enables all QwenClaw skills + +#### Fixed +- **PowerShell CLI Command** - Added `bin/qwenclaw.cmd` wrapper for Windows +- **Path Resolution** - Fixed QWENCLAW_DIR detection in CLI + +#### Changed +- Updated package.json with `set-default` script +- Added `set-default-agent` binary command +- Updated version to 1.5.2 + ### [1.5.1] - 2026-02-26 #### Added diff --git a/bin/qwenclaw.cmd b/bin/qwenclaw.cmd new file mode 100644 index 0000000..1f86f09 --- /dev/null +++ b/bin/qwenclaw.cmd @@ -0,0 +1,22 @@ +@echo off +REM QwenClaw CLI Command Wrapper for Windows +REM Usage: qwenclaw [command] [options] + +setlocal enabledelayedexpansion + +REM Get script directory +set "SCRIPT_DIR=%~dp0" +set "QWENCLAW_DIR=%SCRIPT_DIR%.." + +REM Check if bun is available +where bun >nul 2>nul +if %errorlevel% neq 0 ( + echo [ERROR] bun is not installed or not in PATH + echo Install bun from: https://bun.sh/ + exit /b 1 +) + +REM Execute qwenclaw CLI +bun run "%QWENCLAW_DIR%\bin\qwenclaw.js" %* + +endlocal diff --git a/bin/qwenclaw.js b/bin/qwenclaw.js index a5e1318..f805178 100644 --- a/bin/qwenclaw.js +++ b/bin/qwenclaw.js @@ -20,7 +20,8 @@ import { fileURLToPath } from "url"; import { existsSync, readFileSync } from "fs"; const __dirname = dirname(fileURLToPath(import.meta.url)); -const QWENCLAW_DIR = join(__dirname, ".."); +// Use absolute path to qwenclaw installation +const QWENCLAW_DIR = process.env.QWENCLAW_DIR || join(__dirname, ".."); const QWENCLAW_START = join(QWENCLAW_DIR, "src", "index.ts"); // Colors for terminal output diff --git a/package.json b/package.json index 47cc59a..f39e715 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "qwenclaw", - "version": "1.5.1", + "version": "1.5.2", "type": "module", "bin": { "qwenclaw": "./bin/qwenclaw.js", - "install-qwenclaw": "./scripts/install-qwenclaw.js" + "install-qwenclaw": "./scripts/install-qwenclaw.js", + "set-default-agent": "./scripts/set-default-agent.js" }, "scripts": { "start": "bun run src/index.ts", @@ -17,8 +18,9 @@ "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", - "setup": "bun run scripts/install-qwenclaw.js" + "postinstall": "chmod +x bin/qwenclaw.js bin/qwenclaw.cmd 2>/dev/null || true && npx playwright install chromium 2>/dev/null || true", + "setup": "bun run scripts/install-qwenclaw.js", + "set-default": "bun run scripts/set-default-agent.js" }, "devDependencies": { "@types/bun": "^1.3.9" diff --git a/scripts/set-default-agent.js b/scripts/set-default-agent.js new file mode 100644 index 0000000..325f5ec --- /dev/null +++ b/scripts/set-default-agent.js @@ -0,0 +1,340 @@ +#!/usr/bin/env node +/** + * QwenClaw - Set as Default Always-ON Agent for Qwen Code CLI + * + * This script configures Qwen Code to ALWAYS use QwenClaw as the default agent. + * + * Usage: bun run set-default-agent.js + */ + +import { join } from "path"; +import { existsSync, readFileSync, writeFile, mkdirSync } from "fs"; + +const QWEN_DIR = join(process.env.HOME || process.env.USERPROFILE || "", ".qwen"); +const QWEN_SETTINGS_FILE = join(QWEN_DIR, "settings.json"); +const QWEN_AGENT_FILE = join(QWEN_DIR, "agent.json"); +const QWENCLAW_DIR = process.env.QWENCLAW_DIR || join(process.env.HOME || process.env.USERPROFILE || "", "qwenclaw"); + +const COLORS = { + cyan: "\x1b[36m", + green: "\x1b[32m", + yellow: "\x1b[33m", + red: "\x1b[31m", + magenta: "\x1b[35m", + bold: "\x1b[1m", + reset: "\x1b[0m", +}; + +function log(message, color = "reset") { + console.log(`${COLORS[color]}${message}${COLORS.reset}`); +} + +function showBanner() { + log("\n" + "═".repeat(70), "cyan"); + log(" 🐾 QWENCLAW - SET AS DEFAULT ALWAYS-ON AGENT", "cyan"); + log("═".repeat(70), "cyan"); +} + +/** + * Ensure Qwen directory exists + */ +function ensureQwenDir() { + log("\nšŸ“ Checking Qwen directory...", "cyan"); + + if (!existsSync(QWEN_DIR)) { + mkdirSync(QWEN_DIR, { recursive: true }); + log("āœ… Created Qwen directory: " + QWEN_DIR, "green"); + } else { + log("āœ… Qwen directory exists", "green"); + } +} + +/** + * Create agent.json with QwenClaw as enforced default + */ +function createAgentConfig() { + log("\nāš™ļø Creating agent configuration...", "cyan"); + + const agentConfig = { + version: "1.0.0", + agent: { + default: "qwenclaw", + enforce: true, + agents: { + qwenclaw: { + name: "QwenClaw", + description: "Persistent AI assistant daemon - ALWAYS ON", + autoStart: true, + alwaysOn: true, + priority: 1, + skills: [ + "qwenclaw-integration", + "gui-automation", + "qwenbot-integration", + ], + config: { + daemon: { + autoStart: true, + webDashboard: true, + port: 4632, + checkInterval: 30000, + }, + }, + }, + }, + }, + skills: { + enforce: true, + default: "qwenclaw-integration", + enabled: [ + "qwenclaw-integration", + "gui-automation", + "qwenbot-integration", + ], + disabled: [], + }, + mcpServers: { + qwenclaw: { + enabled: true, + autoStart: true, + command: "bun", + args: ["run", "start", "--web"], + cwd: QWENCLAW_DIR, + env: { + QWENCLAW_AUTO_START: "true", + QWENCLAW_ALWAYS_ON: "true", + }, + }, + }, + context: { + loadMemoryFromIncludeDirectories: true, + persistentSessions: true, + shareContextWithDaemon: true, + }, + tools: { + approvalMode: "yolo", + enableAll: true, + }, + ui: { + showAgentStatus: true, + showDaemonStatus: true, + }, + }; + + try { + writeFile(QWEN_AGENT_FILE, JSON.stringify(agentConfig, null, 2) + "\n", "utf-8"); + log("āœ… Agent configuration created: " + QWEN_AGENT_FILE, "green"); + log(" • Default agent: qwenclaw (ENFORCED)", "magenta"); + log(" • Always ON: true", "magenta"); + log(" • Auto-start: enabled", "magenta"); + } catch (err) { + log(`āŒ Error creating agent config: ${err.message}`, "red"); + } +} + +/** + * Update main settings.json + */ +function updateSettings() { + log("\nāš™ļø 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); + log("āœ… Loaded existing settings", "green"); + } catch (err) { + log(`āš ļø Warning: Could not parse settings.json`, "yellow"); + } + } + + // Enforce QwenClaw as default agent + if (!settings.agents) { + settings.agents = {}; + } + + settings.agents.default = "qwenclaw"; + settings.agents.enforce = true; + + settings.agents.qwenclaw = { + name: "QwenClaw", + description: "Persistent AI assistant daemon - ALWAYS ON", + autoStart: true, + alwaysOn: true, + priority: 1, + skills: ["qwenclaw-integration", "gui-automation", "qwenbot-integration"], + }; + + log(" āœ“ Set default agent: qwenclaw (ENFORCED)", "green"); + + // Enforce skills + if (!settings.skills) { + settings.skills = {}; + } + + settings.skills.enforce = true; + settings.skills.default = "qwenclaw-integration"; + + 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"); + } + } + + // Configure MCP servers + if (!settings.mcpServers) { + settings.mcpServers = {}; + } + + settings.mcpServers.qwenclaw = { + enabled: true, + autoStart: true, + command: "bun", + args: ["run", "start", "--web"], + cwd: QWENCLAW_DIR, + env: { + QWENCLAW_AUTO_START: "true", + QWENCLAW_ALWAYS_ON: "true", + }, + }; + + log(" āœ“ MCP server: qwenclaw (auto-start)", "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"); + } +} + +/** + * Create startup script + */ +function createStartupScript() { + log("\nšŸ“ Creating startup script...", "cyan"); + + const startupScript = join(QWEN_DIR, "startup.js"); + const scriptContent = `#!/usr/bin/env node +/** + * QwenClaw Auto-Start Script + * Ensures QwenClaw daemon is running when Qwen Code starts + */ + +import { spawn } from "child_process"; +import { join } from "path"; +import { existsSync, readFileSync } from "fs"; + +const QWENCLAW_DIR = process.env.QWENCLAW_DIR || join(process.env.HOME || process.env.USERPROFILE || "", "qwenclaw"); +const PID_FILE = join(process.env.HOME || process.env.USERPROFILE || "", ".qwen", "qwenclaw", "daemon.pid"); + +function isRunning() { + if (!existsSync(PID_FILE)) return false; + try { + const pid = parseInt(readFileSync(PID_FILE, "utf-8").trim(), 10); + if (isNaN(pid)) return false; + process.kill(pid, 0); + return true; + } catch { + return false; + } +} + +if (!isRunning()) { + console.log("[QwenClaw] Starting daemon..."); + const proc = spawn("bun", ["run", "start", "--web"], { + cwd: QWENCLAW_DIR, + detached: true, + stdio: "ignore", + windowsHide: true, + }); + proc.unref(); +} else { + console.log("[QwenClaw] Daemon already running"); +} +`; + + try { + writeFile(startupScript, scriptContent, "utf-8"); + log("āœ… Startup script created", "green"); + } catch (err) { + log(`āš ļø Could not create startup script: ${err.message}`, "yellow"); + } +} + +/** + * Show completion summary + */ +function showSummary() { + log("\n" + "═".repeat(70), "cyan"); + log(" āœ… QWENCLAW IS NOW YOUR DEFAULT ALWAYS-ON AGENT!", "green"); + log("═".repeat(70), "cyan"); + + log("\nšŸ“Œ Configuration Summary:", "yellow"); + log(" • Default Agent: qwenclaw (ENFORCED)", "magenta"); + log(" • Always ON: true", "magenta"); + log(" • Auto-Start: enabled", "magenta"); + log(" • Skills Enabled: 3", "magenta"); + log(" • MCP Server: configured", "magenta"); + + log("\nšŸŽÆ What This Means:", "yellow"); + log(" āœ“ Qwen Code will ALWAYS use QwenClaw by default", "green"); + log(" āœ“ QwenClaw daemon auto-starts with Qwen Code", "green"); + log(" āœ“ All QwenClaw skills are automatically enabled", "green"); + log(" āœ“ Persistent sessions across restarts", "green"); + log(" āœ“ Web dashboard auto-enabled", "green"); + + log("\nšŸš€ Next Steps:", "yellow"); + log(" 1. Restart Qwen Code", "cyan"); + log(" 2. QwenClaw will automatically start", "cyan"); + log(" 3. All interactions will use QwenClaw by default", "cyan"); + + log("\nšŸ“š Quick Commands:", "yellow"); + log(" qwenclaw start - Start daemon manually", "cyan"); + log(" qwenclaw status - Check daemon status", "cyan"); + log(" qwenclaw send - Send message to daemon", "cyan"); + log(" qwenclaw skills - List all skills", "cyan"); + log(" qwenclaw help - Show help", "cyan"); + + log("\n🌐 Web Dashboard: http://127.0.0.1:4632", "cyan"); + log("\nšŸ“– Config Files:", "yellow"); + log(" • Agent: " + QWEN_AGENT_FILE, "cyan"); + log(" • Settings: " + QWEN_SETTINGS_FILE, "cyan"); + log("\n"); +} + +/** + * Main function + */ +async function main() { + showBanner(); + + try { + ensureQwenDir(); + createAgentConfig(); + updateSettings(); + createStartupScript(); + showSummary(); + } catch (err) { + log(`\nāŒ Configuration failed: ${err.message}`, "red"); + log("\nPlease check the error and try again.", "yellow"); + process.exit(1); + } +} + +// Run configuration +main();