opencastle 0.31.7 → 0.32.1
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/README.md +4 -1
- package/bin/cli.mjs +15 -0
- package/dist/cli/agents.d.ts.map +1 -1
- package/dist/cli/agents.js +19 -5
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/artifacts-cli.d.ts +3 -0
- package/dist/cli/artifacts-cli.d.ts.map +1 -0
- package/dist/cli/artifacts-cli.js +36 -0
- package/dist/cli/artifacts-cli.js.map +1 -0
- package/dist/cli/baselines.d.ts.map +1 -1
- package/dist/cli/baselines.js +11 -0
- package/dist/cli/baselines.js.map +1 -1
- package/dist/cli/convoy/artifacts.d.ts +25 -0
- package/dist/cli/convoy/artifacts.d.ts.map +1 -0
- package/dist/cli/convoy/artifacts.js +129 -0
- package/dist/cli/convoy/artifacts.js.map +1 -0
- package/dist/cli/convoy/artifacts.test.d.ts +2 -0
- package/dist/cli/convoy/artifacts.test.d.ts.map +1 -0
- package/dist/cli/convoy/artifacts.test.js +169 -0
- package/dist/cli/convoy/artifacts.test.js.map +1 -0
- package/dist/cli/convoy/compaction.d.ts +23 -0
- package/dist/cli/convoy/compaction.d.ts.map +1 -0
- package/dist/cli/convoy/compaction.js +117 -0
- package/dist/cli/convoy/compaction.js.map +1 -0
- package/dist/cli/convoy/compaction.test.d.ts +2 -0
- package/dist/cli/convoy/compaction.test.d.ts.map +1 -0
- package/dist/cli/convoy/compaction.test.js +205 -0
- package/dist/cli/convoy/compaction.test.js.map +1 -0
- package/dist/cli/convoy/contracts.d.ts +22 -0
- package/dist/cli/convoy/contracts.d.ts.map +1 -0
- package/dist/cli/convoy/contracts.js +254 -0
- package/dist/cli/convoy/contracts.js.map +1 -0
- package/dist/cli/convoy/contracts.test.d.ts +2 -0
- package/dist/cli/convoy/contracts.test.d.ts.map +1 -0
- package/dist/cli/convoy/contracts.test.js +239 -0
- package/dist/cli/convoy/contracts.test.js.map +1 -0
- package/dist/cli/convoy/dag-analysis.d.ts +40 -0
- package/dist/cli/convoy/dag-analysis.d.ts.map +1 -0
- package/dist/cli/convoy/dag-analysis.js +282 -0
- package/dist/cli/convoy/dag-analysis.js.map +1 -0
- package/dist/cli/convoy/dag-analysis.test.d.ts +2 -0
- package/dist/cli/convoy/dag-analysis.test.d.ts.map +1 -0
- package/dist/cli/convoy/dag-analysis.test.js +289 -0
- package/dist/cli/convoy/dag-analysis.test.js.map +1 -0
- package/dist/cli/convoy/effort-scaling.d.ts +20 -0
- package/dist/cli/convoy/effort-scaling.d.ts.map +1 -0
- package/dist/cli/convoy/effort-scaling.js +82 -0
- package/dist/cli/convoy/effort-scaling.js.map +1 -0
- package/dist/cli/convoy/effort-scaling.test.d.ts +2 -0
- package/dist/cli/convoy/effort-scaling.test.d.ts.map +1 -0
- package/dist/cli/convoy/effort-scaling.test.js +120 -0
- package/dist/cli/convoy/effort-scaling.test.js.map +1 -0
- package/dist/cli/convoy/engine.d.ts.map +1 -1
- package/dist/cli/convoy/engine.js +280 -6
- package/dist/cli/convoy/engine.js.map +1 -1
- package/dist/cli/convoy/engine.test.js +155 -18
- package/dist/cli/convoy/engine.test.js.map +1 -1
- package/dist/cli/convoy/event-schemas.d.ts.map +1 -1
- package/dist/cli/convoy/event-schemas.js +55 -0
- package/dist/cli/convoy/event-schemas.js.map +1 -1
- package/dist/cli/convoy/isolation.d.ts +27 -0
- package/dist/cli/convoy/isolation.d.ts.map +1 -0
- package/dist/cli/convoy/isolation.js +120 -0
- package/dist/cli/convoy/isolation.js.map +1 -0
- package/dist/cli/convoy/isolation.test.d.ts +2 -0
- package/dist/cli/convoy/isolation.test.d.ts.map +1 -0
- package/dist/cli/convoy/isolation.test.js +105 -0
- package/dist/cli/convoy/isolation.test.js.map +1 -0
- package/dist/cli/convoy/review-stages.d.ts +9 -0
- package/dist/cli/convoy/review-stages.d.ts.map +1 -0
- package/dist/cli/convoy/review-stages.js +134 -0
- package/dist/cli/convoy/review-stages.js.map +1 -0
- package/dist/cli/convoy/review-stages.test.d.ts +2 -0
- package/dist/cli/convoy/review-stages.test.d.ts.map +1 -0
- package/dist/cli/convoy/review-stages.test.js +197 -0
- package/dist/cli/convoy/review-stages.test.js.map +1 -0
- package/dist/cli/convoy/skill-refinement.d.ts +39 -0
- package/dist/cli/convoy/skill-refinement.d.ts.map +1 -0
- package/dist/cli/convoy/skill-refinement.js +239 -0
- package/dist/cli/convoy/skill-refinement.js.map +1 -0
- package/dist/cli/convoy/skill-refinement.test.d.ts +2 -0
- package/dist/cli/convoy/skill-refinement.test.d.ts.map +1 -0
- package/dist/cli/convoy/skill-refinement.test.js +230 -0
- package/dist/cli/convoy/skill-refinement.test.js.map +1 -0
- package/dist/cli/convoy/spec-builder.d.ts +1 -0
- package/dist/cli/convoy/spec-builder.d.ts.map +1 -1
- package/dist/cli/convoy/spec-builder.js +11 -0
- package/dist/cli/convoy/spec-builder.js.map +1 -1
- package/dist/cli/convoy/spec-builder.test.js +54 -0
- package/dist/cli/convoy/spec-builder.test.js.map +1 -1
- package/dist/cli/convoy/store.d.ts +3 -2
- package/dist/cli/convoy/store.d.ts.map +1 -1
- package/dist/cli/convoy/store.js +20 -2
- package/dist/cli/convoy/store.js.map +1 -1
- package/dist/cli/convoy/store.test.js +15 -15
- package/dist/cli/convoy/store.test.js.map +1 -1
- package/dist/cli/convoy/tdd-gate.d.ts +15 -0
- package/dist/cli/convoy/tdd-gate.d.ts.map +1 -0
- package/dist/cli/convoy/tdd-gate.js +119 -0
- package/dist/cli/convoy/tdd-gate.js.map +1 -0
- package/dist/cli/convoy/tdd-gate.test.d.ts +2 -0
- package/dist/cli/convoy/tdd-gate.test.d.ts.map +1 -0
- package/dist/cli/convoy/tdd-gate.test.js +227 -0
- package/dist/cli/convoy/tdd-gate.test.js.map +1 -0
- package/dist/cli/convoy/types.d.ts +91 -0
- package/dist/cli/convoy/types.d.ts.map +1 -1
- package/dist/cli/convoy/types.js +8 -0
- package/dist/cli/convoy/types.js.map +1 -1
- package/dist/cli/insights.d.ts +3 -0
- package/dist/cli/insights.d.ts.map +1 -0
- package/dist/cli/insights.js +94 -0
- package/dist/cli/insights.js.map +1 -0
- package/dist/cli/lesson.d.ts.map +1 -1
- package/dist/cli/lesson.js +7 -0
- package/dist/cli/lesson.js.map +1 -1
- package/dist/cli/log.d.ts.map +1 -1
- package/dist/cli/log.js +7 -0
- package/dist/cli/log.js.map +1 -1
- package/dist/cli/package-config.d.ts +12 -0
- package/dist/cli/package-config.d.ts.map +1 -0
- package/dist/cli/package-config.js +37 -0
- package/dist/cli/package-config.js.map +1 -0
- package/dist/cli/package.d.ts +23 -0
- package/dist/cli/package.d.ts.map +1 -0
- package/dist/cli/package.js +285 -0
- package/dist/cli/package.js.map +1 -0
- package/dist/cli/package.test.d.ts +2 -0
- package/dist/cli/package.test.d.ts.map +1 -0
- package/dist/cli/package.test.js +236 -0
- package/dist/cli/package.test.js.map +1 -0
- package/dist/cli/pipeline.d.ts +6 -0
- package/dist/cli/pipeline.d.ts.map +1 -1
- package/dist/cli/pipeline.js +15 -2
- package/dist/cli/pipeline.js.map +1 -1
- package/dist/cli/run/schema.d.ts.map +1 -1
- package/dist/cli/run/schema.js +32 -0
- package/dist/cli/run/schema.js.map +1 -1
- package/dist/cli/run/schema.test.js +51 -0
- package/dist/cli/run/schema.test.js.map +1 -1
- package/dist/cli/skills.d.ts +3 -0
- package/dist/cli/skills.d.ts.map +1 -0
- package/dist/cli/skills.js +107 -0
- package/dist/cli/skills.js.map +1 -0
- package/dist/cli/types.d.ts +4 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/dashboard/scripts/etl.d.ts.map +1 -1
- package/dist/dashboard/scripts/etl.js +44 -11
- package/dist/dashboard/scripts/etl.js.map +1 -1
- package/package.json +2 -1
- package/src/cli/agents.ts +20 -5
- package/src/cli/artifacts-cli.ts +41 -0
- package/src/cli/baselines.ts +12 -0
- package/src/cli/convoy/artifacts.test.ts +201 -0
- package/src/cli/convoy/artifacts.ts +186 -0
- package/src/cli/convoy/compaction.test.ts +245 -0
- package/src/cli/convoy/compaction.ts +164 -0
- package/src/cli/convoy/contracts.test.ts +279 -0
- package/src/cli/convoy/contracts.ts +280 -0
- package/src/cli/convoy/dag-analysis.test.ts +349 -0
- package/src/cli/convoy/dag-analysis.ts +371 -0
- package/src/cli/convoy/effort-scaling.test.ts +140 -0
- package/src/cli/convoy/effort-scaling.ts +90 -0
- package/src/cli/convoy/engine.test.ts +175 -18
- package/src/cli/convoy/engine.ts +301 -7
- package/src/cli/convoy/event-schemas.ts +55 -0
- package/src/cli/convoy/isolation.test.ts +137 -0
- package/src/cli/convoy/isolation.ts +165 -0
- package/src/cli/convoy/review-stages.test.ts +235 -0
- package/src/cli/convoy/review-stages.ts +166 -0
- package/src/cli/convoy/skill-refinement.test.ts +277 -0
- package/src/cli/convoy/skill-refinement.ts +306 -0
- package/src/cli/convoy/spec-builder.test.ts +61 -0
- package/src/cli/convoy/spec-builder.ts +9 -0
- package/src/cli/convoy/store.test.ts +15 -15
- package/src/cli/convoy/store.ts +26 -4
- package/src/cli/convoy/tdd-gate.test.ts +281 -0
- package/src/cli/convoy/tdd-gate.ts +154 -0
- package/src/cli/convoy/types.ts +51 -0
- package/src/cli/insights.ts +99 -0
- package/src/cli/lesson.ts +8 -0
- package/src/cli/log.ts +8 -0
- package/src/cli/package-config.ts +48 -0
- package/src/cli/package.test.ts +276 -0
- package/src/cli/package.ts +329 -0
- package/src/cli/pipeline.ts +21 -2
- package/src/cli/run/schema.test.ts +58 -0
- package/src/cli/run/schema.ts +33 -0
- package/src/cli/skills.ts +121 -0
- package/src/cli/types.ts +4 -1
- package/src/dashboard/dist/_astro/index.D6quLrA6.css +1 -0
- package/src/dashboard/dist/data/convoy-list.json +21 -7
- package/src/dashboard/dist/data/convoys/demo-api-v2.json +3 -3
- package/src/dashboard/dist/data/convoys/demo-auth-revamp.json +5 -5
- package/src/dashboard/dist/data/convoys/demo-convoy-1.json +2 -2
- package/src/dashboard/dist/data/convoys/demo-convoy-2.json +1 -1
- package/src/dashboard/dist/data/convoys/demo-dashboard-ui.json +7 -7
- package/src/dashboard/dist/data/convoys/demo-data-pipeline.json +3 -3
- package/src/dashboard/dist/data/convoys/demo-deploy-ci.json +2 -2
- package/src/dashboard/dist/data/convoys/demo-docs-update.json +2 -2
- package/src/dashboard/dist/data/convoys/demo-perf-opt.json +4 -4
- package/src/dashboard/dist/index.html +306 -33
- package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
- package/src/dashboard/public/data/convoy-list.json +21 -7
- package/src/dashboard/public/data/convoys/demo-api-v2.json +3 -3
- package/src/dashboard/public/data/convoys/demo-auth-revamp.json +5 -5
- package/src/dashboard/public/data/convoys/demo-convoy-1.json +2 -2
- package/src/dashboard/public/data/convoys/demo-convoy-2.json +1 -1
- package/src/dashboard/public/data/convoys/demo-dashboard-ui.json +7 -7
- package/src/dashboard/public/data/convoys/demo-data-pipeline.json +3 -3
- package/src/dashboard/public/data/convoys/demo-deploy-ci.json +2 -2
- package/src/dashboard/public/data/convoys/demo-docs-update.json +2 -2
- package/src/dashboard/public/data/convoys/demo-perf-opt.json +4 -4
- package/src/dashboard/scripts/etl.test.ts +14 -0
- package/src/dashboard/scripts/etl.ts +48 -16
- package/src/dashboard/scripts/generate-demo-db.ts +18 -10
- package/src/dashboard/src/pages/index.astro +348 -45
- package/src/dashboard/src/styles/dashboard.css +56 -0
- package/src/orchestrator/prompts/assess-complexity.prompt.md +13 -0
- package/src/orchestrator/prompts/generate-convoy.prompt.md +19 -0
- package/src/dashboard/dist/_astro/index.BRDFmNzR.css +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
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.
|
|
2
|
-
const convoyList = [{"id":"demo-deploy-ci","name":"CI/CD Pipeline Setup","status":"running","created_at":"2026-03-11T08:00:00.000Z","finished_at":null,"total_tokens":null,"total_cost_usd":null},{"id":"demo-docs-update","name":"Documentation Refresh","status":"done","created_at":"2026-02-28T15:00:00.000Z","finished_at":"2026-02-28T15:22:00.000Z","total_tokens":14800,"total_cost_usd":1.48},{"id":"demo-data-pipeline","name":"Analytics ETL Pipeline","status":"done","created_at":"2026-02-22T13:00:00.000Z","finished_at":"2026-02-22T13:38:00.000Z","total_tokens":28900,"total_cost_usd":2.89},{"id":"demo-perf-opt","name":"Frontend Performance Boost","status":"done","created_at":"2026-02-17T10:00:00.000Z","finished_at":"2026-02-17T11:02:00.000Z","total_tokens":37200,"total_cost_usd":3.72},{"id":"demo-api-v2","name":"REST API v2 Migration","status":"gate_failed","created_at":"2026-02-12T16:00:00.000Z","finished_at":"2026-02-12T16:28:00.000Z","total_tokens":24600,"total_cost_usd":2.46},{"id":"demo-dashboard-ui","name":"Observability Dashboard UI","status":"done","created_at":"2026-02-07T14:00:00.000Z","finished_at":"2026-02-07T15:38:00.000Z","total_tokens":78400,"total_cost_usd":7.84},{"id":"demo-auth-revamp","name":"Auth System Revamp","status":"done","created_at":"2026-02-03T09:00:00.000Z","finished_at":"2026-02-03T09:47:00.000Z","total_tokens":42850,"total_cost_usd":4.28}];
|
|
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.D6quLrA6.css"></head> <body> <script>(function(){const overallStats = {"convoyCounts":{"total":7,"running":1,"done":5,"failed":0,"gate_failed":0},"durationStats":{"avg_sec":2950.0000052154064,"p95_sec":3720.000019669533,"max_sec":5879.9999713897705},"tokenCostTotals":{"total_tokens":226750,"total_cost_usd":22.67},"topAgents":[{"agent":"Developer","task_count":6,"total_tokens":70100},{"agent":"Reviewer","task_count":5,"total_tokens":16250},{"agent":"UI/UX Expert","task_count":3,"total_tokens":32300},{"agent":"Testing Expert","task_count":3,"total_tokens":28800},{"agent":"DevOps Expert","task_count":3,"total_tokens":6400}],"topModels":[{"model":"claude-sonnet-4-6","task_count":21,"total_tokens":177650},{"model":"claude-haiku-3-5","task_count":5,"total_tokens":17700},{"model":"claude-opus-4-6","task_count":4,"total_tokens":40700}],"dlqSummary":{"count":3,"top_failure_types":[{"type":"timeout","count":1},{"type":"review_blocked","count":1},{"type":"gate_failed","count":1}]}};
|
|
2
|
+
const convoyList = [{"id":"demo-deploy-ci","name":"CI/CD Pipeline Setup","status":"running","created_at":"2026-03-11T08:00:00.000Z","finished_at":null,"total_tokens":null,"total_cost_usd":null,"task_count":3,"pipeline_id":null},{"id":"demo-docs-update","name":"Documentation Refresh","status":"done","created_at":"2026-02-28T15:00:00.000Z","finished_at":"2026-02-28T15:22:00.000Z","total_tokens":14800,"total_cost_usd":1.48,"task_count":3,"pipeline_id":null},{"id":"demo-data-pipeline","name":"Analytics ETL Pipeline","status":"done","created_at":"2026-02-22T13:00:00.000Z","finished_at":"2026-02-22T13:38:00.000Z","total_tokens":28900,"total_cost_usd":2.89,"task_count":4,"pipeline_id":null},{"id":"demo-perf-opt","name":"Frontend Performance Boost","status":"done","created_at":"2026-02-17T10:00:00.000Z","finished_at":"2026-02-17T11:02:00.000Z","total_tokens":37200,"total_cost_usd":3.72,"task_count":5,"pipeline_id":null},{"id":"demo-api-v2","name":"REST API v2 Migration","status":"gate_failed","created_at":"2026-02-12T16:00:00.000Z","finished_at":"2026-02-12T16:28:00.000Z","total_tokens":24600,"total_cost_usd":2.46,"task_count":3,"pipeline_id":null},{"id":"demo-dashboard-ui","name":"Observability Dashboard UI","status":"done","created_at":"2026-02-07T14:00:00.000Z","finished_at":"2026-02-07T15:38:00.000Z","total_tokens":78400,"total_cost_usd":7.84,"task_count":7,"pipeline_id":"demo-pipeline-1"},{"id":"demo-auth-revamp","name":"Auth System Revamp","status":"done","created_at":"2026-02-03T09:00:00.000Z","finished_at":"2026-02-03T09:47:00.000Z","total_tokens":42850,"total_cost_usd":4.28,"task_count":5,"pipeline_id":"demo-pipeline-1"}];
|
|
3
3
|
|
|
4
4
|
window.__DASHBOARD_DATA__ = { overallStats, convoyList }
|
|
5
5
|
})();</script> <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" aria-label="Export dashboard 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>
|
|
6
6
|
Export
|
|
7
|
-
</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 dash-sidebar__link--active" href="#overall-section" data-section="overall-section" data-view="home" aria-label="Overview section">Overview</a></li> <li><a class="dash-sidebar__link" href="#convoy-list-section" data-section="convoy-list-section" data-view="home" aria-label="Convoys section">Convoys</a></li> <li><a class="dash-sidebar__link" href="#tasks-section" data-section="tasks-section" data-view="detail" aria-label="Tasks section">Tasks</a></li> <li><a class="dash-sidebar__link" href="#pipeline-section" data-section="pipeline-section" data-view="detail" aria-label="Pipeline section">Pipeline</a></li> <li><a class="dash-sidebar__link" href="#agent-section" data-section="agent-section" data-view="detail" aria-label="Agents section">Agents</a></li> <li><a class="dash-sidebar__link" href="#tier-section" data-section="tier-section" data-view="detail" aria-label="Tiers section">Tiers</a></li> <li><a class="dash-sidebar__link" href="#model-section" data-section="model-section" data-view="detail" aria-label="Models section">Models</a></li> <li><a class="dash-sidebar__link" href="#quality-section" data-section="quality-section" data-view="detail" aria-label="Quality section">Quality</a></li> <li><a class="dash-sidebar__link" href="#reliability-section" data-section="reliability-section" data-view="detail" aria-label="Reliability section">Reliability</a></li> <li><a class="dash-sidebar__link" href="#drift-section" data-section="drift-section" data-view="detail" aria-label="Drift section">Drift</a></li> <li><a class="dash-sidebar__link" href="#outputs-section" data-section="outputs-section" data-view="detail" aria-label="Outputs section">Outputs</a></li> <li><a class="dash-sidebar__link" href="#execution-section" data-section="execution-section" data-view="detail" aria-label="Execution Log section">Execution Log</a></li> <li><a class="dash-sidebar__link" href="#event-timeline-section" data-section="event-timeline-section" data-view="detail" aria-label="Event Log section">Event Log</a></li> <li><a class="dash-sidebar__link" href="#panel-section" data-section="panel-section" data-view="detail" aria-label="Panel Reviews section">Panel Reviews</a></li> <li><a class="dash-sidebar__link" href="#reviews-section" data-section="reviews-section" data-view="detail" aria-label="Fast Reviews section">Fast Reviews</a></li> </ul> </nav> <main class="dash-main"> <nav class="breadcrumbs" id="breadcrumbs" data-view-hidden> <a class="breadcrumbs__link" href="#" id="breadcrumbs-home">Observability</a> <span class="breadcrumbs__separator">/</span> <span class="breadcrumbs__current" id="breadcrumbs-convoy"></span> </nav> <div class="view-home" id="view-home"> <!-- Overall Stats Section --> <section class="overall-stats" id="overall-section" data-nav-section> <div class="overall-stats__header"> <h2 class="overall-stats__title">Overall Stats</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: How all runs behave across your project." data-tooltip="How all runs behave across your project."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> </div> <div class="overall-stats__grid"> <div class="overall-kpi" id="overall-total-runs"> <span class="overall-kpi__label">Total Runs <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Number of convoy runs executed" data-tooltip="Number of convoy runs executed"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span></span> <span class="overall-kpi__value">—</span> </div> <div class="overall-kpi" id="overall-running"> <span class="overall-kpi__label">Running Now</span> <span class="overall-kpi__value">—</span> </div> <div class="overall-kpi" id="overall-success-rate"> <span class="overall-kpi__label">Success Rate</span> <span class="overall-kpi__value">—</span> </div> <div class="overall-kpi" id="overall-avg-duration"> <span class="overall-kpi__label">Avg Duration</span> <span class="overall-kpi__value">—</span> </div> <div class="overall-kpi" id="overall-total-tokens"> <span class="overall-kpi__label">Total Tokens</span> <span class="overall-kpi__value">—</span> </div> <div class="overall-kpi" id="overall-total-cost"> <span class="overall-kpi__label">Total Cost</span> <span class="overall-kpi__value">—</span> </div> </div> </section> <!-- Convoy List Section --> <section class="convoy-list-section" id="convoy-list-section"> <div class="convoy-list-section__header"> <h2>Convoys</h2> <p class="convoy-list-section__desc">All convoy runs across your project</p> </div> <div class="convoy-list-filters" id="convoy-list-filters"> <div class="convoy-list-filters__group"> <label for="cl-filter-search">Search</label> <input class="convoy-list-filters__input" type="text" id="cl-filter-search" placeholder="Convoy name…"> </div> <div class="convoy-list-filters__group"> <label for="cl-filter-status">Status</label> <select class="convoy-list-filters__select" id="cl-filter-status"> <option value="">All</option> <option value="done">Done</option> <option value="running">Running</option> <option value="failed">Failed</option> <option value="gate-failed">Gate Failed</option> <option value="pending">Pending</option> </select> </div> <div class="convoy-list-filters__group"> <label for="cl-filter-from">From</label> <input class="convoy-list-filters__date" type="date" id="cl-filter-from"> </div> <div class="convoy-list-filters__group"> <label for="cl-filter-to">To</label> <input class="convoy-list-filters__date" type="date" id="cl-filter-to"> </div> <button class="convoy-list-filters__reset" type="button" id="cl-filter-reset">Reset</button> </div> <div id="convoy-list-table-wrap"></div> <div class="convoy-list-empty" id="convoy-list-empty" style="display:none"> <div class="convoy-list-empty__icon"> <svg width="40" height="40" viewBox="0 0 40 40" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="6" y="6" width="28" height="28" rx="4"></rect><line x1="14" y1="20" x2="26" y2="20" opacity="0.5"></line></svg> </div> <p class="convoy-list-empty__text">No convoys match your filters</p> </div> </section> </div><!-- .view-home --> <div class="view-convoy-detail" id="view-convoy-detail" data-view-hidden> <section class="convoy-detail-hero" id="convoy-detail-hero"> <div class="convoy-detail-hero__title" id="detail-hero-title"></div> <span class="convoy-detail-hero__status" id="detail-hero-status"></span> <div class="convoy-detail-hero__meta" id="detail-hero-meta"></div> </section> <!-- Tasks Section --> <section class="chart-card" id="tasks-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Tasks</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Individual units of work in this convoy." data-tooltip="Individual units of work in this convoy."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc" id="tasks-section-desc">Task breakdown for the selected convoy</p> </div> <div class="chart-card__body" id="tasks-section-body"> <div id="task-summary-cards" class="task-summary-cards"></div> <div id="phase-breakdown" class="phase-breakdown"></div> <div id="task-table-wrap" class="task-table-wrap"></div> </div> </section> <!-- Pipeline View --> <section class="chart-card" id="pipeline-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Task Pipeline</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Task flow across execution phases." data-tooltip="Task flow across execution phases."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Task flow across execution phases</p> </div> <div class="chart-card__body" id="pipeline-view"></div> </section> <!-- Charts Row: Agent + Outcomes --> <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">Task count per agent, stacked by outcome</p> </div> <div class="chart-card__body" id="agent-chart"></div> </section> <section class="chart-card"> <div class="chart-card__header"> <h2 class="chart-card__title">Delegation Outcomes</h2> <p class="chart-card__desc">Task outcome distribution</p> </div> <div class="chart-card__body" id="delegation-outcome-chart"></div> </section> </div> <!-- Charts Row: Tiers + Mechanism --> <div class="charts-row" id="tier-section" data-nav-section> <section class="chart-card"> <div class="chart-card__header"> <h2 class="chart-card__title">Tier Distribution</h2> <p class="chart-card__desc">Model tier breakdown</p> </div> <div class="chart-card__body" id="tier-chart"></div> </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> </section> </div> <!-- Model Usage --> <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">Tasks by model</p> </div> <div class="chart-card__body" id="model-chart"></div> </section> <!-- Quality Section --> <section class="chart-card" id="quality-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Quality / Review</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Code review results and dispute resolution." data-tooltip="Code review results and dispute resolution."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Code review results and quality gate outcomes for the selected convoy</p> </div> <div class="chart-card__body"> <div id="quality-cards" class="task-summary-cards"></div> <div id="quality-review-table"></div> </div> </section> <!-- Reliability Section --> <section class="chart-card" id="reliability-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Reliability</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Errors, retry attempts, and safety mechanisms." data-tooltip="Errors, retry attempts, and safety mechanisms."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Retry queue and error overview for the selected convoy</p> </div> <div class="chart-card__body"> <div id="reliability-dlq-card"></div> <div id="reliability-dlq-table"></div> <div style="margin-top:24px"> <h3 style="font-size:1rem;font-weight:600;color:var(--text-secondary);margin:0 0 12px">Error Overview</h3> <div id="reliability-error-overview"></div> </div> </div> </section> <!-- Drift Section --> <section class="chart-card" id="drift-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Drift</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: How far the actual work deviated from the original plan." data-tooltip="How far the actual work deviated from the original plan."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Plan adherence and deviation metrics for the selected convoy</p> </div> <div class="chart-card__body"> <div id="drift-cards" class="task-summary-cards"></div> <div id="drift-secret-banner" style="display:none"></div> </div> </section> <!-- Outputs Section --> <section class="chart-card" id="outputs-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Outputs & Artifacts</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Files, data, and summaries produced by this convoy." data-tooltip="Files, data, and summaries produced by this convoy."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Files, summaries, and structured data produced by tasks in this convoy</p> </div> <div class="chart-card__body"> <div id="outputs-cards" class="task-summary-cards"></div> <div id="artifact-table-wrap"></div> </div> </section> <!-- Event Timeline Section --> <section class="chart-card" id="event-timeline-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Event Timeline</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Chronological log of everything that happened during this run." data-tooltip="Chronological log of everything that happened during this run."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Convoy events in reverse chronological order</p> </div> <div class="chart-card__body"> <div id="event-timeline-filters" class="timeline-filters"></div> <div id="event-timeline-list"></div> <div id="event-timeline-load-more" style="display:none;text-align:center;padding:16px"> <button class="dash-btn dash-btn--ghost" id="event-timeline-more-btn" type="button">Load more</button> </div> </div> </section> <!-- Execution Log --> <section class="chart-card" id="execution-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Execution Log</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Step-by-step trace of recent task activity." data-tooltip="Step-by-step trace of recent task activity."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Recent agent activity, step by step</p> </div> <div class="chart-card__body" id="execution-log"></div> </section> <!-- Panel Reviews --> <section class="chart-card" id="panel-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Panel Reviews</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Quality gate verdicts from majority-vote panels." data-tooltip="Quality gate verdicts from majority-vote panels."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Quality gate verdicts and fix items</p> </div> <div class="chart-card__body" id="panel-chart"></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> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Single-reviewer quality gate results." data-tooltip="Single-reviewer quality gate results."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <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> </section> </div><!-- .view-convoy-detail --> </main> </div> </body></html> <script>(function(){const base = "/";
|
|
7
|
+
</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 dash-sidebar__link--active" href="#overall-section" data-section="overall-section" data-view="home" aria-label="Overview section">Overview</a></li> <li><a class="dash-sidebar__link" href="#convoy-list-section" data-section="convoy-list-section" data-view="home" aria-label="Convoys section">Convoys</a></li> <li><a class="dash-sidebar__link" href="#activity-timeline-section" data-section="activity-timeline-section" data-view="home" aria-label="Activity Timeline section">Activity</a></li> <li><a class="dash-sidebar__link" href="#sessions-section" data-section="sessions-section" data-view="home" aria-label="Sessions section">Sessions</a></li> <li><a class="dash-sidebar__link" href="#tasks-section" data-section="tasks-section" data-view="detail" aria-label="Tasks section">Tasks</a></li> <li><a class="dash-sidebar__link" href="#pipeline-section" data-section="pipeline-section" data-view="detail" aria-label="Pipeline section">Pipeline</a></li> <li><a class="dash-sidebar__link" href="#agent-section" data-section="agent-section" data-view="detail" aria-label="Agents section">Agents</a></li> <li><a class="dash-sidebar__link" href="#tier-section" data-section="tier-section" data-view="detail" aria-label="Tiers section">Tiers</a></li> <li><a class="dash-sidebar__link" href="#model-section" data-section="model-section" data-view="detail" aria-label="Models section">Models</a></li> <li><a class="dash-sidebar__link" href="#quality-section" data-section="quality-section" data-view="detail" aria-label="Quality section">Quality</a></li> <li><a class="dash-sidebar__link" href="#reliability-section" data-section="reliability-section" data-view="detail" aria-label="Reliability section">Reliability</a></li> <li><a class="dash-sidebar__link" href="#drift-section" data-section="drift-section" data-view="detail" aria-label="Drift section">Drift</a></li> <li><a class="dash-sidebar__link" href="#outputs-section" data-section="outputs-section" data-view="detail" aria-label="Outputs section">Outputs</a></li> <li><a class="dash-sidebar__link" href="#execution-section" data-section="execution-section" data-view="detail" aria-label="Execution Log section">Execution Log</a></li> <li><a class="dash-sidebar__link" href="#event-timeline-section" data-section="event-timeline-section" data-view="detail" aria-label="Event Log section">Event Log</a></li> <li><a class="dash-sidebar__link" href="#reviews-section" data-section="reviews-section" data-view="detail" aria-label="Fast Reviews section">Fast Reviews</a></li> <li><a class="dash-sidebar__link" href="#panel-section" data-section="panel-section" data-view="detail" aria-label="Panel Reviews section">Panel Reviews</a></li> </ul> </nav> <main class="dash-main"> <nav class="breadcrumbs" id="breadcrumbs" data-view-hidden> <a class="breadcrumbs__link" href="#" id="breadcrumbs-home">Observability</a> <span class="breadcrumbs__separator">/</span> <span class="breadcrumbs__current" id="breadcrumbs-convoy"></span> </nav> <div class="view-home" id="view-home"> <!-- Overall Stats Section --> <section class="overall-stats" id="overall-section" data-nav-section> <div class="overall-stats__header"> <h2 class="overall-stats__title">Overall Stats</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: How all runs behave across your project." data-tooltip="How all runs behave across your project."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> </div> <div class="overall-stats__grid"> <div class="overall-kpi" id="overall-total-runs"> <span class="overall-kpi__label">Total Runs <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Number of convoy runs executed" data-tooltip="Number of convoy runs executed"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span></span> <span class="overall-kpi__value">—</span> </div> <div class="overall-kpi" id="overall-running"> <span class="overall-kpi__label">Running Now</span> <span class="overall-kpi__value">—</span> </div> <div class="overall-kpi" id="overall-success-rate"> <span class="overall-kpi__label">Success Rate</span> <span class="overall-kpi__value">—</span> </div> <div class="overall-kpi" id="overall-avg-duration"> <span class="overall-kpi__label">Avg Duration</span> <span class="overall-kpi__value">—</span> </div> <div class="overall-kpi" id="overall-total-tokens"> <span class="overall-kpi__label">Total Tokens</span> <span class="overall-kpi__value">—</span> </div> <div class="overall-kpi" id="overall-total-cost"> <span class="overall-kpi__label">Total Cost</span> <span class="overall-kpi__value">—</span> </div> <div class="overall-kpi" id="overall-total-tasks"> <span class="overall-kpi__label">Total Tasks</span> <span class="overall-kpi__value">—</span> </div> <div class="overall-kpi" id="overall-total-retries"> <span class="overall-kpi__label">Total Retries</span> <span class="overall-kpi__value">—</span> </div> </div> </section> <!-- Activity Timeline --> <section class="chart-card" id="activity-timeline-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Activity Timeline</h2> <p class="chart-card__desc">Convoy runs over time</p> </div> <div class="chart-card__body" id="activity-timeline-chart"></div> </section> <!-- Convoy List Section --> <section class="convoy-list-section" id="convoy-list-section"> <div class="convoy-list-section__header"> <h2>Convoys</h2> <p class="convoy-list-section__desc">All convoy runs across your project</p> </div> <div class="convoy-list-filters" id="convoy-list-filters"> <div class="convoy-list-filters__group"> <label for="cl-filter-search">Search</label> <input class="convoy-list-filters__input" type="text" id="cl-filter-search" placeholder="Convoy name…"> </div> <div class="convoy-list-filters__group"> <label for="cl-filter-status">Status</label> <select class="convoy-list-filters__select" id="cl-filter-status"> <option value="">All</option> <option value="done">Done</option> <option value="running">Running</option> <option value="failed">Failed</option> <option value="gate-failed">Gate Failed</option> <option value="pending">Pending</option> </select> </div> <div class="convoy-list-filters__group"> <label for="cl-filter-from">From</label> <input class="convoy-list-filters__date" type="date" id="cl-filter-from"> </div> <div class="convoy-list-filters__group"> <label for="cl-filter-to">To</label> <input class="convoy-list-filters__date" type="date" id="cl-filter-to"> </div> <button class="convoy-list-filters__reset" type="button" id="cl-filter-reset">Reset</button> </div> <div id="convoy-list-table-wrap"></div> <div class="convoy-list-empty" id="convoy-list-empty" style="display:none"> <div class="convoy-list-empty__icon"> <svg width="40" height="40" viewBox="0 0 40 40" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="6" y="6" width="28" height="28" rx="4"></rect><line x1="14" y1="20" x2="26" y2="20" opacity="0.5"></line></svg> </div> <p class="convoy-list-empty__text">No convoys match your filters</p> </div> </section> <!-- Recent Sessions --> <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">Latest agent sessions from observability log</p> </div> <div class="chart-card__body chart-card__body--table" id="sessions-table"></div> </section> </div><!-- .view-home --> <div class="view-convoy-detail" id="view-convoy-detail" data-view-hidden> <section class="convoy-detail-hero" id="convoy-detail-hero"> <div class="convoy-detail-hero__top"> <div class="convoy-detail-hero__title" id="detail-hero-title"></div> <span class="convoy-detail-hero__status" id="detail-hero-status"></span> </div> <div class="convoy-detail-hero__meta" id="detail-hero-meta"></div> </section> <!-- Tasks Section --> <section class="chart-card" id="tasks-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Tasks</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Individual units of work in this convoy." data-tooltip="Individual units of work in this convoy."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc" id="tasks-section-desc">Task breakdown for the selected convoy</p> </div> <div class="chart-card__body" id="tasks-section-body"> <div id="task-summary-cards" class="task-summary-cards"></div> <div id="phase-breakdown" class="phase-breakdown"></div> <div id="task-table-wrap" class="task-table-wrap"></div> </div> </section> <!-- Pipeline View --> <section class="chart-card" id="pipeline-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Task Pipeline</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Visualizes how tasks progress through sequential execution phases." data-tooltip="Visualizes how tasks progress through sequential execution phases — from initial setup through integration, validation, and final quality gate."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Task flow across execution phases</p> </div> <div class="chart-card__body" id="pipeline-view"></div> </section> <!-- Charts Row: Agent + Outcomes --> <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">Task count per agent, stacked by outcome</p> </div> <div class="chart-card__body" id="agent-chart"></div> </section> <section class="chart-card"> <div class="chart-card__header"> <h2 class="chart-card__title">Delegation Outcomes</h2> <p class="chart-card__desc">Task outcome distribution</p> </div> <div class="chart-card__body" id="delegation-outcome-chart"></div> </section> </div> <!-- Charts Row: Tiers + Mechanism --> <div class="charts-row" id="tier-section" data-nav-section> <section class="chart-card"> <div class="chart-card__header"> <h2 class="chart-card__title">Tier Distribution</h2> <p class="chart-card__desc">Model tier breakdown</p> </div> <div class="chart-card__body" id="tier-chart"></div> </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> </section> </div> <!-- Model Usage --> <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">Tasks by model</p> </div> <div class="chart-card__body" id="model-chart"></div> </section> <!-- Quality Section --> <section class="chart-card" id="quality-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Quality / Review</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Code review results and dispute resolution." data-tooltip="Code review results and dispute resolution."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Code review results and quality gate outcomes for the selected convoy</p> </div> <div class="chart-card__body"> <div id="quality-cards" class="task-summary-cards"></div> <div id="quality-review-table"></div> </div> </section> <!-- Reliability Section --> <section class="chart-card" id="reliability-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Reliability</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Errors, retry attempts, and safety mechanisms." data-tooltip="Errors, retry attempts, and safety mechanisms."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Retry queue and error overview for the selected convoy</p> </div> <div class="chart-card__body"> <div id="reliability-dlq-card"></div> <div id="reliability-dlq-table"></div> <div style="margin-top:24px"> <h3 style="font-size:1rem;font-weight:600;color:var(--text-secondary);margin:0 0 12px">Error Overview</h3> <div id="reliability-error-overview"></div> </div> </div> </section> <!-- Drift Section --> <section class="chart-card" id="drift-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Drift</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: How far the actual work deviated from the original plan." data-tooltip="How far the actual work deviated from the original plan."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Plan adherence and deviation metrics for the selected convoy</p> </div> <div class="chart-card__body"> <div id="drift-cards" class="task-summary-cards"></div> <div id="drift-secret-banner" style="display:none"></div> </div> </section> <!-- Outputs Section --> <section class="chart-card" id="outputs-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Outputs & Artifacts</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Files, data, and summaries produced by this convoy." data-tooltip="Files, data, and summaries produced by this convoy."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Files, summaries, and structured data produced by tasks in this convoy</p> </div> <div class="chart-card__body"> <div id="outputs-cards" class="task-summary-cards"></div> <div id="artifact-table-wrap"></div> </div> </section> <!-- Event Timeline Section --> <section class="chart-card" id="event-timeline-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Event Timeline</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Chronological log of everything that happened during this run." data-tooltip="Chronological log of everything that happened during this run."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Convoy events in chronological order</p> </div> <div class="chart-card__body"> <div id="event-timeline-filters" class="timeline-filters"></div> <div id="event-timeline-list"></div> <div id="event-timeline-load-more" style="display:none;text-align:center;padding:16px"> <button class="dash-btn dash-btn--ghost" id="event-timeline-more-btn" type="button">Load more</button> </div> </div> </section> <!-- Execution Log --> <section class="chart-card" id="execution-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Execution Log</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Step-by-step trace of recent task activity." data-tooltip="Step-by-step trace of recent task activity."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Recent agent activity, step by step</p> </div> <div class="chart-card__body" id="execution-log"></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> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Single-reviewer quality gate results." data-tooltip="Single-reviewer quality gate results."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <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> </section> <!-- Panel Reviews --> <section class="chart-card" id="panel-section" data-nav-section> <div class="chart-card__header"> <h2 class="chart-card__title">Panel Reviews</h2> <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Quality gate verdicts from majority-vote panels." data-tooltip="Quality gate verdicts from majority-vote panels."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg></span> <p class="chart-card__desc">Quality gate verdicts and fix items</p> </div> <div class="chart-card__body" id="panel-chart"></div> </section> </div><!-- .view-convoy-detail --> </main> </div> </body></html> <script>(function(){const base = "/";
|
|
8
8
|
|
|
9
9
|
// ── Data Loading ──────────────────────────────────────────
|
|
10
10
|
|
|
@@ -43,6 +43,7 @@ Export
|
|
|
43
43
|
standard: '#a78bfa',
|
|
44
44
|
utility: '#3b82f6',
|
|
45
45
|
economy: '#64748b',
|
|
46
|
+
unknown: '#94a3b8',
|
|
46
47
|
};
|
|
47
48
|
|
|
48
49
|
const MODEL_COLORS = {
|
|
@@ -175,6 +176,8 @@ Export
|
|
|
175
176
|
}
|
|
176
177
|
renderOverallStats();
|
|
177
178
|
renderConvoyList();
|
|
179
|
+
renderActivityTimeline();
|
|
180
|
+
renderRecentSessions();
|
|
178
181
|
} catch {
|
|
179
182
|
// Non-fatal
|
|
180
183
|
}
|
|
@@ -360,6 +363,14 @@ Export
|
|
|
360
363
|
}
|
|
361
364
|
|
|
362
365
|
// ── Convoy List ─────────────────────────────────────────
|
|
366
|
+
var convoyListCurrentPage = 1;
|
|
367
|
+
var CONVOY_LIST_PAGE_SIZE = 10;
|
|
368
|
+
var convoyChainExpanded = {};
|
|
369
|
+
var executionLogPageSize = 20;
|
|
370
|
+
var executionLogCurrentPage = 1;
|
|
371
|
+
var executionLogAllSortedTasks = [];
|
|
372
|
+
var executionLogLimit = 10;
|
|
373
|
+
|
|
363
374
|
function renderConvoyList() {
|
|
364
375
|
const data = window.__DASHBOARD_DATA__;
|
|
365
376
|
const list = data?.convoyList ?? [];
|
|
@@ -380,36 +391,112 @@ Export
|
|
|
380
391
|
|
|
381
392
|
if (filtered.length === 0) {
|
|
382
393
|
wrap.innerHTML = '';
|
|
394
|
+
var existingPag = document.getElementById('convoy-list-pagination');
|
|
395
|
+
if (existingPag) existingPag.remove();
|
|
383
396
|
if (emptyEl) emptyEl.style.display = '';
|
|
384
397
|
return;
|
|
385
398
|
}
|
|
386
399
|
if (emptyEl) emptyEl.style.display = 'none';
|
|
387
400
|
|
|
388
401
|
const statusBadgeClass = (s) => {
|
|
389
|
-
const map = { done: '--done', running: '--running', failed: '--failed', 'gate-failed': '--gate-failed', pending: '--pending' };
|
|
402
|
+
const map = { done: '--done', running: '--running', failed: '--failed', 'gate-failed': '--gate-failed', gate_failed: '--gate-failed', pending: '--pending' };
|
|
390
403
|
return 'status-badge ' + (map[s] || '');
|
|
391
404
|
};
|
|
392
405
|
|
|
406
|
+
// Group convoys by pipeline_id (non-null pipeline_id forms a chain)
|
|
407
|
+
var grouped = [];
|
|
408
|
+
var pipelineMap = {};
|
|
409
|
+
for (var gi = 0; gi < filtered.length; gi++) {
|
|
410
|
+
var gc = filtered[gi];
|
|
411
|
+
if (gc.pipeline_id) {
|
|
412
|
+
if (!pipelineMap[gc.pipeline_id]) {
|
|
413
|
+
pipelineMap[gc.pipeline_id] = { pipeline_id: gc.pipeline_id, convoys: [] };
|
|
414
|
+
grouped.push(pipelineMap[gc.pipeline_id]);
|
|
415
|
+
}
|
|
416
|
+
pipelineMap[gc.pipeline_id].convoys.push(gc);
|
|
417
|
+
} else {
|
|
418
|
+
grouped.push(gc);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Pagination on grouped top-level items
|
|
423
|
+
var totalPages = Math.ceil(grouped.length / CONVOY_LIST_PAGE_SIZE);
|
|
424
|
+
if (convoyListCurrentPage > totalPages) convoyListCurrentPage = 1;
|
|
425
|
+
var pageStart = (convoyListCurrentPage - 1) * CONVOY_LIST_PAGE_SIZE;
|
|
426
|
+
var paginated = grouped.slice(pageStart, pageStart + CONVOY_LIST_PAGE_SIZE);
|
|
427
|
+
|
|
393
428
|
let html = '<table class="convoy-list-table"><thead><tr>' +
|
|
394
429
|
'<th>Name</th><th>Status</th><th>Tasks</th><th>Created</th><th>Duration</th>' +
|
|
395
430
|
'</tr></thead><tbody>';
|
|
396
431
|
|
|
397
|
-
for (
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
432
|
+
for (var pi = 0; pi < paginated.length; pi++) {
|
|
433
|
+
var item = paginated[pi];
|
|
434
|
+
if (item.convoys) {
|
|
435
|
+
// Pipeline group row
|
|
436
|
+
var grpConvoys = item.convoys;
|
|
437
|
+
var grpPipelineId = item.pipeline_id;
|
|
438
|
+
var isExpanded = !!convoyChainExpanded[grpPipelineId];
|
|
439
|
+
var grpStatus = (function(cs) {
|
|
440
|
+
if (cs.some(function(x) { return x.status === 'failed' || x.status === 'gate_failed'; })) return 'gate_failed';
|
|
441
|
+
if (cs.some(function(x) { return x.status === 'running'; })) return 'running';
|
|
442
|
+
if (cs.every(function(x) { return x.status === 'done'; })) return 'done';
|
|
443
|
+
return cs[0] ? cs[0].status : 'pending';
|
|
444
|
+
})(grpConvoys);
|
|
445
|
+
var grpTasks = grpConvoys.reduce(function(s, x) { return s + (x.task_count || 0); }, 0);
|
|
446
|
+
var grpEarliestCreated = grpConvoys.reduce(function(a, x) { return (!a || (x.created_at && x.created_at < a)) ? x.created_at : a; }, null);
|
|
447
|
+
var grpLatestFinished = grpConvoys.reduce(function(a, x) { return (!a || (x.finished_at && x.finished_at > a)) ? x.finished_at : a; }, null);
|
|
448
|
+
var grpAllFinished = grpConvoys.every(function(x) { return !!x.finished_at; });
|
|
449
|
+
var grpDuration = grpEarliestCreated && grpAllFinished && grpLatestFinished ? formatDuration(grpEarliestCreated, grpLatestFinished) : (grpStatus === 'running' ? 'In progress' : '\u2014');
|
|
450
|
+
var grpName = grpConvoys[0].pipeline_name || grpPipelineId.replace(/-/g, ' ').replace(/\b\w/g, function(l) { return l.toUpperCase(); });
|
|
451
|
+
var toggleIcon = isExpanded ? '\u25bc' : '\u25b6';
|
|
452
|
+
html += '<tr class="convoy-chain-row task-row--clickable" data-pipeline-group-id="' + escapeHtml(grpPipelineId) + '" aria-expanded="' + isExpanded + '" role="row">' +
|
|
453
|
+
'<td><span class="convoy-chain-toggle">' + toggleIcon + '</span><strong>' + escapeHtml(grpName) + '</strong></td>' +
|
|
454
|
+
'<td><span class="' + statusBadgeClass(grpStatus) + '">' + escapeHtml(grpStatus) + '</span></td>' +
|
|
455
|
+
'<td>' + grpTasks + '</td>' +
|
|
456
|
+
'<td>' + (grpEarliestCreated ? formatTime(grpEarliestCreated) : '\u2014') + '</td>' +
|
|
457
|
+
'<td>' + grpDuration + '</td>' +
|
|
458
|
+
'</tr>';
|
|
459
|
+
if (isExpanded) {
|
|
460
|
+
for (var ci = 0; ci < grpConvoys.length; ci++) {
|
|
461
|
+
var cc = grpConvoys[ci];
|
|
462
|
+
var ccName = escapeHtml(cc.name || cc.id);
|
|
463
|
+
var ccDate = cc.created_at ? formatTime(cc.created_at) : '\u2014';
|
|
464
|
+
var ccDur = cc.started_at && cc.finished_at ? formatDuration(cc.started_at, cc.finished_at) : (cc.status === 'running' ? 'In progress' : '\u2014');
|
|
465
|
+
var ccTasks = cc.task_count != null ? cc.task_count : '\u2014';
|
|
466
|
+
html += '<tr data-convoy-id="' + escapeHtml(cc.id) + '" class="task-row--clickable convoy-chain-child">' +
|
|
467
|
+
'<td><strong>' + ccName + '</strong></td>' +
|
|
468
|
+
'<td><span class="' + statusBadgeClass(cc.status) + '">' + escapeHtml(cc.status || 'unknown') + '</span></td>' +
|
|
469
|
+
'<td>' + ccTasks + '</td>' +
|
|
470
|
+
'<td>' + ccDate + '</td>' +
|
|
471
|
+
'<td>' + ccDur + '</td>' +
|
|
472
|
+
'</tr>';
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
} else {
|
|
476
|
+
var name = escapeHtml(item.name || item.id);
|
|
477
|
+
var dateStr = item.created_at ? formatTime(item.created_at) : '\u2014';
|
|
478
|
+
var duration = item.started_at && item.finished_at ? formatDuration(item.started_at, item.finished_at) : (item.status === 'running' ? 'In progress' : '\u2014');
|
|
479
|
+
var taskCount = item.task_count != null ? item.task_count : '\u2014';
|
|
480
|
+
html += '<tr data-convoy-id="' + escapeHtml(item.id) + '" class="task-row--clickable">' +
|
|
481
|
+
'<td><strong>' + name + '</strong></td>' +
|
|
482
|
+
'<td><span class="' + statusBadgeClass(item.status) + '">' + escapeHtml(item.status || 'unknown') + '</span></td>' +
|
|
483
|
+
'<td>' + taskCount + '</td>' +
|
|
484
|
+
'<td>' + dateStr + '</td>' +
|
|
485
|
+
'<td>' + (duration || '\u2014') + '</td>' +
|
|
486
|
+
'</tr>';
|
|
487
|
+
}
|
|
409
488
|
}
|
|
410
489
|
html += '</tbody></table>';
|
|
411
490
|
wrap.innerHTML = html;
|
|
412
491
|
|
|
492
|
+
wrap.querySelectorAll('tr[data-pipeline-group-id]').forEach(row => {
|
|
493
|
+
row.addEventListener('click', () => {
|
|
494
|
+
const groupId = row.dataset.pipelineGroupId;
|
|
495
|
+
convoyChainExpanded[groupId] = !convoyChainExpanded[groupId];
|
|
496
|
+
renderConvoyList();
|
|
497
|
+
});
|
|
498
|
+
});
|
|
499
|
+
|
|
413
500
|
wrap.querySelectorAll('tr[data-convoy-id]').forEach(row => {
|
|
414
501
|
row.addEventListener('click', () => {
|
|
415
502
|
const id = row.dataset.convoyId;
|
|
@@ -417,6 +504,26 @@ Export
|
|
|
417
504
|
showConvoyDetailView(id, nameCell ? nameCell.textContent : id);
|
|
418
505
|
});
|
|
419
506
|
});
|
|
507
|
+
|
|
508
|
+
// Render pagination controls
|
|
509
|
+
var oldPag = document.getElementById('convoy-list-pagination');
|
|
510
|
+
if (oldPag) oldPag.remove();
|
|
511
|
+
if (grouped.length > CONVOY_LIST_PAGE_SIZE) {
|
|
512
|
+
var pagEl = document.createElement('div');
|
|
513
|
+
pagEl.id = 'convoy-list-pagination';
|
|
514
|
+
pagEl.className = 'convoy-list-pagination';
|
|
515
|
+
pagEl.innerHTML =
|
|
516
|
+
'<button class="dash-btn dash-btn--ghost" id="convoy-list-prev" type="button"' + (convoyListCurrentPage === 1 ? ' disabled' : '') + '>Previous</button>' +
|
|
517
|
+
'<span class="convoy-list-pagination__info">Page ' + convoyListCurrentPage + ' of ' + totalPages + '</span>' +
|
|
518
|
+
'<button class="dash-btn dash-btn--ghost" id="convoy-list-next" type="button"' + (convoyListCurrentPage === totalPages ? ' disabled' : '') + '>Next</button>';
|
|
519
|
+
wrap.after(pagEl);
|
|
520
|
+
pagEl.querySelector('#convoy-list-prev').addEventListener('click', function() {
|
|
521
|
+
if (convoyListCurrentPage > 1) { convoyListCurrentPage--; renderConvoyList(); }
|
|
522
|
+
});
|
|
523
|
+
pagEl.querySelector('#convoy-list-next').addEventListener('click', function() {
|
|
524
|
+
if (convoyListCurrentPage < totalPages) { convoyListCurrentPage++; renderConvoyList(); }
|
|
525
|
+
});
|
|
526
|
+
}
|
|
420
527
|
}
|
|
421
528
|
|
|
422
529
|
// ── Overall Stats Rendering ──────────────────────────────
|
|
@@ -439,8 +546,28 @@ Export
|
|
|
439
546
|
|
|
440
547
|
const avgSec = ds.avg_sec;
|
|
441
548
|
setKpiValue('overall-avg-duration', avgSec != null ? formatDurationSec(avgSec) : '\u2014');
|
|
442
|
-
|
|
443
|
-
|
|
549
|
+
var totalTokens = (tc && tc.total_tokens) || 0;
|
|
550
|
+
var totalCost = (tc && tc.total_cost_usd) || 0;
|
|
551
|
+
setKpiValue('overall-total-tokens', formatTokens(totalTokens));
|
|
552
|
+
setKpiValue('overall-total-cost', '$' + totalCost.toFixed(2));
|
|
553
|
+
|
|
554
|
+
// Fallback: if overall stats show 0 tokens, sum from convoy list
|
|
555
|
+
if (totalTokens === 0) {
|
|
556
|
+
var convoyListFallback = (window.__DASHBOARD_DATA__ && window.__DASHBOARD_DATA__.convoyList) || [];
|
|
557
|
+
if (convoyListFallback.length > 0) {
|
|
558
|
+
var sumTokens = convoyListFallback.reduce(function(s, c) { return s + (c.total_tokens != null ? c.total_tokens : 0); }, 0);
|
|
559
|
+
var sumCost = convoyListFallback.reduce(function(s, c) { return s + (c.total_cost_usd != null ? c.total_cost_usd : 0); }, 0);
|
|
560
|
+
if (sumTokens > 0) {
|
|
561
|
+
setKpiValue('overall-total-tokens', formatTokens(sumTokens));
|
|
562
|
+
setKpiValue('overall-total-cost', '$' + sumCost.toFixed(2));
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Total tasks and retries
|
|
568
|
+
var tt = stats.taskTotals || {};
|
|
569
|
+
setKpiValue('overall-total-tasks', String(tt.totalTasks || 0));
|
|
570
|
+
setKpiValue('overall-total-retries', String(tt.totalRetries || 0));
|
|
444
571
|
}
|
|
445
572
|
|
|
446
573
|
function setKpiValue(id, value) {
|
|
@@ -461,7 +588,70 @@ Export
|
|
|
461
588
|
return hr + 'h ' + remMin + 'm';
|
|
462
589
|
}
|
|
463
590
|
|
|
591
|
+
function renderActivityTimeline() {
|
|
592
|
+
var el = document.getElementById('activity-timeline-chart');
|
|
593
|
+
if (!el) return;
|
|
594
|
+
var data = window.__DASHBOARD_DATA__;
|
|
595
|
+
var timeline = (data && data.overallStats && data.overallStats.activityTimeline) || [];
|
|
596
|
+
if (timeline.length === 0) {
|
|
597
|
+
el.innerHTML = emptyStateHtml('timeline', 'No activity yet', 'Convoy run activity will appear here as runs complete.');
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
var maxCount = Math.max.apply(null, timeline.map(function(d) { return d.count; }));
|
|
601
|
+
var html = '<div class="activity-timeline">';
|
|
602
|
+
for (var i = 0; i < timeline.length; i++) {
|
|
603
|
+
var d = timeline[i];
|
|
604
|
+
var pct = maxCount > 0 ? Math.round((d.count / maxCount) * 100) : 0;
|
|
605
|
+
html += '<div class="bar-row">' +
|
|
606
|
+
'<span class="bar-label">' + formatShortDate(d.date) + '</span>' +
|
|
607
|
+
'<div class="bar-track"><div class="bar-segment bar--accent" style="width:' + pct + '%"></div></div>' +
|
|
608
|
+
'<span class="bar-value">' + d.count + '</span>' +
|
|
609
|
+
'</div>';
|
|
610
|
+
}
|
|
611
|
+
html += '</div>';
|
|
612
|
+
el.innerHTML = html;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
async function renderRecentSessions() {
|
|
616
|
+
var el = document.getElementById('sessions-table');
|
|
617
|
+
if (!el) return;
|
|
618
|
+
try {
|
|
619
|
+
var allEvents = await loadNdjson(base + 'data/events.ndjson');
|
|
620
|
+
var sessions = allEvents.filter(function(e) { return e.type === 'session'; });
|
|
621
|
+
sessions.sort(function(a, b) {
|
|
622
|
+
return (b.timestamp || '').localeCompare(a.timestamp || '');
|
|
623
|
+
});
|
|
624
|
+
sessions = sessions.slice(0, 15);
|
|
625
|
+
if (sessions.length === 0) {
|
|
626
|
+
el.innerHTML = emptyStateHtml('sessions', 'No sessions recorded yet', 'Agent session data will appear here when sessions are logged via opencastle log.');
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
var thead = '<thead><tr>' +
|
|
630
|
+
'<th>Agent</th><th>Task</th><th>Outcome</th><th>Duration</th><th>Retries</th><th>Files</th><th>Time</th>' +
|
|
631
|
+
'</tr></thead>';
|
|
632
|
+
var tbody = '<tbody>';
|
|
633
|
+
for (var i = 0; i < sessions.length; i++) {
|
|
634
|
+
var s = sessions[i];
|
|
635
|
+
var outcomeClass = s.outcome === 'success' ? 'outcome-badge--success' : s.outcome === 'failed' ? 'outcome-badge--failed' : 'outcome-badge--partial';
|
|
636
|
+
tbody += '<tr>' +
|
|
637
|
+
'<td class="td-agent">' + escapeHtml(s.agent || '\u2014') + '</td>' +
|
|
638
|
+
'<td class="td-task">' + escapeHtml(s.task || '\u2014') + '</td>' +
|
|
639
|
+
'<td><span class="outcome-badge ' + outcomeClass + '">' + escapeHtml(s.outcome || '\u2014') + '</span></td>' +
|
|
640
|
+
'<td>' + (s.duration_min != null ? s.duration_min + 'm' : '\u2014') + '</td>' +
|
|
641
|
+
'<td>' + (s.retries || 0) + '</td>' +
|
|
642
|
+
'<td>' + (s.files_changed || 0) + '</td>' +
|
|
643
|
+
'<td>' + (s.timestamp ? formatTime(s.timestamp) : '\u2014') + '</td>' +
|
|
644
|
+
'</tr>';
|
|
645
|
+
}
|
|
646
|
+
tbody += '</tbody>';
|
|
647
|
+
el.innerHTML = '<table class="sessions-table">' + thead + tbody + '</table>';
|
|
648
|
+
} catch (e) {
|
|
649
|
+
el.innerHTML = emptyStateHtml('sessions', 'No sessions recorded yet', 'Agent session data will appear here when sessions are logged.');
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
464
653
|
async function loadConvoyDetail(convoyId) {
|
|
654
|
+
executionLogLimit = 10;
|
|
465
655
|
if (!convoyId) {
|
|
466
656
|
renderConvoyDetailHeader(null);
|
|
467
657
|
['pipeline-section', 'agent-section', 'tier-section', 'model-section', 'quality-section', 'reliability-section', 'drift-section', 'outputs-section', 'execution-section', 'event-timeline-section', 'panel-section', 'reviews-section'].forEach(function(id) {
|
|
@@ -716,6 +906,21 @@ Export
|
|
|
716
906
|
|
|
717
907
|
function deriveTier(model) {
|
|
718
908
|
if (!model) return 'unknown';
|
|
909
|
+
var TIER_MAP = {
|
|
910
|
+
'claude-opus-4-6': 'premium',
|
|
911
|
+
'claude-opus-4': 'premium',
|
|
912
|
+
'claude-sonnet-4-6': 'standard',
|
|
913
|
+
'claude-sonnet-4': 'standard',
|
|
914
|
+
'claude-haiku-3-5': 'economy',
|
|
915
|
+
'claude-haiku-4': 'economy',
|
|
916
|
+
'gpt-5-mini': 'economy',
|
|
917
|
+
'gpt-5.3-codex': 'standard',
|
|
918
|
+
'gpt-5': 'standard',
|
|
919
|
+
'gemini-3.1-pro': 'standard',
|
|
920
|
+
'gemini-3.0-flash': 'economy',
|
|
921
|
+
};
|
|
922
|
+
if (TIER_MAP[model]) return TIER_MAP[model];
|
|
923
|
+
// Fallback heuristics for unknown models
|
|
719
924
|
var m = model.toLowerCase();
|
|
720
925
|
if (m.includes('opus')) return 'premium';
|
|
721
926
|
if (m.includes('sonnet') || m.includes('pro')) return 'standard';
|
|
@@ -868,8 +1073,9 @@ Export
|
|
|
868
1073
|
var mechOrder = ['sub-agent', 'background', 'unknown'];
|
|
869
1074
|
var mechs = mechOrder.filter(function(m) { return mechCounts[m]; }).map(function(m) { return { name: m, count: mechCounts[m] }; });
|
|
870
1075
|
|
|
871
|
-
|
|
872
|
-
|
|
1076
|
+
var isAllUnknown = mechs.length === 0 || (mechs.length === 1 && mechs[0].name === 'unknown');
|
|
1077
|
+
if (isAllUnknown) {
|
|
1078
|
+
el.innerHTML = emptyStateHtml('mechanism', 'No delegation data', 'Delegation mechanism data is not available for this convoy.');
|
|
873
1079
|
return;
|
|
874
1080
|
}
|
|
875
1081
|
|
|
@@ -947,7 +1153,7 @@ Export
|
|
|
947
1153
|
var models = Object.entries(modelCounts).sort(function(a, b) { return b[1] - a[1]; });
|
|
948
1154
|
|
|
949
1155
|
if (models.length === 0) {
|
|
950
|
-
el.innerHTML = emptyStateHtml('models', 'No model data yet', 'Model utilization across tasks will be shown here.');
|
|
1156
|
+
el.innerHTML = emptyStateHtml('models', tasks.length > 0 ? 'Model information unavailable' : 'No model data yet', tasks.length > 0 ? 'No model information was recorded for tasks in this convoy.' : 'Model utilization across tasks will be shown here.');
|
|
951
1157
|
return;
|
|
952
1158
|
}
|
|
953
1159
|
|
|
@@ -975,7 +1181,8 @@ Export
|
|
|
975
1181
|
return;
|
|
976
1182
|
}
|
|
977
1183
|
|
|
978
|
-
var
|
|
1184
|
+
var allSorted = tasks.slice().filter(function(t) { return t.started_at; }).sort(function(a, b) { return new Date(a.started_at) - new Date(b.started_at); });
|
|
1185
|
+
var sorted = allSorted.slice(0, executionLogLimit);
|
|
979
1186
|
|
|
980
1187
|
if (sorted.length === 0) {
|
|
981
1188
|
el.innerHTML = emptyStateHtml('execLog', 'No execution history yet', 'A step-by-step trace of task activity will appear here.');
|
|
@@ -1017,6 +1224,15 @@ Export
|
|
|
1017
1224
|
'</div>';
|
|
1018
1225
|
}).join('') +
|
|
1019
1226
|
'</div>';
|
|
1227
|
+
if (allSorted.length > executionLogLimit) {
|
|
1228
|
+
var remaining = allSorted.length - executionLogLimit;
|
|
1229
|
+
el.innerHTML += '<div style="text-align:center;padding:16px"><button class="dash-btn dash-btn--ghost" id="exec-log-more-btn" type="button">Show more (' + remaining + ' remaining)</button></div>';
|
|
1230
|
+
document.getElementById('exec-log-more-btn')?.addEventListener('click', function() {
|
|
1231
|
+
executionLogLimit = allSorted.length;
|
|
1232
|
+
var convoy = window.__SELECTED_CONVOY__;
|
|
1233
|
+
renderDetailExecutionLog((convoy && convoy.tasks) ? convoy.tasks : []);
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1020
1236
|
}
|
|
1021
1237
|
|
|
1022
1238
|
// ── Convoy Detail: Panel Reviews ─────────────────────────
|
|
@@ -1028,7 +1244,7 @@ Export
|
|
|
1028
1244
|
var panelTasks = (tasks || []).filter(function(t) { return t.panel_attempts > 0; });
|
|
1029
1245
|
|
|
1030
1246
|
if (panelTasks.length === 0) {
|
|
1031
|
-
el.innerHTML = emptyStateHtml('panels', 'No panel reviews
|
|
1247
|
+
el.innerHTML = emptyStateHtml('panels', 'No panel reviews', 'This convoy completed without requiring panel reviews.');
|
|
1032
1248
|
return;
|
|
1033
1249
|
}
|
|
1034
1250
|
|
|
@@ -1064,7 +1280,7 @@ Export
|
|
|
1064
1280
|
var reviewedTasks = (tasks || []).filter(function(t) { return t.review_level != null; });
|
|
1065
1281
|
|
|
1066
1282
|
if (reviewedTasks.length === 0) {
|
|
1067
|
-
el.innerHTML = emptyStateHtml('panels', 'No fast reviews
|
|
1283
|
+
el.innerHTML = emptyStateHtml('panels', 'No fast reviews', 'This convoy completed without fast review gates.');
|
|
1068
1284
|
return;
|
|
1069
1285
|
}
|
|
1070
1286
|
|
|
@@ -1169,13 +1385,27 @@ Export
|
|
|
1169
1385
|
|
|
1170
1386
|
var dlqCount = detail.dlq_count || 0;
|
|
1171
1387
|
var dlqEntries = detail.dlq_entries || [];
|
|
1388
|
+
var tasks = detail.tasks || [];
|
|
1172
1389
|
|
|
1173
1390
|
var dlqCardEl = document.getElementById('reliability-dlq-card');
|
|
1174
1391
|
if (dlqCardEl) {
|
|
1392
|
+
var totalRetries = tasks.reduce(function(s, t) { return s + (t.retries || 0); }, 0);
|
|
1393
|
+
var doneTasks = tasks.filter(function(t) { return t.status === 'done'; }).length;
|
|
1394
|
+
var successRate = tasks.length > 0 ? Math.round((doneTasks / tasks.length) * 100) + '%' : '\u2014';
|
|
1175
1395
|
dlqCardEl.innerHTML =
|
|
1396
|
+
'<div class="task-summary-cards">' +
|
|
1176
1397
|
'<div class="task-summary-card task-summary-card--' + (dlqCount > 0 ? 'errors' : 'done') + '">' +
|
|
1177
1398
|
'<span class="task-summary-card__label">Retry Queue <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Tasks that failed too many times and need manual attention. Also known as Dead Letter Queue (DLQ)." data-tooltip="Tasks that failed too many times and need manual attention. Also known as Dead Letter Queue (DLQ).">' + INFO_ICON + '</span></span>' +
|
|
1178
1399
|
'<span class="task-summary-card__value">' + dlqCount + '</span>' +
|
|
1400
|
+
'</div>' +
|
|
1401
|
+
'<div class="task-summary-card task-summary-card--running">' +
|
|
1402
|
+
'<span class="task-summary-card__label">Total Retries <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Total number of task retries across all tasks in this convoy." data-tooltip="Total number of task retries across all tasks in this convoy.">' + INFO_ICON + '</span></span>' +
|
|
1403
|
+
'<span class="task-summary-card__value">' + totalRetries + '</span>' +
|
|
1404
|
+
'</div>' +
|
|
1405
|
+
'<div class="task-summary-card task-summary-card--done">' +
|
|
1406
|
+
'<span class="task-summary-card__label">Task Success Rate <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Percentage of tasks that completed successfully." data-tooltip="Percentage of tasks that completed successfully.">' + INFO_ICON + '</span></span>' +
|
|
1407
|
+
'<span class="task-summary-card__value">' + successRate + '</span>' +
|
|
1408
|
+
'</div>' +
|
|
1179
1409
|
'</div>';
|
|
1180
1410
|
}
|
|
1181
1411
|
|
|
@@ -1205,7 +1435,6 @@ Export
|
|
|
1205
1435
|
|
|
1206
1436
|
var errorEl = document.getElementById('reliability-error-overview');
|
|
1207
1437
|
if (errorEl) {
|
|
1208
|
-
var tasks = detail.tasks || [];
|
|
1209
1438
|
var errorCategories = [
|
|
1210
1439
|
{ key: 'failed', label: 'Failed', color: '#ef4444' },
|
|
1211
1440
|
{ key: 'gate-failed', label: 'Quality Check Failed', color: '#f59e0b' },
|
|
@@ -1287,8 +1516,8 @@ Export
|
|
|
1287
1516
|
if (!section) return;
|
|
1288
1517
|
section.style.display = '';
|
|
1289
1518
|
|
|
1290
|
-
var artifactCount = detail.artifact_count != null ? detail.artifact_count : 0;
|
|
1291
1519
|
var artifacts = detail.artifacts || [];
|
|
1520
|
+
var artifactCount = artifacts.length;
|
|
1292
1521
|
|
|
1293
1522
|
var cardsEl = document.getElementById('outputs-cards');
|
|
1294
1523
|
if (cardsEl) {
|
|
@@ -1331,7 +1560,7 @@ Export
|
|
|
1331
1560
|
}
|
|
1332
1561
|
|
|
1333
1562
|
// ── Event Timeline Section ─────────────────────────────
|
|
1334
|
-
var eventTimelinePageSize =
|
|
1563
|
+
var eventTimelinePageSize = 20;
|
|
1335
1564
|
var eventTimelineCurrentPage = 1;
|
|
1336
1565
|
var eventTimelineActiveFilter = 'all';
|
|
1337
1566
|
var eventTimelineAllEvents = [];
|
|
@@ -1368,7 +1597,10 @@ Export
|
|
|
1368
1597
|
if (!section) return;
|
|
1369
1598
|
section.style.display = '';
|
|
1370
1599
|
|
|
1371
|
-
eventTimelineAllEvents = detail.events || []
|
|
1600
|
+
eventTimelineAllEvents = (detail.events || []).slice().sort(function(a, b) {
|
|
1601
|
+
if (!a.created_at || !b.created_at) return 0;
|
|
1602
|
+
return a.created_at < b.created_at ? -1 : a.created_at > b.created_at ? 1 : 0;
|
|
1603
|
+
});
|
|
1372
1604
|
eventTimelineCurrentPage = 1;
|
|
1373
1605
|
eventTimelineActiveFilter = 'all';
|
|
1374
1606
|
|
|
@@ -1454,8 +1686,15 @@ Export
|
|
|
1454
1686
|
});
|
|
1455
1687
|
|
|
1456
1688
|
var loadMoreEl = document.getElementById('event-timeline-load-more');
|
|
1689
|
+
var loadMoreBtn = document.getElementById('event-timeline-more-btn');
|
|
1457
1690
|
if (loadMoreEl) {
|
|
1458
|
-
|
|
1691
|
+
if (visible.length < filtered.length) {
|
|
1692
|
+
loadMoreEl.style.display = '';
|
|
1693
|
+
var remaining = filtered.length - visible.length;
|
|
1694
|
+
if (loadMoreBtn) loadMoreBtn.textContent = 'Show more (' + remaining + ' remaining)';
|
|
1695
|
+
} else {
|
|
1696
|
+
loadMoreEl.style.display = 'none';
|
|
1697
|
+
}
|
|
1459
1698
|
}
|
|
1460
1699
|
}
|
|
1461
1700
|
|
|
@@ -1505,6 +1744,8 @@ Export
|
|
|
1505
1744
|
|
|
1506
1745
|
renderOverallStats();
|
|
1507
1746
|
renderConvoyList();
|
|
1747
|
+
renderActivityTimeline();
|
|
1748
|
+
renderRecentSessions();
|
|
1508
1749
|
|
|
1509
1750
|
var loadMoreBtn = document.getElementById('event-timeline-more-btn');
|
|
1510
1751
|
if (loadMoreBtn) {
|
|
@@ -1519,15 +1760,47 @@ Export
|
|
|
1519
1760
|
showHomeView();
|
|
1520
1761
|
});
|
|
1521
1762
|
|
|
1522
|
-
document.getElementById('
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1763
|
+
document.getElementById('export-btn')?.addEventListener('click', function() {
|
|
1764
|
+
var exportData = {
|
|
1765
|
+
overallStats: window.__DASHBOARD_DATA__ && window.__DASHBOARD_DATA__.overallStats,
|
|
1766
|
+
convoyList: window.__DASHBOARD_DATA__ && window.__DASHBOARD_DATA__.convoyList,
|
|
1767
|
+
};
|
|
1768
|
+
if (window.__SELECTED_CONVOY__) {
|
|
1769
|
+
exportData.selectedConvoy = window.__SELECTED_CONVOY__;
|
|
1770
|
+
}
|
|
1771
|
+
var blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
|
|
1772
|
+
var url = URL.createObjectURL(blob);
|
|
1773
|
+
var a = document.createElement('a');
|
|
1774
|
+
a.href = url;
|
|
1775
|
+
a.download = 'opencastle-dashboard-export.json';
|
|
1776
|
+
document.body.appendChild(a);
|
|
1777
|
+
a.click();
|
|
1778
|
+
document.body.removeChild(a);
|
|
1779
|
+
URL.revokeObjectURL(url);
|
|
1780
|
+
});
|
|
1781
|
+
|
|
1782
|
+
document.getElementById('cl-filter-search')?.addEventListener('input', function() {
|
|
1783
|
+
convoyListCurrentPage = 1;
|
|
1784
|
+
renderConvoyList();
|
|
1785
|
+
});
|
|
1786
|
+
document.getElementById('cl-filter-status')?.addEventListener('change', function() {
|
|
1787
|
+
convoyListCurrentPage = 1;
|
|
1788
|
+
renderConvoyList();
|
|
1789
|
+
});
|
|
1790
|
+
document.getElementById('cl-filter-from')?.addEventListener('change', function() {
|
|
1791
|
+
convoyListCurrentPage = 1;
|
|
1792
|
+
renderConvoyList();
|
|
1793
|
+
});
|
|
1794
|
+
document.getElementById('cl-filter-to')?.addEventListener('change', function() {
|
|
1795
|
+
convoyListCurrentPage = 1;
|
|
1796
|
+
renderConvoyList();
|
|
1797
|
+
});
|
|
1526
1798
|
document.getElementById('cl-filter-reset')?.addEventListener('click', () => {
|
|
1527
1799
|
const s = document.getElementById('cl-filter-search'); if (s) s.value = '';
|
|
1528
1800
|
const st = document.getElementById('cl-filter-status'); if (st) st.value = '';
|
|
1529
1801
|
const f = document.getElementById('cl-filter-from'); if (f) f.value = '';
|
|
1530
1802
|
const t = document.getElementById('cl-filter-to'); if (t) t.value = '';
|
|
1803
|
+
convoyListCurrentPage = 1;
|
|
1531
1804
|
renderConvoyList();
|
|
1532
1805
|
});
|
|
1533
1806
|
|