opencastle 0.21.1 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/convoy/engine.d.ts +4 -0
- package/dist/cli/convoy/engine.d.ts.map +1 -1
- package/dist/cli/convoy/engine.js +23 -1
- package/dist/cli/convoy/engine.js.map +1 -1
- package/dist/cli/convoy/engine.test.js +148 -0
- package/dist/cli/convoy/engine.test.js.map +1 -1
- package/dist/cli/convoy/export.d.ts +1 -0
- package/dist/cli/convoy/export.d.ts.map +1 -1
- package/dist/cli/convoy/export.js +39 -0
- package/dist/cli/convoy/export.js.map +1 -1
- package/dist/cli/convoy/export.test.js +31 -0
- package/dist/cli/convoy/export.test.js.map +1 -1
- package/dist/cli/convoy/pipeline.d.ts +35 -0
- package/dist/cli/convoy/pipeline.d.ts.map +1 -0
- package/dist/cli/convoy/pipeline.js +353 -0
- package/dist/cli/convoy/pipeline.js.map +1 -0
- package/dist/cli/convoy/pipeline.test.d.ts +2 -0
- package/dist/cli/convoy/pipeline.test.d.ts.map +1 -0
- package/dist/cli/convoy/pipeline.test.js +778 -0
- package/dist/cli/convoy/pipeline.test.js.map +1 -0
- package/dist/cli/convoy/store.d.ts +18 -4
- package/dist/cli/convoy/store.d.ts.map +1 -1
- package/dist/cli/convoy/store.js +119 -14
- package/dist/cli/convoy/store.js.map +1 -1
- package/dist/cli/convoy/store.test.js +413 -4
- package/dist/cli/convoy/store.test.js.map +1 -1
- package/dist/cli/convoy/types.d.ts +21 -0
- package/dist/cli/convoy/types.d.ts.map +1 -1
- package/dist/cli/dashboard.d.ts.map +1 -1
- package/dist/cli/dashboard.js +1 -0
- package/dist/cli/dashboard.js.map +1 -1
- package/dist/cli/run/adapters/claude-code.d.ts.map +1 -1
- package/dist/cli/run/adapters/claude-code.js +13 -0
- package/dist/cli/run/adapters/claude-code.js.map +1 -1
- package/dist/cli/run/adapters/copilot.d.ts.map +1 -1
- package/dist/cli/run/adapters/copilot.js +8 -0
- package/dist/cli/run/adapters/copilot.js.map +1 -1
- package/dist/cli/run/adapters/cursor.d.ts.map +1 -1
- package/dist/cli/run/adapters/cursor.js +13 -0
- package/dist/cli/run/adapters/cursor.js.map +1 -1
- package/dist/cli/run/adapters/opencode.d.ts.map +1 -1
- package/dist/cli/run/adapters/opencode.js +13 -0
- package/dist/cli/run/adapters/opencode.js.map +1 -1
- package/dist/cli/run/schema.d.ts +5 -1
- package/dist/cli/run/schema.d.ts.map +1 -1
- package/dist/cli/run/schema.js +41 -8
- package/dist/cli/run/schema.js.map +1 -1
- package/dist/cli/run/schema.test.js +194 -5
- package/dist/cli/run/schema.test.js.map +1 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +167 -2
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/types.d.ts +11 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/convoy/engine.test.ts +177 -0
- package/src/cli/convoy/engine.ts +24 -1
- package/src/cli/convoy/export.test.ts +37 -0
- package/src/cli/convoy/export.ts +46 -0
- package/src/cli/convoy/pipeline.test.ts +939 -0
- package/src/cli/convoy/pipeline.ts +430 -0
- package/src/cli/convoy/store.test.ts +452 -4
- package/src/cli/convoy/store.ts +152 -23
- package/src/cli/convoy/types.ts +23 -0
- package/src/cli/dashboard.ts +1 -0
- package/src/cli/run/adapters/claude-code.ts +13 -1
- package/src/cli/run/adapters/copilot.ts +8 -0
- package/src/cli/run/adapters/cursor.ts +13 -1
- package/src/cli/run/adapters/opencode.ts +13 -1
- package/src/cli/run/schema.test.ts +244 -5
- package/src/cli/run/schema.ts +49 -8
- package/src/cli/run.ts +163 -2
- package/src/cli/types.ts +12 -1
- package/src/dashboard/dist/_astro/{index.DyyaCW8L.css → index.Cq68OHaZ.css} +1 -1
- package/src/dashboard/dist/index.html +225 -3
- package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
- package/src/dashboard/src/pages/index.astro +241 -2
- package/src/dashboard/src/styles/dashboard.css +116 -0
- package/src/orchestrator/customizations/KNOWN-ISSUES.md +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--bg-primary: #0a0a0f;--bg-secondary: #111118;--bg-tertiary: #1a1a24;--bg-card: rgba(255, 255, 255, .03);--bg-card-hover: rgba(255, 255, 255, .06);--text-primary: #f0f0f5;--text-secondary: #8a8a9a;--text-tertiary: #5a5a6e;--text-accent: #a78bfa;--gradient-accent: linear-gradient(135deg, #a78bfa 0%, #6366f1 50%, #3b82f6 100%);--gradient-glow: radial-gradient(ellipse 800px 400px at 50% 0%, rgba(99, 102, 241, .12) 0%, transparent 70%);--border-color: rgba(255, 255, 255, .06);--border-accent: rgba(167, 139, 250, .3);--color-success: #22c55e;--color-partial: #f59e0b;--color-failed: #ef4444;--color-redirected: #64748b;--color-premium: #f59e0b;--color-standard: #a78bfa;--color-utility: #3b82f6;--color-economy: #64748b;--accent-blue: #3b82f6;--accent-purple: #a78bfa;--accent-indigo: #6366f1;--max-width: 1280px;--transition-fast: .15s cubic-bezier(.4, 0, .2, 1);--transition-base: .3s cubic-bezier(.4, 0, .2, 1)}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html{font-size:16px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Inter,Roboto,Helvetica,Arial,sans-serif;background-color:var(--bg-primary);color:var(--text-primary);line-height:1.6;overflow-x:hidden;min-height:100vh}.dash-header{position:sticky;top:0;z-index:50;background:#0a0a0fd9;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border-bottom:1px solid var(--border-color)}.dash-header__inner{max-width:var(--max-width);margin:0 auto;padding:0 24px;height:56px;display:flex;align-items:center;justify-content:space-between}.dash-header__brand{display:flex;align-items:center;gap:10px}.dash-header__icon{width:32px;height:32px;border-radius:8px;object-fit:contain}.dash-header__title{font-size:1rem;font-weight:600;color:var(--text-primary)}.dash-layout{display:flex;max-width:var(--max-width);margin:0 auto;position:relative}.dash-sidebar{position:sticky;top:56px;height:calc(100vh - 56px);width:180px;flex-shrink:0;padding:24px 0 24px 24px;overflow-y:auto;display:none}@media(min-width:1024px){.dash-sidebar{display:block}}.dash-sidebar__list{list-style:none;display:flex;flex-direction:column;gap:2px}.dash-sidebar__link{display:block;padding:8px 16px;font-size:.8125rem;font-weight:500;color:var(--text-tertiary);text-decoration:none;border-radius:8px;transition:color var(--transition-fast),background var(--transition-fast)}.dash-sidebar__link:hover{color:var(--text-secondary);background:#ffffff0a}.dash-sidebar__link--active{color:var(--text-accent);background:#a78bfa14;font-weight:600}.dash-main{flex:1;min-width:0;max-width:var(--max-width);margin:0 auto;padding:24px;display:flex;flex-direction:column;gap:20px;position:relative}.dash-main:before{content:"";position:fixed;top:0;left:50%;transform:translate(-50%);width:100%;height:600px;background:var(--gradient-glow);pointer-events:none;z-index:0}.dash-main>*{position:relative;z-index:1}[data-nav-section]{scroll-margin-top:72px}.kpi-row{display:grid;grid-template-columns:1fr;gap:12px}@media(min-width:480px){.kpi-row{grid-template-columns:repeat(2,1fr)}}@media(min-width:960px){.kpi-row{grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}}.kpi-card{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;padding:20px 24px;display:flex;flex-direction:column;gap:4px;transition:border-color var(--transition-fast)}.kpi-card:hover{border-color:#ffffff1a}.kpi-card__label{font-size:.75rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.kpi-card__value{font-size:2rem;font-weight:700;color:var(--text-primary);line-height:1.2;letter-spacing:-.02em}.kpi-card__sub{font-size:.75rem;color:var(--text-secondary);display:flex;align-items:center;gap:4px}.kpi-trend{font-weight:600}.kpi-trend--up{color:var(--color-success)}.kpi-trend--down{color:var(--color-failed)}.kpi-trend--neutral{color:var(--text-tertiary)}.chart-card{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;overflow:hidden;transition:border-color var(--transition-fast)}.chart-card:hover{border-color:#ffffff1a}.chart-card__header{padding:20px 24px 8px}.chart-card__title{font-size:.9375rem;font-weight:600;color:var(--text-primary)}.chart-card__desc{font-size:.75rem;color:var(--text-tertiary);margin-top:2px}.chart-card__body{padding:16px 24px 24px;min-height:120px}.chart-card__body--table{padding:0}.charts-row{display:grid;grid-template-columns:1fr;gap:20px}@media(min-width:768px){.charts-row{grid-template-columns:repeat(2,1fr)}}.bar-row{display:flex;align-items:center;gap:12px;padding:6px 0}.bar-row+.bar-row{border-top:1px solid rgba(255,255,255,.03)}.bar-label{font-size:.8125rem;color:var(--text-secondary);width:130px;flex-shrink:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bar-track{flex:1;height:24px;background:var(--bg-tertiary);border-radius:6px;display:flex;overflow:hidden}.bar-segment{height:100%;transition:width .8s cubic-bezier(.4,0,.2,1);min-width:0}.bar--success{background:var(--color-success)}.bar--partial{background:var(--color-partial)}.bar--failed{background:var(--color-failed)}.bar--premium{background:var(--color-premium)}.bar--standard{background:var(--color-standard)}.bar--utility{background:var(--color-utility)}.bar--economy{background:var(--color-economy)}.bar--accent{background:var(--accent-blue)}.bar-value{font-size:.8125rem;font-weight:600;color:var(--text-primary);width:36px;text-align:right;flex-shrink:0;font-variant-numeric:tabular-nums}.donut-container{display:flex;align-items:center;justify-content:center;gap:32px;flex-wrap:wrap}.donut-wrap{position:relative;width:180px;height:180px;flex-shrink:0}.donut-svg{width:100%;height:100%}.donut-svg circle{transition:stroke-dasharray .8s cubic-bezier(.4,0,.2,1),stroke-dashoffset .8s cubic-bezier(.4,0,.2,1)}.donut-center{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center}.donut-total{display:block;font-size:1.5rem;font-weight:700;color:var(--text-primary);line-height:1}.donut-total-label{display:block;font-size:.6875rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.08em;margin-top:2px}.donut-legend{display:flex;flex-direction:column;gap:10px}.legend-item{display:flex;align-items:center;gap:8px;font-size:.8125rem}.legend-dot{width:10px;height:10px;border-radius:3px;flex-shrink:0}.legend-name{color:var(--text-secondary);text-transform:capitalize}.legend-count{color:var(--text-tertiary);font-variant-numeric:tabular-nums;margin-left:auto}.timeline-svg{width:100%;height:auto;display:block}.timeline-svg text{font-family:inherit}.timeline-legend{display:flex;gap:16px;justify-content:center;margin-top:12px}.timeline-legend__item{display:flex;align-items:center;gap:6px;font-size:.75rem;color:var(--text-tertiary)}.timeline-legend__dot{width:8px;height:8px;border-radius:2px}.pipeline{display:flex;align-items:stretch;gap:0;overflow-x:auto;padding:8px 0}.pipeline-stage{flex:1;min-width:140px;display:flex;flex-direction:column;align-items:center;gap:8px;padding:16px 12px;position:relative}.pipeline-stage:not(:last-child):after{content:"";position:absolute;right:-1px;top:50%;transform:translateY(-50%);width:2px;height:40%;background:var(--border-color)}.pipeline-stage__icon{width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1rem}.pipeline-stage__icon--pending{background:#64748b26;color:#94a3b8;border:1px solid rgba(100,116,139,.2)}.pipeline-stage__icon--active{background:#3b82f626;color:#60a5fa;border:1px solid rgba(59,130,246,.3);animation:pulse-glow 2s ease-in-out infinite}.pipeline-stage__icon--review{background:#f59e0b26;color:#fbbf24;border:1px solid rgba(245,158,11,.3)}.pipeline-stage__icon--done{background:#22c55e26;color:#4ade80;border:1px solid rgba(34,197,94,.3)}@keyframes pulse-glow{0%,to{box-shadow:0 0 #3b82f633}50%{box-shadow:0 0 12px 4px #3b82f626}}.pipeline-stage__count{font-size:1.5rem;font-weight:700;color:var(--text-primary);line-height:1}.pipeline-stage__label{font-size:.75rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.04em;font-weight:500}.pipeline-arrow{display:flex;align-items:center;color:var(--text-tertiary);font-size:1.25rem;padding:0 4px;flex-shrink:0}.exec-log{display:flex;flex-direction:column}.exec-step{display:flex;gap:16px;padding:14px 0;position:relative}.exec-step+.exec-step{border-top:1px solid rgba(255,255,255,.03)}.exec-step__indicator{display:flex;flex-direction:column;align-items:center;flex-shrink:0;width:32px}.exec-step__dot{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.6875rem;font-weight:700;flex-shrink:0}.exec-step__dot--success{background:#22c55e26;color:var(--color-success);border:1.5px solid rgba(34,197,94,.3)}.exec-step__dot--partial{background:#f59e0b26;color:var(--color-partial);border:1.5px solid rgba(245,158,11,.3)}.exec-step__dot--failed{background:#ef444426;color:var(--color-failed);border:1.5px solid rgba(239,68,68,.3)}.exec-step__line{flex:1;width:1.5px;background:var(--border-color);margin-top:4px}.exec-step__content{flex:1;min-width:0}.exec-step__header{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.exec-step__agent{font-size:.875rem;font-weight:600;color:var(--text-primary)}.exec-step__badge{display:inline-flex;align-items:center;padding:2px 8px;font-size:.6875rem;font-weight:600;border-radius:100px;text-transform:capitalize}.exec-step__badge--success{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.exec-step__badge--partial{background:#f59e0b1f;color:var(--color-partial);border:1px solid rgba(245,158,11,.2)}.exec-step__badge--failed{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.exec-step__task{font-size:.8125rem;color:var(--text-secondary);margin-top:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.exec-step__meta{display:flex;gap:16px;margin-top:6px;font-size:.6875rem;color:var(--text-tertiary)}.exec-step__meta-item{display:flex;align-items:center;gap:4px}.panel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px}.panel-item{background:var(--bg-tertiary);border-radius:8px;padding:16px;display:flex;flex-direction:column;gap:8px;border:1px solid transparent;transition:border-color var(--transition-fast)}.panel-item:hover{border-color:var(--border-color)}.panel-item__header{display:flex;align-items:center;justify-content:space-between}.panel-item__key{font-size:.8125rem;font-weight:600;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.panel-item__verdict{font-size:.6875rem;font-weight:700;padding:2px 8px;border-radius:4px;text-transform:uppercase;letter-spacing:.04em}.panel-item__verdict--pass{background:#22c55e26;color:var(--color-success)}.panel-item__verdict--block{background:#ef444426;color:var(--color-failed)}.panel-item__votes{display:flex;gap:4px}.panel-item__vote{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.625rem;font-weight:700}.panel-item__vote--pass{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.panel-item__vote--block{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.panel-item__fixes{font-size:.6875rem;color:var(--text-tertiary)}.panel-item__meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px;padding-top:8px;border-top:1px solid var(--border-color)}.panel-item__meta-item{font-size:.625rem;color:var(--text-tertiary);white-space:nowrap}.sessions-table{width:100%;border-collapse:collapse;font-size:.8125rem}.sessions-table thead{position:sticky;top:0}.sessions-table th{padding:12px 16px;font-size:.6875rem;font-weight:600;color:var(--text-tertiary);text-align:left;text-transform:uppercase;letter-spacing:.06em;background:var(--bg-tertiary);border-bottom:1px solid var(--border-color)}.sessions-table th:last-child,.sessions-table td:last-child{text-align:right}.sessions-table th:nth-child(5),.sessions-table td:nth-child(5){text-align:right}.sessions-table td{padding:10px 16px;color:var(--text-secondary);border-bottom:1px solid rgba(255,255,255,.03);white-space:nowrap}.sessions-table tr:hover td{background:#ffffff05}.sessions-table .td-agent{font-weight:500;color:var(--text-primary)}.sessions-table .td-task{max-width:260px;overflow:hidden;text-overflow:ellipsis}.outcome-badge{display:inline-flex;align-items:center;padding:3px 10px;font-size:.6875rem;font-weight:600;border-radius:100px;text-transform:capitalize}.outcome-badge--success{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.outcome-badge--partial{background:#f59e0b1f;color:var(--color-partial);border:1px solid rgba(245,158,11,.2)}.outcome-badge--failed{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.td-num{font-variant-numeric:tabular-nums;text-align:right}.td-issue{font-size:.75rem;color:var(--text-accent);font-weight:500;font-variant-numeric:tabular-nums}.loading-skeleton{display:flex;align-items:center;justify-content:center;min-height:200px;color:var(--text-tertiary);font-size:.8125rem}.loading-skeleton:after{content:"Loading data…";animation:fade-pulse 1.5s ease-in-out infinite}@keyframes fade-pulse{0%,to{opacity:.4}50%{opacity:1}}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:48px 24px;text-align:center;gap:12px}.empty-state__icon{font-size:2rem;opacity:.4}.empty-state__text{font-size:.875rem;color:var(--text-tertiary);max-width:320px}.empty-state--enhanced{padding:56px 32px;gap:16px;border:1px dashed rgba(167,139,250,.15);border-radius:12px;background:radial-gradient(ellipse 300px 200px at 50% 30%,rgba(99,102,241,.04) 0%,transparent 70%),var(--bg-tertiary);position:relative;overflow:hidden}.empty-state--enhanced:before{content:"";position:absolute;inset:0;background:repeating-linear-gradient(0deg,transparent,transparent 23px,rgba(255,255,255,.015) 23px,rgba(255,255,255,.015) 24px);pointer-events:none}.empty-state__icon-wrap{width:64px;height:64px;display:flex;align-items:center;justify-content:center;border-radius:16px;background:#a78bfa0f;border:1px solid rgba(167,139,250,.12);color:var(--text-accent);animation:empty-breathe 4s ease-in-out infinite}@keyframes empty-breathe{0%,to{box-shadow:0 0 #a78bfa14;transform:scale(1)}50%{box-shadow:0 0 20px 4px #a78bfa0f;transform:scale(1.03)}}.empty-state__title{font-size:.9375rem;font-weight:600;color:var(--text-secondary);letter-spacing:-.01em}.empty-state__desc{font-size:.8125rem;color:var(--text-tertiary);max-width:380px;line-height:1.55}.kpi-card__hint{color:var(--text-tertiary);font-style:italic;font-size:.6875rem}.kpi-row--empty .kpi-card{border-style:dashed;border-color:#ffffff0a}.kpi-row--empty .kpi-card__value{color:var(--text-tertiary);opacity:.5}.welcome-banner{position:relative;background:var(--bg-secondary);border:1px solid transparent;border-radius:16px;padding:48px 40px;overflow:hidden;z-index:1}.welcome-banner:before{content:"";position:absolute;inset:-1px;border-radius:16px;padding:1px;background:linear-gradient(135deg,#a78bfa4d,#6366f126,#3b82f61a 60%,#a78bfa33);-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none;z-index:0}.welcome-banner__glow{position:absolute;top:-60px;left:50%;transform:translate(-50%);width:500px;height:300px;background:radial-gradient(ellipse at center,rgba(167,139,250,.08) 0%,rgba(99,102,241,.04) 40%,transparent 70%);pointer-events:none;z-index:0}.welcome-banner__content{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;text-align:center;gap:20px}.welcome-banner__icon{width:72px;height:72px;display:flex;align-items:center;justify-content:center;border-radius:20px;background:#a78bfa14;border:1px solid rgba(167,139,250,.15);color:var(--text-accent);animation:welcome-float 6s ease-in-out infinite}@keyframes welcome-float{0%,to{transform:translateY(0);box-shadow:0 8px 32px #a78bfa14}50%{transform:translateY(-6px);box-shadow:0 16px 48px #a78bfa1f}}.welcome-banner__title{font-size:1.375rem;font-weight:700;color:var(--text-primary);letter-spacing:-.02em;line-height:1.3}.welcome-banner__subtitle{font-size:.9375rem;color:var(--text-secondary);max-width:480px;line-height:1.6}.welcome-banner__steps{display:flex;gap:20px;margin-top:12px;flex-wrap:wrap;justify-content:center}.welcome-step{display:flex;align-items:flex-start;gap:12px;text-align:left;padding:16px 20px;background:#ffffff05;border:1px solid rgba(255,255,255,.05);border-radius:12px;min-width:200px;max-width:220px;transition:border-color var(--transition-fast),background var(--transition-fast)}.welcome-step:hover{border-color:#a78bfa26;background:#ffffff08}.welcome-step__num{width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:700;color:var(--text-accent);background:#a78bfa1a;border:1px solid rgba(167,139,250,.2);flex-shrink:0}.welcome-step__text{display:flex;flex-direction:column;gap:3px}.welcome-step__text strong{font-size:.8125rem;font-weight:600;color:var(--text-primary)}.welcome-step__text span{font-size:.75rem;color:var(--text-tertiary);line-height:1.4}@media(max-width:640px){.welcome-banner{padding:32px 24px}.welcome-banner__steps{flex-direction:column;align-items:center}.welcome-step{max-width:100%;width:100%}}@keyframes slide-up{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}.dash-main>*{animation:slide-up .5s ease-out backwards}.dash-main>*:nth-child(1){animation-delay:0ms}.dash-main>*:nth-child(2){animation-delay:60ms}.dash-main>*:nth-child(3){animation-delay:.12s}.dash-main>*:nth-child(4){animation-delay:.18s}.dash-main>*:nth-child(5){animation-delay:.24s}.dash-main>*:nth-child(6){animation-delay:.3s}.dash-main>*:nth-child(7){animation-delay:.36s}.dash-main>*:nth-child(8){animation-delay:.42s}.dash-main>*:nth-child(9){animation-delay:.48s}.dash-main>*:nth-child(10){animation-delay:.54s}.dash-main>*:nth-child(11){animation-delay:.6s}@media(max-width:640px){.bar-label{width:90px;font-size:.75rem}.donut-container{flex-direction:column;align-items:center}.donut-wrap{width:150px;height:150px}.pipeline{gap:0}.pipeline-stage{min-width:100px;padding:12px 8px}.panel-grid{grid-template-columns:1fr}.sessions-table th:nth-child(3),.sessions-table td:nth-child(3){display:none}}.filter-bar{display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end;padding:16px 20px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px}.filter-group{display:flex;flex-direction:column;gap:4px;min-width:0}.filter-label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.filter-input,.filter-select{height:34px;padding:0 10px;font-size:.8125rem;color:var(--text-primary);background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:8px;outline:none;transition:border-color var(--transition-fast);font-family:inherit}.filter-input:focus,.filter-select:focus{border-color:var(--border-accent)}.filter-input{width:140px;color-scheme:dark}.filter-select{min-width:140px;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235a5a6e' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:28px}.filter-reset{height:34px;font-size:.75rem}.dash-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;font-size:.8125rem;font-weight:500;font-family:inherit;border:none;border-radius:8px;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast)}.dash-btn--ghost{color:var(--text-secondary);background:#ffffff0f}.dash-btn--ghost:hover{color:var(--text-primary);background:#ffffff1a}.dash-header__actions{display:flex;align-items:center;gap:8px}@media(max-width:480px){.dash-header__inner{padding:0 12px}.dash-main{padding:12px;gap:12px}.kpi-card,.chart-card__header{padding:14px 16px}.chart-card__body{padding:12px 16px 16px}.filter-bar{padding:12px;gap:8px}.filter-input,.filter-select{width:100%;min-width:unset}.filter-group{flex:1 1 calc(50% - 4px)}.filter-reset{width:100%}.dash-header__title{font-size:.875rem}.exec-step__meta{flex-direction:column;gap:2px}.sessions-table th:nth-child(5),.sessions-table td:nth-child(5),.sessions-table th:nth-child(6),.sessions-table td:nth-child(6),.sessions-table th:nth-child(7),.sessions-table td:nth-child(7),.sessions-table th:nth-child(8),.sessions-table td:nth-child(8){display:none}}@media(max-width:768px){.charts-row{grid-template-columns:1fr}.pipeline{flex-wrap:wrap;gap:8px}.pipeline-arrow{display:none}.pipeline-stage{flex:1 1 calc(50% - 4px);min-width:100px}.tier-chart .donut-container,.donut-container{flex-direction:column;align-items:center}.sessions-table{font-size:.75rem}.sessions-table th,.sessions-table td{padding:8px 6px}}.convoy-overview{display:flex;flex-wrap:wrap;gap:24px;margin-bottom:20px}.convoy-stat{display:flex;flex-direction:column;gap:4px}.convoy-stat__label{font-size:.75rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-stat__value{font-size:.95rem;color:var(--text-primary)}.convoy-progress{display:flex;align-items:center;gap:12px;margin-bottom:20px}.convoy-progress__bar{flex:1;height:8px;background:var(--bg-tertiary);border-radius:4px;overflow:hidden}.convoy-progress__fill{height:100%;background:var(--gradient-accent);border-radius:4px;transition:width var(--transition-base)}.convoy-progress__label{font-size:.8rem;color:var(--text-secondary);white-space:nowrap}.convoy-tasks{margin-top:8px}
|
|
1
|
+
:root{--bg-primary: #0a0a0f;--bg-secondary: #111118;--bg-tertiary: #1a1a24;--bg-card: rgba(255, 255, 255, .03);--bg-card-hover: rgba(255, 255, 255, .06);--text-primary: #f0f0f5;--text-secondary: #8a8a9a;--text-tertiary: #5a5a6e;--text-accent: #a78bfa;--gradient-accent: linear-gradient(135deg, #a78bfa 0%, #6366f1 50%, #3b82f6 100%);--gradient-glow: radial-gradient(ellipse 800px 400px at 50% 0%, rgba(99, 102, 241, .12) 0%, transparent 70%);--border-color: rgba(255, 255, 255, .06);--border-accent: rgba(167, 139, 250, .3);--color-success: #22c55e;--color-partial: #f59e0b;--color-failed: #ef4444;--color-redirected: #64748b;--color-premium: #f59e0b;--color-standard: #a78bfa;--color-utility: #3b82f6;--color-economy: #64748b;--accent-blue: #3b82f6;--accent-purple: #a78bfa;--accent-indigo: #6366f1;--max-width: 1280px;--transition-fast: .15s cubic-bezier(.4, 0, .2, 1);--transition-base: .3s cubic-bezier(.4, 0, .2, 1)}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html{font-size:16px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Inter,Roboto,Helvetica,Arial,sans-serif;background-color:var(--bg-primary);color:var(--text-primary);line-height:1.6;overflow-x:hidden;min-height:100vh}.dash-header{position:sticky;top:0;z-index:50;background:#0a0a0fd9;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border-bottom:1px solid var(--border-color)}.dash-header__inner{max-width:var(--max-width);margin:0 auto;padding:0 24px;height:56px;display:flex;align-items:center;justify-content:space-between}.dash-header__brand{display:flex;align-items:center;gap:10px}.dash-header__icon{width:32px;height:32px;border-radius:8px;object-fit:contain}.dash-header__title{font-size:1rem;font-weight:600;color:var(--text-primary)}.dash-layout{display:flex;max-width:var(--max-width);margin:0 auto;position:relative}.dash-sidebar{position:sticky;top:56px;height:calc(100vh - 56px);width:180px;flex-shrink:0;padding:24px 0 24px 24px;overflow-y:auto;display:none}@media(min-width:1024px){.dash-sidebar{display:block}}.dash-sidebar__list{list-style:none;display:flex;flex-direction:column;gap:2px}.dash-sidebar__link{display:block;padding:8px 16px;font-size:.8125rem;font-weight:500;color:var(--text-tertiary);text-decoration:none;border-radius:8px;transition:color var(--transition-fast),background var(--transition-fast)}.dash-sidebar__link:hover{color:var(--text-secondary);background:#ffffff0a}.dash-sidebar__link--active{color:var(--text-accent);background:#a78bfa14;font-weight:600}.dash-main{flex:1;min-width:0;max-width:var(--max-width);margin:0 auto;padding:24px;display:flex;flex-direction:column;gap:20px;position:relative}.dash-main:before{content:"";position:fixed;top:0;left:50%;transform:translate(-50%);width:100%;height:600px;background:var(--gradient-glow);pointer-events:none;z-index:0}.dash-main>*{position:relative;z-index:1}[data-nav-section]{scroll-margin-top:72px}.kpi-row{display:grid;grid-template-columns:1fr;gap:12px}@media(min-width:480px){.kpi-row{grid-template-columns:repeat(2,1fr)}}@media(min-width:960px){.kpi-row{grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}}.kpi-card{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;padding:20px 24px;display:flex;flex-direction:column;gap:4px;transition:border-color var(--transition-fast)}.kpi-card:hover{border-color:#ffffff1a}.kpi-card__label{font-size:.75rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.kpi-card__value{font-size:2rem;font-weight:700;color:var(--text-primary);line-height:1.2;letter-spacing:-.02em}.kpi-card__sub{font-size:.75rem;color:var(--text-secondary);display:flex;align-items:center;gap:4px}.kpi-trend{font-weight:600}.kpi-trend--up{color:var(--color-success)}.kpi-trend--down{color:var(--color-failed)}.kpi-trend--neutral{color:var(--text-tertiary)}.chart-card{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;overflow:hidden;transition:border-color var(--transition-fast)}.chart-card:hover{border-color:#ffffff1a}.chart-card__header{padding:20px 24px 8px}.chart-card__title{font-size:.9375rem;font-weight:600;color:var(--text-primary)}.chart-card__desc{font-size:.75rem;color:var(--text-tertiary);margin-top:2px}.chart-card__body{padding:16px 24px 24px;min-height:120px}.chart-card__body--table{padding:0}.charts-row{display:grid;grid-template-columns:1fr;gap:20px}@media(min-width:768px){.charts-row{grid-template-columns:repeat(2,1fr)}}.bar-row{display:flex;align-items:center;gap:12px;padding:6px 0}.bar-row+.bar-row{border-top:1px solid rgba(255,255,255,.03)}.bar-label{font-size:.8125rem;color:var(--text-secondary);width:130px;flex-shrink:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bar-track{flex:1;height:24px;background:var(--bg-tertiary);border-radius:6px;display:flex;overflow:hidden}.bar-segment{height:100%;transition:width .8s cubic-bezier(.4,0,.2,1);min-width:0}.bar--success{background:var(--color-success)}.bar--partial{background:var(--color-partial)}.bar--failed{background:var(--color-failed)}.bar--premium{background:var(--color-premium)}.bar--standard{background:var(--color-standard)}.bar--utility{background:var(--color-utility)}.bar--economy{background:var(--color-economy)}.bar--accent{background:var(--accent-blue)}.bar-value{font-size:.8125rem;font-weight:600;color:var(--text-primary);width:36px;text-align:right;flex-shrink:0;font-variant-numeric:tabular-nums}.donut-container{display:flex;align-items:center;justify-content:center;gap:32px;flex-wrap:wrap}.donut-wrap{position:relative;width:180px;height:180px;flex-shrink:0}.donut-svg{width:100%;height:100%}.donut-svg circle{transition:stroke-dasharray .8s cubic-bezier(.4,0,.2,1),stroke-dashoffset .8s cubic-bezier(.4,0,.2,1)}.donut-center{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center}.donut-total{display:block;font-size:1.5rem;font-weight:700;color:var(--text-primary);line-height:1}.donut-total-label{display:block;font-size:.6875rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.08em;margin-top:2px}.donut-legend{display:flex;flex-direction:column;gap:10px}.legend-item{display:flex;align-items:center;gap:8px;font-size:.8125rem}.legend-dot{width:10px;height:10px;border-radius:3px;flex-shrink:0}.legend-name{color:var(--text-secondary);text-transform:capitalize}.legend-count{color:var(--text-tertiary);font-variant-numeric:tabular-nums;margin-left:auto}.timeline-svg{width:100%;height:auto;display:block}.timeline-svg text{font-family:inherit}.timeline-legend{display:flex;gap:16px;justify-content:center;margin-top:12px}.timeline-legend__item{display:flex;align-items:center;gap:6px;font-size:.75rem;color:var(--text-tertiary)}.timeline-legend__dot{width:8px;height:8px;border-radius:2px}.pipeline{display:flex;align-items:stretch;gap:0;overflow-x:auto;padding:8px 0}.pipeline-stage{flex:1;min-width:140px;display:flex;flex-direction:column;align-items:center;gap:8px;padding:16px 12px;position:relative}.pipeline-stage:not(:last-child):after{content:"";position:absolute;right:-1px;top:50%;transform:translateY(-50%);width:2px;height:40%;background:var(--border-color)}.pipeline-stage__icon{width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1rem}.pipeline-stage__icon--pending{background:#64748b26;color:#94a3b8;border:1px solid rgba(100,116,139,.2)}.pipeline-stage__icon--active{background:#3b82f626;color:#60a5fa;border:1px solid rgba(59,130,246,.3);animation:pulse-glow 2s ease-in-out infinite}.pipeline-stage__icon--review{background:#f59e0b26;color:#fbbf24;border:1px solid rgba(245,158,11,.3)}.pipeline-stage__icon--done{background:#22c55e26;color:#4ade80;border:1px solid rgba(34,197,94,.3)}@keyframes pulse-glow{0%,to{box-shadow:0 0 #3b82f633}50%{box-shadow:0 0 12px 4px #3b82f626}}.pipeline-stage__count{font-size:1.5rem;font-weight:700;color:var(--text-primary);line-height:1}.pipeline-stage__label{font-size:.75rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.04em;font-weight:500}.pipeline-arrow{display:flex;align-items:center;color:var(--text-tertiary);font-size:1.25rem;padding:0 4px;flex-shrink:0}.exec-log{display:flex;flex-direction:column}.exec-step{display:flex;gap:16px;padding:14px 0;position:relative}.exec-step+.exec-step{border-top:1px solid rgba(255,255,255,.03)}.exec-step__indicator{display:flex;flex-direction:column;align-items:center;flex-shrink:0;width:32px}.exec-step__dot{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.6875rem;font-weight:700;flex-shrink:0}.exec-step__dot--success{background:#22c55e26;color:var(--color-success);border:1.5px solid rgba(34,197,94,.3)}.exec-step__dot--partial{background:#f59e0b26;color:var(--color-partial);border:1.5px solid rgba(245,158,11,.3)}.exec-step__dot--failed{background:#ef444426;color:var(--color-failed);border:1.5px solid rgba(239,68,68,.3)}.exec-step__line{flex:1;width:1.5px;background:var(--border-color);margin-top:4px}.exec-step__content{flex:1;min-width:0}.exec-step__header{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.exec-step__agent{font-size:.875rem;font-weight:600;color:var(--text-primary)}.exec-step__badge{display:inline-flex;align-items:center;padding:2px 8px;font-size:.6875rem;font-weight:600;border-radius:100px;text-transform:capitalize}.exec-step__badge--success{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.exec-step__badge--partial{background:#f59e0b1f;color:var(--color-partial);border:1px solid rgba(245,158,11,.2)}.exec-step__badge--failed{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.exec-step__task{font-size:.8125rem;color:var(--text-secondary);margin-top:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.exec-step__meta{display:flex;gap:16px;margin-top:6px;font-size:.6875rem;color:var(--text-tertiary)}.exec-step__meta-item{display:flex;align-items:center;gap:4px}.panel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px}.panel-item{background:var(--bg-tertiary);border-radius:8px;padding:16px;display:flex;flex-direction:column;gap:8px;border:1px solid transparent;transition:border-color var(--transition-fast)}.panel-item:hover{border-color:var(--border-color)}.panel-item__header{display:flex;align-items:center;justify-content:space-between}.panel-item__key{font-size:.8125rem;font-weight:600;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.panel-item__verdict{font-size:.6875rem;font-weight:700;padding:2px 8px;border-radius:4px;text-transform:uppercase;letter-spacing:.04em}.panel-item__verdict--pass{background:#22c55e26;color:var(--color-success)}.panel-item__verdict--block{background:#ef444426;color:var(--color-failed)}.panel-item__votes{display:flex;gap:4px}.panel-item__vote{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.625rem;font-weight:700}.panel-item__vote--pass{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.panel-item__vote--block{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.panel-item__fixes{font-size:.6875rem;color:var(--text-tertiary)}.panel-item__meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px;padding-top:8px;border-top:1px solid var(--border-color)}.panel-item__meta-item{font-size:.625rem;color:var(--text-tertiary);white-space:nowrap}.sessions-table{width:100%;border-collapse:collapse;font-size:.8125rem}.sessions-table thead{position:sticky;top:0}.sessions-table th{padding:12px 16px;font-size:.6875rem;font-weight:600;color:var(--text-tertiary);text-align:left;text-transform:uppercase;letter-spacing:.06em;background:var(--bg-tertiary);border-bottom:1px solid var(--border-color)}.sessions-table th:last-child,.sessions-table td:last-child{text-align:right}.sessions-table th:nth-child(5),.sessions-table td:nth-child(5){text-align:right}.sessions-table td{padding:10px 16px;color:var(--text-secondary);border-bottom:1px solid rgba(255,255,255,.03);white-space:nowrap}.sessions-table tr:hover td{background:#ffffff05}.sessions-table .td-agent{font-weight:500;color:var(--text-primary)}.sessions-table .td-task{max-width:260px;overflow:hidden;text-overflow:ellipsis}.outcome-badge{display:inline-flex;align-items:center;padding:3px 10px;font-size:.6875rem;font-weight:600;border-radius:100px;text-transform:capitalize}.outcome-badge--success{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.outcome-badge--partial{background:#f59e0b1f;color:var(--color-partial);border:1px solid rgba(245,158,11,.2)}.outcome-badge--failed{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.td-num{font-variant-numeric:tabular-nums;text-align:right}.td-issue{font-size:.75rem;color:var(--text-accent);font-weight:500;font-variant-numeric:tabular-nums}.loading-skeleton{display:flex;align-items:center;justify-content:center;min-height:200px;color:var(--text-tertiary);font-size:.8125rem}.loading-skeleton:after{content:"Loading data…";animation:fade-pulse 1.5s ease-in-out infinite}@keyframes fade-pulse{0%,to{opacity:.4}50%{opacity:1}}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:48px 24px;text-align:center;gap:12px}.empty-state__icon{font-size:2rem;opacity:.4}.empty-state__text{font-size:.875rem;color:var(--text-tertiary);max-width:320px}.empty-state--enhanced{padding:56px 32px;gap:16px;border:1px dashed rgba(167,139,250,.15);border-radius:12px;background:radial-gradient(ellipse 300px 200px at 50% 30%,rgba(99,102,241,.04) 0%,transparent 70%),var(--bg-tertiary);position:relative;overflow:hidden}.empty-state--enhanced:before{content:"";position:absolute;inset:0;background:repeating-linear-gradient(0deg,transparent,transparent 23px,rgba(255,255,255,.015) 23px,rgba(255,255,255,.015) 24px);pointer-events:none}.empty-state__icon-wrap{width:64px;height:64px;display:flex;align-items:center;justify-content:center;border-radius:16px;background:#a78bfa0f;border:1px solid rgba(167,139,250,.12);color:var(--text-accent);animation:empty-breathe 4s ease-in-out infinite}@keyframes empty-breathe{0%,to{box-shadow:0 0 #a78bfa14;transform:scale(1)}50%{box-shadow:0 0 20px 4px #a78bfa0f;transform:scale(1.03)}}.empty-state__title{font-size:.9375rem;font-weight:600;color:var(--text-secondary);letter-spacing:-.01em}.empty-state__desc{font-size:.8125rem;color:var(--text-tertiary);max-width:380px;line-height:1.55}.kpi-card__hint{color:var(--text-tertiary);font-style:italic;font-size:.6875rem}.kpi-row--empty .kpi-card{border-style:dashed;border-color:#ffffff0a}.kpi-row--empty .kpi-card__value{color:var(--text-tertiary);opacity:.5}.welcome-banner{position:relative;background:var(--bg-secondary);border:1px solid transparent;border-radius:16px;padding:48px 40px;overflow:hidden;z-index:1}.welcome-banner:before{content:"";position:absolute;inset:-1px;border-radius:16px;padding:1px;background:linear-gradient(135deg,#a78bfa4d,#6366f126,#3b82f61a 60%,#a78bfa33);-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none;z-index:0}.welcome-banner__glow{position:absolute;top:-60px;left:50%;transform:translate(-50%);width:500px;height:300px;background:radial-gradient(ellipse at center,rgba(167,139,250,.08) 0%,rgba(99,102,241,.04) 40%,transparent 70%);pointer-events:none;z-index:0}.welcome-banner__content{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;text-align:center;gap:20px}.welcome-banner__icon{width:72px;height:72px;display:flex;align-items:center;justify-content:center;border-radius:20px;background:#a78bfa14;border:1px solid rgba(167,139,250,.15);color:var(--text-accent);animation:welcome-float 6s ease-in-out infinite}@keyframes welcome-float{0%,to{transform:translateY(0);box-shadow:0 8px 32px #a78bfa14}50%{transform:translateY(-6px);box-shadow:0 16px 48px #a78bfa1f}}.welcome-banner__title{font-size:1.375rem;font-weight:700;color:var(--text-primary);letter-spacing:-.02em;line-height:1.3}.welcome-banner__subtitle{font-size:.9375rem;color:var(--text-secondary);max-width:480px;line-height:1.6}.welcome-banner__steps{display:flex;gap:20px;margin-top:12px;flex-wrap:wrap;justify-content:center}.welcome-step{display:flex;align-items:flex-start;gap:12px;text-align:left;padding:16px 20px;background:#ffffff05;border:1px solid rgba(255,255,255,.05);border-radius:12px;min-width:200px;max-width:220px;transition:border-color var(--transition-fast),background var(--transition-fast)}.welcome-step:hover{border-color:#a78bfa26;background:#ffffff08}.welcome-step__num{width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:700;color:var(--text-accent);background:#a78bfa1a;border:1px solid rgba(167,139,250,.2);flex-shrink:0}.welcome-step__text{display:flex;flex-direction:column;gap:3px}.welcome-step__text strong{font-size:.8125rem;font-weight:600;color:var(--text-primary)}.welcome-step__text span{font-size:.75rem;color:var(--text-tertiary);line-height:1.4}@media(max-width:640px){.welcome-banner{padding:32px 24px}.welcome-banner__steps{flex-direction:column;align-items:center}.welcome-step{max-width:100%;width:100%}}@keyframes slide-up{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}.dash-main>*{animation:slide-up .5s ease-out backwards}.dash-main>*:nth-child(1){animation-delay:0ms}.dash-main>*:nth-child(2){animation-delay:60ms}.dash-main>*:nth-child(3){animation-delay:.12s}.dash-main>*:nth-child(4){animation-delay:.18s}.dash-main>*:nth-child(5){animation-delay:.24s}.dash-main>*:nth-child(6){animation-delay:.3s}.dash-main>*:nth-child(7){animation-delay:.36s}.dash-main>*:nth-child(8){animation-delay:.42s}.dash-main>*:nth-child(9){animation-delay:.48s}.dash-main>*:nth-child(10){animation-delay:.54s}.dash-main>*:nth-child(11){animation-delay:.6s}@media(max-width:640px){.bar-label{width:90px;font-size:.75rem}.donut-container{flex-direction:column;align-items:center}.donut-wrap{width:150px;height:150px}.pipeline{gap:0}.pipeline-stage{min-width:100px;padding:12px 8px}.panel-grid{grid-template-columns:1fr}.sessions-table th:nth-child(3),.sessions-table td:nth-child(3){display:none}}.filter-bar{display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end;padding:16px 20px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px}.filter-group{display:flex;flex-direction:column;gap:4px;min-width:0}.filter-label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.filter-input,.filter-select{height:34px;padding:0 10px;font-size:.8125rem;color:var(--text-primary);background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:8px;outline:none;transition:border-color var(--transition-fast);font-family:inherit}.filter-input:focus,.filter-select:focus{border-color:var(--border-accent)}.filter-input{width:140px;color-scheme:dark}.filter-select{min-width:140px;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235a5a6e' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:28px}.filter-reset{height:34px;font-size:.75rem}.dash-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;font-size:.8125rem;font-weight:500;font-family:inherit;border:none;border-radius:8px;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast)}.dash-btn--ghost{color:var(--text-secondary);background:#ffffff0f}.dash-btn--ghost:hover{color:var(--text-primary);background:#ffffff1a}.dash-header__actions{display:flex;align-items:center;gap:8px}@media(max-width:480px){.dash-header__inner{padding:0 12px}.dash-main{padding:12px;gap:12px}.kpi-card,.chart-card__header{padding:14px 16px}.chart-card__body{padding:12px 16px 16px}.filter-bar{padding:12px;gap:8px}.filter-input,.filter-select{width:100%;min-width:unset}.filter-group{flex:1 1 calc(50% - 4px)}.filter-reset{width:100%}.dash-header__title{font-size:.875rem}.exec-step__meta{flex-direction:column;gap:2px}.sessions-table th:nth-child(5),.sessions-table td:nth-child(5),.sessions-table th:nth-child(6),.sessions-table td:nth-child(6),.sessions-table th:nth-child(7),.sessions-table td:nth-child(7),.sessions-table th:nth-child(8),.sessions-table td:nth-child(8){display:none}}@media(max-width:768px){.charts-row{grid-template-columns:1fr}.pipeline{flex-wrap:wrap;gap:8px}.pipeline-arrow{display:none}.pipeline-stage{flex:1 1 calc(50% - 4px);min-width:100px}.tier-chart .donut-container,.donut-container{flex-direction:column;align-items:center}.sessions-table{font-size:.75rem}.sessions-table th,.sessions-table td{padding:8px 6px}}.convoy-overview{display:flex;flex-wrap:wrap;gap:24px;margin-bottom:20px}.convoy-stat{display:flex;flex-direction:column;gap:4px}.convoy-stat__label{font-size:.75rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-stat__value{font-size:.95rem;color:var(--text-primary)}.convoy-progress{display:flex;align-items:center;gap:12px;margin-bottom:20px}.convoy-progress__bar{flex:1;height:8px;background:var(--bg-tertiary);border-radius:4px;overflow:hidden}.convoy-progress__fill{height:100%;background:var(--gradient-accent);border-radius:4px;transition:width var(--transition-base)}.convoy-progress__label{font-size:.8rem;color:var(--text-secondary);white-space:nowrap}.convoy-tasks{margin-top:8px}.convoy-chain{display:flex;align-items:stretch;gap:0;overflow-x:auto;padding:1rem 0 1.5rem;scrollbar-width:thin;scrollbar-color:var(--border-color) transparent}.convoy-chain::-webkit-scrollbar{height:4px}.convoy-chain::-webkit-scrollbar-track{background:transparent}.convoy-chain::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:2px}.convoy-chain__connector{display:flex;align-items:center;padding:0 .5rem;color:var(--text-tertiary);font-size:1.1rem;flex-shrink:0}.convoy-chain__node{display:flex;flex-direction:column;align-items:center;gap:6px;padding:12px 16px;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:10px;min-width:140px;cursor:pointer;transition:background var(--transition-fast),border-color var(--transition-fast),transform var(--transition-fast),box-shadow var(--transition-fast);flex-shrink:0}.convoy-chain__node:hover{background:var(--bg-card-hover);transform:translateY(-2px);box-shadow:0 4px 12px #0000004d}.convoy-chain__node-name{font-size:.8rem;font-weight:600;color:var(--text-primary);text-align:center;word-break:break-word;max-width:120px}.convoy-chain__node-meta{font-size:.72rem;color:var(--text-tertiary);text-align:center}.convoy-chain__node--active{border-color:var(--accent-purple);box-shadow:0 0 0 1px var(--accent-purple),0 0 12px #a78bfa33;animation:convoy-pulse 2s ease-in-out infinite}.convoy-chain__node--done{border-color:#22c55e4d}.convoy-chain__node--failed{border-color:#ef44444d}.convoy-chain__node--pending{opacity:.6}@keyframes convoy-pulse{0%,to{box-shadow:0 0 0 1px var(--accent-purple),0 0 8px #a78bfa26}50%{box-shadow:0 0 0 1px var(--accent-purple),0 0 18px #a78bfa59}}@media(max-width:768px){.convoy-chain{flex-wrap:wrap;gap:8px}.convoy-chain__connector{display:none}.convoy-chain__node{flex:1 1 calc(50% - 4px);min-width:120px}}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Observability Dashboard — OpenCastle</title><meta name="description" content="Real-time observability for OpenCastle multi-agent orchestration — sessions, delegations, model tiers, and quality gates."><meta name="theme-color" content="#0a0a0f"><link rel="icon" type="image/png" sizes="192x192" href="/icon-192.png"><link rel="stylesheet" href="/_astro/index.
|
|
1
|
+
<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Observability Dashboard — OpenCastle</title><meta name="description" content="Real-time observability for OpenCastle multi-agent orchestration — sessions, delegations, model tiers, and quality gates."><meta name="theme-color" content="#0a0a0f"><link rel="icon" type="image/png" sizes="192x192" href="/icon-192.png"><link rel="stylesheet" href="/_astro/index.Cq68OHaZ.css"></head> <body> <header class="dash-header"> <div class="dash-header__inner"> <div class="dash-header__brand"> <img class="dash-header__icon" src="/icon-192.png" alt="OpenCastle" width="32" height="32"> <h1 class="dash-header__title">Observability Dashboard</h1> </div> <div class="dash-header__actions"> <button class="dash-btn dash-btn--ghost" id="export-btn" type="button" title="Export data as JSON"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
|
|
2
2
|
Export
|
|
3
|
-
</button> </div> </div> </header> <div class="dash-layout"> <!-- Sidebar Navigation --> <nav class="dash-sidebar" id="dash-sidebar"> <ul class="dash-sidebar__list"> <li><a class="dash-sidebar__link" href="#convoy-section" data-section="convoy-section">Convoy</a></li> <li><a class="dash-sidebar__link dash-sidebar__link--active" href="#kpi-row" data-section="kpi-row">Overview</a></li> <li><a class="dash-sidebar__link" href="#pipeline-section" data-section="pipeline-section">
|
|
3
|
+
</button> </div> </div> </header> <div class="dash-layout"> <!-- Sidebar Navigation --> <nav class="dash-sidebar" id="dash-sidebar"> <ul class="dash-sidebar__list"> <li><a class="dash-sidebar__link" href="#convoy-section" data-section="convoy-section">Convoy</a></li> <li><a class="dash-sidebar__link" href="#convoy-pipeline-section" data-section="convoy-pipeline-section">Convoy Chain</a></li> <li><a class="dash-sidebar__link dash-sidebar__link--active" href="#kpi-row" data-section="kpi-row">Overview</a></li> <li><a class="dash-sidebar__link" href="#pipeline-section" data-section="pipeline-section">Task Flow</a></li> <li><a class="dash-sidebar__link" href="#agent-section" data-section="agent-section">Agents</a></li> <li><a class="dash-sidebar__link" href="#tier-section" data-section="tier-section">Tiers</a></li> <li><a class="dash-sidebar__link" href="#delegation-section" data-section="delegation-section">Delegations</a></li> <li><a class="dash-sidebar__link" href="#timeline-section" data-section="timeline-section">Timeline</a></li> <li><a class="dash-sidebar__link" href="#model-section" data-section="model-section">Models</a></li> <li><a class="dash-sidebar__link" href="#execution-section" data-section="execution-section">Exec Log</a></li> <li><a class="dash-sidebar__link" href="#panel-section" data-section="panel-section">Panels</a></li> <li><a class="dash-sidebar__link" href="#reviews-section" data-section="reviews-section">Reviews</a></li> <li><a class="dash-sidebar__link" href="#sessions-section" data-section="sessions-section">Sessions</a></li> </ul> </nav> <main class="dash-main"> <!-- Filter Bar --> <div class="filter-bar" id="filter-bar"> <div class="filter-group"> <label class="filter-label" for="filter-date-from">From</label> <input class="filter-input" type="date" id="filter-date-from"> </div> <div class="filter-group"> <label class="filter-label" for="filter-date-to">To</label> <input class="filter-input" type="date" id="filter-date-to"> </div> <div class="filter-group"> <label class="filter-label" for="filter-agent">Agent</label> <select class="filter-select" id="filter-agent"> <option value="">All agents</option> </select> </div> <div class="filter-group"> <label class="filter-label" for="filter-outcome">Outcome</label> <select class="filter-select" id="filter-outcome"> <option value="">All outcomes</option> <option value="success">Success</option> <option value="partial">Partial</option> <option value="failed">Failed</option> </select> </div> <div class="filter-group"> <label class="filter-label" for="filter-convoy">Convoy</label> <select class="filter-select" id="filter-convoy"> <option value="">All convoys</option> </select> </div> <div class="filter-group"> <label class="filter-label" for="filter-pipeline">Pipeline</label> <select class="filter-select" id="filter-pipeline"> <option value="">All</option> </select> </div> <button class="dash-btn dash-btn--ghost filter-reset" id="filter-reset" type="button">Reset</button> </div> <!-- Convoy Status Section --> <section class="chart-card convoy-status" id="convoy-section" data-nav-section style="display:none"> <div class="chart-card__header"> <h2 class="chart-card__title">Convoy Status</h2> <p class="chart-card__desc" id="convoy-desc">Select a convoy to view details</p> </div> <div class="chart-card__body" id="convoy-body"></div> </section> <!-- Convoy Pipeline (Chaining) Section --> <section class="chart-card" id="convoy-pipeline-section" data-nav-section style="display:none"> <div class="chart-card__header"> <h2 class="chart-card__title">Convoy Pipeline</h2> <p class="chart-card__desc" id="convoy-pipeline-desc">Pipeline convoy chain progress</p> </div> <div class="chart-card__body" id="convoy-pipeline-body"></div> </section> <!-- KPI Row --> <section class="kpi-row" id="kpi-row" data-nav-section> <div class="kpi-card" id="kpi-sessions"> <span class="kpi-card__label">Total Sessions</span> <span class="kpi-card__value">—</span> <span class="kpi-card__sub"></span> </div> <div class="kpi-card" id="kpi-success"> <span class="kpi-card__label">Success Rate</span> <span class="kpi-card__value">—</span> <span class="kpi-card__sub"></span> </div> <div class="kpi-card" id="kpi-delegations"> <span class="kpi-card__label">Total Delegations</span> <span class="kpi-card__value">—</span> <span class="kpi-card__sub"></span> </div> <div class="kpi-card" id="kpi-duration"> <span class="kpi-card__label">Avg Duration</span> <span class="kpi-card__value">—</span> <span class="kpi-card__sub"></span> </div> <div class="kpi-card" id="kpi-retries"> <span class="kpi-card__label">Total Retries</span> <span class="kpi-card__value">—</span> <span class="kpi-card__sub"></span> </div> <div class="kpi-card" id="kpi-lessons"> <span class="kpi-card__label">Lessons Added</span> <span class="kpi-card__value">—</span> <span class="kpi-card__sub"></span> </div> </section> <!-- Pipeline View (Steroids-inspired) --> <section class="chart-card" id="pipeline-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Task Pipeline</h2> <p class="chart-card__desc">Delegation flow across execution phases</p> </div> <div class="chart-card__body" id="pipeline-view"> <div class="loading-skeleton"></div> </div> </section> <!-- Charts Row 1 --> <div class="charts-row" id="agent-section" data-nav-section> <section class="chart-card"> <div class="chart-card__header"> <h2 class="chart-card__title">Sessions by Agent</h2> <p class="chart-card__desc">Stacked by outcome</p> </div> <div class="chart-card__body" id="agent-chart"> <div class="loading-skeleton"></div> </div> </section> <section class="chart-card" id="tier-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Tier Distribution</h2> <p class="chart-card__desc">Delegation model tiers</p> </div> <div class="chart-card__body" id="tier-chart"> <div class="loading-skeleton"></div> </div> </section> </div> <!-- Charts Row: Delegation Insights --> <div class="charts-row" id="delegation-section" data-nav-section> <section class="chart-card"> <div class="chart-card__header"> <h2 class="chart-card__title">Delegation Mechanism</h2> <p class="chart-card__desc">Sub-agent vs background split</p> </div> <div class="chart-card__body" id="mechanism-chart"> <div class="loading-skeleton"></div> </div> </section> <section class="chart-card"> <div class="chart-card__header"> <h2 class="chart-card__title">Delegation Outcomes</h2> <p class="chart-card__desc">Success rate by delegation</p> </div> <div class="chart-card__body" id="delegation-outcome-chart"> <div class="loading-skeleton"></div> </div> </section> </div> <!-- Charts Row 2 --> <div class="charts-row" id="timeline-section" data-nav-section> <section class="chart-card"> <div class="chart-card__header"> <h2 class="chart-card__title">Timeline</h2> <p class="chart-card__desc">Sessions and delegations over time</p> </div> <div class="chart-card__body" id="timeline-chart"> <div class="loading-skeleton"></div> </div> </section> <section class="chart-card" id="model-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Model Usage</h2> <p class="chart-card__desc">Sessions by model</p> </div> <div class="chart-card__body" id="model-chart"> <div class="loading-skeleton"></div> </div> </section> </div> <!-- Execution Log (Duvo-inspired) --> <section class="chart-card" id="execution-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Execution Log</h2> <p class="chart-card__desc">Recent agent activity, step by step</p> </div> <div class="chart-card__body" id="execution-log"> <div class="loading-skeleton"></div> </div> </section> <!-- Panel Results --> <section class="chart-card" id="panel-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Panel Reviews</h2> <p class="chart-card__desc">Quality gate verdicts and fix items</p> </div> <div class="chart-card__body" id="panel-chart"> <div class="loading-skeleton"></div> </div> </section> <!-- Fast Reviews --> <section class="chart-card" id="reviews-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Fast Reviews</h2> <p class="chart-card__desc">Single-reviewer quality gate results</p> </div> <div class="chart-card__body chart-card__body--table" id="reviews-table"> <div class="loading-skeleton"></div> </div> </section> <!-- Sessions Table --> <section class="chart-card" id="sessions-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Recent Sessions</h2> <p class="chart-card__desc">Last 15 sessions by timestamp</p> </div> <div class="chart-card__body chart-card__body--table" id="sessions-table"> <div class="loading-skeleton"></div> </div> </section> </main> </div> </body></html> <script>(function(){const base = "/";
|
|
4
4
|
|
|
5
5
|
// ── Data Loading ──────────────────────────────────────────
|
|
6
6
|
|
|
@@ -66,6 +66,12 @@ Export
|
|
|
66
66
|
return div.innerHTML;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
function formatTokens(n) {
|
|
70
|
+
if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M';
|
|
71
|
+
if (n >= 1000) return (n / 1000).toFixed(1) + 'K';
|
|
72
|
+
return String(n);
|
|
73
|
+
}
|
|
74
|
+
|
|
69
75
|
// ── SVG Icon Library (empty states) ────────────────────
|
|
70
76
|
|
|
71
77
|
const EMPTY_ICONS = {
|
|
@@ -929,6 +935,7 @@ Export
|
|
|
929
935
|
let rawPanels = [];
|
|
930
936
|
let rawReviews = [];
|
|
931
937
|
let rawConvoys = [];
|
|
938
|
+
let rawPipelines = [];
|
|
932
939
|
|
|
933
940
|
function applyFilters() {
|
|
934
941
|
const dateFrom = document.getElementById('filter-date-from').value;
|
|
@@ -936,6 +943,7 @@ Export
|
|
|
936
943
|
const agentFilter = document.getElementById('filter-agent').value;
|
|
937
944
|
const outcomeFilter = document.getElementById('filter-outcome').value;
|
|
938
945
|
const convoyFilter = document.getElementById('filter-convoy').value;
|
|
946
|
+
const pipelineFilter = document.getElementById('filter-pipeline')?.value || '';
|
|
939
947
|
|
|
940
948
|
function matchDate(ts) {
|
|
941
949
|
const date = ts.slice(0, 10);
|
|
@@ -965,6 +973,18 @@ Export
|
|
|
965
973
|
return true;
|
|
966
974
|
});
|
|
967
975
|
|
|
976
|
+
// Pipeline filter: restrict events to convoy_ids within the selected pipeline
|
|
977
|
+
if (pipelineFilter) {
|
|
978
|
+
const activePipeline = rawPipelines.find((p) => p.id === pipelineFilter);
|
|
979
|
+
const pipelineConvoyIds = new Set((activePipeline && activePipeline.convoy_ids) || []);
|
|
980
|
+
if (pipelineConvoyIds.size > 0) {
|
|
981
|
+
sessions = sessions.filter((s) => !s.convoy_id || pipelineConvoyIds.has(s.convoy_id));
|
|
982
|
+
delegations = delegations.filter((d) => !d.convoy_id || pipelineConvoyIds.has(d.convoy_id));
|
|
983
|
+
panels = panels.filter((p2) => !p2.convoy_id || pipelineConvoyIds.has(p2.convoy_id));
|
|
984
|
+
reviews = reviews.filter((r) => !r.convoy_id || pipelineConvoyIds.has(r.convoy_id));
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
968
988
|
if (convoyFilter) {
|
|
969
989
|
sessions = sessions.filter((s) => s.convoy_id === convoyFilter);
|
|
970
990
|
delegations = delegations.filter((d) => d.convoy_id === convoyFilter);
|
|
@@ -981,6 +1001,17 @@ Export
|
|
|
981
1001
|
}
|
|
982
1002
|
}
|
|
983
1003
|
|
|
1004
|
+
// Show/hide convoy pipeline section based on pipeline filter
|
|
1005
|
+
const pipelineSectionEl = document.getElementById('convoy-pipeline-section');
|
|
1006
|
+
if (pipelineSectionEl) {
|
|
1007
|
+
if (pipelineFilter) {
|
|
1008
|
+
const activePipeline = rawPipelines.find((p) => p.id === pipelineFilter);
|
|
1009
|
+
renderConvoyPipeline(activePipeline, rawConvoys);
|
|
1010
|
+
} else {
|
|
1011
|
+
pipelineSectionEl.style.display = 'none';
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
984
1015
|
renderAll(sessions, delegations, panels, reviews);
|
|
985
1016
|
}
|
|
986
1017
|
|
|
@@ -1133,6 +1164,9 @@ Export
|
|
|
1133
1164
|
html += '<div class="convoy-stat"><span class="convoy-stat__label">Tasks</span><span class="convoy-stat__value">' + done + '/' + total + '</span></div>';
|
|
1134
1165
|
html += '<div class="convoy-stat"><span class="convoy-stat__label">Events</span><span class="convoy-stat__value">' + (convoy.events_count || 0) + '</span></div>';
|
|
1135
1166
|
html += '<div class="convoy-stat"><span class="convoy-stat__label">Started</span><span class="convoy-stat__value">' + (convoy.started_at ? formatTime(convoy.started_at) : '\u2014') + '</span></div>';
|
|
1167
|
+
if (convoy.total_tokens != null) {
|
|
1168
|
+
html += '<div class="convoy-stat"><span class="convoy-stat__label">Tokens</span><span class="convoy-stat__value">' + formatTokens(convoy.total_tokens) + '</span></div>';
|
|
1169
|
+
}
|
|
1136
1170
|
html += '</div>';
|
|
1137
1171
|
|
|
1138
1172
|
html += '<div class="convoy-progress">';
|
|
@@ -1142,7 +1176,7 @@ Export
|
|
|
1142
1176
|
|
|
1143
1177
|
if (convoy.tasks && convoy.tasks.length > 0) {
|
|
1144
1178
|
html += '<table class="sessions-table convoy-tasks">';
|
|
1145
|
-
html += '<thead><tr><th>Task</th><th>Phase</th><th>Agent</th><th>Adapter</th><th>Status</th><th>Retries</th></tr></thead>';
|
|
1179
|
+
html += '<thead><tr><th>Task</th><th>Phase</th><th>Agent</th><th>Adapter</th><th>Status</th><th>Retries</th><th>Tokens</th></tr></thead>';
|
|
1146
1180
|
html += '<tbody>';
|
|
1147
1181
|
convoy.tasks.forEach(function(t) {
|
|
1148
1182
|
const tStatus = t.status === 'done' ? 'success'
|
|
@@ -1155,6 +1189,7 @@ Export
|
|
|
1155
1189
|
html += '<td>' + escapeHtml(t.adapter || '\u2014') + '</td>';
|
|
1156
1190
|
html += '<td><span class="outcome-badge outcome-badge--' + tStatus + '">' + escapeHtml(t.status) + '</span></td>';
|
|
1157
1191
|
html += '<td class="td-num">' + (t.retries || 0) + '</td>';
|
|
1192
|
+
html += '<td class="td-num">' + (t.total_tokens != null ? formatTokens(t.total_tokens) : '\u2014') + '</td>';
|
|
1158
1193
|
html += '</tr>';
|
|
1159
1194
|
});
|
|
1160
1195
|
html += '</tbody></table>';
|
|
@@ -1163,9 +1198,186 @@ Export
|
|
|
1163
1198
|
bodyEl.innerHTML = html;
|
|
1164
1199
|
}
|
|
1165
1200
|
|
|
1201
|
+
// ── Pipeline Filter Population ───────────────────────────
|
|
1202
|
+
|
|
1203
|
+
function populatePipelineFilter(pipelines) {
|
|
1204
|
+
const select = document.getElementById('filter-pipeline');
|
|
1205
|
+
if (!select) return;
|
|
1206
|
+
while (select.options.length > 1) select.remove(1);
|
|
1207
|
+
const sorted = pipelines.slice().sort((a, b) =>
|
|
1208
|
+
(b.created_at || '').localeCompare(a.created_at || '')
|
|
1209
|
+
);
|
|
1210
|
+
sorted.forEach((p) => {
|
|
1211
|
+
const opt = document.createElement('option');
|
|
1212
|
+
opt.value = p.id;
|
|
1213
|
+
opt.textContent = (p.name || p.id) + ' (' + (p.status || 'unknown') + ')';
|
|
1214
|
+
select.appendChild(opt);
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// ── Convoy Pipeline (Chaining) Render ────────────────────
|
|
1219
|
+
|
|
1220
|
+
function renderConvoyPipeline(pipeline, convoys) {
|
|
1221
|
+
const sectionEl = document.getElementById('convoy-pipeline-section');
|
|
1222
|
+
const descEl = document.getElementById('convoy-pipeline-desc');
|
|
1223
|
+
const bodyEl = document.getElementById('convoy-pipeline-body');
|
|
1224
|
+
if (!sectionEl || !bodyEl) return;
|
|
1225
|
+
|
|
1226
|
+
if (!pipeline) {
|
|
1227
|
+
sectionEl.style.display = 'none';
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
sectionEl.style.display = '';
|
|
1232
|
+
if (descEl) {
|
|
1233
|
+
descEl.textContent =
|
|
1234
|
+
(pipeline.name || pipeline.id) + ' \u2014 ' + (pipeline.branch || 'no branch');
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
const convoyIds = pipeline.convoy_ids || [];
|
|
1238
|
+
const pipelineConvoys = convoyIds
|
|
1239
|
+
.map((id) => convoys.find((c) => c.id === id))
|
|
1240
|
+
.filter(Boolean);
|
|
1241
|
+
|
|
1242
|
+
const total = pipelineConvoys.length;
|
|
1243
|
+
const done = pipelineConvoys.filter((c) => c.status === 'done').length;
|
|
1244
|
+
const failed = pipelineConvoys.filter(
|
|
1245
|
+
(c) => c.status === 'failed' || c.status === 'gate-failed'
|
|
1246
|
+
).length;
|
|
1247
|
+
const totalTasks = pipelineConvoys.reduce((sum, c) => {
|
|
1248
|
+
const s = c.summary || {};
|
|
1249
|
+
return sum + (s.total || (c.tasks ? c.tasks.length : 0));
|
|
1250
|
+
}, 0);
|
|
1251
|
+
const doneTasks = pipelineConvoys.reduce((sum, c) => {
|
|
1252
|
+
const s = c.summary || {};
|
|
1253
|
+
return sum + (s.done || 0);
|
|
1254
|
+
}, 0);
|
|
1255
|
+
const totalTokens = pipelineConvoys.reduce((sum, c) => sum + (c.total_tokens || 0), 0);
|
|
1256
|
+
|
|
1257
|
+
const pct =
|
|
1258
|
+
totalTasks > 0
|
|
1259
|
+
? Math.round((doneTasks / totalTasks) * 100)
|
|
1260
|
+
: total > 0
|
|
1261
|
+
? Math.round((done / total) * 100)
|
|
1262
|
+
: 0;
|
|
1263
|
+
|
|
1264
|
+
const statusClass =
|
|
1265
|
+
pipeline.status === 'done'
|
|
1266
|
+
? 'success'
|
|
1267
|
+
: pipeline.status === 'failed' || pipeline.status === 'gate-failed'
|
|
1268
|
+
? 'failed'
|
|
1269
|
+
: pipeline.status === 'running'
|
|
1270
|
+
? 'partial'
|
|
1271
|
+
: '';
|
|
1272
|
+
|
|
1273
|
+
let html = '<div class="convoy-overview">';
|
|
1274
|
+
html +=
|
|
1275
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Status</span>' +
|
|
1276
|
+
'<span class="outcome-badge outcome-badge--' + statusClass + '">' +
|
|
1277
|
+
escapeHtml(pipeline.status || 'unknown') + '</span></div>';
|
|
1278
|
+
html +=
|
|
1279
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Branch</span>' +
|
|
1280
|
+
'<span class="convoy-stat__value">' + escapeHtml(pipeline.branch || '\u2014') + '</span></div>';
|
|
1281
|
+
html +=
|
|
1282
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Convoys</span>' +
|
|
1283
|
+
'<span class="convoy-stat__value">' + done + '/' + total + '</span></div>';
|
|
1284
|
+
if (totalTasks > 0) {
|
|
1285
|
+
html +=
|
|
1286
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Tasks</span>' +
|
|
1287
|
+
'<span class="convoy-stat__value">' + doneTasks + '/' + totalTasks + '</span></div>';
|
|
1288
|
+
}
|
|
1289
|
+
if (totalTokens > 0) {
|
|
1290
|
+
html +=
|
|
1291
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Tokens</span>' +
|
|
1292
|
+
'<span class="convoy-stat__value">' + formatTokens(totalTokens) + '</span></div>';
|
|
1293
|
+
}
|
|
1294
|
+
html +=
|
|
1295
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Started</span>' +
|
|
1296
|
+
'<span class="convoy-stat__value">' +
|
|
1297
|
+
(pipeline.started_at ? formatTime(pipeline.started_at) : '\u2014') + '</span></div>';
|
|
1298
|
+
if (pipeline.finished_at) {
|
|
1299
|
+
html +=
|
|
1300
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Finished</span>' +
|
|
1301
|
+
'<span class="convoy-stat__value">' + formatTime(pipeline.finished_at) + '</span></div>';
|
|
1302
|
+
}
|
|
1303
|
+
html += '</div>';
|
|
1304
|
+
|
|
1305
|
+
// Convoy chain visualization
|
|
1306
|
+
html += '<div class="convoy-chain">';
|
|
1307
|
+
pipelineConvoys.forEach((convoy, i) => {
|
|
1308
|
+
const cs = convoy.summary || {};
|
|
1309
|
+
const cDone = cs.done || 0;
|
|
1310
|
+
const cTotal = cs.total || (convoy.tasks ? convoy.tasks.length : 0);
|
|
1311
|
+
const cTokens = convoy.total_tokens || 0;
|
|
1312
|
+
const isActive =
|
|
1313
|
+
(pipeline.current_convoy_id && pipeline.current_convoy_id === convoy.id) ||
|
|
1314
|
+
convoy.status === 'running';
|
|
1315
|
+
const nodeStatusClass =
|
|
1316
|
+
convoy.status === 'done'
|
|
1317
|
+
? 'done'
|
|
1318
|
+
: convoy.status === 'failed' || convoy.status === 'gate-failed'
|
|
1319
|
+
? 'failed'
|
|
1320
|
+
: isActive
|
|
1321
|
+
? 'active'
|
|
1322
|
+
: 'pending';
|
|
1323
|
+
const badgeClass =
|
|
1324
|
+
convoy.status === 'done'
|
|
1325
|
+
? 'success'
|
|
1326
|
+
: convoy.status === 'failed' || convoy.status === 'gate-failed'
|
|
1327
|
+
? 'failed'
|
|
1328
|
+
: convoy.status === 'running'
|
|
1329
|
+
? 'partial'
|
|
1330
|
+
: '';
|
|
1331
|
+
|
|
1332
|
+
if (i > 0) {
|
|
1333
|
+
html += '<div class="convoy-chain__connector">\u2192</div>';
|
|
1334
|
+
}
|
|
1335
|
+
html +=
|
|
1336
|
+
'<div class="convoy-chain__node convoy-chain__node--' + nodeStatusClass +
|
|
1337
|
+
'" data-convoy-id="' + escapeHtml(convoy.id) + '" title="Click to filter to this convoy">';
|
|
1338
|
+
html += '<div class="convoy-chain__node-name">' + escapeHtml(convoy.name || convoy.id) + '</div>';
|
|
1339
|
+
html +=
|
|
1340
|
+
'<span class="outcome-badge outcome-badge--' + badgeClass + '">' +
|
|
1341
|
+
escapeHtml(convoy.status) + '</span>';
|
|
1342
|
+
if (cTotal > 0) {
|
|
1343
|
+
html += '<div class="convoy-chain__node-meta">' + cDone + '/' + cTotal + ' tasks</div>';
|
|
1344
|
+
}
|
|
1345
|
+
if (cTokens > 0) {
|
|
1346
|
+
html += '<div class="convoy-chain__node-meta">' + formatTokens(cTokens) + ' tokens</div>';
|
|
1347
|
+
}
|
|
1348
|
+
html += '</div>';
|
|
1349
|
+
});
|
|
1350
|
+
html += '</div>';
|
|
1351
|
+
|
|
1352
|
+
// Progress bar
|
|
1353
|
+
html += '<div class="convoy-progress">';
|
|
1354
|
+
html +=
|
|
1355
|
+
'<div class="convoy-progress__bar">' +
|
|
1356
|
+
'<div class="convoy-progress__fill" style="width:' + pct + '%"></div></div>';
|
|
1357
|
+
html +=
|
|
1358
|
+
'<span class="convoy-progress__label">' + pct + '% complete' +
|
|
1359
|
+
(failed > 0 ? ' \u00B7 ' + failed + ' failed' : '') + '</span>';
|
|
1360
|
+
html += '</div>';
|
|
1361
|
+
|
|
1362
|
+
bodyEl.innerHTML = html;
|
|
1363
|
+
|
|
1364
|
+
// Click handlers for convoy drill-down
|
|
1365
|
+
bodyEl.querySelectorAll('.convoy-chain__node').forEach((node) => {
|
|
1366
|
+
node.addEventListener('click', () => {
|
|
1367
|
+
const convoyId = node.dataset.convoyId;
|
|
1368
|
+
const sel = document.getElementById('filter-convoy');
|
|
1369
|
+
if (sel && convoyId) {
|
|
1370
|
+
sel.value = convoyId;
|
|
1371
|
+
applyFilters();
|
|
1372
|
+
}
|
|
1373
|
+
});
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1166
1377
|
async function main() {
|
|
1167
1378
|
const events = await loadNdjson(base + 'data/events.ndjson');
|
|
1168
1379
|
const convoys = await loadNdjson(base + 'data/convoys.ndjson');
|
|
1380
|
+
const pipelines = await loadNdjson(base + 'data/pipelines.ndjson');
|
|
1169
1381
|
|
|
1170
1382
|
const sessions = events.filter((e) => e.type === 'session');
|
|
1171
1383
|
const delegations = events.filter((e) => e.type === 'delegation');
|
|
@@ -1177,9 +1389,11 @@ Export
|
|
|
1177
1389
|
rawPanels = panels;
|
|
1178
1390
|
rawReviews = reviews;
|
|
1179
1391
|
rawConvoys = convoys;
|
|
1392
|
+
rawPipelines = pipelines;
|
|
1180
1393
|
|
|
1181
1394
|
populateAgentFilter(sessions, delegations, reviews);
|
|
1182
1395
|
populateConvoyFilter(convoys);
|
|
1396
|
+
populatePipelineFilter(pipelines);
|
|
1183
1397
|
|
|
1184
1398
|
// ── Read URL params ───────────────────────────────────
|
|
1185
1399
|
const urlParams = new URLSearchParams(window.location.search);
|
|
@@ -1208,12 +1422,14 @@ Export
|
|
|
1208
1422
|
document.getElementById('filter-agent')?.addEventListener('change', applyFilters);
|
|
1209
1423
|
document.getElementById('filter-outcome')?.addEventListener('change', applyFilters);
|
|
1210
1424
|
document.getElementById('filter-convoy')?.addEventListener('change', applyFilters);
|
|
1425
|
+
document.getElementById('filter-pipeline')?.addEventListener('change', applyFilters);
|
|
1211
1426
|
document.getElementById('filter-reset')?.addEventListener('click', () => {
|
|
1212
1427
|
document.getElementById('filter-date-from').value = '';
|
|
1213
1428
|
document.getElementById('filter-date-to').value = '';
|
|
1214
1429
|
document.getElementById('filter-agent').value = '';
|
|
1215
1430
|
document.getElementById('filter-outcome').value = '';
|
|
1216
1431
|
document.getElementById('filter-convoy').value = '';
|
|
1432
|
+
document.getElementById('filter-pipeline').value = '';
|
|
1217
1433
|
applyFilters();
|
|
1218
1434
|
});
|
|
1219
1435
|
|
|
@@ -1224,15 +1440,21 @@ Export
|
|
|
1224
1440
|
refreshInterval = setInterval(async () => {
|
|
1225
1441
|
const freshEvents = await loadNdjson(base + 'data/events.ndjson');
|
|
1226
1442
|
const freshConvoys = await loadNdjson(base + 'data/convoys.ndjson');
|
|
1443
|
+
const freshPipelines = await loadNdjson(base + 'data/pipelines.ndjson');
|
|
1227
1444
|
rawSessions = freshEvents.filter((e) => e.type === 'session');
|
|
1228
1445
|
rawDelegations = freshEvents.filter((e) => e.type === 'delegation');
|
|
1229
1446
|
rawPanels = freshEvents.filter((e) => e.type === 'panel');
|
|
1230
1447
|
rawReviews = freshEvents.filter((e) => e.type === 'review');
|
|
1231
1448
|
rawConvoys = freshConvoys;
|
|
1449
|
+
rawPipelines = freshPipelines;
|
|
1232
1450
|
const currentValue = document.getElementById('filter-convoy')?.value;
|
|
1451
|
+
const currentPipelineValue = document.getElementById('filter-pipeline')?.value;
|
|
1233
1452
|
populateConvoyFilter(freshConvoys);
|
|
1453
|
+
populatePipelineFilter(freshPipelines);
|
|
1234
1454
|
const sel = document.getElementById('filter-convoy');
|
|
1235
1455
|
if (sel && currentValue) sel.value = currentValue;
|
|
1456
|
+
const pSel = document.getElementById('filter-pipeline');
|
|
1457
|
+
if (pSel && currentPipelineValue) pSel.value = currentPipelineValue;
|
|
1236
1458
|
applyFilters();
|
|
1237
1459
|
}, 5000);
|
|
1238
1460
|
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
{
|
|
2
|
-
"hash": "
|
|
2
|
+
"hash": "9a53c120",
|
|
3
3
|
"configHash": "30f8ea04",
|
|
4
|
-
"lockfileHash": "
|
|
5
|
-
"browserHash": "
|
|
4
|
+
"lockfileHash": "a72a0f06",
|
|
5
|
+
"browserHash": "4ac49c6f",
|
|
6
6
|
"optimized": {
|
|
7
7
|
"astro > cssesc": {
|
|
8
8
|
"src": "../../../../../node_modules/cssesc/cssesc.js",
|
|
9
9
|
"file": "astro___cssesc.js",
|
|
10
|
-
"fileHash": "
|
|
10
|
+
"fileHash": "f6c9bcaa",
|
|
11
11
|
"needsInterop": true
|
|
12
12
|
},
|
|
13
13
|
"astro > aria-query": {
|
|
14
14
|
"src": "../../../../../node_modules/aria-query/lib/index.js",
|
|
15
15
|
"file": "astro___aria-query.js",
|
|
16
|
-
"fileHash": "
|
|
16
|
+
"fileHash": "fd7def22",
|
|
17
17
|
"needsInterop": true
|
|
18
18
|
},
|
|
19
19
|
"astro > axobject-query": {
|
|
20
20
|
"src": "../../../../../node_modules/axobject-query/lib/index.js",
|
|
21
21
|
"file": "astro___axobject-query.js",
|
|
22
|
-
"fileHash": "
|
|
22
|
+
"fileHash": "c92436d0",
|
|
23
23
|
"needsInterop": true
|
|
24
24
|
}
|
|
25
25
|
},
|