opencastle 0.32.6 → 0.32.7

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.
Files changed (42) hide show
  1. package/dist/cli/convoy/engine.d.ts.map +1 -1
  2. package/dist/cli/convoy/engine.js +79 -4
  3. package/dist/cli/convoy/engine.js.map +1 -1
  4. package/dist/cli/convoy/engine.test.js +11 -9
  5. package/dist/cli/convoy/engine.test.js.map +1 -1
  6. package/dist/dashboard/scripts/etl.js +17 -2
  7. package/dist/dashboard/scripts/etl.js.map +1 -1
  8. package/package.json +1 -1
  9. package/src/cli/convoy/engine.test.ts +11 -9
  10. package/src/cli/convoy/engine.ts +78 -4
  11. package/src/dashboard/dist/_astro/index.6xXNs4L2.css +1 -0
  12. package/src/dashboard/dist/data/convoy-list.json +27 -13
  13. package/src/dashboard/dist/data/convoys/demo-api-v2.json +16 -10
  14. package/src/dashboard/dist/data/convoys/demo-auth-revamp.json +25 -15
  15. package/src/dashboard/dist/data/convoys/demo-dashboard-ui.json +35 -21
  16. package/src/dashboard/dist/data/convoys/demo-data-pipeline.json +17 -11
  17. package/src/dashboard/dist/data/convoys/demo-deploy-ci.json +8 -4
  18. package/src/dashboard/dist/data/convoys/demo-docs-update.json +13 -9
  19. package/src/dashboard/dist/data/convoys/demo-perf-opt.json +22 -14
  20. package/src/dashboard/dist/data/overall-stats.json +36 -2
  21. package/src/dashboard/dist/index.html +149 -93
  22. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  23. package/src/dashboard/public/data/convoy-list.json +27 -13
  24. package/src/dashboard/public/data/convoys/demo-api-v2.json +16 -10
  25. package/src/dashboard/public/data/convoys/demo-auth-revamp.json +25 -15
  26. package/src/dashboard/public/data/convoys/demo-dashboard-ui.json +35 -21
  27. package/src/dashboard/public/data/convoys/demo-data-pipeline.json +17 -11
  28. package/src/dashboard/public/data/convoys/demo-deploy-ci.json +8 -4
  29. package/src/dashboard/public/data/convoys/demo-docs-update.json +13 -9
  30. package/src/dashboard/public/data/convoys/demo-perf-opt.json +22 -14
  31. package/src/dashboard/public/data/overall-stats.json +36 -2
  32. package/src/dashboard/scripts/etl.ts +15 -3
  33. package/src/dashboard/scripts/generate-demo-db.ts +42 -34
  34. package/src/dashboard/src/pages/index.astro +159 -112
  35. package/src/dashboard/src/styles/dashboard.css +58 -3
  36. package/src/dashboard/dist/_astro/index.wyN9vmjZ.css +0 -1
  37. package/src/dashboard/dist/data/convoys/demo-convoy-1.json +0 -111
  38. package/src/dashboard/dist/data/convoys/demo-convoy-2.json +0 -72
  39. package/src/dashboard/dist/data/pipelines.ndjson +0 -5285
  40. package/src/dashboard/public/data/convoys/demo-convoy-1.json +0 -111
  41. package/src/dashboard/public/data/convoys/demo-convoy-2.json +0 -72
  42. package/src/dashboard/public/data/pipelines.ndjson +0 -5285
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
1
+ import { existsSync, mkdirSync, writeFileSync, copyFileSync } from 'node:fs';
2
2
  import { resolve, dirname } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  const __filename = fileURLToPath(import.meta.url);
@@ -104,6 +104,9 @@ function parseArgs() {
104
104
  else if (a === '--out' && args[i + 1]) {
105
105
  result.out = args[++i];
106
106
  }
107
+ else if (a === '--events' && args[i + 1]) {
108
+ result.events = args[++i];
109
+ }
107
110
  }
108
111
  return result;
109
112
  }
