UNPKG

pm-orchestrator-enhancement

Version:

PM Orchestrator Enhancement - Multi-agent parallel execution system

237 lines 8.63 kB
"use strict"; /** * PM Orchestrator Enhancement - Execution Logger * * タスク実行の詳細を記録し、ログファイルとして保存します。 */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExecutionLogger = void 0; const fs_1 = require("fs"); const path_1 = __importDefault(require("path")); /** * ExecutionLoggerクラス * * タスク実行の開始から完了までの全ての情報を記録します。 * ログは `.pm-orchestrator/logs/` ディレクトリに保存されます。 */ class ExecutionLogger { /** * コンストラクタ * * @param baseDir ログディレクトリのベースパス(デフォルト: カレントディレクトリ) */ constructor(baseDir = process.cwd()) { this.currentLog = null; this.logDir = path_1.default.join(baseDir, '.pm-orchestrator', 'logs'); } /** * タスクを開始し、新しい実行ログを作成します * * @param userInput ユーザーの入力 * @param taskType タスクの種類(オプション) * @param complexity タスクの複雑度(オプション) * @param detectedPattern 検出されたパターン(オプション) * @returns タスクIDと初期化されたログ */ startTask(userInput, taskType = 'unknown', complexity = 'medium', detectedPattern = 'none') { const now = new Date().toISOString(); const taskId = `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; this.currentLog = { taskId, startTime: now, endTime: '', duration: 0, userInput, taskType, complexity, detectedPattern, subagents: [], status: 'success', autoFixAttempted: false, autoFixSuccess: false, retryCount: 0, rollbackExecuted: false, filesChanged: 0, linesAdded: 0, linesDeleted: 0, testsAdded: 0, qualityScore: 0 }; return { taskId, log: { ...this.currentLog } }; } /** * サブエージェントの実行を記録します * * @param name サブエージェント名 * @param status 実行状態 * @param output 実行結果の出力 * @param error エラーメッセージ(オプション) * @param toolsUsed 使用したツールのリスト(オプション) */ recordSubagent(name, status, output, error, toolsUsed = []) { if (!this.currentLog) { throw new Error('No active task. Call startTask() first.'); } const now = new Date().toISOString(); const startTime = this.currentLog.subagents.find(s => s.name === name)?.startTime || now; const duration = new Date(now).getTime() - new Date(startTime).getTime(); const subagentExecution = { name, startTime, endTime: now, duration, status: status, toolsUsed, output, error }; // 既存のサブエージェント記録を更新または新規追加 const existingIndex = this.currentLog.subagents.findIndex(s => s.name === name); if (existingIndex >= 0) { this.currentLog.subagents[existingIndex] = subagentExecution; } else { this.currentLog.subagents.push(subagentExecution); } } /** * 自動修正の試行を記録します * * @param attempted 自動修正を試行したか * @param success 自動修正が成功したか */ recordAutoFix(attempted, success) { if (!this.currentLog) { throw new Error('No active task. Call startTask() first.'); } this.currentLog.autoFixAttempted = attempted; this.currentLog.autoFixSuccess = success; } /** * リトライの実行を記録します */ recordRetry() { if (!this.currentLog) { throw new Error('No active task. Call startTask() first.'); } this.currentLog.retryCount += 1; } /** * ロールバックの実行を記録します */ recordRollback() { if (!this.currentLog) { throw new Error('No active task. Call startTask() first.'); } this.currentLog.rollbackExecuted = true; this.currentLog.status = 'rollback'; } /** * ファイル変更の統計を記録します * * @param filesChanged 変更されたファイルの数 * @param linesAdded 追加された行数 * @param linesDeleted 削除された行数 * @param testsAdded 追加されたテストの数 */ recordFileChanges(filesChanged, linesAdded, linesDeleted, testsAdded = 0) { if (!this.currentLog) { throw new Error('No active task. Call startTask() first.'); } this.currentLog.filesChanged = filesChanged; this.currentLog.linesAdded = linesAdded; this.currentLog.linesDeleted = linesDeleted; this.currentLog.testsAdded = testsAdded; } /** * タスクを完了し、最終的なログを保存します * * @param status タスクの最終状態 * @param qualityScore 品質スコア * @param errorType エラータイプ(オプション) * @returns 完成したログ */ async completeTask(status, qualityScore, errorType) { if (!this.currentLog) { throw new Error('No active task. Call startTask() first.'); } const now = new Date().toISOString(); this.currentLog.endTime = now; this.currentLog.status = status; this.currentLog.qualityScore = qualityScore; this.currentLog.duration = new Date(now).getTime() - new Date(this.currentLog.startTime).getTime(); if (errorType) { this.currentLog.errorType = errorType; } // ログをファイルに保存 await this.saveLogToFile(this.currentLog); const completedLog = { ...this.currentLog }; this.currentLog = null; return completedLog; } /** * ログをファイルに保存します * * @param log 保存するログ */ async saveLogToFile(log) { // ログディレクトリが存在しない場合は作成 await fs_1.promises.mkdir(this.logDir, { recursive: true }); // 日付ベースのファイル名を生成 const date = new Date(log.startTime); const dateStr = date.toISOString().split('T')[0]; // YYYY-MM-DD const fileName = `${dateStr}_${log.taskId}.json`; const filePath = path_1.default.join(this.logDir, fileName); // JSON形式で保存 await fs_1.promises.writeFile(filePath, JSON.stringify(log, null, 2), 'utf-8'); } /** * 特定期間のログを読み込みます * * @param startDate 開始日 * @param endDate 終了日 * @returns 該当期間のログの配列 */ async getLogsBetween(startDate, endDate) { const logs = []; // ログディレクトリが存在しない場合は空配列を返す try { await fs_1.promises.access(this.logDir); } catch { return logs; } // ログファイルを読み込み const files = await fs_1.promises.readdir(this.logDir); for (const file of files) { if (!file.endsWith('.json')) { continue; } const filePath = path_1.default.join(this.logDir, file); const content = await fs_1.promises.readFile(filePath, 'utf-8'); const log = JSON.parse(content); const logDate = new Date(log.startTime); if (logDate >= startDate && logDate <= endDate) { logs.push(log); } } return logs.sort((a, b) => new Date(a.startTime).getTime() - new Date(b.startTime).getTime()); } /** * 現在のアクティブなログを取得します(主にテスト用) * * @returns 現在のログ、またはnull */ getCurrentLog() { return this.currentLog ? { ...this.currentLog } : null; } } exports.ExecutionLogger = ExecutionLogger; //# sourceMappingURL=execution-logger.js.map