pdca
Version:
🎯 AI 驅動的 PDCA 多代理開發系統 - 智能循環控制 + 成本管理 + Token 優化 + 多 AI 引擎支援
366 lines • 10.4 kB
JavaScript
/**
* Raiy-PDCA 監控介面
* 使用 blessed 提供即時的系統狀態監控
*/
import blessed from 'blessed';
import { EventEmitter } from 'events';
import { readFileSync, existsSync } from 'fs';
import { join } from 'path';
export class Monitor extends EventEmitter {
screen;
agentsBox;
taskBox;
logsBox;
statusBar;
config;
updateTimer;
agents = new Map();
currentTask;
constructor(config) {
super();
this.config = config;
this.screen = this.createScreen();
this.agentsBox = this.createAgentsBox();
this.taskBox = this.createTaskBox();
this.logsBox = this.createLogsBox();
this.statusBar = this.createStatusBar();
this.setupEventHandlers();
this.screen.render();
}
/**
* 創建主螢幕
*/
createScreen() {
const screen = blessed.screen({
smartCSR: true,
title: `Raiy-PDCA Monitor - ${this.config.sessionName}`,
fullUnicode: true
});
// 添加標題
const titleBox = blessed.box({
parent: screen,
top: 0,
left: 0,
width: '100%',
height: 3,
content: `{center}🎯 Raiy-PDCA 監控中心 - ${this.config.sessionName}{/center}`,
tags: true,
style: {
fg: 'white',
bg: 'blue',
bold: true
}
});
return screen;
}
/**
* 創建代理狀態框
*/
createAgentsBox() {
return blessed.box({
parent: this.screen,
label: ' 代理狀態 ',
top: 3,
left: 0,
width: '50%',
height: '40%',
border: {
type: 'line'
},
style: {
border: {
fg: 'cyan'
}
},
scrollable: true,
alwaysScroll: true,
tags: true
});
}
/**
* 創建任務資訊框
*/
createTaskBox() {
return blessed.box({
parent: this.screen,
label: ' 任務資訊 ',
top: 3,
left: '50%',
width: '50%',
height: '40%',
border: {
type: 'line'
},
style: {
border: {
fg: 'green'
}
},
tags: true,
scrollable: true
});
}
/**
* 創建日誌框
*/
createLogsBox() {
return blessed.box({
parent: this.screen,
label: ' 系統日誌 ',
bottom: 3,
left: 0,
width: '100%',
height: '50%',
border: {
type: 'line'
},
style: {
border: {
fg: 'yellow'
}
},
scrollable: true,
alwaysScroll: true,
tags: true
});
}
/**
* 創建狀態列
*/
createStatusBar() {
return blessed.box({
parent: this.screen,
bottom: 0,
left: 0,
width: '100%',
height: 3,
content: '',
tags: true,
style: {
fg: 'white',
bg: 'black'
}
});
}
/**
* 設置事件處理
*/
setupEventHandlers() {
// 鍵盤事件
this.screen.key(['q', 'C-c'], () => {
this.stop();
process.exit(0);
});
this.screen.key(['r'], () => {
this.refresh();
});
this.screen.key(['l'], () => {
this.logsBox.focus();
});
this.screen.key(['a'], () => {
this.agentsBox.focus();
});
this.screen.key(['t'], () => {
this.taskBox.focus();
});
// 滑鼠支援
this.agentsBox.on('click', () => this.agentsBox.focus());
this.taskBox.on('click', () => this.taskBox.focus());
this.logsBox.on('click', () => this.logsBox.focus());
// 定期更新
if (this.config.updateInterval) {
this.updateTimer = setInterval(() => {
this.refresh();
}, this.config.updateInterval);
}
}
/**
* 啟動監控
*/
start() {
this.updateStatusBar('監控啟動中...');
this.refresh();
this.log('info', '監控系統已啟動');
}
/**
* 停止監控
*/
stop() {
if (this.updateTimer) {
clearInterval(this.updateTimer);
}
this.screen.destroy();
this.emit('stop');
}
/**
* 刷新顯示
*/
refresh() {
this.updateAgentStatus();
this.updateTaskInfo();
this.updateStatusBar(`最後更新: ${new Date().toLocaleTimeString()} | 按 q 退出 | r 刷新 | a/t/l 切換焦點`);
this.screen.render();
}
/**
* 更新代理狀態
*/
updateAgentStatus() {
// 從通訊目錄讀取狀態
const statusDir = join(this.config.workingDir, '.raiy-pdca', 'communication', 'status');
let content = '{bold}代理狀態監控{/bold}\n\n';
this.agents.forEach((agent, name) => {
const statusFile = join(statusDir, `${name}.json`);
if (existsSync(statusFile)) {
try {
const status = JSON.parse(readFileSync(statusFile, 'utf-8'));
agent.status = status.status || 'unknown';
agent.lastUpdate = new Date(status.timestamp || Date.now());
agent.message = status.message;
agent.progress = status.progress;
}
catch (error) {
// 忽略解析錯誤
}
}
const statusColor = this.getStatusColor(agent.status);
const progressBar = agent.progress ? this.createProgressBar(agent.progress) : '';
content += `${agent.icon} {bold}${agent.role}{/bold}\n`;
content += ` 狀態: {${statusColor}-fg}${agent.status}{/${statusColor}-fg}\n`;
if (agent.message) {
content += ` 訊息: ${agent.message}\n`;
}
if (progressBar) {
content += ` 進度: ${progressBar}\n`;
}
content += '\n';
});
this.agentsBox.setContent(content);
}
/**
* 更新任務資訊
*/
updateTaskInfo() {
let content = '{bold}任務追蹤{/bold}\n\n';
if (this.currentTask) {
content += `任務 ID: ${this.currentTask.id}\n`;
content += `描述: ${this.currentTask.description}\n`;
content += `狀態: {${this.getTaskStatusColor(this.currentTask.status)}-fg}${this.currentTask.status}{/}\n`;
content += `開始時間: ${this.currentTask.createdAt.toLocaleString()}\n\n`;
content += '{bold}代理進度:{/bold}\n';
for (const [agentName, progress] of Object.entries(this.currentTask.agents)) {
const agent = this.agents.get(agentName);
if (agent) {
content += `${agent.icon} ${agent.role}: ${this.createProgressBar(progress.progress || 0)}\n`;
}
}
}
else {
content += '{gray-fg}暫無活動任務{/gray-fg}';
}
this.taskBox.setContent(content);
}
/**
* 更新狀態列
*/
updateStatusBar(message) {
this.statusBar.setContent(`{center}${message}{/center}`);
}
/**
* 添加日誌
*/
log(level, message) {
const timestamp = new Date().toLocaleTimeString();
const levelColor = {
info: 'cyan',
warn: 'yellow',
error: 'red'
}[level];
// 獲取現有內容並添加新日誌
const currentContent = this.logsBox.getContent();
const newLog = `[${timestamp}] {${levelColor}-fg}${level.toUpperCase()}{/${levelColor}-fg} ${message}`;
const lines = currentContent.split('\n');
lines.push(newLog);
// 保留最後 100 行
if (lines.length > 100) {
lines.splice(0, lines.length - 100);
}
this.logsBox.setContent(lines.join('\n'));
this.screen.render();
}
/**
* 設置代理列表
*/
setAgents(agents) {
this.agents.clear();
agents.forEach(agent => {
this.agents.set(agent.name, {
name: agent.name,
role: agent.role,
icon: agent.icon,
status: agent.status,
lastUpdate: new Date()
});
});
this.refresh();
}
/**
* 設置當前任務
*/
setTask(task) {
this.currentTask = task;
this.refresh();
}
/**
* 更新代理狀態
*/
updateAgent(name, status) {
const agent = this.agents.get(name);
if (agent) {
Object.assign(agent, status);
agent.lastUpdate = new Date();
}
}
/**
* 獲取狀態顏色
*/
getStatusColor(status) {
const colors = {
idle: 'gray',
starting: 'yellow',
running: 'green',
completed: 'blue',
error: 'red'
};
return colors[status] || 'white';
}
/**
* 獲取任務狀態顏色
*/
getTaskStatusColor(status) {
const colors = {
pending: 'yellow',
running: 'green',
completed: 'blue',
failed: 'red'
};
return colors[status] || 'white';
}
/**
* 創建進度條
*/
createProgressBar(progress) {
const width = 20;
const filled = Math.round((progress / 100) * width);
const empty = width - filled;
return `[${'█'.repeat(filled)}${' '.repeat(empty)}] ${progress}%`;
}
}
/**
* 快速啟動監控介面
*/
export function startMonitor(config) {
const monitor = new Monitor(config);
monitor.start();
return monitor;
}
//# sourceMappingURL=monitor.js.map