178 lines
4.3 KiB
JavaScript
178 lines
4.3 KiB
JavaScript
/**
|
|
* 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();
|