UNPKG

chromancer

Version:

A powerful command-line interface for automating Chrome browser using Playwright. Perfect for web scraping, automation, testing, and browser workflows.

157 lines (156 loc) 5.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RunLogManager = void 0; const tslib_1 = require("tslib"); const promises_1 = tslib_1.__importDefault(require("fs/promises")); const path_1 = tslib_1.__importDefault(require("path")); const uuid_1 = require("uuid"); class RunLogManager { logsDir; constructor(baseDir = '.chromancer') { this.logsDir = path_1.default.join(baseDir, 'run-logs'); } async init() { await promises_1.default.mkdir(this.logsDir, { recursive: true }); } async createRunLog(executionResult, options) { const runLog = { id: (0, uuid_1.v4)(), workflowId: options.workflowId, timestamp: Date.now(), url: options.url, steps: this.convertStepsToLogs(executionResult.steps), elapsedMs: executionResult.totalDuration, domDigest: options.domDigest, claudeAnalysis: options.claudeAnalysis, success: executionResult.failedSteps === 0, failureReason: executionResult.failedSteps > 0 ? this.getFailureReason(executionResult.steps) : undefined }; await this.saveRunLog(runLog); return runLog; } convertStepsToLogs(steps) { return steps.map(step => { const log = { n: step.stepNumber, cmd: step.command, ok: step.success, duration: step.duration || 0 }; if (!step.success && step.error) { log.why = step.error; } // Extract selector and digest info from evaluate commands if (step.command === 'evaluate' && step.args) { log.selector = this.extractSelector(step.args); if (step.output) { try { const result = JSON.parse(step.output); if (Array.isArray(result)) { log.digest = { count: result.length, samples: result.slice(0, 3).map(item => typeof item === 'string' ? item : JSON.stringify(item)) }; } else { log.digest = { count: 1, samples: [step.output.substring(0, 100)] }; } } catch { // For non-JSON output if (step.output.includes('0 items') || step.output === '[]') { log.digest = { count: 0 }; } } } } return log; }); } extractSelector(args) { if (args.expression) { // Try to extract selector from expression const match = args.expression.match(/querySelectorAll\(['"]([^'"]+)['"]\)/); if (match) return match[1]; const match2 = args.expression.match(/querySelector\(['"]([^'"]+)['"]\)/); if (match2) return match2[1]; } return undefined; } getFailureReason(steps) { const failedSteps = steps.filter(s => !s.success); if (failedSteps.length === 0) return 'Unknown'; const reasons = failedSteps.map(s => `Step ${s.stepNumber} (${s.command}): ${s.error || 'Failed'}`); return reasons.join('; '); } async saveRunLog(runLog) { const filename = `${runLog.id}.json`; const filepath = path_1.default.join(this.logsDir, filename); await promises_1.default.writeFile(filepath, JSON.stringify(runLog, null, 2), 'utf8'); } async getRunLog(id) { try { const filepath = path_1.default.join(this.logsDir, `${id}.json`); const content = await promises_1.default.readFile(filepath, 'utf8'); return JSON.parse(content); } catch { return null; } } async listRunLogs(workflowId) { try { const files = await promises_1.default.readdir(this.logsDir); const logs = []; for (const file of files) { if (file.endsWith('.json')) { const content = await promises_1.default.readFile(path_1.default.join(this.logsDir, file), 'utf8'); const log = JSON.parse(content); if (!workflowId || log.workflowId === workflowId) { logs.push(log); } } } return logs.sort((a, b) => b.timestamp - a.timestamp); } catch { return []; } } formatRunLogForClaude(runLog) { const lines = [ `Run ID: ${runLog.id}`, `URL: ${runLog.url}`, `Success: ${runLog.success}`, `Duration: ${runLog.elapsedMs}ms`, '', 'Steps:' ]; runLog.steps.forEach(step => { const status = step.ok ? '✅' : '❌'; lines.push(` ${status} Step ${step.n}: ${step.cmd}`); if (!step.ok && step.why) { lines.push(` Error: ${step.why}`); } if (step.selector) { lines.push(` Selector: ${step.selector}`); } if (step.digest) { lines.push(` Found: ${step.digest.count} items`); if (step.digest.samples && step.digest.samples.length > 0) { lines.push(` Samples: ${step.digest.samples.slice(0, 2).join(', ')}`); } } }); if (runLog.failureReason) { lines.push('', `Failure: ${runLog.failureReason}`); } return lines.join('\n'); } } exports.RunLogManager = RunLogManager;