@@ -113,7 +116,19 @@ if (isMain) {
113
116
  const parsed = parseArgs();
114
117
  const dbPath = parsed.db != null ? resolve(process.cwd(), parsed.db) : resolve(process.cwd(), '.opencastle', 'convoy.db');
115
118
  const outputDir = parsed.out != null ? resolve(process.cwd(), parsed.out) : resolve(__dirname, '..', 'public', 'data');
116
- runEtl({ dbPath, outputDir }).catch((err) => {
119
+ runEtl({ dbPath, outputDir }).then(() => {
120
+ if (parsed.events) {
121
+ const eventsPath = resolve(process.cwd(), parsed.events);
122
+ const dest = resolve(outputDir, 'events.ndjson');
123
+ if (existsSync(eventsPath)) {
124
+ copyFileSync(eventsPath, dest);
125
+ console.log(`Events copied: ${eventsPath} → ${dest}`);
126
+ }
127
+ else {
128
+ console.warn(`⚠ Events file not found: ${eventsPath}`);
129
+ }
130
+ }
131
+ }).catch((err) => {
117
132
  console.error('ETL failed:', err.message);
118
133
  process.exit(1);
119
134
  });
@@ -1 +1 @@
1
- {"version":3,"file":"etl.js","sourceRoot":"","sources":["../../../src/dashboard/scripts/etl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"etl.js","sourceRoot":"","sources":["../../../src/dashboard/scripts/etl.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencastle",
3
- "version": "0.32.6",
3
+ "version": "0.32.7",
4
4
  "type": "module",
5
5
  "description": "Multi-agent orchestration framework for AI coding assistants",
6
6
  "bin": {
@@ -1523,7 +1523,7 @@ describe('cost tracking', () => {
1523
1523
  expect(tasks[0].total_tokens).toBe(150)
1524
1524
  })
1525
1525
 
1526
- it('leaves cost fields null when adapter returns no usage', async () => {
1526
+ it('estimates token usage when adapter returns no usage', async () => {
1527
1527
  const adapter = makeAdapter()
1528
1528
  // default makeAdapter returns no usage field
1529
1529
 
@@ -1541,9 +1541,9 @@ describe('cost tracking', () => {
1541
1541
  const store = createConvoyStore(dbPath)
1542
1542
  const tasks = store.getTasksByConvoy(result.convoyId)
1543
1543
  store.close()
1544
- expect(tasks[0].prompt_tokens).toBeNull()
1545
- expect(tasks[0].completion_tokens).toBeNull()
1546
- expect(tasks[0].total_tokens).toBeNull()
1544
+ expect(tasks[0].prompt_tokens).toBeGreaterThan(0)
1545
+ expect(tasks[0].completion_tokens).toBeGreaterThanOrEqual(0)
1546
+ expect(tasks[0].total_tokens).toBeGreaterThan(0)
1547
1547
  })
1548
1548
 
1549
1549
  it('aggregates total_tokens from multiple tasks to convoy record', async () => {
@@ -1596,7 +1596,7 @@ describe('cost tracking', () => {
1596
1596
  expect(result.cost).toEqual({ total_tokens: 75 })
1597
1597
  })
1598
1598
 
1599
- it('omits cost from ConvoyResult when no usage data is available', async () => {
1599
+ it('includes estimated cost in ConvoyResult when adapter returns no usage data', async () => {
1600
1600
  const adapter = makeAdapter()
1601
1601
  // default makeAdapter returns no usage
1602
1602
 
@@ -1611,7 +1611,8 @@ describe('cost tracking', () => {
1611
1611
 
1612
1612
  const result = await engine.run()
1613
1613
 
1614
- expect(result.cost).toBeUndefined()
1614
+ expect(result.cost).toBeDefined()
1615
+ expect(result.cost!.total_tokens).toBeGreaterThan(0)
1615
1616
  })
1616
1617
 
1617
1618
  it('partial usage fields are persisted correctly (only total_tokens set)', async () => {
@@ -1642,7 +1643,7 @@ describe('cost tracking', () => {
1642
1643
  expect(tasks[0].completion_tokens).toBeNull()
1643
1644
  })
1644
1645
 
1645
- it('convoy total_tokens is null when no task has usage', async () => {
1646
+ it('convoy total_tokens uses estimated values when no task has usage', async () => {
1646
1647
  const adapter = makeAdapter()
1647
1648
  // default adapter returns no usage
1648
1649
 
@@ -1663,8 +1664,9 @@ describe('cost tracking', () => {
1663
1664
  const store = createConvoyStore(dbPath)
1664
1665
  const convoy = store.getConvoy(result.convoyId)
1665
1666
  store.close()
1666
- expect(convoy!.total_tokens).toBeNull()
1667
- expect(result.cost).toBeUndefined()
1667
+ expect(convoy!.total_tokens).toBeGreaterThan(0)
1668
+ expect(result.cost).toBeDefined()
1669
+ expect(result.cost!.total_tokens).toBeGreaterThan(0)
1668
1670
  })
1669
1671
  })
1670
1672
 
@@ -44,6 +44,29 @@ import { calculateCost } from './pricing.js'
44
44
 
45
45
  const execFile = promisify(execFileCb)
46
46
 
47
+ /** Map agent names to their default model. Used when adapters don't report model. */
48
+ const AGENT_MODEL_MAP: Record<string, string> = {
49
+ 'developer': 'claude-sonnet-4-6',
50
+ 'ui-ux-expert': 'claude-sonnet-4-6',
51
+ 'testing-expert': 'claude-sonnet-4-6',
52
+ 'security-expert': 'claude-sonnet-4-6',
53
+ 'performance-expert': 'claude-sonnet-4-6',
54
+ 'devops-expert': 'claude-sonnet-4-6',
55
+ 'data-expert': 'claude-sonnet-4-6',
56
+ 'api-designer': 'claude-sonnet-4-6',
57
+ 'copywriter': 'claude-sonnet-4-6',
58
+ 'content-engineer': 'claude-sonnet-4-6',
59
+ 'database-engineer': 'claude-sonnet-4-6',
60
+ 'researcher': 'claude-sonnet-4-6',
61
+ 'release-manager': 'claude-sonnet-4-6',
62
+ 'architect': 'claude-opus-4-6',
63
+ 'team-lead': 'claude-opus-4-6',
64
+ 'reviewer': 'claude-haiku-3-5',
65
+ 'documentation-writer': 'claude-haiku-3-5',
66
+ 'seo-specialist': 'claude-haiku-3-5',
67
+ 'session-guard': 'claude-haiku-3-5',
68
+ }
69
+
47
70
  // ── Public interfaces ─────────────────────────────────────────────────────────
48
71
 
49
72
  export interface ConvoyEngineOptions {
@@ -1228,7 +1251,7 @@ async function runConvoy(
1228
1251
  process.stdout.write(` ${c.cyan('▶')} ${c.bold(`[${taskRecord.id}]`)} ${taskRecord.agent}${worktreePath ? c.dim(' (worktree)') : ''}\n`)
1229
1252
  events.emit(
1230
1253
  'task_started',
1231
- { worker_id: workerId },
1254
+ { worker_id: workerId, mechanism: worktreePath ? 'background' : 'sub-agent' },
1232
1255
  { convoy_id: convoyId, task_id: taskRecord.id, worker_id: workerId },
1233
1256
  )
1234
1257
 
@@ -1434,10 +1457,20 @@ async function runConvoy(
1434
1457
  store.updateWorkerStatus(workerId, 'killed', { finished_at: finishedAt })
1435
1458
  process.stdout.write(` ${c.yellow('⟳')} ${c.bold(`[${taskRecord.id}]`)} timed out, retry ${freshRecord.retries + 1}/${freshRecord.max_retries}\n`)
1436
1459
  } else {
1460
+ // Estimate tokens even for timed-out tasks — you still paid for them
1461
+ const estimatedPrompt = Math.ceil(taskRecord.prompt.length / 4)
1462
+ const estimatedCompletion = Math.ceil((result.output?.length ?? 0) / 4)
1463
+ const timeoutModel = taskRecord.model ?? AGENT_MODEL_MAP[taskRecord.agent.toLowerCase()] ?? taskAdapter.name
1464
+ const timeoutCost = calculateCost(timeoutModel, estimatedPrompt, estimatedCompletion)
1437
1465
  store.withTransaction(() => {
1438
1466
  store.updateTaskStatus(taskRecord.id, convoyId, 'timed-out', {
1439
1467
  finished_at: finishedAt,
1440
1468
  output: result.output,
1469
+ prompt_tokens: estimatedPrompt,
1470
+ completion_tokens: estimatedCompletion,
1471
+ total_tokens: estimatedPrompt + estimatedCompletion,
1472
+ model: timeoutModel,
1473
+ cost_usd: timeoutCost,
1441
1474
  })
1442
1475
  store.updateWorkerStatus(workerId, 'failed', { finished_at: finishedAt })
1443
1476
  })
@@ -2325,8 +2358,16 @@ async function runConvoy(
2325
2358
  if (result.usage.prompt_tokens != null) usageExtra.prompt_tokens = result.usage.prompt_tokens
2326
2359
  if (result.usage.completion_tokens != null) usageExtra.completion_tokens = result.usage.completion_tokens
2327
2360
  if (result.usage.total_tokens != null) usageExtra.total_tokens = result.usage.total_tokens
2328
- } else if (verbose) {
2329
- process.stdout.write(` ${c.dim('ℹ')} No token usage data returned by adapter ${taskAdapter.name}\n`)
2361
+ } else {
2362
+ // Estimate tokens from prompt/output text length (~4 chars per token)
2363
+ const estimatedPrompt = Math.ceil(taskRecord.prompt.length / 4)
2364
+ const estimatedCompletion = Math.ceil((result.output?.length ?? 0) / 4)
2365
+ usageExtra.prompt_tokens = estimatedPrompt
2366
+ usageExtra.completion_tokens = estimatedCompletion
2367
+ usageExtra.total_tokens = estimatedPrompt + estimatedCompletion
2368
+ if (verbose) {
2369
+ process.stdout.write(` ${c.dim('ℹ')} Estimated ${usageExtra.total_tokens} tokens (adapter ${taskAdapter.name} returned no usage data)\n`)
2370
+ }
2330
2371
  }
2331
2372
 
2332
2373
  // ── Context compaction check (Phase 44) ─────────────────────────────
@@ -2445,6 +2486,29 @@ async function runConvoy(
2445
2486
  process.stderr.write(`[artifacts] Warning: extraction failed for task ${taskRecord.id}: ${(err as Error).message}\n`)
2446
2487
  }
2447
2488
 
2489
+ // ── Create file artifacts from task file list ────────────────────────
2490
+ if (taskRecord.files && !taskRecord.outputs) {
2491
+ try {
2492
+ const fileList: string[] = JSON.parse(taskRecord.files)
2493
+ for (const filePath of fileList.slice(0, 20)) {
2494
+ try {
2495
+ store.insertArtifact({
2496
+ id: `artifact-${taskRecord.id}-file-${filePath.replace(/[^a-z0-9]/gi, '-')}-${Date.now()}`,
2497
+ convoy_id: convoyId,
2498
+ task_id: taskRecord.id,
2499
+ name: filePath,
2500
+ type: 'file',
2501
+ content: '',
2502
+ created_at: new Date().toISOString(),
2503
+ })
2504
+ } catch (err) {
2505
+ if (err instanceof ConvoyArtifactLimitError) break
2506
+ // Other errors are non-critical
2507
+ }
2508
+ }
2509
+ } catch { /* files not parseable */ }
2510
+ }
2511
+
2448
2512
  // ── Output contract validation ────────────────────────────────────────
2449
2513
  const contractResult = validateOutput(taskRecord.agent, result.output)
2450
2514
  if (!contractResult.valid) {
@@ -2508,7 +2572,7 @@ async function runConvoy(
2508
2572
  } catch { /* non-critical */ }
2509
2573
  }
2510
2574
 
2511
- const taskModel = taskRecord.model ?? taskAdapter.name
2575
+ const taskModel = taskRecord.model ?? AGENT_MODEL_MAP[taskRecord.agent.toLowerCase()] ?? taskAdapter.name
2512
2576
  const taskCost = calculateCost(taskModel, usageExtra.prompt_tokens, usageExtra.completion_tokens)
2513
2577
 
2514
2578
  store.withTransaction(() => {
@@ -2592,11 +2656,21 @@ async function runConvoy(
2592
2656
  store.updateWorkerStatus(workerId, 'failed', { finished_at: finishedAt })
2593
2657
  process.stdout.write(` ${c.yellow('⟳')} ${c.bold(`[${taskRecord.id}]`)} retry ${freshRecord.retries + 1}/${freshRecord.max_retries}\n`)
2594
2658
  } else {
2659
+ // Estimate tokens even for failed tasks — you still paid for them
2660
+ const estimatedPrompt = Math.ceil(taskRecord.prompt.length / 4)
2661
+ const estimatedCompletion = Math.ceil((result.output?.length ?? 0) / 4)
2662
+ const failModel = taskRecord.model ?? AGENT_MODEL_MAP[taskRecord.agent.toLowerCase()] ?? taskAdapter.name
2663
+ const failCost = calculateCost(failModel, estimatedPrompt, estimatedCompletion)
2595
2664
  store.withTransaction(() => {
2596
2665
  store.updateTaskStatus(taskRecord.id, convoyId, 'failed', {
2597
2666
  finished_at: finishedAt,
2598
2667
  output: result.output,
2599
2668
  exit_code: result.exitCode,
2669
+ prompt_tokens: estimatedPrompt,
2670
+ completion_tokens: estimatedCompletion,
2671
+ total_tokens: estimatedPrompt + estimatedCompletion,
2672
+ model: failModel,
2673
+ cost_usd: failCost,
2600
2674
  })
2601
2675
  store.updateWorkerStatus(workerId, 'failed', { finished_at: finishedAt })
2602
2676
  })
@@ -0,0 +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: #7a7a8e;--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__logo-link{display:flex;align-items:center;text-decoration:none}.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;transition:border-color var(--transition-fast)}.chart-card:hover{border-color:#ffffff1a}.chart-card__header{padding:20px 24px 8px;display:flex;flex-wrap:wrap;align-items:baseline;gap:6px}.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;width:100%}.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}.activity-timeline--vertical{display:flex;flex-direction:row;gap:2px;align-items:flex-end;overflow-x:auto;padding:8px 0 0;min-height:180px}.vbar-col{display:flex;flex-direction:column;align-items:center;min-width:44px;flex-shrink:0}.vbar-value{font-size:.7rem;color:var(--text-tertiary);margin-bottom:4px}.vbar-track{width:28px;height:120px;background:var(--bg-tertiary);border-radius:4px 4px 0 0;display:flex;align-items:flex-end;overflow:hidden}.vbar-fill{width:100%;background:var(--accent-blue);border-radius:4px 4px 0 0;transition:height .3s ease;min-height:2px}.vbar-label{font-size:.65rem;color:var(--text-tertiary);margin-top:4px;white-space:nowrap}.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);max-width:130px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sessions-table .td-task{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.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-stat__value--error{color:var(--color-failed)}.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}}.convoy-selector{display:flex;align-items:center;gap:.5rem}.convoy-selector__label{font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary)}.convoy-selector__select{appearance:none;background:var(--bg-tertiary);border:1px solid rgba(255,255,255,.08);border-radius:6px;color:var(--text-primary);font-size:.8125rem;padding:.375rem 2rem .375rem .75rem;cursor:pointer;max-width:320px;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='%238a8a9a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right .75rem center;transition:border-color .15s}.convoy-selector__select:hover{border-color:#ffffff26}.convoy-selector__select:focus{outline:2px solid var(--accent-purple);outline-offset:2px}.overall-stats{margin-bottom:0;padding:1.25rem;background:var(--bg-secondary);border-radius:12px;border:1px solid rgba(255,255,255,.06)}.overall-stats__header{display:flex;align-items:center;gap:.5rem;margin-bottom:1rem}.overall-stats__title{font-size:1rem;font-weight:600;color:var(--text-primary);margin:0}.overall-stats__grid{display:grid;grid-template-columns:repeat(4,1fr);gap:.75rem}.overall-kpi{display:flex;flex-direction:column;gap:.25rem;padding:.75rem;background:var(--bg-tertiary);border-radius:8px;border:1px solid rgba(255,255,255,.04);transition:border-color .15s}.overall-kpi:hover{border-color:#ffffff1a}.overall-kpi__label{font-size:.6875rem;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary);display:flex;align-items:center;gap:.25rem}.overall-kpi__value{font-size:1.375rem;font-weight:700;color:var(--text-primary);font-variant-numeric:tabular-nums}.convoy-detail-header{padding:1.25rem;background:var(--bg-secondary);border-radius:12px;border:1px solid rgba(255,255,255,.06)}.convoy-detail-header__top{display:flex;align-items:center;gap:.75rem;margin-bottom:.75rem}.convoy-detail-header__name{font-size:1.25rem;font-weight:700;color:var(--text-primary);margin:0}.convoy-detail-header__meta{display:flex;flex-wrap:wrap;gap:1rem}.convoy-meta__item{font-size:.8125rem;color:var(--text-secondary)}.status-badge{display:inline-flex;align-items:center;padding:.125rem .625rem;border-radius:999px;font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em}.status-badge--done{background:#22c55e26;color:var(--color-success)}.status-badge--running{background:#3b82f626;color:var(--accent-blue)}.status-badge--failed{background:#ef444426;color:var(--color-failed)}.status-badge--gate-failed,.status-badge--gate_failed{background:#f59e0b26;color:var(--color-partial)}.tooltip-trigger{position:relative;cursor:help;font-size:.75rem;opacity:.5;transition:opacity .15s}.tooltip-trigger:hover{opacity:1}.tooltip-trigger:hover:after{content:attr(data-tooltip);position:absolute;bottom:100%;left:50%;transform:translate(-50%);padding:.5rem .875rem;background:var(--bg-primary);border:1px solid rgba(255,255,255,.12);border-radius:6px;font-size:.8125rem;color:var(--text-primary);max-width:420px;min-width:180px;white-space:normal;text-align:left;line-height:1.5;word-break:break-word;z-index:100;pointer-events:none;box-shadow:0 4px 12px #0006;text-transform:none}.tooltip-trigger:focus{opacity:1;outline:2px solid var(--accent-blue);outline-offset:2px;border-radius:2px}.tooltip-trigger:focus:after,.tooltip-trigger:focus-visible:after{content:attr(data-tooltip);position:absolute;bottom:100%;left:50%;transform:translate(-50%);padding:.5rem .875rem;background:var(--bg-primary);border:1px solid rgba(255,255,255,.12);border-radius:6px;font-size:.8125rem;color:var(--text-primary);max-width:420px;min-width:180px;white-space:normal;text-align:left;line-height:1.5;word-break:break-word;z-index:100;pointer-events:none;box-shadow:0 4px 12px #0006;text-transform:none}.status-badge--pending{background:#64748b26;color:#94a3b8}.status-badge--assigned{background:#3b82f61a;color:#60a5fa}.status-badge--timed-out{background:#ef44441f;color:#f87171}.status-badge--review-blocked{background:#f59e0b1f;color:#fbbf24}.status-badge--skipped{background:#64748b1a;color:#64748b}.status-badge--hook-failed{background:#ef44441a;color:#f87171}.status-badge--disputed{background:#a78bfa26;color:var(--accent-purple)}.status-badge--wait-for-input{background:#f59e0b1a;color:var(--color-partial)}.task-summary-cards{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:20px}.task-summary-card{flex:1 1 140px;display:flex;flex-direction:column;gap:8px;padding:14px 16px;background:var(--bg-card);border:1px solid var(--border-color);border-radius:10px;transition:border-color .15s}.task-summary-card:hover{border-color:#ffffff1f}.task-summary-card__label{font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--text-tertiary)}.task-summary-card__value{font-size:1.75rem;font-weight:700;line-height:1;color:var(--text-primary)}.task-summary-card--done{border-left:3px solid var(--color-success)}.task-summary-card--running{border-left:3px solid var(--accent-blue)}.task-summary-card--errors{border-left:3px solid var(--color-failed)}.task-summary-card--waiting{border-left:3px solid #94a3b8}.task-summary-card--input{border-left:3px solid var(--color-partial)}.task-table-wrap{overflow-x:auto}.task-table .td-num{text-align:right}.sortable-th{cursor:pointer;user-select:none}.sortable-th:hover{color:var(--text-secondary)}.sortable-th--active{color:var(--text-primary)}.sort-indicator{margin-left:4px;font-size:.5625rem;opacity:.5}.sortable-th--active .sort-indicator{opacity:1;color:var(--accent-blue)}.phase-breakdown{display:flex;flex-direction:column;gap:8px;margin-bottom:20px}.phase-breakdown__row{display:flex;align-items:center;gap:12px}.phase-breakdown__label{font-size:.75rem;font-weight:600;color:var(--text-tertiary);min-width:60px}.phase-breakdown__bar{flex:1;height:10px;background:#ffffff0a;border-radius:5px;overflow:hidden;display:flex}.phase-breakdown__seg{height:100%;transition:width .3s ease}.phase-breakdown__seg--done{background:var(--color-success)}.phase-breakdown__seg--running{background:var(--accent-blue)}.phase-breakdown__seg--waiting{background:#475569}.phase-breakdown__seg--failed{background:var(--color-failed)}.phase-breakdown__count{font-size:.6875rem;color:var(--text-tertiary);min-width:52px;text-align:right}@media(max-width:960px){.overall-stats__grid{grid-template-columns:repeat(3,1fr)}}@media(max-width:640px){.overall-stats__grid{grid-template-columns:repeat(2,1fr)}.convoy-detail-header__name{font-size:1rem}.convoy-selector__select{max-width:200px}}@media(max-width:480px){.overall-stats__grid{grid-template-columns:1fr}}.reliability-empty{font-size:.875rem;color:var(--text-tertiary);padding:12px 0;margin:0}.secret-leak-banner{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;background:#f59e0b1a;border:1px solid rgba(245,158,11,.3);border-radius:8px;margin-top:16px}.secret-leak-banner__icon{font-size:1.25rem;flex-shrink:0;line-height:1.4}.secret-leak-banner__text{display:flex;flex-direction:column;gap:4px}.secret-leak-banner__text strong{font-size:.875rem;font-weight:600;color:var(--color-partial)}.secret-leak-banner__text span{font-size:.8125rem;color:var(--text-secondary)}.artifact-type-badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:.75rem;font-weight:600;color:#fff;text-transform:uppercase;letter-spacing:.03em}.timeline-filters{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:16px}.timeline-filter-chip{display:inline-flex;align-items:center;padding:6px 14px;border-radius:20px;border:1px solid var(--border);background:transparent;color:var(--text-secondary);font-size:.8125rem;font-weight:500;cursor:pointer;transition:all .15s ease}.timeline-filter-chip:hover{border-color:var(--accent);color:var(--text-primary)}.timeline-filter-chip--active{background:var(--accent);border-color:var(--accent);color:#fff}.event-timeline-row{padding:12px 16px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .15s ease}.event-timeline-row:hover{background:#a78bfa0d}.event-timeline-row--expanded{background:#a78bfa14}.event-timeline-row__main{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.event-timeline-ts{font-size:.8125rem;color:var(--text-secondary);min-width:140px;font-variant-numeric:tabular-nums}.event-type-badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:.6875rem;font-weight:600;color:#fff;text-transform:uppercase;letter-spacing:.03em}.event-timeline-context{font-size:.8125rem;color:var(--text-tertiary, #6b7280);font-family:var(--font-mono, "SF Mono", "Fira Code", monospace)}.event-timeline-detail{margin-top:8px;padding:12px;background:var(--bg-card, #111118);border-radius:6px;border:1px solid var(--border)}.event-timeline-json{font-size:.75rem;color:var(--text-secondary);white-space:pre-wrap;word-break:break-all;margin:0;font-family:var(--font-mono, "SF Mono", "Fira Code", monospace);max-height:300px;overflow-y:auto}@media(max-width:640px){.event-timeline-ts{min-width:auto;font-size:.75rem}.event-timeline-row__main{gap:8px}.timeline-filter-chip{padding:4px 10px;font-size:.75rem}}.dash-btn:focus-visible,.convoy-selector__select:focus-visible,.filter-select:focus-visible,.filter-input:focus-visible,.dash-sidebar__link:focus-visible,.timeline-filter-chip:focus-visible{outline:2px solid var(--accent-blue);outline-offset:2px}.convoy-status-explanation{font-size:.8125rem;color:var(--text-secondary);margin-top:.25rem;margin-bottom:.5rem;font-style:italic}.view-home,.view-convoy-detail{display:flex;flex-direction:column;gap:20px}[data-view-hidden]{display:none!important}.breadcrumbs{display:flex;align-items:center;gap:6px;font-size:.8125rem;color:var(--text-tertiary);flex-wrap:wrap;padding:0;margin-bottom:-8px}.breadcrumbs__link{color:var(--text-secondary);text-decoration:none;transition:color var(--transition-fast);border-bottom:1px solid transparent}.breadcrumbs__link:hover{color:var(--text-accent);border-bottom-color:#a78bfa66}.breadcrumbs__link:focus-visible{outline:2px solid var(--accent-blue);outline-offset:2px;border-radius:2px}.breadcrumbs__separator{color:var(--text-tertiary);opacity:.5;user-select:none;font-size:.75rem}.breadcrumbs__current{color:var(--text-accent);font-weight:500;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.convoy-list-section{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;transition:border-color var(--transition-fast)}.convoy-list-section:hover{border-color:#ffffff1a}.convoy-list-section__header{padding:20px 24px 12px;border-bottom:1px solid var(--border-color)}.convoy-list-section__header h2,.convoy-list-section__header .convoy-list-section__title{font-size:.9375rem;font-weight:600;color:var(--text-primary);margin:0}.convoy-list-section__desc{font-size:.75rem;color:var(--text-tertiary);margin-top:2px}.convoy-list-filters{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end;padding:14px 24px;background:#ffffff03;border-bottom:1px solid var(--border-color)}.convoy-list-filters__group{display:flex;flex-direction:column;gap:4px}.convoy-list-filters__group label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-list-filters__input,.convoy-list-filters__select,.convoy-list-filters__date{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;font-family:inherit;transition:border-color var(--transition-fast);color-scheme:dark}.convoy-list-filters__input:focus,.convoy-list-filters__select:focus,.convoy-list-filters__date:focus{border-color:var(--border-accent)}.convoy-list-filters__input{width:180px}.convoy-list-filters__date{width:150px}.convoy-list-filters__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}.convoy-list-filters__reset{height:34px;padding:0 14px;font-size:.75rem;font-weight:500;font-family:inherit;color:var(--text-secondary);background:#ffffff0f;border:none;border-radius:8px;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast);align-self:flex-end;white-space:nowrap}.convoy-list-filters__reset:hover{background:#ffffff1a;color:var(--text-primary)}.convoy-list-filters__reset:focus-visible{outline:2px solid var(--accent-blue);outline-offset:2px}.convoy-list-table{width:100%;border-collapse:collapse;font-size:.8125rem}.convoy-list-table thead{position:sticky;top:0}.convoy-list-table th{padding:10px 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);white-space:nowrap}.convoy-list-table td{padding:10px 16px;color:var(--text-secondary);border-bottom:1px solid rgba(255,255,255,.03);white-space:nowrap}.convoy-list-table tr{cursor:pointer;transition:background var(--transition-fast)}.convoy-list-table tbody tr:hover td{background:#a78bfa0d;color:var(--text-primary)}.convoy-list-table tbody tr:hover td:first-child{color:var(--text-accent)}.convoy-list-table .td-convoy-name{font-weight:600;color:var(--text-primary);max-width:240px;overflow:hidden;text-overflow:ellipsis}.convoy-list-pagination{display:flex;align-items:center;justify-content:center;gap:12px;padding:16px 0;margin-top:4px}.convoy-list-pagination__info{font-size:.8125rem;color:var(--text-secondary);min-width:100px;text-align:center}.convoy-list-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:48px 24px;text-align:center;color:var(--text-tertiary)}.convoy-list-empty__icon{font-size:2rem;opacity:.35}.convoy-list-empty__text{font-size:.875rem;color:var(--text-tertiary);max-width:300px;line-height:1.5}.convoy-detail-hero{display:flex;flex-direction:column;gap:12px;padding:24px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;position:relative}.convoy-detail-hero:before{content:"";position:absolute;top:0;left:0;right:0;height:2px;background:var(--gradient-accent);opacity:.6;pointer-events:none}.convoy-detail-hero__top{display:flex;align-items:center;gap:14px;flex-wrap:wrap;justify-content:space-between}.convoy-chain-toggle{cursor:pointer;user-select:none;font-size:.75rem;margin-right:6px;opacity:.6}.convoy-chain-row{background:#a78bfa0a}.convoy-chain-row td:first-child{font-weight:600}.convoy-chain-child td:first-child{padding-left:28px}.convoy-chain-child td:first-child:before{content:"└ ";opacity:.4}.convoy-detail-hero__title{font-size:1.5rem;font-weight:700;color:var(--text-primary);letter-spacing:-.02em;line-height:1.25;margin:0}.convoy-detail-hero__status{flex-shrink:0}.convoy-detail-hero__status .status-badge{padding:.25rem .875rem;font-size:.75rem;border-radius:8px}.convoy-detail-hero__meta{display:flex;flex-wrap:wrap;gap:20px;padding-top:4px;border-top:1px solid var(--border-color)}.convoy-detail-hero__meta-item{display:flex;flex-direction:column;gap:2px}.convoy-detail-hero__meta-label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-detail-hero__meta-value{font-size:.875rem;color:var(--text-secondary);font-variant-numeric:tabular-nums}.task-row--clickable{cursor:pointer;transition:background var(--transition-fast)}.task-row--clickable:hover td{background:#a78bfa0a}.task-row--clickable td:first-child{position:relative}.task-row--clickable td:first-child:before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:transparent;transition:background var(--transition-fast)}.task-row--clickable:hover td:first-child:before{background:var(--border-accent)}.task-detail-expand{background:var(--bg-tertiary);border-bottom:1px solid var(--border-color)}.task-detail-expand__inner{padding:16px 20px}.task-detail-expand__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px 24px}.task-detail-expand__field{display:flex;flex-direction:column;gap:3px}.task-detail-expand__label{font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-tertiary)}.task-detail-expand__value{font-size:.8125rem;color:var(--text-secondary);word-break:break-word;font-variant-numeric:tabular-nums}.task-detail-expand__value code{font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:.75rem;background:#ffffff0f;padding:1px 6px;border-radius:4px;color:var(--text-accent)}@media(max-width:768px){.convoy-list-filters{padding:12px 16px;gap:8px}.convoy-list-filters__input,.convoy-list-filters__select,.convoy-list-filters__date{width:100%;min-width:unset}.convoy-list-filters__group{flex:1 1 calc(50% - 4px)}.convoy-list-filters__reset{flex:1 1 100%;width:100%}.convoy-list-section__header{padding:16px 16px 12px}}@media(max-width:480px){.convoy-list-filters__group{flex:1 1 100%}.convoy-detail-hero__title{font-size:1.25rem}.convoy-detail-hero{padding:16px}.task-detail-expand__grid{grid-template-columns:1fr}.breadcrumbs__current{max-width:180px}}.waiting-banner{text-align:center;padding:3rem 2rem;margin-bottom:2rem;border-radius:var(--radius-lg, 12px);background:var(--bg-surface, #1e1e2e);border:1px solid var(--border-subtle, rgba(255,255,255,.06))}.waiting-banner__content{display:flex;flex-direction:column;align-items:center;gap:.75rem}.waiting-banner__spinner{width:32px;height:32px;border:3px solid var(--border-subtle, rgba(255,255,255,.1));border-top-color:var(--accent, #60a5fa);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.waiting-banner__title{font-size:1.25rem;font-weight:600;margin:0;color:var(--text-primary, #e2e8f0)}.waiting-banner__subtitle{font-size:.875rem;color:var(--text-muted, #94a3b8);margin:0}.pipeline-chain-nav{display:flex;align-items:center;gap:.5rem;padding:.5rem 0;margin-bottom:.5rem;flex-wrap:wrap}.pipeline-chain__label{font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted, #94a3b8);margin-right:.25rem}.pipeline-chain__item{display:inline-flex;align-items:center;gap:.375rem;padding:.25rem .625rem;font-size:.8125rem;border-radius:var(--radius-sm, 6px);border:1px solid var(--border-subtle, rgba(255,255,255,.06));background:var(--bg-surface, #1e1e2e);color:var(--text-secondary, #cbd5e1);cursor:pointer;transition:border-color .15s,background .15s}.pipeline-chain__item:hover{border-color:var(--border-hover, rgba(255,255,255,.15));background:var(--bg-hover, rgba(255,255,255,.04))}.pipeline-chain__item--active{border-color:var(--accent, #60a5fa);background:#60a5fa14;color:var(--text-primary, #e2e8f0)}.pipeline-chain__dot{display:inline-block;width:8px;height:8px;border-radius:50%;flex-shrink:0}.activity-timeline:not(.activity-timeline--vertical){display:flex;flex-direction:column;gap:4px}
@@ -4,76 +4,90 @@
4
4
  "name": "CI/CD Pipeline Setup",
5
5
  "status": "running",
6
6
  "created_at": "2026-03-11T08:00:00.000Z",
7
+ "started_at": "2026-03-11T08:00:00.000Z",
7
8
  "finished_at": null,
8
9
  "total_tokens": null,
9
10
  "total_cost_usd": null,
10
11
  "task_count": 3,
11
- "pipeline_id": null
12
+ "pipeline_id": null,
13
+ "pipeline_name": null
12
14
  },
13
15
  {
14
16
  "id": "demo-docs-update",
15
17
  "name": "Documentation Refresh",
16
18
  "status": "done",
17
19
  "created_at": "2026-02-28T15:00:00.000Z",
20
+ "started_at": "2026-02-28T15:00:00.000Z",
18
21
  "finished_at": "2026-02-28T15:22:00.000Z",
19
22
  "total_tokens": 14800,
20
- "total_cost_usd": 1.48,
23
+ "total_cost_usd": 0.0296,
21
24
  "task_count": 3,
22
- "pipeline_id": null
25
+ "pipeline_id": null,
26
+ "pipeline_name": null
23
27
  },
24
28
  {
25
29
  "id": "demo-data-pipeline",
26
30
  "name": "Analytics ETL Pipeline",
27
31
  "status": "done",
28
32
  "created_at": "2026-02-22T13:00:00.000Z",
33
+ "started_at": "2026-02-22T13:00:00.000Z",
29
34
  "finished_at": "2026-02-22T13:38:00.000Z",
30
35
  "total_tokens": 28900,
31
- "total_cost_usd": 2.89,
36
+ "total_cost_usd": 0.2312,
32
37
  "task_count": 4,
33
- "pipeline_id": null
38
+ "pipeline_id": null,
39
+ "pipeline_name": null
34
40
  },
35
41
  {
36
42
  "id": "demo-perf-opt",
37
43
  "name": "Frontend Performance Boost",
38
44
  "status": "done",
39
45
  "created_at": "2026-02-17T10:00:00.000Z",
46
+ "started_at": "2026-02-17T10:00:00.000Z",
40
47
  "finished_at": "2026-02-17T11:02:00.000Z",
41
48
  "total_tokens": 37200,
42
- "total_cost_usd": 3.72,
49
+ "total_cost_usd": 0.2976,
43
50
  "task_count": 5,
44
- "pipeline_id": null
51
+ "pipeline_id": null,
52
+ "pipeline_name": null
45
53
  },
46
54
  {
47
55
  "id": "demo-api-v2",
48
56
  "name": "REST API v2 Migration",
49
57
  "status": "gate_failed",
50
58
  "created_at": "2026-02-12T16:00:00.000Z",
59
+ "started_at": "2026-02-12T16:00:00.000Z",
51
60
  "finished_at": "2026-02-12T16:28:00.000Z",
52
61
  "total_tokens": 24600,
53
- "total_cost_usd": 2.46,
62
+ "total_cost_usd": 0.1968,
54
63
  "task_count": 3,
55
- "pipeline_id": null
64
+ "pipeline_id": null,
65
+ "pipeline_name": null
56
66
  },
57
67
  {
58
68
  "id": "demo-dashboard-ui",
59
69
  "name": "Observability Dashboard UI",
60
70
  "status": "done",
61
71
  "created_at": "2026-02-07T14:00:00.000Z",
72
+ "started_at": "2026-02-07T14:00:00.000Z",
62
73
  "finished_at": "2026-02-07T15:38:00.000Z",
63
74
  "total_tokens": 78400,
64
- "total_cost_usd": 7.84,
75
+ "total_cost_usd": 1.4993,
65
76
  "task_count": 7,
66
- "pipeline_id": "demo-pipeline-1"
77
+ "pipeline_id": "demo-pipeline-1",
78
+ "pipeline_name": "Auth & Dashboard Sprint"
67
79
  },
68
80
  {
69
81
  "id": "demo-auth-revamp",
70
82
  "name": "Auth System Revamp",
71
83
  "status": "done",
72
84
  "created_at": "2026-02-03T09:00:00.000Z",
85
+ "started_at": "2026-02-03T09:00:00.000Z",
73
86
  "finished_at": "2026-02-03T09:47:00.000Z",
74
87
  "total_tokens": 42850,
75
- "total_cost_usd": 4.28,
88
+ "total_cost_usd": 0.5696,
76
89
  "task_count": 5,
77
- "pipeline_id": "demo-pipeline-1"
90
+ "pipeline_id": "demo-pipeline-1",
91
+ "pipeline_name": "Auth & Dashboard Sprint"
78
92
  }
79
93
  ]
@@ -7,7 +7,7 @@
7
7
  "finished_at": "2026-02-12T16:28:00.000Z",
8
8
  "branch": "feat/api-v2",
9
9
  "total_tokens": 24600,
10
- "total_cost_usd": 2.46
10
+ "total_cost_usd": 0.1968
11
11
  },
12
12
  "taskSummary": {
13
13
  "total": 3,
@@ -51,21 +51,21 @@
51
51
  "name": "docs/api-v2-contract.json",
52
52
  "type": "json",
53
53
  "task_id": "api-t1",
54
- "created_at": "2026-03-12T22:26:01.388Z"
54
+ "created_at": "2026-03-18T01:18:30.528Z"
55
55
  },
56
56
  {
57
57
  "id": "artifact-demo-api-v2-reports-security-gate-failure-md",
58
58
  "name": "reports/security-gate-failure.md",
59
59
  "type": "summary",
60
60
  "task_id": "api-t3",
61
- "created_at": "2026-03-12T22:26:01.388Z"
61
+ "created_at": "2026-03-18T01:18:30.528Z"
62
62
  },
63
63
  {
64
64
  "id": "artifact-demo-api-v2-src-api-rate-limiter-ts",
65
65
  "name": "src/api/rate-limiter.ts",
66
66
  "type": "file",
67
67
  "task_id": "api-t2",
68
- "created_at": "2026-03-12T22:26:01.388Z"
68
+ "created_at": "2026-03-18T01:18:30.528Z"
69
69
  }
70
70
  ],
71
71
  "has_more_events": false,
@@ -81,7 +81,9 @@
81
81
  {
82
82
  "type": "task_started",
83
83
  "task_id": "api-t3",
84
- "data": {"mechanism": "sub-agent"},
84
+ "data": {
85
+ "mechanism": "sub-agent"
86
+ },
85
87
  "created_at": "2026-02-12T16:24:00.000Z"
86
88
  },
87
89
  {
@@ -93,7 +95,9 @@
93
95
  {
94
96
  "type": "task_started",
95
97
  "task_id": "api-t2",
96
- "data": {"mechanism": "background"},
98
+ "data": {
99
+ "mechanism": "background"
100
+ },
97
101
  "created_at": "2026-02-12T16:12:00.000Z"
98
102
  },
99
103
  {
@@ -105,7 +109,9 @@
105
109
  {
106
110
  "type": "task_started",
107
111
  "task_id": "api-t1",
108
- "data": {"mechanism": "sub-agent"},
112
+ "data": {
113
+ "mechanism": "sub-agent"
114
+ },
109
115
  "created_at": "2026-02-12T16:00:05.000Z"
110
116
  }
111
117
  ],
@@ -120,7 +126,7 @@
120
126
  "started_at": "2026-02-12T16:00:05.000Z",
121
127
  "finished_at": "2026-02-12T16:11:00.000Z",
122
128
  "total_tokens": 7200,
123
- "cost_usd": 0.72,
129
+ "cost_usd": 0.03888,
124
130
  "review_level": null,
125
131
  "review_verdict": null,
126
132
  "review_tokens": null,
@@ -141,7 +147,7 @@
141
147
  "started_at": "2026-02-12T16:12:00.000Z",
142
148
  "finished_at": "2026-02-12T16:23:00.000Z",
143
149
  "total_tokens": 11400,
144
- "cost_usd": 1.14,
150
+ "cost_usd": 0.061560000000000004,
145
151
  "review_level": null,
146
152
  "review_verdict": null,
147
153
  "review_tokens": null,
@@ -162,7 +168,7 @@
162
168
  "started_at": "2026-02-12T16:24:00.000Z",
163
169
  "finished_at": "2026-02-12T16:27:00.000Z",
164
170
  "total_tokens": 6000,
165
- "cost_usd": 0.6,
171
+ "cost_usd": 0.0324,
166
172
  "review_level": "deep",
167
173
  "review_verdict": "block",
168
174
  "review_tokens": 2100,