v1.6.0: Replace Rig with Agents Council + Keep FULL RAG
This commit is contained in:
105
qwen-agent/commands/qwenclaw.js
Normal file
105
qwen-agent/commands/qwenclaw.js
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* QwenClaw Command Handler for Qwen Code CLI
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
export async function handle(args) {
|
||||
const command = args[0];
|
||||
|
||||
switch (command) {
|
||||
case "start":
|
||||
if (isRunning()) {
|
||||
return "✅ QwenClaw daemon is already running";
|
||||
}
|
||||
|
||||
const proc = spawn("bun", ["run", "start", "--web"], {
|
||||
cwd: QWENCLAW_DIR,
|
||||
detached: true,
|
||||
stdio: "ignore",
|
||||
windowsHide: true,
|
||||
});
|
||||
|
||||
proc.unref();
|
||||
|
||||
return "🚀 Starting QwenClaw daemon...\n Web Dashboard: http://127.0.0.1:4632";
|
||||
|
||||
case "status":
|
||||
if (isRunning()) {
|
||||
const pid = parseInt(readFileSync(PID_FILE, "utf-8").trim(), 10);
|
||||
return `✅ QwenClaw daemon is running\n PID: ${pid}\n Web Dashboard: http://127.0.0.1:4632`;
|
||||
}
|
||||
return "❌ QwenClaw daemon is not running\n Run: /qwenclaw start";
|
||||
|
||||
case "send":
|
||||
const message = args.slice(1).join(" ");
|
||||
if (!message) return "Usage: /qwenclaw send <message>";
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const proc = spawn("bun", ["run", "send", message], {
|
||||
cwd: QWENCLAW_DIR,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
let output = "";
|
||||
proc.stdout.on("data", (data) => {
|
||||
output += data.toString();
|
||||
});
|
||||
|
||||
proc.on("close", () => {
|
||||
resolve(output || "Message sent to daemon");
|
||||
});
|
||||
});
|
||||
|
||||
case "skills":
|
||||
return `
|
||||
QwenClaw Skills (79 total):
|
||||
• qwenclaw-integration - Daemon control & communication
|
||||
• gui-automation - Full browser automation with Playwright
|
||||
• qwenbot-integration - QwenBot AI assistant
|
||||
• shadcn-ui-design - shadcn/ui design patterns
|
||||
• metatrader5-trading - MetaTrader 5 trading
|
||||
• ... and 74 more
|
||||
|
||||
Run: qwenclaw skills (in terminal) for full list
|
||||
`;
|
||||
|
||||
case "help":
|
||||
default:
|
||||
return `
|
||||
🐾 QwenClaw - Your Always-ON AI Assistant
|
||||
|
||||
Commands:
|
||||
/qwenclaw start - Start daemon
|
||||
/qwenclaw status - Check status
|
||||
/qwenclaw send - Send message
|
||||
/qwenclaw skills - List skills
|
||||
/qwenclaw help - This help
|
||||
|
||||
Terminal Commands:
|
||||
qwenclaw start --web
|
||||
qwenclaw status
|
||||
qwenclaw send "message"
|
||||
qwenclaw skills
|
||||
|
||||
Web Dashboard: http://127.0.0.1:4632
|
||||
`;
|
||||
}
|
||||
}
|
||||
177
qwen-agent/index.js
Normal file
177
qwen-agent/index.js
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* QwenClaw Agent for Qwen Code CLI
|
||||
*
|
||||
* This agent intercepts all Qwen Code CLI interactions
|
||||
* and ensures QwenClaw daemon is always active.
|
||||
*/
|
||||
|
||||
import { spawn } from "child_process";
|
||||
import { join } from "path";
|
||||
import { existsSync, readFileSync, writeFile } from "fs";
|
||||
|
||||
const QWENCLAW_DIR = process.env.QWENCLAW_DIR || join(process.env.HOME || process.env.USERPROFILE || "", "qwenclaw");
|
||||
const QWEN_DIR = join(process.env.HOME || process.env.USERPROFILE || "", ".qwen");
|
||||
const PID_FILE = join(QWEN_DIR, "qwenclaw", "daemon.pid");
|
||||
|
||||
/**
|
||||
* Check if QwenClaw daemon is running
|
||||
*/
|
||||
function isDaemonRunning() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start QwenClaw daemon
|
||||
*/
|
||||
function startDaemon() {
|
||||
if (isDaemonRunning()) {
|
||||
console.log("[QwenClaw] Daemon already running");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("[QwenClaw] Starting daemon...");
|
||||
|
||||
const proc = spawn("bun", ["run", "start", "--web"], {
|
||||
cwd: QWENCLAW_DIR,
|
||||
detached: true,
|
||||
stdio: "ignore",
|
||||
windowsHide: true,
|
||||
});
|
||||
|
||||
proc.unref();
|
||||
|
||||
setTimeout(() => {
|
||||
if (isDaemonRunning()) {
|
||||
console.log("[QwenClaw] ✅ Daemon started");
|
||||
console.log("[QwenClaw] Web Dashboard: http://127.0.0.1:4632");
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept Qwen Code CLI input and prepend QwenClaw context
|
||||
*/
|
||||
function interceptInput(input) {
|
||||
// If input starts with /qwenclaw, handle as daemon command
|
||||
if (input.startsWith("/qwenclaw")) {
|
||||
return handleQwenClawCommand(input);
|
||||
}
|
||||
|
||||
// Otherwise, pass through to Qwen Code with QwenClaw context
|
||||
return {
|
||||
context: "QwenClaw daemon is active. All interactions are logged and can be automated.",
|
||||
input: input,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle QwenClaw commands
|
||||
*/
|
||||
function handleQwenClawCommand(command) {
|
||||
const args = command.slice("/qwenclaw".length).trim().split(/\s+/);
|
||||
const subcommand = args[0];
|
||||
|
||||
switch (subcommand) {
|
||||
case "start":
|
||||
startDaemon();
|
||||
return "Starting QwenClaw daemon...";
|
||||
|
||||
case "status":
|
||||
if (isDaemonRunning()) {
|
||||
const pid = parseInt(readFileSync(PID_FILE, "utf-8").trim(), 10);
|
||||
return `✅ QwenClaw daemon is running (PID: ${pid})\n Web Dashboard: http://127.0.0.1:4632`;
|
||||
} else {
|
||||
return "❌ QwenClaw daemon is not running\n Run /qwenclaw start to start it";
|
||||
}
|
||||
|
||||
case "stop":
|
||||
if (isDaemonRunning()) {
|
||||
const pid = parseInt(readFileSync(PID_FILE, "utf-8").trim(), 10);
|
||||
try {
|
||||
process.kill(pid, "SIGTERM");
|
||||
return "Stopping QwenClaw daemon...";
|
||||
} catch {
|
||||
return "Failed to stop daemon";
|
||||
}
|
||||
} else {
|
||||
return "Daemon is not running";
|
||||
}
|
||||
|
||||
case "send":
|
||||
const message = args.slice(1).join(" ");
|
||||
if (!message) {
|
||||
return "Usage: /qwenclaw send <message>";
|
||||
}
|
||||
return sendToDaemon(message);
|
||||
|
||||
case "help":
|
||||
return `
|
||||
QwenClaw Commands:
|
||||
/qwenclaw start - Start daemon
|
||||
/qwenclaw status - Check daemon status
|
||||
/qwenclaw stop - Stop daemon
|
||||
/qwenclaw send - Send message to daemon
|
||||
/qwenclaw skills - List available skills
|
||||
/qwenclaw help - Show this help
|
||||
|
||||
Web Dashboard: http://127.0.0.1:4632
|
||||
`;
|
||||
|
||||
default:
|
||||
return `Unknown command: ${subcommand}\nRun /qwenclaw help for usage`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message to daemon
|
||||
*/
|
||||
function sendToDaemon(message) {
|
||||
return new Promise((resolve) => {
|
||||
const proc = spawn("bun", ["run", "send", message], {
|
||||
cwd: QWENCLAW_DIR,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
let output = "";
|
||||
proc.stdout.on("data", (data) => {
|
||||
output += data.toString();
|
||||
});
|
||||
|
||||
proc.on("close", () => {
|
||||
resolve(output || "Message sent to daemon");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize QwenClaw agent
|
||||
*/
|
||||
export function init() {
|
||||
console.log("\n🐾 QwenClaw Agent initialized");
|
||||
console.log(" QwenClaw is now your ALWAYS-ON agent");
|
||||
console.log(" Use /qwenclaw help for commands\n");
|
||||
|
||||
// Auto-start daemon
|
||||
startDaemon();
|
||||
|
||||
return {
|
||||
name: "QwenClaw",
|
||||
version: "1.0.0",
|
||||
interceptInput,
|
||||
commands: {
|
||||
qwenclaw: handleQwenClawCommand,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Auto-initialize when loaded
|
||||
init();
|
||||
48
qwen-agent/package.json
Normal file
48
qwen-agent/package.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "qwenclaw-agent",
|
||||
"version": "1.0.0",
|
||||
"description": "QwenClaw - Persistent AI assistant daemon for Qwen Code CLI",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"qwen": {
|
||||
"type": "agent",
|
||||
"displayName": "QwenClaw 🐾",
|
||||
"description": "Persistent AI assistant daemon with full automation capabilities",
|
||||
"autoStart": true,
|
||||
"alwaysOn": true,
|
||||
"priority": 1,
|
||||
"commands": [
|
||||
{
|
||||
"name": "qwenclaw",
|
||||
"description": "Interact with QwenClaw daemon",
|
||||
"handler": "./commands/qwenclaw.js"
|
||||
}
|
||||
],
|
||||
"skills": [
|
||||
"qwenclaw-integration",
|
||||
"gui-automation",
|
||||
"qwenbot-integration"
|
||||
],
|
||||
"config": {
|
||||
"daemon": {
|
||||
"autoStart": true,
|
||||
"webDashboard": true,
|
||||
"port": 4632
|
||||
}
|
||||
}
|
||||
},
|
||||
"keywords": [
|
||||
"qwen",
|
||||
"qwenclaw",
|
||||
"agent",
|
||||
"daemon",
|
||||
"automation",
|
||||
"ai-assistant"
|
||||
],
|
||||
"author": "QwenClaw Team",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.rommark.dev/admin/QwenClaw-with-Auth.git"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user