From 4b6c876f365a1c1921afab652db99ab8646d8739 Mon Sep 17 00:00:00 2001 From: Frederico Castro Date: Thu, 26 Feb 2026 01:36:28 -0300 Subject: [PATCH] =?UTF-8?q?Hist=C3=B3rico=20persistente=20de=20execu=C3=A7?= =?UTF-8?q?=C3=B5es=20com=20visualiza=C3=A7=C3=A3o=20detalhada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Novo executionsStore em db.js com cache in-memory e escrita debounced - Camada de cache (src/cache/index.js) com TTL e suporte opcional a Redis - Persistência de execuções de agentes e pipelines com metadados completos - Pipeline grava cada etapa com prompt, resultado, timestamps e status - 4 endpoints REST: listagem paginada com filtros, detalhe, exclusão individual e limpeza total - Componente frontend (history.js) com cards, filtros, paginação e modal de detalhe - Timeline visual para pipelines com prompts colapsáveis por etapa - Correção do executor: --max-turns em vez de --max-tokens, --permission-mode bypassPermissions - Refatoração do scheduler com persistência melhorada e graceful shutdown --- public/css/styles.css | 426 ++++++++++++++++++++++++++++++++ public/index.html | 50 ++++ public/js/api.js | 7 + public/js/app.js | 38 +++ public/js/components/history.js | 421 +++++++++++++++++++++++++++++++ server.js | 26 +- src/agents/executor.js | 54 ++-- src/agents/manager.js | 146 +++++------ src/agents/pipeline.js | 109 ++++---- src/agents/scheduler.js | 104 +++----- src/cache/index.js | 153 ++++++++++++ src/routes/api.js | 170 +++++++++---- src/store/db.js | 230 ++++++++++------- 13 files changed, 1536 insertions(+), 398 deletions(-) create mode 100644 public/js/components/history.js create mode 100644 src/cache/index.js diff --git a/public/css/styles.css b/public/css/styles.css index 865148e..7dce52d 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -3295,3 +3295,429 @@ tbody tr:hover td { align-items: center; gap: 4px; } + +.toolbar-filters { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; + flex: 1; +} + +.toolbar-actions { + display: flex; + align-items: center; + gap: 8px; + flex-shrink: 0; +} + +.badge-agent { + background-color: rgba(99, 102, 241, 0.15); + color: var(--accent); +} + +.badge-pipeline { + background-color: rgba(139, 92, 246, 0.15); + color: #8b5cf6; +} + +.history-card { + background-color: var(--bg-card); + border: 1px solid var(--border-primary); + border-radius: 12px; + padding: 16px 20px; + display: flex; + flex-direction: column; + gap: 10px; + transition: all 0.2s; + animation: fadeInUp 0.2s ease both; + margin-bottom: 8px; +} + +.history-card:hover { + border-color: var(--border-secondary); + background-color: var(--bg-card-hover); +} + +.history-card-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + flex-wrap: wrap; +} + +.history-card-identity { + display: flex; + align-items: center; + gap: 8px; + min-width: 0; +} + +.history-card-name { + font-size: 15px; + font-weight: 600; + color: var(--text-primary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.history-card-status { + display: flex; + align-items: center; + gap: 10px; + flex-shrink: 0; +} + +.history-card-date { + font-size: 12px; + color: var(--text-muted); + white-space: nowrap; +} + +.history-card-meta { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.history-card-task { + font-size: 13px; + color: var(--text-secondary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + flex: 1; + min-width: 0; +} + +.history-card-duration { + display: flex; + align-items: center; + gap: 4px; + font-size: 12px; + color: var(--text-muted); + flex-shrink: 0; + white-space: nowrap; +} + +.history-card-duration i { + width: 12px; + height: 12px; + flex-shrink: 0; +} + +.history-card-actions { + display: flex; + align-items: center; + gap: 8px; + padding-top: 8px; + border-top: 1px solid var(--border-primary); +} + +.execution-result { + background-color: #08080e; + border: 1px solid var(--border-primary); + border-radius: 8px; + padding: 16px; + font-family: 'JetBrains Mono', monospace; + font-size: 12px; + color: #c8c8d8; + white-space: pre-wrap; + word-break: break-word; + overflow-y: auto; + max-height: 400px; + line-height: 1.7; +} + +.execution-result--error { + border-color: rgba(239, 68, 68, 0.3); + color: var(--error); +} + +.execution-result--prompt { + color: var(--text-secondary); + background-color: var(--bg-tertiary); + max-height: 200px; +} + +.execution-detail-meta { + display: flex; + flex-direction: column; + gap: 0; + border: 1px solid var(--border-primary); + border-radius: 10px; + overflow: hidden; + margin-bottom: 20px; +} + +.execution-detail-row { + display: flex; + align-items: center; + gap: 12px; + padding: 10px 16px; + border-bottom: 1px solid var(--border-primary); +} + +.execution-detail-row:last-child { + border-bottom: none; +} + +.execution-detail-label { + font-size: 12px; + font-weight: 500; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.4px; + min-width: 80px; + flex-shrink: 0; +} + +.execution-detail-value { + font-size: 14px; + color: var(--text-primary); + display: flex; + align-items: center; + gap: 8px; +} + +.execution-detail-section { + margin-bottom: 20px; +} + +.execution-detail-section:last-child { + margin-bottom: 0; +} + +.execution-detail-section-title { + font-size: 13px; + font-weight: 600; + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 10px; +} + +.execution-detail-task { + font-size: 14px; + color: var(--text-secondary); + line-height: 1.6; + background-color: var(--bg-tertiary); + border: 1px solid var(--border-primary); + border-radius: 8px; + padding: 12px 16px; +} + +.pipeline-timeline { + display: flex; + flex-direction: column; + gap: 0; +} + +.pipeline-step-item { + display: flex; + gap: 16px; + align-items: flex-start; +} + +.pipeline-step-connector { + display: flex; + flex-direction: column; + align-items: center; + flex-shrink: 0; + padding-top: 2px; +} + +.pipeline-step-node { + width: 28px; + height: 28px; + border-radius: 50%; + background-color: var(--bg-tertiary); + border: 2px solid var(--border-secondary); + display: flex; + align-items: center; + justify-content: center; + font-size: 11px; + font-weight: 700; + color: var(--text-secondary); + flex-shrink: 0; + z-index: 1; +} + +.pipeline-step-node--completed { + background-color: rgba(34, 197, 94, 0.15); + border-color: var(--success); + color: var(--success); +} + +.pipeline-step-node--error { + background-color: rgba(239, 68, 68, 0.15); + border-color: var(--error); + color: var(--error); +} + +.pipeline-step-connector-line { + width: 2px; + flex: 1; + min-height: 24px; + background-color: var(--border-secondary); + margin: 4px 0; +} + +.pipeline-step-detail { + flex: 1; + min-width: 0; + background-color: var(--bg-card); + border: 1px solid var(--border-primary); + border-radius: 10px; + padding: 14px 16px; + margin-bottom: 16px; + display: flex; + flex-direction: column; + gap: 12px; +} + +.pipeline-step-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.pipeline-step-identity { + display: flex; + align-items: center; + gap: 8px; + min-width: 0; +} + +.pipeline-step-agent { + font-size: 14px; + font-weight: 600; + color: var(--text-primary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.pipeline-step-duration { + display: flex; + align-items: center; + gap: 4px; + font-size: 12px; + color: var(--text-muted); + flex-shrink: 0; + white-space: nowrap; +} + +.pipeline-step-duration i { + width: 12px; + height: 12px; +} + +.pipeline-step-prompt { + display: flex; + flex-direction: column; + gap: 8px; +} + +.pipeline-step-prompt-toggle { + display: inline-flex; + align-items: center; + gap: 6px; + background: none; + border: none; + cursor: pointer; + font-size: 12px; + font-weight: 500; + color: var(--text-muted); + padding: 0; + font-family: 'Inter', sans-serif; + transition: color 0.2s; +} + +.pipeline-step-prompt-toggle:hover { + color: var(--accent); +} + +.pipeline-step-prompt-toggle[aria-expanded="true"] i { + transform: rotate(90deg); +} + +.pipeline-step-prompt-toggle i { + width: 14px; + height: 14px; + transition: transform 0.2s; +} + +.pipeline-step-prompt-body { + margin-top: 4px; +} + +.pipeline-step-result { + display: flex; + flex-direction: column; + gap: 6px; +} + +.pipeline-step-result-label { + font-size: 11px; + font-weight: 600; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.4px; +} + +.pagination { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 0; + gap: 12px; +} + +.pagination-info { + font-size: 13px; + color: var(--text-muted); +} + +.pagination-controls { + display: flex; + align-items: center; + gap: 10px; +} + +.pagination-page { + font-size: 13px; + color: var(--text-secondary); + white-space: nowrap; +} + +.input { + width: 100%; + padding: 8px 12px; + background-color: var(--bg-input); + border: 1px solid var(--border-primary); + border-radius: 8px; + color: var(--text-primary); + font-size: 14px; + font-family: 'Inter', sans-serif; + outline: none; + transition: border-color 0.2s, box-shadow 0.2s; +} + +.input:focus { + border-color: var(--accent); + box-shadow: 0 0 0 3px var(--accent-glow); +} + +.input::placeholder { + color: var(--text-muted); +} + +.input--sm { + padding: 5px 10px; + font-size: 12px; +} diff --git a/public/index.html b/public/index.html index edf90e3..32631c4 100644 --- a/public/index.html +++ b/public/index.html @@ -59,6 +59,12 @@ Terminal +