loki-mode 9.53.0 → 9.54.2

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 (119) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/completion-council.sh +28 -5
  4. package/autonomy/council-v2.sh +13 -7
  5. package/autonomy/lib/done-recognition.sh +24 -16
  6. package/autonomy/lib/proof-check.sh +11 -3
  7. package/autonomy/lib/proof-generator.py +36 -5
  8. package/autonomy/lib/voter-agents.sh +8 -3
  9. package/autonomy/lib/workspace_diff.py +106 -12
  10. package/autonomy/prd-checklist.sh +19 -11
  11. package/autonomy/run.sh +503 -52
  12. package/dashboard/__init__.py +1 -1
  13. package/dashboard/api_v2.py +4 -0
  14. package/dashboard/audit.py +9 -1
  15. package/dashboard/auth.py +16 -4
  16. package/dashboard/registry.py +34 -12
  17. package/dashboard/rigour_integration.py +25 -17
  18. package/dashboard/server.py +252 -104
  19. package/dashboard/static/cost.html +55 -26
  20. package/dashboard/static/index.html +475 -1544
  21. package/dashboard/static/proofs.html +1 -1
  22. package/docs/INSTALLATION.md +1 -1
  23. package/docs/air-gapped.md +7 -2
  24. package/docs/image-provenance.md +4 -2
  25. package/docs/v10/BACKLOG.md +82 -2
  26. package/docs/v10/BOARD.md +105 -0
  27. package/docs/v10/DECISIONS.md +71 -0
  28. package/docs/v10/METRICS.md +2 -1
  29. package/docs/v10/PROGRESS.md +60 -0
  30. package/docs/v10/SWARM-PROMPT.md +98 -0
  31. package/docs/v10/SWARM.md +237 -0
  32. package/loki-ts/dist/loki.js +323 -322
  33. package/mcp/__init__.py +1 -1
  34. package/package.json +1 -1
  35. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  36. package/providers/aider.sh +8 -0
  37. package/providers/cline.sh +8 -0
  38. package/providers/codex.sh +9 -0
  39. package/providers/opencode.sh +9 -0
  40. package/web-app/dist/assets/AdminPage-CZrBkzRF.js +32 -0
  41. package/web-app/dist/assets/Avatar-gQIp6FBI.js +11 -0
  42. package/web-app/dist/assets/{Badge-BF3mhT57.js → Badge-D2_fBTFY.js} +1 -1
  43. package/web-app/dist/assets/{Button-BDp9aJ9q.js → Button-D5qDd2ef.js} +1 -1
  44. package/web-app/dist/assets/CockpitPage-DVMk2RUK.js +47 -0
  45. package/web-app/dist/assets/ComparePage-NMLyE1xL.js +1 -0
  46. package/web-app/dist/assets/{ErrorBoundary-ut3wrUmu.js → ErrorBoundary-BRABI-BT.js} +1 -1
  47. package/web-app/dist/assets/EvidenceReceiptPanel-D2LNKqUx.js +1 -0
  48. package/web-app/dist/assets/GitHubIssuesPanel-BC5GzKUN.js +7 -0
  49. package/web-app/dist/assets/{GitHubPRsPanel-DurZgSaj.js → GitHubPRsPanel-BSlmoVTS.js} +3 -3
  50. package/web-app/dist/assets/HomePage-D_CDMoen.js +12 -0
  51. package/web-app/dist/assets/{LoginPage-HeRGJeZy.js → LoginPage-BBNA_N9t.js} +1 -1
  52. package/web-app/dist/assets/{MagicPage-CUKrqsZs.js → MagicPage-CnFRZCMx.js} +1 -1
  53. package/web-app/dist/assets/MetricsPage-CPfLMRlh.js +6 -0
  54. package/web-app/dist/assets/{NotFoundPage-BZDZ-B77.js → NotFoundPage-lA0XSGTz.js} +1 -1
  55. package/web-app/dist/assets/ProjectPage-CNAPbr9z.js +256 -0
  56. package/web-app/dist/assets/ProjectsPage-CMtm8goN.js +6 -0
  57. package/web-app/dist/assets/SettingsPage-BhIjVMYE.js +10 -0
  58. package/web-app/dist/assets/{ShowcasePage-BGS2jTGH.js → ShowcasePage-BndtGeYo.js} +1 -1
  59. package/web-app/dist/assets/SystemSettingsPage-euXI-KXE.js +1 -0
  60. package/web-app/dist/assets/TeamsPage-ClUKecun.js +11 -0
  61. package/web-app/dist/assets/TemplatesPage-BWHWVk0L.js +29 -0
  62. package/web-app/dist/assets/{TerminalOutput-togzv9Zl.js → TerminalOutput-Cv3N3Szf.js} +1 -1
  63. package/web-app/dist/assets/{activity-Dreyb_Kr.js → activity-dEhz-bXR.js} +1 -1
  64. package/web-app/dist/assets/{bell-DWH0drES.js → bell-B3XUMq1t.js} +1 -1
  65. package/web-app/dist/assets/{bot-78MoCuDl.js → bot-X-ssNlwR.js} +1 -1
  66. package/web-app/dist/assets/{check-ikfylPst.js → check-C_9Nx7kb.js} +1 -1
  67. package/web-app/dist/assets/{chevron-left-DXUqkd8J.js → chevron-left-tvNswo3A.js} +1 -1
  68. package/web-app/dist/assets/{circle-alert-Da74VO8P.js → circle-alert-CSB88nEs.js} +1 -1
  69. package/web-app/dist/assets/{clock-mlGCFq8l.js → clock-C8p2e4NI.js} +1 -1
  70. package/web-app/dist/assets/{cloud-B_Y5ZrIO.js → cloud-CKp2ZvhG.js} +1 -1
  71. package/web-app/dist/assets/{code-xml-Bbom7YWV.js → code-xml-dY70LCHD.js} +1 -1
  72. package/web-app/dist/assets/{database-CLcofiVp.js → database-DObn5fmn.js} +1 -1
  73. package/web-app/dist/assets/{dollar-sign-C5mkjXIM.js → dollar-sign-DSu6n3K3.js} +1 -1
  74. package/web-app/dist/assets/{file-code-corner-CVrkaOQP.js → file-code-corner-DpCnS73z.js} +1 -1
  75. package/web-app/dist/assets/{file-plus-BV9240gX.js → file-plus-D3IPKCf1.js} +1 -1
  76. package/web-app/dist/assets/{globe-aZ0Zso4I.js → globe-C9QXkgH_.js} +1 -1
  77. package/web-app/dist/assets/{hammer-EgOQNukG.js → hammer-D_FtWe1y.js} +1 -1
  78. package/web-app/dist/assets/index-CI54rara.css +1 -0
  79. package/web-app/dist/assets/{index-DvZ0Kk2x.js → index-Cz7q1bvC.js} +2 -2
  80. package/web-app/dist/assets/{layers-BOVKmepE.js → layers-DsW7jnJX.js} +1 -1
  81. package/web-app/dist/assets/{loader-circle-0K8yLgHl.js → loader-circle-B3HspjKR.js} +1 -1
  82. package/web-app/dist/assets/{lock-XzlDMy8M.js → lock-DSI29pct.js} +1 -1
  83. package/web-app/dist/assets/{package-BtXTKusI.js → package-CLNxtA2x.js} +1 -1
  84. package/web-app/dist/assets/{plus-PxeiD8ju.js → plus-DyI4WC4_.js} +1 -1
  85. package/web-app/dist/assets/{refresh-cw-CjqzYczt.js → refresh-cw-D2dv0xA0.js} +1 -1
  86. package/web-app/dist/assets/{rotate-ccw-CY0os4DH.js → rotate-ccw-CBvihA-a.js} +1 -1
  87. package/web-app/dist/assets/scroll-text-DvoOvAl_.js +6 -0
  88. package/web-app/dist/assets/{server-pIIs9vNp.js → server-DenWvSUt.js} +1 -1
  89. package/web-app/dist/assets/{shield-alert-CsDqKXwA.js → shield-alert-40cX_FvG.js} +1 -1
  90. package/web-app/dist/assets/{thumbs-up-CAh3HVzH.js → thumbs-up-BrjZ6QuV.js} +12 -7
  91. package/web-app/dist/assets/trash-2-C6evwkEH.js +16 -0
  92. package/web-app/dist/assets/{trending-down-DrtBd_C9.js → trending-down-CfbZis3O.js} +1 -1
  93. package/web-app/dist/assets/{trending-up-D-DbCHXm.js → trending-up-DWuEK3WC.js} +1 -1
  94. package/web-app/dist/assets/{upload-D4l6DCOt.js → upload-B9DFBcPG.js} +1 -1
  95. package/web-app/dist/assets/{usePolling-D0aoTX80.js → usePolling-BryVC-T1.js} +1 -1
  96. package/web-app/dist/assets/{user-BQf_XJO_.js → user-DMRXwZiw.js} +1 -1
  97. package/web-app/dist/index.html +2 -2
  98. package/web-app/server.py +122 -47
  99. package/web-app/dist/assets/AdminPage-y6_b2Xo4.js +0 -32
  100. package/web-app/dist/assets/Avatar-BFPkXhIJ.js +0 -6
  101. package/web-app/dist/assets/CockpitPage-5TKICCoA.js +0 -47
  102. package/web-app/dist/assets/ComparePage-BSuNsUHy.js +0 -1
  103. package/web-app/dist/assets/EvidenceReceiptPanel-CcaBwEI-.js +0 -1
  104. package/web-app/dist/assets/GitHubIssuesPanel-DJeYgzAa.js +0 -12
  105. package/web-app/dist/assets/HomePage-Bs451LAy.js +0 -28
  106. package/web-app/dist/assets/MetricsPage-DvY1csgz.js +0 -6
  107. package/web-app/dist/assets/ProjectPage-CqHkEZkl.js +0 -257
  108. package/web-app/dist/assets/ProjectsPage-CLvCK1Y8.js +0 -6
  109. package/web-app/dist/assets/SettingsPage-DP7OmdwP.js +0 -10
  110. package/web-app/dist/assets/SystemSettingsPage-P_rlLh0x.js +0 -1
  111. package/web-app/dist/assets/TeamsPage-DxtBDcBC.js +0 -11
  112. package/web-app/dist/assets/TemplatesPage-5e-faH3W.js +0 -29
  113. package/web-app/dist/assets/folder-open-D_6yV78G.js +0 -11
  114. package/web-app/dist/assets/index-BSgmPwC0.css +0 -1
  115. package/web-app/dist/assets/lightbulb-DdASgqOG.js +0 -6
  116. package/web-app/dist/assets/mail-COu670_W.js +0 -6
  117. package/web-app/dist/assets/minus-bQpUt9ff.js +0 -6
  118. package/web-app/dist/assets/save-v8qep5cY.js +0 -6
  119. package/web-app/dist/assets/trash-2-Dt6urTyY.js +0 -6
@@ -1358,14 +1358,16 @@
1358
1358
  <script>
1359
1359
  (function(){
1360
1360
  function loadEconomics(){
1361
- fetch('/api/memory/economics').then(function(r){ return r.json(); }).then(function(j){
1361
+ fetch('/api/memory/economics').then(function(r){ if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); }).then(function(j){
1362
1362
  var hr = document.getElementById('econ-hit-rate');
1363
1363
  var tt = document.getElementById('econ-total-tokens');
1364
1364
  var sv = document.getElementById('econ-savings');
1365
1365
  var top = document.getElementById('memory-economics-top');
1366
- if (hr) hr.textContent = ((j.hit_rate || 0) * 100).toFixed(1) + '%';
1367
- if (tt) tt.textContent = (j.total_tokens || 0).toLocaleString();
1368
- if (sv) sv.textContent = (j.savings_percent || 0).toFixed(1) + '%';
1366
+ // null means nothing was recorded: the tile keeps "--".
1367
+ function isNum(v){ return typeof v === 'number' && isFinite(v); }
1368
+ if (hr) hr.textContent = isNum(j.hit_rate) ? (j.hit_rate * 100).toFixed(1) + '%' : '--';
1369
+ if (tt) tt.textContent = isNum(j.total_tokens) ? j.total_tokens.toLocaleString() : '--';
1370
+ if (sv) sv.textContent = isNum(j.savings_percent) ? j.savings_percent.toFixed(1) + '%' : '--';
1369
1371
  if (top) {
1370
1372
  var patterns = j.top_patterns || [];
1371
1373
  // v7.7.21 council fix (Opus 1): build DOM with
@@ -1382,7 +1384,7 @@
1382
1384
  patterns.slice(0, 5).forEach(function(p){
1383
1385
  var row = document.createElement('div');
1384
1386
  // textContent escapes everything; no markup injection.
1385
- row.textContent = (p.access_count || 0) + 'x · ' +
1387
+ row.textContent = p.access_count + 'x · ' +
1386
1388
  (p.summary || p.id || '');
1387
1389
  top.appendChild(row);
1388
1390
  });
@@ -1855,24 +1857,24 @@
1855
1857
 
1856
1858
  <!-- Inlined JavaScript Bundle -->
1857
1859
  <script>
1858
- var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropertyDescriptor;var Dt=Object.getOwnPropertyNames;var Ht=Object.prototype.hasOwnProperty;var Mt=(d,e,t)=>e in d?Ie(d,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):d[e]=t;var Rt=(d,e)=>{for(var t in e)Ie(d,t,{get:e[t],enumerable:!0})},Pt=(d,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of Dt(e))!Ht.call(d,a)&&a!==t&&Ie(d,a,{get:()=>e[a],enumerable:!(i=zt(e,a))||i.enumerable});return d};var It=d=>Pt(Ie({},"__esModule",{value:!0}),d);var S=(d,e,t)=>Mt(d,typeof e!="symbol"?e+"":e,t);var vi={};Rt(vi,{ANIMATION:()=>P,ARIA_PATTERNS:()=>Ue,ApiEvents:()=>f,BASE_STYLES:()=>W,BREAKPOINTS:()=>Be,COMMON_STYLES:()=>ot,KEYBOARD_SHORTCUTS:()=>je,KeyboardHandler:()=>O,LokiActivityStream:()=>$e,LokiAgentLeaderboard:()=>Le,LokiAnalytics:()=>ve,LokiApiClient:()=>J,LokiApiKeys:()=>ye,LokiAppPreview:()=>ne,LokiAppStatus:()=>oe,LokiAuditViewer:()=>_e,LokiChecklistViewer:()=>re,LokiCheckpointViewer:()=>de,LokiContextTracker:()=>ce,LokiCostDashboard:()=>le,LokiCostWaterfall:()=>Te,LokiCouncilDashboard:()=>se,LokiCouncilTranscripts:()=>He,LokiElement:()=>v,LokiEscalations:()=>De,LokiFleet:()=>xe,LokiLearningDashboard:()=>ae,LokiLogStream:()=>te,LokiManagedMemoryPanel:()=>ze,LokiMascotPresence:()=>Pe,LokiMemoryBrowser:()=>ie,LokiMemoryGraph:()=>Ae,LokiMigrationDashboard:()=>me,LokiNotificationCenter:()=>pe,LokiOverview:()=>X,LokiPipelineView:()=>Ce,LokiPromptOptimizer:()=>he,LokiProviderHealth:()=>Ee,LokiQualityGates:()=>fe,LokiQualityScore:()=>ge,LokiRarvTimeline:()=>be,LokiRunManager:()=>ke,LokiSessionControl:()=>ee,LokiSessionDiff:()=>ue,LokiSpecPanel:()=>Re,LokiState:()=>Q,LokiTaskBoard:()=>Z,LokiTenantSwitcher:()=>we,LokiTheme:()=>U,LokiWikiBrowser:()=>Me,MARKDOWN_STYLES:()=>L,RADIUS:()=>R,SPACING:()=>z,STATE_CHANGE_EVENT:()=>Je,THEMES:()=>A,THEME_VARIABLES:()=>Oe,TYPOGRAPHY:()=>$,UnifiedThemeManager:()=>w,VERSION:()=>gi,Z_INDEX:()=>I,createApiClient:()=>dt,createStore:()=>ct,escapeHtml:()=>Ge,generateThemeCSS:()=>E,generateTokensCSS:()=>Y,getApiClient:()=>h,getState:()=>N,init:()=>mi,renderMarkdown:()=>C});var A={light:{"--loki-bg-primary":"#FFFEFB","--loki-bg-secondary":"#F8F4F0","--loki-bg-tertiary":"#ECEAE3","--loki-bg-card":"#ffffff","--loki-bg-hover":"#F3EFE9","--loki-bg-active":"#E6E2DA","--loki-bg-overlay":"rgba(32, 21, 21, 0.5)","--loki-accent":"#553DE9","--loki-accent-hover":"#4432c4","--loki-accent-active":"#3828a0","--loki-accent-light":"#553de9","--loki-accent-muted":"rgba(85, 61, 233, 0.10)","--loki-text-primary":"#201515","--loki-text-secondary":"#36342E","--loki-text-muted":"#939084","--loki-text-disabled":"#C5C0B1","--loki-text-inverse":"#ffffff","--loki-border":"#ECEAE3","--loki-border-light":"#C5C0B1","--loki-border-focus":"#553DE9","--loki-success":"#1FC5A8","--loki-success-muted":"rgba(31, 197, 168, 0.12)","--loki-warning":"#D4A03C","--loki-warning-muted":"rgba(212, 160, 60, 0.12)","--loki-error":"#C45B5B","--loki-error-muted":"rgba(196, 91, 91, 0.12)","--loki-info":"#2F71E3","--loki-info-muted":"rgba(47, 113, 227, 0.12)","--loki-green":"#1FC5A8","--loki-green-muted":"rgba(31, 197, 168, 0.12)","--loki-yellow":"#D4A03C","--loki-yellow-muted":"rgba(212, 160, 60, 0.12)","--loki-red":"#C45B5B","--loki-red-muted":"rgba(196, 91, 91, 0.12)","--loki-blue":"#2F71E3","--loki-blue-muted":"rgba(47, 113, 227, 0.12)","--loki-purple":"#553DE9","--loki-purple-muted":"rgba(85, 61, 233, 0.10)","--loki-opus":"#d97706","--loki-sonnet":"#553DE9","--loki-haiku":"#1FC5A8","--loki-shadow-sm":"0 1px 2px rgba(32, 21, 21, 0.04)","--loki-shadow-md":"0 4px 6px rgba(32, 21, 21, 0.06)","--loki-shadow-lg":"0 10px 15px rgba(32, 21, 21, 0.08)","--loki-shadow-focus":"0 0 0 3px rgba(85, 61, 233, 0.25)"},dark:{"--loki-bg-primary":"#1A0F2E","--loki-bg-secondary":"#140B24","--loki-bg-tertiary":"#251842","--loki-bg-card":"#1F1338","--loki-bg-hover":"#2A1F4A","--loki-bg-active":"#352A55","--loki-bg-overlay":"rgba(20, 11, 36, 0.85)","--loki-accent":"#553de9","--loki-accent-hover":"#9488F5","--loki-accent-active":"#6258D0","--loki-accent-light":"#9488F5","--loki-accent-muted":"rgba(123, 107, 240, 0.18)","--loki-text-primary":"#F0ECF8","--loki-text-secondary":"#C0B8D0","--loki-text-muted":"#8B7FA8","--loki-text-disabled":"#5A4E78","--loki-text-inverse":"#1A0F2E","--loki-border":"#2A1F3E","--loki-border-light":"#3D3060","--loki-border-focus":"#553de9","--loki-success":"#2ED8B6","--loki-success-muted":"rgba(46, 216, 182, 0.18)","--loki-warning":"#E8B84A","--loki-warning-muted":"rgba(232, 184, 74, 0.18)","--loki-error":"#E07070","--loki-error-muted":"rgba(224, 112, 112, 0.18)","--loki-info":"#5A9CF5","--loki-info-muted":"rgba(90, 156, 245, 0.18)","--loki-green":"#2ED8B6","--loki-green-muted":"rgba(46, 216, 182, 0.18)","--loki-yellow":"#E8B84A","--loki-yellow-muted":"rgba(232, 184, 74, 0.18)","--loki-red":"#E07070","--loki-red-muted":"rgba(224, 112, 112, 0.18)","--loki-blue":"#5A9CF5","--loki-blue-muted":"rgba(90, 156, 245, 0.18)","--loki-purple":"#9488F5","--loki-purple-muted":"rgba(148, 136, 245, 0.18)","--loki-opus":"#f59e0b","--loki-sonnet":"#553de9","--loki-haiku":"#2ED8B6","--loki-shadow-sm":"0 1px 2px rgba(0, 0, 0, 0.4)","--loki-shadow-md":"0 4px 12px rgba(0, 0, 0, 0.5)","--loki-shadow-lg":"0 10px 25px rgba(0, 0, 0, 0.6)","--loki-shadow-focus":"0 0 0 3px rgba(123, 107, 240, 0.30)"},"high-contrast":{"--loki-bg-primary":"#000000","--loki-bg-secondary":"#0a0a0a","--loki-bg-tertiary":"#141414","--loki-bg-card":"#0a0a0a","--loki-bg-hover":"#1a1a1a","--loki-bg-active":"#242424","--loki-bg-overlay":"rgba(0, 0, 0, 0.9)","--loki-accent":"#c084fc","--loki-accent-hover":"#d8b4fe","--loki-accent-active":"#e9d5ff","--loki-accent-light":"#d8b4fe","--loki-accent-muted":"rgba(192, 132, 252, 0.25)","--loki-text-primary":"#ffffff","--loki-text-secondary":"#e0e0e0","--loki-text-muted":"#b0b0b0","--loki-text-disabled":"#666666","--loki-text-inverse":"#000000","--loki-border":"#ffffff","--loki-border-light":"#cccccc","--loki-border-focus":"#c084fc","--loki-success":"#4ade80","--loki-success-muted":"rgba(74, 222, 128, 0.25)","--loki-warning":"#fde047","--loki-warning-muted":"rgba(253, 224, 71, 0.25)","--loki-error":"#f87171","--loki-error-muted":"rgba(248, 113, 113, 0.25)","--loki-info":"#60a5fa","--loki-info-muted":"rgba(96, 165, 250, 0.25)","--loki-green":"#4ade80","--loki-green-muted":"rgba(74, 222, 128, 0.25)","--loki-yellow":"#fde047","--loki-yellow-muted":"rgba(253, 224, 71, 0.25)","--loki-red":"#f87171","--loki-red-muted":"rgba(248, 113, 113, 0.25)","--loki-blue":"#60a5fa","--loki-blue-muted":"rgba(96, 165, 250, 0.25)","--loki-purple":"#c084fc","--loki-purple-muted":"rgba(192, 132, 252, 0.25)","--loki-opus":"#fbbf24","--loki-sonnet":"#818cf8","--loki-haiku":"#34d399","--loki-shadow-sm":"none","--loki-shadow-md":"none","--loki-shadow-lg":"none","--loki-shadow-focus":"0 0 0 3px #c084fc"},"vscode-light":{"--loki-bg-primary":"var(--vscode-editor-background, #ffffff)","--loki-bg-secondary":"var(--vscode-sideBar-background, #f3f3f3)","--loki-bg-tertiary":"var(--vscode-input-background, #ffffff)","--loki-bg-card":"var(--vscode-editor-background, #ffffff)","--loki-bg-hover":"var(--vscode-list-hoverBackground, #e8e8e8)","--loki-bg-active":"var(--vscode-list-activeSelectionBackground, #0060c0)","--loki-bg-overlay":"rgba(0, 0, 0, 0.4)","--loki-accent":"var(--vscode-focusBorder, #0066cc)","--loki-accent-hover":"var(--vscode-button-hoverBackground, #0055aa)","--loki-accent-active":"var(--vscode-button-background, #007acc)","--loki-accent-light":"var(--vscode-focusBorder, #0066cc)","--loki-accent-muted":"var(--vscode-editor-selectionBackground, rgba(0, 102, 204, 0.2))","--loki-text-primary":"var(--vscode-foreground, #333333)","--loki-text-secondary":"var(--vscode-descriptionForeground, #717171)","--loki-text-muted":"var(--vscode-disabledForeground, #a0a0a0)","--loki-text-disabled":"var(--vscode-disabledForeground, #cccccc)","--loki-text-inverse":"var(--vscode-button-foreground, #ffffff)","--loki-border":"var(--vscode-widget-border, #c8c8c8)","--loki-border-light":"var(--vscode-widget-border, #e0e0e0)","--loki-border-focus":"var(--vscode-focusBorder, #0066cc)","--loki-success":"var(--vscode-testing-iconPassed, #388a34)","--loki-success-muted":"rgba(56, 138, 52, 0.15)","--loki-warning":"var(--vscode-editorWarning-foreground, #bf8803)","--loki-warning-muted":"rgba(191, 136, 3, 0.15)","--loki-error":"var(--vscode-errorForeground, #e51400)","--loki-error-muted":"rgba(229, 20, 0, 0.15)","--loki-info":"var(--vscode-editorInfo-foreground, #1a85ff)","--loki-info-muted":"rgba(26, 133, 255, 0.15)","--loki-green":"var(--vscode-testing-iconPassed, #388a34)","--loki-green-muted":"rgba(56, 138, 52, 0.15)","--loki-yellow":"var(--vscode-editorWarning-foreground, #bf8803)","--loki-yellow-muted":"rgba(191, 136, 3, 0.15)","--loki-red":"var(--vscode-errorForeground, #e51400)","--loki-red-muted":"rgba(229, 20, 0, 0.15)","--loki-blue":"var(--vscode-editorInfo-foreground, #1a85ff)","--loki-blue-muted":"rgba(26, 133, 255, 0.15)","--loki-purple":"#9333ea","--loki-purple-muted":"rgba(147, 51, 234, 0.15)","--loki-opus":"#d97706","--loki-sonnet":"#4f46e5","--loki-haiku":"#059669","--loki-shadow-sm":"0 1px 2px rgba(0, 0, 0, 0.05)","--loki-shadow-md":"0 2px 4px rgba(0, 0, 0, 0.1)","--loki-shadow-lg":"0 4px 8px rgba(0, 0, 0, 0.15)","--loki-shadow-focus":"0 0 0 2px var(--vscode-focusBorder, #0066cc)"},"vscode-dark":{"--loki-bg-primary":"var(--vscode-editor-background, #1e1e1e)","--loki-bg-secondary":"var(--vscode-sideBar-background, #252526)","--loki-bg-tertiary":"var(--vscode-input-background, #3c3c3c)","--loki-bg-card":"var(--vscode-editor-background, #1e1e1e)","--loki-bg-hover":"var(--vscode-list-hoverBackground, #2a2d2e)","--loki-bg-active":"var(--vscode-list-activeSelectionBackground, #094771)","--loki-bg-overlay":"rgba(0, 0, 0, 0.6)","--loki-accent":"var(--vscode-focusBorder, #007fd4)","--loki-accent-hover":"var(--vscode-button-hoverBackground, #1177bb)","--loki-accent-active":"var(--vscode-button-background, #0e639c)","--loki-accent-light":"var(--vscode-focusBorder, #007fd4)","--loki-accent-muted":"var(--vscode-editor-selectionBackground, rgba(0, 127, 212, 0.25))","--loki-text-primary":"var(--vscode-foreground, #cccccc)","--loki-text-secondary":"var(--vscode-descriptionForeground, #9d9d9d)","--loki-text-muted":"var(--vscode-disabledForeground, #6b6b6b)","--loki-text-disabled":"var(--vscode-disabledForeground, #4d4d4d)","--loki-text-inverse":"var(--vscode-button-foreground, #ffffff)","--loki-border":"var(--vscode-widget-border, #454545)","--loki-border-light":"var(--vscode-widget-border, #5a5a5a)","--loki-border-focus":"var(--vscode-focusBorder, #007fd4)","--loki-success":"var(--vscode-testing-iconPassed, #89d185)","--loki-success-muted":"rgba(137, 209, 133, 0.2)","--loki-warning":"var(--vscode-editorWarning-foreground, #cca700)","--loki-warning-muted":"rgba(204, 167, 0, 0.2)","--loki-error":"var(--vscode-errorForeground, #f48771)","--loki-error-muted":"rgba(244, 135, 113, 0.2)","--loki-info":"var(--vscode-editorInfo-foreground, #75beff)","--loki-info-muted":"rgba(117, 190, 255, 0.2)","--loki-green":"var(--vscode-testing-iconPassed, #89d185)","--loki-green-muted":"rgba(137, 209, 133, 0.2)","--loki-yellow":"var(--vscode-editorWarning-foreground, #cca700)","--loki-yellow-muted":"rgba(204, 167, 0, 0.2)","--loki-red":"var(--vscode-errorForeground, #f48771)","--loki-red-muted":"rgba(244, 135, 113, 0.2)","--loki-blue":"var(--vscode-editorInfo-foreground, #75beff)","--loki-blue-muted":"rgba(117, 190, 255, 0.2)","--loki-purple":"#c084fc","--loki-purple-muted":"rgba(192, 132, 252, 0.2)","--loki-opus":"#f59e0b","--loki-sonnet":"#818cf8","--loki-haiku":"#34d399","--loki-shadow-sm":"0 1px 2px rgba(0, 0, 0, 0.3)","--loki-shadow-md":"0 2px 4px rgba(0, 0, 0, 0.4)","--loki-shadow-lg":"0 4px 8px rgba(0, 0, 0, 0.5)","--loki-shadow-focus":"0 0 0 2px var(--vscode-focusBorder, #007fd4)"}},z={xs:"4px",sm:"8px",md:"12px",lg:"16px",xl:"24px","2xl":"32px","3xl":"48px"},R={none:"0",sm:"2px",md:"4px",lg:"5px",xl:"5px",full:"9999px"},$={fontFamily:{sans:"'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif",serif:"'Fraunces', Georgia, 'Times New Roman', serif",mono:"'JetBrains Mono', 'Fira Code', 'SF Mono', Menlo, monospace"},fontSize:{xs:"10px",sm:"11px",base:"12px",md:"13px",lg:"14px",xl:"16px","2xl":"18px","3xl":"24px"},fontWeight:{normal:"400",medium:"500",semibold:"600",bold:"700"},lineHeight:{tight:"1.25",normal:"1.5",relaxed:"1.75"}},P={duration:{fast:"100ms",normal:"200ms",slow:"300ms",slower:"500ms"},easing:{default:"cubic-bezier(0.4, 0, 0.2, 1)",in:"cubic-bezier(0.4, 0, 1, 1)",out:"cubic-bezier(0, 0, 0.2, 1)",bounce:"cubic-bezier(0.68, -0.55, 0.265, 1.55)"}},Be={sm:"640px",md:"768px",lg:"1024px",xl:"1280px","2xl":"1536px"},I={base:"0",dropdown:"100",sticky:"200",modal:"300",popover:"400",tooltip:"500",toast:"600"},je={"navigation.nextItem":{key:"ArrowDown",modifiers:[]},"navigation.prevItem":{key:"ArrowUp",modifiers:[]},"navigation.nextSection":{key:"Tab",modifiers:[]},"navigation.prevSection":{key:"Tab",modifiers:["Shift"]},"navigation.confirm":{key:"Enter",modifiers:[]},"navigation.cancel":{key:"Escape",modifiers:[]},"action.refresh":{key:"r",modifiers:["Meta"]},"action.search":{key:"k",modifiers:["Meta"]},"action.save":{key:"s",modifiers:["Meta"]},"action.close":{key:"w",modifiers:["Meta"]},"theme.toggle":{key:"d",modifiers:["Meta","Shift"]},"task.create":{key:"n",modifiers:["Meta"]},"task.complete":{key:"Enter",modifiers:["Meta"]},"view.toggleLogs":{key:"l",modifiers:["Meta","Shift"]},"view.toggleMemory":{key:"m",modifiers:["Meta","Shift"]}},Ue={button:{role:"button",tabIndex:0},tablist:{role:"tablist"},tab:{role:"tab",ariaSelected:!1,tabIndex:-1},tabpanel:{role:"tabpanel",tabIndex:0},list:{role:"list"},listitem:{role:"listitem"},livePolite:{ariaLive:"polite",ariaAtomic:!0},liveAssertive:{ariaLive:"assertive",ariaAtomic:!0},dialog:{role:"dialog",ariaModal:!0},alertdialog:{role:"alertdialog",ariaModal:!0},status:{role:"status",ariaLive:"polite"},alert:{role:"alert",ariaLive:"assertive"},log:{role:"log",ariaLive:"polite",ariaRelevant:"additions"}};function E(d){let e=A[d];return e?Object.entries(e).map(([t,i])=>`${t}: ${i};`).join(`
1859
- `):""}function Y(){return`
1860
+ var LokiDashboard=(()=>{var Le=Object.defineProperty;var kt=Object.getOwnPropertyDescriptor;var xt=Object.getOwnPropertyNames;var _t=Object.prototype.hasOwnProperty;var yt=(d,e,t)=>e in d?Le(d,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):d[e]=t;var wt=(d,e)=>{for(var t in e)Le(d,t,{get:e[t],enumerable:!0})},$t=(d,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of xt(e))!_t.call(d,a)&&a!==t&&Le(d,a,{get:()=>e[a],enumerable:!(i=kt(e,a))||i.enumerable});return d};var Et=d=>$t(Le({},"__esModule",{value:!0}),d);var S=(d,e,t)=>yt(d,typeof e!="symbol"?e+"":e,t);var ri={};wt(ri,{ANIMATION:()=>I,ARIA_PATTERNS:()=>Me,ApiEvents:()=>f,BASE_STYLES:()=>Y,BREAKPOINTS:()=>ze,COMMON_STYLES:()=>Qe,KEYBOARD_SHORTCUTS:()=>He,KeyboardHandler:()=>O,LokiAnalytics:()=>me,LokiApiClient:()=>q,LokiApiKeys:()=>_e,LokiAppPreview:()=>oe,LokiAppStatus:()=>re,LokiAuditViewer:()=>xe,LokiChecklistViewer:()=>se,LokiCheckpointViewer:()=>le,LokiContextTracker:()=>de,LokiCostDashboard:()=>ne,LokiCostWaterfall:()=>we,LokiCouncilDashboard:()=>ae,LokiCouncilTranscripts:()=>Ce,LokiElement:()=>v,LokiEscalations:()=>Ee,LokiFleet:()=>ke,LokiLearningDashboard:()=>ie,LokiLogStream:()=>ee,LokiManagedMemoryPanel:()=>$e,LokiMascotPresence:()=>Te,LokiMemoryBrowser:()=>te,LokiMigrationDashboard:()=>ge,LokiNotificationCenter:()=>ce,LokiOverview:()=>Q,LokiPromptOptimizer:()=>ue,LokiQualityGates:()=>ve,LokiQualityScore:()=>he,LokiRarvTimeline:()=>fe,LokiRunManager:()=>be,LokiSessionControl:()=>Z,LokiSessionDiff:()=>pe,LokiSpecPanel:()=>Ae,LokiState:()=>W,LokiTaskBoard:()=>X,LokiTenantSwitcher:()=>ye,LokiTheme:()=>U,LokiWikiBrowser:()=>Se,MARKDOWN_STYLES:()=>z,RADIUS:()=>P,SPACING:()=>H,STATE_CHANGE_EVENT:()=>Ie,THEMES:()=>A,THEME_VARIABLES:()=>Re,TYPOGRAPHY:()=>$,UnifiedThemeManager:()=>w,VERSION:()=>ai,Z_INDEX:()=>B,createApiClient:()=>et,createStore:()=>tt,escapeHtml:()=>Be,generateThemeCSS:()=>E,generateTokensCSS:()=>K,getApiClient:()=>h,getState:()=>N,init:()=>si,renderMarkdown:()=>C});var A={light:{"--loki-bg-primary":"#FFFEFB","--loki-bg-secondary":"#F8F4F0","--loki-bg-tertiary":"#ECEAE3","--loki-bg-card":"#ffffff","--loki-bg-hover":"#F3EFE9","--loki-bg-active":"#E6E2DA","--loki-bg-overlay":"rgba(32, 21, 21, 0.5)","--loki-accent":"#553DE9","--loki-accent-hover":"#4432c4","--loki-accent-active":"#3828a0","--loki-accent-light":"#553de9","--loki-accent-muted":"rgba(85, 61, 233, 0.10)","--loki-text-primary":"#201515","--loki-text-secondary":"#36342E","--loki-text-muted":"#939084","--loki-text-disabled":"#C5C0B1","--loki-text-inverse":"#ffffff","--loki-border":"#ECEAE3","--loki-border-light":"#C5C0B1","--loki-border-focus":"#553DE9","--loki-success":"#1FC5A8","--loki-success-muted":"rgba(31, 197, 168, 0.12)","--loki-warning":"#D4A03C","--loki-warning-muted":"rgba(212, 160, 60, 0.12)","--loki-error":"#C45B5B","--loki-error-muted":"rgba(196, 91, 91, 0.12)","--loki-info":"#2F71E3","--loki-info-muted":"rgba(47, 113, 227, 0.12)","--loki-green":"#1FC5A8","--loki-green-muted":"rgba(31, 197, 168, 0.12)","--loki-yellow":"#D4A03C","--loki-yellow-muted":"rgba(212, 160, 60, 0.12)","--loki-red":"#C45B5B","--loki-red-muted":"rgba(196, 91, 91, 0.12)","--loki-blue":"#2F71E3","--loki-blue-muted":"rgba(47, 113, 227, 0.12)","--loki-purple":"#553DE9","--loki-purple-muted":"rgba(85, 61, 233, 0.10)","--loki-opus":"#d97706","--loki-sonnet":"#553DE9","--loki-haiku":"#1FC5A8","--loki-shadow-sm":"0 1px 2px rgba(32, 21, 21, 0.04)","--loki-shadow-md":"0 4px 6px rgba(32, 21, 21, 0.06)","--loki-shadow-lg":"0 10px 15px rgba(32, 21, 21, 0.08)","--loki-shadow-focus":"0 0 0 3px rgba(85, 61, 233, 0.25)"},dark:{"--loki-bg-primary":"#1A0F2E","--loki-bg-secondary":"#140B24","--loki-bg-tertiary":"#251842","--loki-bg-card":"#1F1338","--loki-bg-hover":"#2A1F4A","--loki-bg-active":"#352A55","--loki-bg-overlay":"rgba(20, 11, 36, 0.85)","--loki-accent":"#553de9","--loki-accent-hover":"#9488F5","--loki-accent-active":"#6258D0","--loki-accent-light":"#9488F5","--loki-accent-muted":"rgba(123, 107, 240, 0.18)","--loki-text-primary":"#F0ECF8","--loki-text-secondary":"#C0B8D0","--loki-text-muted":"#8B7FA8","--loki-text-disabled":"#5A4E78","--loki-text-inverse":"#1A0F2E","--loki-border":"#2A1F3E","--loki-border-light":"#3D3060","--loki-border-focus":"#553de9","--loki-success":"#2ED8B6","--loki-success-muted":"rgba(46, 216, 182, 0.18)","--loki-warning":"#E8B84A","--loki-warning-muted":"rgba(232, 184, 74, 0.18)","--loki-error":"#E07070","--loki-error-muted":"rgba(224, 112, 112, 0.18)","--loki-info":"#5A9CF5","--loki-info-muted":"rgba(90, 156, 245, 0.18)","--loki-green":"#2ED8B6","--loki-green-muted":"rgba(46, 216, 182, 0.18)","--loki-yellow":"#E8B84A","--loki-yellow-muted":"rgba(232, 184, 74, 0.18)","--loki-red":"#E07070","--loki-red-muted":"rgba(224, 112, 112, 0.18)","--loki-blue":"#5A9CF5","--loki-blue-muted":"rgba(90, 156, 245, 0.18)","--loki-purple":"#9488F5","--loki-purple-muted":"rgba(148, 136, 245, 0.18)","--loki-opus":"#f59e0b","--loki-sonnet":"#553de9","--loki-haiku":"#2ED8B6","--loki-shadow-sm":"0 1px 2px rgba(0, 0, 0, 0.4)","--loki-shadow-md":"0 4px 12px rgba(0, 0, 0, 0.5)","--loki-shadow-lg":"0 10px 25px rgba(0, 0, 0, 0.6)","--loki-shadow-focus":"0 0 0 3px rgba(123, 107, 240, 0.30)"},"high-contrast":{"--loki-bg-primary":"#000000","--loki-bg-secondary":"#0a0a0a","--loki-bg-tertiary":"#141414","--loki-bg-card":"#0a0a0a","--loki-bg-hover":"#1a1a1a","--loki-bg-active":"#242424","--loki-bg-overlay":"rgba(0, 0, 0, 0.9)","--loki-accent":"#c084fc","--loki-accent-hover":"#d8b4fe","--loki-accent-active":"#e9d5ff","--loki-accent-light":"#d8b4fe","--loki-accent-muted":"rgba(192, 132, 252, 0.25)","--loki-text-primary":"#ffffff","--loki-text-secondary":"#e0e0e0","--loki-text-muted":"#b0b0b0","--loki-text-disabled":"#666666","--loki-text-inverse":"#000000","--loki-border":"#ffffff","--loki-border-light":"#cccccc","--loki-border-focus":"#c084fc","--loki-success":"#4ade80","--loki-success-muted":"rgba(74, 222, 128, 0.25)","--loki-warning":"#fde047","--loki-warning-muted":"rgba(253, 224, 71, 0.25)","--loki-error":"#f87171","--loki-error-muted":"rgba(248, 113, 113, 0.25)","--loki-info":"#60a5fa","--loki-info-muted":"rgba(96, 165, 250, 0.25)","--loki-green":"#4ade80","--loki-green-muted":"rgba(74, 222, 128, 0.25)","--loki-yellow":"#fde047","--loki-yellow-muted":"rgba(253, 224, 71, 0.25)","--loki-red":"#f87171","--loki-red-muted":"rgba(248, 113, 113, 0.25)","--loki-blue":"#60a5fa","--loki-blue-muted":"rgba(96, 165, 250, 0.25)","--loki-purple":"#c084fc","--loki-purple-muted":"rgba(192, 132, 252, 0.25)","--loki-opus":"#fbbf24","--loki-sonnet":"#818cf8","--loki-haiku":"#34d399","--loki-shadow-sm":"none","--loki-shadow-md":"none","--loki-shadow-lg":"none","--loki-shadow-focus":"0 0 0 3px #c084fc"},"vscode-light":{"--loki-bg-primary":"var(--vscode-editor-background, #ffffff)","--loki-bg-secondary":"var(--vscode-sideBar-background, #f3f3f3)","--loki-bg-tertiary":"var(--vscode-input-background, #ffffff)","--loki-bg-card":"var(--vscode-editor-background, #ffffff)","--loki-bg-hover":"var(--vscode-list-hoverBackground, #e8e8e8)","--loki-bg-active":"var(--vscode-list-activeSelectionBackground, #0060c0)","--loki-bg-overlay":"rgba(0, 0, 0, 0.4)","--loki-accent":"var(--vscode-focusBorder, #0066cc)","--loki-accent-hover":"var(--vscode-button-hoverBackground, #0055aa)","--loki-accent-active":"var(--vscode-button-background, #007acc)","--loki-accent-light":"var(--vscode-focusBorder, #0066cc)","--loki-accent-muted":"var(--vscode-editor-selectionBackground, rgba(0, 102, 204, 0.2))","--loki-text-primary":"var(--vscode-foreground, #333333)","--loki-text-secondary":"var(--vscode-descriptionForeground, #717171)","--loki-text-muted":"var(--vscode-disabledForeground, #a0a0a0)","--loki-text-disabled":"var(--vscode-disabledForeground, #cccccc)","--loki-text-inverse":"var(--vscode-button-foreground, #ffffff)","--loki-border":"var(--vscode-widget-border, #c8c8c8)","--loki-border-light":"var(--vscode-widget-border, #e0e0e0)","--loki-border-focus":"var(--vscode-focusBorder, #0066cc)","--loki-success":"var(--vscode-testing-iconPassed, #388a34)","--loki-success-muted":"rgba(56, 138, 52, 0.15)","--loki-warning":"var(--vscode-editorWarning-foreground, #bf8803)","--loki-warning-muted":"rgba(191, 136, 3, 0.15)","--loki-error":"var(--vscode-errorForeground, #e51400)","--loki-error-muted":"rgba(229, 20, 0, 0.15)","--loki-info":"var(--vscode-editorInfo-foreground, #1a85ff)","--loki-info-muted":"rgba(26, 133, 255, 0.15)","--loki-green":"var(--vscode-testing-iconPassed, #388a34)","--loki-green-muted":"rgba(56, 138, 52, 0.15)","--loki-yellow":"var(--vscode-editorWarning-foreground, #bf8803)","--loki-yellow-muted":"rgba(191, 136, 3, 0.15)","--loki-red":"var(--vscode-errorForeground, #e51400)","--loki-red-muted":"rgba(229, 20, 0, 0.15)","--loki-blue":"var(--vscode-editorInfo-foreground, #1a85ff)","--loki-blue-muted":"rgba(26, 133, 255, 0.15)","--loki-purple":"#9333ea","--loki-purple-muted":"rgba(147, 51, 234, 0.15)","--loki-opus":"#d97706","--loki-sonnet":"#4f46e5","--loki-haiku":"#059669","--loki-shadow-sm":"0 1px 2px rgba(0, 0, 0, 0.05)","--loki-shadow-md":"0 2px 4px rgba(0, 0, 0, 0.1)","--loki-shadow-lg":"0 4px 8px rgba(0, 0, 0, 0.15)","--loki-shadow-focus":"0 0 0 2px var(--vscode-focusBorder, #0066cc)"},"vscode-dark":{"--loki-bg-primary":"var(--vscode-editor-background, #1e1e1e)","--loki-bg-secondary":"var(--vscode-sideBar-background, #252526)","--loki-bg-tertiary":"var(--vscode-input-background, #3c3c3c)","--loki-bg-card":"var(--vscode-editor-background, #1e1e1e)","--loki-bg-hover":"var(--vscode-list-hoverBackground, #2a2d2e)","--loki-bg-active":"var(--vscode-list-activeSelectionBackground, #094771)","--loki-bg-overlay":"rgba(0, 0, 0, 0.6)","--loki-accent":"var(--vscode-focusBorder, #007fd4)","--loki-accent-hover":"var(--vscode-button-hoverBackground, #1177bb)","--loki-accent-active":"var(--vscode-button-background, #0e639c)","--loki-accent-light":"var(--vscode-focusBorder, #007fd4)","--loki-accent-muted":"var(--vscode-editor-selectionBackground, rgba(0, 127, 212, 0.25))","--loki-text-primary":"var(--vscode-foreground, #cccccc)","--loki-text-secondary":"var(--vscode-descriptionForeground, #9d9d9d)","--loki-text-muted":"var(--vscode-disabledForeground, #6b6b6b)","--loki-text-disabled":"var(--vscode-disabledForeground, #4d4d4d)","--loki-text-inverse":"var(--vscode-button-foreground, #ffffff)","--loki-border":"var(--vscode-widget-border, #454545)","--loki-border-light":"var(--vscode-widget-border, #5a5a5a)","--loki-border-focus":"var(--vscode-focusBorder, #007fd4)","--loki-success":"var(--vscode-testing-iconPassed, #89d185)","--loki-success-muted":"rgba(137, 209, 133, 0.2)","--loki-warning":"var(--vscode-editorWarning-foreground, #cca700)","--loki-warning-muted":"rgba(204, 167, 0, 0.2)","--loki-error":"var(--vscode-errorForeground, #f48771)","--loki-error-muted":"rgba(244, 135, 113, 0.2)","--loki-info":"var(--vscode-editorInfo-foreground, #75beff)","--loki-info-muted":"rgba(117, 190, 255, 0.2)","--loki-green":"var(--vscode-testing-iconPassed, #89d185)","--loki-green-muted":"rgba(137, 209, 133, 0.2)","--loki-yellow":"var(--vscode-editorWarning-foreground, #cca700)","--loki-yellow-muted":"rgba(204, 167, 0, 0.2)","--loki-red":"var(--vscode-errorForeground, #f48771)","--loki-red-muted":"rgba(244, 135, 113, 0.2)","--loki-blue":"var(--vscode-editorInfo-foreground, #75beff)","--loki-blue-muted":"rgba(117, 190, 255, 0.2)","--loki-purple":"#c084fc","--loki-purple-muted":"rgba(192, 132, 252, 0.2)","--loki-opus":"#f59e0b","--loki-sonnet":"#818cf8","--loki-haiku":"#34d399","--loki-shadow-sm":"0 1px 2px rgba(0, 0, 0, 0.3)","--loki-shadow-md":"0 2px 4px rgba(0, 0, 0, 0.4)","--loki-shadow-lg":"0 4px 8px rgba(0, 0, 0, 0.5)","--loki-shadow-focus":"0 0 0 2px var(--vscode-focusBorder, #007fd4)"}},H={xs:"4px",sm:"8px",md:"12px",lg:"16px",xl:"24px","2xl":"32px","3xl":"48px"},P={none:"0",sm:"2px",md:"4px",lg:"5px",xl:"5px",full:"9999px"},$={fontFamily:{sans:"'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif",serif:"'Fraunces', Georgia, 'Times New Roman', serif",mono:"'JetBrains Mono', 'Fira Code', 'SF Mono', Menlo, monospace"},fontSize:{xs:"10px",sm:"11px",base:"12px",md:"13px",lg:"14px",xl:"16px","2xl":"18px","3xl":"24px"},fontWeight:{normal:"400",medium:"500",semibold:"600",bold:"700"},lineHeight:{tight:"1.25",normal:"1.5",relaxed:"1.75"}},I={duration:{fast:"100ms",normal:"200ms",slow:"300ms",slower:"500ms"},easing:{default:"cubic-bezier(0.4, 0, 0.2, 1)",in:"cubic-bezier(0.4, 0, 1, 1)",out:"cubic-bezier(0, 0, 0.2, 1)",bounce:"cubic-bezier(0.68, -0.55, 0.265, 1.55)"}},ze={sm:"640px",md:"768px",lg:"1024px",xl:"1280px","2xl":"1536px"},B={base:"0",dropdown:"100",sticky:"200",modal:"300",popover:"400",tooltip:"500",toast:"600"},He={"navigation.nextItem":{key:"ArrowDown",modifiers:[]},"navigation.prevItem":{key:"ArrowUp",modifiers:[]},"navigation.nextSection":{key:"Tab",modifiers:[]},"navigation.prevSection":{key:"Tab",modifiers:["Shift"]},"navigation.confirm":{key:"Enter",modifiers:[]},"navigation.cancel":{key:"Escape",modifiers:[]},"action.refresh":{key:"r",modifiers:["Meta"]},"action.search":{key:"k",modifiers:["Meta"]},"action.save":{key:"s",modifiers:["Meta"]},"action.close":{key:"w",modifiers:["Meta"]},"theme.toggle":{key:"d",modifiers:["Meta","Shift"]},"task.create":{key:"n",modifiers:["Meta"]},"task.complete":{key:"Enter",modifiers:["Meta"]},"view.toggleLogs":{key:"l",modifiers:["Meta","Shift"]},"view.toggleMemory":{key:"m",modifiers:["Meta","Shift"]}},Me={button:{role:"button",tabIndex:0},tablist:{role:"tablist"},tab:{role:"tab",ariaSelected:!1,tabIndex:-1},tabpanel:{role:"tabpanel",tabIndex:0},list:{role:"list"},listitem:{role:"listitem"},livePolite:{ariaLive:"polite",ariaAtomic:!0},liveAssertive:{ariaLive:"assertive",ariaAtomic:!0},dialog:{role:"dialog",ariaModal:!0},alertdialog:{role:"alertdialog",ariaModal:!0},status:{role:"status",ariaLive:"polite"},alert:{role:"alert",ariaLive:"assertive"},log:{role:"log",ariaLive:"polite",ariaRelevant:"additions"}};function E(d){let e=A[d];return e?Object.entries(e).map(([t,i])=>`${t}: ${i};`).join(`
1861
+ `):""}function K(){return`
1860
1862
  /* Spacing */
1861
- --loki-space-xs: ${z.xs};
1862
- --loki-space-sm: ${z.sm};
1863
- --loki-space-md: ${z.md};
1864
- --loki-space-lg: ${z.lg};
1865
- --loki-space-xl: ${z.xl};
1866
- --loki-space-2xl: ${z["2xl"]};
1867
- --loki-space-3xl: ${z["3xl"]};
1863
+ --loki-space-xs: ${H.xs};
1864
+ --loki-space-sm: ${H.sm};
1865
+ --loki-space-md: ${H.md};
1866
+ --loki-space-lg: ${H.lg};
1867
+ --loki-space-xl: ${H.xl};
1868
+ --loki-space-2xl: ${H["2xl"]};
1869
+ --loki-space-3xl: ${H["3xl"]};
1868
1870
 
1869
1871
  /* Border Radius */
1870
- --loki-radius-none: ${R.none};
1871
- --loki-radius-sm: ${R.sm};
1872
- --loki-radius-md: ${R.md};
1873
- --loki-radius-lg: ${R.lg};
1874
- --loki-radius-xl: ${R.xl};
1875
- --loki-radius-full: ${R.full};
1872
+ --loki-radius-none: ${P.none};
1873
+ --loki-radius-sm: ${P.sm};
1874
+ --loki-radius-md: ${P.md};
1875
+ --loki-radius-lg: ${P.lg};
1876
+ --loki-radius-xl: ${P.xl};
1877
+ --loki-radius-full: ${P.full};
1876
1878
 
1877
1879
  /* Typography */
1878
1880
  --loki-font-sans: ${$.fontFamily.sans};
@@ -1888,25 +1890,25 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
1888
1890
  --loki-text-3xl: ${$.fontSize["3xl"]};
1889
1891
 
1890
1892
  /* Animation */
1891
- --loki-duration-fast: ${P.duration.fast};
1892
- --loki-duration-normal: ${P.duration.normal};
1893
- --loki-duration-slow: ${P.duration.slow};
1894
- --loki-easing-default: ${P.easing.default};
1895
- --loki-transition: ${P.duration.normal} ${P.easing.default};
1893
+ --loki-duration-fast: ${I.duration.fast};
1894
+ --loki-duration-normal: ${I.duration.normal};
1895
+ --loki-duration-slow: ${I.duration.slow};
1896
+ --loki-easing-default: ${I.easing.default};
1897
+ --loki-transition: ${I.duration.normal} ${I.easing.default};
1896
1898
 
1897
1899
  /* Z-Index */
1898
- --loki-z-dropdown: ${I.dropdown};
1899
- --loki-z-sticky: ${I.sticky};
1900
- --loki-z-modal: ${I.modal};
1901
- --loki-z-popover: ${I.popover};
1902
- --loki-z-tooltip: ${I.tooltip};
1903
- --loki-z-toast: ${I.toast};
1900
+ --loki-z-dropdown: ${B.dropdown};
1901
+ --loki-z-sticky: ${B.sticky};
1902
+ --loki-z-modal: ${B.modal};
1903
+ --loki-z-popover: ${B.popover};
1904
+ --loki-z-tooltip: ${B.tooltip};
1905
+ --loki-z-toast: ${B.toast};
1904
1906
 
1905
1907
  /* Glass effect */
1906
1908
  --loki-glass-bg: rgba(255, 255, 255, 0.03);
1907
1909
  --loki-glass-border: rgba(255, 255, 255, 0.06);
1908
1910
  --loki-glass-blur: blur(12px);
1909
- `}var W=`
1911
+ `}var Y=`
1910
1912
  /* Reset and base */
1911
1913
  :host {
1912
1914
  font-family: var(--loki-font-sans);
@@ -2182,20 +2184,20 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
2182
2184
  }
2183
2185
 
2184
2186
  /* Responsive utilities */
2185
- @media (max-width: ${Be.md}) {
2187
+ @media (max-width: ${ze.md}) {
2186
2188
  .hide-mobile { display: none !important; }
2187
2189
  }
2188
2190
 
2189
- @media (min-width: ${Be.md}) {
2191
+ @media (min-width: ${ze.md}) {
2190
2192
  .hide-desktop { display: none !important; }
2191
2193
  }
2192
2194
  `,y=class y{static detectContext(){return typeof acquireVsCodeApi<"u"||document.body.classList.contains("vscode-body")||getComputedStyle(document.documentElement).getPropertyValue("--vscode-editor-background")?"vscode":document.documentElement.dataset.lokiContext==="cli"?"cli":"browser"}static detectVSCodeTheme(){let e=document.body;if(e.classList.contains("vscode-high-contrast"))return"high-contrast";if(e.classList.contains("vscode-dark"))return"dark";if(e.classList.contains("vscode-light"))return"light";let t=getComputedStyle(document.documentElement).getPropertyValue("--vscode-editor-background");if(t){let i=t.match(/\d+/g);if(i)return(parseInt(i[0])*299+parseInt(i[1])*587+parseInt(i[2])*114)/1e3>128?"light":"dark"}return null}static getTheme(){if(y.detectContext()==="vscode"){let t=y.detectVSCodeTheme();return t==="high-contrast"?"high-contrast":t==="dark"?"vscode-dark":"vscode-light"}return"light"}static setTheme(e){if(!A[e]){console.warn(`Unknown theme: ${e}`);return}localStorage.setItem(y.STORAGE_KEY,e),document.documentElement.setAttribute("data-loki-theme",e),window.dispatchEvent(new CustomEvent("loki-theme-change",{detail:{theme:e,context:y.detectContext()}}))}static toggle(){let e=y.getTheme();return e.startsWith("vscode")?e:(y.setTheme("light"),"light")}static getVariables(e=null){let t=e||y.getTheme();return A[t]||A.light}static generateCSS(e=null){let t=e||y.getTheme();return`
2193
2195
  :host {
2194
2196
  ${E(t)}
2195
- ${Y()}
2197
+ ${K()}
2196
2198
  }
2197
- ${W}
2198
- `}static init(){let e=y.getTheme();document.documentElement.setAttribute("data-loki-theme",e),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{localStorage.getItem(y.STORAGE_KEY)||y.setTheme(y.getTheme())}),y.detectContext()==="vscode"&&new MutationObserver(()=>{let i=y.getTheme();document.documentElement.setAttribute("data-loki-theme",i),window.dispatchEvent(new CustomEvent("loki-theme-change",{detail:{theme:i,context:"vscode"}}))}).observe(document.body,{attributes:!0,attributeFilter:["class"]})}};S(y,"STORAGE_KEY","loki-theme"),S(y,"CONTEXT_KEY","loki-context");var w=y,O=class{constructor(){this._handlers=new Map,this._enabled=!0}register(e,t){let i=je[e];if(!i){console.warn(`Unknown keyboard action: ${e}`);return}this._handlers.set(e,{shortcut:i,handler:t})}unregister(e){this._handlers.delete(e)}setEnabled(e){this._enabled=e}handleEvent(e){if(!this._enabled)return!1;for(let[t,{shortcut:i,handler:a}]of this._handlers)if(this._matchesShortcut(e,i))return e.preventDefault(),e.stopPropagation(),a(e),!0;return!1}_matchesShortcut(e,t){let i=e.key.toLowerCase(),a=t.modifiers||[];if(i!==t.key.toLowerCase())return!1;let s=a.includes("Ctrl")||a.includes("Meta"),r=a.includes("Shift"),o=a.includes("Alt"),n=(e.ctrlKey||e.metaKey)===s,l=e.shiftKey===r,c=e.altKey===o;return n&&l&&c}attach(e){this._boundHandler||(this._boundHandler=t=>this.handleEvent(t)),e.addEventListener("keydown",this._boundHandler)}detach(e){this._boundHandler&&e.removeEventListener("keydown",this._boundHandler)}},Fe="unknown";function q(d,e=t=>String(t)){if(d==null)return Fe;let t=typeof d=="number"?d:Number(d);return Number.isNaN(t)?Fe:e(t)}function B(d){return q(d,e=>e!==0&&Math.abs(e)<.01?e<0?">-$0.01":"<$0.01":(e<0?"-$":"$")+Math.abs(e).toFixed(2))}function Ne(d){return q(d,e=>{let t=Math.abs(e);return t>=1e6?(e/1e6).toFixed(2)+"M":t>=1e3?(e/1e3).toFixed(1)+"K":String(e)})}function st(d){return q(d,e=>Math.abs(e)<1e3?Math.round(e)+"ms":Math.abs(e)<6e4?(e/1e3).toFixed(1)+"s":Math.floor(e/6e4)+"m "+Math.round(e%6e4/1e3)+"s")}function rt(d,e=1){return q(d,t=>t.toFixed(e)+"%")}var Oe={light:{"--loki-bg-primary":"#FFFEFB","--loki-bg-secondary":"#F8F4F0","--loki-bg-tertiary":"#ECEAE3","--loki-bg-card":"#ffffff","--loki-bg-hover":"#F3EFE9","--loki-accent":"#553DE9","--loki-accent-light":"#553de9","--loki-accent-muted":"rgba(85, 61, 233, 0.10)","--loki-text-primary":"#201515","--loki-text-secondary":"#36342E","--loki-text-muted":"#939084","--loki-border":"#ECEAE3","--loki-border-light":"#C5C0B1","--loki-green":"#1FC5A8","--loki-green-muted":"rgba(31, 197, 168, 0.12)","--loki-yellow":"#D4A03C","--loki-yellow-muted":"rgba(212, 160, 60, 0.12)","--loki-red":"#C45B5B","--loki-red-muted":"rgba(196, 91, 91, 0.12)","--loki-blue":"#2F71E3","--loki-blue-muted":"rgba(47, 113, 227, 0.12)","--loki-purple":"#553DE9","--loki-purple-muted":"rgba(85, 61, 233, 0.10)","--loki-opus":"#d97706","--loki-sonnet":"#553DE9","--loki-haiku":"#1FC5A8","--loki-transition":"0.2s cubic-bezier(0.4, 0, 0.2, 1)"},dark:{"--loki-bg-primary":"#1A0F2E","--loki-bg-secondary":"#140B24","--loki-bg-tertiary":"#251842","--loki-bg-card":"#1F1338","--loki-bg-hover":"#2A1F4A","--loki-accent":"#553de9","--loki-accent-light":"#9488F5","--loki-accent-muted":"rgba(123, 107, 240, 0.18)","--loki-text-primary":"#F0ECF8","--loki-text-secondary":"#C0B8D0","--loki-text-muted":"#8B7FA8","--loki-border":"#2A1F3E","--loki-border-light":"#3D3060","--loki-green":"#2ED8B6","--loki-green-muted":"rgba(46, 216, 182, 0.18)","--loki-yellow":"#E8B84A","--loki-yellow-muted":"rgba(232, 184, 74, 0.18)","--loki-red":"#E07070","--loki-red-muted":"rgba(224, 112, 112, 0.18)","--loki-blue":"#5A9CF5","--loki-blue-muted":"rgba(90, 156, 245, 0.18)","--loki-purple":"#9488F5","--loki-purple-muted":"rgba(148, 136, 245, 0.18)","--loki-opus":"#f59e0b","--loki-sonnet":"#553de9","--loki-haiku":"#2ED8B6","--loki-transition":"0.2s cubic-bezier(0.4, 0, 0.2, 1)"}},ot=`
2199
+ ${Y}
2200
+ `}static init(){let e=y.getTheme();document.documentElement.setAttribute("data-loki-theme",e),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{localStorage.getItem(y.STORAGE_KEY)||y.setTheme(y.getTheme())}),y.detectContext()==="vscode"&&new MutationObserver(()=>{let i=y.getTheme();document.documentElement.setAttribute("data-loki-theme",i),window.dispatchEvent(new CustomEvent("loki-theme-change",{detail:{theme:i,context:"vscode"}}))}).observe(document.body,{attributes:!0,attributeFilter:["class"]})}};S(y,"STORAGE_KEY","loki-theme"),S(y,"CONTEXT_KEY","loki-context");var w=y,O=class{constructor(){this._handlers=new Map,this._enabled=!0}register(e,t){let i=He[e];if(!i){console.warn(`Unknown keyboard action: ${e}`);return}this._handlers.set(e,{shortcut:i,handler:t})}unregister(e){this._handlers.delete(e)}setEnabled(e){this._enabled=e}handleEvent(e){if(!this._enabled)return!1;for(let[t,{shortcut:i,handler:a}]of this._handlers)if(this._matchesShortcut(e,i))return e.preventDefault(),e.stopPropagation(),a(e),!0;return!1}_matchesShortcut(e,t){let i=e.key.toLowerCase(),a=t.modifiers||[];if(i!==t.key.toLowerCase())return!1;let s=a.includes("Ctrl")||a.includes("Meta"),r=a.includes("Shift"),o=a.includes("Alt"),n=(e.ctrlKey||e.metaKey)===s,l=e.shiftKey===r,c=e.altKey===o;return n&&l&&c}attach(e){this._boundHandler||(this._boundHandler=t=>this.handleEvent(t)),e.addEventListener("keydown",this._boundHandler)}detach(e){this._boundHandler&&e.removeEventListener("keydown",this._boundHandler)}},We="unknown";function Ue(d,e=t=>String(t)){if(d==null)return We;let t=typeof d=="number"?d:Number(d);return Number.isNaN(t)?We:e(t)}function T(d){return Ue(d,e=>e!==0&&Math.abs(e)<.01?e<0?">-$0.01":"<$0.01":(e<0?"-$":"$")+Math.abs(e).toFixed(2))}function De(d){return Ue(d,e=>{let t=Math.abs(e);return t>=1e6?(e/1e6).toFixed(2)+"M":t>=1e3?(e/1e3).toFixed(1)+"K":String(e)})}function Ne(d){return Ue(d,e=>Math.abs(e)<1e3?Math.round(e)+"ms":Math.abs(e)<6e4?(e/1e3).toFixed(1)+"s":Math.floor(e/6e4)+"m "+Math.round(e%6e4/1e3)+"s")}var Re={light:{"--loki-bg-primary":"#FFFEFB","--loki-bg-secondary":"#F8F4F0","--loki-bg-tertiary":"#ECEAE3","--loki-bg-card":"#ffffff","--loki-bg-hover":"#F3EFE9","--loki-accent":"#553DE9","--loki-accent-light":"#553de9","--loki-accent-muted":"rgba(85, 61, 233, 0.10)","--loki-text-primary":"#201515","--loki-text-secondary":"#36342E","--loki-text-muted":"#939084","--loki-border":"#ECEAE3","--loki-border-light":"#C5C0B1","--loki-green":"#1FC5A8","--loki-green-muted":"rgba(31, 197, 168, 0.12)","--loki-yellow":"#D4A03C","--loki-yellow-muted":"rgba(212, 160, 60, 0.12)","--loki-red":"#C45B5B","--loki-red-muted":"rgba(196, 91, 91, 0.12)","--loki-blue":"#2F71E3","--loki-blue-muted":"rgba(47, 113, 227, 0.12)","--loki-purple":"#553DE9","--loki-purple-muted":"rgba(85, 61, 233, 0.10)","--loki-opus":"#d97706","--loki-sonnet":"#553DE9","--loki-haiku":"#1FC5A8","--loki-transition":"0.2s cubic-bezier(0.4, 0, 0.2, 1)"},dark:{"--loki-bg-primary":"#1A0F2E","--loki-bg-secondary":"#140B24","--loki-bg-tertiary":"#251842","--loki-bg-card":"#1F1338","--loki-bg-hover":"#2A1F4A","--loki-accent":"#553de9","--loki-accent-light":"#9488F5","--loki-accent-muted":"rgba(123, 107, 240, 0.18)","--loki-text-primary":"#F0ECF8","--loki-text-secondary":"#C0B8D0","--loki-text-muted":"#8B7FA8","--loki-border":"#2A1F3E","--loki-border-light":"#3D3060","--loki-green":"#2ED8B6","--loki-green-muted":"rgba(46, 216, 182, 0.18)","--loki-yellow":"#E8B84A","--loki-yellow-muted":"rgba(232, 184, 74, 0.18)","--loki-red":"#E07070","--loki-red-muted":"rgba(224, 112, 112, 0.18)","--loki-blue":"#5A9CF5","--loki-blue-muted":"rgba(90, 156, 245, 0.18)","--loki-purple":"#9488F5","--loki-purple-muted":"rgba(148, 136, 245, 0.18)","--loki-opus":"#f59e0b","--loki-sonnet":"#553de9","--loki-haiku":"#2ED8B6","--loki-transition":"0.2s cubic-bezier(0.4, 0, 0.2, 1)"}},Qe=`
2199
2201
  :host {
2200
2202
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
2201
2203
  line-height: 1.5;
@@ -2291,11 +2293,11 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
2291
2293
  ::-webkit-scrollbar-track { background: var(--loki-bg-primary); }
2292
2294
  ::-webkit-scrollbar-thumb { background: var(--loki-border); border-radius: 3px; }
2293
2295
  ::-webkit-scrollbar-thumb:hover { background: var(--loki-border-light); }
2294
- `,j=class j{static getTheme(){return w.getTheme()}static setTheme(e){w.setTheme(e)}static toggle(){return w.toggle()}static getVariables(e=null){let t=e||j.getTheme();return A[t]||Oe[t]||Oe.light}static toCSSString(e=null){let t=e||j.getTheme();if(A[t])return E(t);let i=j.getVariables(t);return Object.entries(i).map(([a,s])=>`${a}: ${s};`).join(`
2295
- `)}static applyToElement(e,t=null){let i=j.getVariables(t);for(let[a,s]of Object.entries(i))e.style.setProperty(a,s)}static init(){w.init()}static detectContext(){return w.detectContext()}static getAvailableThemes(){return Object.keys(A)}};S(j,"STORAGE_KEY","loki-theme");var U=j,v=class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._theme=U.getTheme(),this._themeChangeHandler=this._onThemeChange.bind(this),this._keyboardHandler=new O}connectedCallback(){window.addEventListener("loki-theme-change",this._themeChangeHandler),this._applyTheme(),this._setupKeyboardHandling(),this.render()}disconnectedCallback(){window.removeEventListener("loki-theme-change",this._themeChangeHandler),this._keyboardHandler.detach(this)}_onThemeChange(e){this._theme=e.detail.theme,this._applyTheme(),this.onThemeChange&&this.onThemeChange(this._theme)}_applyTheme(){U.applyToElement(this.shadowRoot.host,this._theme),this.setAttribute("data-loki-theme",this._theme)}_setupKeyboardHandling(){this._keyboardHandler.attach(this)}registerShortcut(e,t){this._keyboardHandler.register(e,t)}getBaseStyles(){return`
2296
+ `,F=class F{static getTheme(){return w.getTheme()}static setTheme(e){w.setTheme(e)}static toggle(){return w.toggle()}static getVariables(e=null){let t=e||F.getTheme();return A[t]||Re[t]||Re.light}static toCSSString(e=null){let t=e||F.getTheme();if(A[t])return E(t);let i=F.getVariables(t);return Object.entries(i).map(([a,s])=>`${a}: ${s};`).join(`
2297
+ `)}static applyToElement(e,t=null){let i=F.getVariables(t);for(let[a,s]of Object.entries(i))e.style.setProperty(a,s)}static init(){w.init()}static detectContext(){return w.detectContext()}static getAvailableThemes(){return Object.keys(A)}};S(F,"STORAGE_KEY","loki-theme");var U=F,v=class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._theme=U.getTheme(),this._themeChangeHandler=this._onThemeChange.bind(this),this._keyboardHandler=new O}connectedCallback(){window.addEventListener("loki-theme-change",this._themeChangeHandler),this._applyTheme(),this._setupKeyboardHandling(),this.render()}disconnectedCallback(){window.removeEventListener("loki-theme-change",this._themeChangeHandler),this._keyboardHandler.detach(this)}_onThemeChange(e){this._theme=e.detail.theme,this._applyTheme(),this.onThemeChange&&this.onThemeChange(this._theme)}_applyTheme(){U.applyToElement(this.shadowRoot.host,this._theme),this.setAttribute("data-loki-theme",this._theme)}_setupKeyboardHandling(){this._keyboardHandler.attach(this)}registerShortcut(e,t){this._keyboardHandler.register(e,t)}getBaseStyles(){return`
2296
2298
  /* Design tokens */
2297
2299
  :host {
2298
- ${Y()}
2300
+ ${K()}
2299
2301
  }
2300
2302
 
2301
2303
  /* Light theme (default) */
@@ -2349,11 +2351,11 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
2349
2351
  }
2350
2352
  }
2351
2353
 
2352
- ${W}
2353
- `}getAriaPattern(e){return Ue[e]||{}}applyAriaPattern(e,t){let i=this.getAriaPattern(t);for(let[a,s]of Object.entries(i))if(a==="role")e.setAttribute("role",s);else{let r=a.replace(/([A-Z])/g,"-$1").toLowerCase();e.setAttribute(r,s)}}render(){}};var F={realtime:1e3,normal:2e3,background:5e3,offline:1e4},nt={vscode:F.normal,browser:F.realtime,cli:F.background},lt={baseUrl:typeof window<"u"?window.location.origin:"http://localhost:57374",wsUrl:typeof window<"u"?`${window.location.protocol==="https:"?"wss:":"ws:"}//${window.location.host}/ws`:"ws://localhost:57374/ws",pollInterval:2e3,timeout:1e4,retryAttempts:3,retryDelay:1e3},f={CONNECTED:"api:connected",DISCONNECTED:"api:disconnected",ERROR:"api:error",STATUS_UPDATE:"api:status-update",TASK_CREATED:"api:task-created",TASK_UPDATED:"api:task-updated",TASK_DELETED:"api:task-deleted",PROJECT_CREATED:"api:project-created",PROJECT_UPDATED:"api:project-updated",AGENT_UPDATE:"api:agent-update",LOG_MESSAGE:"api:log-message",MEMORY_UPDATE:"api:memory-update",CHECKLIST_UPDATE:"api:checklist-update"},D=class D extends EventTarget{static getInstance(e={}){let t=e.baseUrl||lt.baseUrl;return D._instances.has(t)||D._instances.set(t,new D(e)),D._instances.get(t)}static clearInstances(){D._instances.forEach(e=>e.disconnect()),D._instances.clear()}constructor(e={}){super(),this.config={...lt,...e},this._ws=null,this._connected=!1,this._intentionalClose=!1,this._pollInterval=null,this._reconnectTimeout=null,this._reconnectAttempts=0,this._maxReconnectAttempts=20,this._cache=new Map,this._cacheTimeout=5e3,this._vscodeApi=null,this._context=this._detectContext(),this._currentPollInterval=nt[this._context]||F.normal,this._visibilityChangeHandler=null,this._messageHandler=null,this._setupAdaptivePolling(),this._setupVSCodeBridge()}_detectContext(){return typeof acquireVsCodeApi<"u"?"vscode":typeof window<"u"&&window.location?"browser":"cli"}get context(){return this._context}static get POLL_INTERVALS(){return F}_setupAdaptivePolling(){typeof document>"u"||(this._visibilityChangeHandler=()=>{document.hidden?this._setPollInterval(F.background):this._setPollInterval(nt[this._context]||F.normal)},document.addEventListener("visibilitychange",this._visibilityChangeHandler))}_setPollInterval(e){this._currentPollInterval=e,this._pollInterval&&(this.stopPolling(),this.startPolling(null,e))}setPollMode(e){let t=F[e];t&&this._setPollInterval(t)}_setupVSCodeBridge(){if(!(typeof acquireVsCodeApi>"u")){try{this._vscodeApi=acquireVsCodeApi()}catch{console.warn("VS Code API already acquired or unavailable");return}this._messageHandler=e=>{let t=e.data;if(!(!t||!t.type))switch(t.type){case"updateStatus":this._emit(f.STATUS_UPDATE,t.data);break;case"updateTasks":this._emit(f.TASK_UPDATED,t.data);break;case"taskCreated":this._emit(f.TASK_CREATED,t.data);break;case"taskDeleted":this._emit(f.TASK_DELETED,t.data);break;case"projectCreated":this._emit(f.PROJECT_CREATED,t.data);break;case"projectUpdated":this._emit(f.PROJECT_UPDATED,t.data);break;case"agentUpdate":this._emit(f.AGENT_UPDATE,t.data);break;case"logMessage":this._emit(f.LOG_MESSAGE,t.data);break;case"memoryUpdate":this._emit(f.MEMORY_UPDATE,t.data);break;case"connected":this._connected=!0,this._emit(f.CONNECTED,t.data);break;case"disconnected":this._connected=!1,this._emit(f.DISCONNECTED,t.data);break;case"error":this._emit(f.ERROR,t.data);break;case"setPollMode":this.setPollMode(t.data.mode);break;default:this._emit(`api:${t.type}`,t.data)}},window.addEventListener("message",this._messageHandler)}}get isVSCode(){return this._context==="vscode"}postToVSCode(e,t={}){this._vscodeApi&&this._vscodeApi.postMessage({type:e,data:t})}requestRefresh(){this.postToVSCode("requestRefresh")}notifyVSCode(e,t={}){this.postToVSCode("userAction",{action:e,...t})}get baseUrl(){return this.config.baseUrl}set baseUrl(e){this.config.baseUrl=e,this.config.wsUrl=e.replace(/^http/,"ws")+"/ws"}get isConnected(){return this._connected}async connect(){if(this._intentionalClose=!1,!(this._ws&&this._ws.readyState===WebSocket.OPEN))return new Promise((e,t)=>{try{this._ws=new WebSocket(this.config.wsUrl),this._ws.onopen=()=>{this._connected=!0,this._reconnectAttempts=0,this._emit(f.CONNECTED),e()},this._ws.onclose=()=>{this._connected=!1,this._emit(f.DISCONNECTED),this._intentionalClose||this._scheduleReconnect()},this._ws.onerror=i=>{this._emit(f.ERROR,{error:i}),t(i)},this._ws.onmessage=i=>{try{let a=JSON.parse(i.data);this._handleMessage(a)}catch(a){console.error("Failed to parse WebSocket message:",a)}}}catch(i){t(i)}})}disconnect(){this._intentionalClose=!0,this._ws&&(this._ws.close(),this._ws=null),this._pollInterval&&(clearInterval(this._pollInterval),this._pollInterval=null),this._reconnectTimeout&&(clearTimeout(this._reconnectTimeout),this._reconnectTimeout=null),this._connected=!1,this._cleanupGlobalListeners()}_cleanupGlobalListeners(){this._visibilityChangeHandler&&typeof document<"u"&&(document.removeEventListener("visibilitychange",this._visibilityChangeHandler),this._visibilityChangeHandler=null),this._messageHandler&&typeof window<"u"&&(window.removeEventListener("message",this._messageHandler),this._messageHandler=null)}destroy(){this.disconnect()}_scheduleReconnect(){if(this._reconnectTimeout)return;if(this._reconnectAttempts>=this._maxReconnectAttempts){console.warn("WebSocket max reconnect attempts reached, giving up"),this._emit(f.ERROR,{error:"Max reconnect attempts reached"});return}let e=Math.min(this.config.retryDelay*Math.pow(2,this._reconnectAttempts),3e4);this._reconnectAttempts++,this._reconnectTimeout=setTimeout(()=>{this._reconnectTimeout=null,this.connect().catch(()=>{})},e)}_handleMessage(e){if(e.type==="ping"){this._ws&&this._ws.readyState===WebSocket.OPEN&&this._ws.send(JSON.stringify({type:"pong"}));return}let i={connected:f.CONNECTED,status_update:f.STATUS_UPDATE,task_created:f.TASK_CREATED,task_updated:f.TASK_UPDATED,task_deleted:f.TASK_DELETED,task_moved:f.TASK_UPDATED,project_created:f.PROJECT_CREATED,project_updated:f.PROJECT_UPDATED,agent_update:f.AGENT_UPDATE,log:f.LOG_MESSAGE}[e.type]||`api:${e.type}`;this._emit(i,e.data)}_emit(e,t={}){this.dispatchEvent(new CustomEvent(e,{detail:t}))}async _request(e,t={}){let i=`${this.config.baseUrl}${e}`,a=new AbortController,s=t&&typeof t.timeout=="number"?t.timeout:this.config.timeout,r=setTimeout(()=>a.abort(),s);try{let o=await fetch(i,{...t,signal:a.signal,credentials:"include",headers:{"Content-Type":"application/json",...t.headers}});if(clearTimeout(r),!o.ok){let n=await o.text().catch(()=>""),l=o.statusText||`HTTP ${o.status}`;if(n)try{let c=JSON.parse(n);l=c.detail||c.error||c.message||l}catch{l=n.length>200?n.slice(0,200)+"...":n}throw new Error(l)}return o.status===204?null:await o.json()}catch(o){throw clearTimeout(r),o.name==="AbortError"?new Error("Request timeout"):o}}async _get(e,t=!1){if(t&&this._cache.has(e)){let a=this._cache.get(e);if(Date.now()-a.timestamp<this._cacheTimeout)return a.data}let i=await this._request(e);return t&&this._cache.set(e,{data:i,timestamp:Date.now()}),i}async _post(e,t,i={}){return this._request(e,{method:"POST",body:JSON.stringify(t),...i})}async _put(e,t){return this._request(e,{method:"PUT",body:JSON.stringify(t)})}async _delete(e){return this._request(e,{method:"DELETE"})}async get(e){return this._get(e)}async getStatus(){return this._get("/api/status")}async healthCheck(){return this._get("/health")}async listProjects(e=null){let t=e?`?status=${e}`:"";return this._get(`/api/projects${t}`)}async getProject(e){return this._get(`/api/projects/${e}`)}async createProject(e){return this._post("/api/projects",e)}async updateProject(e,t){return this._put(`/api/projects/${e}`,t)}async deleteProject(e){return this._delete(`/api/projects/${e}`)}async listTasks(e={}){let t=new URLSearchParams;e.projectId&&t.append("project_id",e.projectId),e.status&&t.append("status",e.status),e.priority&&t.append("priority",e.priority);let i=t.toString()?`?${t}`:"";return this._get(`/api/tasks${i}`)}async getTask(e){return this._get(`/api/tasks/${e}`)}async createTask(e){return this._post("/api/tasks",e)}async updateTask(e,t){return this._put(`/api/tasks/${e}`,t)}async moveTask(e,t,i){return this._post(`/api/tasks/${e}/move`,{status:t,position:i})}async deleteTask(e){return this._delete(`/api/tasks/${e}`)}async getMemorySummary(){return this._get("/api/memory/summary",!0)}async getMemoryIndex(){return this._get("/api/memory/index",!0)}async getMemoryTimeline(){return this._get("/api/memory/timeline")}async listEpisodes(e={}){let t=new URLSearchParams(e).toString();return this._get(`/api/memory/episodes${t?"?"+t:""}`)}async getEpisode(e){return this._get(`/api/memory/episodes/${e}`)}async listPatterns(e={}){let t=new URLSearchParams(e).toString();return this._get(`/api/memory/patterns${t?"?"+t:""}`)}async getPattern(e){return this._get(`/api/memory/patterns/${e}`)}async listSkills(){return this._get("/api/memory/skills")}async getSkill(e){return this._get(`/api/memory/skills/${e}`)}async retrieveMemories(e,t=null,i=5){return this._post("/api/memory/retrieve",{query:e,taskType:t,topK:i},{timeout:3e4})}async consolidateMemory(e=24){return this._post("/api/memory/consolidate",{sinceHours:e},{timeout:12e4})}async getTokenEconomics(){return this._get("/api/memory/economics")}async searchMemory(e,t="all",i=20){let a=new URLSearchParams({q:e,collection:t,limit:String(i)});return this._get(`/api/memory/search?${a}`)}async getMemoryStats(){return this._get("/api/memory/stats",!0)}async listRegisteredProjects(e=!1){return this._get(`/api/registry/projects?include_inactive=${e}`)}async registerProject(e,t=null,i=null){return this._post("/api/registry/projects",{path:e,name:t,alias:i})}async discoverProjects(e=3){return this._get(`/api/registry/discover?max_depth=${e}`)}async syncRegistry(){return this._post("/api/registry/sync",{},{timeout:45e3})}async getCrossProjectTasks(e=null){let t=e?`?project_ids=${e.join(",")}`:"";return this._get(`/api/registry/tasks${t}`)}async getLearningMetrics(e={}){let t=new URLSearchParams;e.timeRange&&t.append("timeRange",e.timeRange),e.signalType&&t.append("signalType",e.signalType),e.source&&t.append("source",e.source);let i=t.toString()?`?${t}`:"";return this._get(`/api/learning/metrics${i}`)}async getLearningTrends(e={}){let t=new URLSearchParams;e.timeRange&&t.append("timeRange",e.timeRange),e.signalType&&t.append("signalType",e.signalType),e.source&&t.append("source",e.source);let i=t.toString()?`?${t}`:"";return this._get(`/api/learning/trends${i}`)}async getLearningSignals(e={}){let t=new URLSearchParams;e.timeRange&&t.append("timeRange",e.timeRange),e.signalType&&t.append("signalType",e.signalType),e.source&&t.append("source",e.source),e.limit&&t.append("limit",String(e.limit)),e.offset&&t.append("offset",String(e.offset));let i=t.toString()?`?${t}`:"";return this._get(`/api/learning/signals${i}`)}async getLatestAggregation(){return this._get("/api/learning/aggregation")}async triggerAggregation(e={}){return this._post("/api/learning/aggregate",e,{timeout:6e4})}async getAggregatedPreferences(e=20){return this._get(`/api/learning/preferences?limit=${e}`)}async getAggregatedErrors(e=20){return this._get(`/api/learning/errors?limit=${e}`)}async getAggregatedSuccessPatterns(e=20){return this._get(`/api/learning/success?limit=${e}`)}async getToolEfficiency(e=20){return this._get(`/api/learning/tools?limit=${e}`)}async getCost(){return this._get("/api/cost")}async getPricing(){return this._get("/api/pricing")}async getCouncilState(){return this._get("/api/council/state")}async getCouncilVerdicts(e=20){return this._get(`/api/council/verdicts?limit=${e}`)}async getCouncilConvergence(){return this._get("/api/council/convergence")}async getCouncilReport(){return this._get("/api/council/report")}async forceCouncilReview(){return this._post("/api/council/force-review",{})}async getContext(){return this._get("/api/context")}async getNotifications(e,t){let i=new URLSearchParams;e&&i.set("severity",e),t&&i.set("unread_only","true");let a=i.toString();return this._get("/api/notifications"+(a?"?"+a:""))}async getNotificationTriggers(){return this._get("/api/notifications/triggers")}async updateNotificationTriggers(e){return this._put("/api/notifications/triggers",{triggers:e})}async acknowledgeNotification(e){return this._post("/api/notifications/"+encodeURIComponent(e)+"/acknowledge",{})}async startSession(e,t={}){let i={provider:t.provider||"claude",parallel:!!t.parallel};return t.prdPath?i.prd_path=t.prdPath:i.prd_text=e||"",t.model&&(i.model=t.model),t.advisorModel&&(i.advisor_model=t.advisorModel),this._post("/api/control/start",i)}async pauseSession(){return this._post("/api/control/pause",{})}async resumeSession(){return this._post("/api/control/resume",{})}async stopSession(){return this._post("/api/control/stop",{})}async getSessionModel(){return this._get("/api/session/model")}async setSessionModel(e){return this._post("/api/session/model",{model:e||null})}async getLogs(e=100){return this._get(`/api/logs?lines=${e}`)}async getChecklist(){return this._get("/api/checklist")}async getChecklistSummary(){return this._get("/api/checklist/summary")}async getPrdObservations(){let e=await fetch(`${this.baseUrl}/api/prd-observations`,{credentials:"include"});if(!e.ok)throw new Error(`HTTP ${e.status}`);return e.text()}async getChecklistWaivers(){return this._get("/api/checklist/waivers")}async addChecklistWaiver(e,t,i="dashboard"){return this._post("/api/checklist/waivers",{item_id:e,reason:t,waived_by:i})}async removeChecklistWaiver(e){return this._delete(`/api/checklist/waivers/${encodeURIComponent(e)}`)}async getCouncilGate(){return this._get("/api/council/gate")}async getAppRunnerStatus(){return this._get("/api/app-runner/status")}async getAppRunnerLogs(e=100){return this._get(`/api/app-runner/logs?lines=${e}`)}async getAppRunnerErrors(e=50){return this._get(`/api/app-runner/errors?lines=${e}`)}async restartApp(){return this._post("/api/control/app-restart",{})}async stopApp(){return this._post("/api/control/app-stop",{})}async getPlaywrightResults(){return this._get("/api/playwright/results")}async getPlaywrightScreenshot(){return this._get("/api/playwright/screenshot")}startPolling(e,t=null){if(this._pollInterval)return;this._pollCallback=e;let i=async()=>{try{let s=await this.getStatus();this._connected=!0,this._pollCallback&&this._pollCallback(s),this._emit(f.STATUS_UPDATE,s),this._vscodeApi&&this.postToVSCode("pollSuccess",{timestamp:Date.now()})}catch(s){this._connected=!1,this._emit(f.ERROR,{error:s}),this._vscodeApi&&this.postToVSCode("pollError",{error:s.message})}};i();let a=t||this._currentPollInterval||this.config.pollInterval;this._pollInterval=setInterval(i,a)}stopPolling(){this._pollInterval&&(clearInterval(this._pollInterval),this._pollInterval=null)}};S(D,"_instances",new Map);var J=D;function dt(d={}){return new J(d)}function h(d={}){return J.getInstance(d)}var Je="loki-state-change",qe={ui:{theme:"light",sidebarCollapsed:!1,activeSection:"kanban",terminalAutoScroll:!0},session:{connected:!1,lastSync:null,mode:"offline",phase:null,iteration:null},localTasks:[],cache:{projects:[],tasks:[],agents:[],memory:null,lastFetch:null},preferences:{pollInterval:2e3,notifications:!0,soundEnabled:!1}},T=class T extends EventTarget{static getInstance(){return T._instance||(T._instance=new T),T._instance}constructor(){super(),this._state=this._loadState(),this._subscribers=new Map,this._batchUpdates=[],this._batchTimeout=null}_loadState(){try{let e=localStorage.getItem(T.STORAGE_KEY);if(e){let t=JSON.parse(e);return this._mergeState(qe,t)}}catch(e){console.warn("Failed to load state from localStorage:",e)}return{...qe}}_mergeState(e,t){let i={...e};for(let a of Object.keys(t))a in e&&typeof e[a]=="object"&&!Array.isArray(e[a])?i[a]=this._mergeState(e[a],t[a]):i[a]=t[a];return i}_saveState(){try{let e={ui:this._state.ui,localTasks:this._state.localTasks,preferences:this._state.preferences};localStorage.setItem(T.STORAGE_KEY,JSON.stringify(e))}catch(e){console.warn("Failed to save state to localStorage:",e)}}get(e=null){if(!e)return{...this._state};let t=e.split("."),i=this._state;for(let a of t){if(i==null)return;i=i[a]}return i}set(e,t,i=!0){let a=e.split("."),s=a.pop(),r=this._state;for(let n of a)n in r||(r[n]={}),r=r[n];let o=r[s];r[s]=t,i&&this._saveState(),this._notifyChange(e,t,o)}update(e,t=!0){let i=[];for(let[a,s]of Object.entries(e)){let r=this.get(a);this.set(a,s,!1),i.push({path:a,value:s,oldValue:r})}t&&this._saveState();for(let a of i)this._notifyChange(a.path,a.value,a.oldValue)}_notifyChange(e,t,i){this.dispatchEvent(new CustomEvent(Je,{detail:{path:e,value:t,oldValue:i}}));let a=this._subscribers.get(e)||[];for(let r of a)try{r(t,i,e)}catch(o){console.error("State subscriber error:",o)}let s=e.split(".");for(;s.length>1;){s.pop();let r=s.join("."),o=this._subscribers.get(r)||[];for(let n of o)try{n(this.get(r),null,r)}catch(l){console.error("State subscriber error:",l)}}}subscribe(e,t){return this._subscribers.has(e)||this._subscribers.set(e,[]),this._subscribers.get(e).push(t),()=>{let i=this._subscribers.get(e),a=i.indexOf(t);a>-1&&i.splice(a,1)}}reset(e=null){if(e){let t=e.split("."),i=qe;for(let a of t)i=i?.[a];this.set(e,i)}else this._state={...qe},this._saveState(),this.dispatchEvent(new CustomEvent(Je,{detail:{path:null,value:this._state,oldValue:null}}))}addLocalTask(e){let t=this.get("localTasks")||[],i={id:`local-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,createdAt:new Date().toISOString(),status:"pending",...e};return this.set("localTasks",[...t,i]),i}updateLocalTask(e,t){let i=this.get("localTasks")||[],a=i.findIndex(r=>r.id===e);if(a===-1)return null;let s={...i[a],...t,updatedAt:new Date().toISOString()};return i[a]=s,this.set("localTasks",[...i]),s}deleteLocalTask(e){let t=this.get("localTasks")||[];this.set("localTasks",t.filter(i=>i.id!==e))}moveLocalTask(e,t,i=null){let s=(this.get("localTasks")||[]).find(r=>r.id===e);return s?this.updateLocalTask(e,{status:t,position:i??s.position}):null}updateSession(e){this.update(Object.fromEntries(Object.entries(e).map(([t,i])=>[`session.${t}`,i])),!1)}updateCache(e){this.update({"cache.projects":e.projects??this.get("cache.projects"),"cache.tasks":e.tasks??this.get("cache.tasks"),"cache.agents":e.agents??this.get("cache.agents"),"cache.memory":e.memory??this.get("cache.memory"),"cache.lastFetch":new Date().toISOString()},!1)}getMergedTasks(){let e=this.get("cache.tasks")||[],i=(this.get("localTasks")||[]).map(a=>({...a,isLocal:!0}));return[...e,...i]}getTasksByStatus(e){return this.getMergedTasks().filter(t=>t.status===e)}};S(T,"STORAGE_KEY","loki-dashboard-state"),S(T,"_instance",null);var Q=T;function N(){return Q.getInstance()}function ct(d){let e=N();return{get:()=>e.get(d),set:t=>e.set(d,t),subscribe:t=>e.subscribe(d,t)}}function Ge(d){return String(d??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function C(d){if(d==null||d==="")return"";let e=String(d).replace(/\r\n/g,`
2354
- `),t=[];e=e.replace(/```[^\n]*\n([\s\S]*?)```/g,(u,m)=>{let g=t.length;return t.push(`<pre class="md-code"><code>${Ge(m.replace(/\n$/,""))}</code></pre>`),`\0CODEBLOCK${g}\0`});let i=Ge(e);i=i.replace(/`([^`\n]+)`/g,(u,m)=>`<code class="md-inline-code">${m}</code>`),i=i.replace(/\[([^\]\n]+)\]\(([^)\s]+)\)/g,(u,m,g)=>/^(https?:|mailto:|\/|#|\.)/.test(g)?`<a class="md-link" href="${g}" target="_blank" rel="noopener noreferrer">${m}</a>`:u);let a=i.split(`
2355
- `),s=[],r=[],o=[],n=()=>{r.length&&(s.push(`<p class="md-p">${r.join("<br>")}</p>`),r=[])},l=u=>{for(;o.length&&o[o.length-1].indent>=u;)s.push(`</${o.pop().tag}>`)},c=()=>{for(;o.length;)s.push(`</${o.pop().tag}>`)};for(let u of a){let m=u,g=m.trim(),x=g.match(/^CODEBLOCK(\d+)$/);if(x){n(),c(),s.push(t[Number(x[1])]);continue}if(g===""){n(),c();continue}let k=g.match(/^(#{1,6})\s+(.+)$/);if(k){n(),c();let M=Math.min(k[1].length+1,6);s.push(`<h${M} class="md-h${M}">${k[2]}</h${M}>`);continue}if(/^(-{3,}|\*{3,}|_{3,})$/.test(g)){n(),c(),s.push('<hr class="md-hr">');continue}let _=g.match(/^&gt;\s?(.*)$/);if(_){n(),c(),s.push(`<blockquote class="md-quote">${_[1]}</blockquote>`);continue}let H=m.match(/^(\s*)/)[1].replace(/\t/g," ").length,K=g.match(/^([-*+])\s+(.+)$/),V=g.match(/^(\d+)[.)]\s+(.+)$/);if(K||V){n();let M=V?"ol":"ul",Lt=K?K[2]:V[2];!o.length||H>o[o.length-1].indent?(s.push(`<${M} class="md-list">`),o.push({tag:M,indent:H})):(l(H+1),o.length||(s.push(`<${M} class="md-list">`),o.push({tag:M,indent:H}))),s.push(`<li>${Lt}</li>`);continue}c(),r.push(m.trim())}n(),c();let p=s.join(`
2356
- `);return p=p.replace(/\*\*([^*\n]+)\*\*/g,"<strong>$1</strong>"),p=p.replace(/__([^_\n]+)__/g,"<strong>$1</strong>"),p=p.replace(/(^|[^*])\*([^*\n]+)\*/g,"$1<em>$2</em>"),p}var L=`
2354
+ ${Y}
2355
+ `}getAriaPattern(e){return Me[e]||{}}applyAriaPattern(e,t){let i=this.getAriaPattern(t);for(let[a,s]of Object.entries(i))if(a==="role")e.setAttribute("role",s);else{let r=a.replace(/([A-Z])/g,"-$1").toLowerCase();e.setAttribute(r,s)}}render(){}};var j={realtime:1e3,normal:2e3,background:5e3,offline:1e4},Xe={vscode:j.normal,browser:j.realtime,cli:j.background},Ze={baseUrl:typeof window<"u"?window.location.origin:"http://localhost:57374",wsUrl:typeof window<"u"?`${window.location.protocol==="https:"?"wss:":"ws:"}//${window.location.host}/ws`:"ws://localhost:57374/ws",pollInterval:2e3,timeout:1e4,retryAttempts:3,retryDelay:1e3},f={CONNECTED:"api:connected",DISCONNECTED:"api:disconnected",ERROR:"api:error",STATUS_UPDATE:"api:status-update",TASK_CREATED:"api:task-created",TASK_UPDATED:"api:task-updated",TASK_DELETED:"api:task-deleted",PROJECT_CREATED:"api:project-created",PROJECT_UPDATED:"api:project-updated",AGENT_UPDATE:"api:agent-update",LOG_MESSAGE:"api:log-message",MEMORY_UPDATE:"api:memory-update",CHECKLIST_UPDATE:"api:checklist-update"},M=class M extends EventTarget{static getInstance(e={}){let t=e.baseUrl||Ze.baseUrl;return M._instances.has(t)||M._instances.set(t,new M(e)),M._instances.get(t)}static clearInstances(){M._instances.forEach(e=>e.disconnect()),M._instances.clear()}constructor(e={}){super(),this.config={...Ze,...e},this._ws=null,this._connected=!1,this._intentionalClose=!1,this._pollInterval=null,this._reconnectTimeout=null,this._reconnectAttempts=0,this._maxReconnectAttempts=20,this._cache=new Map,this._cacheTimeout=5e3,this._vscodeApi=null,this._context=this._detectContext(),this._currentPollInterval=Xe[this._context]||j.normal,this._visibilityChangeHandler=null,this._messageHandler=null,this._setupAdaptivePolling(),this._setupVSCodeBridge()}_detectContext(){return typeof acquireVsCodeApi<"u"?"vscode":typeof window<"u"&&window.location?"browser":"cli"}get context(){return this._context}static get POLL_INTERVALS(){return j}_setupAdaptivePolling(){typeof document>"u"||(this._visibilityChangeHandler=()=>{document.hidden?this._setPollInterval(j.background):this._setPollInterval(Xe[this._context]||j.normal)},document.addEventListener("visibilitychange",this._visibilityChangeHandler))}_setPollInterval(e){this._currentPollInterval=e,this._pollInterval&&(this.stopPolling(),this.startPolling(null,e))}setPollMode(e){let t=j[e];t&&this._setPollInterval(t)}_setupVSCodeBridge(){if(!(typeof acquireVsCodeApi>"u")){try{this._vscodeApi=acquireVsCodeApi()}catch{console.warn("VS Code API already acquired or unavailable");return}this._messageHandler=e=>{let t=e.data;if(!(!t||!t.type))switch(t.type){case"updateStatus":this._emit(f.STATUS_UPDATE,t.data);break;case"updateTasks":this._emit(f.TASK_UPDATED,t.data);break;case"taskCreated":this._emit(f.TASK_CREATED,t.data);break;case"taskDeleted":this._emit(f.TASK_DELETED,t.data);break;case"projectCreated":this._emit(f.PROJECT_CREATED,t.data);break;case"projectUpdated":this._emit(f.PROJECT_UPDATED,t.data);break;case"agentUpdate":this._emit(f.AGENT_UPDATE,t.data);break;case"logMessage":this._emit(f.LOG_MESSAGE,t.data);break;case"memoryUpdate":this._emit(f.MEMORY_UPDATE,t.data);break;case"connected":this._connected=!0,this._emit(f.CONNECTED,t.data);break;case"disconnected":this._connected=!1,this._emit(f.DISCONNECTED,t.data);break;case"error":this._emit(f.ERROR,t.data);break;case"setPollMode":this.setPollMode(t.data.mode);break;default:this._emit(`api:${t.type}`,t.data)}},window.addEventListener("message",this._messageHandler)}}get isVSCode(){return this._context==="vscode"}postToVSCode(e,t={}){this._vscodeApi&&this._vscodeApi.postMessage({type:e,data:t})}requestRefresh(){this.postToVSCode("requestRefresh")}notifyVSCode(e,t={}){this.postToVSCode("userAction",{action:e,...t})}get baseUrl(){return this.config.baseUrl}set baseUrl(e){this.config.baseUrl=e,this.config.wsUrl=e.replace(/^http/,"ws")+"/ws"}get isConnected(){return this._connected}async connect(){if(this._intentionalClose=!1,!(this._ws&&this._ws.readyState===WebSocket.OPEN))return new Promise((e,t)=>{try{this._ws=new WebSocket(this.config.wsUrl),this._ws.onopen=()=>{this._connected=!0,this._reconnectAttempts=0,this._emit(f.CONNECTED),e()},this._ws.onclose=()=>{this._connected=!1,this._emit(f.DISCONNECTED),this._intentionalClose||this._scheduleReconnect()},this._ws.onerror=i=>{this._emit(f.ERROR,{error:i}),t(i)},this._ws.onmessage=i=>{try{let a=JSON.parse(i.data);this._handleMessage(a)}catch(a){console.error("Failed to parse WebSocket message:",a)}}}catch(i){t(i)}})}disconnect(){this._intentionalClose=!0,this._ws&&(this._ws.close(),this._ws=null),this._pollInterval&&(clearInterval(this._pollInterval),this._pollInterval=null),this._reconnectTimeout&&(clearTimeout(this._reconnectTimeout),this._reconnectTimeout=null),this._connected=!1,this._cleanupGlobalListeners()}_cleanupGlobalListeners(){this._visibilityChangeHandler&&typeof document<"u"&&(document.removeEventListener("visibilitychange",this._visibilityChangeHandler),this._visibilityChangeHandler=null),this._messageHandler&&typeof window<"u"&&(window.removeEventListener("message",this._messageHandler),this._messageHandler=null)}destroy(){this.disconnect()}_scheduleReconnect(){if(this._reconnectTimeout)return;if(this._reconnectAttempts>=this._maxReconnectAttempts){console.warn("WebSocket max reconnect attempts reached, giving up"),this._emit(f.ERROR,{error:"Max reconnect attempts reached"});return}let e=Math.min(this.config.retryDelay*Math.pow(2,this._reconnectAttempts),3e4);this._reconnectAttempts++,this._reconnectTimeout=setTimeout(()=>{this._reconnectTimeout=null,this.connect().catch(()=>{})},e)}_handleMessage(e){if(e.type==="ping"){this._ws&&this._ws.readyState===WebSocket.OPEN&&this._ws.send(JSON.stringify({type:"pong"}));return}let i={connected:f.CONNECTED,status_update:f.STATUS_UPDATE,task_created:f.TASK_CREATED,task_updated:f.TASK_UPDATED,task_deleted:f.TASK_DELETED,task_moved:f.TASK_UPDATED,project_created:f.PROJECT_CREATED,project_updated:f.PROJECT_UPDATED,agent_update:f.AGENT_UPDATE,log:f.LOG_MESSAGE}[e.type]||`api:${e.type}`;this._emit(i,e.data)}_emit(e,t={}){this.dispatchEvent(new CustomEvent(e,{detail:t}))}async _request(e,t={}){let i=`${this.config.baseUrl}${e}`,a=new AbortController,s=t&&typeof t.timeout=="number"?t.timeout:this.config.timeout,r=setTimeout(()=>a.abort(),s);try{let o=await fetch(i,{...t,signal:a.signal,credentials:"include",headers:{"Content-Type":"application/json",...t.headers}});if(clearTimeout(r),!o.ok){let n=await o.text().catch(()=>""),l=o.statusText||`HTTP ${o.status}`;if(n)try{let c=JSON.parse(n);l=c.detail||c.error||c.message||l}catch{l=n.length>200?n.slice(0,200)+"...":n}throw new Error(l)}return o.status===204?null:await o.json()}catch(o){throw clearTimeout(r),o.name==="AbortError"?new Error("Request timeout"):o}}async _get(e,t=!1){if(t&&this._cache.has(e)){let a=this._cache.get(e);if(Date.now()-a.timestamp<this._cacheTimeout)return a.data}let i=await this._request(e);return t&&this._cache.set(e,{data:i,timestamp:Date.now()}),i}async _post(e,t,i={}){return this._request(e,{method:"POST",body:JSON.stringify(t),...i})}async _put(e,t){return this._request(e,{method:"PUT",body:JSON.stringify(t)})}async _delete(e){return this._request(e,{method:"DELETE"})}async get(e){return this._get(e)}async getStatus(){return this._get("/api/status")}async healthCheck(){return this._get("/health")}async listProjects(e=null){let t=e?`?status=${e}`:"";return this._get(`/api/projects${t}`)}async getProject(e){return this._get(`/api/projects/${e}`)}async createProject(e){return this._post("/api/projects",e)}async updateProject(e,t){return this._put(`/api/projects/${e}`,t)}async deleteProject(e){return this._delete(`/api/projects/${e}`)}async listTasks(e={}){let t=new URLSearchParams;e.projectId&&t.append("project_id",e.projectId),e.status&&t.append("status",e.status),e.priority&&t.append("priority",e.priority);let i=t.toString()?`?${t}`:"";return this._get(`/api/tasks${i}`)}async getTask(e){return this._get(`/api/tasks/${e}`)}async createTask(e){return this._post("/api/tasks",e)}async updateTask(e,t){return this._put(`/api/tasks/${e}`,t)}async moveTask(e,t,i){return this._post(`/api/tasks/${e}/move`,{status:t,position:i})}async deleteTask(e){return this._delete(`/api/tasks/${e}`)}async getMemorySummary(){return this._get("/api/memory/summary",!0)}async getMemoryIndex(){return this._get("/api/memory/index",!0)}async getMemoryTimeline(){return this._get("/api/memory/timeline")}async listEpisodes(e={}){let t=new URLSearchParams(e).toString();return this._get(`/api/memory/episodes${t?"?"+t:""}`)}async getEpisode(e){return this._get(`/api/memory/episodes/${e}`)}async listPatterns(e={}){let t=new URLSearchParams(e).toString();return this._get(`/api/memory/patterns${t?"?"+t:""}`)}async getPattern(e){return this._get(`/api/memory/patterns/${e}`)}async listSkills(){return this._get("/api/memory/skills")}async getSkill(e){return this._get(`/api/memory/skills/${e}`)}async retrieveMemories(e,t=null,i=5){return this._post("/api/memory/retrieve",{query:e,taskType:t,topK:i},{timeout:3e4})}async consolidateMemory(e=24){return this._post("/api/memory/consolidate",{sinceHours:e},{timeout:12e4})}async getTokenEconomics(){return this._get("/api/memory/economics")}async searchMemory(e,t="all",i=20){let a=new URLSearchParams({q:e,collection:t,limit:String(i)});return this._get(`/api/memory/search?${a}`)}async getMemoryStats(){return this._get("/api/memory/stats",!0)}async listRegisteredProjects(e=!1){return this._get(`/api/registry/projects?include_inactive=${e}`)}async registerProject(e,t=null,i=null){return this._post("/api/registry/projects",{path:e,name:t,alias:i})}async discoverProjects(e=3){return this._get(`/api/registry/discover?max_depth=${e}`)}async syncRegistry(){return this._post("/api/registry/sync",{},{timeout:45e3})}async getCrossProjectTasks(e=null){let t=e?`?project_ids=${e.join(",")}`:"";return this._get(`/api/registry/tasks${t}`)}async getLearningMetrics(e={}){let t=new URLSearchParams;e.timeRange&&t.append("timeRange",e.timeRange),e.signalType&&t.append("signalType",e.signalType),e.source&&t.append("source",e.source);let i=t.toString()?`?${t}`:"";return this._get(`/api/learning/metrics${i}`)}async getLearningTrends(e={}){let t=new URLSearchParams;e.timeRange&&t.append("timeRange",e.timeRange),e.signalType&&t.append("signalType",e.signalType),e.source&&t.append("source",e.source);let i=t.toString()?`?${t}`:"";return this._get(`/api/learning/trends${i}`)}async getLearningSignals(e={}){let t=new URLSearchParams;e.timeRange&&t.append("timeRange",e.timeRange),e.signalType&&t.append("signalType",e.signalType),e.source&&t.append("source",e.source),e.limit&&t.append("limit",String(e.limit)),e.offset&&t.append("offset",String(e.offset));let i=t.toString()?`?${t}`:"";return this._get(`/api/learning/signals${i}`)}async getLatestAggregation(){return this._get("/api/learning/aggregation")}async triggerAggregation(e={}){return this._post("/api/learning/aggregate",e,{timeout:6e4})}async getAggregatedPreferences(e=20){return this._get(`/api/learning/preferences?limit=${e}`)}async getAggregatedErrors(e=20){return this._get(`/api/learning/errors?limit=${e}`)}async getAggregatedSuccessPatterns(e=20){return this._get(`/api/learning/success?limit=${e}`)}async getToolEfficiency(e=20){return this._get(`/api/learning/tools?limit=${e}`)}async getCost(){return this._get("/api/cost")}async getPricing(){return this._get("/api/pricing")}async getCouncilState(){return this._get("/api/council/state")}async getCouncilVerdicts(e=20){return this._get(`/api/council/verdicts?limit=${e}`)}async getCouncilConvergence(){return this._get("/api/council/convergence")}async getCouncilReport(){return this._get("/api/council/report")}async forceCouncilReview(){return this._post("/api/council/force-review",{})}async getContext(){return this._get("/api/context")}async getNotifications(e,t){let i=new URLSearchParams;e&&i.set("severity",e),t&&i.set("unread_only","true");let a=i.toString();return this._get("/api/notifications"+(a?"?"+a:""))}async getNotificationTriggers(){return this._get("/api/notifications/triggers")}async updateNotificationTriggers(e){return this._put("/api/notifications/triggers",{triggers:e})}async acknowledgeNotification(e){return this._post("/api/notifications/"+encodeURIComponent(e)+"/acknowledge",{})}async startSession(e,t={}){let i={provider:t.provider||"claude",parallel:!!t.parallel};return t.prdPath?i.prd_path=t.prdPath:i.prd_text=e||"",t.model&&(i.model=t.model),t.advisorModel&&(i.advisor_model=t.advisorModel),this._post("/api/control/start",i)}async pauseSession(){return this._post("/api/control/pause",{})}async resumeSession(){return this._post("/api/control/resume",{})}async stopSession(){return this._post("/api/control/stop",{})}async getSessionModel(){return this._get("/api/session/model")}async setSessionModel(e){return this._post("/api/session/model",{model:e||null})}async getLogs(e=100){return this._get(`/api/logs?lines=${e}`)}async getChecklist(){return this._get("/api/checklist")}async getChecklistSummary(){return this._get("/api/checklist/summary")}async getPrdObservations(){let e=await fetch(`${this.baseUrl}/api/prd-observations`,{credentials:"include"});if(!e.ok)throw new Error(`HTTP ${e.status}`);return e.text()}async getChecklistWaivers(){return this._get("/api/checklist/waivers")}async addChecklistWaiver(e,t,i="dashboard"){return this._post("/api/checklist/waivers",{item_id:e,reason:t,waived_by:i})}async removeChecklistWaiver(e){return this._delete(`/api/checklist/waivers/${encodeURIComponent(e)}`)}async getCouncilGate(){return this._get("/api/council/gate")}async getAppRunnerStatus(){return this._get("/api/app-runner/status")}async getAppRunnerLogs(e=100){return this._get(`/api/app-runner/logs?lines=${e}`)}async getAppRunnerErrors(e=50){return this._get(`/api/app-runner/errors?lines=${e}`)}async restartApp(){return this._post("/api/control/app-restart",{})}async stopApp(){return this._post("/api/control/app-stop",{})}async getPlaywrightResults(){return this._get("/api/playwright/results")}async getPlaywrightScreenshot(){return this._get("/api/playwright/screenshot")}startPolling(e,t=null){if(this._pollInterval)return;this._pollCallback=e;let i=async()=>{try{let s=await this.getStatus();this._connected=!0,this._pollCallback&&this._pollCallback(s),this._emit(f.STATUS_UPDATE,s),this._vscodeApi&&this.postToVSCode("pollSuccess",{timestamp:Date.now()})}catch(s){this._connected=!1,this._emit(f.ERROR,{error:s}),this._vscodeApi&&this.postToVSCode("pollError",{error:s.message})}};i();let a=t||this._currentPollInterval||this.config.pollInterval;this._pollInterval=setInterval(i,a)}stopPolling(){this._pollInterval&&(clearInterval(this._pollInterval),this._pollInterval=null)}};S(M,"_instances",new Map);var q=M;function et(d={}){return new q(d)}function h(d={}){return q.getInstance(d)}var Ie="loki-state-change",Pe={ui:{theme:"light",sidebarCollapsed:!1,activeSection:"kanban",terminalAutoScroll:!0},session:{connected:!1,lastSync:null,mode:"offline",phase:null,iteration:null},localTasks:[],cache:{projects:[],tasks:[],agents:[],memory:null,lastFetch:null},preferences:{pollInterval:2e3,notifications:!0,soundEnabled:!1}},L=class L extends EventTarget{static getInstance(){return L._instance||(L._instance=new L),L._instance}constructor(){super(),this._state=this._loadState(),this._subscribers=new Map,this._batchUpdates=[],this._batchTimeout=null}_loadState(){try{let e=localStorage.getItem(L.STORAGE_KEY);if(e){let t=JSON.parse(e);return this._mergeState(Pe,t)}}catch(e){console.warn("Failed to load state from localStorage:",e)}return{...Pe}}_mergeState(e,t){let i={...e};for(let a of Object.keys(t))a in e&&typeof e[a]=="object"&&!Array.isArray(e[a])?i[a]=this._mergeState(e[a],t[a]):i[a]=t[a];return i}_saveState(){try{let e={ui:this._state.ui,localTasks:this._state.localTasks,preferences:this._state.preferences};localStorage.setItem(L.STORAGE_KEY,JSON.stringify(e))}catch(e){console.warn("Failed to save state to localStorage:",e)}}get(e=null){if(!e)return{...this._state};let t=e.split("."),i=this._state;for(let a of t){if(i==null)return;i=i[a]}return i}set(e,t,i=!0){let a=e.split("."),s=a.pop(),r=this._state;for(let n of a)n in r||(r[n]={}),r=r[n];let o=r[s];r[s]=t,i&&this._saveState(),this._notifyChange(e,t,o)}update(e,t=!0){let i=[];for(let[a,s]of Object.entries(e)){let r=this.get(a);this.set(a,s,!1),i.push({path:a,value:s,oldValue:r})}t&&this._saveState();for(let a of i)this._notifyChange(a.path,a.value,a.oldValue)}_notifyChange(e,t,i){this.dispatchEvent(new CustomEvent(Ie,{detail:{path:e,value:t,oldValue:i}}));let a=this._subscribers.get(e)||[];for(let r of a)try{r(t,i,e)}catch(o){console.error("State subscriber error:",o)}let s=e.split(".");for(;s.length>1;){s.pop();let r=s.join("."),o=this._subscribers.get(r)||[];for(let n of o)try{n(this.get(r),null,r)}catch(l){console.error("State subscriber error:",l)}}}subscribe(e,t){return this._subscribers.has(e)||this._subscribers.set(e,[]),this._subscribers.get(e).push(t),()=>{let i=this._subscribers.get(e),a=i.indexOf(t);a>-1&&i.splice(a,1)}}reset(e=null){if(e){let t=e.split("."),i=Pe;for(let a of t)i=i?.[a];this.set(e,i)}else this._state={...Pe},this._saveState(),this.dispatchEvent(new CustomEvent(Ie,{detail:{path:null,value:this._state,oldValue:null}}))}addLocalTask(e){let t=this.get("localTasks")||[],i={id:`local-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,createdAt:new Date().toISOString(),status:"pending",...e};return this.set("localTasks",[...t,i]),i}updateLocalTask(e,t){let i=this.get("localTasks")||[],a=i.findIndex(r=>r.id===e);if(a===-1)return null;let s={...i[a],...t,updatedAt:new Date().toISOString()};return i[a]=s,this.set("localTasks",[...i]),s}deleteLocalTask(e){let t=this.get("localTasks")||[];this.set("localTasks",t.filter(i=>i.id!==e))}moveLocalTask(e,t,i=null){let s=(this.get("localTasks")||[]).find(r=>r.id===e);return s?this.updateLocalTask(e,{status:t,position:i??s.position}):null}updateSession(e){this.update(Object.fromEntries(Object.entries(e).map(([t,i])=>[`session.${t}`,i])),!1)}updateCache(e){this.update({"cache.projects":e.projects??this.get("cache.projects"),"cache.tasks":e.tasks??this.get("cache.tasks"),"cache.agents":e.agents??this.get("cache.agents"),"cache.memory":e.memory??this.get("cache.memory"),"cache.lastFetch":new Date().toISOString()},!1)}getMergedTasks(){let e=this.get("cache.tasks")||[],i=(this.get("localTasks")||[]).map(a=>({...a,isLocal:!0}));return[...e,...i]}getTasksByStatus(e){return this.getMergedTasks().filter(t=>t.status===e)}};S(L,"STORAGE_KEY","loki-dashboard-state"),S(L,"_instance",null);var W=L;function N(){return W.getInstance()}function tt(d){let e=N();return{get:()=>e.get(d),set:t=>e.set(d,t),subscribe:t=>e.subscribe(d,t)}}function Be(d){return String(d??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function C(d){if(d==null||d==="")return"";let e=String(d).replace(/\r\n/g,`
2356
+ `),t=[];e=e.replace(/```[^\n]*\n([\s\S]*?)```/g,(u,m)=>{let g=t.length;return t.push(`<pre class="md-code"><code>${Be(m.replace(/\n$/,""))}</code></pre>`),`\0CODEBLOCK${g}\0`});let i=Be(e);i=i.replace(/`([^`\n]+)`/g,(u,m)=>`<code class="md-inline-code">${m}</code>`),i=i.replace(/\[([^\]\n]+)\]\(([^)\s]+)\)/g,(u,m,g)=>/^(https?:|mailto:|\/|#|\.)/.test(g)?`<a class="md-link" href="${g}" target="_blank" rel="noopener noreferrer">${m}</a>`:u);let a=i.split(`
2357
+ `),s=[],r=[],o=[],n=()=>{r.length&&(s.push(`<p class="md-p">${r.join("<br>")}</p>`),r=[])},l=u=>{for(;o.length&&o[o.length-1].indent>=u;)s.push(`</${o.pop().tag}>`)},c=()=>{for(;o.length;)s.push(`</${o.pop().tag}>`)};for(let u of a){let m=u,g=m.trim(),k=g.match(/^CODEBLOCK(\d+)$/);if(k){n(),c(),s.push(t[Number(k[1])]);continue}if(g===""){n(),c();continue}let x=g.match(/^(#{1,6})\s+(.+)$/);if(x){n(),c();let R=Math.min(x[1].length+1,6);s.push(`<h${R} class="md-h${R}">${x[2]}</h${R}>`);continue}if(/^(-{3,}|\*{3,}|_{3,})$/.test(g)){n(),c(),s.push('<hr class="md-hr">');continue}let _=g.match(/^&gt;\s?(.*)$/);if(_){n(),c(),s.push(`<blockquote class="md-quote">${_[1]}</blockquote>`);continue}let D=m.match(/^(\s*)/)[1].replace(/\t/g," ").length,J=g.match(/^([-*+])\s+(.+)$/),V=g.match(/^(\d+)[.)]\s+(.+)$/);if(J||V){n();let R=V?"ol":"ul",bt=J?J[2]:V[2];!o.length||D>o[o.length-1].indent?(s.push(`<${R} class="md-list">`),o.push({tag:R,indent:D})):(l(D+1),o.length||(s.push(`<${R} class="md-list">`),o.push({tag:R,indent:D}))),s.push(`<li>${bt}</li>`);continue}c(),r.push(m.trim())}n(),c();let p=s.join(`
2358
+ `);return p=p.replace(/\*\*([^*\n]+)\*\*/g,"<strong>$1</strong>"),p=p.replace(/__([^_\n]+)__/g,"<strong>$1</strong>"),p=p.replace(/(^|[^*])\*([^*\n]+)\*/g,"$1<em>$2</em>"),p}var z=`
2357
2359
  .md-body { line-height: 1.6; color: var(--loki-text, #2b2a28); font-size: 14px; word-wrap: break-word; }
2358
2360
  .md-body .md-h2 { font-size: 18px; font-weight: 650; margin: 18px 0 8px; }
2359
2361
  .md-body .md-h3 { font-size: 16px; font-weight: 600; margin: 16px 0 6px; }
@@ -2369,7 +2371,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
2369
2371
  .md-body .md-link:hover { text-decoration: underline; }
2370
2372
  .md-body .md-hr { border: 0; border-top: 1px solid var(--loki-border, #e5e1d8); margin: 16px 0; }
2371
2373
  .md-body strong { font-weight: 650; }
2372
- `;function pt(d){return!d||typeof d!="string"?null:d.startsWith("page-")?d.slice(5):d}function Ke(){if(typeof document>"u")return null;let d=document.querySelector(".section-page.active");if(d&&d.id)return pt(d.id);try{if(typeof localStorage<"u"){let e=localStorage.getItem("loki-active-section");if(e)return e}}catch{}return null}var We=class{constructor(){this._regs=new Map,this._seq=0,this._activeSection=Ke(),this._hidden=typeof document<"u"?!!document.hidden:!1,this._listenersInstalled=!1,this._sectionChangeHandler=null,this._visibilityHandler=null,this._mutationObserver=null}get _hasDom(){return typeof document<"u"}_ensureListeners(){if(!(this._listenersInstalled||!this._hasDom)){this._sectionChangeHandler=e=>{let t=e&&e.detail&&e.detail.section?e.detail.section:Ke();this._setActiveSection(t)},document.addEventListener("loki:section-change",this._sectionChangeHandler),this._visibilityHandler=()=>{let e=!!document.hidden;e!==this._hidden&&(this._hidden=e,e||(this._activeSection=Ke()),this._reevaluateAll())},document.addEventListener("visibilitychange",this._visibilityHandler);try{let e=document.getElementById("main-content")||document.body;e&&typeof MutationObserver<"u"&&(this._mutationObserver=new MutationObserver(()=>{let t=Ke();t&&t!==this._activeSection&&this._setActiveSection(t)}),this._mutationObserver.observe(e,{subtree:!0,attributes:!0,attributeFilter:["class"]}))}catch{}this._listenersInstalled=!0}}_setActiveSection(e){e!==this._activeSection&&(this._activeSection=e,this._reevaluateAll())}_resolveSection(e){if(Object.prototype.hasOwnProperty.call(e,"sectionId"))return e.sectionId===null?void 0:e.sectionId;if(e.element&&typeof e.element.closest=="function"){let t=e.element.closest(".section-page"),i=pt(t&&t.id);return i===null?void 0:i}}_isAllowed(e){if(!this._hasDom)return!0;if(this._hidden)return!1;let t=this._resolveSection(e);return t===void 0?!0:t===this._activeSection}_reevaluateAll(){for(let e of this._regs.values()){let t=this._isAllowed(e);t&&!e._wasAllowed?(e._wasAllowed=!0,this._safeRun(e)):e._wasAllowed=t}}_safeRun(e){try{let t=e.loadFn();t&&typeof t.then=="function"&&t.catch(()=>{})}catch{}}register(e={}){let{loadFn:t,intervalMs:i}=e;if(typeof t!="function")throw new Error("registerPoll: loadFn must be a function");if(typeof i!="number"||!(i>0))throw new Error("registerPoll: intervalMs must be a positive number");this._ensureListeners();let a=e.id||`poll-${++this._seq}`;this._regs.has(a)&&this._stopReg(this._regs.get(a));let s={id:a,loadFn:t,intervalMs:i,element:e.element||null,_timer:null,_wasAllowed:!1};return Object.prototype.hasOwnProperty.call(e,"sectionId")&&(s.sectionId=e.sectionId),s._wasAllowed=this._isAllowed(s),s._timer=setInterval(()=>{this._isAllowed(s)?(s._wasAllowed=!0,this._safeRun(s)):s._wasAllowed=!1},i),this._regs.set(a,s),e.immediate!==!1&&s._wasAllowed&&this._safeRun(s),{id:a,stop:()=>this.unregister(a),isActive:()=>this._isAllowed(s)}}_stopReg(e){e&&e._timer&&(clearInterval(e._timer),e._timer=null)}unregister(e){let t=this._regs.get(e);return t?(this._stopReg(t),this._regs.delete(e),!0):!1}get activeSection(){return this._activeSection}get size(){return this._regs.size}destroy(){for(let e of this._regs.values())this._stopReg(e);this._regs.clear(),this._hasDom&&(this._sectionChangeHandler&&(document.removeEventListener("loki:section-change",this._sectionChangeHandler),this._sectionChangeHandler=null),this._visibilityHandler&&(document.removeEventListener("visibilitychange",this._visibilityHandler),this._visibilityHandler=null),this._mutationObserver&&(this._mutationObserver.disconnect(),this._mutationObserver=null)),this._listenersInstalled=!1}},Ye=null;function Bt(){return Ye||(Ye=new We),Ye}function b(d){return Bt().register(d)}var X=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._data={status:"offline",phase:null,iteration:null,provider:null,running_agents:0,pending_tasks:null,uptime_seconds:0,complexity:null,connected:!1},this._api=null,this._pollInterval=null,this._statusUpdateHandler=null,this._connectedHandler=null,this._disconnectedHandler=null,this._checklistSummary=null,this._appRunnerStatus=null,this._playwrightResults=null,this._gateStatus=null,this._journeyProof=null,this._journeyState="empty"}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadStatus(),this._startPolling(),this._api.connect().catch(()=>{})}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling(),this._loadAbortController&&(this._loadAbortController.abort(),this._loadAbortController=null),this._teardownApiListeners()}attributeChangedCallback(e,t,i){if(t!==i){if(e==="api-url"&&this._api){let a=this._api;this._teardownApiListeners(),this._setupApi(),a&&a!==this._api&&a.disconnect(),this._api.connect().catch(()=>{}),this._loadStatus()}e==="theme"&&this._applyTheme()}}_teardownApiListeners(){this._api&&(this._statusUpdateHandler&&this._api.removeEventListener(f.STATUS_UPDATE,this._statusUpdateHandler),this._connectedHandler&&this._api.removeEventListener(f.CONNECTED,this._connectedHandler),this._disconnectedHandler&&this._api.removeEventListener(f.DISCONNECTED,this._disconnectedHandler))}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e}),this._statusUpdateHandler=t=>this._updateFromStatus(t.detail),this._connectedHandler=()=>{this._data.connected=!0,this.render()},this._disconnectedHandler=()=>{this._data.connected=!1,this._data.status="offline",this.render()},this._api.addEventListener(f.STATUS_UPDATE,this._statusUpdateHandler),this._api.addEventListener(f.CONNECTED,this._connectedHandler),this._api.addEventListener(f.DISCONNECTED,this._disconnectedHandler)}async _loadStatus(){this._loadAbortController&&this._loadAbortController.abort(),this._loadAbortController=new AbortController;let{signal:e}=this._loadAbortController;try{let[t,i,a,s,r,o]=await Promise.allSettled([this._api.getStatus(),this._api.getChecklistSummary(),this._api.getAppRunnerStatus(),this._api.getPlaywrightResults(),this._api.getCouncilGate(),this._api._get("/api/proofs")]);if(e.aborted)return;if(t.status==="fulfilled"?this._updateFromStatus(t.value):(this._data.connected=!1,this._data.status="offline"),i.status==="fulfilled"&&(this._checklistSummary=i.value?.summary||null),a.status==="fulfilled"&&(this._appRunnerStatus=a.value),s.status==="fulfilled"&&(this._playwrightResults=s.value),r.status==="fulfilled"&&(this._gateStatus=r.value),o.status==="fulfilled"){let n=Array.isArray(o.value?.proofs)?o.value.proofs:[];if(n.length===0)this._journeyProof=null,this._journeyState="empty";else{let l=n[0]?.run_id;if(typeof l=="string"&&l)try{let c=await this._api._get(`/api/proofs/${encodeURIComponent(l)}`);if(e.aborted)return;this._journeyProof=c,this._journeyState="ready"}catch{this._journeyProof=null,this._journeyState="unavailable"}else this._journeyProof=null,this._journeyState="unavailable"}}else this._journeyProof=null,this._journeyState="unavailable";this.render()}catch{if(e.aborted)return;this._data.connected=!1,this._data.status="offline",this.render()}}_updateFromStatus(e){e&&(this._data={...this._data,connected:!0,status:e.status||"offline",phase:e.phase||null,iteration:e.iteration!=null?e.iteration:null,provider:e.provider||null,running_agents:e.running_agents||0,pending_tasks:e.pending_tasks!=null?e.pending_tasks:null,uptime_seconds:e.uptime_seconds||0,complexity:e.complexity||null})}_startPolling(){this._poll=b({loadFn:async()=>{try{await this._loadStatus()}catch{this._data.connected=!1,this._data.status="offline",this.render()}},intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_formatUptime(e){if(!e||e<0)return"--";let t=Math.floor(e/3600),i=Math.floor(e%3600/60),a=Math.floor(e%60);return t>0?`${t}h ${i}m`:i>0?`${i}m ${a}s`:`${a}s`}_getStatusDotClass(){switch(this._data.status){case"running":case"autonomous":return"active";case"paused":return"paused";case"stopped":return"stopped";case"error":return"error";default:return"offline"}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_renderAppRunnerCard(){let e=this._appRunnerStatus;if(!e||e.status==="not_initialized")return`
2374
+ `;function it(d){return!d||typeof d!="string"?null:d.startsWith("page-")?d.slice(5):d}function je(){if(typeof document>"u")return null;let d=document.querySelector(".section-page.active");if(d&&d.id)return it(d.id);try{if(typeof localStorage<"u"){let e=localStorage.getItem("loki-active-section");if(e)return e}}catch{}return null}var qe=class{constructor(){this._regs=new Map,this._seq=0,this._activeSection=je(),this._hidden=typeof document<"u"?!!document.hidden:!1,this._listenersInstalled=!1,this._sectionChangeHandler=null,this._visibilityHandler=null,this._mutationObserver=null}get _hasDom(){return typeof document<"u"}_ensureListeners(){if(!(this._listenersInstalled||!this._hasDom)){this._sectionChangeHandler=e=>{let t=e&&e.detail&&e.detail.section?e.detail.section:je();this._setActiveSection(t)},document.addEventListener("loki:section-change",this._sectionChangeHandler),this._visibilityHandler=()=>{let e=!!document.hidden;e!==this._hidden&&(this._hidden=e,e||(this._activeSection=je()),this._reevaluateAll())},document.addEventListener("visibilitychange",this._visibilityHandler);try{let e=document.getElementById("main-content")||document.body;e&&typeof MutationObserver<"u"&&(this._mutationObserver=new MutationObserver(()=>{let t=je();t&&t!==this._activeSection&&this._setActiveSection(t)}),this._mutationObserver.observe(e,{subtree:!0,attributes:!0,attributeFilter:["class"]}))}catch{}this._listenersInstalled=!0}}_setActiveSection(e){e!==this._activeSection&&(this._activeSection=e,this._reevaluateAll())}_resolveSection(e){if(Object.prototype.hasOwnProperty.call(e,"sectionId"))return e.sectionId===null?void 0:e.sectionId;if(e.element&&typeof e.element.closest=="function"){let t=e.element.closest(".section-page"),i=it(t&&t.id);return i===null?void 0:i}}_isAllowed(e){if(!this._hasDom)return!0;if(this._hidden)return!1;let t=this._resolveSection(e);return t===void 0?!0:t===this._activeSection}_reevaluateAll(){for(let e of this._regs.values()){let t=this._isAllowed(e);t&&!e._wasAllowed?(e._wasAllowed=!0,this._safeRun(e)):e._wasAllowed=t}}_safeRun(e){try{let t=e.loadFn();t&&typeof t.then=="function"&&t.catch(()=>{})}catch{}}register(e={}){let{loadFn:t,intervalMs:i}=e;if(typeof t!="function")throw new Error("registerPoll: loadFn must be a function");if(typeof i!="number"||!(i>0))throw new Error("registerPoll: intervalMs must be a positive number");this._ensureListeners();let a=e.id||`poll-${++this._seq}`;this._regs.has(a)&&this._stopReg(this._regs.get(a));let s={id:a,loadFn:t,intervalMs:i,element:e.element||null,_timer:null,_wasAllowed:!1};return Object.prototype.hasOwnProperty.call(e,"sectionId")&&(s.sectionId=e.sectionId),s._wasAllowed=this._isAllowed(s),s._timer=setInterval(()=>{this._isAllowed(s)?(s._wasAllowed=!0,this._safeRun(s)):s._wasAllowed=!1},i),this._regs.set(a,s),e.immediate!==!1&&s._wasAllowed&&this._safeRun(s),{id:a,stop:()=>this.unregister(a),isActive:()=>this._isAllowed(s)}}_stopReg(e){e&&e._timer&&(clearInterval(e._timer),e._timer=null)}unregister(e){let t=this._regs.get(e);return t?(this._stopReg(t),this._regs.delete(e),!0):!1}get activeSection(){return this._activeSection}get size(){return this._regs.size}destroy(){for(let e of this._regs.values())this._stopReg(e);this._regs.clear(),this._hasDom&&(this._sectionChangeHandler&&(document.removeEventListener("loki:section-change",this._sectionChangeHandler),this._sectionChangeHandler=null),this._visibilityHandler&&(document.removeEventListener("visibilitychange",this._visibilityHandler),this._visibilityHandler=null),this._mutationObserver&&(this._mutationObserver.disconnect(),this._mutationObserver=null)),this._listenersInstalled=!1}},Oe=null;function Ct(){return Oe||(Oe=new qe),Oe}function b(d){return Ct().register(d)}var Q=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._data={status:"offline",phase:null,iteration:null,provider:null,running_agents:null,pending_tasks:null,uptime_seconds:0,complexity:null,connected:!1},this._api=null,this._pollInterval=null,this._statusUpdateHandler=null,this._connectedHandler=null,this._disconnectedHandler=null,this._checklistSummary=null,this._appRunnerStatus=null,this._playwrightResults=null,this._gateStatus=null,this._journeyProof=null,this._journeyState="empty"}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadStatus(),this._startPolling(),this._api.connect().catch(()=>{})}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling(),this._loadAbortController&&(this._loadAbortController.abort(),this._loadAbortController=null),this._teardownApiListeners()}attributeChangedCallback(e,t,i){if(t!==i){if(e==="api-url"&&this._api){let a=this._api;this._teardownApiListeners(),this._setupApi(),a&&a!==this._api&&a.disconnect(),this._api.connect().catch(()=>{}),this._loadStatus()}e==="theme"&&this._applyTheme()}}_teardownApiListeners(){this._api&&(this._statusUpdateHandler&&this._api.removeEventListener(f.STATUS_UPDATE,this._statusUpdateHandler),this._connectedHandler&&this._api.removeEventListener(f.CONNECTED,this._connectedHandler),this._disconnectedHandler&&this._api.removeEventListener(f.DISCONNECTED,this._disconnectedHandler))}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e}),this._statusUpdateHandler=t=>this._updateFromStatus(t.detail),this._connectedHandler=()=>{this._data.connected=!0,this.render()},this._disconnectedHandler=()=>{this._data.connected=!1,this._data.status="offline",this.render()},this._api.addEventListener(f.STATUS_UPDATE,this._statusUpdateHandler),this._api.addEventListener(f.CONNECTED,this._connectedHandler),this._api.addEventListener(f.DISCONNECTED,this._disconnectedHandler)}async _loadStatus(){this._loadAbortController&&this._loadAbortController.abort(),this._loadAbortController=new AbortController;let{signal:e}=this._loadAbortController;try{let[t,i,a,s,r,o]=await Promise.allSettled([this._api.getStatus(),this._api.getChecklistSummary(),this._api.getAppRunnerStatus(),this._api.getPlaywrightResults(),this._api.getCouncilGate(),this._api._get("/api/proofs")]);if(e.aborted)return;if(t.status==="fulfilled"?this._updateFromStatus(t.value):(this._data.connected=!1,this._data.status="offline"),i.status==="fulfilled"&&(this._checklistSummary=i.value?.summary||null),a.status==="fulfilled"&&(this._appRunnerStatus=a.value),s.status==="fulfilled"&&(this._playwrightResults=s.value),r.status==="fulfilled"&&(this._gateStatus=r.value),o.status==="fulfilled"){let n=Array.isArray(o.value?.proofs)?o.value.proofs:[];if(n.length===0)this._journeyProof=null,this._journeyState="empty";else{let l=n[0]?.run_id;if(typeof l=="string"&&l)try{let c=await this._api._get(`/api/proofs/${encodeURIComponent(l)}`);if(e.aborted)return;this._journeyProof=c,this._journeyState="ready"}catch{this._journeyProof=null,this._journeyState="unavailable"}else this._journeyProof=null,this._journeyState="unavailable"}}else this._journeyProof=null,this._journeyState="unavailable";this.render()}catch{if(e.aborted)return;this._data.connected=!1,this._data.status="offline",this.render()}}_updateFromStatus(e){e&&(this._data={...this._data,connected:!0,status:e.status||"offline",phase:e.phase||null,iteration:e.iteration!=null?e.iteration:null,provider:e.provider||null,running_agents:e.running_agents??null,pending_tasks:e.pending_tasks!=null?e.pending_tasks:null,uptime_seconds:e.uptime_seconds||0,complexity:e.complexity||null})}_startPolling(){this._poll=b({loadFn:async()=>{try{await this._loadStatus()}catch{this._data.connected=!1,this._data.status="offline",this.render()}},intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_formatUptime(e){if(!e||e<0)return"--";let t=Math.floor(e/3600),i=Math.floor(e%3600/60),a=Math.floor(e%60);return t>0?`${t}h ${i}m`:i>0?`${i}m ${a}s`:`${a}s`}_getStatusDotClass(){switch(this._data.status){case"running":case"autonomous":return"active";case"paused":return"paused";case"stopped":return"stopped";case"error":return"error";default:return"offline"}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_renderAppRunnerCard(){let e=this._appRunnerStatus;if(!e||e.status==="not_initialized")return`
2373
2375
  <div class="overview-card">
2374
2376
  <div class="card-label">App Status</div>
2375
2377
  <div class="card-value small-text">${this._data.status==="running"||this._data.status==="autonomous"?"Starting...":"Not started"}</div>
@@ -2419,41 +2421,41 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
2419
2421
  </div>
2420
2422
  ${e.failing?`<div style="font-size:10px;color:var(--loki-red,#ef4444);margin-top:2px;">${e.failing} failing</div>`:""}
2421
2423
  </div>
2422
- `}_renderCouncilGateCard(){let e=this._gateStatus;if(!e||!e.status){let t=this._data.status==="running"||this._data.status==="autonomous";return`
2424
+ `}_renderCouncilGateCard(){let e=this._gateStatus;if(!e||!e.status){let i=this._data.status==="running"||this._data.status==="autonomous";return`
2423
2425
  <div class="overview-card">
2424
2426
  <div class="card-label">Council Gate</div>
2425
2427
  <div class="card-value small-text">
2426
- <span class="status-dot ${t?"paused":"offline"}"></span>
2427
- ${t?"Pending review":"Not evaluated"}
2428
+ <span class="status-dot ${i?"paused":"offline"}"></span>
2429
+ ${i?"Pending review":"Not evaluated"}
2428
2430
  </div>
2429
2431
  </div>
2430
- `}if(e.status==="blocked"){let t=e.critical_failures||0;return`
2432
+ `}if(e.status==="blocked"){let i=e.critical_failures||0;return`
2431
2433
  <div class="overview-card">
2432
2434
  <div class="card-label">Council Gate</div>
2433
2435
  <div class="card-value small-text">
2434
2436
  <span class="status-dot error"></span>
2435
2437
  BLOCKED
2436
2438
  </div>
2437
- ${t>0?`<div style="font-size:10px;color:var(--loki-red,#ef4444);margin-top:2px;">${t} critical failure${t!==1?"s":""}</div>`:""}
2439
+ ${i>0?`<div style="font-size:10px;color:var(--loki-red,#ef4444);margin-top:2px;">${i} critical failure${i!==1?"s":""}</div>`:""}
2438
2440
  </div>
2439
- `}return`
2441
+ `}let t=e.status==="passed"||e.status==="pass";return`
2440
2442
  <div class="overview-card">
2441
2443
  <div class="card-label">Council Gate</div>
2442
2444
  <div class="card-value small-text">
2443
- <span class="status-dot active"></span>
2444
- PASSED
2445
+ <span class="status-dot ${t?"active":"offline"}"></span>
2446
+ ${t?"PASSED":`Unknown (${this._escapeHtml(String(e.status))})`}
2445
2447
  </div>
2446
2448
  </div>
2447
2449
  `}_renderDisconnected(){return`<div class="journey-state" role="status">
2448
2450
  Not connected to the Loki API. No session numbers can be shown until it
2449
2451
  reconnects. Start it with <code>loki dashboard start</code>, or check the
2450
2452
  API URL in Settings.
2451
- </div>`}_renderJourney(){if(this._journeyState==="unavailable")return'<div class="journey-state" role="status">Issue-to-PR evidence is unavailable. No readiness claim can be made.</div>';if(this._journeyState!=="ready"||!this._journeyProof)return'<div class="journey-state" role="status">No issue-to-PR receipt yet. Start an issue run to record its first result, proof, and PR state.</div>';let e=this._journeyProof,t=e?.facts?.journey;if(!t||!t.issue)return'<div class="journey-state" role="status">Latest receipt is not an issue run. Issue-to-PR readiness is not applicable.</div>';let i=t.time_to_first_result_sec,a=typeof i=="number"&&i>=0,s=t.first_result_kind==="code_change"?"verified patch":t.first_result_kind==="proposed_solution_plan"?"proposed solution":"result",r=a?`${Math.round(i)}s to ${s}`:"Not measured",o=typeof e?.honesty?.headline=="string"?e.honesty.headline:null,n=Array.isArray(e?.honesty?.degraded)?e.honesty.degraded.length:null,l=o||"Not evaluated",c=n===null?"Uncertainty not measured":n===0?"No recorded gaps":`${n} recorded gap${n===1?"":"s"}`,p=t.pull_request,u="Not prepared",m="";p&&p.state&&(u=String(p.state).replace(/_/g," "),this._isSafeWebUrl(p.url)&&(m=`<a class="journey-link" href="${this._escapeHtml(p.url)}" target="_blank" rel="noopener noreferrer">Open PR</a>`));let g=this._data.phase||(this._data.status==="running"?"In progress":"Run complete");return`
2453
+ </div>`}_renderJourney(){if(this._journeyState==="unavailable")return'<div class="journey-state" role="status">Issue-to-PR evidence is unavailable. No readiness claim can be made.</div>';if(this._journeyState!=="ready"||!this._journeyProof)return'<div class="journey-state" role="status">No issue-to-PR receipt yet. Start an issue run to record its first result, proof, and PR state.</div>';let e=this._journeyProof,t=e?.facts?.journey;if(!t||!t.issue)return'<div class="journey-state" role="status">Latest receipt is not an issue run. Issue-to-PR readiness is not applicable.</div>';let i=t.time_to_first_result_sec,a=typeof i=="number"&&i>=0,s=t.first_result_kind==="code_change"?"first code change":t.first_result_kind==="proposed_solution_plan"?"proposed solution":"result",r=a?`${Math.round(i)}s to ${s}`:"Not measured",o=typeof e?.honesty?.headline=="string"?e.honesty.headline:null,n=Array.isArray(e?.honesty?.degraded)?e.honesty.degraded.length:null,l=o||"Not evaluated",c=(o?"Recorded, not re-verified here; ":"")+(n===null?"uncertainty not measured":n===0?"no recorded gaps":`${n} recorded gap${n===1?"":"s"}`),p=t.pull_request,u="Not prepared",m="";p&&p.state&&(u=String(p.state).replace(/_/g," "),this._isSafeWebUrl(p.url)&&(m=`<a class="journey-link" href="${this._escapeHtml(p.url)}" target="_blank" rel="noopener noreferrer">Open PR</a>`));let g=this._data.phase||(this._data.status==="running"?"In progress":"Run complete");return`
2452
2454
  <section class="journey" aria-labelledby="journey-heading">
2453
2455
  <div class="journey-heading" id="journey-heading">Issue to PR</div>
2454
2456
  <div class="journey-steps">
2455
2457
  ${this._renderJourneyStep("Current phase",g,"Live session status")}
2456
- ${this._renderJourneyStep("First useful result",r,a&&t.first_result_verified_patch!==!0?"Plan only, not a verified patch":"From the run receipt")}
2458
+ ${this._renderJourneyStep("First useful result",r,a&&t.first_result_verified_patch!==!0?"Plan only, no code change yet":"From the run receipt")}
2457
2459
  ${this._renderJourneyStep("Gates and evidence",l,c)}
2458
2460
  ${this._renderJourneyStep("PR readiness",u,m||"No public PR URL recorded")}
2459
2461
  </div>
@@ -2461,7 +2463,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
2461
2463
  <div class="journey-label">${this._escapeHtml(e)}</div>
2462
2464
  <div class="journey-value">${this._escapeHtml(t)}</div>
2463
2465
  <div class="journey-meta">${i}</div>
2464
- </div>`}_isSafeWebUrl(e){if(typeof e!="string")return!1;try{let t=new URL(e);return t.protocol==="https:"||t.protocol==="http:"}catch{return!1}}render(){let e=this._getStatusDotClass(),t=this._escapeHtml((this._data.status||"OFFLINE").toUpperCase()),i=this._escapeHtml(this._data.phase||"--"),a=this._escapeHtml(this._data.iteration!=null?String(this._data.iteration):"0"),s=this._escapeHtml((this._data.provider||"CLAUDE").toUpperCase()),r=this._data.status==="running"||this._data.status==="autonomous",o=this._data.running_agents||0,n=r&&o===0?"Sequential":this._escapeHtml(String(o)),l=this._escapeHtml(this._data.pending_tasks!=null?`${this._data.pending_tasks} pending`:r?"Inline":"--"),c=this._escapeHtml(this._formatUptime(this._data.uptime_seconds)),p=this._escapeHtml((this._data.complexity||"STANDARD").toUpperCase());this.shadowRoot.innerHTML=`
2466
+ </div>`}_isSafeWebUrl(e){if(typeof e!="string")return!1;try{let t=new URL(e);return t.protocol==="https:"||t.protocol==="http:"}catch{return!1}}render(){let e=this._getStatusDotClass(),t=this._escapeHtml((this._data.status||"OFFLINE").toUpperCase()),i=this._escapeHtml(this._data.phase||"--"),a=this._escapeHtml(this._data.iteration!=null?String(this._data.iteration):"--"),s=this._escapeHtml((this._data.provider||"--").toUpperCase()),r=this._data.status==="running"||this._data.status==="autonomous",o=this._data.running_agents,n=o==null?"--":r&&o===0?"Sequential":this._escapeHtml(String(o)),l=this._escapeHtml(this._data.pending_tasks!=null?`${this._data.pending_tasks} pending`:"--"),c=this._escapeHtml(this._formatUptime(this._data.uptime_seconds)),p=this._escapeHtml((this._data.complexity||"--").toUpperCase());this.shadowRoot.innerHTML=`
2465
2467
  <style>
2466
2468
  ${this.getBaseStyles()}
2467
2469
 
@@ -2694,7 +2696,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
2694
2696
  </div>
2695
2697
  `:this._renderDisconnected()}
2696
2698
  </div>
2697
- `}};customElements.get("loki-overview")||customElements.define("loki-overview",X);var Ft=[{id:"pending",label:"Pending",status:"pending",color:"var(--loki-text-muted)"},{id:"in_progress",label:"In Progress",status:"in_progress",color:"var(--loki-blue)"},{id:"review",label:"In Review",status:"review",color:"var(--loki-purple)"},{id:"done",label:"Completed",status:"done",color:"var(--loki-green)"}],Z=class d extends v{static get observedAttributes(){return["api-url","project-id","theme","readonly"]}constructor(){super(),this._tasks=[],this._loading=!0,this._error=null,this._draggedTask=null,this._selectedTask=null,this._expandedCards=new Set,this._selectedTasks=new Set,this._bulkMode=!1,this._activeFilter="all",this._searchQuery="",this._visibleCounts={},this._api=null,this._state=N()}static get PAGE_SIZE(){return 10}_getVisibleCount(e){let t=this._visibleCounts[e];return typeof t=="number"&&t>0?t:d.PAGE_SIZE}_showMore(e){this._visibleCounts[e]=this._getVisibleCount(e)+d.PAGE_SIZE,this.render()}_columnIcon(e){switch(e){case"pending":return'<circle cx="12" cy="12" r="10"/>';case"in_progress":return'<path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83"/>';case"review":return'<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>';case"done":return'<path d="M22 11.08V12a10 10 0 11-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/>';default:return'<circle cx="12" cy="12" r="10"/>'}}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadTasks()}disconnectedCallback(){super.disconnectedCallback(),this._teardownApiListeners()}_teardownApiListeners(){this._api&&this._onTaskEvent&&(this._api.removeEventListener(f.TASK_CREATED,this._onTaskEvent),this._api.removeEventListener(f.TASK_UPDATED,this._onTaskEvent),this._api.removeEventListener(f.TASK_DELETED,this._onTaskEvent))}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._teardownApiListeners(),this._setupApi(),this._loadTasks()),e==="project-id"&&this._loadTasks(),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e}),this._onTaskEvent=()=>this._loadTasks(),this._api.addEventListener(f.TASK_CREATED,this._onTaskEvent),this._api.addEventListener(f.TASK_UPDATED,this._onTaskEvent),this._api.addEventListener(f.TASK_DELETED,this._onTaskEvent)}async _loadTasks(){let e=this._api;this._loading=!0,this._error=null,this.render();try{let t=this.getAttribute("project-id"),i=t?{projectId:parseInt(t)}:{},a=await e.listTasks(i);if(e!==this._api)return;this._tasks=a;let s=this._state.get("localTasks")||[];s.length>0&&(this._tasks=[...this._tasks,...s.map(r=>({...r,isLocal:!0}))]),this._state.update({"cache.tasks":this._tasks},!1)}catch(t){if(e!==this._api)return;this._error=t.message,this._tasks=(this._state.get("localTasks")||[]).map(i=>({...i,isLocal:!0}))}this._loading=!1,this.render()}_getTasksByStatus(e){return this._getFilteredTasks().filter(i=>i.status?.toLowerCase().replace(/-/g,"_")===e)}_handleDragStart(e,t){this.hasAttribute("readonly")||(this._draggedTask=t,e.target.classList.add("dragging"),e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("text/plain",t.id.toString()))}_handleDragEnd(e){e.target.classList.remove("dragging"),this._draggedTask=null,this.shadowRoot.querySelectorAll(".kanban-tasks").forEach(t=>{t.classList.remove("drag-over")})}_handleDragOver(e){e.preventDefault(),e.dataTransfer.dropEffect="move"}_handleDragEnter(e){e.preventDefault(),e.currentTarget.classList.add("drag-over")}_handleDragLeave(e){e.currentTarget.contains(e.relatedTarget)||e.currentTarget.classList.remove("drag-over")}async _handleDrop(e,t){if(e.preventDefault(),e.currentTarget.classList.remove("drag-over"),!this._draggedTask||this.hasAttribute("readonly"))return;let i=this._draggedTask.id,a=this._tasks.find(r=>r.id===i);if(!a)return;let s=a.status;if(s!==t){a.status=t,this.render();try{a.isLocal?this._state.moveLocalTask(i,t):await this._api.moveTask(i,t,0),this.dispatchEvent(new CustomEvent("task-moved",{detail:{taskId:i,oldStatus:s,newStatus:t}}))}catch(r){a.status=s,this.render(),console.error("Failed to move task:",r)}}}_toggleCardExpand(e){this._expandedCards.has(e)?this._expandedCards.delete(e):this._expandedCards.add(e),this.render()}_toggleTaskSelection(e,t){t&&t.stopPropagation(),this._selectedTasks.has(e)?this._selectedTasks.delete(e):this._selectedTasks.add(e),this.render()}_toggleBulkMode(){this._bulkMode=!this._bulkMode,this._bulkMode||this._selectedTasks.clear(),this.render()}async _bulkMove(e){let t=[...this._selectedTasks];for(let i of t){let a=this._tasks.find(s=>String(s.id)===String(i));if(a&&a.status!==e)try{a.isLocal?this._state.moveLocalTask(i,e):await this._api.moveTask(i,e,0),a.status=e}catch(s){console.error("Failed to bulk move task:",i,s)}}this._selectedTasks.clear(),this._bulkMode=!1,this.render(),this._loadTasks()}async _bulkDelete(){let e=[...this._selectedTasks];for(let t of e)try{await this._api.deleteTask(t)}catch(i){console.error("Failed to delete task:",t,i)}this._selectedTasks.clear(),this._bulkMode=!1,this._loadTasks()}_setFilter(e){this._activeFilter=e,this._visibleCounts={},this.render()}_setSearch(e){this._searchQuery=e||"",this._visibleCounts={},this._renderTaskRegion();let t=this.shadowRoot.getElementById("task-search");if(t){t.focus();let i=t.value.length;try{t.setSelectionRange(i,i)}catch{}}}_getFilteredTasks(){let e=[...this._tasks],t=new Date,i=new Date(t.getFullYear(),t.getMonth(),t.getDate()),a=new Date(i.getTime()-7*24*60*60*1e3);switch(this._activeFilter){case"today":e=e.filter(r=>{let o=r.created_at?new Date(r.created_at):null;return o&&o>=i});break;case"this-week":e=e.filter(r=>{let o=r.created_at?new Date(r.created_at):null;return o&&o>=a});break;case"running":e=e.filter(r=>r.status==="in_progress");break;case"failed":e=e.filter(r=>r.status==="failed"||r.status==="error");break;default:break}let s=this._searchQuery.trim().toLowerCase();return s&&(e=e.filter(r=>[r.id,r.title,r.description,r.type].map(n=>String(n??"").toLowerCase()).join(" ").includes(s))),e}_openAddTaskModal(e="pending"){this.dispatchEvent(new CustomEvent("add-task",{detail:{status:e}}))}_openTaskDetail(e){this._selectedTask=e,this.render(),this.dispatchEvent(new CustomEvent("task-click",{detail:{task:e}}))}_closeTaskDetail(){this._selectedTask=null,this.render()}_renderMarkdown(e){return C(e)}_formatTimestamp(e){if(!e)return"";try{let t=new Date(e);return isNaN(t.getTime())?this._escapeHtml(String(e)):t.toLocaleString()}catch{return this._escapeHtml(String(e))}}_phaseClass(e){let t=String(e||"").toLowerCase();return["reason","plan","planning"].includes(t)?"phase-reason":["act","execute","execution","implement"].includes(t)?"phase-act":["reflect","review"].includes(t)?"phase-reflect":["verify","test","gate"].includes(t)?"phase-verify":"phase-default"}_logLevelClass(e){let t=String(e||"info").toLowerCase();return t==="error"||t==="fatal"?"log-error":t==="warn"||t==="warning"?"log-warn":t==="debug"||t==="trace"?"log-debug":"log-info"}_renderTaskDetailModal(e){if(!e)return"";let t=(e.priority||"medium").toLowerCase(),i=t.charAt(0).toUpperCase()+t.slice(1),a=e.status||"pending",s=a.replace(/_/g," ").replace(/\b\w/g,g=>g.toUpperCase()),r=e.metadata||{},o=Array.isArray(e.acceptance_criteria)?e.acceptance_criteria:[],n=Array.isArray(e.context_files)?e.context_files:[],l=e.specification||"",c=e.description||"",p=Array.isArray(e.notes)?e.notes:[],u=Array.isArray(e.logs)?e.logs:[],m=e.full_content||"";return`
2699
+ `}};customElements.get("loki-overview")||customElements.define("loki-overview",Q);var St=[{id:"pending",label:"Pending",status:"pending",color:"var(--loki-text-muted)"},{id:"in_progress",label:"In Progress",status:"in_progress",color:"var(--loki-blue)"},{id:"review",label:"In Review",status:"review",color:"var(--loki-purple)"},{id:"done",label:"Completed",status:"done",color:"var(--loki-green)"}],X=class d extends v{static get observedAttributes(){return["api-url","project-id","theme","readonly"]}constructor(){super(),this._tasks=[],this._loading=!0,this._error=null,this._draggedTask=null,this._selectedTask=null,this._expandedCards=new Set,this._selectedTasks=new Set,this._bulkMode=!1,this._activeFilter="all",this._searchQuery="",this._visibleCounts={},this._api=null,this._state=N()}static get PAGE_SIZE(){return 10}_getVisibleCount(e){let t=this._visibleCounts[e];return typeof t=="number"&&t>0?t:d.PAGE_SIZE}_showMore(e){this._visibleCounts[e]=this._getVisibleCount(e)+d.PAGE_SIZE,this.render()}_columnIcon(e){switch(e){case"pending":return'<circle cx="12" cy="12" r="10"/>';case"in_progress":return'<path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83"/>';case"review":return'<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>';case"done":return'<path d="M22 11.08V12a10 10 0 11-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/>';default:return'<circle cx="12" cy="12" r="10"/>'}}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadTasks()}disconnectedCallback(){super.disconnectedCallback(),this._teardownApiListeners()}_teardownApiListeners(){this._api&&this._onTaskEvent&&(this._api.removeEventListener(f.TASK_CREATED,this._onTaskEvent),this._api.removeEventListener(f.TASK_UPDATED,this._onTaskEvent),this._api.removeEventListener(f.TASK_DELETED,this._onTaskEvent))}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._teardownApiListeners(),this._setupApi(),this._loadTasks()),e==="project-id"&&this._loadTasks(),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e}),this._onTaskEvent=()=>this._loadTasks(),this._api.addEventListener(f.TASK_CREATED,this._onTaskEvent),this._api.addEventListener(f.TASK_UPDATED,this._onTaskEvent),this._api.addEventListener(f.TASK_DELETED,this._onTaskEvent)}async _loadTasks(){let e=this._api;this._loading=!0,this._error=null,this.render();try{let t=this.getAttribute("project-id"),i=t?{projectId:parseInt(t)}:{},a=await e.listTasks(i);if(e!==this._api)return;this._tasks=a;let s=this._state.get("localTasks")||[];s.length>0&&(this._tasks=[...this._tasks,...s.map(r=>({...r,isLocal:!0}))]),this._state.update({"cache.tasks":this._tasks},!1)}catch(t){if(e!==this._api)return;this._error=t.message,this._tasks=(this._state.get("localTasks")||[]).map(i=>({...i,isLocal:!0}))}this._loading=!1,this.render()}_getTasksByStatus(e){return this._getFilteredTasks().filter(i=>i.status?.toLowerCase().replace(/-/g,"_")===e)}_handleDragStart(e,t){this.hasAttribute("readonly")||(this._draggedTask=t,e.target.classList.add("dragging"),e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("text/plain",t.id.toString()))}_handleDragEnd(e){e.target.classList.remove("dragging"),this._draggedTask=null,this.shadowRoot.querySelectorAll(".kanban-tasks").forEach(t=>{t.classList.remove("drag-over")})}_handleDragOver(e){e.preventDefault(),e.dataTransfer.dropEffect="move"}_handleDragEnter(e){e.preventDefault(),e.currentTarget.classList.add("drag-over")}_handleDragLeave(e){e.currentTarget.contains(e.relatedTarget)||e.currentTarget.classList.remove("drag-over")}async _handleDrop(e,t){if(e.preventDefault(),e.currentTarget.classList.remove("drag-over"),!this._draggedTask||this.hasAttribute("readonly"))return;let i=this._draggedTask.id,a=this._tasks.find(r=>r.id===i);if(!a)return;let s=a.status;if(s!==t){a.status=t,this.render();try{a.isLocal?this._state.moveLocalTask(i,t):await this._api.moveTask(i,t,0),this.dispatchEvent(new CustomEvent("task-moved",{detail:{taskId:i,oldStatus:s,newStatus:t}}))}catch(r){a.status=s,this.render(),console.error("Failed to move task:",r)}}}_toggleCardExpand(e){this._expandedCards.has(e)?this._expandedCards.delete(e):this._expandedCards.add(e),this.render()}_toggleTaskSelection(e,t){t&&t.stopPropagation(),this._selectedTasks.has(e)?this._selectedTasks.delete(e):this._selectedTasks.add(e),this.render()}_toggleBulkMode(){this._bulkMode=!this._bulkMode,this._bulkMode||this._selectedTasks.clear(),this.render()}async _bulkMove(e){let t=[...this._selectedTasks];for(let i of t){let a=this._tasks.find(s=>String(s.id)===String(i));if(a&&a.status!==e)try{a.isLocal?this._state.moveLocalTask(i,e):await this._api.moveTask(i,e,0),a.status=e}catch(s){console.error("Failed to bulk move task:",i,s)}}this._selectedTasks.clear(),this._bulkMode=!1,this.render(),this._loadTasks()}async _bulkDelete(){let e=[...this._selectedTasks];for(let t of e)try{await this._api.deleteTask(t)}catch(i){console.error("Failed to delete task:",t,i)}this._selectedTasks.clear(),this._bulkMode=!1,this._loadTasks()}_setFilter(e){this._activeFilter=e,this._visibleCounts={},this.render()}_setSearch(e){this._searchQuery=e||"",this._visibleCounts={},this._renderTaskRegion();let t=this.shadowRoot.getElementById("task-search");if(t){t.focus();let i=t.value.length;try{t.setSelectionRange(i,i)}catch{}}}_getFilteredTasks(){let e=[...this._tasks],t=new Date,i=new Date(t.getFullYear(),t.getMonth(),t.getDate()),a=new Date(i.getTime()-7*24*60*60*1e3);switch(this._activeFilter){case"today":e=e.filter(r=>{let o=r.created_at?new Date(r.created_at):null;return o&&o>=i});break;case"this-week":e=e.filter(r=>{let o=r.created_at?new Date(r.created_at):null;return o&&o>=a});break;case"running":e=e.filter(r=>r.status==="in_progress");break;case"failed":e=e.filter(r=>r.status==="failed"||r.status==="error");break;default:break}let s=this._searchQuery.trim().toLowerCase();return s&&(e=e.filter(r=>[r.id,r.title,r.description,r.type].map(n=>String(n??"").toLowerCase()).join(" ").includes(s))),e}_openAddTaskModal(e="pending"){this.dispatchEvent(new CustomEvent("add-task",{detail:{status:e}}))}_openTaskDetail(e){this._selectedTask=e,this.render(),this.dispatchEvent(new CustomEvent("task-click",{detail:{task:e}}))}_closeTaskDetail(){this._selectedTask=null,this.render()}_renderMarkdown(e){return C(e)}_formatTimestamp(e){if(!e)return"";try{let t=new Date(e);return isNaN(t.getTime())?this._escapeHtml(String(e)):t.toLocaleString()}catch{return this._escapeHtml(String(e))}}_phaseClass(e){let t=String(e||"").toLowerCase();return["reason","plan","planning"].includes(t)?"phase-reason":["act","execute","execution","implement"].includes(t)?"phase-act":["reflect","review"].includes(t)?"phase-reflect":["verify","test","gate"].includes(t)?"phase-verify":"phase-default"}_logLevelClass(e){let t=String(e||"info").toLowerCase();return t==="error"||t==="fatal"?"log-error":t==="warn"||t==="warning"?"log-warn":t==="debug"||t==="trace"?"log-debug":"log-info"}_renderTaskDetailModal(e){if(!e)return"";let t=(e.priority||"medium").toLowerCase(),i=t.charAt(0).toUpperCase()+t.slice(1),a=e.status||"pending",s=a.replace(/_/g," ").replace(/\b\w/g,g=>g.toUpperCase()),r=e.metadata||{},o=Array.isArray(e.acceptance_criteria)?e.acceptance_criteria:[],n=Array.isArray(e.context_files)?e.context_files:[],l=e.specification||"",c=e.description||"",p=Array.isArray(e.notes)?e.notes:[],u=Array.isArray(e.logs)?e.logs:[],m=e.full_content||"";return`
2698
2700
  <div class="modal-overlay" id="task-detail-overlay">
2699
2701
  <div class="modal-container">
2700
2702
  <div class="modal-header">
@@ -2711,10 +2713,10 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
2711
2713
  <div class="modal-section">
2712
2714
  <h3 class="modal-section-title">Metadata</h3>
2713
2715
  <div class="meta-grid">
2714
- ${Object.entries(r).map(([g,x])=>`
2716
+ ${Object.entries(r).map(([g,k])=>`
2715
2717
  <div class="meta-cell">
2716
2718
  <span class="meta-label">${this._escapeHtml(g.replace(/_/g," "))}</span>
2717
- <span class="meta-value">${this._escapeHtml(String(x))}</span>
2719
+ <span class="meta-value">${this._escapeHtml(String(k))}</span>
2718
2720
  </div>
2719
2721
  `).join("")}
2720
2722
  </div>
@@ -2739,9 +2741,9 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
2739
2741
  <div class="modal-section">
2740
2742
  <h3 class="modal-section-title">Acceptance Criteria</h3>
2741
2743
  <ul class="criteria-checklist" role="list">
2742
- ${o.map(g=>{let x=g&&typeof g=="object",k=x?g.text||g.title||"":g,_=x?!!g.done:!1;return`<li class="criteria-item">
2744
+ ${o.map(g=>{let k=g&&typeof g=="object",x=k?g.text||g.title||"":g,_=k?!!g.done:!1;return`<li class="criteria-item">
2743
2745
  <span class="criteria-checkbox ${_?"checked":""}" aria-hidden="true">${_?"&#10003;":""}</span>
2744
- <span class="criteria-text ${_?"done":""}">${this._escapeHtml(String(k))}</span>
2746
+ <span class="criteria-text ${_?"done":""}">${this._escapeHtml(String(x))}</span>
2745
2747
  </li>`}).join("")}
2746
2748
  </ul>
2747
2749
  </div>
@@ -2751,10 +2753,10 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
2751
2753
  <div class="modal-section">
2752
2754
  <h3 class="modal-section-title">Notes</h3>
2753
2755
  <ul class="notes-timeline" role="list">
2754
- ${p.map(g=>{let x=this._formatTimestamp(g&&g.timestamp),k=g&&g.author?this._escapeHtml(String(g.author)):"unknown",_=g&&g.body?this._escapeHtml(String(g.body)):"";return`<li class="note-entry">
2756
+ ${p.map(g=>{let k=this._formatTimestamp(g&&g.timestamp),x=g&&g.author?this._escapeHtml(String(g.author)):"unknown",_=g&&g.body?this._escapeHtml(String(g.body)):"";return`<li class="note-entry">
2755
2757
  <div class="note-meta">
2756
- <span class="note-author">${k}</span>
2757
- ${x?`<span class="note-time">${x}</span>`:""}
2758
+ <span class="note-author">${x}</span>
2759
+ ${k?`<span class="note-time">${k}</span>`:""}
2758
2760
  </div>
2759
2761
  <div class="note-body">${_}</div>
2760
2762
  </li>`}).join("")}
@@ -2767,10 +2769,10 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
2767
2769
  <h3 class="modal-section-title">Logs</h3>
2768
2770
  <div class="logs-scroll">
2769
2771
  <ul class="logs-timeline" role="list">
2770
- ${u.map(g=>{let x=this._formatTimestamp(g&&g.timestamp),k=g&&g.iteration!==void 0&&g.iteration!==null?`i${this._escapeHtml(String(g.iteration))}`:"",_=g&&g.phase?String(g.phase):"",H=this._phaseClass(_),K=this._logLevelClass(g&&g.level),V=g&&g.message?this._escapeHtml(String(g.message)):"";return`<li class="log-entry ${K}">
2771
- ${x?`<span class="log-time">${x}</span>`:""}
2772
- ${k?`<span class="log-iter">${k}</span>`:""}
2773
- ${_?`<span class="log-phase ${H}">${this._escapeHtml(_)}</span>`:""}
2772
+ ${u.map(g=>{let k=this._formatTimestamp(g&&g.timestamp),x=g&&g.iteration!==void 0&&g.iteration!==null?`i${this._escapeHtml(String(g.iteration))}`:"",_=g&&g.phase?String(g.phase):"",D=this._phaseClass(_),J=this._logLevelClass(g&&g.level),V=g&&g.message?this._escapeHtml(String(g.message)):"";return`<li class="log-entry ${J}">
2773
+ ${k?`<span class="log-time">${k}</span>`:""}
2774
+ ${x?`<span class="log-iter">${x}</span>`:""}
2775
+ ${_?`<span class="log-phase ${D}">${this._escapeHtml(_)}</span>`:""}
2774
2776
  <span class="log-message">${V}</span>
2775
2777
  </li>`}).join("")}
2776
2778
  </ul>
@@ -3296,7 +3298,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
3296
3298
  (.md-quote, .md-hr, .md-link, .md-h5/h6, strong) is themed. The
3297
3299
  task-board overrides below have equal specificity and come after, so
3298
3300
  they still win on the classes they target (compact fonts/margins). */
3299
- ${L}
3301
+ ${z}
3300
3302
 
3301
3303
  /* Markdown body inside Description section (compact overrides) */
3302
3304
  .md-body .md-h2 { font-size: 14px; margin: 8px 0 4px; color: var(--loki-text-primary); }
@@ -3816,7 +3818,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
3816
3818
  `:""}
3817
3819
 
3818
3820
  <div class="kanban-board">
3819
- ${Ft.map(a=>{let s=this._getTasksByStatus(a.status),r=this._getVisibleCount(a.status),o=s.slice(0,r),n=s.length-o.length;return`
3821
+ ${St.map(a=>{let s=this._getTasksByStatus(a.status),r=this._getVisibleCount(a.status),o=s.slice(0,r),n=s.length-o.length;return`
3820
3822
  <div class="kanban-column" data-status="${a.status}">
3821
3823
  <div class="kanban-column-header">
3822
3824
  <span class="kanban-column-title">
@@ -3880,7 +3882,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
3880
3882
  </div>
3881
3883
  `}).join("")}
3882
3884
  </div>
3883
- `}}_attachEventListeners(){let e=this.shadowRoot.getElementById("refresh-btn");e&&e.addEventListener("click",()=>this._loadTasks());let t=this.shadowRoot.getElementById("bulk-toggle-btn");t&&t.addEventListener("click",()=>this._toggleBulkMode()),this.shadowRoot.querySelectorAll(".filter-pill").forEach(r=>{r.addEventListener("click",()=>this._setFilter(r.dataset.filter))});let i=this.shadowRoot.getElementById("task-search");i&&i.addEventListener("input",r=>this._setSearch(r.target.value)),this.shadowRoot.querySelectorAll(".show-more-btn").forEach(r=>{r.addEventListener("click",()=>this._showMore(r.dataset.showMore))}),this.shadowRoot.querySelectorAll(".bulk-btn").forEach(r=>{r.addEventListener("click",()=>{let o=r.dataset.bulkAction;o==="delete"?this._bulkDelete():this._bulkMove(o)})}),this.shadowRoot.querySelectorAll(".add-task-btn").forEach(r=>{r.addEventListener("click",()=>{this._openAddTaskModal(r.dataset.status)})}),this.shadowRoot.querySelectorAll(".task-checkbox").forEach(r=>{r.addEventListener("click",o=>{o.stopPropagation(),this._toggleTaskSelection(r.dataset.checkId,o)})}),this.shadowRoot.querySelectorAll(".expand-toggle").forEach(r=>{r.addEventListener("click",o=>{o.stopPropagation(),this._toggleCardExpand(r.dataset.expandId)})}),this.shadowRoot.querySelectorAll(".task-card").forEach(r=>{let o=r.dataset.taskId,n=this._tasks.find(l=>l.id.toString()===o);n&&(r.addEventListener("click",l=>{if(this._bulkMode){this._toggleTaskSelection(o,l);return}this._openTaskDetail(n)}),r.addEventListener("keydown",l=>{l.key==="Enter"||l.key===" "?(l.preventDefault(),this._bulkMode?this._toggleTaskSelection(o,l):this._openTaskDetail(n)):(l.key==="ArrowDown"||l.key==="ArrowUp")&&(l.preventDefault(),this._navigateTaskCards(r,l.key==="ArrowDown"?"next":"prev"))}),r.classList.contains("draggable")&&(r.addEventListener("dragstart",l=>this._handleDragStart(l,n)),r.addEventListener("dragend",l=>this._handleDragEnd(l))))}),this.shadowRoot.querySelectorAll(".kanban-tasks").forEach(r=>{r.addEventListener("dragover",o=>this._handleDragOver(o)),r.addEventListener("dragenter",o=>this._handleDragEnter(o)),r.addEventListener("dragleave",o=>this._handleDragLeave(o)),r.addEventListener("drop",o=>this._handleDrop(o,r.dataset.status))});let a=this.shadowRoot.getElementById("modal-close-btn");a&&a.addEventListener("click",()=>this._closeTaskDetail());let s=this.shadowRoot.getElementById("task-detail-overlay");s&&s.addEventListener("click",r=>{r.target===s&&this._closeTaskDetail()})}_escapeHtml(e){let t=document.createElement("div");return t.textContent=e,t.innerHTML}_navigateTaskCards(e,t){let i=Array.from(this.shadowRoot.querySelectorAll(".task-card")),a=i.indexOf(e);if(a===-1)return;let s=t==="next"?a+1:a-1;s>=0&&s<i.length&&i[s].focus()}};customElements.get("loki-task-board")||customElements.define("loki-task-board",Z);var ee=class d extends v{static get observedAttributes(){return["api-url","theme","compact"]}constructor(){super(),this._status={mode:"offline",phase:null,iteration:null,complexity:null,connected:!1,version:null,uptime:0,activeAgents:0,pendingTasks:0},this._model={override:null,default:"sonnet",effective:"sonnet",notice:"",provider:"claude",switchable:!0,offers:[]},this._modelBusy=!1,this._startBusy=!1,this._startNotice="",this._specText="",this._startModel="",this._advisorModel="",this._api=null,this._state=N(),this._statusUpdateHandler=null,this._connectedHandler=null,this._disconnectedHandler=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadStatus(),this._loadModel(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling(),this._teardownApiListeners()}_teardownApiListeners(){this._api&&(this._statusUpdateHandler&&this._api.removeEventListener(f.STATUS_UPDATE,this._statusUpdateHandler),this._connectedHandler&&this._api.removeEventListener(f.CONNECTED,this._connectedHandler),this._disconnectedHandler&&this._api.removeEventListener(f.DISCONNECTED,this._disconnectedHandler))}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._teardownApiListeners(),this._setupApi(),this._loadStatus(),this._loadModel()),e==="theme"&&this._applyTheme(),e==="compact"&&this.render())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e}),this._statusUpdateHandler=t=>this._updateFromStatus(t.detail),this._connectedHandler=()=>{this._status.connected=!0,this.render()},this._disconnectedHandler=()=>{this._status.connected=!1,this._status.mode="offline",this.render()},this._api.addEventListener(f.STATUS_UPDATE,this._statusUpdateHandler),this._api.addEventListener(f.CONNECTED,this._connectedHandler),this._api.addEventListener(f.DISCONNECTED,this._disconnectedHandler)}async _loadStatus(){let e=this._api;try{let t=await e.getStatus();if(e!==this._api)return;this._updateFromStatus(t)}catch{if(e!==this._api)return;this._status.connected=!1,this._status.mode="offline",this.render()}}_updateFromStatus(e){e&&(this._status={...this._status,connected:!0,mode:e.status||"running",version:e.version,uptime:e.uptime_seconds||0,activeAgents:e.running_agents||0,pendingTasks:e.pending_tasks||0,phase:e.phase,iteration:e.iteration,complexity:e.complexity},this._state.updateSession({connected:!0,mode:this._status.mode,lastSync:new Date().toISOString()}),this.render())}_startPolling(){this._poll=b({loadFn:()=>this._loadStatus(),intervalMs:3e3,sectionId:null,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_formatUptime(e){if(!e||e<0)return"--";let t=Math.floor(e/3600),i=Math.floor(e%3600/60),a=Math.floor(e%60);return t>0?`${t}h ${i}m`:i>0?`${i}m ${a}s`:`${a}s`}_escapeHtml(e){let t=document.createElement("div");return t.textContent=String(e??""),t.innerHTML}_getStatusClass(){switch(this._status.mode){case"running":case"autonomous":return"active";case"paused":return"paused";case"stopped":return"stopped";case"error":return"error";default:return"offline"}}_getStatusLabel(){switch(this._status.mode){case"running":case"autonomous":return"AUTONOMOUS";case"paused":return"PAUSED";case"stopped":return"STOPPED";case"error":return"ERROR";default:return"OFFLINE"}}async _triggerStart(){if(this._startBusy)return;let e=(this._specText||"").trim();if(!e){this._startNotice="Enter a spec or one-line brief to start a build.",this.render();return}if(!this._api||typeof this._api.startSession!="function"){this._startNotice="Start is not available on this server.",this.render();return}this._startBusy=!0,this._startNotice="Starting build...",this.render();try{let t=await this._api.startSession(e,{provider:this._status.provider||"claude",model:this._startModel||"",advisorModel:this._advisorModel||""});if(t&&t.error)throw new Error(t.error);this._startBusy=!1,this._startNotice="",this._specText="",this._status.mode="running",this._status.connected=!0,this.render(),this._loadStatus(),this.dispatchEvent(new CustomEvent("session-start",{detail:{...this._status,pid:t&&t.pid,spec:t&&t.spec}}))}catch(t){console.error("Failed to start build:",t),this._startBusy=!1,this._startNotice=t&&t.message?`Could not start: ${t.message}`:"Could not start the build. Try again.",this.render()}}_onSpecInput(e){this._specText=e}async _triggerPause(){try{let e=await this._api.pauseSession();if(e&&e.error)throw new Error(e.error);this._status.mode="paused",this.render(),this.dispatchEvent(new CustomEvent("session-pause",{detail:this._status}))}catch(e){console.error("Failed to pause session:",e),this.render()}}async _triggerResume(){try{let e=await this._api.resumeSession();if(e&&e.error)throw new Error(e.error);this._status.mode="running",this.render(),this.dispatchEvent(new CustomEvent("session-resume",{detail:this._status}))}catch(e){console.error("Failed to resume session:",e),this.render()}}async _triggerStop(){try{let e=await this._api.stopSession();if(e&&e.error)throw new Error(e.error);this._status.mode="stopped",this.render(),this.dispatchEvent(new CustomEvent("session-stop",{detail:this._status}))}catch(e){console.error("Failed to stop session:",e),this.render()}}async _loadModel(){if(!this._api||typeof this._api.getSessionModel!="function")return;let e=this._api;try{let t=await e.getSessionModel();if(e!==this._api)return;t&&!t.error&&(this._model={...this._model,override:t.override??null,default:t.default||"sonnet",effective:t.effective||t.default||"sonnet",provider:t.provider||"claude",switchable:t.switchable!==!1,offers:Array.isArray(t.offers)?t.offers:[]},this.render())}catch{}}async _onModelChange(e){if(this._modelBusy)return;this._modelBusy=!0;let t=e===""?null:e;try{let i=await this._api.setSessionModel(t);if(i&&i.error)throw new Error(i.error);this._model.override=t,this._model.notice=t?`Switching to ${t}. Applies from the next iteration, for the current run only.`:"Override cleared. Reverts to the tier mapping from the next iteration.",this._modelBusy=!1,await this._loadModel()}catch(i){console.error("Failed to set session model:",i),this._model.notice="Could not change the model. Try again.",this._modelBusy=!1,this.render()}}static get MODEL_HINTS(){return{haiku:"fastest, cheapest",sonnet:"balanced",opus:"top coding",fable:"2x Opus cost: $10/$50 per MTok"}}_renderModelControl(){let e=this._model.override||"",t=this._model.offers,i=d.MODEL_HINTS,s=[{value:"",label:`Default (${this._model.default})`},...t.map(l=>{let c=i[l.value],p=c?`${l.value} (${c})`:l.value;return{value:l.value,label:l.model?`${p} -> ${l.model}`:p}})].map(l=>{let c=l.value===e?" selected":"";return`<option value="${this._escapeHtml(l.value)}"${c}>${this._escapeHtml(l.label)}</option>`}).join(""),r=this._model.effective==="fable",o=this._model.switchable===!1;return`
3885
+ `}}_attachEventListeners(){let e=this.shadowRoot.getElementById("refresh-btn");e&&e.addEventListener("click",()=>this._loadTasks());let t=this.shadowRoot.getElementById("bulk-toggle-btn");t&&t.addEventListener("click",()=>this._toggleBulkMode()),this.shadowRoot.querySelectorAll(".filter-pill").forEach(r=>{r.addEventListener("click",()=>this._setFilter(r.dataset.filter))});let i=this.shadowRoot.getElementById("task-search");i&&i.addEventListener("input",r=>this._setSearch(r.target.value)),this.shadowRoot.querySelectorAll(".show-more-btn").forEach(r=>{r.addEventListener("click",()=>this._showMore(r.dataset.showMore))}),this.shadowRoot.querySelectorAll(".bulk-btn").forEach(r=>{r.addEventListener("click",()=>{let o=r.dataset.bulkAction;o==="delete"?this._bulkDelete():this._bulkMove(o)})}),this.shadowRoot.querySelectorAll(".add-task-btn").forEach(r=>{r.addEventListener("click",()=>{this._openAddTaskModal(r.dataset.status)})}),this.shadowRoot.querySelectorAll(".task-checkbox").forEach(r=>{r.addEventListener("click",o=>{o.stopPropagation(),this._toggleTaskSelection(r.dataset.checkId,o)})}),this.shadowRoot.querySelectorAll(".expand-toggle").forEach(r=>{r.addEventListener("click",o=>{o.stopPropagation(),this._toggleCardExpand(r.dataset.expandId)})}),this.shadowRoot.querySelectorAll(".task-card").forEach(r=>{let o=r.dataset.taskId,n=this._tasks.find(l=>l.id.toString()===o);n&&(r.addEventListener("click",l=>{if(this._bulkMode){this._toggleTaskSelection(o,l);return}this._openTaskDetail(n)}),r.addEventListener("keydown",l=>{l.key==="Enter"||l.key===" "?(l.preventDefault(),this._bulkMode?this._toggleTaskSelection(o,l):this._openTaskDetail(n)):(l.key==="ArrowDown"||l.key==="ArrowUp")&&(l.preventDefault(),this._navigateTaskCards(r,l.key==="ArrowDown"?"next":"prev"))}),r.classList.contains("draggable")&&(r.addEventListener("dragstart",l=>this._handleDragStart(l,n)),r.addEventListener("dragend",l=>this._handleDragEnd(l))))}),this.shadowRoot.querySelectorAll(".kanban-tasks").forEach(r=>{r.addEventListener("dragover",o=>this._handleDragOver(o)),r.addEventListener("dragenter",o=>this._handleDragEnter(o)),r.addEventListener("dragleave",o=>this._handleDragLeave(o)),r.addEventListener("drop",o=>this._handleDrop(o,r.dataset.status))});let a=this.shadowRoot.getElementById("modal-close-btn");a&&a.addEventListener("click",()=>this._closeTaskDetail());let s=this.shadowRoot.getElementById("task-detail-overlay");s&&s.addEventListener("click",r=>{r.target===s&&this._closeTaskDetail()})}_escapeHtml(e){let t=document.createElement("div");return t.textContent=e,t.innerHTML}_navigateTaskCards(e,t){let i=Array.from(this.shadowRoot.querySelectorAll(".task-card")),a=i.indexOf(e);if(a===-1)return;let s=t==="next"?a+1:a-1;s>=0&&s<i.length&&i[s].focus()}};customElements.get("loki-task-board")||customElements.define("loki-task-board",X);var Z=class d extends v{static get observedAttributes(){return["api-url","theme","compact"]}constructor(){super(),this._status={mode:"offline",phase:null,iteration:null,complexity:null,connected:!1,version:null,uptime:0,activeAgents:null,pendingTasks:null},this._model={override:null,default:"sonnet",effective:"sonnet",notice:"",provider:"claude",switchable:!0,offers:[]},this._modelBusy=!1,this._startBusy=!1,this._startNotice="",this._specText="",this._startModel="",this._advisorModel="",this._api=null,this._state=N(),this._statusUpdateHandler=null,this._connectedHandler=null,this._disconnectedHandler=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadStatus(),this._loadModel(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling(),this._teardownApiListeners()}_teardownApiListeners(){this._api&&(this._statusUpdateHandler&&this._api.removeEventListener(f.STATUS_UPDATE,this._statusUpdateHandler),this._connectedHandler&&this._api.removeEventListener(f.CONNECTED,this._connectedHandler),this._disconnectedHandler&&this._api.removeEventListener(f.DISCONNECTED,this._disconnectedHandler))}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._teardownApiListeners(),this._setupApi(),this._loadStatus(),this._loadModel()),e==="theme"&&this._applyTheme(),e==="compact"&&this.render())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e}),this._statusUpdateHandler=t=>this._updateFromStatus(t.detail),this._connectedHandler=()=>{this._status.connected=!0,this.render()},this._disconnectedHandler=()=>{this._status.connected=!1,this._status.mode="offline",this.render()},this._api.addEventListener(f.STATUS_UPDATE,this._statusUpdateHandler),this._api.addEventListener(f.CONNECTED,this._connectedHandler),this._api.addEventListener(f.DISCONNECTED,this._disconnectedHandler)}async _loadStatus(){let e=this._api;try{let t=await e.getStatus();if(e!==this._api)return;this._updateFromStatus(t)}catch{if(e!==this._api)return;this._status.connected=!1,this._status.mode="offline",this._status.activeAgents=null,this._status.pendingTasks=null,this.render()}}_updateFromStatus(e){e&&(this._status={...this._status,connected:!0,mode:e.status||"running",version:e.version,uptime:e.uptime_seconds||0,activeAgents:e.running_agents??null,pendingTasks:e.pending_tasks??null,phase:e.phase,iteration:e.iteration,complexity:e.complexity},this._state.updateSession({connected:!0,mode:this._status.mode,lastSync:new Date().toISOString()}),this.render())}_startPolling(){this._poll=b({loadFn:()=>this._loadStatus(),intervalMs:3e3,sectionId:null,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_formatUptime(e){if(!e||e<0)return"--";let t=Math.floor(e/3600),i=Math.floor(e%3600/60),a=Math.floor(e%60);return t>0?`${t}h ${i}m`:i>0?`${i}m ${a}s`:`${a}s`}_escapeHtml(e){let t=document.createElement("div");return t.textContent=String(e??""),t.innerHTML}_getStatusClass(){switch(this._status.mode){case"running":case"autonomous":return"active";case"paused":return"paused";case"stopped":return"stopped";case"error":return"error";default:return"offline"}}_getStatusLabel(){switch(this._status.mode){case"running":case"autonomous":return"AUTONOMOUS";case"paused":return"PAUSED";case"stopped":return"STOPPED";case"error":return"ERROR";default:return"OFFLINE"}}async _triggerStart(){if(this._startBusy)return;let e=(this._specText||"").trim();if(!e){this._startNotice="Enter a spec or one-line brief to start a build.",this.render();return}if(!this._api||typeof this._api.startSession!="function"){this._startNotice="Start is not available on this server.",this.render();return}this._startBusy=!0,this._startNotice="Starting build...",this.render();try{let t=await this._api.startSession(e,{provider:this._status.provider||"claude",model:this._startModel||"",advisorModel:this._advisorModel||""});if(t&&t.error)throw new Error(t.error);this._startBusy=!1,this._startNotice="",this._specText="",this._status.mode="running",this._status.connected=!0,this.render(),this._loadStatus(),this.dispatchEvent(new CustomEvent("session-start",{detail:{...this._status,pid:t&&t.pid,spec:t&&t.spec}}))}catch(t){console.error("Failed to start build:",t),this._startBusy=!1,this._startNotice=t&&t.message?`Could not start: ${t.message}`:"Could not start the build. Try again.",this.render()}}_onSpecInput(e){this._specText=e}async _triggerPause(){try{let e=await this._api.pauseSession();if(e&&e.error)throw new Error(e.error);this._status.mode="paused",this.render(),this.dispatchEvent(new CustomEvent("session-pause",{detail:this._status}))}catch(e){console.error("Failed to pause session:",e),this.render()}}async _triggerResume(){try{let e=await this._api.resumeSession();if(e&&e.error)throw new Error(e.error);this._status.mode="running",this.render(),this.dispatchEvent(new CustomEvent("session-resume",{detail:this._status}))}catch(e){console.error("Failed to resume session:",e),this.render()}}async _triggerStop(){try{let e=await this._api.stopSession();if(e&&e.error)throw new Error(e.error);this._status.mode="stopped",this.render(),this.dispatchEvent(new CustomEvent("session-stop",{detail:this._status}))}catch(e){console.error("Failed to stop session:",e),this.render()}}async _loadModel(){if(!this._api||typeof this._api.getSessionModel!="function")return;let e=this._api;try{let t=await e.getSessionModel();if(e!==this._api)return;t&&!t.error&&(this._model={...this._model,override:t.override??null,default:t.default||"sonnet",effective:t.effective||t.default||"sonnet",provider:t.provider||"claude",switchable:t.switchable!==!1,offers:Array.isArray(t.offers)?t.offers:[]},this.render())}catch{}}async _onModelChange(e){if(this._modelBusy)return;this._modelBusy=!0;let t=e===""?null:e;try{let i=await this._api.setSessionModel(t);if(i&&i.error)throw new Error(i.error);this._model.override=t,this._model.notice=t?`Switching to ${t}. Applies from the next iteration, for the current run only.`:"Override cleared. Reverts to the tier mapping from the next iteration.",this._modelBusy=!1,await this._loadModel()}catch(i){console.error("Failed to set session model:",i),this._model.notice="Could not change the model. Try again.",this._modelBusy=!1,this.render()}}static get MODEL_HINTS(){return{haiku:"fastest, cheapest",sonnet:"balanced",opus:"top coding",fable:"2x Opus cost: $10/$50 per MTok"}}_renderModelControl(){let e=this._model.override||"",t=this._model.offers,i=d.MODEL_HINTS,s=[{value:"",label:`Default (${this._model.default})`},...t.map(l=>{let c=i[l.value],p=c?`${l.value} (${c})`:l.value;return{value:l.value,label:l.model?`${p} -> ${l.model}`:p}})].map(l=>{let c=l.value===e?" selected":"";return`<option value="${this._escapeHtml(l.value)}"${c}>${this._escapeHtml(l.label)}</option>`}).join(""),r=this._model.effective==="fable",o=this._model.switchable===!1;return`
3884
3886
  <div class="model-control">
3885
3887
  <div class="model-row">
3886
3888
  <label for="model-select">Model</label>
@@ -4319,11 +4321,11 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
4319
4321
 
4320
4322
  <div class="stats-row">
4321
4323
  <div class="stat-item">
4322
- <div class="stat-value">${this._status.activeAgents}</div>
4324
+ <div class="stat-value">${this._escapeHtml(this._status.activeAgents??"--")}</div>
4323
4325
  <div class="stat-label">Agents running</div>
4324
4326
  </div>
4325
4327
  <div class="stat-item">
4326
- <div class="stat-value">${this._status.pendingTasks}</div>
4328
+ <div class="stat-value">${this._escapeHtml(this._status.pendingTasks??"--")}</div>
4327
4329
  <div class="stat-label">Tasks queued</div>
4328
4330
  </div>
4329
4331
  </div>
@@ -4331,9 +4333,9 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
4331
4333
  `,c=this.shadowRoot.activeElement,p=c&&c.id==="spec-input",u=p?c.selectionStart:null,m=p?c.selectionEnd:null;if(this.shadowRoot.innerHTML=`
4332
4334
  ${o}
4333
4335
  ${e?n:l}
4334
- `,this._attachEventListeners(),p){let g=this.shadowRoot.getElementById("spec-input");if(g&&!g.disabled){g.focus();try{g.setSelectionRange(u,m)}catch{}}}}_attachEventListeners(){let e=this.shadowRoot.getElementById("pause-btn"),t=this.shadowRoot.getElementById("resume-btn"),i=this.shadowRoot.getElementById("stop-btn"),a=this.shadowRoot.getElementById("start-btn");e&&e.addEventListener("click",()=>this._triggerPause()),t&&t.addEventListener("click",()=>this._triggerResume()),i&&i.addEventListener("click",()=>this._triggerStop()),a&&a.addEventListener("click",()=>this._triggerStart());let s=this.shadowRoot.getElementById("model-select");if(s){let l=()=>{this._modelInteracting=!1,this._renderPending&&(this._renderPending=!1,this.render())};s.addEventListener("mousedown",()=>{this._modelInteracting=!0}),s.addEventListener("focus",()=>{this._modelInteracting=!0}),s.addEventListener("blur",l),s.addEventListener("change",c=>{this._modelInteracting=!1,this._renderPending=!1,this._onModelChange(c.target.value)})}let r=this.shadowRoot.getElementById("spec-input");r&&r.addEventListener("input",l=>this._onSpecInput(l.target.value));let o=this.shadowRoot.getElementById("start-model-select");o&&(o.addEventListener("mousedown",()=>{this._modelInteracting=!0}),o.addEventListener("focus",()=>{this._modelInteracting=!0}),o.addEventListener("blur",()=>{this._modelInteracting=!1,this._renderPending&&(this._renderPending=!1,this.render())}),o.addEventListener("change",l=>{this._modelInteracting=!1,this._renderPending=!1,this._startModel=l.target.value}));let n=this.shadowRoot.getElementById("advisor-select");n&&(n.addEventListener("mousedown",()=>{this._modelInteracting=!0}),n.addEventListener("focus",()=>{this._modelInteracting=!0}),n.addEventListener("blur",()=>{this._modelInteracting=!1,this._renderPending&&(this._renderPending=!1,this.render())}),n.addEventListener("change",l=>{this._modelInteracting=!1,this._renderPending=!1,this._advisorModel=l.target.value}))}};customElements.get("loki-session-control")||customElements.define("loki-session-control",ee);var ut={info:{color:"var(--loki-blue)",label:"INFO"},success:{color:"var(--loki-green)",label:"SUCCESS"},warning:{color:"var(--loki-yellow)",label:"WARN"},error:{color:"var(--loki-red)",label:"ERROR"},step:{color:"var(--loki-purple)",label:"STEP"},agent:{color:"var(--loki-accent)",label:"AGENT"},debug:{color:"var(--loki-text-muted)",label:"DEBUG"}},te=class extends v{static get observedAttributes(){return["api-url","max-lines","auto-scroll","theme","log-file"]}constructor(){super(),this._logs=[],this._maxLines=500,this._autoScroll=!0,this._filter="",this._levelFilter="all",this._api=null,this._pollInterval=null,this._logMessageHandler=null,this._apiLastCount=0,this._apiLastSig=null,this._fileLastSize=0,this._fileLastSig=null}connectedCallback(){super.connectedCallback(),this._maxLines=parseInt(this.getAttribute("max-lines"))||500,this._autoScroll=this.hasAttribute("auto-scroll"),this._setupApi(),this._startLogPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopLogPolling(),this._teardownApiListeners()}_teardownApiListeners(){this._api&&this._logMessageHandler&&this._api.removeEventListener(f.LOG_MESSAGE,this._logMessageHandler)}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"api-url":this._api&&(this._teardownApiListeners(),this._logs=[],this._apiLastCount=0,this._apiLastSig=null,this._setupApi(),this.render());break;case"max-lines":this._maxLines=parseInt(i)||500,this._trimLogs(),this.render();break;case"auto-scroll":this._autoScroll=this.hasAttribute("auto-scroll"),this.render();break;case"theme":this._applyTheme();break}}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e}),this._logMessageHandler=t=>this._addLog(t.detail),this._api.addEventListener(f.LOG_MESSAGE,this._logMessageHandler)}_startLogPolling(){let e=this.getAttribute("log-file");e?this._pollLogFile(e):this._pollApiLogs()}async _pollApiLogs(){await this._apiLogPollTick(),this._poll=b({loadFn:()=>this._apiLogPollTick(),intervalMs:5e3,element:this,immediate:!1})}async _apiLogPollTick(){try{let e=await this._api.getLogs(200);if(!Array.isArray(e))return;let t=e.length?`${e.length}:${e[e.length-1]?.timestamp||""}:${e[e.length-1]?.message||""}`:"0";if(t===this._apiLastSig)return;if(this._apiLastSig=t,e.length>this._apiLastCount){let i=e.slice(this._apiLastCount);for(let a of i)a.message&&a.message.trim()&&this._addLog({message:a.message,level:a.level||"info",timestamp:a.timestamp||new Date().toLocaleTimeString()})}else e.length<this._apiLastCount&&(this._apiLastCount=0);this._apiLastCount=e.length}catch{}}async _pollLogFile(e){await this._fileLogPollTick(e),this._poll=b({loadFn:()=>this._fileLogPollTick(e),intervalMs:1e3,element:this,immediate:!1})}async _fileLogPollTick(e){try{let t=await fetch(`${e}?t=${Date.now()}`,{credentials:"include"});if(!t.ok)return;let i=await t.text(),a=`${i.length}`;if(a===this._fileLastSig)return;this._fileLastSig=a;let s=i.split(`
4336
+ `,this._attachEventListeners(),p){let g=this.shadowRoot.getElementById("spec-input");if(g&&!g.disabled){g.focus();try{g.setSelectionRange(u,m)}catch{}}}}_attachEventListeners(){let e=this.shadowRoot.getElementById("pause-btn"),t=this.shadowRoot.getElementById("resume-btn"),i=this.shadowRoot.getElementById("stop-btn"),a=this.shadowRoot.getElementById("start-btn");e&&e.addEventListener("click",()=>this._triggerPause()),t&&t.addEventListener("click",()=>this._triggerResume()),i&&i.addEventListener("click",()=>this._triggerStop()),a&&a.addEventListener("click",()=>this._triggerStart());let s=this.shadowRoot.getElementById("model-select");if(s){let l=()=>{this._modelInteracting=!1,this._renderPending&&(this._renderPending=!1,this.render())};s.addEventListener("mousedown",()=>{this._modelInteracting=!0}),s.addEventListener("focus",()=>{this._modelInteracting=!0}),s.addEventListener("blur",l),s.addEventListener("change",c=>{this._modelInteracting=!1,this._renderPending=!1,this._onModelChange(c.target.value)})}let r=this.shadowRoot.getElementById("spec-input");r&&r.addEventListener("input",l=>this._onSpecInput(l.target.value));let o=this.shadowRoot.getElementById("start-model-select");o&&(o.addEventListener("mousedown",()=>{this._modelInteracting=!0}),o.addEventListener("focus",()=>{this._modelInteracting=!0}),o.addEventListener("blur",()=>{this._modelInteracting=!1,this._renderPending&&(this._renderPending=!1,this.render())}),o.addEventListener("change",l=>{this._modelInteracting=!1,this._renderPending=!1,this._startModel=l.target.value}));let n=this.shadowRoot.getElementById("advisor-select");n&&(n.addEventListener("mousedown",()=>{this._modelInteracting=!0}),n.addEventListener("focus",()=>{this._modelInteracting=!0}),n.addEventListener("blur",()=>{this._modelInteracting=!1,this._renderPending&&(this._renderPending=!1,this.render())}),n.addEventListener("change",l=>{this._modelInteracting=!1,this._renderPending=!1,this._advisorModel=l.target.value}))}};customElements.get("loki-session-control")||customElements.define("loki-session-control",Z);var at={info:{color:"var(--loki-blue)",label:"INFO"},success:{color:"var(--loki-green)",label:"SUCCESS"},warning:{color:"var(--loki-yellow)",label:"WARN"},error:{color:"var(--loki-red)",label:"ERROR"},step:{color:"var(--loki-purple)",label:"STEP"},agent:{color:"var(--loki-accent)",label:"AGENT"},debug:{color:"var(--loki-text-muted)",label:"DEBUG"}},ee=class extends v{static get observedAttributes(){return["api-url","max-lines","auto-scroll","theme","log-file"]}constructor(){super(),this._logs=[],this._maxLines=500,this._autoScroll=!0,this._filter="",this._levelFilter="all",this._api=null,this._pollInterval=null,this._logMessageHandler=null,this._apiLastCount=0,this._apiLastSig=null,this._fileLastSize=0,this._fileLastSig=null}connectedCallback(){super.connectedCallback(),this._maxLines=parseInt(this.getAttribute("max-lines"))||500,this._autoScroll=this.hasAttribute("auto-scroll"),this._setupApi(),this._startLogPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopLogPolling(),this._teardownApiListeners()}_teardownApiListeners(){this._api&&this._logMessageHandler&&this._api.removeEventListener(f.LOG_MESSAGE,this._logMessageHandler)}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"api-url":this._api&&(this._teardownApiListeners(),this._logs=[],this._apiLastCount=0,this._apiLastSig=null,this._setupApi(),this.render());break;case"max-lines":this._maxLines=parseInt(i)||500,this._trimLogs(),this.render();break;case"auto-scroll":this._autoScroll=this.hasAttribute("auto-scroll"),this.render();break;case"theme":this._applyTheme();break}}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e}),this._logMessageHandler=t=>this._addLog(t.detail),this._api.addEventListener(f.LOG_MESSAGE,this._logMessageHandler)}_startLogPolling(){let e=this.getAttribute("log-file");e?this._pollLogFile(e):this._pollApiLogs()}async _pollApiLogs(){await this._apiLogPollTick(),this._poll=b({loadFn:()=>this._apiLogPollTick(),intervalMs:5e3,element:this,immediate:!1})}async _apiLogPollTick(){try{let e=await this._api.getLogs(200);if(!Array.isArray(e))return;let t=e.length?`${e.length}:${e[e.length-1]?.timestamp||""}:${e[e.length-1]?.message||""}`:"0";if(t===this._apiLastSig)return;if(this._apiLastSig=t,e.length>this._apiLastCount){let i=e.slice(this._apiLastCount);for(let a of i)a.message&&a.message.trim()&&this._addLog({message:a.message,level:a.level||"info",timestamp:a.timestamp||new Date().toLocaleTimeString()})}else e.length<this._apiLastCount&&(this._apiLastCount=0);this._apiLastCount=e.length}catch{}}async _pollLogFile(e){await this._fileLogPollTick(e),this._poll=b({loadFn:()=>this._fileLogPollTick(e),intervalMs:1e3,element:this,immediate:!1})}async _fileLogPollTick(e){try{let t=await fetch(`${e}?t=${Date.now()}`,{credentials:"include"});if(!t.ok)return;let i=await t.text(),a=`${i.length}`;if(a===this._fileLastSig)return;this._fileLastSig=a;let s=i.split(`
4335
4337
  `);if(s.length>this._fileLastSize){let r=s.slice(this._fileLastSize);for(let o of r)o.trim()&&this._addLog(this._parseLine(o))}else s.length<this._fileLastSize&&(this._fileLastSize=0);this._fileLastSize=s.length}catch{}}_stopLogPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_parseLine(e){let t=e.match(/^\[([^\]]+)\]\s*\[([^\]]+)\]\s*(.+)$/);if(t)return{timestamp:t[1],level:t[2].toLowerCase(),message:t[3]};let i=e.match(/^(\d{2}:\d{2}:\d{2})\s+(\w+)\s+(.+)$/);return i?{timestamp:i[1],level:i[2].toLowerCase(),message:i[3]}:{timestamp:new Date().toLocaleTimeString(),level:"info",message:e}}_addLog(e){if(!e)return;let t={id:Date.now()+Math.random(),timestamp:e.timestamp||new Date().toLocaleTimeString(),level:(e.level||"info").toLowerCase(),message:e.message||e};this._logs.push(t),this._trimLogs(),this.dispatchEvent(new CustomEvent("log-received",{detail:t})),this._renderLogs(),this._autoScroll&&this._scrollToBottom()}_trimLogs(){this._logs.length>this._maxLines&&(this._logs=this._logs.slice(-this._maxLines))}_clearLogs(){this._logs=[],this.dispatchEvent(new CustomEvent("logs-cleared")),this._renderLogs()}_toggleAutoScroll(){this._autoScroll=!this._autoScroll,this.render(),this._autoScroll&&this._scrollToBottom()}_scrollToBottom(){requestAnimationFrame(()=>{let e=this.shadowRoot.getElementById("log-output");e&&(e.scrollTop=e.scrollHeight)})}_downloadLogs(){let e=this._logs.map(s=>`[${s.timestamp}] [${s.level.toUpperCase()}] ${s.message}`).join(`
4336
- `),t=new Blob([e],{type:"text/plain"}),i=URL.createObjectURL(t),a=document.createElement("a");a.href=i,a.download=`loki-logs-${new Date().toISOString().split("T")[0]}.txt`,a.click(),URL.revokeObjectURL(i)}_setFilter(e){this._filter=e.toLowerCase(),this._renderLogs()}_setLevelFilter(e){this._levelFilter=e,this._renderLogs()}_getFilteredLogs(){return this._logs.filter(e=>!(this._levelFilter!=="all"&&e.level!==this._levelFilter||this._filter&&!e.message.toLowerCase().includes(this._filter)))}_renderLogs(){let e=this.shadowRoot.getElementById("log-output");if(!e)return;let t=this._getFilteredLogs();if(t.length===0){e.innerHTML='<div class="log-empty">No log output yet. Terminal will update when Loki Mode is running.</div>';return}e.innerHTML=t.map(i=>{let a=ut[i.level]||ut.info;return`
4338
+ `),t=new Blob([e],{type:"text/plain"}),i=URL.createObjectURL(t),a=document.createElement("a");a.href=i,a.download=`loki-logs-${new Date().toISOString().split("T")[0]}.txt`,a.click(),URL.revokeObjectURL(i)}_setFilter(e){this._filter=e.toLowerCase(),this._renderLogs()}_setLevelFilter(e){this._levelFilter=e,this._renderLogs()}_getFilteredLogs(){return this._logs.filter(e=>!(this._levelFilter!=="all"&&e.level!==this._levelFilter||this._filter&&!e.message.toLowerCase().includes(this._filter)))}_renderLogs(){let e=this.shadowRoot.getElementById("log-output");if(!e)return;let t=this._getFilteredLogs();if(t.length===0){e.innerHTML='<div class="log-empty">No log output yet. Terminal will update when Loki Mode is running.</div>';return}e.innerHTML=t.map(i=>{let a=at[i.level]||at.info;return`
4337
4339
  <div class="log-line">
4338
4340
  <span class="timestamp">${this._escapeHtml(i.timestamp)}</span>
4339
4341
  <span class="level" style="color: ${a.color}">[${this._escapeHtml(a.label)}]</span>
@@ -4532,7 +4534,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
4532
4534
  ${this._logs.length} lines (${this._getFilteredLogs().length} shown)
4533
4535
  </div>
4534
4536
  </div>
4535
- `,this._attachEventListeners(),this._renderLogs()}_attachEventListeners(){let e=this.shadowRoot.getElementById("filter-input"),t=this.shadowRoot.getElementById("level-select"),i=this.shadowRoot.getElementById("auto-scroll-btn"),a=this.shadowRoot.getElementById("clear-btn"),s=this.shadowRoot.getElementById("download-btn");e&&(e.value=this._filter,e.addEventListener("input",r=>this._setFilter(r.target.value))),t&&(t.value=this._levelFilter,t.addEventListener("change",r=>this._setLevelFilter(r.target.value))),i&&i.addEventListener("click",()=>this._toggleAutoScroll()),a&&a.addEventListener("click",()=>this._clearLogs()),s&&s.addEventListener("click",()=>this._downloadLogs())}addLog(e,t="info"){this._addLog({message:e,level:t,timestamp:new Date().toLocaleTimeString()})}clear(){this._clearLogs()}};customElements.get("loki-log-stream")||customElements.define("loki-log-stream",te);var jt=[{id:"summary",label:"Summary",icon:"M4 6h16M4 12h16M4 18h16"},{id:"search",label:"Search",icon:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"},{id:"episodes",label:"Episodes",icon:"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"},{id:"patterns",label:"Patterns",icon:"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"},{id:"skills",label:"Skills",icon:"M13 10V3L4 14h7v7l9-11h-7z"}],ie=class extends v{static get observedAttributes(){return["api-url","theme","tab"]}constructor(){super(),this._activeTab="summary",this._loading=!1,this._error=null,this._api=null,this._summary=null,this._stats=null,this._episodes=[],this._patterns=[],this._skills=[],this._tokenEconomics=null,this._selectedItem=null,this._lastFocusedElement=null,this._searchQuery="",this._searchCollection="all",this._searchResults=[],this._searchLoading=!1,this._searchError=null}connectedCallback(){super.connectedCallback(),this._activeTab=this.getAttribute("tab")||"summary",this._setupApi(),this._loadData()}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"api-url":this._api&&(this._api=h({baseUrl:i}),this._loadData());break;case"theme":this._applyTheme();break;case"tab":this._setTab(i);break}}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;this._loading=!0,this._error=null,this.render();try{let[t,i,a]=await Promise.allSettled([e.getMemorySummary(),e.getTokenEconomics(),e.getMemoryStats()]);if(e!==this._api||(this._summary=t.status==="fulfilled"?t.value:null,this._tokenEconomics=i.status==="fulfilled"?i.value:null,this._stats=a.status==="fulfilled"?a.value:null,await this._loadTabData(),e!==this._api))return}catch(t){if(e!==this._api)return;this._error=t.message||"Failed to load memory data"}this._loading=!1,this.render()}async _loadTabData(){let e=this._api;switch(this._activeTab){case"episodes":{let t=await e.listEpisodes({limit:50}).catch(()=>[]);if(e!==this._api)return;this._episodes=t;break}case"patterns":{let t=await e.listPatterns().catch(()=>[]);if(e!==this._api)return;this._patterns=t;break}case"skills":{let t=await e.listSkills().catch(()=>[]);if(e!==this._api)return;this._skills=t;break}}}_setTab(e){this._activeTab!==e&&(this._activeTab=e,this._selectedItem=null,this._loadTabData().then(()=>this.render()))}async _selectEpisode(e){let t=this._api;try{this._lastFocusedElement=this.shadowRoot.activeElement;let i=await t.getEpisode(e);if(t!==this._api)return;this._selectedItem=i,this.dispatchEvent(new CustomEvent("episode-select",{detail:this._selectedItem})),this.render(),this._focusDetailPanel()}catch(i){console.error("Failed to load episode:",i)}}async _selectPattern(e){let t=this._api;try{this._lastFocusedElement=this.shadowRoot.activeElement;let i=await t.getPattern(e);if(t!==this._api)return;this._selectedItem=i,this.dispatchEvent(new CustomEvent("pattern-select",{detail:this._selectedItem})),this.render(),this._focusDetailPanel()}catch(i){console.error("Failed to load pattern:",i)}}async _selectSkill(e){let t=this._api;try{this._lastFocusedElement=this.shadowRoot.activeElement;let i=await t.getSkill(e);if(t!==this._api)return;this._selectedItem=i,this.dispatchEvent(new CustomEvent("skill-select",{detail:this._selectedItem})),this.render(),this._focusDetailPanel()}catch(i){console.error("Failed to load skill:",i)}}_focusDetailPanel(){requestAnimationFrame(()=>{let e=this.shadowRoot.getElementById("close-detail");e&&e.focus()})}_closeDetail(){this._selectedItem=null,this.render(),this._lastFocusedElement&&requestAnimationFrame(()=>{this._lastFocusedElement.focus(),this._lastFocusedElement=null})}async _triggerConsolidation(){try{let e=await this._api.consolidateMemory(24);alert(`Consolidation complete:
4537
+ `,this._attachEventListeners(),this._renderLogs()}_attachEventListeners(){let e=this.shadowRoot.getElementById("filter-input"),t=this.shadowRoot.getElementById("level-select"),i=this.shadowRoot.getElementById("auto-scroll-btn"),a=this.shadowRoot.getElementById("clear-btn"),s=this.shadowRoot.getElementById("download-btn");e&&(e.value=this._filter,e.addEventListener("input",r=>this._setFilter(r.target.value))),t&&(t.value=this._levelFilter,t.addEventListener("change",r=>this._setLevelFilter(r.target.value))),i&&i.addEventListener("click",()=>this._toggleAutoScroll()),a&&a.addEventListener("click",()=>this._clearLogs()),s&&s.addEventListener("click",()=>this._downloadLogs())}addLog(e,t="info"){this._addLog({message:e,level:t,timestamp:new Date().toLocaleTimeString()})}clear(){this._clearLogs()}};customElements.get("loki-log-stream")||customElements.define("loki-log-stream",ee);var At=[{id:"summary",label:"Summary",icon:"M4 6h16M4 12h16M4 18h16"},{id:"search",label:"Search",icon:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"},{id:"episodes",label:"Episodes",icon:"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"},{id:"patterns",label:"Patterns",icon:"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"},{id:"skills",label:"Skills",icon:"M13 10V3L4 14h7v7l9-11h-7z"}],te=class extends v{static get observedAttributes(){return["api-url","theme","tab"]}constructor(){super(),this._activeTab="summary",this._loading=!1,this._error=null,this._api=null,this._summary=null,this._stats=null,this._episodes=[],this._patterns=[],this._skills=[],this._tokenEconomics=null,this._selectedItem=null,this._lastFocusedElement=null,this._searchQuery="",this._searchCollection="all",this._searchResults=[],this._searchLoading=!1,this._searchError=null}connectedCallback(){super.connectedCallback(),this._activeTab=this.getAttribute("tab")||"summary",this._setupApi(),this._loadData()}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"api-url":this._api&&(this._api=h({baseUrl:i}),this._loadData());break;case"theme":this._applyTheme();break;case"tab":this._setTab(i);break}}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;this._loading=!0,this._error=null,this.render();try{let[t,i,a]=await Promise.allSettled([e.getMemorySummary(),e.getTokenEconomics(),e.getMemoryStats()]);if(e!==this._api||(this._summary=t.status==="fulfilled"?t.value:null,this._tokenEconomics=i.status==="fulfilled"?i.value:null,this._stats=a.status==="fulfilled"?a.value:null,await this._loadTabData(),e!==this._api))return}catch(t){if(e!==this._api)return;this._error=t.message||"Failed to load memory data"}this._loading=!1,this.render()}async _loadTabData(){let e=this._api;switch(this._activeTab){case"episodes":{let t=await e.listEpisodes({limit:50}).catch(()=>null);if(e!==this._api)return;this._episodes=t;break}case"patterns":{let t=await e.listPatterns().catch(()=>null);if(e!==this._api)return;this._patterns=t;break}case"skills":{let t=await e.listSkills().catch(()=>null);if(e!==this._api)return;this._skills=t;break}}}_setTab(e){this._activeTab!==e&&(this._activeTab=e,this._selectedItem=null,this._loadTabData().then(()=>this.render()))}async _selectEpisode(e){let t=this._api;try{this._lastFocusedElement=this.shadowRoot.activeElement;let i=await t.getEpisode(e);if(t!==this._api)return;this._selectedItem=i,this.dispatchEvent(new CustomEvent("episode-select",{detail:this._selectedItem})),this.render(),this._focusDetailPanel()}catch(i){console.error("Failed to load episode:",i)}}async _selectPattern(e){let t=this._api;try{this._lastFocusedElement=this.shadowRoot.activeElement;let i=await t.getPattern(e);if(t!==this._api)return;this._selectedItem=i,this.dispatchEvent(new CustomEvent("pattern-select",{detail:this._selectedItem})),this.render(),this._focusDetailPanel()}catch(i){console.error("Failed to load pattern:",i)}}async _selectSkill(e){let t=this._api;try{this._lastFocusedElement=this.shadowRoot.activeElement;let i=await t.getSkill(e);if(t!==this._api)return;this._selectedItem=i,this.dispatchEvent(new CustomEvent("skill-select",{detail:this._selectedItem})),this.render(),this._focusDetailPanel()}catch(i){console.error("Failed to load skill:",i)}}_focusDetailPanel(){requestAnimationFrame(()=>{let e=this.shadowRoot.getElementById("close-detail");e&&e.focus()})}_closeDetail(){this._selectedItem=null,this.render(),this._lastFocusedElement&&requestAnimationFrame(()=>{this._lastFocusedElement.focus(),this._lastFocusedElement=null})}async _triggerConsolidation(){try{let e=await this._api.consolidateMemory(24);alert(`Consolidation complete:
4536
4538
  - Patterns created: ${e.patternsCreated}
4537
4539
  - Patterns merged: ${e.patternsMerged}
4538
4540
  - Episodes processed: ${e.episodesProcessed}`),this._loadData()}catch(e){alert("Consolidation failed: "+e.message)}}async _executeSearch(){let e=this._searchQuery.trim();if(!e)return;let t=this._api;this._searchLoading=!0,this._searchError=null,this.render();try{let i=await t.searchMemory(e,this._searchCollection,20);if(t!==this._api)return;this._searchResults=i.results||[]}catch(i){if(t!==this._api)return;this._searchError=i.message||"Search failed",this._searchResults=[]}this._searchLoading=!1,this.render(),requestAnimationFrame(()=>{let i=this.shadowRoot.getElementById("memory-search-input");i&&i.focus()})}_renderSearch(){let e=["all","episodes","patterns","skills"];return`
@@ -4574,47 +4576,38 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
4574
4576
  `:!this._searchLoading&&this._searchQuery?'<div class="empty-state">No results found</div>':""}
4575
4577
  ${this._searchQuery?"":'<div class="empty-state">Enter a query to search across all memory layers using full-text search</div>'}
4576
4578
  </div>
4577
- `}_renderSummary(){if(!this._summary)return'<div class="empty-state">No memory data available</div>';let{episodic:e,semantic:t,procedural:i,tokenEconomics:a}=this._summary;return`
4579
+ `}_fmtCount(e){return typeof e=="number"&&Number.isFinite(e)?e.toLocaleString():"--"}_renderSummary(){if(!this._summary)return'<div class="empty-state">No memory data available</div>';let{episodic:e,semantic:t,procedural:i,tokenEconomics:a}=this._summary;return`
4578
4580
  <div class="summary-grid">
4579
4581
  <div class="summary-card">
4580
4582
  <div class="summary-card-header">
4581
4583
  <span class="summary-card-title">Episodic Memory</span>
4582
- <span class="summary-card-count">${e?.count||0}</span>
4584
+ <span class="summary-card-count">${this._fmtCount(e?.count)}</span>
4583
4585
  </div>
4584
4586
  <div class="summary-card-detail">
4585
4587
  Specific interaction traces and outcomes
4586
4588
  </div>
4587
4589
  ${e?.latestDate?`<div class="summary-card-meta">Latest: ${new Date(e.latestDate).toLocaleDateString()}</div>`:""}
4588
- <div class="memory-bar">
4589
- <div class="memory-bar-fill episodic" style="width: ${Math.min((e?.count||0)/100*100,100)}%"></div>
4590
- </div>
4591
4590
  </div>
4592
4591
 
4593
4592
  <div class="summary-card">
4594
4593
  <div class="summary-card-header">
4595
4594
  <span class="summary-card-title">Semantic Memory</span>
4596
- <span class="summary-card-count">${t?.patterns||0}</span>
4595
+ <span class="summary-card-count">${this._fmtCount(t?.patterns)}</span>
4597
4596
  </div>
4598
4597
  <div class="summary-card-detail">
4599
4598
  Generalized patterns and anti-patterns
4600
4599
  </div>
4601
- <div class="summary-card-meta">Anti-patterns: ${t?.antiPatterns||0}</div>
4602
- <div class="memory-bar">
4603
- <div class="memory-bar-fill semantic" style="width: ${Math.min((t?.patterns||0)/100*100,100)}%"></div>
4604
- </div>
4600
+ <div class="summary-card-meta">Anti-patterns: ${this._fmtCount(t?.antiPatterns)}</div>
4605
4601
  </div>
4606
4602
 
4607
4603
  <div class="summary-card">
4608
4604
  <div class="summary-card-header">
4609
4605
  <span class="summary-card-title">Procedural Memory</span>
4610
- <span class="summary-card-count">${i?.skills||0}</span>
4606
+ <span class="summary-card-count">${this._fmtCount(i?.skills)}</span>
4611
4607
  </div>
4612
4608
  <div class="summary-card-detail">
4613
4609
  Learned skills and procedures
4614
4610
  </div>
4615
- <div class="memory-bar">
4616
- <div class="memory-bar-fill procedural" style="width: ${Math.min((i?.skills||0)/100*100,100)}%"></div>
4617
- </div>
4618
4611
  </div>
4619
4612
 
4620
4613
  ${this._tokenEconomics?`
@@ -4625,15 +4618,15 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
4625
4618
  <div class="economics-stats">
4626
4619
  <div class="econ-stat">
4627
4620
  <span class="econ-label">Discovery</span>
4628
- <span class="econ-value">${this._tokenEconomics.discoveryTokens?.toLocaleString()||0}</span>
4621
+ <span class="econ-value">${this._fmtCount(this._tokenEconomics.discoveryTokens)}</span>
4629
4622
  </div>
4630
4623
  <div class="econ-stat">
4631
4624
  <span class="econ-label">Read</span>
4632
- <span class="econ-value">${this._tokenEconomics.readTokens?.toLocaleString()||0}</span>
4625
+ <span class="econ-value">${this._fmtCount(this._tokenEconomics.readTokens)}</span>
4633
4626
  </div>
4634
4627
  <div class="econ-stat">
4635
4628
  <span class="econ-label">Savings</span>
4636
- <span class="econ-value savings">${(this._tokenEconomics.savingsPercent||0).toFixed(1)}%</span>
4629
+ <span class="econ-value savings">${typeof this._tokenEconomics.savingsPercent=="number"?this._tokenEconomics.savingsPercent.toFixed(1)+"%":"--"}</span>
4637
4630
  </div>
4638
4631
  </div>
4639
4632
  </div>
@@ -4651,7 +4644,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
4651
4644
  ${this._stats.total_entries!=null?`
4652
4645
  <div class="stats-item">
4653
4646
  <span class="stats-label">Total Entries</span>
4654
- <span class="stats-value mono">${(this._stats.total_entries??0).toLocaleString()}</span>
4647
+ <span class="stats-value mono">${this._fmtCount(this._stats.total_entries)}</span>
4655
4648
  </div>
4656
4649
  `:""}
4657
4650
  ${this._stats.db_size_bytes!=null?`
@@ -4705,7 +4698,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
4705
4698
  Refresh
4706
4699
  </button>
4707
4700
  </div>
4708
- `}_renderEpisodes(){return this._episodes.length===0?'<div class="empty-state">No episodes recorded yet</div>':`
4701
+ `}_renderEpisodes(){return this._episodes==null?'<div class="empty-state">Could not load episodes</div>':this._episodes.length===0?'<div class="empty-state">No episodes recorded yet</div>':`
4709
4702
  <div class="item-list" role="list" aria-label="Episodes list">
4710
4703
  ${this._episodes.map(e=>`
4711
4704
  <div class="item-card" data-id="${this._escapeHtml(e.id)}" data-type="episode" tabindex="0" role="listitem" aria-label="Episode ${this._escapeHtml(e.id)}: ${this._escapeHtml(e.taskId||"Task")}, outcome ${this._escapeHtml(e.outcome||"unknown")}">
@@ -4722,7 +4715,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
4722
4715
  </div>
4723
4716
  `).join("")}
4724
4717
  </div>
4725
- `}_renderPatterns(){return this._patterns.length===0?'<div class="empty-state">No patterns discovered yet</div>':`
4718
+ `}_renderPatterns(){return this._patterns==null?'<div class="empty-state">Could not load patterns</div>':this._patterns.length===0?'<div class="empty-state">No patterns discovered yet</div>':`
4726
4719
  <div class="item-list" role="list" aria-label="Patterns list">
4727
4720
  ${this._patterns.map(e=>`
4728
4721
  <div class="item-card" data-id="${this._escapeHtml(e.id)}" data-type="pattern" tabindex="0" role="listitem" aria-label="Pattern: ${this._escapeHtml(e.pattern)}, ${(e.confidence*100).toFixed(0)} percent confidence">
@@ -4732,12 +4725,12 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
4732
4725
  </div>
4733
4726
  <div class="item-title">${this._escapeHtml(e.pattern)}</div>
4734
4727
  <div class="item-meta">
4735
- <span>Used ${e.usageCount||0} times</span>
4728
+ <span>Used ${this._fmtCount(e.usage_count??e.usageCount)} times</span>
4736
4729
  </div>
4737
4730
  </div>
4738
4731
  `).join("")}
4739
4732
  </div>
4740
- `}_renderSkills(){return this._skills.length===0?'<div class="empty-state">No skills learned yet</div>':`
4733
+ `}_renderSkills(){return this._skills==null?'<div class="empty-state">Could not load skills</div>':this._skills.length===0?'<div class="empty-state">No skills learned yet</div>':`
4741
4734
  <div class="item-list" role="list" aria-label="Skills list">
4742
4735
  ${this._skills.map(e=>`
4743
4736
  <div class="item-card" data-id="${this._escapeHtml(e.id)}" data-type="skill" tabindex="0" role="listitem" aria-label="Skill: ${this._escapeHtml(e.name)}">
@@ -4774,11 +4767,11 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
4774
4767
  </div>
4775
4768
  <div class="detail-row">
4776
4769
  <span class="detail-label">Duration</span>
4777
- <span class="detail-value">${e.durationSeconds||0}s</span>
4770
+ <span class="detail-value">${typeof e.durationSeconds=="number"?e.durationSeconds+"s":"--"}</span>
4778
4771
  </div>
4779
4772
  <div class="detail-row">
4780
4773
  <span class="detail-label">Tokens Used</span>
4781
- <span class="detail-value">${e.tokensUsed?.toLocaleString()||0}</span>
4774
+ <span class="detail-value">${this._fmtCount(e.tokensUsed)}</span>
4782
4775
  </div>
4783
4776
  ${e.goal?`
4784
4777
  <div class="detail-section">
@@ -4819,7 +4812,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
4819
4812
  </div>
4820
4813
  <div class="detail-row">
4821
4814
  <span class="detail-label">Usage Count</span>
4822
- <span class="detail-value">${e.usageCount||0}</span>
4815
+ <span class="detail-value">${this._fmtCount(e.usage_count??e.usageCount)}</span>
4823
4816
  </div>
4824
4817
  <div class="detail-section">
4825
4818
  <div class="detail-label">Pattern</div>
@@ -5023,23 +5016,6 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5023
5016
  margin-bottom: 8px;
5024
5017
  }
5025
5018
 
5026
- .memory-bar {
5027
- height: 4px;
5028
- background: var(--loki-bg-tertiary);
5029
- border-radius: 2px;
5030
- overflow: hidden;
5031
- }
5032
-
5033
- .memory-bar-fill {
5034
- height: 100%;
5035
- border-radius: 2px;
5036
- transition: width 0.3s ease;
5037
- }
5038
-
5039
- .memory-bar-fill.episodic { background: var(--loki-blue); }
5040
- .memory-bar-fill.semantic { background: var(--loki-purple); }
5041
- .memory-bar-fill.procedural { background: var(--loki-green); }
5042
-
5043
5019
  .token-economics .economics-stats {
5044
5020
  display: flex;
5045
5021
  gap: 16px;
@@ -5403,7 +5379,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5403
5379
  <span class="browser-title">Memory System</span>
5404
5380
  </div>
5405
5381
  <div class="tabs" role="tablist" aria-label="Memory browser sections">
5406
- ${jt.map((i,a)=>`
5382
+ ${At.map((i,a)=>`
5407
5383
  <button class="tab ${this._activeTab===i.id?"active":""}"
5408
5384
  data-tab="${i.id}"
5409
5385
  role="tab"
@@ -5420,12 +5396,12 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5420
5396
  ${t}
5421
5397
  </div>
5422
5398
  </div>
5423
- `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot.querySelectorAll(".tab");e.forEach((n,l)=>{n.addEventListener("click",()=>this._setTab(n.dataset.tab)),n.addEventListener("keydown",c=>{if(c.key==="ArrowRight"||c.key==="ArrowLeft"){c.preventDefault();let p=Array.from(e),u=c.key==="ArrowRight"?(l+1)%p.length:(l-1+p.length)%p.length;p[u].focus(),this._setTab(p[u].dataset.tab)}})}),this.shadowRoot.querySelectorAll(".item-card").forEach(n=>{n.addEventListener("click",()=>this._handleItemClick(n)),n.addEventListener("keydown",l=>{l.key==="Enter"||l.key===" "?(l.preventDefault(),this._handleItemClick(n)):(l.key==="ArrowDown"||l.key==="ArrowUp")&&(l.preventDefault(),this._navigateItemCards(n,l.key==="ArrowDown"?"next":"prev"))})});let t=this.shadowRoot.getElementById("close-detail");t&&t.addEventListener("click",()=>this._closeDetail());let i=this.shadowRoot.getElementById("consolidate-btn");i&&i.addEventListener("click",()=>this._triggerConsolidation());let a=this.shadowRoot.getElementById("refresh-btn");a&&a.addEventListener("click",()=>this._loadData());let s=this.shadowRoot.getElementById("memory-search-input"),r=this.shadowRoot.getElementById("search-btn"),o=this.shadowRoot.getElementById("memory-search-collection");s&&(s.addEventListener("keydown",n=>{n.key==="Enter"&&(n.preventDefault(),this._searchQuery=s.value,this._executeSearch())}),s.addEventListener("input",n=>{this._searchQuery=n.target.value})),r&&r.addEventListener("click",()=>{let n=this.shadowRoot.getElementById("memory-search-input");n&&(this._searchQuery=n.value),this._executeSearch()}),o&&o.addEventListener("change",n=>{this._searchCollection=n.target.value})}_handleItemClick(e){let t=e.dataset.id;switch(e.dataset.type){case"episode":this._selectEpisode(t);break;case"pattern":this._selectPattern(t);break;case"skill":this._selectSkill(t);break}}_navigateItemCards(e,t){let i=Array.from(this.shadowRoot.querySelectorAll(".item-card")),a=i.indexOf(e);if(a===-1)return;let s=t==="next"?a+1:a-1;s>=0&&s<i.length&&i[s].focus()}};customElements.get("loki-memory-browser")||customElements.define("loki-memory-browser",ie);var Ut=[{id:"1h",label:"1 Hour",hours:1},{id:"24h",label:"24 Hours",hours:24},{id:"7d",label:"7 Days",hours:168},{id:"30d",label:"30 Days",hours:720}],Nt=[{id:"all",label:"All Signals"},{id:"user_preference",label:"User Preferences"},{id:"error_pattern",label:"Error Patterns"},{id:"success_pattern",label:"Success Patterns"},{id:"tool_efficiency",label:"Tool Efficiency"},{id:"context_relevance",label:"Context Relevance"}],Ot=[{id:"all",label:"All Sources"},{id:"cli",label:"CLI"},{id:"api",label:"API"},{id:"vscode",label:"VS Code"},{id:"mcp",label:"MCP"},{id:"dashboard",label:"Dashboard"}],ae=class extends v{static get observedAttributes(){return["api-url","theme","time-range","signal-type","source"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._timeRange="7d",this._signalType="all",this._source="all",this._metrics=null,this._trends=null,this._signals=[],this._selectedMetric=null}connectedCallback(){super.connectedCallback(),this._timeRange=this.getAttribute("time-range")||"7d",this._signalType=this.getAttribute("signal-type")||"all",this._source=this.getAttribute("source")||"all",this._setupApi(),this._loadData()}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"api-url":this._api&&(this._api=h({baseUrl:i}),this._loadData());break;case"theme":this._applyTheme();break;case"time-range":this._timeRange=i,this._loadData();break;case"signal-type":this._signalType=i,this._loadData();break;case"source":this._source=i,this._loadData();break}}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){this._loading=!0,this._error=null,this.render();let e=this._api;try{let t={timeRange:this._timeRange,signalType:this._signalType!=="all"?this._signalType:void 0,source:this._source!=="all"?this._source:void 0},[i,a,s]=await Promise.all([e.getLearningMetrics(t).catch(()=>null),e.getLearningTrends(t).catch(()=>null),e.getLearningSignals({...t,limit:50}).catch(()=>[])]);if(e!==this._api)return;this._metrics=i,this._trends=a,this._signals=s||[]}catch(t){if(e!==this._api)return;this._error=t.message||"Failed to load learning data"}this._loading=!1,this.render()}_setFilter(e,t){switch(e){case"timeRange":this._timeRange=t,this.setAttribute("time-range",t);break;case"signalType":this._signalType=t,this.setAttribute("signal-type",t);break;case"source":this._source=t,this.setAttribute("source",t);break}this.dispatchEvent(new CustomEvent("filter-change",{detail:{timeRange:this._timeRange,signalType:this._signalType,source:this._source}})),this._loadData()}_selectMetric(e,t){this._selectedMetric={type:e,item:t},this.dispatchEvent(new CustomEvent("metric-select",{detail:{type:e,item:t}})),this.render()}_closeDetail(){this._selectedMetric=null,this.render()}_formatNumber(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"K":e?.toString()||"0"}_formatPercent(e){return(e*100).toFixed(1)+"%"}_formatDuration(e){return e<60?e.toFixed(0)+"s":e<3600?(e/60).toFixed(1)+"m":(e/3600).toFixed(1)+"h"}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}_renderFilters(){return`
5399
+ `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot.querySelectorAll(".tab");e.forEach((n,l)=>{n.addEventListener("click",()=>this._setTab(n.dataset.tab)),n.addEventListener("keydown",c=>{if(c.key==="ArrowRight"||c.key==="ArrowLeft"){c.preventDefault();let p=Array.from(e),u=c.key==="ArrowRight"?(l+1)%p.length:(l-1+p.length)%p.length;p[u].focus(),this._setTab(p[u].dataset.tab)}})}),this.shadowRoot.querySelectorAll(".item-card").forEach(n=>{n.addEventListener("click",()=>this._handleItemClick(n)),n.addEventListener("keydown",l=>{l.key==="Enter"||l.key===" "?(l.preventDefault(),this._handleItemClick(n)):(l.key==="ArrowDown"||l.key==="ArrowUp")&&(l.preventDefault(),this._navigateItemCards(n,l.key==="ArrowDown"?"next":"prev"))})});let t=this.shadowRoot.getElementById("close-detail");t&&t.addEventListener("click",()=>this._closeDetail());let i=this.shadowRoot.getElementById("consolidate-btn");i&&i.addEventListener("click",()=>this._triggerConsolidation());let a=this.shadowRoot.getElementById("refresh-btn");a&&a.addEventListener("click",()=>this._loadData());let s=this.shadowRoot.getElementById("memory-search-input"),r=this.shadowRoot.getElementById("search-btn"),o=this.shadowRoot.getElementById("memory-search-collection");s&&(s.addEventListener("keydown",n=>{n.key==="Enter"&&(n.preventDefault(),this._searchQuery=s.value,this._executeSearch())}),s.addEventListener("input",n=>{this._searchQuery=n.target.value})),r&&r.addEventListener("click",()=>{let n=this.shadowRoot.getElementById("memory-search-input");n&&(this._searchQuery=n.value),this._executeSearch()}),o&&o.addEventListener("change",n=>{this._searchCollection=n.target.value})}_handleItemClick(e){let t=e.dataset.id;switch(e.dataset.type){case"episode":this._selectEpisode(t);break;case"pattern":this._selectPattern(t);break;case"skill":this._selectSkill(t);break}}_navigateItemCards(e,t){let i=Array.from(this.shadowRoot.querySelectorAll(".item-card")),a=i.indexOf(e);if(a===-1)return;let s=t==="next"?a+1:a-1;s>=0&&s<i.length&&i[s].focus()}};customElements.get("loki-memory-browser")||customElements.define("loki-memory-browser",te);var Tt=[{id:"1h",label:"1 Hour",hours:1},{id:"24h",label:"24 Hours",hours:24},{id:"7d",label:"7 Days",hours:168},{id:"30d",label:"30 Days",hours:720}],Lt=[{id:"all",label:"All Signals"},{id:"user_preference",label:"User Preferences"},{id:"error_pattern",label:"Error Patterns"},{id:"success_pattern",label:"Success Patterns"},{id:"tool_efficiency",label:"Tool Efficiency"},{id:"context_relevance",label:"Context Relevance"}],zt=[{id:"all",label:"All Sources"},{id:"cli",label:"CLI"},{id:"api",label:"API"},{id:"vscode",label:"VS Code"},{id:"mcp",label:"MCP"},{id:"dashboard",label:"Dashboard"}],ie=class extends v{static get observedAttributes(){return["api-url","theme","time-range","signal-type","source"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._timeRange="7d",this._signalType="all",this._source="all",this._metrics=null,this._trends=null,this._signals=[],this._selectedMetric=null}connectedCallback(){super.connectedCallback(),this._timeRange=this.getAttribute("time-range")||"7d",this._signalType=this.getAttribute("signal-type")||"all",this._source=this.getAttribute("source")||"all",this._setupApi(),this._loadData()}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"api-url":this._api&&(this._api=h({baseUrl:i}),this._loadData());break;case"theme":this._applyTheme();break;case"time-range":this._timeRange=i,this._loadData();break;case"signal-type":this._signalType=i,this._loadData();break;case"source":this._source=i,this._loadData();break}}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){this._loading=!0,this._error=null,this.render();let e=this._api;try{let t={timeRange:this._timeRange,signalType:this._signalType!=="all"?this._signalType:void 0,source:this._source!=="all"?this._source:void 0},[i,a,s]=await Promise.all([e.getLearningMetrics(t).catch(()=>null),e.getLearningTrends(t).catch(()=>null),e.getLearningSignals({...t,limit:50}).catch(()=>null)]);if(e!==this._api)return;this._metrics=i,this._trends=a,this._signals=s}catch(t){if(e!==this._api)return;this._error=t.message||"Failed to load learning data"}this._loading=!1,this.render()}_setFilter(e,t){switch(e){case"timeRange":this._timeRange=t,this.setAttribute("time-range",t);break;case"signalType":this._signalType=t,this.setAttribute("signal-type",t);break;case"source":this._source=t,this.setAttribute("source",t);break}this.dispatchEvent(new CustomEvent("filter-change",{detail:{timeRange:this._timeRange,signalType:this._signalType,source:this._source}})),this._loadData()}_selectMetric(e,t){this._selectedMetric={type:e,item:t},this.dispatchEvent(new CustomEvent("metric-select",{detail:{type:e,item:t}})),this.render()}_closeDetail(){this._selectedMetric=null,this.render()}_num(e){let t=e==null?NaN:Number(e);return Number.isFinite(t)?t:null}_formatNumber(e){let t=this._num(e);return t==null?"--":t>=1e6?(t/1e6).toFixed(1)+"M":t>=1e3?(t/1e3).toFixed(1)+"K":String(t)}_formatPercent(e){let t=this._num(e);return t==null?"--":(t*100).toFixed(1)+"%"}_formatDuration(e){let t=this._num(e);return t==null?"--":t<60?t.toFixed(0)+"s":t<3600?(t/60).toFixed(1)+"m":(t/3600).toFixed(1)+"h"}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}_renderFilters(){return`
5424
5400
  <div class="filters">
5425
5401
  <div class="filter-group">
5426
5402
  <label>Time Range</label>
5427
5403
  <select id="time-range-select" class="filter-select">
5428
- ${Ut.map(e=>`
5404
+ ${Tt.map(e=>`
5429
5405
  <option value="${e.id}" ${this._timeRange===e.id?"selected":""}>${e.label}</option>
5430
5406
  `).join("")}
5431
5407
  </select>
@@ -5433,7 +5409,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5433
5409
  <div class="filter-group">
5434
5410
  <label>Signal Type</label>
5435
5411
  <select id="signal-type-select" class="filter-select">
5436
- ${Nt.map(e=>`
5412
+ ${Lt.map(e=>`
5437
5413
  <option value="${e.id}" ${this._signalType===e.id?"selected":""}>${e.label}</option>
5438
5414
  `).join("")}
5439
5415
  </select>
@@ -5441,7 +5417,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5441
5417
  <div class="filter-group">
5442
5418
  <label>Source</label>
5443
5419
  <select id="source-select" class="filter-select">
5444
- ${Ot.map(e=>`
5420
+ ${zt.map(e=>`
5445
5421
  <option value="${e.id}" ${this._source===e.id?"selected":""}>${e.label}</option>
5446
5422
  `).join("")}
5447
5423
  </select>
@@ -5454,19 +5430,19 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5454
5430
  Refresh
5455
5431
  </button>
5456
5432
  </div>
5457
- `}_renderSummaryCards(){if(!this._metrics)return'<div class="empty-state">No metrics available</div>';let{totalSignals:e,signalsByType:t,signalsBySource:i,aggregation:a}=this._metrics;return`
5433
+ `}_renderSummaryCards(){if(!this._metrics)return'<div class="empty-state">No metrics available</div>';let{totalSignals:e,signalsByType:t,signalsBySource:i,aggregation:a}=this._metrics,s=e>0?this._num(this._metrics.avgConfidence):null;return`
5458
5434
  <div class="summary-cards">
5459
5435
  <div class="summary-card">
5460
5436
  <div class="summary-card-header">
5461
5437
  <span class="summary-card-title">Total Signals</span>
5462
- <span class="summary-card-count">${this._formatNumber(e||0)}</span>
5438
+ <span class="summary-card-count">${this._formatNumber(e)}</span>
5463
5439
  </div>
5464
5440
  <div class="summary-card-detail">Learning signals collected</div>
5465
5441
  <div class="signal-breakdown">
5466
- ${Object.entries(t||{}).map(([s,r])=>`
5442
+ ${Object.entries(t||{}).map(([r,o])=>`
5467
5443
  <div class="breakdown-item">
5468
- <span class="breakdown-label">${this._escapeHtml(s.replace("_"," "))}</span>
5469
- <span class="breakdown-value">${this._formatNumber(r)}</span>
5444
+ <span class="breakdown-label">${this._escapeHtml(r.replace("_"," "))}</span>
5445
+ <span class="breakdown-value">${this._formatNumber(o)}</span>
5470
5446
  </div>
5471
5447
  `).join("")}
5472
5448
  </div>
@@ -5479,10 +5455,10 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5479
5455
  </div>
5480
5456
  <div class="summary-card-detail">Signal sources active</div>
5481
5457
  <div class="signal-breakdown">
5482
- ${Object.entries(i||{}).map(([s,r])=>`
5458
+ ${Object.entries(i||{}).map(([r,o])=>`
5483
5459
  <div class="breakdown-item">
5484
- <span class="breakdown-label source-badge ${this._escapeHtml(s)}">${this._escapeHtml(s)}</span>
5485
- <span class="breakdown-value">${this._formatNumber(r)}</span>
5460
+ <span class="breakdown-label source-badge ${this._escapeHtml(r)}">${this._escapeHtml(r)}</span>
5461
+ <span class="breakdown-value">${this._formatNumber(o)}</span>
5486
5462
  </div>
5487
5463
  `).join("")}
5488
5464
  </div>
@@ -5514,12 +5490,12 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5514
5490
  <div class="summary-card-header">
5515
5491
  <span class="summary-card-title">Avg Confidence</span>
5516
5492
  <span class="summary-card-count confidence-high">
5517
- ${this._formatPercent(this._metrics.avgConfidence||0)}
5493
+ ${this._formatPercent(s)}
5518
5494
  </span>
5519
5495
  </div>
5520
5496
  <div class="summary-card-detail">Signal reliability</div>
5521
5497
  <div class="confidence-bar">
5522
- <div class="confidence-fill" style="width: ${(this._metrics.avgConfidence||0)*100}%"></div>
5498
+ <div class="confidence-fill" style="width: ${s==null?0:s*100}%"></div>
5523
5499
  </div>
5524
5500
  </div>
5525
5501
  </div>
@@ -5585,7 +5561,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5585
5561
  <div class="list-item error-item" data-type="error_pattern" data-id="${this._escapeHtml(s.error_type)}" tabindex="0" role="listitem">
5586
5562
  <div class="item-main">
5587
5563
  <span class="item-key">${this._escapeHtml(s.error_type)}</span>
5588
- <span class="resolution-rate ${s.resolution_rate>.5?"good":"poor"}">${this._formatPercent(s.resolution_rate)} resolved</span>
5564
+ <span class="resolution-rate ${s.resolution_rate==null?"":s.resolution_rate>.5?"good":"poor"}">${this._formatPercent(s.resolution_rate)} resolved</span>
5589
5565
  </div>
5590
5566
  <div class="item-meta">
5591
5567
  <span class="item-freq">${s.frequency}x</span>
@@ -5634,14 +5610,14 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5634
5610
  </div>
5635
5611
  <div class="item-meta">
5636
5612
  <span class="success-rate ${s.success_rate>.8?"good":""}">${this._formatPercent(s.success_rate)}</span>
5637
- <span class="item-time">${Number(s.avg_execution_time_ms??0).toFixed(0)}ms</span>
5613
+ <span class="item-time">${Ne(s.avg_execution_time_ms)}</span>
5638
5614
  </div>
5639
5615
  </div>
5640
5616
  `).join("")||'<div class="list-empty">No tool data found</div>'}
5641
5617
  </div>
5642
5618
  </div>
5643
5619
  </div>
5644
- `}_renderRecentSignals(){return!this._signals||this._signals.length===0?'<div class="signals-empty">No recent signals</div>':`
5620
+ `}_renderRecentSignals(){return Array.isArray(this._signals)?this._signals.length===0?'<div class="signals-empty">No recent signals</div>':`
5645
5621
  <div class="recent-signals">
5646
5622
  <div class="signals-header">
5647
5623
  <span class="signals-title">Recent Signals</span>
@@ -5662,7 +5638,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5662
5638
  </div>`}).join("")}
5663
5639
  </div>
5664
5640
  </div>
5665
- `}_renderDetailPanel(){if(!this._selectedMetric)return"";let{type:e,item:t}=this._selectedMetric,i="";switch(e){case"preference":i=`
5641
+ `:'<div class="signals-empty">Could not load signals</div>'}_renderDetailPanel(){if(!this._selectedMetric)return"";let{type:e,item:t}=this._selectedMetric,i="";switch(e){case"preference":i=`
5666
5642
  <div class="detail-row">
5667
5643
  <span class="detail-label">Preference Key</span>
5668
5644
  <span class="detail-value">${this._escapeHtml(t.preference_key)}</span>
@@ -5736,7 +5712,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5736
5712
  </div>
5737
5713
  <div class="detail-row">
5738
5714
  <span class="detail-label">Usage Count</span>
5739
- <span class="detail-value">${t.usage_count}</span>
5715
+ <span class="detail-value">${this._formatNumber(t.count??t.usage_count)}</span>
5740
5716
  </div>
5741
5717
  <div class="detail-row">
5742
5718
  <span class="detail-label">Success Rate</span>
@@ -5744,7 +5720,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
5744
5720
  </div>
5745
5721
  <div class="detail-row">
5746
5722
  <span class="detail-label">Avg Execution Time</span>
5747
- <span class="detail-value">${Number(t.avg_execution_time_ms??0).toFixed(0)}ms</span>
5723
+ <span class="detail-value">${Ne(t.avg_execution_time_ms)}</span>
5748
5724
  </div>
5749
5725
  <div class="detail-row">
5750
5726
  <span class="detail-label">Total Tokens</span>
@@ -6432,13 +6408,13 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
6432
6408
  ${t}
6433
6409
  </div>
6434
6410
  </div>
6435
- `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot.getElementById("time-range-select");e&&e.addEventListener("change",r=>this._setFilter("timeRange",r.target.value));let t=this.shadowRoot.getElementById("signal-type-select");t&&t.addEventListener("change",r=>this._setFilter("signalType",r.target.value));let i=this.shadowRoot.getElementById("source-select");i&&i.addEventListener("change",r=>this._setFilter("source",r.target.value));let a=this.shadowRoot.getElementById("refresh-btn");a&&a.addEventListener("click",()=>this._loadData());let s=this.shadowRoot.getElementById("close-detail");s&&s.addEventListener("click",()=>this._closeDetail()),this.shadowRoot.querySelectorAll(".list-item").forEach(r=>{r.addEventListener("click",()=>{let o=r.dataset.type,n=r.dataset.id,l=this._findItemData(o,n);l&&this._selectMetric(o,l)}),r.addEventListener("keydown",o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),r.click())})})}_findItemData(e,t){if(!this._metrics?.aggregation)return null;switch(e){case"preference":return this._metrics.aggregation.preferences?.find(i=>i.preference_key===t);case"error_pattern":return this._metrics.aggregation.error_patterns?.find(i=>i.error_type===t);case"success_pattern":return this._metrics.aggregation.success_patterns?.find(i=>i.pattern_name===t);case"tool_efficiency":return this._metrics.aggregation.tool_efficiencies?.find(i=>i.tool_name===t);default:return null}}};customElements.get("loki-learning-dashboard")||customElements.define("loki-learning-dashboard",ae);var qt=[{id:"overview",label:"Overview"},{id:"decisions",label:"Decision Log"},{id:"convergence",label:"Convergence"},{id:"agents",label:"Agents"}],se=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._activeTab="overview",this._pollInterval=null,this._councilState=null,this._verdicts=[],this._convergence=[],this._agents=[],this._selectedAgent=null,this._lastDataHash=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null),this._pendingRaf&&(cancelAnimationFrame(this._pendingRaf),this._pendingRaf=null)}async _loadData(){let e=this._api;try{let[i,a,s,r]=await Promise.allSettled([e._get("/api/council/state"),e._get("/api/council/verdicts"),e._get("/api/council/convergence"),e._get("/api/agents")]);if(e!==this._api)return;i.status==="fulfilled"&&(this._councilState=i.value),a.status==="fulfilled"&&(this._verdicts=a.value.verdicts||[]),s.status==="fulfilled"&&(this._convergence=s.value.dataPoints||[]),r.status==="fulfilled"&&(this._agents=Array.isArray(r.value)?r.value:[]),this._error=null}catch(i){if(e!==this._api)return;this._error=i.message}let t=JSON.stringify({s:this._councilState,v:this._verdicts,c:this._convergence,a:this._agents,e:this._error});t!==this._lastDataHash&&(this._lastDataHash=t,this.render())}async _forceReview(){try{await this._api._post("/api/council/force-review"),this.dispatchEvent(new CustomEvent("council-action",{detail:{action:"force-review"},bubbles:!0}))}catch(e){this._error=`Failed to force review: ${e.message}`,this.render()}}async _killAgent(e){if(confirm(`Kill agent ${e}?`))try{await this._api._post(`/api/agents/${e}/kill`),this.dispatchEvent(new CustomEvent("council-action",{detail:{action:"kill-agent",agentId:e},bubbles:!0})),await this._loadData()}catch(t){this._error=`Failed to kill agent: ${t.message}`,this.render()}}async _pauseAgent(e){try{await this._api._post(`/api/agents/${e}/pause`),await this._loadData()}catch(t){this._error=`Failed to pause agent: ${t.message}`,this.render()}}async _resumeAgent(e){try{await this._api._post(`/api/agents/${e}/resume`),await this._loadData()}catch(t){this._error=`Failed to resume agent: ${t.message}`,this.render()}}_setTab(e){this._activeTab=e,this.render()}_selectAgent(e){this._selectedAgent=this._selectedAgent?.id===e.id?null:e,this.render()}render(){let e=this.shadowRoot;e&&(this._pendingRaf&&(cancelAnimationFrame(this._pendingRaf),this._pendingRaf=null),e.innerHTML=`
6411
+ `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot.getElementById("time-range-select");e&&e.addEventListener("change",r=>this._setFilter("timeRange",r.target.value));let t=this.shadowRoot.getElementById("signal-type-select");t&&t.addEventListener("change",r=>this._setFilter("signalType",r.target.value));let i=this.shadowRoot.getElementById("source-select");i&&i.addEventListener("change",r=>this._setFilter("source",r.target.value));let a=this.shadowRoot.getElementById("refresh-btn");a&&a.addEventListener("click",()=>this._loadData());let s=this.shadowRoot.getElementById("close-detail");s&&s.addEventListener("click",()=>this._closeDetail()),this.shadowRoot.querySelectorAll(".list-item").forEach(r=>{r.addEventListener("click",()=>{let o=r.dataset.type,n=r.dataset.id,l=this._findItemData(o,n);l&&this._selectMetric(o,l)}),r.addEventListener("keydown",o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),r.click())})})}_findItemData(e,t){if(!this._metrics?.aggregation)return null;switch(e){case"preference":return this._metrics.aggregation.preferences?.find(i=>i.preference_key===t);case"error_pattern":return this._metrics.aggregation.error_patterns?.find(i=>i.error_type===t);case"success_pattern":return this._metrics.aggregation.success_patterns?.find(i=>i.pattern_name===t);case"tool_efficiency":return this._metrics.aggregation.tool_efficiencies?.find(i=>i.tool_name===t);default:return null}}};customElements.get("loki-learning-dashboard")||customElements.define("loki-learning-dashboard",ie);var Ht=[{id:"overview",label:"Overview"},{id:"decisions",label:"Decision Log"},{id:"convergence",label:"Convergence"},{id:"agents",label:"Agents"}],ae=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._activeTab="overview",this._pollInterval=null,this._councilState=null,this._verdicts=null,this._convergence=[],this._agents=null,this._selectedAgent=null,this._lastDataHash=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null),this._pendingRaf&&(cancelAnimationFrame(this._pendingRaf),this._pendingRaf=null)}async _loadData(){let e=this._api;try{let[i,a,s,r]=await Promise.allSettled([e._get("/api/council/state"),e._get("/api/council/verdicts"),e._get("/api/council/convergence"),e._get("/api/agents")]);if(e!==this._api)return;this._councilState=i.status==="fulfilled"?i.value:null,this._verdicts=a.status==="fulfilled"?a.value?.verdicts||[]:null,s.status==="fulfilled"&&(this._convergence=s.value.dataPoints||[]),this._agents=r.status==="fulfilled"&&Array.isArray(r.value)?r.value:null,this._error=null}catch(i){if(e!==this._api)return;this._error=i.message}let t=JSON.stringify({s:this._councilState,v:this._verdicts,c:this._convergence,a:this._agents,e:this._error});t!==this._lastDataHash&&(this._lastDataHash=t,this.render())}async _forceReview(){try{await this._api._post("/api/council/force-review"),this.dispatchEvent(new CustomEvent("council-action",{detail:{action:"force-review"},bubbles:!0}))}catch(e){this._error=`Failed to force review: ${e.message}`,this.render()}}async _killAgent(e){if(confirm(`Kill agent ${e}?`))try{await this._api._post(`/api/agents/${e}/kill`),this.dispatchEvent(new CustomEvent("council-action",{detail:{action:"kill-agent",agentId:e},bubbles:!0})),await this._loadData()}catch(t){this._error=`Failed to kill agent: ${t.message}`,this.render()}}async _pauseAgent(e){try{await this._api._post(`/api/agents/${e}/pause`),await this._loadData()}catch(t){this._error=`Failed to pause agent: ${t.message}`,this.render()}}async _resumeAgent(e){try{await this._api._post(`/api/agents/${e}/resume`),await this._loadData()}catch(t){this._error=`Failed to resume agent: ${t.message}`,this.render()}}_setTab(e){this._activeTab=e,this.render()}_selectAgent(e){this._selectedAgent=this._selectedAgent?.id===e.id?null:e,this.render()}render(){let e=this.shadowRoot;e&&(this._pendingRaf&&(cancelAnimationFrame(this._pendingRaf),this._pendingRaf=null),e.innerHTML=`
6436
6412
  <style>${this.getBaseStyles()}${this._getStyles()}</style>
6437
6413
  <div class="council-dashboard">
6438
6414
  <div class="council-header">
6439
6415
  <div class="header-left">
6440
6416
  <h2 class="title">Completion Council</h2>
6441
- ${this._councilState?.enabled!==!1?'<span class="badge badge-active">Active</span>':'<span class="badge badge-inactive">Disabled</span>'}
6417
+ ${this._councilState?.enabled===!0?'<span class="badge badge-active">Active</span>':`<span class="badge badge-inactive">${this._councilState?.enabled===!1?"Disabled":"Unknown"}</span>`}
6442
6418
  </div>
6443
6419
  <button class="btn btn-primary" id="force-review-btn">
6444
6420
  Force Review
@@ -6446,7 +6422,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
6446
6422
  </div>
6447
6423
 
6448
6424
  <div class="tabs">
6449
- ${qt.map(t=>`
6425
+ ${Ht.map(t=>`
6450
6426
  <button
6451
6427
  class="tab ${this._activeTab===t.id?"active":""}"
6452
6428
  data-tab="${t.id}"
@@ -6460,40 +6436,40 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
6460
6436
 
6461
6437
  ${this._error?`<div class="error-banner">${this._escapeHtml(this._error)}</div>`:""}
6462
6438
  </div>
6463
- `,this._attachEventListeners())}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.getElementById("force-review-btn");t&&t.addEventListener("click",()=>this._forceReview()),e.querySelectorAll(".tab[data-tab]").forEach(i=>{i.addEventListener("click",()=>this._setTab(i.dataset.tab))})}_renderTabContent(){switch(this._activeTab){case"overview":return this._renderOverview();case"decisions":return this._renderDecisions();case"convergence":return this._renderConvergence();case"agents":return this._renderAgents();default:return""}}_renderOverview(){let e=this._councilState||{},t=e.consecutive_no_change||0,i=e.done_signals||0,a=e.total_votes||0,s=e.approve_votes||0,r=this._verdicts.length>0?this._verdicts[this._verdicts.length-1]:null,o=this._agents.filter(n=>n.alive).length;return`
6439
+ `,this._attachEventListeners())}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.getElementById("force-review-btn");t&&t.addEventListener("click",()=>this._forceReview()),e.querySelectorAll(".tab[data-tab]").forEach(i=>{i.addEventListener("click",()=>this._setTab(i.dataset.tab))})}_renderTabContent(){switch(this._activeTab){case"overview":return this._renderOverview();case"decisions":return this._renderDecisions();case"convergence":return this._renderConvergence();case"agents":return this._renderAgents();default:return""}}_renderOverview(){let e=this._councilState||{},t=c=>c??"--",i=e.consecutive_no_change,a=e.done_signals,s=t(e.total_votes),r=t(e.approve_votes),o=this._verdicts?.length>0?this._verdicts[this._verdicts.length-1]:null,n=this._agents,l=e.enabled===!0?"Monitoring":e.enabled===!1?"Disabled":"Unknown";return`
6464
6440
  <div class="overview-grid">
6465
6441
  <div class="stat-card">
6466
6442
  <div class="stat-label">Council Status</div>
6467
- <div class="stat-value ${e.enabled!==!1?"text-green":"text-muted"}">
6468
- ${e.enabled!==!1?"Monitoring":"Disabled"}
6443
+ <div class="stat-value ${e.enabled===!0?"text-green":"text-muted"}">
6444
+ ${l}
6469
6445
  </div>
6470
6446
  </div>
6471
6447
  <div class="stat-card">
6472
6448
  <div class="stat-label">Total Votes Cast</div>
6473
- <div class="stat-value">${a}</div>
6474
- <div class="stat-sub">${s} approved</div>
6449
+ <div class="stat-value">${s}</div>
6450
+ <div class="stat-sub">${r} approved</div>
6475
6451
  </div>
6476
6452
  <div class="stat-card">
6477
6453
  <div class="stat-label">Stagnation Streak</div>
6478
- <div class="stat-value ${t>=3?"text-warn":""}">${t}</div>
6454
+ <div class="stat-value ${i>=3?"text-warn":""}">${t(i)}</div>
6479
6455
  <div class="stat-sub">consecutive no-change</div>
6480
6456
  </div>
6481
6457
  <div class="stat-card">
6482
6458
  <div class="stat-label">Done Signals</div>
6483
- <div class="stat-value ${i>=2?"text-green":""}">${i}</div>
6459
+ <div class="stat-value ${a>=2?"text-green":""}">${t(a)}</div>
6484
6460
  <div class="stat-sub">from agent output</div>
6485
6461
  </div>
6486
6462
  <div class="stat-card">
6487
6463
  <div class="stat-label">Active Agents</div>
6488
- <div class="stat-value">${o}</div>
6489
- <div class="stat-sub">of ${this._agents.length} total</div>
6464
+ <div class="stat-value">${n?n.filter(c=>c.alive).length:"--"}</div>
6465
+ <div class="stat-sub">${n?`of ${n.length} total`:"agent list unavailable"}</div>
6490
6466
  </div>
6491
6467
  <div class="stat-card">
6492
6468
  <div class="stat-label">Last Verdict</div>
6493
- <div class="stat-value ${r?.result==="APPROVED"?"text-green":"text-muted"}">
6494
- ${r?r.result:"None"}
6469
+ <div class="stat-value ${o?.result==="APPROVED"?"text-green":"text-muted"}">
6470
+ ${o?o.result:this._verdicts?"None":"--"}
6495
6471
  </div>
6496
- ${r?`<div class="stat-sub">iteration ${r.iteration}</div>`:""}
6472
+ ${o?`<div class="stat-sub">iteration ${o.iteration}</div>`:""}
6497
6473
  </div>
6498
6474
  </div>
6499
6475
 
@@ -6514,7 +6490,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
6514
6490
  </div>
6515
6491
  `}).join("")}
6516
6492
  </div>
6517
- `}_renderDecisions(){return this._verdicts.length===0?`<div class="empty-state">No review decisions yet. The council checks for completion every ${this._councilState?.check_interval||5} build steps.</div>`:`
6493
+ `}_renderDecisions(){if(!this._verdicts)return'<div class="empty-state">Review decisions unavailable.</div>';if(this._verdicts.length===0){let e=this._councilState?.check_interval;return`<div class="empty-state">No review decisions yet. The council checks for completion ${e!=null?`every ${e} build steps`:"periodically"}.</div>`}return`
6518
6494
  <div class="decision-list">
6519
6495
  ${this._verdicts.slice().reverse().map(e=>`
6520
6496
  <div class="decision-card ${e.result==="APPROVED"?"decision-approved":"decision-rejected"}">
@@ -6565,7 +6541,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
6565
6541
  </table>
6566
6542
  </div>
6567
6543
  </div>
6568
- `}_renderAgents(){if(this._agents.length===0)return'<div class="empty-state">No agents registered.</div>';let e=`
6544
+ `}_renderAgents(){if(!this._agents)return'<div class="empty-state">Agent list unavailable.</div>';if(this._agents.length===0)return'<div class="empty-state">No agents registered.</div>';let e=`
6569
6545
  <div class="agents-list">
6570
6546
  ${this._agents.map((t,i)=>`
6571
6547
  <div class="agent-card ${this._selectedAgent?.id===t.id?"agent-selected":""}"
@@ -6600,7 +6576,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
6600
6576
  </div>
6601
6577
  `).join("")}
6602
6578
  </div>
6603
- `;return this._pendingRaf=requestAnimationFrame(()=>{this._pendingRaf=null;let t=this.shadowRoot;t&&t.querySelectorAll(".agent-card[data-agent-index]").forEach(i=>{let a=parseInt(i.dataset.agentIndex,10),s=this._agents[a];s&&(i.addEventListener("click",()=>this._selectAgent(s)),i.querySelectorAll("[data-action]").forEach(r=>{r.addEventListener("click",o=>{o.stopPropagation();let n=r.dataset.action,l=r.dataset.agentId;n==="pause"?this._pauseAgent(l):n==="kill"?this._killAgent(l):n==="resume"&&this._resumeAgent(l)})}))})}),e}_formatTime(e){if(!e)return"";try{return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}catch{return e}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
6579
+ `;return this._pendingRaf=requestAnimationFrame(()=>{this._pendingRaf=null;let t=this.shadowRoot;t&&t.querySelectorAll(".agent-card[data-agent-index]").forEach(i=>{let a=parseInt(i.dataset.agentIndex,10),s=this._agents?.[a];s&&(i.addEventListener("click",()=>this._selectAgent(s)),i.querySelectorAll("[data-action]").forEach(r=>{r.addEventListener("click",o=>{o.stopPropagation();let n=r.dataset.action,l=r.dataset.agentId;n==="pause"?this._pauseAgent(l):n==="kill"?this._killAgent(l):n==="resume"&&this._resumeAgent(l)})}))})}),e}_formatTime(e){if(!e)return"";try{return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}catch{return e}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
6604
6580
  :host {
6605
6581
  display: block;
6606
6582
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
@@ -7019,7 +6995,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
7019
6995
  color: var(--loki-error);
7020
6996
  font-size: 12px;
7021
6997
  }
7022
- `}};customElements.get("loki-council-dashboard")||customElements.define("loki-council-dashboard",se);var ht={critical:0,major:1,minor:2},Jt={critical:"var(--loki-status-error, #ef4444)",major:"var(--loki-status-warning, #f59e0b)",minor:"var(--loki-text-muted, #71717a)"},re=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._pollInterval=null,this._checklist=null,this._waivers=[],this._expandedCategories=new Set,this._lastDataHash=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let[t,i]=await Promise.all([e.getChecklist(),e.getChecklistWaivers().catch(()=>null)]);if(e!==this._api)return;let a=JSON.stringify(i),s=JSON.stringify(t)+a;if(s===this._lastDataHash)return;this._lastDataHash=s,this._checklist=t,this._waivers=i&&i.waivers?i.waivers.filter(r=>r.active):[],this._error=null,this.render()}catch(t){if(e!==this._api)return;this._error=`Failed to load checklist: ${t.message}`,this.render()}}_isItemWaived(e){return this._waivers.some(t=>t.item_id===e)}_getWaiverForItem(e){return this._waivers.find(t=>t.item_id===e)||null}async _waiveItem(e){let t=window.prompt("Enter reason for waiving this item:");if(!t)return;let i=this._api;try{if(await i.addChecklistWaiver(e,t),i!==this._api)return;this._lastDataHash=null,await this._loadData()}catch(a){if(i!==this._api)return;this._error=`Failed to add waiver: ${a.message}`,this.render()}}async _unwaiveItem(e){let t=this._api;try{if(await t.removeChecklistWaiver(e),t!==this._api)return;this._lastDataHash=null,await this._loadData()}catch(i){if(t!==this._api)return;this._error=`Failed to remove waiver: ${i.message}`,this.render()}}_toggleCategory(e){this._expandedCategories.has(e)?this._expandedCategories.delete(e):this._expandedCategories.add(e),this.render()}_getStyles(){return`
6998
+ `}};customElements.get("loki-council-dashboard")||customElements.define("loki-council-dashboard",ae);var st={critical:0,major:1,minor:2},Mt={critical:"var(--loki-status-error, #ef4444)",major:"var(--loki-status-warning, #f59e0b)",minor:"var(--loki-text-muted, #71717a)"},se=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._pollInterval=null,this._checklist=null,this._waivers=null,this._expandedCategories=new Set,this._lastDataHash=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let[t,i]=await Promise.all([e.getChecklist(),e.getChecklistWaivers().catch(()=>null)]);if(e!==this._api)return;let a=JSON.stringify(i),s=JSON.stringify(t)+a;if(s===this._lastDataHash)return;this._lastDataHash=s,this._checklist=t,this._waivers=i&&!i.error&&Array.isArray(i.waivers)?i.waivers.filter(r=>r.active):null,this._error=null,this.render()}catch(t){if(e!==this._api)return;this._error=`Failed to load checklist: ${t.message}`,this.render()}}_isItemWaived(e){return(this._waivers||[]).some(t=>t.item_id===e)}_getWaiverForItem(e){return(this._waivers||[]).find(t=>t.item_id===e)||null}async _waiveItem(e){let t=window.prompt("Enter reason for waiving this item:");if(!t)return;let i=this._api;try{if(await i.addChecklistWaiver(e,t),i!==this._api)return;this._lastDataHash=null,await this._loadData()}catch(a){if(i!==this._api)return;this._error=`Failed to add waiver: ${a.message}`,this.render()}}async _unwaiveItem(e){let t=this._api;try{if(await t.removeChecklistWaiver(e),t!==this._api)return;this._lastDataHash=null,await this._loadData()}catch(i){if(t!==this._api)return;this._error=`Failed to remove waiver: ${i.message}`,this.render()}}_toggleCategory(e){this._expandedCategories.has(e)?this._expandedCategories.delete(e):this._expandedCategories.add(e),this.render()}_getStyles(){return`
7023
6999
  .checklist-viewer {
7024
7000
  padding: 16px;
7025
7001
  font-family: var(--loki-font-family, system-ui, -apple-system, sans-serif);
@@ -7267,7 +7243,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
7267
7243
  border-radius: 4px;
7268
7244
  font-size: 12px;
7269
7245
  }
7270
- `}_getUnwaivedCriticalFailures(){if(!this._checklist?.categories)return[];let e=[];for(let t of this._checklist.categories)for(let i of t.items||[])i.status==="failing"&&i.priority==="critical"&&!this._isItemWaived(i.id)&&e.push(i);return e}_renderGateBanner(){let e=this._getUnwaivedCriticalFailures();return e.length>0?`<div class="gate-banner gate-blocked">COUNCIL GATE: BLOCKED - ${e.length} critical item${e.length!==1?"s":""} must be verified or waived before completion</div>`:'<div class="gate-banner gate-passed">COUNCIL GATE: PASSED - No blocking critical failures</div>'}render(){let e=this.shadowRoot;if(!e)return;let t=this._checklist,i=t&&t.status!=="not_initialized"&&t.categories?.length>0;e.innerHTML=`
7246
+ `}_getUnwaivedCriticalFailures(){if(!this._checklist?.categories)return[];let e=[];for(let t of this._checklist.categories)for(let i of t.items||[])i.status==="failing"&&i.priority==="critical"&&!this._isItemWaived(i.id)&&e.push(i);return e}_renderGateBanner(){let e=this._getUnwaivedCriticalFailures();return e.length>0&&!this._waivers?`<div class="gate-banner gate-blocked">COUNCIL GATE: UNKNOWN - ${e.length} critical item${e.length!==1?"s":""} failing, waivers could not be read</div>`:e.length>0?`<div class="gate-banner gate-blocked">COUNCIL GATE: BLOCKED - ${e.length} critical item${e.length!==1?"s":""} must be verified or waived before completion</div>`:'<div class="gate-banner gate-passed">COUNCIL GATE: NOT BLOCKED - no critical item is failing</div>'}render(){let e=this.shadowRoot;if(!e)return;let t=this._checklist,i=t&&t.status!=="not_initialized"&&t.categories?.length>0;e.innerHTML=`
7271
7247
  <style>${this.getBaseStyles()}${this._getStyles()}</style>
7272
7248
  <div class="checklist-viewer">
7273
7249
  <div class="checklist-header">
@@ -7279,11 +7255,11 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
7279
7255
  ${i?this._renderCategories(t.categories):this._renderEmpty()}
7280
7256
  ${this._error?`<div class="error-banner">${this._escapeHtml(this._error)}</div>`:""}
7281
7257
  </div>
7282
- `,this._attachEventListeners()}_renderBadges(e){if(!e)return"";let t=this._waivers.length;return`
7258
+ `,this._attachEventListeners()}_renderBadges(e){if(!e)return"";let t=this._waivers?this._waivers.length:null;return`
7283
7259
  <div class="summary-badges">
7284
7260
  ${e.verified?`<span class="badge badge-verified">${e.verified} verified</span>`:""}
7285
7261
  ${e.failing?`<span class="badge badge-failing">${e.failing} failing</span>`:""}
7286
- ${t?`<span class="badge badge-waived">${t} waived</span>`:""}
7262
+ ${t==null?'<span class="badge badge-waived">waivers unknown</span>':t?`<span class="badge badge-waived">${t} waived</span>`:""}
7287
7263
  ${e.pending?`<span class="badge badge-pending">${e.pending} pending</span>`:""}
7288
7264
  </div>
7289
7265
  `}_renderProgress(e){if(!e||!e.total)return"";let t=e.verified/e.total*100,i=e.failing/e.total*100;return`
@@ -7293,7 +7269,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
7293
7269
  <div class="progress-failing" style="width: ${i}%"></div>
7294
7270
  </div>
7295
7271
  <div class="progress-label">
7296
- <span>${e.verified}/${e.total} verified | ${e.failing||0} failing | ${this._waivers.length} waived | ${e.pending||0} pending</span>
7272
+ <span>${e.verified}/${e.total} verified | ${e.failing??"--"} failing | ${this._waivers?`${this._waivers.length} waived`:"waivers unknown"} | ${e.pending??"--"} pending</span>
7297
7273
  <span>${Math.round(t)}%</span>
7298
7274
  </div>
7299
7275
  </div>
@@ -7308,7 +7284,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
7308
7284
  </div>
7309
7285
  ${i?`<div class="category-body">${this._renderItems(a)}</div>`:""}
7310
7286
  </div>
7311
- `}).join(""):this._renderEmpty()}_renderItems(e){return e?.length?[...e].sort((i,a)=>(ht[i.priority]??2)-(ht[a.priority]??2)).map(i=>{let a=i.status==="verified"?"status-verified":i.status==="failing"?"status-failing":"status-pending",s=["critical","major","minor"].includes(i.priority)?i.priority:"minor",r=Jt[s],o=i.verification||[],n=this._getWaiverForItem(i.id),l=!!n,c=i.status==="failing"&&(s==="critical"||s==="major"),p=l?`<span class="item-waived-badge" title="${this._escapeHtml(n.reason||"No reason provided")}">WAIVED</span>`:"",u="";return c&&(l?u=`<button class="waiver-btn waiver-btn-unwaive" data-unwaive-id="${this._escapeHtml(i.id)}">Unwaive</button>`:u=`<button class="waiver-btn" data-waive-id="${this._escapeHtml(i.id)}">Waive</button>`),`
7287
+ `}).join(""):this._renderEmpty()}_renderItems(e){return e?.length?[...e].sort((i,a)=>(st[i.priority]??2)-(st[a.priority]??2)).map(i=>{let a=i.status==="verified"?"status-verified":i.status==="failing"?"status-failing":"status-pending",s=["critical","major","minor"].includes(i.priority)?i.priority:"minor",r=Mt[s],o=i.verification||[],n=this._getWaiverForItem(i.id),l=!!n,c=i.status==="failing"&&(s==="critical"||s==="major"),p=l?`<span class="item-waived-badge" title="${this._escapeHtml(n.reason||"No reason provided")}">WAIVED</span>`:"",u="";return c&&(l?u=`<button class="waiver-btn waiver-btn-unwaive" data-unwaive-id="${this._escapeHtml(i.id)}">Unwaive</button>`:u=`<button class="waiver-btn" data-waive-id="${this._escapeHtml(i.id)}">Waive</button>`),`
7312
7288
  <div class="item">
7313
7289
  <div class="item-status ${a}"></div>
7314
7290
  <div class="item-title">${this._escapeHtml(i.title||i.id||"?")}</div>
@@ -7324,7 +7300,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
7324
7300
  <p><strong>No checklist data yet.</strong></p>
7325
7301
  <p class="hint">The spec checklist is generated during the first iteration. Start a session with <code>loki start ./spec.md</code> (PRD files also accepted) -- groups and items will appear here as the session progresses and can be expanded for details.</p>
7326
7302
  </div>
7327
- `}_attachEventListeners(){let e=this.shadowRoot;e&&(e.querySelectorAll(".category-header[data-category]").forEach(t=>{t.addEventListener("click",()=>this._toggleCategory(t.dataset.category))}),e.querySelectorAll("button[data-waive-id]").forEach(t=>{t.addEventListener("click",i=>{i.stopPropagation(),this._waiveItem(t.dataset.waiveId)})}),e.querySelectorAll("button[data-unwaive-id]").forEach(t=>{t.addEventListener("click",i=>{i.stopPropagation(),this._unwaiveItem(t.dataset.unwaiveId)})}))}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}};customElements.define("loki-checklist-viewer",re);var gt={not_initialized:{color:"var(--loki-text-muted, #71717a)",label:"Not Started",pulse:!1},starting:{color:"var(--loki-yellow, #ca8a04)",label:"Starting...",pulse:!0},running:{color:"var(--loki-green, #16a34a)",label:"Running",pulse:!0},stale:{color:"var(--loki-yellow, #ca8a04)",label:"Stale",pulse:!1},completed:{color:"var(--loki-text-muted, #a1a1aa)",label:"Completed",pulse:!1},failed:{color:"var(--loki-red, #dc2626)",label:"Failed",pulse:!1},crashed:{color:"var(--loki-red, #dc2626)",label:"Crashed",pulse:!1},stopped:{color:"var(--loki-text-muted, #a1a1aa)",label:"Stopped",pulse:!1},unknown:{color:"var(--loki-text-muted, #71717a)",label:"Unknown",pulse:!1}},oe=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._pollInterval=null,this._status=null,this._logs=[],this._lastDataHash=null,this._lastLogsHash=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let[t,i]=await Promise.all([e.getAppRunnerStatus(),e.getAppRunnerLogs()]);if(e!==this._api)return;let a=JSON.stringify({status:t?.status,port:t?.port,restarts:t?.restart_count,url:t?.url,services:Array.isArray(t?.services)?t.services.map(o=>`${o?.url||""}|${o?.name||""}`).join(","):null}),s=JSON.stringify(i?.lines?.slice(-5)||[]),r=s!==this._lastLogsHash;if(a===this._lastDataHash&&!r)return;this._lastDataHash=a,this._lastLogsHash=s,this._status=t,this._logs=i?.lines||[],this._error=null,this.render(),this._scrollLogsToBottom()}catch(t){if(e!==this._api)return;this._error||(this._error=`Failed to load app status: ${t.message}`,this.render())}}_scrollLogsToBottom(){let e=this.shadowRoot;if(!e)return;let t=e.querySelector(".log-area");t&&(t.scrollTop=t.scrollHeight)}async _handleRestart(){let e=this._api;try{if(await e.restartApp(),e!==this._api)return;this._loadData()}catch(t){if(e!==this._api)return;this._error=`Restart failed: ${t.message}`,this.render()}}async _handleStop(){let e=this._api;try{if(await e.stopApp(),e!==this._api)return;this._loadData()}catch(t){if(e!==this._api)return;this._error=`Stop failed: ${t.message}`,this.render()}}_formatUptime(e){if(!e)return"--";let t=new Date(e),a=Math.floor((new Date-t)/1e3);if(a<60)return`${a}s`;if(a<3600)return`${Math.floor(a/60)}m ${a%60}s`;let s=Math.floor(a/3600),r=Math.floor(a%3600/60);return`${s}h ${r}m`}_isValidUrl(e){if(!e)return!1;try{let t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}}_extraServices(e){if(!e||!Array.isArray(e.services))return[];let t=e.url||"",i=[],a=new Set;for(let s of e.services){if(!s||typeof s.url!="string"||!s.url||s.url===t||a.has(s.url))continue;a.add(s.url);let r=typeof s.name=="string"?s.name.trim():"",o=typeof s.role=="string"?s.role.trim():"",n=s.port!=null?String(s.port):"",l=r||o||(n?`Port ${n}`:"Service");i.push({url:s.url,label:l,urlValid:this._isValidUrl(s.url)})}return i}_getStyles(){return`
7303
+ `}_attachEventListeners(){let e=this.shadowRoot;e&&(e.querySelectorAll(".category-header[data-category]").forEach(t=>{t.addEventListener("click",()=>this._toggleCategory(t.dataset.category))}),e.querySelectorAll("button[data-waive-id]").forEach(t=>{t.addEventListener("click",i=>{i.stopPropagation(),this._waiveItem(t.dataset.waiveId)})}),e.querySelectorAll("button[data-unwaive-id]").forEach(t=>{t.addEventListener("click",i=>{i.stopPropagation(),this._unwaiveItem(t.dataset.unwaiveId)})}))}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}};customElements.define("loki-checklist-viewer",se);var Ge={not_initialized:{color:"var(--loki-text-muted, #71717a)",label:"Not Started",pulse:!1},starting:{color:"var(--loki-yellow, #ca8a04)",label:"Starting...",pulse:!0},running:{color:"var(--loki-green, #16a34a)",label:"Running",pulse:!0},stale:{color:"var(--loki-yellow, #ca8a04)",label:"Stale",pulse:!1},completed:{color:"var(--loki-text-muted, #a1a1aa)",label:"Completed",pulse:!1},failed:{color:"var(--loki-red, #dc2626)",label:"Failed",pulse:!1},crashed:{color:"var(--loki-red, #dc2626)",label:"Crashed",pulse:!1},stopped:{color:"var(--loki-text-muted, #a1a1aa)",label:"Stopped",pulse:!1},unknown:{color:"var(--loki-text-muted, #71717a)",label:"Unknown",pulse:!1}},re=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._pollInterval=null,this._status=null,this._logs=[],this._lastDataHash=null,this._lastLogsHash=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let[t,i]=await Promise.all([e.getAppRunnerStatus(),e.getAppRunnerLogs()]);if(e!==this._api)return;let a=JSON.stringify({status:t?.status,port:t?.port,restarts:t?.restart_count,url:t?.url,services:Array.isArray(t?.services)?t.services.map(o=>`${o?.url||""}|${o?.name||""}`).join(","):null}),s=JSON.stringify(i?.lines?.slice(-5)||[]),r=s!==this._lastLogsHash;if(a===this._lastDataHash&&!r)return;this._lastDataHash=a,this._lastLogsHash=s,this._status=t,this._logs=i?.lines||[],this._error=null,this.render(),this._scrollLogsToBottom()}catch(t){if(e!==this._api)return;this._error||(this._error=`Failed to load app status: ${t.message}`,this._status=null,this._lastDataHash=null,this.render())}}_scrollLogsToBottom(){let e=this.shadowRoot;if(!e)return;let t=e.querySelector(".log-area");t&&(t.scrollTop=t.scrollHeight)}async _handleRestart(){let e=this._api;try{if(await e.restartApp(),e!==this._api)return;this._loadData()}catch(t){if(e!==this._api)return;this._error=`Restart failed: ${t.message}`,this.render()}}async _handleStop(){let e=this._api;try{if(await e.stopApp(),e!==this._api)return;this._loadData()}catch(t){if(e!==this._api)return;this._error=`Stop failed: ${t.message}`,this.render()}}_formatUptime(e){if(!e)return"--";let t=new Date(e),a=Math.floor((new Date-t)/1e3);if(a<60)return`${a}s`;if(a<3600)return`${Math.floor(a/60)}m ${a%60}s`;let s=Math.floor(a/3600),r=Math.floor(a%3600/60);return`${s}h ${r}m`}_isValidUrl(e){if(!e)return!1;try{let t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}}_extraServices(e){if(!e||!Array.isArray(e.services))return[];let t=e.url||"",i=[],a=new Set;for(let s of e.services){if(!s||typeof s.url!="string"||!s.url||s.url===t||a.has(s.url))continue;a.add(s.url);let r=typeof s.name=="string"?s.name.trim():"",o=typeof s.role=="string"?s.role.trim():"",n=s.port!=null?String(s.port):"",l=r||o||(n?`Port ${n}`:"Service");i.push({url:s.url,label:l,urlValid:this._isValidUrl(s.url)})}return i}_getStyles(){return`
7328
7304
  .app-status {
7329
7305
  padding: 16px;
7330
7306
  font-family: var(--loki-font-family, system-ui, -apple-system, sans-serif);
@@ -7485,7 +7461,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
7485
7461
  border-radius: 4px;
7486
7462
  font-size: 12px;
7487
7463
  }
7488
- `}render(){let e=this.shadowRoot;if(!e)return;let t=this._status,i=t&&t.status&&t.status!=="not_initialized";e.innerHTML=`
7464
+ `}render(){let e=this.shadowRoot;if(!e)return;let t=this._status,i=t?.status||"unknown",a=!!Ge[i]&&i!=="not_initialized"&&i!=="unknown";e.innerHTML=`
7489
7465
  <style>${this.getBaseStyles()}${this._getStyles()}</style>
7490
7466
  <div class="app-status">
7491
7467
  <div class="header">
@@ -7493,14 +7469,14 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
7493
7469
  <h2 class="title">App Status</h2>
7494
7470
  ${this._renderStatusBadge(t)}
7495
7471
  </div>
7496
- ${i?this._renderActions(t):""}
7472
+ ${a?this._renderActions(t):""}
7497
7473
  </div>
7498
- ${i?this._renderStatusCard(t):""}
7499
- ${i&&this._logs.length>0?this._renderLogs():""}
7500
- ${i?"":this._renderEmpty()}
7474
+ ${a?this._renderStatusCard(t):""}
7475
+ ${a&&this._logs.length>0?this._renderLogs():""}
7476
+ ${a?"":this._renderEmpty(i)}
7501
7477
  ${this._error?`<div class="error-banner">${this._escapeHtml(this._error)}</div>`:""}
7502
7478
  </div>
7503
- `,this._attachEventListeners()}_renderStatusBadge(e){let t=e?.status||"not_initialized",i=gt[t]||gt.not_initialized;return`
7479
+ `,this._attachEventListeners()}_renderStatusBadge(e){let t=e?.status||"unknown",i=Ge[t]||Ge.unknown;return`
7504
7480
  <span class="status-badge" style="background: color-mix(in srgb, ${i.color} 15%, transparent); color: ${i.color}">
7505
7481
  <span class="status-dot ${i.pulse?"pulse":""}" style="background: ${i.color}"></span>
7506
7482
  ${this._escapeHtml(i.label)}
@@ -7551,12 +7527,12 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
7551
7527
  <button class="btn" data-action="restart" ${t?"":"disabled"}>Restart</button>
7552
7528
  <button class="btn btn-danger" data-action="stop" ${i?"":"disabled"}>Stop</button>
7553
7529
  </div>
7554
- `}_renderEmpty(){return`
7530
+ `}_renderEmpty(e){return e!=="not_initialized"?'<div class="empty-state"><p>App status unknown</p></div>':`
7555
7531
  <div class="empty-state">
7556
7532
  <p>App not running yet</p>
7557
7533
  <p class="hint">Your app will start automatically after the first successful build step.</p>
7558
7534
  </div>
7559
- `}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.querySelector('[data-action="restart"]'),i=e.querySelector('[data-action="stop"]');t&&t.addEventListener("click",()=>this._handleRestart()),i&&i.addEventListener("click",()=>this._handleStop())}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}};customElements.define("loki-app-status",oe);var mt={not_initialized:{color:"var(--loki-text-muted, #71717a)",label:"No app yet",pulse:!1},starting:{color:"var(--loki-yellow, #ca8a04)",label:"Starting",pulse:!0},running:{color:"var(--loki-green, #16a34a)",label:"Running",pulse:!0},stale:{color:"var(--loki-yellow, #ca8a04)",label:"Stale",pulse:!1},completed:{color:"var(--loki-text-muted, #a1a1aa)",label:"Completed",pulse:!1},failed:{color:"var(--loki-red, #dc2626)",label:"Could not start",pulse:!1},crashed:{color:"var(--loki-red, #dc2626)",label:"Crashed",pulse:!1},stopped:{color:"var(--loki-text-muted, #a1a1aa)",label:"Stopped",pulse:!1},error:{color:"var(--loki-text-muted, #71717a)",label:"Status unavailable",pulse:!1},unknown:{color:"var(--loki-text-muted, #71717a)",label:"Unknown",pulse:!1}},ne=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._api=null,this._pollInterval=null,this._status=null,this._errors=null,this._error=null,this._lastDataHash=null,this._detailsOpen=!1,this._iframeFailed=!1,this._iframeLoadTimer=null,this._IFRAME_LOAD_TIMEOUT_MS=6e3,this._activeServiceKey=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this.render(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling(),this._clearIframeLoadTimer()}_clearIframeLoadTimer(){this._iframeLoadTimer&&(clearTimeout(this._iframeLoadTimer),this._iframeLoadTimer=null)}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let t=await e.getAppRunnerStatus();if(e!==this._api)return;let i=t?.status||"not_initialized",a=null;if(i==="crashed"||i==="failed")try{a=await e.getAppRunnerErrors(50)}catch{a=null}if(e!==this._api)return;let s=JSON.stringify({status:i,port:t?.port,url:t?.url,crash:t?.crash_count,errLen:a?.lines?.length||0,extMgd:t?.externally_managed===!0,source:t?.source||null,healthOk:t?.last_health?.ok===!0?"ok":t?.last_health?.ok===!1?"down":"unknown",services:Array.isArray(t?.services)?t.services.map(o=>`${o?.url||""}|${o?.role||""}|${o?.name||""}`).join(","):null}),r=this._error!==null;if(s===this._lastDataHash&&!r)return;this._iframeFailed=!1,this._lastDataHash=s,this._status=t,this._errors=a,this._error=null,this.render()}catch(t){if(e!==this._api)return;this._error||(this._error=`Could not read app status: ${t.message}`,this.render())}}_isValidUrl(e){if(!e)return!1;try{let t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}}_getServices(){let e=this._status;if(!e)return[];let t=Array.isArray(e.services)&&e.services.length>0?e.services:[{url:e.url,role:"",name:e.primary_service||"",port:e.port}],i=new Set,a=[];for(let s of t){if(!s||!this._isValidUrl(s.url))continue;let r=typeof s.name=="string"?s.name.trim():"",o=s.port!=null?String(s.port):"",n=this._inferServiceRole(s.role,r),l=s.url||r||o;if(i.has(l))continue;i.add(l);let c=r;c||(c=n==="api"?"API":n==="ui"?"UI":""),c||(c=o?`Port ${o}`:"Service"),a.push({key:l,url:s.url,role:n,name:r,port:o,label:c})}return a}_inferServiceRole(e,t){let i=typeof e=="string"?e.trim().toLowerCase():"";if(i==="ui"||i==="web"||i==="frontend")return"ui";if(i==="api"||i==="backend"||i==="server")return"api";let a=(t||"").toLowerCase();return/\b(api|backend|server|graphql|grpc)\b/.test(a)||a.includes("api")?"api":""}_activeService(e){if(!e||e.length===0)return null;if(this._activeServiceKey){let t=e.find(i=>i.key===this._activeServiceKey);if(t)return t}return e[0]}_handleSelectService(e){this._activeServiceKey!==e&&(this._activeServiceKey=e,this._iframeFailed=!1,this.render())}async _handleRestart(){let e=this._api;try{if(await e.restartApp(),e!==this._api)return;this._loadData()}catch(t){if(e!==this._api)return;this._error=`Restart failed: ${t.message}`,this.render()}}_currentTargetUrl(){let e=this._activeService(this._getServices());if(e&&this._isValidUrl(e.url))return e.url;let t=this._status;return t&&this._isValidUrl(t.url)?t.url:""}_handleRefresh(){let e=this.shadowRoot;if(!e)return;let t=e.querySelector("iframe.preview-frame"),i=this._currentTargetUrl();if(t&&i){this._iframeFailed=!1,this._clearIframeLoadTimer();let a=(i.includes("?")?"&":"?")+"_t="+Date.now();t.src=i+a,this._armIframeLoadDetection()}}_handleRetryFrame(){this._iframeFailed=!1,this._lastDataHash=null,this.render(),this._loadData()}_handleOpenExternal(){let e=this._currentTargetUrl();e&&window.open(e,"_blank","noopener")}_toggleDetails(){this._detailsOpen=!this._detailsOpen,this.render()}_getStyles(){return`
7535
+ `}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.querySelector('[data-action="restart"]'),i=e.querySelector('[data-action="stop"]');t&&t.addEventListener("click",()=>this._handleRestart()),i&&i.addEventListener("click",()=>this._handleStop())}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}};customElements.define("loki-app-status",re);var rt={not_initialized:{color:"var(--loki-text-muted, #71717a)",label:"No app yet",pulse:!1},starting:{color:"var(--loki-yellow, #ca8a04)",label:"Starting",pulse:!0},running:{color:"var(--loki-green, #16a34a)",label:"Running",pulse:!0},stale:{color:"var(--loki-yellow, #ca8a04)",label:"Stale",pulse:!1},completed:{color:"var(--loki-text-muted, #a1a1aa)",label:"Completed",pulse:!1},failed:{color:"var(--loki-red, #dc2626)",label:"Could not start",pulse:!1},crashed:{color:"var(--loki-red, #dc2626)",label:"Crashed",pulse:!1},stopped:{color:"var(--loki-text-muted, #a1a1aa)",label:"Stopped",pulse:!1},error:{color:"var(--loki-text-muted, #71717a)",label:"Status unavailable",pulse:!1},unknown:{color:"var(--loki-text-muted, #71717a)",label:"Unknown",pulse:!1}},oe=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._api=null,this._pollInterval=null,this._status=null,this._errors=null,this._error=null,this._lastDataHash=null,this._detailsOpen=!1,this._iframeFailed=!1,this._iframeLoadTimer=null,this._IFRAME_LOAD_TIMEOUT_MS=6e3,this._activeServiceKey=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this.render(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling(),this._clearIframeLoadTimer()}_clearIframeLoadTimer(){this._iframeLoadTimer&&(clearTimeout(this._iframeLoadTimer),this._iframeLoadTimer=null)}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let t=await e.getAppRunnerStatus();if(e!==this._api)return;let i=t?.status||"unknown",a=null;if(i==="crashed"||i==="failed")try{a=await e.getAppRunnerErrors(50)}catch{a=null}if(e!==this._api)return;let s=JSON.stringify({status:i,port:t?.port,url:t?.url,crash:t?.crash_count,errLen:a?.lines?.length||0,errRead:a!=null,extMgd:t?.externally_managed===!0,source:t?.source||null,healthOk:t?.last_health?.ok===!0?"ok":t?.last_health?.ok===!1?"down":"unknown",services:Array.isArray(t?.services)?t.services.map(o=>`${o?.url||""}|${o?.role||""}|${o?.name||""}`).join(","):null}),r=this._error!==null;if(s===this._lastDataHash&&!r)return;this._iframeFailed=!1,this._lastDataHash=s,this._status=t,this._errors=a,this._error=null,this.render()}catch(t){if(e!==this._api)return;this._error||(this._error=`Could not read app status: ${t.message}`,this.render())}}_isValidUrl(e){if(!e)return!1;try{let t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}}_getServices(){let e=this._status;if(!e)return[];let t=Array.isArray(e.services)&&e.services.length>0?e.services:[{url:e.url,role:"",name:e.primary_service||"",port:e.port}],i=new Set,a=[];for(let s of t){if(!s||!this._isValidUrl(s.url))continue;let r=typeof s.name=="string"?s.name.trim():"",o=s.port!=null?String(s.port):"",n=this._inferServiceRole(s.role,r),l=s.url||r||o;if(i.has(l))continue;i.add(l);let c=r;c||(c=n==="api"?"API":n==="ui"?"UI":""),c||(c=o?`Port ${o}`:"Service"),a.push({key:l,url:s.url,role:n,name:r,port:o,label:c})}return a}_inferServiceRole(e,t){let i=typeof e=="string"?e.trim().toLowerCase():"";if(i==="ui"||i==="web"||i==="frontend")return"ui";if(i==="api"||i==="backend"||i==="server")return"api";let a=(t||"").toLowerCase();return/\b(api|backend|server|graphql|grpc)\b/.test(a)||a.includes("api")?"api":""}_activeService(e){if(!e||e.length===0)return null;if(this._activeServiceKey){let t=e.find(i=>i.key===this._activeServiceKey);if(t)return t}return e[0]}_handleSelectService(e){this._activeServiceKey!==e&&(this._activeServiceKey=e,this._iframeFailed=!1,this.render())}async _handleRestart(){let e=this._api;try{if(await e.restartApp(),e!==this._api)return;this._loadData()}catch(t){if(e!==this._api)return;this._error=`Restart failed: ${t.message}`,this.render()}}_currentTargetUrl(){let e=this._activeService(this._getServices());if(e&&this._isValidUrl(e.url))return e.url;let t=this._status;return t&&this._isValidUrl(t.url)?t.url:""}_handleRefresh(){let e=this.shadowRoot;if(!e)return;let t=e.querySelector("iframe.preview-frame"),i=this._currentTargetUrl();if(t&&i){this._iframeFailed=!1,this._clearIframeLoadTimer();let a=(i.includes("?")?"&":"?")+"_t="+Date.now();t.src=i+a,this._armIframeLoadDetection()}}_handleRetryFrame(){this._iframeFailed=!1,this._lastDataHash=null,this.render(),this._loadData()}_handleOpenExternal(){let e=this._currentTargetUrl();e&&window.open(e,"_blank","noopener")}_toggleDetails(){this._detailsOpen=!this._detailsOpen,this.render()}_getStyles(){return`
7560
7536
  .preview { padding: 16px; font-family: var(--loki-font-family, system-ui, -apple-system, sans-serif); color: var(--loki-text-primary, #201515); display: flex; flex-direction: column; width: 100%; box-sizing: border-box; }
7561
7537
  .header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; gap: 12px; flex-wrap: wrap; }
7562
7538
  .header-left { display: flex; align-items: center; gap: 10px; }
@@ -7606,7 +7582,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
7606
7582
  .details-toggle:hover { text-decoration: underline; }
7607
7583
  .details-body { margin-top: 8px; background: var(--loki-bg-code, #1e1e1e); color: #d4d4d4; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; padding: 10px; border-radius: 6px; max-height: 200px; overflow: auto; white-space: pre-wrap; }
7608
7584
  .error-banner { margin-top: 12px; padding: 10px 12px; border-radius: 6px; background: color-mix(in srgb, var(--loki-red, #dc2626) 10%, transparent); color: var(--loki-red, #dc2626); font-size: 13px; }
7609
- `}_effectiveView(e,t){let i=this._status,a=i?.last_health,s=a&&typeof a.ok=="boolean"?a.ok:null;if(e==="running"&&t&&(i?.externally_managed===!0||i?.source==="discovered"))return{view:"running",healthOk:s};if(e==="running"&&t){if(s===!1)return{view:"starting",healthOk:s};if(s===!0)return{view:"running",healthOk:s};let r=i?.started_at?Date.parse(i.started_at):NaN;return{view:Number.isFinite(r)&&Date.now()-r<15e3?"running":"starting",healthOk:s}}return{view:e,healthOk:s}}render(){let e=this.shadowRoot;if(!e)return;this._clearIframeLoadTimer();let t=this._status,i=t?.status||"not_initialized",a=this._getServices(),s=this._activeService(a),r=a.length>1,o=s?.url||t?.url,n=this._isValidUrl(o),{view:l,healthOk:c}=this._effectiveView(i,n),p=t?.externally_managed===!0||t?.source==="discovered",u=mt[l]||mt.not_initialized,m=i==="running"&&c===!1?"Starting / not responding yet":u.label;e.innerHTML=`
7585
+ `}_effectiveView(e,t){let i=this._status,a=i?.last_health,s=a&&typeof a.ok=="boolean"?a.ok:null;if(e==="running"&&t&&(i?.externally_managed===!0||i?.source==="discovered"))return{view:"running",healthOk:s};if(e==="running"&&t){if(s===!1)return{view:"starting",healthOk:s};if(s===!0)return{view:"running",healthOk:s};let r=i?.started_at?Date.parse(i.started_at):NaN;return{view:Number.isFinite(r)&&Date.now()-r<15e3?"running":"starting",healthOk:s}}return{view:e,healthOk:s}}render(){let e=this.shadowRoot;if(!e)return;this._clearIframeLoadTimer();let t=this._status,i=t?.status||"unknown",a=this._getServices(),s=this._activeService(a),r=a.length>1,o=s?.url||t?.url,n=this._isValidUrl(o),{view:l,healthOk:c}=this._effectiveView(i,n),p=t?.externally_managed===!0||t?.source==="discovered",u=rt[l]||rt.unknown,m=i==="running"&&c===!1?"Starting / not responding yet":u.label;e.innerHTML=`
7610
7586
  <style>${this.getBaseStyles()}${this._getStyles()}</style>
7611
7587
  <div class="preview">
7612
7588
  <div class="header">
@@ -7709,13 +7685,22 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
7709
7685
  <h3>Status unavailable</h3>
7710
7686
  <p>Could not read the app status. Try refreshing.</p>
7711
7687
  </div>
7712
- `:`
7688
+ `:e==="not_initialized"?`
7713
7689
  <div class="state-block">
7714
7690
  <h3>No app running yet</h3>
7715
7691
  <p>Loki has not started your app yet. It will appear here automatically once the build is running.</p>
7716
7692
  </div>
7693
+ `:e==="completed"?`
7694
+ <div class="state-block">
7695
+ <h3>App is not running</h3>
7696
+ <p>The app run has completed.</p>
7697
+ </div>
7698
+ `:`
7699
+ <div class="state-block">
7700
+ <h3>${this._error?"Could not read app status":"Checking app status..."}</h3>
7701
+ </div>
7717
7702
  `}_renderErrorBanner(e){if(e!=="crashed"&&e!=="failed")return"";let t=e==="crashed"?"Your app stopped after an error":"Loki could not start your app",i=e==="crashed"?"Loki detected a crash in the running app.":"The app did not start.",a=this._errors&&Array.isArray(this._errors.lines)?this._errors.lines:[],s=a.length>0?a.map(r=>this._escapeHtml(r)).join(`
7718
- `):"No error output captured yet.";return`
7703
+ `):this._errors?"No error output captured yet.":"Could not read error output.";return`
7719
7704
  <div class="err-banner">
7720
7705
  <p class="err-head">${this._escapeHtml(t)}</p>
7721
7706
  <p class="err-body">${this._escapeHtml(i)}</p>
@@ -7727,7 +7712,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
7727
7712
  </button>
7728
7713
  ${this._detailsOpen?`<div class="details-body">${s}</div>`:""}
7729
7714
  </div>
7730
- `}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=(i,a)=>{let s=e.querySelector(i);s&&s.addEventListener("click",a)};e.querySelectorAll('[data-action="restart"]').forEach(i=>i.addEventListener("click",()=>this._handleRestart())),e.querySelectorAll('[data-action="open-external"]').forEach(i=>i.addEventListener("click",()=>this._handleOpenExternal())),e.querySelectorAll('[data-action="retry-frame"]').forEach(i=>i.addEventListener("click",()=>this._handleRetryFrame())),t('[data-action="refresh"]',()=>this._handleRefresh()),t('[data-action="toggle-details"]',()=>this._toggleDetails()),e.querySelectorAll('[data-action="select-service"]').forEach(i=>i.addEventListener("click",()=>this._handleSelectService(i.getAttribute("data-service-key"))))}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}};customElements.define("loki-app-preview",ne);var Gt={opus:{input:5,output:25,label:"Opus 4.6",provider:"claude"},sonnet:{input:3,output:15,label:"Sonnet 5",provider:"claude"},haiku:{input:1,output:5,label:"Haiku 4.5",provider:"claude"},"gpt-5.3-codex":{input:1.5,output:12,label:"GPT-5.3 Codex",provider:"codex"}},le=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._data={total_input_tokens:null,total_output_tokens:null,estimated_cost_usd:null,by_phase:{},by_model:{},budget_limit:null,budget_used:null,budget_remaining:null,connected:!1},this._api=null,this._pollInterval=null,this._modelPricing={...Gt}}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadPricing(),this._loadCost(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadCost()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadPricing(){let e=this._api;try{let t=await e.getPricing();if(e!==this._api)return;if(t&&t.models){let i={};for(let[a,s]of Object.entries(t.models))i[a]={input:s.input,output:s.output,label:s.label||a,provider:s.provider||"unknown",note:s.note||""};this._modelPricing=i,this._pricingSource=t.source||"api",this._pricingDate=t.updated||"",this._activeProvider=t.provider||"claude",this.render()}}catch{}}async _loadCost(){let e=this._api;try{let t=await e.getCost();if(e!==this._api)return;this._updateFromCost(t)}catch{if(e!==this._api)return;this._data.connected=!1,this.render()}}_updateFromCost(e){e&&(this._data={...this._data,connected:!0,total_input_tokens:e.total_input_tokens??null,total_output_tokens:e.total_output_tokens??null,estimated_cost_usd:e.estimated_cost_usd??null,by_phase:e.by_phase||{},by_model:e.by_model||{},budget_limit:e.budget_limit,budget_used:e.budget_used??null,budget_remaining:e.budget_remaining},this.render())}_startPolling(){this._poll=b({loadFn:()=>this._loadCost(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_formatTokens(e){return Ne(e)}_formatUSD(e){return B(e)}_getBudgetPercent(){return!this._data.budget_limit||this._data.budget_limit<=0?0:Math.min(100,(this._data.budget_used??0)/this._data.budget_limit*100)}_getBudgetStatusClass(){let e=this._getBudgetPercent();return e>=90?"critical":e>=70?"warning":"ok"}_renderPhaseRows(){let e=this._data.by_phase;return!e||Object.keys(e).length===0?'<tr><td colspan="4" class="empty-cell">No phase data yet</td></tr>':Object.entries(e).map(([t,i])=>{let a=i.input_tokens??null,s=i.output_tokens??null,r=i.cost_usd??null;return`
7715
+ `}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=(i,a)=>{let s=e.querySelector(i);s&&s.addEventListener("click",a)};e.querySelectorAll('[data-action="restart"]').forEach(i=>i.addEventListener("click",()=>this._handleRestart())),e.querySelectorAll('[data-action="open-external"]').forEach(i=>i.addEventListener("click",()=>this._handleOpenExternal())),e.querySelectorAll('[data-action="retry-frame"]').forEach(i=>i.addEventListener("click",()=>this._handleRetryFrame())),t('[data-action="refresh"]',()=>this._handleRefresh()),t('[data-action="toggle-details"]',()=>this._toggleDetails()),e.querySelectorAll('[data-action="select-service"]').forEach(i=>i.addEventListener("click",()=>this._handleSelectService(i.getAttribute("data-service-key"))))}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}};customElements.define("loki-app-preview",oe);var Dt={opus:{input:5,output:25,label:"Opus 4.6",provider:"claude"},sonnet:{input:3,output:15,label:"Sonnet 5",provider:"claude"},haiku:{input:1,output:5,label:"Haiku 4.5",provider:"claude"},"gpt-5.3-codex":{input:1.5,output:12,label:"GPT-5.3 Codex",provider:"codex"}},ne=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._data={total_input_tokens:null,total_output_tokens:null,estimated_cost_usd:null,by_phase:{},by_model:{},budget_limit:null,budget_used:null,budget_remaining:null,connected:!1},this._api=null,this._pollInterval=null,this._modelPricing={...Dt}}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadPricing(),this._loadCost(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadCost()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadPricing(){let e=this._api;try{let t=await e.getPricing();if(e!==this._api)return;if(t&&t.models){let i={};for(let[a,s]of Object.entries(t.models))i[a]={input:s.input,output:s.output,label:s.label||a,provider:s.provider||"unknown",note:s.note||""};this._modelPricing=i,this._pricingSource=t.source||"api",this._pricingDate=t.updated||"",this._activeProvider=t.provider||"claude",this.render()}}catch{}}async _loadCost(){let e=this._api;try{let t=await e.getCost();if(e!==this._api)return;this._updateFromCost(t)}catch{if(e!==this._api)return;this._data.connected=!1,this.render()}}_updateFromCost(e){e&&(this._data={...this._data,connected:!0,total_input_tokens:e.total_input_tokens??null,total_output_tokens:e.total_output_tokens??null,estimated_cost_usd:e.estimated_cost_usd??null,by_phase:e.by_phase||{},by_model:e.by_model||{},budget_limit:e.budget_limit,budget_used:e.budget_used??null,budget_remaining:e.budget_remaining},this.render())}_startPolling(){this._poll=b({loadFn:()=>this._loadCost(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_formatTokens(e){return De(e)}_formatUSD(e){return T(e)}_getBudgetPercent(){return!this._data.budget_limit||this._data.budget_limit<=0?0:Math.min(100,(this._data.budget_used??0)/this._data.budget_limit*100)}_getBudgetStatusClass(){let e=this._getBudgetPercent();return e>=90?"critical":e>=70?"warning":"ok"}_renderPhaseRows(){let e=this._data.by_phase;return!e||Object.keys(e).length===0?'<tr><td colspan="4" class="empty-cell">No phase data yet</td></tr>':Object.entries(e).map(([t,i])=>{let a=i.input_tokens??null,s=i.output_tokens??null,r=i.cost_usd??null;return`
7731
7716
  <tr>
7732
7717
  <td class="phase-name">${this._escapeHTML(t)}</td>
7733
7718
  <td class="mono-cell">${this._formatTokens(a)}</td>
@@ -8131,13 +8116,13 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
8131
8116
  ${Object.entries(this._modelPricing).map(([a,s])=>`
8132
8117
  <div class="pricing-item">
8133
8118
  <div class="pricing-model ${this._getPricingColorClass(a,s)}">${this._escapeHTML(s.label||a)}</div>
8134
- <div class="pricing-rates">In: $${Number(s.input??0).toFixed(2)} / Out: $${Number(s.output??0).toFixed(2)}</div>
8119
+ <div class="pricing-rates">In: ${T(s.input)} / Out: ${T(s.output)}</div>
8135
8120
  ${s.note?`<div class="pricing-note">${this._escapeHTML(s.note)}</div>`:""}
8136
8121
  </div>`).join("")}
8137
8122
  </div>
8138
8123
  </div>
8139
8124
  </div>
8140
- `}};customElements.get("loki-cost-dashboard")||customElements.define("loki-cost-dashboard",le);var de=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._checkpoints=[],this._pollInterval=null,this._lastDataHash=null,this._showCreateForm=!1,this._creating=!1,this._rollingBack=!1,this._rollbackTarget=null,this._notice=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let[i]=await Promise.allSettled([e._get("/api/checkpoints?limit=50")]);if(e!==this._api)return;i.status==="fulfilled"&&(this._checkpoints=Array.isArray(i.value)?i.value:i.value?.checkpoints||[]),this._error=null}catch(i){if(e!==this._api)return;this._error=i.message}let t=JSON.stringify({c:this._checkpoints,e:this._error});t!==this._lastDataHash&&(this._lastDataHash=t,this.render())}async _createCheckpoint(){let e=this.shadowRoot.getElementById("checkpoint-message"),t=e?e.value.trim():"";if(t){this._creating=!0,this.render();try{await this._api._post("/api/checkpoints",{message:t}),this._showCreateForm=!1,this._creating=!1,this.dispatchEvent(new CustomEvent("checkpoint-action",{detail:{action:"create",message:t},bubbles:!0})),this._lastDataHash=null,await this._loadData()}catch(i){this._creating=!1,this._error=`Failed to create checkpoint: ${i.message}`,this.render()}}}async _rollbackCheckpoint(e){if(!this._rollingBack){this._rollingBack=!0,this._notice=null,this.render();try{let t=await this._api._post(`/api/checkpoints/${e}/rollback`);this._rollbackTarget=null;let i=t&&t.pre_rollback_snapshot;this._notice=i?`Rolled back to ${e}. Undo this with checkpoint ${i}`:`Rolled back to ${e}.`,this.dispatchEvent(new CustomEvent("checkpoint-action",{detail:{action:"rollback",checkpointId:e,preRollbackSnapshot:i||null},bubbles:!0})),this._lastDataHash=null,await this._loadData()}catch(t){this._rollbackTarget=null,this._error=`Failed to rollback: ${t.message}`}finally{this._rollingBack=!1,this.render()}}}_toggleCreateForm(){this._showCreateForm=!this._showCreateForm,this._rollbackTarget=null,this._notice=null,this.render()}_confirmRollback(e){this._rollbackTarget=e,this.render()}_cancelRollback(){this._rollbackTarget=null,this._notice=null,this.render()}_formatRelativeTime(e){if(!e)return"";try{let t=Date.now(),i=new Date(e).getTime(),a=Math.floor((t-i)/1e3);return a<60?`${a}s ago`:a<3600?`${Math.floor(a/60)}m ago`:a<86400?`${Math.floor(a/3600)}h ago`:`${Math.floor(a/86400)}d ago`}catch{return this._escapeHTML(e)}}render(){let e=this.shadowRoot;if(!e)return;let t=this._checkpoints.length;e.innerHTML=`
8125
+ `}};customElements.get("loki-cost-dashboard")||customElements.define("loki-cost-dashboard",ne);var le=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._checkpoints=[],this._pollInterval=null,this._lastDataHash=null,this._showCreateForm=!1,this._creating=!1,this._rollingBack=!1,this._rollbackTarget=null,this._notice=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let[i]=await Promise.allSettled([e._get("/api/checkpoints?limit=50")]);if(e!==this._api)return;i.status==="fulfilled"&&(this._checkpoints=Array.isArray(i.value)?i.value:i.value?.checkpoints||[]),this._error=null}catch(i){if(e!==this._api)return;this._error=i.message}let t=JSON.stringify({c:this._checkpoints,e:this._error});t!==this._lastDataHash&&(this._lastDataHash=t,this.render())}async _createCheckpoint(){let e=this.shadowRoot.getElementById("checkpoint-message"),t=e?e.value.trim():"";if(t){this._creating=!0,this.render();try{await this._api._post("/api/checkpoints",{message:t}),this._showCreateForm=!1,this._creating=!1,this.dispatchEvent(new CustomEvent("checkpoint-action",{detail:{action:"create",message:t},bubbles:!0})),this._lastDataHash=null,await this._loadData()}catch(i){this._creating=!1,this._error=`Failed to create checkpoint: ${i.message}`,this.render()}}}async _rollbackCheckpoint(e){if(!this._rollingBack){this._rollingBack=!0,this._notice=null,this.render();try{let t=await this._api._post(`/api/checkpoints/${e}/rollback`);this._rollbackTarget=null;let i=t&&t.pre_rollback_snapshot;this._notice=i?`Rolled back to ${e}. Undo this with checkpoint ${i}`:`Rolled back to ${e}.`,this.dispatchEvent(new CustomEvent("checkpoint-action",{detail:{action:"rollback",checkpointId:e,preRollbackSnapshot:i||null},bubbles:!0})),this._lastDataHash=null,await this._loadData()}catch(t){this._rollbackTarget=null,this._error=`Failed to rollback: ${t.message}`}finally{this._rollingBack=!1,this.render()}}}_toggleCreateForm(){this._showCreateForm=!this._showCreateForm,this._rollbackTarget=null,this._notice=null,this.render()}_confirmRollback(e){this._rollbackTarget=e,this.render()}_cancelRollback(){this._rollbackTarget=null,this._notice=null,this.render()}_formatRelativeTime(e){if(!e)return"";try{let t=Date.now(),i=new Date(e).getTime(),a=Math.floor((t-i)/1e3);return a<60?`${a}s ago`:a<3600?`${Math.floor(a/60)}m ago`:a<86400?`${Math.floor(a/3600)}h ago`:`${Math.floor(a/86400)}d ago`}catch{return this._escapeHTML(e)}}render(){let e=this.shadowRoot;if(!e)return;let t=this._checkpoints.length;e.innerHTML=`
8141
8126
  <style>${this.getBaseStyles()}${this._getStyles()}</style>
8142
8127
  <div class="checkpoint-viewer">
8143
8128
  <div class="checkpoint-header">
@@ -8456,32 +8441,32 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
8456
8441
  color: var(--loki-green, #22c55e);
8457
8442
  font-size: 12px;
8458
8443
  }
8459
- `}};customElements.get("loki-checkpoint-viewer")||customElements.define("loki-checkpoint-viewer",de);var ce=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._data=null,this._connected=!1,this._activeTab="gauge",this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadContext(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadContext()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadContext(){let e=this._api;try{let t=this.getAttribute("api-url")||window.location.origin,i=await fetch(t+"/api/context");if(i.ok){let a=await i.json();if(e!==this._api)return;this._data=a,this._connected=!0}}catch{if(e!==this._api)return;this._connected=!1}this.render()}_startPolling(){this._poll=b({loadFn:()=>this._loadContext(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_setTab(e){this._activeTab=e,this.render()}_formatTokens(e){return e==null||Number.isNaN(e)?"unknown":e>=1e6?(e/1e6).toFixed(2)+"M":e>=1e3?(e/1e3).toFixed(1)+"K":String(e)}_formatUSD(e){return e==null||Number.isNaN(e)?"unknown":e===0?"$0.00":e<.01?"<$0.01":"$"+e.toFixed(2)}_sumTokens(e){let t=[e.input_tokens,e.output_tokens,e.cache_read_tokens,e.cache_creation_tokens];return t.every(i=>i==null)?null:t.reduce((i,a)=>i+(a??0),0)}_escapeHTML(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getGaugeColor(e){return e>80?"var(--loki-red)":e>=60?"var(--loki-yellow)":"var(--loki-green)"}_getGaugeColorClass(e){return e>80?"gauge-red":e>=60?"gauge-yellow":"gauge-green"}_renderGaugeTab(){let e=this._data?.current||{},t=this._data?.totals||{},i=e.context_window_pct||0,a=this._getGaugeColor(i),s=this._getGaugeColorClass(i),r=70,o=2*Math.PI*r,n=o-i/100*o;return`
8444
+ `}};customElements.get("loki-checkpoint-viewer")||customElements.define("loki-checkpoint-viewer",le);var de=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._data=null,this._connected=!1,this._activeTab="gauge",this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadContext(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadContext()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadContext(){let e=this._api;try{let t=this.getAttribute("api-url")||window.location.origin,i=await fetch(t+"/api/context");if(i.ok){let a=await i.json();if(e!==this._api)return;this._data=a,this._connected=!0,this._loadError=null}else{if(e!==this._api)return;this._connected=!1,this._loadError=`Context API unavailable (HTTP ${i.status})`}}catch{if(e!==this._api)return;this._connected=!1,this._loadError="Context API unreachable"}this.render()}_startPolling(){this._poll=b({loadFn:()=>this._loadContext(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_setTab(e){this._activeTab=e,this.render()}_formatTokens(e){return e==null||Number.isNaN(e)?"unknown":e>=1e6?(e/1e6).toFixed(2)+"M":e>=1e3?(e/1e3).toFixed(1)+"K":String(e)}_formatUSD(e){return e==null||Number.isNaN(e)?"unknown":e===0?"$0.00":e<.01?"<$0.01":"$"+e.toFixed(2)}_sumTokens(e){let t=[e.input_tokens,e.output_tokens,e.cache_read_tokens,e.cache_creation_tokens];return t.every(i=>i==null)?null:t.reduce((i,a)=>i+(a??0),0)}_escapeHTML(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getGaugeColor(e){return e>80?"var(--loki-red)":e>=60?"var(--loki-yellow)":"var(--loki-green)"}_getGaugeColorClass(e){return e>80?"gauge-red":e>=60?"gauge-yellow":"gauge-green"}_renderGaugeTab(){let e=!!this._data?.updated_at,t=e&&this._data.current||{},i=e&&this._data.totals||{},a=typeof t.context_window_pct=="number"?t.context_window_pct:null,s=a==null?"unknown":a.toFixed(1)+"%",r=this._getGaugeColor(a),o=this._getGaugeColorClass(a),n=70,l=2*Math.PI*n,c=a==null?l:l-a/100*l;return`
8460
8445
  <div class="gauge-tab">
8461
8446
  <div class="gauge-container">
8462
- <svg class="gauge-svg" viewBox="0 0 180 180" aria-label="Context window usage: ${i.toFixed(1)}%">
8447
+ <svg class="gauge-svg" viewBox="0 0 180 180" aria-label="Context window usage: ${s}">
8463
8448
  <circle
8464
8449
  class="gauge-bg"
8465
- cx="90" cy="90" r="${r}"
8450
+ cx="90" cy="90" r="${n}"
8466
8451
  fill="none"
8467
8452
  stroke="var(--loki-bg-tertiary)"
8468
8453
  stroke-width="12"
8469
8454
  />
8470
8455
  <circle
8471
- class="gauge-ring ${s}"
8472
- cx="90" cy="90" r="${r}"
8456
+ class="gauge-ring ${o}"
8457
+ cx="90" cy="90" r="${n}"
8473
8458
  fill="none"
8474
- stroke="${a}"
8459
+ stroke="${r}"
8475
8460
  stroke-width="12"
8476
8461
  stroke-linecap="round"
8477
- stroke-dasharray="${o}"
8478
- stroke-dashoffset="${n}"
8462
+ stroke-dasharray="${l}"
8463
+ stroke-dashoffset="${c}"
8479
8464
  transform="rotate(-90 90 90)"
8480
8465
  />
8481
8466
  <text class="gauge-pct" x="90" y="85" text-anchor="middle"
8482
8467
  fill="var(--loki-text-primary)" font-size="28" font-weight="600"
8483
8468
  font-family="'JetBrains Mono', monospace">
8484
- ${i.toFixed(1)}%
8469
+ ${s}
8485
8470
  </text>
8486
8471
  <text class="gauge-label" x="90" y="108" text-anchor="middle"
8487
8472
  fill="var(--loki-text-muted)" font-size="11">
@@ -8493,20 +8478,20 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
8493
8478
  <div class="summary-grid">
8494
8479
  <div class="summary-card">
8495
8480
  <div class="card-label">Total Tokens</div>
8496
- <div class="card-value">${this._formatTokens(e.total_tokens)}</div>
8497
- <div class="card-sub">${this._formatTokens(e.input_tokens)} in / ${this._formatTokens(e.output_tokens)} out</div>
8481
+ <div class="card-value">${this._formatTokens(t.total_tokens)}</div>
8482
+ <div class="card-sub">${this._formatTokens(t.input_tokens)} in / ${this._formatTokens(t.output_tokens)} out</div>
8498
8483
  </div>
8499
8484
  <div class="summary-card">
8500
8485
  <div class="card-label">Estimated Cost</div>
8501
- <div class="card-value accent">${this._formatUSD(e.estimated_cost_usd)}</div>
8486
+ <div class="card-value accent">${this._formatUSD(t.estimated_cost_usd)}</div>
8502
8487
  </div>
8503
8488
  <div class="summary-card">
8504
8489
  <div class="card-label">Compactions</div>
8505
- <div class="card-value">${t.compaction_count||0}</div>
8490
+ <div class="card-value">${i.compaction_count??"--"}</div>
8506
8491
  </div>
8507
8492
  <div class="summary-card">
8508
8493
  <div class="card-label">Iterations Tracked</div>
8509
- <div class="card-value">${t.iterations_tracked||0}</div>
8494
+ <div class="card-value">${i.iterations_tracked??"--"}</div>
8510
8495
  </div>
8511
8496
  </div>
8512
8497
 
@@ -8522,11 +8507,11 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
8522
8507
  <div class="cache-grid">
8523
8508
  <div class="cache-item">
8524
8509
  <span class="cache-label">Cache Read</span>
8525
- <span class="cache-value">${this._formatTokens(e.cache_read_tokens)}</span>
8510
+ <span class="cache-value">${this._formatTokens(t.cache_read_tokens)}</span>
8526
8511
  </div>
8527
8512
  <div class="cache-item">
8528
8513
  <span class="cache-label">Cache Creation</span>
8529
- <span class="cache-value">${this._formatTokens(e.cache_creation_tokens)}</span>
8514
+ <span class="cache-value">${this._formatTokens(t.cache_creation_tokens)}</span>
8530
8515
  </div>
8531
8516
  </div>
8532
8517
  </div>
@@ -8968,7 +8953,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
8968
8953
 
8969
8954
  <div class="context-container">
8970
8955
  ${this._connected?"":`
8971
- <div class="offline-notice">Connecting to context API...</div>
8956
+ <div class="offline-notice">${this._escapeHTML(this._loadError||"Connecting to context API...")}</div>
8972
8957
  `}
8973
8958
 
8974
8959
  <div class="tabs">
@@ -8979,9 +8964,9 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
8979
8964
 
8980
8965
  ${e}
8981
8966
  </div>
8982
- `,this.shadowRoot.querySelectorAll(".tab").forEach(t=>{t.addEventListener("click",()=>{this._setTab(t.dataset.tab)})})}};customElements.get("loki-context-tracker")||customElements.define("loki-context-tracker",ce);var Qe={critical:"var(--loki-red, #ef4444)",warning:"var(--loki-yellow, #eab308)",info:"var(--loki-blue, #3b82f6)",success:"var(--loki-green, #1FC5A8)"},vt={build:{label:"Build",icon:"B"},quality:{label:"Quality",icon:"Q"},system:{label:"System",icon:"S"},security:{label:"Security",icon:"!"}},pe=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._notifications=[],this._triggers=[],this._summary={},this._connected=!1,this._activeTab="feed",this._categoryFilter="all",this._panelOpen=!0,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._loadNotifications(),this._loadTriggers(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&(this._loadNotifications(),this._loadTriggers()),e==="theme"&&this._applyTheme())}async _loadNotifications(){try{let e=this.getAttribute("api-url")||window.location.origin,t=await fetch(e+"/api/notifications");if(t.ok){let i=await t.json();this._notifications=i.notifications||[],this._summary=i.summary||{},this._connected=!0}}catch{this._connected=!1}this.render()}async _loadTriggers(){try{let e=this.getAttribute("api-url")||window.location.origin,t=await fetch(e+"/api/notifications/triggers");if(t.ok){let i=await t.json();this._triggers=i.triggers||[]}}catch{}}async _acknowledgeNotification(e){let t=this.getAttribute("api-url")||window.location.origin;try{await fetch(t+"/api/notifications/"+encodeURIComponent(e)+"/acknowledge",{method:"POST"})}catch{}this._loadNotifications()}async _unacknowledgeNotification(e){let t=this.getAttribute("api-url")||window.location.origin;await fetch(t+"/api/notifications/"+encodeURIComponent(e)+"/unacknowledge",{method:"POST"}),this._loadNotifications()}async _acknowledgeAll(){let e=this.getAttribute("api-url")||window.location.origin,t=this._notifications.filter(i=>!i.acknowledged);for(let i of t)await fetch(e+"/api/notifications/"+encodeURIComponent(i.id)+"/acknowledge",{method:"POST"});this._loadNotifications()}async _toggleTrigger(e,t){let i=this.getAttribute("api-url")||window.location.origin,a=this._triggers.map(s=>s.id===e?{...s,enabled:t}:s);await fetch(i+"/api/notifications/triggers",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({triggers:a})}),this._triggers=a,this.render()}_startPolling(){this._poll=b({loadFn:()=>{this._loadNotifications(),this._loadTriggers()},intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_formatTime(e){if(!e)return"";try{let t=new Date(e),a=new Date-t,s=Math.floor(a/1e3),r=Math.floor(s/60),o=Math.floor(r/60),n=Math.floor(o/24);return s<60?s+"s ago":r<60?r+"m ago":o<24?o+"h ago":n<7?n+"d ago":t.toLocaleDateString()}catch{return String(e)}}_getTimeGroup(e){if(!e)return"Other";try{let t=new Date(e),i=new Date,a=new Date(i.getFullYear(),i.getMonth(),i.getDate()),s=new Date(a);s.setDate(s.getDate()-1);let r=new Date(a);return r.setDate(r.getDate()-7),t>=a?"Today":t>=s?"Yesterday":t>=r?"This Week":"Earlier"}catch{return"Other"}}_escapeHTML(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getSeverityColor(e){return Qe[e]||Qe.info}_getCategory(e){return e.category||e.type||"system"}_switchTab(e){this._activeTab=e,this.render()}_setCategoryFilter(e){this._categoryFilter=e,this.render()}_togglePanel(){this._panelOpen=!this._panelOpen,this.render()}_bindEvents(){let e=this.shadowRoot;e.querySelectorAll(".tab").forEach(a=>{a.addEventListener("click",()=>{this._switchTab(a.dataset.tab)})}),e.querySelectorAll(".cat-btn").forEach(a=>{a.addEventListener("click",()=>{this._setCategoryFilter(a.dataset.cat)})}),e.querySelectorAll(".ack-btn").forEach(a=>{a.addEventListener("click",s=>{s.stopPropagation(),this._acknowledgeNotification(a.dataset.id)})}),e.querySelectorAll(".unread-btn").forEach(a=>{a.addEventListener("click",s=>{s.stopPropagation(),this._unacknowledgeNotification(a.dataset.id)})});let t=e.querySelector(".ack-all-btn");t&&t.addEventListener("click",()=>{this._acknowledgeAll()});let i=e.querySelector(".bell-icon");i&&i.addEventListener("click",()=>{this._togglePanel()}),e.querySelectorAll(".toggle input").forEach(a=>{a.addEventListener("change",()=>{this._toggleTrigger(a.dataset.triggerId,a.checked)})}),e.querySelectorAll(".dismiss-btn").forEach(a=>{a.addEventListener("click",s=>{s.stopPropagation(),this._acknowledgeNotification(a.dataset.id)})})}_renderBellIcon(){let e=this._summary.unacknowledged||0;return`
8967
+ `,this.shadowRoot.querySelectorAll(".tab").forEach(t=>{t.addEventListener("click",()=>{this._setTab(t.dataset.tab)})})}};customElements.get("loki-context-tracker")||customElements.define("loki-context-tracker",de);var Je={critical:"var(--loki-red, #ef4444)",warning:"var(--loki-yellow, #eab308)",info:"var(--loki-blue, #3b82f6)",success:"var(--loki-green, #1FC5A8)"},ot={build:{label:"Build",icon:"B"},quality:{label:"Quality",icon:"Q"},system:{label:"System",icon:"S"},security:{label:"Security",icon:"!"}},ce=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._notifications=[],this._triggers=[],this._summary=null,this._connected=!1,this._loadFailed=!1,this._activeTab="feed",this._categoryFilter="all",this._panelOpen=!0,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._loadNotifications(),this._loadTriggers(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&(this._loadNotifications(),this._loadTriggers()),e==="theme"&&this._applyTheme())}async _loadNotifications(){try{let e=this.getAttribute("api-url")||window.location.origin,t=await fetch(e+"/api/notifications");if(t.ok){let i=await t.json();this._notifications=i.notifications||[],this._summary=i.summary||null,this._connected=!0,this._loadFailed=!1}else this._markLoadFailed()}catch{this._markLoadFailed()}this.render()}_markLoadFailed(){this._connected=!1,this._loadFailed=!0,this._summary=null}async _loadTriggers(){try{let e=this.getAttribute("api-url")||window.location.origin,t=await fetch(e+"/api/notifications/triggers");if(t.ok){let i=await t.json();this._triggers=i.triggers||[]}}catch{}}async _acknowledgeNotification(e){let t=this.getAttribute("api-url")||window.location.origin;try{await fetch(t+"/api/notifications/"+encodeURIComponent(e)+"/acknowledge",{method:"POST"})}catch{}this._loadNotifications()}async _unacknowledgeNotification(e){let t=this.getAttribute("api-url")||window.location.origin;await fetch(t+"/api/notifications/"+encodeURIComponent(e)+"/unacknowledge",{method:"POST"}),this._loadNotifications()}async _acknowledgeAll(){let e=this.getAttribute("api-url")||window.location.origin,t=this._notifications.filter(i=>!i.acknowledged);for(let i of t)await fetch(e+"/api/notifications/"+encodeURIComponent(i.id)+"/acknowledge",{method:"POST"});this._loadNotifications()}async _toggleTrigger(e,t){let i=this.getAttribute("api-url")||window.location.origin,a=this._triggers.map(s=>s.id===e?{...s,enabled:t}:s);await fetch(i+"/api/notifications/triggers",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({triggers:a})}),this._triggers=a,this.render()}_startPolling(){this._poll=b({loadFn:()=>{this._loadNotifications(),this._loadTriggers()},intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_formatTime(e){if(!e)return"";try{let t=new Date(e),a=new Date-t,s=Math.floor(a/1e3),r=Math.floor(s/60),o=Math.floor(r/60),n=Math.floor(o/24);return s<60?s+"s ago":r<60?r+"m ago":o<24?o+"h ago":n<7?n+"d ago":t.toLocaleDateString()}catch{return String(e)}}_getTimeGroup(e){if(!e)return"Other";try{let t=new Date(e),i=new Date,a=new Date(i.getFullYear(),i.getMonth(),i.getDate()),s=new Date(a);s.setDate(s.getDate()-1);let r=new Date(a);return r.setDate(r.getDate()-7),t>=a?"Today":t>=s?"Yesterday":t>=r?"This Week":"Earlier"}catch{return"Other"}}_escapeHTML(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getSeverityColor(e){return Je[e]||Je.info}_getCategory(e){return e.category||e.type||"system"}_switchTab(e){this._activeTab=e,this.render()}_setCategoryFilter(e){this._categoryFilter=e,this.render()}_togglePanel(){this._panelOpen=!this._panelOpen,this.render()}_bindEvents(){let e=this.shadowRoot;e.querySelectorAll(".tab").forEach(a=>{a.addEventListener("click",()=>{this._switchTab(a.dataset.tab)})}),e.querySelectorAll(".cat-btn").forEach(a=>{a.addEventListener("click",()=>{this._setCategoryFilter(a.dataset.cat)})}),e.querySelectorAll(".ack-btn").forEach(a=>{a.addEventListener("click",s=>{s.stopPropagation(),this._acknowledgeNotification(a.dataset.id)})}),e.querySelectorAll(".unread-btn").forEach(a=>{a.addEventListener("click",s=>{s.stopPropagation(),this._unacknowledgeNotification(a.dataset.id)})});let t=e.querySelector(".ack-all-btn");t&&t.addEventListener("click",()=>{this._acknowledgeAll()});let i=e.querySelector(".bell-icon");i&&i.addEventListener("click",()=>{this._togglePanel()}),e.querySelectorAll(".toggle input").forEach(a=>{a.addEventListener("change",()=>{this._toggleTrigger(a.dataset.triggerId,a.checked)})}),e.querySelectorAll(".dismiss-btn").forEach(a=>{a.addEventListener("click",s=>{s.stopPropagation(),this._acknowledgeNotification(a.dataset.id)})})}_renderBellIcon(){let e=this._summary?.unacknowledged;return`
8983
8968
  <div class="bell-container">
8984
- <button class="bell-icon" title="${e} unread notifications">
8969
+ <button class="bell-icon" title="${e!=null?`${e} unread notifications`:"Unread count unknown"}">
8985
8970
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
8986
8971
  <path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
8987
8972
  <path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
@@ -8989,31 +8974,31 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
8989
8974
  ${e>0?`<span class="badge">${e>99?"99+":e}</span>`:""}
8990
8975
  </button>
8991
8976
  </div>
8992
- `}_renderSummaryBar(){let e=this._summary.total||0,t=this._summary.unacknowledged||0,i=this._summary.critical||0;return`
8977
+ `}_renderSummaryBar(){let e=s=>s??"--",t=e(this._summary?.total),i=this._summary?.unacknowledged,a=e(this._summary?.critical);return`
8993
8978
  <div class="summary-row">
8994
8979
  <div class="summary-grid">
8995
8980
  <div class="summary-card">
8996
8981
  <div class="card-label">Total</div>
8997
- <div class="card-value">${e}</div>
8982
+ <div class="card-value">${t}</div>
8998
8983
  </div>
8999
8984
  <div class="summary-card">
9000
8985
  <div class="card-label">Unread</div>
9001
- <div class="card-value">${t}</div>
8986
+ <div class="card-value">${e(i)}</div>
9002
8987
  </div>
9003
8988
  <div class="summary-card">
9004
8989
  <div class="card-label">Critical</div>
9005
- <div class="card-value" style="color: ${Qe.critical}">${i}</div>
8990
+ <div class="card-value" style="color: ${Je.critical}">${a}</div>
9006
8991
  </div>
9007
8992
  </div>
9008
- ${t>0?`
8993
+ ${i>0?`
9009
8994
  <button class="ack-all-btn">Mark All as Read</button>
9010
8995
  `:""}
9011
8996
  </div>
9012
8997
  `}_renderCategoryFilter(){return`
9013
8998
  <div class="category-bar">
9014
- ${["all","build","quality","system","security"].map(t=>{let i=this._categoryFilter===t,a=t==="all"?"All":vt[t]?.label||t;return`<button class="cat-btn ${i?"active":""}" data-cat="${t}">${a}</button>`}).join("")}
8999
+ ${["all","build","quality","system","security"].map(t=>{let i=this._categoryFilter===t,a=t==="all"?"All":ot[t]?.label||t;return`<button class="cat-btn ${i?"active":""}" data-cat="${t}">${a}</button>`}).join("")}
9015
9000
  </div>
9016
- `}_renderNotificationList(){let e=[...this._notifications].sort((s,r)=>new Date(r.timestamp)-new Date(s.timestamp));if(this._categoryFilter!=="all"&&(e=e.filter(s=>this._getCategory(s)===this._categoryFilter)),e.length===0)return'<div class="empty-state">No notifications</div>';let t={};for(let s of e){let r=this._getTimeGroup(s.timestamp);t[r]||(t[r]=[]),t[r].push(s)}let i=["Today","Yesterday","This Week","Earlier","Other"],a="";for(let s of i)!t[s]||t[s].length===0||(a+=`<div class="time-group-label">${s}</div>`,a+=t[s].map(r=>{let o=r.acknowledged,n=this._getSeverityColor(r.severity),l=this._getCategory(r),c=vt[l]||{label:l,icon:"?"};return`
9001
+ `}_renderNotificationList(){let e=[...this._notifications].sort((s,r)=>new Date(r.timestamp)-new Date(s.timestamp));if(this._categoryFilter!=="all"&&(e=e.filter(s=>this._getCategory(s)===this._categoryFilter)),!this._connected)return'<div class="empty-state">Notifications not loaded</div>';if(e.length===0)return'<div class="empty-state">No notifications</div>';let t={};for(let s of e){let r=this._getTimeGroup(s.timestamp);t[r]||(t[r]=[]),t[r].push(s)}let i=["Today","Yesterday","This Week","Earlier","Other"],a="";for(let s of i)!t[s]||t[s].length===0||(a+=`<div class="time-group-label">${s}</div>`,a+=t[s].map(r=>{let o=r.acknowledged,n=this._getSeverityColor(r.severity),l=this._getCategory(r),c=ot[l]||{label:l,icon:"?"};return`
9017
9002
  <div class="notif-row ${o?"acknowledged":""}">
9018
9003
  <span class="severity-dot" style="background: ${n};" title="${this._escapeHTML(r.severity)}"></span>
9019
9004
  <span class="cat-icon" title="${this._escapeHTML(c.label)}">${c.icon}</span>
@@ -9470,7 +9455,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
9470
9455
  <div class="notif-container">
9471
9456
  ${this._renderBellIcon()}
9472
9457
 
9473
- ${this._connected?"":'<div class="offline-notice">Connecting to notifications API...</div>'}
9458
+ ${this._connected?"":`<div class="offline-notice">${this._loadFailed?"Could not reach notifications API, retrying...":"Connecting to notifications API..."}</div>`}
9474
9459
 
9475
9460
  ${this._panelOpen?`
9476
9461
  <!-- Tabs -->
@@ -9496,7 +9481,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
9496
9481
  `:""}
9497
9482
  `:""}
9498
9483
  </div>
9499
- `,this._bindEvents()}};customElements.get("loki-notification-center")||customElements.define("loki-notification-center",pe);var ue=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._data=null,this._error=null,this._loading=!0,this._api=null,this._pollInterval=null,this._expandedDecisions=new Set}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;try{let t=await e._get("/api/session-diff");if(e!==this._api)return;this._data=t,this._error=null}catch(t){if(e!==this._api)return;this._error=t.message,this._data=null}this._loading=!1,this.render()}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_toggleDecision(e){this._expandedDecisions.has(e)?this._expandedDecisions.delete(e):this._expandedDecisions.add(e),this.render()}render(){let e=`
9484
+ `,this._bindEvents()}};customElements.get("loki-notification-center")||customElements.define("loki-notification-center",ce);var pe=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._data=null,this._error=null,this._loading=!0,this._api=null,this._pollInterval=null,this._expandedDecisions=new Set}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;try{let t=await e._get("/api/session-diff");if(e!==this._api)return;this._data=t,this._error=null}catch(t){if(e!==this._api)return;this._error=t.message,this._data=null}this._loading=!1,this.render()}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_toggleDecision(e){this._expandedDecisions.has(e)?this._expandedDecisions.delete(e):this._expandedDecisions.add(e),this.render()}render(){let e=`
9500
9485
  ${this.getBaseStyles()}
9501
9486
 
9502
9487
  :host {
@@ -9705,9 +9690,9 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
9705
9690
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 013 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
9706
9691
  <span class="diff-title">Session Resume</span>
9707
9692
  </div>
9708
- <div class="empty-state">Nothing to compare yet. Changes will show here after your first build.</div>
9693
+ <div class="empty-state">Could not load session diff: ${this._escapeHtml(this._error)}</div>
9709
9694
  </div>
9710
- `;return}let t=this._data||{},i=this._escapeHtml(t.period||"--"),a=t.counts||{},s=a.tasks_created!=null||a.tasks_completed!=null||a.tasks_blocked!=null||a.errors!=null,r=t.highlights||[],o=t.decisions||[],n="";r.length>0&&(n=`
9695
+ `;return}let t=this._data||{},i=this._escapeHtml(t.period||(t.period_hours!=null?`Last ${t.period_hours}h`:"--")),a=t.summary||t.counts||{},s=a.tasks_created!=null||a.tasks_completed!=null||a.tasks_blocked!=null||a.errors!=null,r=t.highlights||[],o=t.decisions||[],n="";r.length>0&&(n=`
9711
9696
  <div class="highlights-section">
9712
9697
  <div class="section-label">Highlights</div>
9713
9698
  <ul class="highlight-list">
@@ -9762,7 +9747,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
9762
9747
  ${n}
9763
9748
  ${l}
9764
9749
  </div>
9765
- `,this.shadowRoot.querySelectorAll(".decision-header").forEach(c=>{c.addEventListener("click",()=>{this._toggleDecision(parseInt(c.dataset.index))})})}};customElements.get("loki-session-diff")||customElements.define("loki-session-diff",ue);var he=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._data=null,this._error=null,this._loading=!0,this._optimizing=!1,this._api=null,this._pollInterval=null,this._expandedChanges=new Set}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;try{let t=await e._get("/api/prompt-versions");if(e!==this._api)return;this._data=t,this._error=null}catch(t){if(e!==this._api)return;this._error=t.message,this._data=null}this._loading=!1,this.render()}async _triggerOptimize(){if(this._optimizing)return;let e=this._api;this._optimizing=!0,this.render();try{if(await e._post("/api/prompt-optimize?dry_run=false",{}),e!==this._api)return;await this._loadData()}catch(t){if(e!==this._api)return;this._error=t.message}this._optimizing=!1,this.render()}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:6e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_formatTime(e){if(!e)return"--";try{let t=new Date(e),a=new Date-t,s=Math.floor(a/6e4);if(s<1)return"Just now";if(s<60)return`${s}m ago`;let r=Math.floor(s/60);return r<24?`${r}h ago`:`${Math.floor(r/24)}d ago`}catch{return"--"}}_toggleChange(e){this._expandedChanges.has(e)?this._expandedChanges.delete(e):this._expandedChanges.add(e),this.render()}render(){let e=`
9750
+ `,this.shadowRoot.querySelectorAll(".decision-header").forEach(c=>{c.addEventListener("click",()=>{this._toggleDecision(parseInt(c.dataset.index))})})}};customElements.get("loki-session-diff")||customElements.define("loki-session-diff",pe);var ue=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._data=null,this._error=null,this._loading=!0,this._optimizing=!1,this._api=null,this._pollInterval=null,this._expandedChanges=new Set}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;try{let t=await e._get("/api/prompt-versions");if(e!==this._api)return;this._data=t,this._error=null}catch(t){if(e!==this._api)return;this._error=t.message,this._data=null}this._loading=!1,this.render()}async _triggerOptimize(){if(this._optimizing)return;let e=this._api;this._optimizing=!0,this.render();try{if(await e._post("/api/prompt-optimize?dry_run=false",{}),e!==this._api)return;await this._loadData()}catch(t){if(e!==this._api)return;this._error=t.message}this._optimizing=!1,this.render()}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:6e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_formatTime(e){if(!e)return"--";try{let t=new Date(e),a=new Date-t,s=Math.floor(a/6e4);if(s<1)return"Just now";if(s<60)return`${s}m ago`;let r=Math.floor(s/60);return r<24?`${r}h ago`:`${Math.floor(r/24)}d ago`}catch{return"--"}}_toggleChange(e){this._expandedChanges.has(e)?this._expandedChanges.delete(e):this._expandedChanges.add(e),this.render()}render(){let e=`
9766
9751
  ${this.getBaseStyles()}
9767
9752
 
9768
9753
  :host {
@@ -9972,16 +9957,16 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
9972
9957
  </div>
9973
9958
  <div class="empty-state">No prompt optimization data available</div>
9974
9959
  </div>
9975
- `;return}let t=this._data||{},i=t.version!=null?t.version:"--",a=this._formatTime(t.last_optimized),s=t.failures_analyzed!=null?t.failures_analyzed:"--",r=t.changes||[],o="";r.length>0&&(o=`
9960
+ `;return}let t=this._data||{},i=t.generated_at??t.last_optimized,a=!t.version&&i==null,s=a||t.version==null?"--":`v${t.version}`,r=a?"No optimization run yet":this._formatTime(i),o=a||t.failures_analyzed==null?"--":t.failures_analyzed,n=t.changes||[],l="";n.length>0&&(l=`
9976
9961
  <div class="changes-section">
9977
9962
  <div class="section-label">Changes</div>
9978
- ${r.map((l,c)=>{let p=this._expandedChanges.has(c);return`
9963
+ ${n.map((p,u)=>{let m=this._expandedChanges.has(u);return`
9979
9964
  <div class="change-item">
9980
- <button class="change-header" data-index="${c}">
9981
- <span class="change-arrow ${p?"expanded":""}">&#9654;</span>
9982
- ${this._escapeHtml(l.description||l.title||"Change")}
9965
+ <button class="change-header" data-index="${u}">
9966
+ <span class="change-arrow ${m?"expanded":""}">&#9654;</span>
9967
+ ${this._escapeHtml(p.description||p.title||"Change")}
9983
9968
  </button>
9984
- ${p?`<div class="change-rationale">${this._escapeHtml(l.rationale||l.reasoning||"No rationale provided")}</div>`:""}
9969
+ ${m?`<div class="change-rationale">${this._escapeHtml(p.rationale||p.reasoning||"No rationale provided")}</div>`:""}
9985
9970
  </div>
9986
9971
  `}).join("")}
9987
9972
  </div>
@@ -9999,21 +9984,21 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
9999
9984
  <div class="info-grid">
10000
9985
  <div class="info-item">
10001
9986
  <div class="info-label">Version</div>
10002
- <div class="info-value">v${this._escapeHtml(String(i))}</div>
9987
+ <div class="info-value">${this._escapeHtml(String(s))}</div>
10003
9988
  </div>
10004
9989
  <div class="info-item">
10005
9990
  <div class="info-label">Last Optimized</div>
10006
- <div class="info-value muted">${this._escapeHtml(a)}</div>
9991
+ <div class="info-value muted">${this._escapeHtml(r)}</div>
10007
9992
  </div>
10008
9993
  <div class="info-item">
10009
9994
  <div class="info-label">Failures Analyzed</div>
10010
- <div class="info-value">${s}</div>
9995
+ <div class="info-value">${o}</div>
10011
9996
  </div>
10012
9997
  </div>
10013
9998
 
10014
- ${o}
9999
+ ${l}
10015
10000
  </div>
10016
- `;let n=this.shadowRoot.getElementById("optimize-btn");n&&n.addEventListener("click",()=>this._triggerOptimize()),this.shadowRoot.querySelectorAll(".change-header").forEach(l=>{l.addEventListener("click",()=>{this._toggleChange(parseInt(l.dataset.index))})})}};customElements.get("loki-prompt-optimizer")||customElements.define("loki-prompt-optimizer",he);var ge=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._data=null,this._history=[],this._error=null,this._loading=!0,this._scanning=!1,this._rigourAvailable=!0,this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;try{let[t,i]=await Promise.allSettled([e._get("/api/quality-score"),e._get("/api/quality-score/history")]);if(e!==this._api)return;if(t.status==="fulfilled"){let a=t.value;a&&a.error&&a.error.includes("not installed")?(this._rigourAvailable=!1,this._data=null):a&&a.available===!1?(this._rigourAvailable=!1,this._data=null):a&&a.score==null?(this._rigourAvailable=!0,this._data=null):(this._rigourAvailable=!0,this._data=a),this._error=null}else(t.reason?.message||"").includes("404")?(this._rigourAvailable=!1,this._data=null,this._error=null):(this._error="Failed to load quality score",this._data=null);if(i.status==="fulfilled"){let a=i.value;this._history=Array.isArray(a)?a.slice(-10):(a.scores||[]).slice(-10)}}catch(t){if(e!==this._api)return;this._error=t.message,this._data=null}this._loading=!1,this.render()}async _triggerScan(){if(!this._scanning){this._scanning=!0,this.render();try{await this._api._post("/api/quality-scan",{},{timeout:3e5}),await this._loadData()}catch(e){this._error=e.message}this._scanning=!1,this.render()}}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:6e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getGrade(e){return e>=90?{grade:"A",color:"var(--loki-success)"}:e>=80?{grade:"B",color:"var(--loki-success)"}:e>=70?{grade:"C",color:"var(--loki-warning)"}:e>=60?{grade:"D",color:"var(--loki-warning)"}:{grade:"F",color:"var(--loki-error)"}}_renderSparkline(e){if(!e||e.length<2)return"";let t=e.map(c=>typeof c=="number"?c:c.score||0),i=Math.min(...t),s=Math.max(...t)-i||1,r=120,o=32,n=2,l=t.map((c,p)=>{let u=n+p/(t.length-1)*(r-n*2),m=n+(1-(c-i)/s)*(o-n*2);return`${u},${m}`}).join(" ");return`
10001
+ `;let c=this.shadowRoot.getElementById("optimize-btn");c&&c.addEventListener("click",()=>this._triggerOptimize()),this.shadowRoot.querySelectorAll(".change-header").forEach(p=>{p.addEventListener("click",()=>{this._toggleChange(parseInt(p.dataset.index))})})}};customElements.get("loki-prompt-optimizer")||customElements.define("loki-prompt-optimizer",ue);var he=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._data=null,this._history=[],this._error=null,this._loading=!0,this._scanning=!1,this._rigourAvailable=!0,this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;try{let[t,i]=await Promise.allSettled([e._get("/api/quality-score"),e._get("/api/quality-score/history")]);if(e!==this._api)return;if(t.status==="fulfilled"){let a=t.value;a&&a.error&&a.error.includes("not installed")?(this._rigourAvailable=!1,this._data=null):a&&a.available===!1?(this._rigourAvailable=!1,this._data=null):a&&a.score==null?(this._rigourAvailable=!0,this._data=null):(this._rigourAvailable=!0,this._data=a),this._error=null}else(t.reason?.message||"").includes("404")?(this._rigourAvailable=!1,this._data=null,this._error=null):(this._error="Failed to load quality score",this._data=null);if(i.status==="fulfilled"){let a=i.value,s=Array.isArray(a)?a:a?.scores||[];this._history=s.filter(r=>(typeof r=="number"?r:r?.score)!=null).slice(0,10).reverse()}}catch(t){if(e!==this._api)return;this._error=t.message,this._data=null}this._loading=!1,this.render()}async _triggerScan(){if(!this._scanning){this._scanning=!0,this.render();try{await this._api._post("/api/quality-scan",{},{timeout:3e5}),await this._loadData()}catch(e){this._error=e.message}this._scanning=!1,this.render()}}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:6e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getGrade(e){return e>=90?{grade:"A",color:"var(--loki-success)"}:e>=80?{grade:"B",color:"var(--loki-success)"}:e>=70?{grade:"C",color:"var(--loki-warning)"}:e>=60?{grade:"D",color:"var(--loki-warning)"}:{grade:"F",color:"var(--loki-error)"}}_renderSparkline(e){if(!e||e.length<2)return"";let t=e.map(c=>typeof c=="number"?c:c.score),i=Math.min(...t),s=Math.max(...t)-i||1,r=120,o=32,n=2,l=t.map((c,p)=>{let u=n+p/(t.length-1)*(r-n*2),m=n+(1-(c-i)/s)*(o-n*2);return`${u},${m}`}).join(" ");return`
10017
10002
  <svg width="${r}" height="${o}" viewBox="0 0 ${r} ${o}" class="sparkline">
10018
10003
  <polyline points="${l}" fill="none" stroke="var(--loki-accent)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
10019
10004
  <circle cx="${l.split(" ").pop().split(",")[0]}" cy="${l.split(" ").pop().split(",")[1]}" r="2.5" fill="var(--loki-accent)"/>
@@ -10387,7 +10372,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
10387
10372
  <button class="es-cta" id="retry-btn">Retry</button>
10388
10373
  </div>
10389
10374
  </div>
10390
- `;let k=this.shadowRoot.getElementById("retry-btn");k&&k.addEventListener("click",()=>{this._loading=!0,this.render(),this._loadData()});return}if(!this._data){this.shadowRoot.innerHTML=`
10375
+ `;let x=this.shadowRoot.getElementById("retry-btn");x&&x.addEventListener("click",()=>{this._loading=!0,this.render(),this._loadData()});return}if(!this._data){this.shadowRoot.innerHTML=`
10391
10376
  <style>${e}</style>
10392
10377
  <div class="quality-container">
10393
10378
  <div class="quality-header">
@@ -10403,15 +10388,15 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
10403
10388
  </button>
10404
10389
  </div>
10405
10390
  </div>
10406
- `;let k=this.shadowRoot.getElementById("scan-btn");k&&k.addEventListener("click",()=>this._triggerScan());return}let i=this._data||{},a=i.score!=null?Math.round(i.score):0,{grade:s,color:r}=this._getGrade(a),o=i.categories||{},n=i.findings||{},l=["security","code_quality","compliance","best_practices"],c={security:"Security",code_quality:"Code Quality",compliance:"Compliance",best_practices:"Best Practices"},p=l.map(k=>{let _=o[k]!=null?Math.round(o[k]):0,H=_>=80?"var(--loki-success)":_>=60?"var(--loki-warning)":"var(--loki-error)";return`
10391
+ `;let x=this.shadowRoot.getElementById("scan-btn");x&&x.addEventListener("click",()=>this._triggerScan());return}let i=this._data||{},a=Math.round(i.score),{grade:s,color:r}=this._getGrade(a),o=i.categories||{},n=i.findings||{},l=["security","code_quality","compliance","best_practices"],c={security:"Security",code_quality:"Code Quality",compliance:"Compliance",best_practices:"Best Practices"},p=l.map(x=>{let _=o[x]!=null?Math.round(o[x]):null,D=_>=80?"var(--loki-success)":_>=60?"var(--loki-warning)":"var(--loki-error)";return`
10407
10392
  <div class="category-item">
10408
- <span class="category-name">${c[k]||k}</span>
10393
+ <span class="category-name">${c[x]||x}</span>
10409
10394
  <div class="progress-bar">
10410
- <div class="progress-fill" style="width:${_}%;background:${H};"></div>
10395
+ ${_!=null?`<div class="progress-fill" style="width:${_}%;background:${D};"></div>`:""}
10411
10396
  </div>
10412
- <span class="category-score">${_}</span>
10397
+ <span class="category-score">${_??"--"}</span>
10413
10398
  </div>
10414
- `}).join(""),m=[{key:"critical",cls:"finding-critical",label:"Critical"},{key:"major",cls:"finding-major",label:"Major"},{key:"minor",cls:"finding-minor",label:"Minor"},{key:"info",cls:"finding-info",label:"Info"}].filter(k=>(n[k.key]||0)>0).map(k=>`<span class="finding-badge ${k.cls}">${k.label}: ${n[k.key]}</span>`).join(""),g=this._renderSparkline(this._history);this.shadowRoot.innerHTML=`
10399
+ `}).join(""),m=[{key:"critical",cls:"finding-critical",label:"Critical"},{key:"major",cls:"finding-major",label:"Major"},{key:"minor",cls:"finding-minor",label:"Minor"},{key:"info",cls:"finding-info",label:"Info"}].filter(x=>(n[x.key]||0)>0).map(x=>`<span class="finding-badge ${x.cls}">${x.label}: ${n[x.key]}</span>`).join(""),g=this._renderSparkline(this._history);this.shadowRoot.innerHTML=`
10415
10400
  <style>${e}</style>
10416
10401
  <div class="quality-container">
10417
10402
  <div class="quality-header">
@@ -10447,27 +10432,37 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
10447
10432
  </div>
10448
10433
  `:""}
10449
10434
  </div>
10450
- `;let x=this.shadowRoot.getElementById("scan-btn");x&&x.addEventListener("click",()=>this._triggerScan())}};customElements.get("loki-quality-score")||customElements.define("loki-quality-score",ge);var ft=["understand","guardrail","migrate","verify"],bt={understand:"Understand",guardrail:"Guardrail",migrate:"Migrate",verify:"Verify"},Kt={understand:"#5b9bd5",guardrail:"#e8b84a",migrate:"#5bb870",verify:"#5bc8c8"},me=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._migration=null,this._migrations=[],this._loading=!0,this._error=null,this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._fetchMigrations(),this._poll=b({loadFn:()=>this._fetchData(),intervalMs:15e3,element:this,immediate:!1})}disconnectedCallback(){super.disconnectedCallback(),this._poll&&(this._poll.stop(),this._poll=null)}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._fetchMigrations()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _fetchMigrations(){let e=this._api;try{let t=await e._get("/api/migration/list");if(e!==this._api)return;this._migrations=Array.isArray(t)?t:t.migrations||[],this._error=null;let i=this._migrations.find(a=>a.status==="in_progress"||a.status==="active");if(i){if(await this._fetchStatus(i.migration_id||i.id),e!==this._api)return}else this._migration=null}catch(t){if(e!==this._api)return;this._error=t.message,this._migrations=[],this._migration=null}this._loading=!1,this.render()}async _fetchStatus(e){let t=this._api;try{let i=await t._get(`/api/migration/${encodeURIComponent(e)}/status`);if(t!==this._api)return;this._migration=i,this._error=null}catch(i){if(t!==this._api)return;this._error=i.message}}async _fetchData(){let e=this._api,t=this._migration&&(this._migration.migration_id||this._migration.id);if(t){if(await this._fetchStatus(t),e!==this._api)return;this.render()}else await this._fetchMigrations()}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;"):""}_getPhaseIcon(e,t,i){return(i||[]).includes(e)?"[x]":e===t?"[>]":"[ ]"}_getPhaseIndex(e){let t=ft.indexOf(e);return t>=0?t:0}_renderPhaseBar(e,t){let i=t||[];return ft.map(a=>{let s=i.includes(a),r=a===e,o=Kt[a],n=s?"1":r?"0.7":"0.2",l=this._getPhaseIcon(a,e,t);return`
10435
+ `;let k=this.shadowRoot.getElementById("scan-btn");k&&k.addEventListener("click",()=>this._triggerScan())}};customElements.get("loki-quality-score")||customElements.define("loki-quality-score",he);var nt=["understand","guardrail","migrate","verify"],lt={understand:"Understand",guardrail:"Guardrail",migrate:"Migrate",verify:"Verify"},Rt={understand:"#5b9bd5",guardrail:"#e8b84a",migrate:"#5bb870",verify:"#5bc8c8"},ge=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._migration=null,this._migrations=[],this._loading=!0,this._error=null,this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._fetchMigrations(),this._poll=b({loadFn:()=>this._fetchData(),intervalMs:15e3,element:this,immediate:!1})}disconnectedCallback(){super.disconnectedCallback(),this._poll&&(this._poll.stop(),this._poll=null)}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._fetchMigrations()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _fetchMigrations(){let e=this._api;try{let t=await e._get("/api/migration/list");if(e!==this._api)return;this._migrations=Array.isArray(t)?t:t.migrations||[],this._error=null;let i=this._migrations.find(a=>a.status==="in_progress"||a.status==="active");if(i){if(await this._fetchStatus(i.migration_id||i.id),e!==this._api)return}else this._migration=null}catch(t){if(e!==this._api)return;this._error=t.message,this._migrations=[],this._migration=null}this._loading=!1,this.render()}async _fetchStatus(e){let t=this._api;try{let i=await t._get(`/api/migration/${encodeURIComponent(e)}/status`);if(t!==this._api)return;this._migration=i,this._error=null}catch(i){if(t!==this._api)return;this._error=i.message}}async _fetchData(){let e=this._api,t=this._migration&&(this._migration.migration_id||this._migration.id);if(t){if(await this._fetchStatus(t),e!==this._api)return;this.render()}else await this._fetchMigrations()}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;"):""}_getPhaseIcon(e,t,i){return(i||[]).includes(e)?"[x]":e===t?"[>]":"[ ]"}_getPhaseIndex(e){let t=nt.indexOf(e);return t>=0?t:0}_renderPhaseBar(e,t){let i=t||[];return nt.map(a=>{let s=i.includes(a),r=a===e,o=Rt[a],n=s?"1":r?"0.7":"0.2",l=this._getPhaseIcon(a,e,t);return`
10451
10436
  <div class="phase-segment">
10452
10437
  <div class="phase-bar-fill" style="background:${o};opacity:${n};"></div>
10453
10438
  <div class="phase-label">
10454
10439
  <span class="phase-icon">${l}</span>
10455
- ${bt[a]}
10440
+ ${lt[a]}
10456
10441
  </div>
10457
10442
  </div>
10458
- `}).join("")}_renderFeatureStats(e){if(!e)return"";let t=e.passing||0,i=e.total||0,a=i>0?Math.round(t/i*100):0,s=a>=80?"var(--loki-success)":a>=50?"var(--loki-warning)":"var(--loki-error)";return`
10443
+ `}).join("")}_renderFeatureStats(e){if(!e)return"";let t=e.total,i=e.passing;if(!t||i==null)return`
10444
+ <div class="stat-card">
10445
+ <div class="stat-header">Feature Tracking</div>
10446
+ <div class="stat-pct">No features recorded</div>
10447
+ </div>
10448
+ `;let a=Math.round(i/t*100),s=a>=80?"var(--loki-success)":a>=50?"var(--loki-warning)":"var(--loki-error)";return`
10459
10449
  <div class="stat-card">
10460
10450
  <div class="stat-header">Feature Tracking</div>
10461
- <div class="stat-value">${t} / ${i}</div>
10451
+ <div class="stat-value">${i} / ${t}</div>
10462
10452
  <div class="stat-pct">${a}% passing</div>
10463
10453
  <div class="progress-bar">
10464
10454
  <div class="progress-fill" style="width:${a}%;background:${s};"></div>
10465
10455
  </div>
10466
10456
  </div>
10467
- `}_renderStepProgress(e){if(!e)return"";let t=e.current||0,i=e.total||0,a=i>0?Math.round(t/i*100):0;return`
10457
+ `}_renderStepProgress(e){if(!e)return"";let t=e.total,i=e.completed;if(!t||i==null)return`
10468
10458
  <div class="stat-card">
10469
10459
  <div class="stat-header">Step Progress</div>
10470
- <div class="stat-value">${t} / ${i}</div>
10460
+ <div class="stat-pct">No plan recorded</div>
10461
+ </div>
10462
+ `;let a=Math.round(i/t*100);return`
10463
+ <div class="stat-card">
10464
+ <div class="stat-header">Step Progress</div>
10465
+ <div class="stat-value">${i} / ${t}</div>
10471
10466
  <div class="stat-pct">${a}% complete</div>
10472
10467
  <div class="progress-bar">
10473
10468
  <div class="progress-fill" style="width:${a}%;background:var(--loki-accent);"></div>
@@ -10820,7 +10815,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
10820
10815
  </div>
10821
10816
  <div class="empty-state">No migration data available</div>
10822
10817
  </div>
10823
- `;return}if(this._migration){let i=this._migration,a=this._escapeHtml(i.migration_id||i.id||"--"),s=this._escapeHtml(i.source||"--"),r=this._escapeHtml(i.target||"--"),o=i.current_phase||i.phase||"understand",n=i.completed_phases||[];this.shadowRoot.innerHTML=`
10818
+ `;return}if(this._migration){let i=this._migration,a=this._escapeHtml(i.migration_id||i.id||"--"),s=this._escapeHtml(i.source||"--"),r=this._escapeHtml(i.target||"--"),o=i.current_phase||i.phase||"unknown",n=i.completed_phases||[];this.shadowRoot.innerHTML=`
10824
10819
  <style>${e}</style>
10825
10820
  <div class="migration-container">
10826
10821
  <div class="migration-header">
@@ -10843,7 +10838,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
10843
10838
  </div>
10844
10839
  <div class="meta-item">
10845
10840
  <span class="meta-label">Phase</span>
10846
- <span>${bt[o]||this._escapeHtml(o)}</span>
10841
+ <span>${lt[o]||this._escapeHtml(o)}</span>
10847
10842
  </div>
10848
10843
  </div>
10849
10844
 
@@ -10870,7 +10865,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
10870
10865
  <div class="section-label">Migrations</div>
10871
10866
  ${this._renderMigrationList()}
10872
10867
  </div>
10873
- `}};customElements.get("loki-migration-dashboard")||customElements.define("loki-migration-dashboard",me);var Vt=[["claude-opus","claude"],["claude-sonnet","claude"],["claude-haiku","claude"],["opus","claude"],["sonnet","claude"],["haiku","claude"],["claude","claude"],["gpt-4","codex"],["gpt-5","codex"],["gpt","codex"],["codex","codex"],["o1","codex"],["o3","codex"],["cline","cline"],["aider","aider"]];function Yt(d){if(d==null)return null;switch(d%4){case 0:return{tier:"planning",model:"opus",provider:"claude"};case 1:return{tier:"development",model:"sonnet",provider:"claude"};case 2:return{tier:"development",model:"sonnet",provider:"claude"};case 3:return{tier:"fast",model:"haiku",provider:"claude"};default:return{tier:"development",model:"sonnet",provider:"claude"}}}function Wt(d,e){if(e!=null){let i=Yt(e);if(i)return i.provider}let t=(d||"").toLowerCase();for(let[i,a]of Vt)if(t.includes(i))return a;return"unknown"}var ve=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._api=null,this._pollInterval=null,this._activeTab="heatmap",this._activity=[],this._tools=[],this._cost={},this._context={},this._trends=[],this._toolTimeRange="7d",this._connected=!1,this._loading=!1,this._loadedOnce=!1}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _fetchActivity(e=this._api){let t=e.baseUrl||window.location.origin,i=new AbortController,a=setTimeout(()=>i.abort(),1e4);try{let s=await fetch(`${t}/api/activity?limit=1000`,{signal:i.signal});if(clearTimeout(a),!s.ok)throw new Error(`Activity API ${s.status}`);return s.json()}catch(s){throw clearTimeout(a),s}}async _loadData(){if(!this.isConnected||this._loading)return;let e=this._api;this._loading=!0;try{let t=await Promise.allSettled([this._fetchActivity(e),e.getToolEfficiency(50),e.getCost(),e.getContext(),e.getLearningTrends({timeRange:this._toolTimeRange})]);if(e!==this._api)return;if(t[0].status==="fulfilled"&&(this._activity=t[0].value||[]),t[1].status==="fulfilled"&&(this._tools=t[1].value||[]),t[2].status==="fulfilled"&&(this._cost=t[2].value||{}),t[3].status==="fulfilled"&&(this._context=t[3].value||{}),t[4].status==="fulfilled"){let i=t[4].value||{};this._trends=Array.isArray(i)?i:i.dataPoints||[]}this._connected=t.some(i=>i.status==="fulfilled"),this._loadedOnce=!0,this.render()}finally{this._loading=!1}}_hasAnyData(){let e=Array.isArray(this._activity)?this._activity.length:0,t=Array.isArray(this._tools)?this._tools.length:0,i=this._cost&&this._cost.by_model?Object.keys(this._cost.by_model).length:0,a=this._context||{},r=(a.totals||{}).iterations_tracked||a.total_iterations||a.iteration||0;return e>0||t>0||i>0||r>0}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_computeHeatmap(){let e={},t=Array.isArray(this._activity)?this._activity:[];for(let c of t){let p=c.timestamp||c.ts||c.created_at;if(!p)continue;let u=new Date(p);if(isNaN(u.getTime()))continue;let m=this._localDateKey(u);e[m]=(e[m]||0)+1}let i=new Date;i.setHours(0,0,0,0);let a=i.getDay(),s=new Date(i),r=new Date(i);r.setDate(r.getDate()-(52*7+a));let o=[],n=new Date(r),l=0;for(;n<=s;){let c=this._localDateKey(n),p=e[c]||0;p>l&&(l=p),o.push({date:c,count:p,day:n.getDay()}),n.setDate(n.getDate()+1)}return{cells:o,maxCount:l}}_getHeatmapLevel(e,t){if(e===0||t===0)return 0;let i=e/t;return i<=.25?1:i<=.5?2:i<=.75?3:4}_renderHeatmap(){let{cells:e,maxCount:t}=this._computeHeatmap(),i=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],a=["","Mon","","Wed","","Fri",""],s=[],r=-1,o=-1;for(let p=0;p<e.length;p++){e[p].day===0&&o++;let u=new Date(e[p].date).getMonth();u!==r&&(s.push({month:i[u],col:Math.max(o,1)}),r=u)}let n=s.map(p=>`<span class="heatmap-month" style="grid-column: ${p.col}">${p.month}</span>`).join(""),l=e.map(p=>`<div class="heatmap-cell level-${this._getHeatmapLevel(p.count,t)}" title="${p.date}: ${p.count} activities"></div>`).join(""),c=a.map(p=>`<span class="heatmap-day-label">${p}</span>`).join("");return`
10868
+ `}};customElements.get("loki-migration-dashboard")||customElements.define("loki-migration-dashboard",ge);var Pt=[["claude-opus","claude"],["claude-sonnet","claude"],["claude-haiku","claude"],["opus","claude"],["sonnet","claude"],["haiku","claude"],["claude","claude"],["gpt-4","codex"],["gpt-5","codex"],["gpt","codex"],["codex","codex"],["o1","codex"],["o3","codex"],["cline","cline"],["aider","aider"]];function It(d){if(d==null)return null;switch(d%4){case 0:return{tier:"planning",model:"opus",provider:"claude"};case 1:return{tier:"development",model:"sonnet",provider:"claude"};case 2:return{tier:"development",model:"sonnet",provider:"claude"};case 3:return{tier:"fast",model:"haiku",provider:"claude"};default:return{tier:"development",model:"sonnet",provider:"claude"}}}function Bt(d,e){if(e!=null){let i=It(e);if(i)return i.provider}let t=(d||"").toLowerCase();for(let[i,a]of Pt)if(t.includes(i))return a;return"unknown"}var me=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._api=null,this._pollInterval=null,this._activeTab="heatmap",this._activity=[],this._tools=[],this._cost={},this._context={},this._trends=[],this._toolTimeRange="7d",this._connected=!1,this._loading=!1,this._loadedOnce=!1}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _fetchActivity(e=this._api){let t=e.baseUrl||window.location.origin,i=new AbortController,a=setTimeout(()=>i.abort(),1e4);try{let s=await fetch(`${t}/api/activity?limit=1000`,{signal:i.signal});if(clearTimeout(a),!s.ok)throw new Error(`Activity API ${s.status}`);return s.json()}catch(s){throw clearTimeout(a),s}}async _loadData(){if(!this.isConnected||this._loading)return;let e=this._api;this._loading=!0;try{let t=await Promise.allSettled([this._fetchActivity(e),e.getToolEfficiency(50),e.getCost(),e.getContext(),e.getLearningTrends({timeRange:this._toolTimeRange})]);if(e!==this._api)return;if(t[0].status==="fulfilled"&&(this._activity=t[0].value||[]),t[1].status==="fulfilled"&&(this._tools=t[1].value||[]),t[2].status==="fulfilled"&&(this._cost=t[2].value||{}),t[3].status==="fulfilled"&&(this._context=t[3].value||{}),t[4].status==="fulfilled"){let i=t[4].value||{};this._trends=Array.isArray(i)?i:i.dataPoints||[]}this._connected=t.some(i=>i.status==="fulfilled"),this._loadedOnce=!0,this.render()}finally{this._loading=!1}}_hasAnyData(){let e=Array.isArray(this._activity)?this._activity.length:0,t=Array.isArray(this._tools)?this._tools.length:0,i=this._cost&&this._cost.by_model?Object.keys(this._cost.by_model).length:0,a=this._context||{},r=(a.totals||{}).iterations_tracked||a.total_iterations||a.iteration||0;return e>0||t>0||i>0||r>0}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_computeHeatmap(){let e={},t=Array.isArray(this._activity)?this._activity:[];for(let c of t){let p=c.timestamp||c.ts||c.created_at;if(!p)continue;let u=new Date(p);if(isNaN(u.getTime()))continue;let m=this._localDateKey(u);e[m]=(e[m]||0)+1}let i=new Date;i.setHours(0,0,0,0);let a=i.getDay(),s=new Date(i),r=new Date(i);r.setDate(r.getDate()-(52*7+a));let o=[],n=new Date(r),l=0;for(;n<=s;){let c=this._localDateKey(n),p=e[c]||0;p>l&&(l=p),o.push({date:c,count:p,day:n.getDay()}),n.setDate(n.getDate()+1)}return{cells:o,maxCount:l}}_getHeatmapLevel(e,t){if(e===0||t===0)return 0;let i=e/t;return i<=.25?1:i<=.5?2:i<=.75?3:4}_renderHeatmap(){let{cells:e,maxCount:t}=this._computeHeatmap(),i=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],a=["","Mon","","Wed","","Fri",""],s=[],r=-1,o=-1;for(let p=0;p<e.length;p++){e[p].day===0&&o++;let u=new Date(e[p].date).getMonth();u!==r&&(s.push({month:i[u],col:Math.max(o,1)}),r=u)}let n=s.map(p=>`<span class="heatmap-month" style="grid-column: ${p.col}">${p.month}</span>`).join(""),l=e.map(p=>`<div class="heatmap-cell level-${this._getHeatmapLevel(p.count,t)}" title="${p.date}: ${p.count} activities"></div>`).join(""),c=a.map(p=>`<span class="heatmap-day-label">${p}</span>`).join("");return`
10874
10869
  <div class="heatmap-container">
10875
10870
  <div class="heatmap-months">${n}</div>
10876
10871
  <div class="heatmap-body">
@@ -10895,7 +10890,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
10895
10890
  </div>
10896
10891
  <span class="tool-count">${s}</span>
10897
10892
  </div>
10898
- `}).join("")+"</div>"}_computeVelocity(){let e=this._context||{},t=e.per_iteration||e.iterations||[],i=Array.isArray(t)&&t.length>0?t.length:e.totals&&e.totals.iterations_tracked||e.total_iterations||0,a=0;if(Array.isArray(t)&&t.length>=2){let o=t.map(n=>new Date(n.timestamp||n.started_at||n.ts).getTime()).filter(n=>!isNaN(n)).sort((n,l)=>n-l);if(o.length>=2){let n=(o[o.length-1]-o[0])/36e5;n>0&&(a=Math.max(o.length-1,1)/n)}}let s=[],r=Array.isArray(this._trends)?this._trends:[];if(r.length>0)for(let o of r.slice(-24))s.push(o.count??o.value??0);else if(Array.isArray(t)&&t.length>0){let o={};for(let l of t){let c=l.timestamp||l.started_at||l.ts;if(!c)continue;let u=new Date(c).toISOString().slice(0,13);o[u]=(o[u]||0)+1}let n=Object.keys(o).sort().slice(-24);for(let l of n)s.push(o[l])}return{iterPerHour:a,totalIterations:i,hourlyBuckets:s}}_renderVelocity(){let{iterPerHour:e,totalIterations:t,hourlyBuckets:i}=this._computeVelocity(),a=Math.max(1,...i),s=i.length>0?i.map(o=>{let n=o/a*100;return`<div class="spark-bar" style="height: ${Math.max(2,n)}%" title="${o}"></div>`}).join(""):'<div class="empty-state" style="padding: 12px">No trend data</div>';return`
10893
+ `}).join("")+"</div>"}_computeVelocity(){let e=this._context||{},t=e.per_iteration||e.iterations||[],i=!!e.updated_at,a=Array.isArray(t)&&t.length>0?t.length:i?e.totals?.iterations_tracked??e.total_iterations??null:null,s=null;if(Array.isArray(t)&&t.length>=2){let n=t.map(l=>new Date(l.timestamp||l.started_at||l.ts).getTime()).filter(l=>!isNaN(l)).sort((l,c)=>l-c);if(n.length>=2){let l=(n[n.length-1]-n[0])/36e5;l>0&&(s=Math.max(n.length-1,1)/l)}}let r=[],o=Array.isArray(this._trends)?this._trends:[];if(o.length>0)for(let n of o.slice(-24))r.push(n.count??n.value??0);else if(Array.isArray(t)&&t.length>0){let n={};for(let c of t){let p=c.timestamp||c.started_at||c.ts;if(!p)continue;let m=new Date(p).toISOString().slice(0,13);n[m]=(n[m]||0)+1}let l=Object.keys(n).sort().slice(-24);for(let c of l)r.push(n[c])}return{iterPerHour:s,totalIterations:a,hourlyBuckets:r}}_renderVelocity(){let{iterPerHour:e,totalIterations:t,hourlyBuckets:i}=this._computeVelocity(),a=Math.max(1,...i),s=i.length>0?i.map(o=>{let n=o/a*100;return`<div class="spark-bar" style="height: ${Math.max(2,n)}%" title="${o}"></div>`}).join(""):'<div class="empty-state" style="padding: 12px">No trend data</div>';return`
10899
10894
  ${`
10900
10895
  <div class="tool-filter">
10901
10896
  <select class="tool-time-select" id="tool-time-range">
@@ -10909,41 +10904,41 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
10909
10904
  <div class="velocity-cards">
10910
10905
  <div class="velocity-card">
10911
10906
  <div class="velocity-label">Iterations / Hour</div>
10912
- <div class="velocity-value">${e.toFixed(1)}</div>
10907
+ <div class="velocity-value">${e==null?"--":e.toFixed(1)}</div>
10913
10908
  </div>
10914
10909
  <div class="velocity-card">
10915
10910
  <div class="velocity-label">Total Iterations</div>
10916
- <div class="velocity-value">${t}</div>
10911
+ <div class="velocity-value">${t??"--"}</div>
10917
10912
  </div>
10918
10913
  </div>
10919
10914
  <div class="sparkline-container">
10920
10915
  <div class="sparkline-label">Activity Trend (hourly)</div>
10921
10916
  <div class="sparkline">${s}</div>
10922
10917
  </div>
10923
- `}_computeProviders(){let e=this._cost.by_model||{},t={};for(let[r,o]of Object.entries(e)){let n=Wt(r);t[n]||(t[n]={cost:0,tokens:0,iterations:0,models:[]});let l=o.cost_usd||0,c=(o.input_tokens||0)+(o.output_tokens||0);t[n].cost+=l,t[n].tokens+=c,t[n].models.push(r)}let a=(this._context.totals||{}).iterations_tracked||this._context.total_iterations||this._context.iteration||0,s=this._cost.estimated_cost_usd||0;for(let r of Object.values(t))if(s>0&&a>0){let o=r.cost/s;r.iterations=Math.round(o*a)}return t}_renderProviders(){let e=this._computeProviders(),t={claude:{label:"Claude",color:"var(--loki-accent)"},codex:{label:"Codex",color:"var(--loki-success)"},cline:{label:"Cline",color:"var(--loki-info)"},aider:{label:"Aider",color:"var(--loki-blue)"},unknown:{label:"Other",color:"var(--loki-text-muted)"}},i=Object.entries(e);return i.length===0?'<div class="empty-state">No provider activity yet. Start a build to compare providers side by side.</div>':`
10918
+ `}_computeProviders(){let e=this._cost.by_model||{},t={};for(let[r,o]of Object.entries(e)){let n=Bt(r);t[n]||(t[n]={cost:null,tokens:null,iterations:0,models:[],unmeasured:0});let l=t[n];o.cost_usd==null?l.unmeasured+=1:l.cost=l.cost==null?Number(o.cost_usd):l.cost+Number(o.cost_usd),(o.input_tokens!=null||o.output_tokens!=null)&&(l.tokens=(l.tokens??0)+Number(o.input_tokens??0)+Number(o.output_tokens??0)),l.models.push(r)}let a=(this._context.totals||{}).iterations_tracked||this._context.total_iterations||this._context.iteration||0,s=this._cost.estimated_cost_usd??null;for(let r of Object.values(t))if(r.cost!=null&&s>0&&a>0){let o=r.cost/s;r.iterations=Math.round(o*a)}return t}_renderProviders(){let e=this._computeProviders(),t={claude:{label:"Claude",color:"var(--loki-accent)"},codex:{label:"Codex",color:"var(--loki-success)"},cline:{label:"Cline",color:"var(--loki-info)"},aider:{label:"Aider",color:"var(--loki-blue)"},unknown:{label:"Other",color:"var(--loki-text-muted)"}},i=Object.entries(e);return i.length===0?'<div class="empty-state">No provider activity yet. Start a build to compare providers side by side.</div>':`
10924
10919
  <div class="provider-grid">
10925
- ${i.map(([a,s])=>{let r=t[a]||t.unknown,o=s.iterations>0?(s.cost/s.iterations).toFixed(4):"--",n=s.iterations>0?Math.round(s.tokens/s.iterations).toLocaleString():"--";return`
10920
+ ${i.map(([a,s])=>{let r=t[a]||t.unknown,o=s.iterations>0&&s.cost!=null?(s.cost/s.iterations).toFixed(4):"--",n=s.iterations>0&&s.tokens!=null?Math.round(s.tokens/s.iterations).toLocaleString():"--",l=s.cost!=null&&s.unmeasured>0?" (partial)":"";return`
10926
10921
  <div class="provider-card">
10927
10922
  <div class="provider-accent" style="background: ${r.color}"></div>
10928
10923
  <div class="provider-body">
10929
10924
  <div class="provider-name">${r.label}</div>
10930
10925
  <div class="provider-stat">
10931
10926
  <span class="provider-stat-label">Total Cost</span>
10932
- <span class="provider-stat-value">${s.cost>0?"$"+s.cost.toFixed(2):"$0.00"}</span>
10927
+ <span class="provider-stat-value">${T(s.cost)}${l}</span>
10933
10928
  </div>
10934
10929
  <div class="provider-stat">
10935
- <span class="provider-stat-label">Cost / Iteration</span>
10930
+ <span class="provider-stat-label">Cost / Iteration (est.)</span>
10936
10931
  <span class="provider-stat-value">${o!=="--"?"$"+o:o}</span>
10937
10932
  </div>
10938
10933
  <div class="provider-stat">
10939
- <span class="provider-stat-label">Tokens / Iteration</span>
10934
+ <span class="provider-stat-label">Tokens / Iteration (est.)</span>
10940
10935
  <span class="provider-stat-value">${n}</span>
10941
10936
  </div>
10942
10937
  <div class="provider-stat">
10943
10938
  <span class="provider-stat-label">Total Tokens</span>
10944
- <span class="provider-stat-value">${(s.tokens??0).toLocaleString()}</span>
10939
+ <span class="provider-stat-value">${s.tokens==null?De(null):s.tokens.toLocaleString()}</span>
10945
10940
  </div>
10946
- <div class="provider-models">${s.models.map(l=>this._esc(l)).join(", ")}</div>
10941
+ <div class="provider-models">${s.models.map(c=>this._esc(c)).join(", ")}</div>
10947
10942
  </div>
10948
10943
  </div>
10949
10944
  `}).join("")}
@@ -11423,7 +11418,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
11423
11418
  </div>
11424
11419
  `}
11425
11420
  </div>
11426
- `,this.shadowRoot.querySelectorAll("[data-tab]").forEach(l=>{l.addEventListener("click",c=>this._handleTabClick(c))});let r=this.shadowRoot.getElementById("tool-time-range");r&&r.addEventListener("change",l=>this._handleTimeRangeChange(l));let o=this.shadowRoot.getElementById("analytics-retry-btn");o&&o.addEventListener("click",()=>this._loadData());let n=this.shadowRoot.getElementById("analytics-overview-btn");n&&n.addEventListener("click",()=>this._navigateToOverview())}_navigateToOverview(){this.dispatchEvent(new CustomEvent("loki-navigate",{detail:{view:"overview"},bubbles:!0,composed:!0}))}};customElements.get("loki-analytics")||customElements.define("loki-analytics",ve);var kt={pass:{color:"var(--loki-green, #22c55e)",bg:"var(--loki-green-muted, rgba(34, 197, 94, 0.15))",label:"PASS"},fail:{color:"var(--loki-red, #ef4444)",bg:"var(--loki-red-muted, rgba(239, 68, 68, 0.15))",label:"FAIL"},pending:{color:"var(--loki-yellow, #eab308)",bg:"var(--loki-yellow-muted, rgba(234, 179, 8, 0.15))",label:"PENDING"}};function Qt(d){if(!d)return"Never";try{return new Date(d).toLocaleString([],{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return"Unknown"}}function Xt(d){if(!d||d.length===0)return{pass:0,fail:0,pending:0,total:0};let e={pass:0,fail:0,pending:0,total:d.length};for(let t of d){let i=(t.status||"pending").toLowerCase();i==="pass"?e.pass++:i==="fail"?e.fail++:e.pending++}return e}var fe=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._gates=[],this._evidence={blocked:!1},this._policy=null,this._pollInterval=null,this._lastDataHash=null,this._scanning=!1}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_policyLine(e){if(!Array.isArray(this._policy)||!e)return"";let i={"Static Analysis":"static_analysis","Test Suite":"test_coverage","Blind Code Review":"code_review","Anti-Sycophancy":"anti_sycophancy","Mock Integrity":"mock_integrity","Test Mutation":"mutation_integrity","Documentation Coverage":"doc_coverage","Magic Modules Debate":"magic_debate"}[e];if(!i)return"";let a=this._policy.find(l=>l&&l.gate===i);if(!a||!a.mode)return"";let s=a.mode==="blocking",r=a.audit_hits===null||a.audit_hits===void 0?"not measured":`${a.audit_hits} hit${a.audit_hits===1?"":"s"}`,o=s?"BLOCKS":"advisory",n=!s&&a.promote_with?` -- promote with ${this._escapeHtml(a.promote_with)}`:"";return`<div class="gate-meta gate-policy">${o} &middot; ${r}${n}</div>`}async _loadData(){let e=this._api;try{this._loading=!0;let t=await e._get("/api/council/gate");if(e!==this._api)return;let i=t?.gates||t||[],a=t?.evidence||{blocked:!1},s=null;try{let o=await e._get("/api/gate-policy");if(e!==this._api)return;s=Array.isArray(o?.gates)?o.gates:null}catch{s=null}let r=JSON.stringify({gates:i,evidence:a,policy:s});if(r===this._lastDataHash)return;this._lastDataHash=r,this._gates=Array.isArray(i)?i:[],this._evidence=a,this._policy=s,this._error=null}catch(t){if(e!==this._api)return;this._error||(this._error=`Failed to load quality gates: ${t.message}`)}finally{this._loading=!1}this.render()}async _triggerScan(){if(this._scanning)return;let e=this._api;this._scanning=!0,this.render();try{if(await e._post("/api/quality-scan",{},{timeout:3e5}),e!==this._api)return;this._lastDataHash=null,await this._loadData()}catch(t){if(e!==this._api)return;this._error=`Quality scan failed: ${t.message}`}finally{this._scanning=!1,this.render()}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
11421
+ `,this.shadowRoot.querySelectorAll("[data-tab]").forEach(l=>{l.addEventListener("click",c=>this._handleTabClick(c))});let r=this.shadowRoot.getElementById("tool-time-range");r&&r.addEventListener("change",l=>this._handleTimeRangeChange(l));let o=this.shadowRoot.getElementById("analytics-retry-btn");o&&o.addEventListener("click",()=>this._loadData());let n=this.shadowRoot.getElementById("analytics-overview-btn");n&&n.addEventListener("click",()=>this._navigateToOverview())}_navigateToOverview(){this.dispatchEvent(new CustomEvent("loki-navigate",{detail:{view:"overview"},bubbles:!0,composed:!0}))}};customElements.get("loki-analytics")||customElements.define("loki-analytics",me);var jt={pass:{color:"var(--loki-green, #22c55e)",bg:"var(--loki-green-muted, rgba(34, 197, 94, 0.15))",label:"PASS"},fail:{color:"var(--loki-red, #ef4444)",bg:"var(--loki-red-muted, rgba(239, 68, 68, 0.15))",label:"FAIL"},pending:{color:"var(--loki-yellow, #eab308)",bg:"var(--loki-yellow-muted, rgba(234, 179, 8, 0.15))",label:"PENDING"}},Ft={color:"var(--loki-text-muted, #939084)",bg:"var(--loki-bg-tertiary, #ECEAE3)"};function Ut(d){if(!d)return"Not recorded";try{return new Date(d).toLocaleString([],{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return"Unknown"}}function Nt(d){if(!d||d.length===0)return{pass:0,fail:0,pending:0,notEvaluated:0,total:0};let e={pass:0,fail:0,pending:0,notEvaluated:0,total:d.length};for(let t of d){let i=(t.status||"").toLowerCase();i==="pass"?e.pass++:i==="fail"?e.fail++:i==="pending"?e.pending++:e.notEvaluated++}return e}var ve=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!0,this._error=null,this._api=null,this._gates=[],this._evidence={blocked:!1},this._policy=null,this._pollInterval=null,this._lastDataHash=null,this._scanning=!1}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}_policyLine(e){if(!Array.isArray(this._policy)||!e)return"";let i={"Static Analysis":"static_analysis","Test Suite":"test_coverage","Blind Code Review":"code_review","Anti-Sycophancy":"anti_sycophancy","Mock Integrity":"mock_integrity","Test Mutation":"mutation_integrity","Documentation Coverage":"doc_coverage","Magic Modules Debate":"magic_debate"}[e];if(!i)return"";let a=this._policy.find(l=>l&&l.gate===i);if(!a||!a.mode)return"";let s=a.mode==="blocking",r=a.audit_hits===null||a.audit_hits===void 0?"not measured":`${a.audit_hits} hit${a.audit_hits===1?"":"s"}`,o=s?"BLOCKS":"advisory",n=!s&&a.promote_with?` -- promote with ${this._escapeHtml(a.promote_with)}`:"";return`<div class="gate-meta gate-policy">${o} &middot; ${r}${n}</div>`}async _loadData(){let e=this._api;try{this._loading=!0;let t=await e._get("/api/council/gate");if(e!==this._api)return;let i=t?.gates||t||[],a=t?.evidence||{blocked:!1},s=null;try{let o=await e._get("/api/gate-policy");if(e!==this._api)return;s=Array.isArray(o?.gates)?o.gates:null}catch{s=null}let r=JSON.stringify({gates:i,evidence:a,policy:s});if(r===this._lastDataHash)return;this._lastDataHash=r,this._gates=Array.isArray(i)?i:[],this._evidence=a,this._policy=s,this._error=null}catch(t){if(e!==this._api)return;this._error||(this._error=`Failed to load quality gates: ${t.message}`)}finally{this._loading=!1}this.render()}async _triggerScan(){if(this._scanning)return;let e=this._api;this._scanning=!0,this.render();try{if(await e._post("/api/quality-scan",{},{timeout:3e5}),e!==this._api)return;this._lastDataHash=null,await this._loadData()}catch(t){if(e!==this._api)return;this._error=`Quality scan failed: ${t.message}`}finally{this._scanning=!1,this.render()}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
11427
11422
  :host {
11428
11423
  display: block;
11429
11424
  }
@@ -11683,22 +11678,26 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
11683
11678
  color: var(--loki-text-muted, #939084);
11684
11679
  font-size: 13px;
11685
11680
  }
11686
- `}render(){let e=this.shadowRoot;if(!e)return;let t=this._gates,i=Xt(t),a='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>',s;this._loading&&t.length===0?s='<div class="loading">Loading quality gates...</div>':t.length===0?s=`
11681
+ `}render(){let e=this.shadowRoot;if(!e)return;let t=this._gates,i=Nt(t),a='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>',s;this._loading&&t.length===0?s='<div class="loading">Loading quality gates...</div>':t.length===0&&this._error?s=`
11682
+ <div class="es">
11683
+ <div class="es-icon">${a}</div>
11684
+ <div class="es-title">Could not read gate results</div>
11685
+ </div>`:t.length===0?s=`
11687
11686
  <div class="es">
11688
11687
  <div class="es-icon">${a}</div>
11689
- <div class="es-title">No gate results yet</div>
11688
+ <div class="es-title">No gate results recorded yet</div>
11690
11689
  <div class="es-desc">Quality gates run automatically during each build step. Run a scan now, or start a session with <code>loki start ./prd.md</code>.</div>
11691
11690
  <button class="es-cta" id="gates-scan-btn" ${this._scanning?"disabled":""}>
11692
11691
  ${this._scanning?'<span class="es-spinner"></span> Scanning...':"Run quality scan"}
11693
11692
  </button>
11694
- </div>`:s=`<div class="gates-grid">${t.map(p=>{let u=(p.status||"pending").toLowerCase(),m=kt[u]||kt.pending;return`
11695
- <div class="gate-card status-${u}">
11693
+ </div>`:s=`<div class="gates-grid">${t.map(p=>{let u=(p.status||"").toLowerCase(),m=jt[u]||{...Ft,label:u?u.toUpperCase():"NOT EVALUATED"};return`
11694
+ <div class="gate-card status-${this._escapeHtml(u||"none")}">
11696
11695
  <div class="gate-header">
11697
11696
  <span class="gate-name">${this._escapeHtml(p.name||"Unnamed Gate")}</span>
11698
- <span class="gate-badge" style="background: ${m.bg}; color: ${m.color};">${m.label}</span>
11697
+ <span class="gate-badge" style="background: ${m.bg}; color: ${m.color};">${this._escapeHtml(m.label)}</span>
11699
11698
  </div>
11700
11699
  ${p.description?`<div class="gate-description">${this._escapeHtml(p.description)}</div>`:""}
11701
- <div class="gate-meta">Last checked: ${Qt(p.last_checked||p.lastChecked)}</div>
11700
+ <div class="gate-meta">Last checked: ${Ut(p.last_checked||p.lastChecked)}</div>
11702
11701
  ${this._policyLine(p.name)}
11703
11702
  </div>
11704
11703
  `}).join("")}</div>`;let r="",o=this._evidence||{};if(o.blocked){let c={empty_diff:"No changes were shipped (empty diff vs run start).",tests_red:"Tests ran and were red.",empty_diff_and_tests_red:"No changes shipped and tests were red.",no_evidence_of_completion:"No evidence of completion."},p=o.error?this._escapeHtml(o.error):c[o.reason]||this._escapeHtml(o.reason||"Completion blocked."),u=Array.isArray(o.failures)?o.failures:[],m=u.length?`<ul class="evidence-failures">${u.map(g=>`<li>${this._escapeHtml(g)}</li>`).join("")}</ul>`:"";r=`
@@ -11722,6 +11721,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
11722
11721
  <span class="summary-dot" style="background: var(--loki-yellow, #eab308)"></span>
11723
11722
  ${i.pending} Pending
11724
11723
  </span>
11724
+ ${i.notEvaluated?`<span class="summary-item">${i.notEvaluated} Not evaluated</span>`:""}
11725
11725
  </div>
11726
11726
  `:"";e.innerHTML=`
11727
11727
  <style>${this.getBaseStyles()}${this._getStyles()}</style>
@@ -11734,7 +11734,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
11734
11734
  ${s}
11735
11735
  ${this._error?`<div class="error-banner">${this._escapeHtml(this._error)}</div>`:""}
11736
11736
  </div>
11737
- `;let l=e.getElementById("gates-scan-btn");l&&l.addEventListener("click",()=>this._triggerScan())}};customElements.get("loki-quality-gates")||customElements.define("loki-quality-gates",fe);var G={reason:{color:"var(--loki-blue, #3b82f6)",label:"Reason",description:"Analyzing requirements and planning approach"},act:{color:"var(--loki-green, #22c55e)",label:"Act",description:"Implementing changes and executing tasks"},reflect:{color:"var(--loki-purple, #a78bfa)",label:"Reflect",description:"Reviewing results and evaluating quality"},verify:{color:"var(--loki-yellow, #eab308)",label:"Verify",description:"Running tests and validating correctness"}},Xe=["reason","act","reflect","verify"];function Ve(d){if(d==null||d<0)return"--";if(d<1e3)return`${d}ms`;let e=Math.floor(d/1e3);if(e<60)return`${e}s`;let t=Math.floor(e/60),i=e%60;if(t<60)return`${t}m ${i}s`;let a=Math.floor(t/60),s=t%60;return`${a}h ${s}m`}function Zt(d){if(!d||d.length===0)return[];let e=d.reduce((t,i)=>t+(i.duration_ms||0),0);return e===0?d.map(t=>({phase:t.phase,pct:100/d.length,duration:0})):d.map(t=>({phase:t.phase,pct:(t.duration_ms||0)/e*100,duration:t.duration_ms||0}))}function ei(d){return d==null?"--":d>=1e6?(d/1e6).toFixed(1)+"M":d>=1e3?(d/1e3).toFixed(1)+"K":String(d)}var be=class extends v{static get observedAttributes(){return["run-id","api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._timeline=null,this._pollInterval=null,this._selectedPhase=null,this._cycleHistory=[]}get runId(){let e=this.getAttribute("run-id");return e?parseInt(e,10):null}set runId(e){e!=null?this.setAttribute("run-id",String(e)):this.removeAttribute("run-id")}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="run-id"&&this._loadData(),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this.runId;if(e==null){this._timeline=null,this.render();return}let t=this._api;try{this._loading=!0;let i=await t._get(`/api/v2/runs/${e}/timeline`);if(t!==this._api)return;this._timeline=i,this._cycleHistory=i.history||[],this._error=null}catch(i){if(t!==this._api)return;i.message&&(i.message.includes("404")||i.message.includes("Not Found"))?(this._timeline=null,this._error=null):this._error=`Failed to load timeline: ${i.message}`}finally{this._loading=!1}this.render()}_selectPhase(e){this._selectedPhase=this._selectedPhase===e?null:e,this.render()}_bindEvents(){let e=this.shadowRoot;e.querySelectorAll(".phase-segment-interactive").forEach(t=>{t.addEventListener("click",()=>{this._selectPhase(t.dataset.phase)})}),e.querySelectorAll(".legend-item-interactive").forEach(t=>{t.addEventListener("click",()=>{this._selectPhase(t.dataset.phase)})}),e.querySelectorAll(".close-detail").forEach(t=>{t.addEventListener("click",i=>{i.stopPropagation(),this._selectedPhase=null,this.render()})})}_getStyles(){return`
11737
+ `;let l=e.getElementById("gates-scan-btn");l&&l.addEventListener("click",()=>this._triggerScan())}};customElements.get("loki-quality-gates")||customElements.define("loki-quality-gates",ve);var G={reason:{color:"var(--loki-blue, #3b82f6)",label:"Reason",description:"Analyzing requirements and planning approach"},act:{color:"var(--loki-green, #22c55e)",label:"Act",description:"Implementing changes and executing tasks"},reflect:{color:"var(--loki-purple, #a78bfa)",label:"Reflect",description:"Reviewing results and evaluating quality"},verify:{color:"var(--loki-yellow, #eab308)",label:"Verify",description:"Running tests and validating correctness"}},Ve=["reason","act","reflect","verify"];function Fe(d){if(d==null||d<0)return"--";if(d<1e3)return`${d}ms`;let e=Math.floor(d/1e3);if(e<60)return`${e}s`;let t=Math.floor(e/60),i=e%60;if(t<60)return`${t}m ${i}s`;let a=Math.floor(t/60),s=t%60;return`${a}h ${s}m`}function Ot(d){if(!d||d.length===0)return[];let e=d.reduce((t,i)=>t+(i.duration_ms||0),0);return e===0?d.map(t=>({phase:t.phase,pct:100/d.length,duration:0})):d.map(t=>({phase:t.phase,pct:(t.duration_ms||0)/e*100,duration:t.duration_ms||0}))}function qt(d){return d==null?"--":d>=1e6?(d/1e6).toFixed(1)+"M":d>=1e3?(d/1e3).toFixed(1)+"K":String(d)}var fe=class extends v{static get observedAttributes(){return["run-id","api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._timeline=null,this._pollInterval=null,this._selectedPhase=null,this._cycleHistory=[]}get runId(){let e=this.getAttribute("run-id");return e?parseInt(e,10):null}set runId(e){e!=null?this.setAttribute("run-id",String(e)):this.removeAttribute("run-id")}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="run-id"&&this._loadData(),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this.runId;if(e==null){this._timeline=null,this.render();return}let t=this._api;try{this._loading=!0;let i=await t._get(`/api/v2/runs/${e}/timeline`);if(t!==this._api)return;this._timeline=i,this._cycleHistory=i.history||[],this._error=null}catch(i){if(t!==this._api)return;i.message&&(i.message.includes("404")||i.message.includes("Not Found"))?(this._timeline=null,this._error=null):this._error=`Failed to load timeline: ${i.message}`}finally{this._loading=!1}this.render()}_selectPhase(e){this._selectedPhase=this._selectedPhase===e?null:e,this.render()}_bindEvents(){let e=this.shadowRoot;e.querySelectorAll(".phase-segment-interactive").forEach(t=>{t.addEventListener("click",()=>{this._selectPhase(t.dataset.phase)})}),e.querySelectorAll(".legend-item-interactive").forEach(t=>{t.addEventListener("click",()=>{this._selectPhase(t.dataset.phase)})}),e.querySelectorAll(".close-detail").forEach(t=>{t.addEventListener("click",i=>{i.stopPropagation(),this._selectedPhase=null,this.render()})})}_getStyles(){return`
11738
11738
  :host {
11739
11739
  display: block;
11740
11740
  }
@@ -12019,12 +12019,12 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12019
12019
  color: var(--loki-text-muted, #939084);
12020
12020
  font-size: 13px;
12021
12021
  }
12022
- `}_renderPlaceholderTimeline(){let e=Xe.map(i=>{let a=G[i];return`<div class="phase-segment-interactive"
12022
+ `}_renderPlaceholderTimeline(){let e=Ve.map(i=>{let a=G[i];return`<div class="phase-segment-interactive"
12023
12023
  data-phase="${i}"
12024
12024
  style="width: 25%; background: ${a.color}; opacity: 0.3;"
12025
12025
  title="${a.label}: awaiting data">
12026
12026
  ${a.label}
12027
- </div>`}).join(""),t=Xe.map(i=>{let a=G[i];return`<div class="legend-item-interactive" data-phase="${i}">
12027
+ </div>`}).join(""),t=Ve.map(i=>{let a=G[i];return`<div class="legend-item-interactive" data-phase="${i}">
12028
12028
  <span class="legend-dot" style="background: ${a.color}; opacity: 0.4;"></span>
12029
12029
  <span class="legend-label">${a.label}</span>
12030
12030
  <span class="legend-duration">--</span>
@@ -12049,11 +12049,11 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12049
12049
  <div class="detail-metrics">
12050
12050
  <div class="detail-metric">
12051
12051
  <span class="detail-metric-label">Time Spent</span>
12052
- <span class="detail-metric-value">${Ve(a?.duration_ms)}</span>
12052
+ <span class="detail-metric-value">${Fe(a?.duration_ms)}</span>
12053
12053
  </div>
12054
12054
  <div class="detail-metric">
12055
12055
  <span class="detail-metric-label">Tokens Used</span>
12056
- <span class="detail-metric-value">${ei(a?.tokens_used)}</span>
12056
+ <span class="detail-metric-value">${qt(a?.tokens_used)}</span>
12057
12057
  </div>
12058
12058
  <div class="detail-metric">
12059
12059
  <span class="detail-metric-label">Quality</span>
@@ -12065,21 +12065,21 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12065
12065
  </div>
12066
12066
  </div>
12067
12067
  </div>
12068
- `}_renderCycleHistory(){if(this._cycleHistory.length===0)return"";let t=this._cycleHistory.slice(-8).map((i,a)=>`<div class="history-cycle">${Xe.map(r=>{let o=i.phases?.find(p=>p.phase===r),n=G[r],l=o?.status||"pending",c=l==="complete"?"0.8":l==="active"?"1":"0.3";return`<div class="history-dot" style="background: ${n.color}; opacity: ${c};"
12069
- title="Cycle ${a+1}: ${n.label} - ${Ve(o?.duration_ms)}"></div>`}).join("")}</div>`).join('<div class="history-separator"></div>');return`
12068
+ `}_renderCycleHistory(){if(this._cycleHistory.length===0)return"";let t=this._cycleHistory.slice(-8).map((i,a)=>`<div class="history-cycle">${Ve.map(r=>{let o=i.phases?.find(p=>p.phase===r),n=G[r],l=o?.status||"pending",c=l==="complete"?"0.8":l==="active"?"1":"0.3";return`<div class="history-dot" style="background: ${n.color}; opacity: ${c};"
12069
+ title="Cycle ${a+1}: ${n.label} - ${Fe(o?.duration_ms)}"></div>`}).join("")}</div>`).join('<div class="history-separator"></div>');return`
12070
12070
  <div class="cycle-history">
12071
12071
  <div class="history-label">Past Cycles (${this._cycleHistory.length} total)</div>
12072
12072
  <div class="history-cycles">${t}</div>
12073
12073
  </div>
12074
- `}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}render(){let e=this.shadowRoot;if(!e)return;let t=this.runId,i=this._timeline,a=i?.phases||[],s=i?.current_phase||null,r=Zt(a),o;if(this._loading&&!i)o='<div class="loading">Loading timeline...</div>';else if(t==null)o=this._renderPlaceholderTimeline();else if(a.length===0)o=this._renderPlaceholderTimeline();else{let n=r.map(u=>{let m=G[u.phase]||{color:"var(--loki-text-muted)",label:u.phase},g=s===u.phase,x=this._selectedPhase===u.phase;return`<div class="phase-segment-interactive ${g?"current":""} ${x?"selected":""}"
12074
+ `}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}render(){let e=this.shadowRoot;if(!e)return;let t=this.runId,i=this._timeline,a=i?.phases||[],s=i?.current_phase||null,r=Ot(a),o;if(this._loading&&!i)o='<div class="loading">Loading timeline...</div>';else if(t==null)o=this._renderPlaceholderTimeline();else if(a.length===0)o=this._renderPlaceholderTimeline();else{let n=r.map(u=>{let m=G[u.phase]||{color:"var(--loki-text-muted)",label:u.phase},g=s===u.phase,k=this._selectedPhase===u.phase;return`<div class="phase-segment-interactive ${g?"current":""} ${k?"selected":""}"
12075
12075
  data-phase="${u.phase}"
12076
12076
  style="width: ${Math.max(u.pct,2)}%; background: ${m.color};"
12077
- title="${m.label}: ${Ve(u.duration)}">
12077
+ title="${m.label}: ${Fe(u.duration)}">
12078
12078
  ${u.pct>12?m.label:""}
12079
12079
  </div>`}).join(""),l=a.map(u=>{let m=G[u.phase]||{color:"var(--loki-text-muted)",label:u.phase},g=s===u.phase;return`<div class="legend-item-interactive ${this._selectedPhase===u.phase?"selected":""}" data-phase="${u.phase}">
12080
12080
  <span class="legend-dot" style="background: ${m.color}"></span>
12081
12081
  <span class="legend-label">${m.label}</span>
12082
- <span class="legend-duration">${Ve(u.duration_ms)}</span>
12082
+ <span class="legend-duration">${Fe(u.duration_ms)}</span>
12083
12083
  ${g?'<span class="phase-current-tag">ACTIVE</span>':""}
12084
12084
  </div>`}).join(""),c=this._selectedPhase?this._renderPhaseDetail(this._selectedPhase):"",p=this._renderCycleHistory();o=`
12085
12085
  <div class="timeline-bar">${n}</div>
@@ -12096,7 +12096,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12096
12096
  ${o}
12097
12097
  ${this._error?`<div class="error-banner">${this._escapeHtml(this._error)}</div>`:""}
12098
12098
  </div>
12099
- `,this._bindEvents()}};customElements.get("loki-rarv-timeline")||customElements.define("loki-rarv-timeline",be);function xt(d){if(!d||typeof d!="object")return null;let e=d.freshness_s;return typeof e!="number"||!Number.isFinite(e)||e<0?null:e}function _t(d){if(!Array.isArray(d))return null;let e=null;for(let t of d){let i=xt(t);i!==null&&(e===null||i<e)&&(e=i)}return e}function yt(d={}){let{payload:e=null,receivedAtMs:t=null,nowMs:i=Date.now(),staleAfterS:a=120}=d,s=xt(e),r=null,o="none";return s!==null?(r=s,o="server"):typeof t=="number"&&Number.isFinite(t)&&(r=Math.max(0,Math.floor((i-t)/1e3)),o="client"),{known:r!==null,ageS:r,source:o,isStale:r===null?null:r>=a,staleAfterS:a}}function ti(d){if(!d||!d.known||typeof d.ageS!="number")return"unknown";let e=d.ageS;return e<60?`${e}s ago`:e<3600?`${Math.floor(e/60)}m ago`:e<86400?`${Math.floor(e/3600)}h ago`:`${Math.floor(e/86400)}d ago`}function Ze(d){if(!d||!d.known)return"Data age unknown";let e=d.source==="client"?" (receive time)":"",t=d.isStale?" - STALE":"";return`Updated ${ti(d)}${e}${t}`}var wt={running:{color:"var(--loki-green, #22c55e)",bg:"var(--loki-green-muted, rgba(34, 197, 94, 0.15))",label:"Running"},completed:{color:"var(--loki-blue, #3b82f6)",bg:"var(--loki-blue-muted, rgba(59, 130, 246, 0.15))",label:"Completed"},failed:{color:"var(--loki-red, #ef4444)",bg:"var(--loki-red-muted, rgba(239, 68, 68, 0.15))",label:"Failed"},cancelled:{color:"var(--loki-yellow, #eab308)",bg:"var(--loki-yellow-muted, rgba(234, 179, 8, 0.15))",label:"Cancelled"},pending:{color:"var(--loki-text-muted, #939084)",bg:"var(--loki-bg-tertiary, #ECEAE3)",label:"Pending"},queued:{color:"var(--loki-text-muted, #939084)",bg:"var(--loki-bg-tertiary, #ECEAE3)",label:"Queued"},building:{color:"var(--loki-green, #22c55e)",bg:"var(--loki-green-muted, rgba(34, 197, 94, 0.15))",label:"Building"},bootstrap:{color:"var(--loki-green, #22c55e)",bg:"var(--loki-green-muted, rgba(34, 197, 94, 0.15))",label:"Bootstrap"},complete:{color:"var(--loki-blue, #3b82f6)",bg:"var(--loki-blue-muted, rgba(59, 130, 246, 0.15))",label:"Completed"},stopped:{color:"var(--loki-yellow, #eab308)",bg:"var(--loki-yellow-muted, rgba(234, 179, 8, 0.15))",label:"Stopped"},paused:{color:"var(--loki-yellow, #eab308)",bg:"var(--loki-yellow-muted, rgba(234, 179, 8, 0.15))",label:"Paused"},unknown:{color:"var(--loki-text-muted, #939084)",bg:"var(--loki-bg-tertiary, #ECEAE3)",label:"Unknown"}};function ii(d,e,t){let i=d;if(i==null&&e){let l=new Date(e).getTime();i=(t?new Date(t).getTime():Date.now())-l}if(i==null||i<0)return"--";if(i<1e3)return`${i}ms`;let a=Math.floor(i/1e3);if(a<60)return`${a}s`;let s=Math.floor(a/60),r=a%60;if(s<60)return`${s}m ${r}s`;let o=Math.floor(s/60),n=s%60;return`${o}h ${n}m`}function ai(d){if(!d)return"--";try{return new Date(d).toLocaleString([],{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return String(d)}}var ke=class extends v{static get observedAttributes(){return["api-url","project-id","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._runs=[],this._pollInterval=null,this._lastDataHash=null,this._emptyReason=null,this._source=null,this._freshPayload=null,this._changedAtMs=null}_freshness(){let e=t=>{if(!t)return!1;if(t.current===!0)return!0;let i=String(t.status||"").toLowerCase();return i==="running"||i==="in_progress"||i==="active"};return yt({payload:this._freshPayload,receivedAtMs:this._changedAtMs,staleAfterS:this._runs.some(e)?void 0:1/0})}_renderFreshness(){let e=this.shadowRoot&&this.shadowRoot.getElementById("freshness");if(!e)return;let t=this._freshness();e.className=`freshness ${t.known?t.isStale?"is-stale":"":"is-unknown"}`,e.dataset.source=t.source,e.dataset.stale=t.isStale===null?"unknown":String(t.isStale),e.textContent=Ze(t)}get projectId(){let e=this.getAttribute("project-id");return e?parseInt(e,10):null}set projectId(e){e!=null?this.setAttribute("project-id",String(e)):this.removeAttribute("project-id")}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="project-id"&&this._loadData(),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let t=this.projectId,i=t!=null?`?project_id=${t}`:"",a=await e._get(`/api/v2/runs${i}`);if(e!==this._api)return;let s=a?.runs||a||[],r=Array.isArray(s)?s:[];this._freshPayload=a&&typeof a=="object"&&!Array.isArray(a)&&"freshness_s"in a?a:{freshness_s:_t(r)};let o=JSON.stringify(s),n=o!==this._lastDataHash||!!this._error;n&&(this._lastDataHash=o,this._runs=r,this._changedAtMs=Date.now()),this._emptyReason=a&&!Array.isArray(a)&&a.reason||null,this._source=a&&!Array.isArray(a)&&a.source||null,this._error=null,this._loading=!1,n?this.render():this._renderFreshness();return}catch(t){if(e!==this._api)return;this._error||(this._error=`Failed to load runs: ${t.message}`)}finally{this._loading=!1}this.render()}async _cancelRun(e){try{await this._api._post(`/api/v2/runs/${e}/cancel`),await this._loadData()}catch(t){this._error=`Cancel failed: ${t.message}`,this.render()}}async _replayRun(e){try{await this._api._post(`/api/v2/runs/${e}/replay`),await this._loadData()}catch(t){this._error=`Replay failed: ${t.message}`,this.render()}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
12099
+ `,this._bindEvents()}};customElements.get("loki-rarv-timeline")||customElements.define("loki-rarv-timeline",fe);function dt(d){if(!d||typeof d!="object")return null;let e=d.freshness_s;return typeof e!="number"||!Number.isFinite(e)||e<0?null:e}function ct(d){if(!Array.isArray(d))return null;let e=null;for(let t of d){let i=dt(t);i!==null&&(e===null||i<e)&&(e=i)}return e}function pt(d={}){let{payload:e=null,receivedAtMs:t=null,nowMs:i=Date.now(),staleAfterS:a=120}=d,s=dt(e),r=null,o="none";return s!==null?(r=s,o="server"):typeof t=="number"&&Number.isFinite(t)&&(r=Math.max(0,Math.floor((i-t)/1e3)),o="client"),{known:r!==null,ageS:r,source:o,isStale:r===null?null:r>=a,staleAfterS:a}}function Gt(d){if(!d||!d.known||typeof d.ageS!="number")return"unknown";let e=d.ageS;return e<60?`${e}s ago`:e<3600?`${Math.floor(e/60)}m ago`:e<86400?`${Math.floor(e/3600)}h ago`:`${Math.floor(e/86400)}d ago`}function Ke(d){if(!d||!d.known)return"Data age unknown";let e=d.source==="client"?" (receive time)":"",t=d.isStale?" - STALE":"";return`Updated ${Gt(d)}${e}${t}`}var ut={running:{color:"var(--loki-green, #22c55e)",bg:"var(--loki-green-muted, rgba(34, 197, 94, 0.15))",label:"Running"},completed:{color:"var(--loki-blue, #3b82f6)",bg:"var(--loki-blue-muted, rgba(59, 130, 246, 0.15))",label:"Completed"},failed:{color:"var(--loki-red, #ef4444)",bg:"var(--loki-red-muted, rgba(239, 68, 68, 0.15))",label:"Failed"},cancelled:{color:"var(--loki-yellow, #eab308)",bg:"var(--loki-yellow-muted, rgba(234, 179, 8, 0.15))",label:"Cancelled"},pending:{color:"var(--loki-text-muted, #939084)",bg:"var(--loki-bg-tertiary, #ECEAE3)",label:"Pending"},queued:{color:"var(--loki-text-muted, #939084)",bg:"var(--loki-bg-tertiary, #ECEAE3)",label:"Queued"},building:{color:"var(--loki-green, #22c55e)",bg:"var(--loki-green-muted, rgba(34, 197, 94, 0.15))",label:"Building"},bootstrap:{color:"var(--loki-green, #22c55e)",bg:"var(--loki-green-muted, rgba(34, 197, 94, 0.15))",label:"Bootstrap"},complete:{color:"var(--loki-blue, #3b82f6)",bg:"var(--loki-blue-muted, rgba(59, 130, 246, 0.15))",label:"Completed"},stopped:{color:"var(--loki-yellow, #eab308)",bg:"var(--loki-yellow-muted, rgba(234, 179, 8, 0.15))",label:"Stopped"},paused:{color:"var(--loki-yellow, #eab308)",bg:"var(--loki-yellow-muted, rgba(234, 179, 8, 0.15))",label:"Paused"},unknown:{color:"var(--loki-text-muted, #939084)",bg:"var(--loki-bg-tertiary, #ECEAE3)",label:"Unknown"}},Jt=new Set(["running","in_progress","active","building","bootstrap"]);function Vt(d,e,t,i=!1){let a=d;if(a==null&&e&&(t||i)){let c=new Date(e).getTime();a=(t?new Date(t).getTime():Date.now())-c}if(a==null||a<0)return"--";if(a<1e3)return`${a}ms`;let s=Math.floor(a/1e3);if(s<60)return`${s}s`;let r=Math.floor(s/60),o=s%60;if(r<60)return`${r}m ${o}s`;let n=Math.floor(r/60),l=r%60;return`${n}h ${l}m`}function Kt(d){if(!d)return"--";try{return new Date(d).toLocaleString([],{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return String(d)}}var be=class extends v{static get observedAttributes(){return["api-url","project-id","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._runs=[],this._pollInterval=null,this._lastDataHash=null,this._emptyReason=null,this._source=null,this._freshPayload=null,this._changedAtMs=null}_freshness(){let e=t=>{if(!t)return!1;if(t.current===!0)return!0;let i=String(t.status||"").toLowerCase();return i==="running"||i==="in_progress"||i==="active"};return pt({payload:this._freshPayload,receivedAtMs:this._changedAtMs,staleAfterS:this._runs.some(e)?void 0:1/0})}_renderFreshness(){let e=this.shadowRoot&&this.shadowRoot.getElementById("freshness");if(!e)return;let t=this._freshness();e.className=`freshness ${t.known?t.isStale?"is-stale":"":"is-unknown"}`,e.dataset.source=t.source,e.dataset.stale=t.isStale===null?"unknown":String(t.isStale),e.textContent=Ke(t)}get projectId(){let e=this.getAttribute("project-id");return e?parseInt(e,10):null}set projectId(e){e!=null?this.setAttribute("project-id",String(e)):this.removeAttribute("project-id")}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="project-id"&&this._loadData(),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let t=this.projectId,i=t!=null?`?project_id=${t}`:"",a=await e._get(`/api/v2/runs${i}`);if(e!==this._api)return;let s=a?.runs||a||[],r=Array.isArray(s)?s:[];this._freshPayload=a&&typeof a=="object"&&!Array.isArray(a)&&"freshness_s"in a?a:{freshness_s:ct(r)};let o=JSON.stringify(s),n=o!==this._lastDataHash||!!this._error;n&&(this._lastDataHash=o,this._runs=r,this._changedAtMs=Date.now()),this._emptyReason=a&&!Array.isArray(a)&&a.reason||null,this._source=a&&!Array.isArray(a)&&a.source||null,this._error=null,this._loading=!1,n?this.render():this._renderFreshness();return}catch(t){if(e!==this._api)return;this._error||(this._error=`Failed to load runs: ${t.message}`)}finally{this._loading=!1}this.render()}async _cancelRun(e){try{await this._api._post(`/api/v2/runs/${e}/cancel`),await this._loadData()}catch(t){this._error=`Cancel failed: ${t.message}`,this.render()}}async _replayRun(e){try{await this._api._post(`/api/v2/runs/${e}/replay`),await this._loadData()}catch(t){this._error=`Replay failed: ${t.message}`,this.render()}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
12100
12100
  :host {
12101
12101
  display: block;
12102
12102
  }
@@ -12270,13 +12270,13 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12270
12270
  align-items: center;
12271
12271
  gap: 10px;
12272
12272
  }
12273
- `}render(){let e=this.shadowRoot;if(!e)return;let t=this._runs,i;if(this._loading&&t.length===0)i='<div class="loading">Loading runs...</div>';else if(this._error&&t.length===0)i=`<div class="empty-state error-state" role="status" aria-live="polite">Could not load runs.<div class="error-state-detail">${this._escapeHtml(this._error)}</div></div>`;else if(t.length===0){let r=this._emptyReason?`<div class="empty-reason">${this._escapeHtml(this._emptyReason)}</div>`:'<div class="empty-reason">The server did not state a reason.</div>',o=this._source?`<div class="empty-source">Read from: ${this._escapeHtml(Array.isArray(this._source)?this._source.join(", "):this._source)}</div>`:"";i=`<div class="empty-state" role="status" aria-live="polite">No runs found.${r}${o}</div>`}else{let r=t.map(o=>{let n=(o.status||"pending").toLowerCase(),l=wt[n]||wt.pending,c=n==="running",p=n==="completed"||n==="failed"||n==="cancelled",u=ii(o.duration_ms,o.started_at,o.ended_at);return`
12273
+ `}render(){let e=this.shadowRoot;if(!e)return;let t=this._runs,i;if(this._loading&&t.length===0)i='<div class="loading">Loading runs...</div>';else if(this._error&&t.length===0)i=`<div class="empty-state error-state" role="status" aria-live="polite">Could not load runs.<div class="error-state-detail">${this._escapeHtml(this._error)}</div></div>`;else if(t.length===0){let r=this._emptyReason?`<div class="empty-reason">${this._escapeHtml(this._emptyReason)}</div>`:'<div class="empty-reason">The server did not state a reason.</div>',o=this._source?`<div class="empty-source">Read from: ${this._escapeHtml(Array.isArray(this._source)?this._source.join(", "):this._source)}</div>`:"";i=`<div class="empty-state" role="status" aria-live="polite">No runs found.${r}${o}</div>`}else{let r=t.map(o=>{let n=(o.status||"unknown").toLowerCase(),l=ut[n]||{...ut.unknown,label:o.status},c=n==="running",p=n==="completed"||n==="failed"||n==="cancelled",u=Vt(o.duration_ms,o.started_at,o.ended_at,Jt.has(n));return`
12274
12274
  <tr>
12275
12275
  <td><span class="run-id">#${o.id}</span></td>
12276
12276
  <td>${this._escapeHtml(o.project_name||o.project||(o.project_id?`Project #${o.project_id}`:"--"))}</td>
12277
- <td><span class="status-badge" style="background: ${l.bg}; color: ${l.color};">${l.label}</span></td>
12277
+ <td><span class="status-badge" style="background: ${l.bg}; color: ${l.color};">${this._escapeHtml(l.label)}</span></td>
12278
12278
  <td>${this._escapeHtml(o.trigger||o.trigger_type||"--")}</td>
12279
- <td>${ai(o.started_at)}</td>
12279
+ <td>${Kt(o.started_at)}</td>
12280
12280
  <td>${u}</td>
12281
12281
  <td>
12282
12282
  <div class="actions-cell">
@@ -12309,14 +12309,14 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12309
12309
  <div class="header">
12310
12310
  <h2 class="title">Run Manager</h2>
12311
12311
  <div class="header-right">
12312
- <span class="freshness ${s}" id="freshness" data-source="${a.source}" data-stale="${a.isStale===null?"unknown":String(a.isStale)}">${this._escapeHtml(Ze(a))}</span>
12312
+ <span class="freshness ${s}" id="freshness" data-source="${a.source}" data-stale="${a.isStale===null?"unknown":String(a.isStale)}">${this._escapeHtml(Ke(a))}</span>
12313
12313
  <button class="btn btn-refresh" id="refresh-btn">Refresh</button>
12314
12314
  </div>
12315
12315
  </div>
12316
12316
  ${i}
12317
12317
  ${this._error?`<div class="error-banner">${this._escapeHtml(this._error)}</div>`:""}
12318
12318
  </div>
12319
- `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.getElementById("refresh-btn");t&&t.addEventListener("click",()=>this._loadData()),e.querySelectorAll('[data-action="cancel"]').forEach(i=>{i.addEventListener("click",()=>this._cancelRun(i.dataset.runId))}),e.querySelectorAll('[data-action="replay"]').forEach(i=>{i.addEventListener("click",()=>this._replayRun(i.dataset.runId))})}};customElements.get("loki-run-manager")||customElements.define("loki-run-manager",ke);var $t={running:{color:"var(--loki-green, #22c55e)",bg:"var(--loki-green-muted, rgba(34, 197, 94, 0.15))",label:"Running"},stopped:{color:"var(--loki-yellow, #eab308)",bg:"var(--loki-yellow-muted, rgba(234, 179, 8, 0.15))",label:"Stopped"},active:{color:"var(--loki-blue, #3b82f6)",bg:"var(--loki-blue-muted, rgba(59, 130, 246, 0.15))",label:"Idle"},missing:{color:"var(--loki-red, #ef4444)",bg:"var(--loki-red-muted, rgba(239, 68, 68, 0.15))",label:"Missing"},unknown:{color:"var(--loki-text-muted, #939084)",bg:"var(--loki-bg-tertiary, #ECEAE3)",label:"Unknown"}};function si(d){if(d==null||d<0)return"--";if(d<60)return`${d}s`;let e=Math.floor(d/60),t=d%60;if(e<60)return`${e}m ${t}s`;let i=Math.floor(e/60),a=e%60;return`${i}h ${a}m`}function Et(d){return d==null||isNaN(d)?"$0.00":`$${Number(d).toFixed(2)}`}var xe=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!0,this._error=null,this._api=null,this._runs=[],this._summary=null,this._pollInterval=null,this._lastDataHash=null,this._emptyReason=null,this._source=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let[t,i]=await Promise.all([e._get("/api/fleet/runs"),e._get("/api/fleet/summary")]);if(e!==this._api)return;let a=Array.isArray(t)?t:t?.runs||[],s=JSON.stringify({runs:a,summaryResp:i});if(s===this._lastDataHash&&!this._error)return;this._lastDataHash=s,this._runs=Array.isArray(a)?a:[],this._summary=i||null,this._emptyReason=t&&!Array.isArray(t)&&t.reason||null,this._source=t&&!Array.isArray(t)&&t.source||null,this._error=null}catch(t){if(e!==this._api)return;this._emptyReason=null,this._source=null,this._error||(this._error=`Failed to load fleet: ${t.message}`)}finally{this._loading=!1}this.render()}async _cancelRun(e){if(e&&!(typeof confirm=="function"&&!confirm(`Cancel build "${e}"? This stops the running build.`)))try{await this._api._post(`/api/fleet/runs/${encodeURIComponent(e)}/cancel`),this._lastDataHash=null,await this._loadData()}catch(t){this._error=`Cancel failed: ${t.message}`,this.render()}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
12319
+ `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.getElementById("refresh-btn");t&&t.addEventListener("click",()=>this._loadData()),e.querySelectorAll('[data-action="cancel"]').forEach(i=>{i.addEventListener("click",()=>this._cancelRun(i.dataset.runId))}),e.querySelectorAll('[data-action="replay"]').forEach(i=>{i.addEventListener("click",()=>this._replayRun(i.dataset.runId))})}};customElements.get("loki-run-manager")||customElements.define("loki-run-manager",be);var ht={running:{color:"var(--loki-green, #22c55e)",bg:"var(--loki-green-muted, rgba(34, 197, 94, 0.15))",label:"Running"},stopped:{color:"var(--loki-yellow, #eab308)",bg:"var(--loki-yellow-muted, rgba(234, 179, 8, 0.15))",label:"Stopped"},active:{color:"var(--loki-blue, #3b82f6)",bg:"var(--loki-blue-muted, rgba(59, 130, 246, 0.15))",label:"Idle"},missing:{color:"var(--loki-red, #ef4444)",bg:"var(--loki-red-muted, rgba(239, 68, 68, 0.15))",label:"Missing"},unknown:{color:"var(--loki-text-muted, #939084)",bg:"var(--loki-bg-tertiary, #ECEAE3)",label:"Unknown"}};function Yt(d){if(d==null||d<0)return"--";if(d<60)return`${d}s`;let e=Math.floor(d/60),t=d%60;if(e<60)return`${e}m ${t}s`;let i=Math.floor(e/60),a=e%60;return`${i}h ${a}m`}function gt(d){return T(d)}var ke=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!0,this._error=null,this._api=null,this._runs=[],this._summary=null,this._pollInterval=null,this._lastDataHash=null,this._emptyReason=null,this._source=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let[t,i]=await Promise.all([e._get("/api/fleet/runs"),e._get("/api/fleet/summary")]);if(e!==this._api)return;let a=Array.isArray(t)?t:t?.runs||[],s=JSON.stringify({runs:a,summaryResp:i});if(s===this._lastDataHash&&!this._error)return;this._lastDataHash=s,this._runs=Array.isArray(a)?a:[],this._summary=i||null,this._emptyReason=t&&!Array.isArray(t)&&t.reason||null,this._source=t&&!Array.isArray(t)&&t.source||null,this._error=null}catch(t){if(e!==this._api)return;this._emptyReason=null,this._source=null,this._error||(this._error=`Failed to load fleet: ${t.message}`)}finally{this._loading=!1}this.render()}async _cancelRun(e){if(e&&!(typeof confirm=="function"&&!confirm(`Cancel build "${e}"? This stops the running build.`)))try{await this._api._post(`/api/fleet/runs/${encodeURIComponent(e)}/cancel`),this._lastDataHash=null,await this._loadData()}catch(t){this._error=`Cancel failed: ${t.message}`,this.render()}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
12320
12320
  :host { display: block; }
12321
12321
 
12322
12322
  .fleet {
@@ -12506,7 +12506,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12506
12506
  color: var(--loki-text-muted, #939084);
12507
12507
  font-size: 13px;
12508
12508
  }
12509
- `}_renderSummary(){let e=this._summary;return e?`
12509
+ `}_renderSummary(){let e=this._summary;if(!e)return"";let t=this._runs.some(i=>i.cost_usd==null)&&e.total_cost_usd!=null?" (partial)":"";return`
12510
12510
  <div class="summary-cards">
12511
12511
  <div class="summary-card">
12512
12512
  <div class="summary-label">Builds</div>
@@ -12522,16 +12522,16 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12522
12522
  </div>
12523
12523
  <div class="summary-card">
12524
12524
  <div class="summary-label">Total Cost</div>
12525
- <div class="summary-value">${Et(e.total_cost_usd)}</div>
12525
+ <div class="summary-value">${gt(e.total_cost_usd)}${t}</div>
12526
12526
  </div>
12527
12527
  </div>
12528
- `:""}render(){let e=this.shadowRoot;if(!e)return;let t=this._runs,i;if(this._loading&&t.length===0)i='<div class="loading">Loading fleet...</div>';else if(this._error&&t.length===0)i=`
12528
+ `}render(){let e=this.shadowRoot;if(!e)return;let t=this._runs,i;if(this._loading&&t.length===0)i='<div class="loading">Loading fleet...</div>';else if(this._error&&t.length===0)i=`
12529
12529
  <div class="error-state" role="status">
12530
12530
  <div class="error-state-title">Could not load the fleet</div>
12531
12531
  <div class="error-state-detail">${this._escapeHtml(this._error)}</div>
12532
12532
  <div class="error-state-hint">This is a read failure, not an empty fleet. Builds may be running.</div>
12533
12533
  </div>
12534
- `;else if(t.length===0){let a=this._emptyReason?`<div class="empty-reason">${this._escapeHtml(this._emptyReason)}</div>`:'<div class="empty-reason">The server did not state a reason, so an unreadable registry is indistinguishable from an idle one here.</div>',s=this._source?`<div class="empty-source">Source: ${this._escapeHtml(Array.isArray(this._source)?this._source.join(", "):String(this._source))}</div>`:"";i=`<div class="empty-state">No registered builds. Run <code>loki start</code> in a project to populate the fleet.${a}${s}</div>`}else{let a=t.map(s=>{let r=(s.status||"unknown").toLowerCase(),o=$t[r]||$t.unknown,n=s.running===!0,l=si(s.duration_seconds),c=s.iteration!=null?s.iteration:0,p=s.phase?this._escapeHtml(s.phase):"--";return`
12534
+ `;else if(t.length===0){let a=this._emptyReason?`<div class="empty-reason">${this._escapeHtml(this._emptyReason)}</div>`:'<div class="empty-reason">The server did not state a reason, so an unreadable registry is indistinguishable from an idle one here.</div>',s=this._source?`<div class="empty-source">Source: ${this._escapeHtml(Array.isArray(this._source)?this._source.join(", "):String(this._source))}</div>`:"";i=`<div class="empty-state">No registered builds. Run <code>loki start</code> in a project to populate the fleet.${a}${s}</div>`}else{let a=t.map(s=>{let r=(s.status||"unknown").toLowerCase(),o=ht[r]||ht.unknown,n=s.running===!0,l=Yt(s.duration_seconds),c=s.iteration!=null?this._escapeHtml(String(s.iteration)):"--",p=s.phase?this._escapeHtml(s.phase):"--";return`
12535
12535
  <tr>
12536
12536
  <td>
12537
12537
  <div class="project-name">${this._escapeHtml(s.name||"project")}</div>
@@ -12540,7 +12540,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12540
12540
  <td><span class="status-badge" style="background: ${o.bg}; color: ${o.color};">${o.label}</span></td>
12541
12541
  <td>${p}</td>
12542
12542
  <td>${c}</td>
12543
- <td class="cost-cell">${Et(s.cost_usd)}</td>
12543
+ <td class="cost-cell">${gt(s.cost_usd)}</td>
12544
12544
  <td>${l}</td>
12545
12545
  <td>
12546
12546
  ${n?`<button class="btn btn-cancel" data-action="cancel" data-id="${this._escapeHtml(s.id||s.path||"")}">Cancel</button>`:""}
@@ -12580,7 +12580,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12580
12580
  ${i}
12581
12581
  ${this._error&&t.length>0?`<div class="error-banner">${this._escapeHtml(this._error)}</div>`:""}
12582
12582
  </div>
12583
- `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.getElementById("refresh-btn");t&&t.addEventListener("click",()=>{this._lastDataHash=null,this._loadData()}),e.querySelectorAll('[data-action="cancel"]').forEach(i=>{i.addEventListener("click",()=>this._cancelRun(i.dataset.id))})}};customElements.get("loki-fleet")||customElements.define("loki-fleet",xe);function ri(d){if(!d)return"--";try{return new Date(d).toLocaleString([],{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"})}catch{return String(d)}}function oi(d){let e=new URLSearchParams;for(let[i,a]of Object.entries(d))a!=null&&a!==""&&e.set(i,String(a));let t=e.toString();return t?`?${t}`:""}var _e=class extends v{static get observedAttributes(){return["api-url","limit","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._entries=[],this._emptyReason=null,this._verifyResult=null,this._verifying=!1,this._filters={action:"",resource:"",dateFrom:"",dateTo:""}}get limit(){let e=this.getAttribute("limit");return e?parseInt(e,10):50}set limit(e){this.setAttribute("limit",String(e))}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData()}disconnectedCallback(){super.disconnectedCallback()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="limit"&&this._loadData(),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;try{this._loading=!0,this.render();let t={limit:this.limit,action:this._filters.action,resource:this._filters.resource,date_from:this._filters.dateFrom,date_to:this._filters.dateTo},i=oi(t),a=await e._get(`/api/v2/audit${i}`);if(e!==this._api)return;this._entries=a?.entries||a||[],this._emptyReason=a&&!Array.isArray(a)&&a.reason||null,this._error=null}catch(t){if(e!==this._api)return;this._emptyReason=null,this._error=`Failed to load audit log: ${t.message}`}finally{this._loading=!1}this.render()}async _verifyIntegrity(){let e=this._api;try{this._verifying=!0,this._verifyResult=null,this.render();let t=await e._get("/api/v2/audit/verify");if(e!==this._api)return;this._verifyResult=t}catch(t){if(e!==this._api)return;this._verifyResult={valid:!1,error:t.message}}finally{this._verifying=!1}this.render()}_onFilterChange(e,t){this._filters[e]=t,this._loadData()}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
12583
+ `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.getElementById("refresh-btn");t&&t.addEventListener("click",()=>{this._lastDataHash=null,this._loadData()}),e.querySelectorAll('[data-action="cancel"]').forEach(i=>{i.addEventListener("click",()=>this._cancelRun(i.dataset.id))})}};customElements.get("loki-fleet")||customElements.define("loki-fleet",ke);function Wt(d){if(!d)return"--";try{return new Date(d).toLocaleString([],{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"})}catch{return String(d)}}function Qt(d){let e=new URLSearchParams;for(let[i,a]of Object.entries(d))a!=null&&a!==""&&e.set(i,String(a));let t=e.toString();return t?`?${t}`:""}function Xt(d){if(!d||d.requestError)return{kind:"unchecked",text:`[NOT VERIFIED] Could not check the audit chain: ${d&&d.requestError||"no response"}`};let e=typeof d.files_checked=="number"?d.files_checked:null;if(d.valid===!1)return{kind:"invalid",text:`[TAMPERED] Audit chain broken${d.first_tampered_file?` at ${String(d.first_tampered_file).split("/").pop()}${d.first_tampered_line?` line ${d.first_tampered_line}`:""}`:""}.`};if(d.valid===!0&&e!==null&&e>0){let t=typeof d.entries_checked=="number"?`, ${d.entries_checked} entries`:"";return{kind:"valid",text:`[VALID] Audit chain integrity verified (${e} file${e===1?"":"s"}${t}).`}}return d.valid===!0&&e===0?{kind:"unchecked",text:"[NOT VERIFIED] Nothing was checked: no audit log file carries integrity hashes yet."}:{kind:"unchecked",text:"[NOT VERIFIED] The server returned no verdict."}}var xe=class extends v{static get observedAttributes(){return["api-url","limit","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._entries=[],this._emptyReason=null,this._verifyResult=null,this._verifying=!1,this._filters={action:"",resource:"",dateFrom:"",dateTo:""}}get limit(){let e=this.getAttribute("limit");return e?parseInt(e,10):50}set limit(e){this.setAttribute("limit",String(e))}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData()}disconnectedCallback(){super.disconnectedCallback()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="limit"&&this._loadData(),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;try{this._loading=!0,this.render();let t={limit:this.limit,action:this._filters.action,resource:this._filters.resource,date_from:this._filters.dateFrom,date_to:this._filters.dateTo},i=Qt(t),a=await e._get(`/api/v2/audit${i}`);if(e!==this._api)return;this._entries=a?.entries||a||[],this._emptyReason=a&&!Array.isArray(a)&&a.reason||null,this._error=null}catch(t){if(e!==this._api)return;this._emptyReason=null,this._error=`Failed to load audit log: ${t.message}`}finally{this._loading=!1}this.render()}async _verifyIntegrity(){let e=this._api;try{this._verifying=!0,this._verifyResult=null,this.render();let t=await e._get("/api/v2/audit/verify");if(e!==this._api)return;this._verifyResult=t}catch(t){if(e!==this._api)return;this._verifyResult={requestError:t.message}}finally{this._verifying=!1}this.render()}_onFilterChange(e,t){this._filters[e]=t,this._loadData()}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
12584
12584
  :host {
12585
12585
  display: block;
12586
12586
  }
@@ -12702,6 +12702,12 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12702
12702
  border: 1px solid var(--loki-red-muted, rgba(239, 68, 68, 0.15));
12703
12703
  }
12704
12704
 
12705
+ .verify-unchecked {
12706
+ background: var(--loki-yellow-muted, rgba(234, 179, 8, 0.15));
12707
+ color: var(--loki-yellow, #eab308);
12708
+ border: 1px solid var(--loki-yellow-muted, rgba(234, 179, 8, 0.15));
12709
+ }
12710
+
12705
12711
  .audit-table-wrapper {
12706
12712
  background: var(--loki-bg-card, #ffffff);
12707
12713
  border: 1px solid var(--loki-border, #ECEAE3);
@@ -12831,9 +12837,9 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12831
12837
  color: var(--loki-text-muted, #939084);
12832
12838
  margin-bottom: 8px;
12833
12839
  }
12834
- `}_getStatusClass(e){if(!e)return"status-warning";let t=e.toLowerCase();return t==="success"||t==="ok"||t==="pass"?"status-success":t==="failure"||t==="error"||t==="fail"?"status-failure":"status-warning"}render(){let e=this.shadowRoot;if(!e)return;let t=this._entries,i="";if(this._verifyResult){let s=this._verifyResult.valid!==!1;i=`
12835
- <div class="verify-result ${s?"verify-valid":"verify-invalid"}">
12836
- ${s?"[VALID] Audit chain integrity verified.":`[TAMPERED] ${this._escapeHtml(this._verifyResult.error||"Integrity check failed.")}`}
12840
+ `}_getStatusClass(e){if(!e)return"status-warning";let t=e.toLowerCase();return t==="success"||t==="ok"||t==="pass"?"status-success":t==="failure"||t==="error"||t==="fail"?"status-failure":"status-warning"}render(){let e=this.shadowRoot;if(!e)return;let t=this._entries,i="";if(this._verifyResult){let s=Xt(this._verifyResult);i=`
12841
+ <div class="verify-result verify-${s.kind}">
12842
+ ${this._escapeHtml(s.text)}
12837
12843
  </div>
12838
12844
  `}let a;if(this._loading&&t.length===0)a='<div class="loading">Loading audit log...</div>';else if(this._error&&t.length===0)a=`
12839
12845
  <div class="error-state" role="status">
@@ -12843,7 +12849,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12843
12849
  </div>
12844
12850
  `;else if(t.length===0)a=`<div class="empty-state">No audit entries found matching filters.${this._emptyReason?`<div class="empty-reason">${this._escapeHtml(this._emptyReason)}</div>`:'<div class="empty-reason">The server did not state a reason.</div>'}</div>`;else{let s=t.map(r=>`
12845
12851
  <tr>
12846
- <td>${ri(r.timestamp)}</td>
12852
+ <td>${Wt(r.timestamp)}</td>
12847
12853
  <td>${this._escapeHtml(r.action||"--")}</td>
12848
12854
  <td>${this._escapeHtml(r.resource||r.resource_type||"--")}</td>
12849
12855
  <td>${this._escapeHtml(r.user||r.actor||"--")}</td>
@@ -12907,7 +12913,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
12907
12913
  ${a}
12908
12914
  ${this._error&&t.length>0?`<div class="error-banner">${this._escapeHtml(this._error)}</div>`:""}
12909
12915
  </div>
12910
- `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.getElementById("verify-btn");t&&t.addEventListener("click",()=>this._verifyIntegrity());let i=e.getElementById("refresh-btn");i&&i.addEventListener("click",()=>this._loadData());let a=e.getElementById("filter-action");a&&a.addEventListener("change",n=>this._onFilterChange("action",n.target.value));let s=e.getElementById("filter-resource");s&&s.addEventListener("change",n=>this._onFilterChange("resource",n.target.value));let r=e.getElementById("filter-date-from");r&&r.addEventListener("change",n=>this._onFilterChange("dateFrom",n.target.value));let o=e.getElementById("filter-date-to");o&&o.addEventListener("change",n=>this._onFilterChange("dateTo",n.target.value))}};customElements.get("loki-audit-viewer")||customElements.define("loki-audit-viewer",_e);function Ct(d){if(!d)return"Never";try{return new Date(d).toLocaleString([],{month:"short",day:"numeric",year:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return String(d)}}var ye=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._keys=[],this._showCreateForm=!1,this._newToken=null,this._confirmDeleteId=null,this._rotateKeyId=null,this._rotateGracePeriod="24",this._createName="",this._createRole="read",this._createExpiration=""}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData()}disconnectedCallback(){super.disconnectedCallback()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;try{this._loading=!0,this.render();let t=await e._get("/api/v2/api-keys");if(e!==this._api)return;this._keys=Array.isArray(t)?t:t?.keys||[],this._error=null}catch(t){if(e!==this._api)return;this._error=`Failed to load API keys: ${t.message}`}finally{this._loading=!1}this.render()}async _createKey(){if(!this._createName.trim()){this._error="Key name is required.",this.render();return}try{let e={name:this._createName.trim(),role:this._createRole};this._createExpiration&&(e.expiration=this._createExpiration);let t=await this._api._post("/api/v2/api-keys",e);this._newToken=t?.token||t?.key||null,this._showCreateForm=!1,this._createName="",this._createRole="read",this._createExpiration="",this._error=null,await this._loadData()}catch(e){this._error=`Create failed: ${e.message}`,this.render()}}async _rotateKey(e){try{let t={grace_period_hours:parseInt(this._rotateGracePeriod,10)||24},i=await this._api._post(`/api/v2/api-keys/${e}/rotate`,t);this._newToken=i?.token||i?.key||null,this._rotateKeyId=null,this._error=null,await this._loadData()}catch(t){this._error=`Rotate failed: ${t.message}`,this.render()}}async _deleteKey(e){try{await this._api._delete(`/api/v2/api-keys/${e}`),this._confirmDeleteId=null,this._error=null,await this._loadData()}catch(t){this._error=`Delete failed: ${t.message}`,this._confirmDeleteId=null,this.render()}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
12916
+ `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.getElementById("verify-btn");t&&t.addEventListener("click",()=>this._verifyIntegrity());let i=e.getElementById("refresh-btn");i&&i.addEventListener("click",()=>this._loadData());let a=e.getElementById("filter-action");a&&a.addEventListener("change",n=>this._onFilterChange("action",n.target.value));let s=e.getElementById("filter-resource");s&&s.addEventListener("change",n=>this._onFilterChange("resource",n.target.value));let r=e.getElementById("filter-date-from");r&&r.addEventListener("change",n=>this._onFilterChange("dateFrom",n.target.value));let o=e.getElementById("filter-date-to");o&&o.addEventListener("change",n=>this._onFilterChange("dateTo",n.target.value))}};customElements.get("loki-audit-viewer")||customElements.define("loki-audit-viewer",xe);function mt(d){if(!d)return"Never";try{return new Date(d).toLocaleString([],{month:"short",day:"numeric",year:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return String(d)}}function Zt(d){return d.status?String(d.status).toLowerCase():d.revoked?"revoked":d.expires_at&&Date.parse(d.expires_at)<=Date.now()?"expired":d.rotation_expires_at?"rotating":d.revoked===!1?"active":"unknown"}var _e=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._keys=[],this._showCreateForm=!1,this._newToken=null,this._confirmDeleteId=null,this._rotateKeyId=null,this._rotateGracePeriod="24",this._createName="",this._createRole="read",this._createExpiration=""}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData()}disconnectedCallback(){super.disconnectedCallback()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;try{this._loading=!0,this.render();let t=await e._get("/api/v2/api-keys");if(e!==this._api)return;this._keys=Array.isArray(t)?t:t?.keys||[],this._error=null}catch(t){if(e!==this._api)return;this._error=`Failed to load API keys: ${t.message}`}finally{this._loading=!1}this.render()}async _createKey(){if(!this._createName.trim()){this._error="Key name is required.",this.render();return}try{let e={name:this._createName.trim(),role:this._createRole};this._createExpiration&&(e.expiration=this._createExpiration);let t=await this._api._post("/api/v2/api-keys",e);this._newToken=t?.token||t?.key||null,this._showCreateForm=!1,this._createName="",this._createRole="read",this._createExpiration="",this._error=null,await this._loadData()}catch(e){this._error=`Create failed: ${e.message}`,this.render()}}async _rotateKey(e){try{let t={grace_period_hours:parseInt(this._rotateGracePeriod,10)||24},i=await this._api._post(`/api/v2/api-keys/${e}/rotate`,t);this._newToken=i?.token||i?.key||null,this._rotateKeyId=null,this._error=null,await this._loadData()}catch(t){this._error=`Rotate failed: ${t.message}`,this.render()}}async _deleteKey(e){try{await this._api._delete(`/api/v2/api-keys/${e}`),this._confirmDeleteId=null,this._error=null,await this._loadData()}catch(t){this._error=`Delete failed: ${t.message}`,this._confirmDeleteId=null,this.render()}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
12911
12917
  :host {
12912
12918
  display: block;
12913
12919
  }
@@ -13262,7 +13268,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
13262
13268
  <th>Actions</th>
13263
13269
  </tr>
13264
13270
  </thead>
13265
- <tbody>${t.map(o=>{let n=o.id||o.key_id,l=(o.status||"active").toLowerCase(),c=l==="active"?"key-status-active":l==="expired"?"key-status-expired":"key-status-revoked",p=this._confirmDeleteId===n,u=this._rotateKeyId===n,m;return p?m=`
13271
+ <tbody>${t.map(o=>{let n=o.id||o.key_id,l=Zt(o),c=l==="active"?"key-status-active":l==="expired"?"key-status-expired":"key-status-revoked",p=this._confirmDeleteId===n,u=this._rotateKeyId===n,m;return p?m=`
13266
13272
  <div class="confirm-delete">
13267
13273
  <span>Delete this key?</span>
13268
13274
  <button class="btn btn-sm btn-danger" data-action="confirm-delete" data-key-id="${n}">Yes</button>
@@ -13286,8 +13292,8 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
13286
13292
  <tr>
13287
13293
  <td><span class="key-name">${this._escapeHtml(o.name||"Unnamed")}</span></td>
13288
13294
  <td><span class="key-role">${this._escapeHtml(o.role||o.scopes||"--")}</span></td>
13289
- <td>${Ct(o.created_at||o.created)}</td>
13290
- <td>${Ct(o.last_used_at||o.last_used)}</td>
13295
+ <td>${mt(o.created_at||o.created)}</td>
13296
+ <td>${mt(o.last_used_at||o.last_used)}</td>
13291
13297
  <td><span class="${c}">${this._escapeHtml(l)}</span></td>
13292
13298
  <td><div class="actions-cell">${m}</div></td>
13293
13299
  </tr>
@@ -13306,7 +13312,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
13306
13312
  ${s}
13307
13313
  ${this._error?`<div class="error-banner">${this._escapeHtml(this._error)}</div>`:""}
13308
13314
  </div>
13309
- `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.getElementById("show-create");t&&t.addEventListener("click",()=>{this._showCreateForm=!0,this.render()});let i=e.getElementById("dismiss-token");i&&i.addEventListener("click",()=>{this._newToken=null,this.render()});let a=e.getElementById("submit-create");a&&a.addEventListener("click",()=>{let r=e.getElementById("create-name"),o=e.getElementById("create-role"),n=e.getElementById("create-expiration");this._createName=r?.value||"",this._createRole=o?.value||"read",this._createExpiration=n?.value||"",this._createKey()});let s=e.getElementById("cancel-create");s&&s.addEventListener("click",()=>{this._showCreateForm=!1,this.render()}),e.querySelectorAll('[data-action="delete"]').forEach(r=>{r.addEventListener("click",()=>{this._confirmDeleteId=r.dataset.keyId,this.render()})}),e.querySelectorAll('[data-action="confirm-delete"]').forEach(r=>{r.addEventListener("click",()=>{this._deleteKey(r.dataset.keyId)})}),e.querySelectorAll('[data-action="cancel-delete"]').forEach(r=>{r.addEventListener("click",()=>{this._confirmDeleteId=null,this.render()})}),e.querySelectorAll('[data-action="rotate"]').forEach(r=>{r.addEventListener("click",()=>{this._rotateKeyId=r.dataset.keyId,this.render()})}),e.querySelectorAll('[data-action="confirm-rotate"]').forEach(r=>{r.addEventListener("click",()=>{let o=e.getElementById(`rotate-grace-${r.dataset.keyId}`);this._rotateGracePeriod=o?.value||"24",this._rotateKey(r.dataset.keyId)})}),e.querySelectorAll('[data-action="cancel-rotate"]').forEach(r=>{r.addEventListener("click",()=>{this._rotateKeyId=null,this.render()})})}};customElements.get("loki-api-keys")||customElements.define("loki-api-keys",ye);function ni(d){return d?d.slug&&d.name?`${d.name} (${d.slug})`:d.name||d.slug||"Unknown":"Unknown"}var we=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._tenants=[],this._selectedTenantId=null,this._dropdownOpen=!1}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._outsideClickHandler=e=>{this._dropdownOpen&&!this.contains(e.target)&&(this._dropdownOpen=!1,this.render())},document.addEventListener("click",this._outsideClickHandler)}disconnectedCallback(){super.disconnectedCallback(),this._outsideClickHandler&&(document.removeEventListener("click",this._outsideClickHandler),this._outsideClickHandler=null)}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;try{this._loading=!0;let t=await e._get("/api/v2/tenants");if(e!==this._api)return;this._tenants=Array.isArray(t)?t:t?.tenants||[],this._error=null}catch(t){if(e!==this._api)return;this._error=`Failed to load tenants: ${t.message}`}finally{this._loading=!1}this.render()}_toggleDropdown(){this._dropdownOpen=!this._dropdownOpen,this.render()}_selectTenant(e,t){this._selectedTenantId=e,this._dropdownOpen=!1,this.render(),this.dispatchEvent(new CustomEvent("tenant-changed",{detail:{tenantId:e,tenantName:t},bubbles:!0,composed:!0}))}_getSelectedTenant(){return this._selectedTenantId==null?null:this._tenants.find(e=>(e.id||e.slug)===this._selectedTenantId)||null}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
13315
+ `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.getElementById("show-create");t&&t.addEventListener("click",()=>{this._showCreateForm=!0,this.render()});let i=e.getElementById("dismiss-token");i&&i.addEventListener("click",()=>{this._newToken=null,this.render()});let a=e.getElementById("submit-create");a&&a.addEventListener("click",()=>{let r=e.getElementById("create-name"),o=e.getElementById("create-role"),n=e.getElementById("create-expiration");this._createName=r?.value||"",this._createRole=o?.value||"read",this._createExpiration=n?.value||"",this._createKey()});let s=e.getElementById("cancel-create");s&&s.addEventListener("click",()=>{this._showCreateForm=!1,this.render()}),e.querySelectorAll('[data-action="delete"]').forEach(r=>{r.addEventListener("click",()=>{this._confirmDeleteId=r.dataset.keyId,this.render()})}),e.querySelectorAll('[data-action="confirm-delete"]').forEach(r=>{r.addEventListener("click",()=>{this._deleteKey(r.dataset.keyId)})}),e.querySelectorAll('[data-action="cancel-delete"]').forEach(r=>{r.addEventListener("click",()=>{this._confirmDeleteId=null,this.render()})}),e.querySelectorAll('[data-action="rotate"]').forEach(r=>{r.addEventListener("click",()=>{this._rotateKeyId=r.dataset.keyId,this.render()})}),e.querySelectorAll('[data-action="confirm-rotate"]').forEach(r=>{r.addEventListener("click",()=>{let o=e.getElementById(`rotate-grace-${r.dataset.keyId}`);this._rotateGracePeriod=o?.value||"24",this._rotateKey(r.dataset.keyId)})}),e.querySelectorAll('[data-action="cancel-rotate"]').forEach(r=>{r.addEventListener("click",()=>{this._rotateKeyId=null,this.render()})})}};customElements.get("loki-api-keys")||customElements.define("loki-api-keys",_e);function ei(d){return d?d.slug&&d.name?`${d.name} (${d.slug})`:d.name||d.slug||"Unknown":"Unknown"}var ye=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._loading=!1,this._error=null,this._api=null,this._tenants=[],this._selectedTenantId=null,this._dropdownOpen=!1}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._outsideClickHandler=e=>{this._dropdownOpen&&!this.contains(e.target)&&(this._dropdownOpen=!1,this.render())},document.addEventListener("click",this._outsideClickHandler)}disconnectedCallback(){super.disconnectedCallback(),this._outsideClickHandler&&(document.removeEventListener("click",this._outsideClickHandler),this._outsideClickHandler=null)}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _loadData(){let e=this._api;try{this._loading=!0;let t=await e._get("/api/v2/tenants");if(e!==this._api)return;this._tenants=Array.isArray(t)?t:t?.tenants||[],this._error=null}catch(t){if(e!==this._api)return;this._error=`Failed to load tenants: ${t.message}`}finally{this._loading=!1}this.render()}_toggleDropdown(){this._dropdownOpen=!this._dropdownOpen,this.render()}_selectTenant(e,t){this._selectedTenantId=e,this._dropdownOpen=!1,this.render(),this.dispatchEvent(new CustomEvent("tenant-changed",{detail:{tenantId:e,tenantName:t},bubbles:!0,composed:!0}))}_getSelectedTenant(){return this._selectedTenantId==null?null:this._tenants.find(e=>(e.id||e.slug)===this._selectedTenantId)||null}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getStyles(){return`
13310
13316
  :host {
13311
13317
  display: inline-block;
13312
13318
  position: relative;
@@ -13440,7 +13446,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
13440
13446
  color: var(--loki-text-muted, #939084);
13441
13447
  font-size: 12px;
13442
13448
  }
13443
- `}render(){let e=this.shadowRoot;if(!e)return;let t=this._getSelectedTenant(),i=t?ni(t):"All Tenants",a=this._dropdownOpen,s="";if(a){let r;if(this._loading)r='<div class="loading-text">Loading tenants...</div>';else if(this._error)r=`<div class="error-text">${this._escapeHtml(this._error)}</div>`;else{let o=this._selectedTenantId==null;r=`
13449
+ `}render(){let e=this.shadowRoot;if(!e)return;let t=this._getSelectedTenant(),i=t?ei(t):"All Tenants",a=this._dropdownOpen,s="";if(a){let r;if(this._loading)r='<div class="loading-text">Loading tenants...</div>';else if(this._error)r=`<div class="error-text">${this._escapeHtml(this._error)}</div>`;else{let o=this._selectedTenantId==null;r=`
13444
13450
  <button class="dropdown-item all-tenants ${o?"selected":""}" data-tenant-id="">
13445
13451
  <span class="tenant-name">All Tenants</span>
13446
13452
  ${o?'<span class="check-mark">*</span>':""}
@@ -13465,12 +13471,12 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
13465
13471
  </button>
13466
13472
  ${s}
13467
13473
  </div>
13468
- `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.getElementById("trigger-btn");t&&t.addEventListener("click",i=>{i.stopPropagation(),this._toggleDropdown()}),e.querySelectorAll(".dropdown-item").forEach(i=>{i.addEventListener("click",a=>{a.stopPropagation();let s=i.dataset.tenantId||null,r=i.dataset.tenantName||null;this._selectTenant(s||null,r||"All Tenants")})})}};customElements.get("loki-tenant-switcher")||customElements.define("loki-tenant-switcher",we);var et={info:{color:"var(--loki-blue, #2F71E3)",label:"INFO",icon:"i"},success:{color:"var(--loki-green, #1FC5A8)",label:"OK",icon:"+"},warning:{color:"var(--loki-yellow, #D4A03C)",label:"WARN",icon:"!"},error:{color:"var(--loki-red, #C45B5B)",label:"ERR",icon:"x"}},li=100,$e=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._items=[],this._filter="all",this._api=null,this._pollInterval=null,this._paused=!1,this._lastTimestamp=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:3e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let t=await e._get("/api/v2/activity");if(e!==this._api)return;let i=t.events||t.activities||[];if(i.length>0){let a=i.filter(s=>!this._lastTimestamp||new Date(s.timestamp)>new Date(this._lastTimestamp)).map(s=>({id:s.id||crypto.randomUUID(),timestamp:s.timestamp||new Date().toISOString(),message:s.message||s.description||"",severity:s.severity||s.level||"info",source:s.source||s.component||"",isNew:!0}));a.length>0&&(this._items=[...a,...this._items].slice(0,li),this._lastTimestamp=a[0].timestamp,setTimeout(()=>{this._items.forEach(s=>s.isNew=!1)},600))}}catch{if(e!==this._api)return;this._items.length===0&&(this._items=this._getDemoItems())}this.render()}_getDemoItems(){let e=Date.now();return[{id:"1",timestamp:new Date(e-2e3).toISOString(),message:"Build iteration #12 started",severity:"info",source:"runner"},{id:"2",timestamp:new Date(e-5e3).toISOString(),message:"Code review passed (3/3 reviewers)",severity:"success",source:"review"},{id:"3",timestamp:new Date(e-8e3).toISOString(),message:"Context window at 78% capacity",severity:"warning",source:"context"},{id:"4",timestamp:new Date(e-12e3).toISOString(),message:"Test suite completed: 42/42 passed",severity:"success",source:"testing"},{id:"5",timestamp:new Date(e-15e3).toISOString(),message:"Verify step complete: changes checked",severity:"info",source:"rarv"}]}_formatTime(e){if(!e)return"";try{return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}catch{return""}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_getFilteredItems(){return this._filter==="all"?this._items:this._items.filter(e=>e.severity===this._filter)}_setFilter(e){this._filter=e,this.render()}_bindEvents(){let e=this.shadowRoot;e.querySelectorAll(".filter-btn").forEach(i=>{i.addEventListener("click",()=>{this._setFilter(i.dataset.filter)})});let t=e.querySelector(".activity-feed");t&&(t.addEventListener("mouseenter",()=>{this._paused=!0}),t.addEventListener("mouseleave",()=>{this._paused=!1}))}_getStyles(){return`
13474
+ `,this._attachEventListeners()}_attachEventListeners(){let e=this.shadowRoot;if(!e)return;let t=e.getElementById("trigger-btn");t&&t.addEventListener("click",i=>{i.stopPropagation(),this._toggleDropdown()}),e.querySelectorAll(".dropdown-item").forEach(i=>{i.addEventListener("click",a=>{a.stopPropagation();let s=i.dataset.tenantId||null,r=i.dataset.tenantName||null;this._selectTenant(s||null,r||"All Tenants")})})}};customElements.get("loki-tenant-switcher")||customElements.define("loki-tenant-switcher",ye);var Ye={planning:{color:"var(--loki-blue, #2F71E3)",label:"Planning"},building:{color:"var(--loki-green, #1FC5A8)",label:"Building"},implementation:{color:"var(--loki-green, #1FC5A8)",label:"Building"},testing:{color:"var(--loki-purple, #553DE9)",label:"Testing"},review:{color:"var(--loki-yellow, #D4A03C)",label:"Review"},overhead:{color:"var(--loki-text-muted, #939084)",label:"Overhead"}},we=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._phases=[],this._budget=null,this._totalCost=null,this._hoveredPhase=null,this._loadFailed=!1,this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:1e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let t=await e._get("/api/cost");if(e!==this._api)return;let i={phases:Object.entries(t.by_phase||{}).map(([a,s])=>({phase:a,cost_usd:s.cost_usd??null})),budget_usd:t.budget_limit,total_usd:t.estimated_cost_usd};if(this._phases=i.phases||[],this._budget=i.budget_usd||null,i.total_usd!=null)this._totalCost=i.total_usd;else{let a=this._phases.filter(s=>s.cost_usd!=null);this._totalCost=a.length?a.reduce((s,r)=>s+r.cost_usd,0):null}this._loadFailed=!1}catch{if(e!==this._api)return;this._loadFailed=!0}this.render()}_formatCost(e){return T(e)}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_bindEvents(){this.shadowRoot.querySelectorAll(".waterfall-bar").forEach(t=>{t.addEventListener("mouseenter",()=>{this._hoveredPhase=t.dataset.phase,this._updateTooltip(t)}),t.addEventListener("mouseleave",()=>{this._hoveredPhase=null,this._hideTooltip()})})}_updateTooltip(e){let t=this.shadowRoot.querySelector(".tooltip");if(!t)return;let i=this._phases.find(o=>o.phase===this._hoveredPhase);if(!i)return;let a=Ye[i.phase]||{label:i.phase};t.innerHTML=`<strong>${this._escapeHtml(a.label)}</strong>: ${this._formatCost(i.cost_usd)}`,t.style.display="block";let s=e.getBoundingClientRect(),r=this.shadowRoot.querySelector(".chart-area").getBoundingClientRect();t.style.left=s.left-r.left+s.width/2+"px",t.style.top=s.top-r.top-30+"px"}_hideTooltip(){let e=this.shadowRoot.querySelector(".tooltip");e&&(e.style.display="none")}_getStyles(){return`
13469
13475
  :host {
13470
13476
  display: block;
13471
13477
  }
13472
13478
 
13473
- .stream-container {
13479
+ .waterfall-container {
13474
13480
  font-family: var(--loki-font-family, 'Inter', -apple-system, sans-serif);
13475
13481
  color: var(--loki-text-primary, #201515);
13476
13482
  }
@@ -13479,7 +13485,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
13479
13485
  display: flex;
13480
13486
  align-items: center;
13481
13487
  justify-content: space-between;
13482
- margin-bottom: 12px;
13488
+ margin-bottom: 16px;
13483
13489
  }
13484
13490
 
13485
13491
  .title {
@@ -13488,139 +13494,157 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
13488
13494
  margin: 0;
13489
13495
  }
13490
13496
 
13491
- .filter-bar {
13492
- display: flex;
13493
- gap: 4px;
13494
- background: var(--loki-bg-tertiary, #ECEAE3);
13497
+ .total-cost {
13498
+ font-size: 14px;
13499
+ font-family: 'JetBrains Mono', monospace;
13500
+ font-weight: 600;
13501
+ color: var(--loki-accent, #553DE9);
13502
+ }
13503
+
13504
+ .chart-card {
13505
+ background: var(--loki-bg-card, #ffffff);
13506
+ border: 1px solid var(--loki-border, #ECEAE3);
13495
13507
  border-radius: 5px;
13496
- padding: 2px;
13508
+ padding: 20px;
13497
13509
  }
13498
13510
 
13499
- .filter-btn {
13500
- padding: 4px 10px;
13501
- border: none;
13502
- background: none;
13503
- color: var(--loki-text-muted, #939084);
13504
- cursor: pointer;
13505
- border-radius: 4px;
13506
- font-size: 11px;
13507
- font-weight: 500;
13508
- transition: all 0.2s;
13509
- font-family: inherit;
13510
- text-transform: uppercase;
13511
- letter-spacing: 0.03em;
13511
+ .chart-area {
13512
+ position: relative;
13513
+ display: flex;
13514
+ align-items: flex-end;
13515
+ gap: 8px;
13516
+ height: 200px;
13517
+ padding-bottom: 40px;
13518
+ border-bottom: 1px solid var(--loki-border, #ECEAE3);
13512
13519
  }
13513
13520
 
13514
- .filter-btn:hover {
13515
- color: var(--loki-text-secondary, #36342E);
13521
+ .bar-group {
13522
+ flex: 1;
13523
+ display: flex;
13524
+ flex-direction: column;
13525
+ align-items: center;
13526
+ height: 100%;
13527
+ justify-content: flex-end;
13528
+ position: relative;
13516
13529
  }
13517
13530
 
13518
- .filter-btn.active {
13519
- background: var(--loki-accent, #553DE9);
13520
- color: white;
13531
+ .waterfall-bar {
13532
+ width: 100%;
13533
+ max-width: 60px;
13534
+ border-radius: 4px 4px 0 0;
13535
+ transition: all 0.3s ease;
13536
+ cursor: pointer;
13537
+ min-height: 4px;
13538
+ position: relative;
13521
13539
  }
13522
13540
 
13523
- .activity-feed {
13524
- background: var(--loki-bg-card, #ffffff);
13525
- border: 1px solid var(--loki-border, #ECEAE3);
13526
- border-radius: 5px;
13527
- max-height: 400px;
13528
- overflow-y: auto;
13529
- overflow-x: hidden;
13541
+ .waterfall-bar:hover {
13542
+ opacity: 0.85;
13543
+ transform: scaleY(1.03);
13544
+ transform-origin: bottom;
13530
13545
  }
13531
13546
 
13532
- .activity-item {
13533
- display: flex;
13534
- align-items: stretch;
13535
- gap: 0;
13536
- border-bottom: 1px solid var(--loki-border, #ECEAE3);
13537
- transition: background 0.2s, opacity 0.3s;
13538
- animation: slideIn 0.3s ease-out;
13547
+ .bar-label {
13548
+ position: absolute;
13549
+ bottom: -32px;
13550
+ left: 50%;
13551
+ transform: translateX(-50%);
13552
+ font-size: 10px;
13553
+ font-weight: 600;
13554
+ color: var(--loki-text-muted, #939084);
13555
+ text-transform: uppercase;
13556
+ letter-spacing: 0.03em;
13557
+ white-space: nowrap;
13539
13558
  }
13540
13559
 
13541
- .activity-item:last-child {
13542
- border-bottom: none;
13560
+ .bar-value {
13561
+ position: absolute;
13562
+ top: -20px;
13563
+ left: 50%;
13564
+ transform: translateX(-50%);
13565
+ font-size: 11px;
13566
+ font-family: 'JetBrains Mono', monospace;
13567
+ color: var(--loki-text-secondary, #36342E);
13568
+ white-space: nowrap;
13543
13569
  }
13544
13570
 
13545
- .activity-item:hover {
13546
- background: var(--loki-bg-hover, #F3EFE9);
13571
+ .budget-line {
13572
+ position: absolute;
13573
+ left: 0;
13574
+ right: 0;
13575
+ border-top: 2px dashed var(--loki-red, #C45B5B);
13576
+ z-index: 1;
13547
13577
  }
13548
13578
 
13549
- .activity-item.new-item {
13550
- animation: slideInFromRight 0.4s ease-out;
13579
+ .budget-label {
13580
+ position: absolute;
13581
+ right: 0;
13582
+ top: -16px;
13583
+ font-size: 10px;
13584
+ font-family: 'JetBrains Mono', monospace;
13585
+ color: var(--loki-red, #C45B5B);
13586
+ font-weight: 600;
13551
13587
  }
13552
13588
 
13553
- @keyframes slideInFromRight {
13554
- from {
13555
- transform: translateX(30px);
13556
- opacity: 0;
13557
- }
13558
- to {
13559
- transform: translateX(0);
13560
- opacity: 1;
13561
- }
13589
+ .running-total-line {
13590
+ position: absolute;
13591
+ left: 0;
13592
+ right: 0;
13593
+ bottom: 40px;
13594
+ height: calc(100% - 40px);
13595
+ pointer-events: none;
13562
13596
  }
13563
13597
 
13564
- @keyframes slideIn {
13565
- from { opacity: 0; }
13566
- to { opacity: 1; }
13598
+ .running-total-line svg {
13599
+ width: 100%;
13600
+ height: 100%;
13567
13601
  }
13568
13602
 
13569
- .severity-band {
13570
- width: 4px;
13571
- flex-shrink: 0;
13603
+ .tooltip {
13604
+ display: none;
13605
+ position: absolute;
13606
+ background: var(--loki-bg-primary, #FFFEFB);
13607
+ border: 1px solid var(--loki-border, #ECEAE3);
13608
+ border-radius: 4px;
13609
+ padding: 6px 10px;
13610
+ font-size: 12px;
13611
+ box-shadow: var(--loki-shadow-md, 0 4px 6px rgba(32, 21, 21, 0.06));
13612
+ white-space: nowrap;
13613
+ z-index: 10;
13614
+ transform: translateX(-50%);
13615
+ pointer-events: none;
13572
13616
  }
13573
13617
 
13574
- .item-content {
13618
+ .summary-row {
13575
13619
  display: flex;
13576
- align-items: center;
13577
- gap: 10px;
13578
- padding: 10px 14px;
13579
- flex: 1;
13580
- min-width: 0;
13620
+ gap: 16px;
13621
+ margin-top: 16px;
13622
+ flex-wrap: wrap;
13581
13623
  }
13582
13624
 
13583
- .severity-icon {
13584
- width: 22px;
13585
- height: 22px;
13586
- border-radius: 4px;
13625
+ .summary-item {
13587
13626
  display: flex;
13588
13627
  align-items: center;
13589
- justify-content: center;
13590
- font-size: 11px;
13591
- font-weight: 700;
13592
- color: white;
13593
- flex-shrink: 0;
13594
- font-family: 'JetBrains Mono', monospace;
13628
+ gap: 6px;
13629
+ font-size: 12px;
13595
13630
  }
13596
13631
 
13597
- .item-time {
13598
- font-size: 11px;
13599
- font-family: 'JetBrains Mono', monospace;
13600
- color: var(--loki-text-muted, #939084);
13601
- white-space: nowrap;
13602
- min-width: 70px;
13632
+ .summary-dot {
13633
+ width: 10px;
13634
+ height: 10px;
13635
+ border-radius: 3px;
13636
+ flex-shrink: 0;
13603
13637
  }
13604
13638
 
13605
- .item-message {
13606
- flex: 1;
13607
- font-size: 13px;
13608
- color: var(--loki-text-primary, #201515);
13609
- line-height: 1.4;
13610
- overflow: hidden;
13611
- text-overflow: ellipsis;
13612
- white-space: nowrap;
13639
+ .summary-label {
13640
+ color: var(--loki-text-secondary, #36342E);
13641
+ font-weight: 500;
13613
13642
  }
13614
13643
 
13615
- .item-source {
13616
- font-size: 10px;
13644
+ .summary-value {
13617
13645
  font-family: 'JetBrains Mono', monospace;
13618
13646
  color: var(--loki-text-muted, #939084);
13619
- background: var(--loki-bg-tertiary, #ECEAE3);
13620
- padding: 2px 8px;
13621
- border-radius: 5px;
13622
- white-space: nowrap;
13623
- flex-shrink: 0;
13647
+ font-size: 11px;
13624
13648
  }
13625
13649
 
13626
13650
  .empty-state {
@@ -13629,1153 +13653,49 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
13629
13653
  color: var(--loki-text-muted, #939084);
13630
13654
  font-size: 13px;
13631
13655
  }
13632
-
13633
- .count-badge {
13634
- font-size: 11px;
13635
- font-family: 'JetBrains Mono', monospace;
13636
- color: var(--loki-text-muted, #939084);
13637
- margin-left: 4px;
13638
- }
13639
-
13640
- .pause-indicator {
13641
- font-size: 10px;
13642
- color: var(--loki-text-muted, #939084);
13643
- text-transform: uppercase;
13644
- letter-spacing: 0.05em;
13645
- padding: 2px 8px;
13646
- background: var(--loki-bg-tertiary, #ECEAE3);
13647
- border-radius: 4px;
13648
- }
13649
-
13650
- ::-webkit-scrollbar { width: 6px; }
13651
- ::-webkit-scrollbar-track { background: var(--loki-bg-primary, #FFFEFB); }
13652
- ::-webkit-scrollbar-thumb { background: var(--loki-border, #ECEAE3); border-radius: 3px; }
13653
- ::-webkit-scrollbar-thumb:hover { background: var(--loki-border-light, #C5C0B1); }
13654
- `}render(){let e=this.shadowRoot;if(!e)return;let t=this._getFilteredItems(),a=["all","info","success","warning","error"].map(r=>{let o=this._filter===r,n=r==="all"?"All":et[r]?.label||r;return`<button class="filter-btn ${o?"active":""}" data-filter="${r}">${n}</button>`}).join(""),s;if(t.length===0?s='<div class="empty-state">No activity yet. Updates will stream here as your build runs.</div>':s=t.map(r=>{let o=et[r.severity]||et.info;return`
13655
- <div class="activity-item ${r.isNew?"new-item":""}">
13656
- <div class="severity-band" style="background: ${o.color};"></div>
13657
- <div class="item-content">
13658
- <div class="severity-icon" style="background: ${o.color};">${o.icon}</div>
13659
- <span class="item-time">${this._formatTime(r.timestamp)}</span>
13660
- <span class="item-message">${this._escapeHtml(r.message)}</span>
13661
- ${r.source?`<span class="item-source">${this._escapeHtml(r.source)}</span>`:""}
13662
- </div>
13656
+ `}render(){let e=this.shadowRoot;if(!e)return;if(this._phases.length===0){let p=this._loadFailed?"Could not load the cost breakdown. Nothing is shown rather than a guess.":"Cost details will appear once a build starts running.";e.innerHTML=`
13657
+ <style>${this.getBaseStyles()}${this._getStyles()}</style>
13658
+ <div class="waterfall-container">
13659
+ <div class="header">
13660
+ <h3 class="title">Cost Breakdown</h3>
13663
13661
  </div>
13664
- `}).join(""),e.innerHTML=`
13665
- <style>${this.getBaseStyles()}${this._getStyles()}</style>
13666
- <div class="stream-container">
13667
- <div class="header">
13668
- <h3 class="title">Activity Stream <span class="count-badge">${this._items.length}</span></h3>
13669
- <div class="filter-bar">${a}</div>
13662
+ <div class="empty-state">${p}</div>
13670
13663
  </div>
13671
- <div class="activity-feed">
13672
- ${s}
13664
+ `;return}let t=this._phases.filter(p=>p.cost_usd!=null),i=Math.max(...t.map(p=>p.cost_usd),.01),a=this._totalCost!=null&&t.length<this._phases.length?" (partial)":"",s=160,r=this._budget?Math.max(i,this._budget):i,o=this._budget?this._budget/r*s:null,n=this._phases.map(p=>{let u=Ye[p.phase]||{color:"var(--loki-text-muted)",label:p.phase},m=this._hoveredPhase===p.phase,g=p.cost_usd==null,k=g?`height: 4px; border: 1px dashed ${u.color}; background: transparent;`:`height: ${Math.max(p.cost_usd/r*s,4)}px; background: ${u.color}; ${m?"opacity: 0.85;":""}`;return`
13665
+ <div class="bar-group">
13666
+ <span class="bar-value">${this._formatCost(p.cost_usd)}</span>
13667
+ <div class="waterfall-bar${g?" unmeasured":""}" data-phase="${this._escapeHtml(p.phase)}"
13668
+ style="${k}">
13669
+ </div>
13670
+ <span class="bar-label">${this._escapeHtml(u.label)}</span>
13673
13671
  </div>
13672
+ `}).join(""),l=o!=null?`
13673
+ <div class="budget-line" style="bottom: ${o+40}px;">
13674
+ <span class="budget-label">Budget: ${this._formatCost(this._budget)}</span>
13674
13675
  </div>
13675
- `,this._bindEvents(),!this._paused){let r=e.querySelector(".activity-feed");r&&(r.scrollTop=0)}}};customElements.get("loki-activity-stream")||customElements.define("loki-activity-stream",$e);var di={claude:{initial:"C",color:"#553DE9",bgColor:"rgba(85, 61, 233, 0.12)"},codex:{initial:"X",color:"#1FC5A8",bgColor:"rgba(31, 197, 168, 0.12)"},cline:{initial:"L",color:"#D4A03C",bgColor:"rgba(212, 160, 60, 0.12)"},aider:{initial:"A",color:"#C45B5B",bgColor:"rgba(196, 91, 91, 0.12)"}},St={healthy:"var(--loki-green, #1FC5A8)",degraded:"var(--loki-yellow, #D4A03C)",down:"var(--loki-red, #C45B5B)",unknown:"var(--loki-text-muted, #939084)"},Ee=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._providers=[],this._expandedProvider=null,this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:1e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let t=await e._get("/api/v2/providers/health");if(e!==this._api)return;this._providers=t.providers||[]}catch{if(e!==this._api)return;this._providers.length===0&&(this._providers=this._getDemoData())}this.render()}_getDemoData(){return[{name:"claude",status:"healthy",latency_ms:245,tokens_used:125400,model:"claude-opus-4-7",api_version:"v1",rate_limit:{remaining:45,limit:50},cost_usd:3.42},{name:"codex",status:"degraded",latency_ms:890,tokens_used:45200,model:"gpt-5.3-codex",api_version:"v1",rate_limit:{remaining:12,limit:60},cost_usd:.87},{name:"cline",status:"healthy",latency_ms:320,tokens_used:78600,model:"cline-default",api_version:"v1",rate_limit:{remaining:55,limit:60},cost_usd:1.15}]}_formatTokens(e){return Ne(e)}_formatLatency(e){return st(e)}_formatCost(e){return B(e)}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_toggleExpand(e){this._expandedProvider=this._expandedProvider===e?null:e,this.render()}_bindEvents(){this.shadowRoot.querySelectorAll(".provider-card").forEach(t=>{t.addEventListener("click",()=>{this._toggleExpand(t.dataset.provider)})})}_getStyles(){return`
13676
- :host {
13677
- display: block;
13678
- }
13679
-
13680
- .health-container {
13681
- font-family: var(--loki-font-family, 'Inter', -apple-system, sans-serif);
13682
- color: var(--loki-text-primary, #201515);
13683
- }
13684
-
13685
- .header {
13686
- display: flex;
13687
- align-items: center;
13688
- justify-content: space-between;
13689
- margin-bottom: 16px;
13690
- }
13691
-
13692
- .title {
13693
- font-size: 16px;
13694
- font-weight: 600;
13695
- margin: 0;
13696
- }
13697
-
13698
- .refresh-label {
13699
- font-size: 11px;
13700
- color: var(--loki-text-muted, #939084);
13701
- }
13702
-
13703
- .provider-grid {
13704
- display: grid;
13705
- grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
13706
- gap: 12px;
13707
- }
13708
-
13709
- .provider-card {
13710
- background: var(--loki-bg-card, #ffffff);
13711
- border: 1px solid var(--loki-border, #ECEAE3);
13712
- border-radius: 5px;
13713
- padding: 16px;
13714
- cursor: pointer;
13715
- transition: all 0.2s;
13716
- }
13717
-
13718
- .provider-card:hover {
13719
- border-color: var(--loki-border-light, #C5C0B1);
13720
- }
13721
-
13722
- .provider-card.expanded {
13723
- border-color: var(--loki-accent, #553DE9);
13724
- }
13725
-
13726
- .card-header {
13727
- display: flex;
13728
- align-items: center;
13729
- gap: 12px;
13730
- margin-bottom: 14px;
13731
- }
13732
-
13733
- .provider-icon {
13734
- width: 36px;
13735
- height: 36px;
13736
- border-radius: 50%;
13737
- display: flex;
13738
- align-items: center;
13739
- justify-content: center;
13740
- font-size: 15px;
13741
- font-weight: 700;
13742
- flex-shrink: 0;
13743
- }
13744
-
13745
- .provider-name {
13746
- font-size: 14px;
13747
- font-weight: 600;
13748
- text-transform: capitalize;
13749
- flex: 1;
13750
- }
13751
-
13752
- .status-dot {
13753
- width: 10px;
13754
- height: 10px;
13755
- border-radius: 50%;
13756
- flex-shrink: 0;
13757
- }
13758
-
13759
- .status-dot.pulse {
13760
- animation: statusPulse 2s infinite;
13761
- }
13762
-
13763
- @keyframes statusPulse {
13764
- 0%, 100% { opacity: 1; }
13765
- 50% { opacity: 0.5; }
13766
- }
13767
-
13768
- .card-metrics {
13769
- display: grid;
13770
- grid-template-columns: 1fr 1fr;
13771
- gap: 10px;
13772
- }
13773
-
13774
- .metric {
13775
- display: flex;
13776
- flex-direction: column;
13777
- gap: 2px;
13778
- }
13779
-
13780
- .metric-label {
13781
- font-size: 10px;
13782
- font-weight: 600;
13783
- text-transform: uppercase;
13784
- letter-spacing: 0.05em;
13785
- color: var(--loki-text-muted, #939084);
13786
- }
13787
-
13788
- .metric-value {
13789
- font-size: 15px;
13790
- font-weight: 600;
13791
- font-family: 'JetBrains Mono', monospace;
13792
- color: var(--loki-text-primary, #201515);
13793
- }
13794
-
13795
- .expand-details {
13796
- margin-top: 14px;
13797
- padding-top: 14px;
13798
- border-top: 1px solid var(--loki-border, #ECEAE3);
13799
- display: grid;
13800
- grid-template-columns: 1fr 1fr;
13801
- gap: 10px;
13802
- animation: expandIn 0.2s ease-out;
13803
- }
13804
-
13805
- @keyframes expandIn {
13806
- from { opacity: 0; max-height: 0; }
13807
- to { opacity: 1; max-height: 200px; }
13808
- }
13809
-
13810
- .detail-row {
13811
- display: flex;
13812
- flex-direction: column;
13813
- gap: 2px;
13814
- }
13815
-
13816
- .detail-label {
13817
- font-size: 10px;
13818
- font-weight: 600;
13819
- text-transform: uppercase;
13820
- letter-spacing: 0.05em;
13821
- color: var(--loki-text-muted, #939084);
13822
- }
13823
-
13824
- .detail-value {
13825
- font-size: 12px;
13826
- font-family: 'JetBrains Mono', monospace;
13827
- color: var(--loki-text-secondary, #36342E);
13828
- }
13829
-
13830
- .rate-limit-bar {
13831
- width: 100%;
13832
- height: 4px;
13833
- background: var(--loki-bg-tertiary, #ECEAE3);
13834
- border-radius: 2px;
13835
- overflow: hidden;
13836
- margin-top: 4px;
13837
- }
13838
-
13839
- .rate-limit-fill {
13840
- height: 100%;
13841
- border-radius: 2px;
13842
- transition: width 0.3s ease;
13843
- }
13844
-
13845
- .empty-state {
13846
- text-align: center;
13847
- padding: 32px 16px;
13848
- color: var(--loki-text-muted, #939084);
13849
- font-size: 13px;
13850
- background: var(--loki-bg-card, #ffffff);
13851
- border: 1px solid var(--loki-border, #ECEAE3);
13852
- border-radius: 5px;
13853
- }
13854
- `}render(){let e=this.shadowRoot;if(!e)return;let t;this._providers.length===0?t='<div class="empty-state">Provider status will appear once a build starts.</div>':t=`<div class="provider-grid">${this._providers.map(i=>{let a=di[i.name]||{initial:(i.name??"?").charAt(0).toUpperCase(),color:"#939084",bgColor:"rgba(147, 144, 132, 0.12)"},s=St[i.status]||St.unknown,r=this._expandedProvider===i.name,o=i.rate_limit?i.rate_limit.remaining/i.rate_limit.limit*100:100,n=o>50?"var(--loki-green)":o>20?"var(--loki-yellow)":"var(--loki-red)";return`
13855
- <div class="provider-card ${r?"expanded":""}" data-provider="${this._escapeHtml(i.name)}">
13856
- <div class="card-header">
13857
- <div class="provider-icon" style="background: ${a.bgColor}; color: ${a.color};">${a.initial}</div>
13858
- <span class="provider-name">${this._escapeHtml(i.name)}</span>
13859
- <div class="status-dot ${i.status==="healthy"?"pulse":""}" style="background: ${s};" title="${this._escapeHtml(i.status)}"></div>
13860
- </div>
13861
- <div class="card-metrics">
13862
- <div class="metric">
13863
- <span class="metric-label">Latency</span>
13864
- <span class="metric-value">${this._formatLatency(i.latency_ms)}</span>
13865
- </div>
13866
- <div class="metric">
13867
- <span class="metric-label">Tokens</span>
13868
- <span class="metric-value">${this._formatTokens(i.tokens_used)}</span>
13869
- </div>
13870
- </div>
13871
- ${r?`
13872
- <div class="expand-details">
13873
- <div class="detail-row">
13874
- <span class="detail-label">Model</span>
13875
- <span class="detail-value">${this._escapeHtml(i.model||"--")}</span>
13876
- </div>
13877
- <div class="detail-row">
13878
- <span class="detail-label">API Version</span>
13879
- <span class="detail-value">${this._escapeHtml(i.api_version||"--")}</span>
13880
- </div>
13881
- <div class="detail-row">
13882
- <span class="detail-label">Cost</span>
13883
- <span class="detail-value">${this._formatCost(i.cost_usd)}</span>
13884
- </div>
13885
- <div class="detail-row">
13886
- <span class="detail-label">Rate Limit</span>
13887
- <span class="detail-value">${i.rate_limit?i.rate_limit.remaining+"/"+i.rate_limit.limit:"--"}</span>
13888
- ${i.rate_limit?`
13889
- <div class="rate-limit-bar">
13890
- <div class="rate-limit-fill" style="width: ${o}%; background: ${n};"></div>
13891
- </div>
13892
- `:""}
13893
- </div>
13894
- </div>
13895
- `:""}
13896
- </div>
13897
- `}).join("")}</div>`,e.innerHTML=`
13898
- <style>${this.getBaseStyles()}${this._getStyles()}</style>
13899
- <div class="health-container">
13900
- <div class="header">
13901
- <h3 class="title">Provider Health</h3>
13902
- <span class="refresh-label">Auto-refresh: 10s</span>
13903
- </div>
13904
- ${t}
13905
- </div>
13906
- `,this._bindEvents()}};customElements.get("loki-provider-health")||customElements.define("loki-provider-health",Ee);var tt=[{id:"planning",label:"Planning",icon:"P"},{id:"scaffolding",label:"Scaffolding",icon:"S"},{id:"implementation",label:"Implementation",icon:"I"},{id:"testing",label:"Testing",icon:"T"},{id:"review",label:"Review",icon:"R"},{id:"deploy",label:"Deploy",icon:"D"}],it={waiting:{color:"var(--loki-text-muted, #939084)",bgColor:"var(--loki-bg-tertiary, #ECEAE3)",label:"Waiting"},active:{color:"var(--loki-accent, #553DE9)",bgColor:"var(--loki-accent-muted, rgba(85, 61, 233, 0.10))",label:"Active"},complete:{color:"var(--loki-green, #1FC5A8)",bgColor:"var(--loki-green-muted, rgba(31, 197, 168, 0.12))",label:"Complete"},failed:{color:"var(--loki-red, #C45B5B)",bgColor:"var(--loki-red-muted, rgba(196, 91, 91, 0.12))",label:"Failed"}},Ce=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._stages=[],this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:5e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let t=await e._get("/api/v2/pipeline/status");if(e!==this._api)return;this._stages=t.stages||[]}catch{if(e!==this._api)return;this._stages.length===0&&(this._stages=this._getDemoData())}this.render()}_getDemoData(){return[{id:"planning",status:"complete",errors:0,duration_ms:12500},{id:"scaffolding",status:"complete",errors:0,duration_ms:8300},{id:"implementation",status:"active",errors:0,duration_ms:45e3},{id:"testing",status:"waiting",errors:0,duration_ms:null},{id:"review",status:"waiting",errors:0,duration_ms:null},{id:"deploy",status:"waiting",errors:0,duration_ms:null}]}_getStageData(e){return this._stages.find(t=>t.id===e)||{id:e,status:"waiting",errors:0}}_formatDuration(e){if(e==null||e<0)return"";if(e<1e3)return e+"ms";let t=Math.floor(e/1e3);if(t<60)return t+"s";let i=Math.floor(t/60),a=t%60;return i+"m "+a+"s"}_getStyles(){return`
13907
- :host {
13908
- display: block;
13909
- }
13910
-
13911
- .pipeline-container {
13912
- font-family: var(--loki-font-family, 'Inter', -apple-system, sans-serif);
13913
- color: var(--loki-text-primary, #201515);
13914
- }
13915
-
13916
- .header {
13917
- display: flex;
13918
- align-items: center;
13919
- justify-content: space-between;
13920
- margin-bottom: 16px;
13921
- }
13922
-
13923
- .title {
13924
- font-size: 16px;
13925
- font-weight: 600;
13926
- margin: 0;
13927
- }
13928
-
13929
- .pipeline-track {
13930
- display: flex;
13931
- align-items: center;
13932
- gap: 0;
13933
- padding: 20px 12px;
13934
- background: var(--loki-bg-card, #ffffff);
13935
- border: 1px solid var(--loki-border, #ECEAE3);
13936
- border-radius: 5px;
13937
- overflow-x: auto;
13938
- }
13939
-
13940
- .stage-node {
13941
- display: flex;
13942
- flex-direction: column;
13943
- align-items: center;
13944
- gap: 8px;
13945
- min-width: 90px;
13946
- flex-shrink: 0;
13947
- }
13948
-
13949
- .stage-circle {
13950
- width: 48px;
13951
- height: 48px;
13952
- border-radius: 50%;
13953
- display: flex;
13954
- align-items: center;
13955
- justify-content: center;
13956
- font-size: 16px;
13957
- font-weight: 700;
13958
- transition: all 0.3s;
13959
- position: relative;
13960
- }
13961
-
13962
- .stage-circle.active {
13963
- animation: stagePulse 2s ease-in-out infinite;
13964
- }
13965
-
13966
- @keyframes stagePulse {
13967
- 0%, 100% { box-shadow: 0 0 0 0 rgba(85, 61, 233, 0.3); }
13968
- 50% { box-shadow: 0 0 0 10px rgba(85, 61, 233, 0); }
13969
- }
13970
-
13971
- .stage-check {
13972
- font-size: 18px;
13973
- line-height: 1;
13974
- }
13975
-
13976
- .stage-label {
13977
- font-size: 11px;
13978
- font-weight: 600;
13979
- color: var(--loki-text-secondary, #36342E);
13980
- text-align: center;
13981
- max-width: 90px;
13982
- }
13983
-
13984
- .stage-duration {
13985
- font-size: 10px;
13986
- font-family: 'JetBrains Mono', monospace;
13987
- color: var(--loki-text-muted, #939084);
13988
- }
13989
-
13990
- .stage-error-count {
13991
- font-size: 10px;
13992
- font-weight: 600;
13993
- color: var(--loki-red, #C45B5B);
13994
- background: var(--loki-red-muted, rgba(196, 91, 91, 0.12));
13995
- padding: 1px 6px;
13996
- border-radius: 4px;
13997
- }
13998
-
13999
- .connector {
14000
- flex: 1;
14001
- height: 3px;
14002
- min-width: 24px;
14003
- position: relative;
14004
- overflow: hidden;
14005
- margin: 0 -2px;
14006
- align-self: center;
14007
- margin-bottom: 36px;
14008
- }
14009
-
14010
- .connector-line {
14011
- position: absolute;
14012
- top: 0;
14013
- left: 0;
14014
- right: 0;
14015
- bottom: 0;
14016
- border-radius: 2px;
14017
- }
14018
-
14019
- .connector-line.completed {
14020
- background: var(--loki-green, #1FC5A8);
14021
- }
14022
-
14023
- .connector-line.pending {
14024
- background: var(--loki-border, #ECEAE3);
14025
- }
14026
-
14027
- .connector-line.active {
14028
- background: var(--loki-border, #ECEAE3);
14029
- }
14030
-
14031
- .flow-dot {
14032
- position: absolute;
14033
- top: -1px;
14034
- width: 5px;
14035
- height: 5px;
14036
- border-radius: 50%;
14037
- background: var(--loki-accent, #553DE9);
14038
- animation: flowDot 1.5s linear infinite;
14039
- }
14040
-
14041
- @keyframes flowDot {
14042
- 0% { left: 0; opacity: 0; }
14043
- 10% { opacity: 1; }
14044
- 90% { opacity: 1; }
14045
- 100% { left: 100%; opacity: 0; }
14046
- }
14047
-
14048
- .status-legend {
14049
- display: flex;
14050
- gap: 16px;
14051
- margin-top: 14px;
14052
- flex-wrap: wrap;
14053
- }
14054
-
14055
- .legend-item {
14056
- display: flex;
14057
- align-items: center;
14058
- gap: 6px;
14059
- font-size: 11px;
14060
- color: var(--loki-text-muted, #939084);
14061
- }
14062
-
14063
- .legend-dot {
14064
- width: 8px;
14065
- height: 8px;
14066
- border-radius: 50%;
14067
- flex-shrink: 0;
14068
- }
14069
- `}render(){let e=this.shadowRoot;if(!e)return;let t=tt.map((a,s)=>{let r=this._getStageData(a.id),o=it[r.status]||it.waiting,n=r.status==="complete",l=r.status==="active",c=r.status==="failed",p=n?'<span class="stage-check">&#10003;</span>':c?'<span class="stage-check">&#10007;</span>':a.icon,u=`
14070
- <div class="stage-node">
14071
- <div class="stage-circle ${l?"active":""}"
14072
- style="background: ${o.bgColor}; color: ${o.color}; border: 2px solid ${o.color};">
14073
- ${p}
14074
- </div>
14075
- <span class="stage-label">${a.label}</span>
14076
- ${r.duration_ms?`<span class="stage-duration">${this._formatDuration(r.duration_ms)}</span>`:""}
14077
- ${r.errors>0?`<span class="stage-error-count">${r.errors} error${r.errors>1?"s":""}</span>`:""}
14078
- </div>
14079
- `;if(s<tt.length-1){let m=this._getStageData(tt[s+1].id),g=n,x=l||n&&(m.status==="active"||m.status==="waiting");return u+`
14080
- <div class="connector">
14081
- <div class="connector-line ${g?"completed":l?"active":"pending"}"></div>
14082
- ${l?'<div class="flow-dot"></div>':""}
14083
- </div>
14084
- `}return u}).join(""),i=Object.entries(it).map(([a,s])=>`<div class="legend-item">
14085
- <div class="legend-dot" style="background: ${s.color};"></div>
14086
- <span>${s.label}</span>
14087
- </div>`).join("");e.innerHTML=`
14088
- <style>${this.getBaseStyles()}${this._getStyles()}</style>
14089
- <div class="pipeline-container">
14090
- <div class="header">
14091
- <h3 class="title">Build Pipeline</h3>
14092
- </div>
14093
- <div class="pipeline-track">
14094
- ${t}
14095
- </div>
14096
- <div class="status-legend">
14097
- ${i}
14098
- </div>
14099
- </div>
14100
- `}};customElements.get("loki-pipeline-view")||customElements.define("loki-pipeline-view",Ce);var Se={episode:{color:"var(--loki-blue, #2F71E3)",shape:"circle",label:"Episode"},pattern:{color:"var(--loki-green, #1FC5A8)",shape:"square",label:"Pattern"},skill:{color:"var(--loki-purple, #553DE9)",shape:"diamond",label:"Skill"}};function ci(d,e,t){let i=e/2,a=t/2,s=Math.min(i,a)*.65,r=d.length;return d.map((o,n)=>{let l=2*Math.PI*n/r-Math.PI/2,c=o.importance||.5,p=s*(.5+c*.5);return{...o,x:i+p*Math.cos(l),y:a+p*Math.sin(l)}})}var Ae=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._nodes=[],this._edges=[],this._selectedNode=null,this._api=null,this._pollInterval=null,this._graphWidth=600,this._graphHeight=400}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:15e3,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let t=await e._get("/api/v2/memory/graph");if(e!==this._api)return;this._nodes=t.nodes||[],this._edges=t.edges||[]}catch{if(e!==this._api)return;if(this._nodes.length===0){let t=this._getDemoData();this._nodes=t.nodes,this._edges=t.edges}}this.render()}_getDemoData(){return{nodes:[{id:"ep1",type:"episode",label:"Build iteration #12",importance:.8,details:"Completed scaffolding and initial implementation"},{id:"ep2",type:"episode",label:"Code review #5",importance:.6,details:"Quality gate passed with 3/3 approval"},{id:"ep3",type:"episode",label:"Test failure #3",importance:.7,details:"Integration test timeout resolved"},{id:"pt1",type:"pattern",label:"Error recovery",importance:.9,details:"Retry with exponential backoff pattern"},{id:"pt2",type:"pattern",label:"API design",importance:.7,details:"REST endpoint naming conventions"},{id:"pt3",type:"pattern",label:"Test structure",importance:.5,details:"Arrange-Act-Assert with setup helpers"},{id:"sk1",type:"skill",label:"Playwright E2E",importance:.85,details:"Browser automation test writing"},{id:"sk2",type:"skill",label:"FastAPI routing",importance:.6,details:"Python API server development"}],edges:[{source:"ep1",target:"pt1",strength:.8},{source:"ep1",target:"sk1",strength:.6},{source:"ep2",target:"pt2",strength:.9},{source:"ep3",target:"pt1",strength:.7},{source:"ep3",target:"pt3",strength:.5},{source:"pt1",target:"sk2",strength:.4},{source:"pt2",target:"sk2",strength:.7},{source:"pt3",target:"sk1",strength:.6}]}}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_selectNode(e){this._selectedNode=this._selectedNode===e?null:e,this.render()}_bindEvents(){let e=this.shadowRoot;e.querySelectorAll(".graph-node").forEach(t=>{t.addEventListener("click",()=>{this._selectNode(t.dataset.nodeId)})}),e.querySelectorAll(".close-detail").forEach(t=>{t.addEventListener("click",()=>{this._selectedNode=null,this.render()})})}_renderNodeShape(e,t,i){let a=Se[e.type]||Se.episode,s=10+(e.importance||.5)*16,r=this._selectedNode===e.id,o=r?"var(--loki-accent, #553DE9)":a.color,n=r?3:1.5,l=this._selectedNode&&!r?.4:1,c;switch(a.shape){case"square":c=`<rect x="${t-s/2}" y="${i-s/2}" width="${s}" height="${s}"
14101
- rx="3" fill="${a.color}" fill-opacity="0.2" stroke="${o}" stroke-width="${n}" opacity="${l}" />`;break;case"diamond":{let u=s/2;c=`<polygon points="${t},${i-u} ${t+u},${i} ${t},${i+u} ${t-u},${i}"
14102
- fill="${a.color}" fill-opacity="0.2" stroke="${o}" stroke-width="${n}" opacity="${l}" />`;break}default:c=`<circle cx="${t}" cy="${i}" r="${s/2}" fill="${a.color}" fill-opacity="0.2"
14103
- stroke="${o}" stroke-width="${n}" opacity="${l}" />`}let p=`<text x="${t}" y="${i+s/2+14}" text-anchor="middle" font-size="10"
14104
- font-family="Inter, sans-serif" fill="var(--loki-text-secondary, #36342E)" opacity="${l}">${this._escapeHtml(e.label)}</text>`;return`<g class="graph-node" data-node-id="${this._escapeHtml(e.id)}" style="cursor: pointer;">
14105
- ${c}${p}
14106
- </g>`}_renderEdge(e,t){let i=t.find(n=>n.id===e.source),a=t.find(n=>n.id===e.target);if(!i||!a)return"";let s=(e.strength||1)<.6,r=this._selectedNode?e.source===this._selectedNode||e.target===this._selectedNode?.8:.15:.4,o=s?'stroke-dasharray="4 4"':"";return`<line x1="${i.x}" y1="${i.y}" x2="${a.x}" y2="${a.y}"
14107
- stroke="var(--loki-border-light, #C5C0B1)" stroke-width="1.5" opacity="${r}" ${o} />`}_getStyles(){return`
14108
- :host {
14109
- display: block;
14110
- }
14111
-
14112
- .graph-container {
14113
- font-family: var(--loki-font-family, 'Inter', -apple-system, sans-serif);
14114
- color: var(--loki-text-primary, #201515);
14115
- }
14116
-
14117
- .header {
14118
- display: flex;
14119
- align-items: center;
14120
- justify-content: space-between;
14121
- margin-bottom: 12px;
14122
- }
14123
-
14124
- .title {
14125
- font-size: 16px;
14126
- font-weight: 600;
14127
- margin: 0;
14128
- }
14129
-
14130
- .graph-wrap {
14131
- background: var(--loki-bg-card, #ffffff);
14132
- border: 1px solid var(--loki-border, #ECEAE3);
14133
- border-radius: 5px;
14134
- overflow: hidden;
14135
- position: relative;
14136
- }
14137
-
14138
- .graph-svg {
14139
- display: block;
14140
- width: 100%;
14141
- height: 400px;
14142
- }
14143
-
14144
- .legend {
14145
- display: flex;
14146
- gap: 16px;
14147
- margin-top: 12px;
14148
- flex-wrap: wrap;
14149
- }
14150
-
14151
- .legend-item {
14152
- display: flex;
14153
- align-items: center;
14154
- gap: 6px;
14155
- font-size: 11px;
14156
- color: var(--loki-text-muted, #939084);
14157
- }
14158
-
14159
- .legend-shape {
14160
- width: 14px;
14161
- height: 14px;
14162
- display: flex;
14163
- align-items: center;
14164
- justify-content: center;
14165
- }
14166
-
14167
- .legend-circle {
14168
- width: 12px;
14169
- height: 12px;
14170
- border-radius: 50%;
14171
- border: 2px solid;
14172
- }
14173
-
14174
- .legend-square {
14175
- width: 12px;
14176
- height: 12px;
14177
- border-radius: 2px;
14178
- border: 2px solid;
14179
- }
14180
-
14181
- .legend-diamond {
14182
- width: 10px;
14183
- height: 10px;
14184
- border: 2px solid;
14185
- transform: rotate(45deg);
14186
- }
14187
-
14188
- .detail-panel {
14189
- position: absolute;
14190
- bottom: 12px;
14191
- left: 12px;
14192
- right: 12px;
14193
- background: var(--loki-bg-card, #ffffff);
14194
- border: 1px solid var(--loki-border, #ECEAE3);
14195
- border-radius: 5px;
14196
- padding: 14px;
14197
- box-shadow: var(--loki-shadow-md, 0 4px 6px rgba(32, 21, 21, 0.06));
14198
- animation: slideUp 0.2s ease-out;
14199
- }
14200
-
14201
- @keyframes slideUp {
14202
- from { transform: translateY(10px); opacity: 0; }
14203
- to { transform: translateY(0); opacity: 1; }
14204
- }
14205
-
14206
- .detail-header {
14207
- display: flex;
14208
- align-items: center;
14209
- justify-content: space-between;
14210
- margin-bottom: 8px;
14211
- }
14212
-
14213
- .detail-title {
14214
- font-size: 14px;
14215
- font-weight: 600;
14216
- }
14217
-
14218
- .detail-type {
14219
- font-size: 10px;
14220
- font-weight: 600;
14221
- text-transform: uppercase;
14222
- letter-spacing: 0.05em;
14223
- padding: 2px 8px;
14224
- border-radius: 4px;
14225
- }
14226
-
14227
- .close-detail {
14228
- background: none;
14229
- border: none;
14230
- font-size: 16px;
14231
- color: var(--loki-text-muted, #939084);
14232
- cursor: pointer;
14233
- padding: 0 4px;
14234
- font-family: inherit;
14235
- }
14236
-
14237
- .close-detail:hover {
14238
- color: var(--loki-text-primary, #201515);
14239
- }
14240
-
14241
- .detail-body {
14242
- font-size: 13px;
14243
- color: var(--loki-text-secondary, #36342E);
14244
- line-height: 1.5;
14245
- }
14246
-
14247
- .empty-state {
14248
- text-align: center;
14249
- padding: 32px 16px;
14250
- color: var(--loki-text-muted, #939084);
14251
- font-size: 13px;
14252
- }
14253
- `}render(){let e=this.shadowRoot;if(!e)return;if(this._nodes.length===0){e.innerHTML=`
14254
- <style>${this.getBaseStyles()}${this._getStyles()}</style>
14255
- <div class="graph-container">
14256
- <div class="header">
14257
- <h3 class="title">Memory Network</h3>
14258
- </div>
14259
- <div class="empty-state">No memory entries to visualize</div>
14260
- </div>
14261
- `;return}let t=this._graphWidth,i=this._graphHeight,a=ci(this._nodes,t,i),s=this._edges.map(l=>this._renderEdge(l,a)).join(""),r=a.map(l=>this._renderNodeShape(l,l.x,l.y)).join(""),o="";if(this._selectedNode){let l=this._nodes.find(c=>c.id===this._selectedNode);if(l){let c=Se[l.type]||Se.episode;o=`
14262
- <div class="detail-panel">
14263
- <div class="detail-header">
14264
- <span class="detail-title">${this._escapeHtml(l.label)}</span>
14265
- <span class="detail-type" style="background: ${c.color}; color: white;">${c.label}</span>
14266
- <button class="close-detail" title="Close">&#10005;</button>
14267
- </div>
14268
- <div class="detail-body">${this._escapeHtml(l.details||"No details available")}</div>
14269
- </div>
14270
- `}}let n=Object.entries(Se).map(([,l])=>{let c;return l.shape==="circle"?c=`<div class="legend-circle" style="border-color: ${l.color};"></div>`:l.shape==="square"?c=`<div class="legend-square" style="border-color: ${l.color};"></div>`:c=`<div class="legend-diamond" style="border-color: ${l.color};"></div>`,`<div class="legend-item">
14271
- <div class="legend-shape">${c}</div>
14272
- <span>${l.label}</span>
14273
- </div>`}).join("");e.innerHTML=`
14274
- <style>${this.getBaseStyles()}${this._getStyles()}</style>
14275
- <div class="graph-container">
14276
- <div class="header">
14277
- <h3 class="title">Memory Network</h3>
14278
- </div>
14279
- <div class="graph-wrap">
14280
- <svg class="graph-svg" viewBox="0 0 ${t} ${i}" xmlns="http://www.w3.org/2000/svg">
14281
- ${s}
14282
- ${r}
14283
- </svg>
14284
- ${o}
14285
- </div>
14286
- <div class="legend">${n}</div>
14287
- </div>
14288
- `,this._bindEvents()}};customElements.get("loki-memory-graph")||customElements.define("loki-memory-graph",Ae);var at={planning:{color:"var(--loki-blue, #2F71E3)",label:"Planning"},building:{color:"var(--loki-green, #1FC5A8)",label:"Building"},implementation:{color:"var(--loki-green, #1FC5A8)",label:"Building"},testing:{color:"var(--loki-purple, #553DE9)",label:"Testing"},review:{color:"var(--loki-yellow, #D4A03C)",label:"Review"},overhead:{color:"var(--loki-text-muted, #939084)",label:"Overhead"}},Te=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._phases=[],this._budget=null,this._totalCost=null,this._hoveredPhase=null,this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:1e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let t=await e._get("/api/v2/cost/breakdown");if(e!==this._api)return;if(this._phases=t.phases||[],this._budget=t.budget_usd||null,t.total_usd!=null)this._totalCost=t.total_usd;else{let i=this._phases.filter(a=>a.cost_usd!=null);this._totalCost=i.length?i.reduce((a,s)=>a+s.cost_usd,0):null}}catch{if(e!==this._api)return;this._phases.length===0&&(this._phases=this._getDemoData(),this._budget=10,this._totalCost=this._phases.reduce((t,i)=>t+i.cost_usd,0))}this.render()}_getDemoData(){return[{phase:"planning",cost_usd:.85,tokens:12400},{phase:"building",cost_usd:3.2,tokens:68500},{phase:"testing",cost_usd:1.45,tokens:31200},{phase:"review",cost_usd:.9,tokens:18800},{phase:"overhead",cost_usd:.35,tokens:5600}]}_formatCost(e){return B(e)}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_bindEvents(){this.shadowRoot.querySelectorAll(".waterfall-bar").forEach(t=>{t.addEventListener("mouseenter",()=>{this._hoveredPhase=t.dataset.phase,this._updateTooltip(t)}),t.addEventListener("mouseleave",()=>{this._hoveredPhase=null,this._hideTooltip()})})}_updateTooltip(e){let t=this.shadowRoot.querySelector(".tooltip");if(!t)return;let i=this._phases.find(o=>o.phase===this._hoveredPhase);if(!i)return;let a=at[i.phase]||{label:i.phase};t.innerHTML=`<strong>${this._escapeHtml(a.label)}</strong>: ${this._formatCost(i.cost_usd)}`,t.style.display="block";let s=e.getBoundingClientRect(),r=this.shadowRoot.querySelector(".chart-area").getBoundingClientRect();t.style.left=s.left-r.left+s.width/2+"px",t.style.top=s.top-r.top-30+"px"}_hideTooltip(){let e=this.shadowRoot.querySelector(".tooltip");e&&(e.style.display="none")}_getStyles(){return`
14289
- :host {
14290
- display: block;
14291
- }
14292
-
14293
- .waterfall-container {
14294
- font-family: var(--loki-font-family, 'Inter', -apple-system, sans-serif);
14295
- color: var(--loki-text-primary, #201515);
14296
- }
14297
-
14298
- .header {
14299
- display: flex;
14300
- align-items: center;
14301
- justify-content: space-between;
14302
- margin-bottom: 16px;
14303
- }
14304
-
14305
- .title {
14306
- font-size: 16px;
14307
- font-weight: 600;
14308
- margin: 0;
14309
- }
14310
-
14311
- .total-cost {
14312
- font-size: 14px;
14313
- font-family: 'JetBrains Mono', monospace;
14314
- font-weight: 600;
14315
- color: var(--loki-accent, #553DE9);
14316
- }
14317
-
14318
- .chart-card {
14319
- background: var(--loki-bg-card, #ffffff);
14320
- border: 1px solid var(--loki-border, #ECEAE3);
14321
- border-radius: 5px;
14322
- padding: 20px;
14323
- }
14324
-
14325
- .chart-area {
14326
- position: relative;
14327
- display: flex;
14328
- align-items: flex-end;
14329
- gap: 8px;
14330
- height: 200px;
14331
- padding-bottom: 40px;
14332
- border-bottom: 1px solid var(--loki-border, #ECEAE3);
14333
- }
14334
-
14335
- .bar-group {
14336
- flex: 1;
14337
- display: flex;
14338
- flex-direction: column;
14339
- align-items: center;
14340
- height: 100%;
14341
- justify-content: flex-end;
14342
- position: relative;
14343
- }
14344
-
14345
- .waterfall-bar {
14346
- width: 100%;
14347
- max-width: 60px;
14348
- border-radius: 4px 4px 0 0;
14349
- transition: all 0.3s ease;
14350
- cursor: pointer;
14351
- min-height: 4px;
14352
- position: relative;
14353
- }
14354
-
14355
- .waterfall-bar:hover {
14356
- opacity: 0.85;
14357
- transform: scaleY(1.03);
14358
- transform-origin: bottom;
14359
- }
14360
-
14361
- .bar-label {
14362
- position: absolute;
14363
- bottom: -32px;
14364
- left: 50%;
14365
- transform: translateX(-50%);
14366
- font-size: 10px;
14367
- font-weight: 600;
14368
- color: var(--loki-text-muted, #939084);
14369
- text-transform: uppercase;
14370
- letter-spacing: 0.03em;
14371
- white-space: nowrap;
14372
- }
14373
-
14374
- .bar-value {
14375
- position: absolute;
14376
- top: -20px;
14377
- left: 50%;
14378
- transform: translateX(-50%);
14379
- font-size: 11px;
14380
- font-family: 'JetBrains Mono', monospace;
14381
- color: var(--loki-text-secondary, #36342E);
14382
- white-space: nowrap;
14383
- }
14384
-
14385
- .budget-line {
14386
- position: absolute;
14387
- left: 0;
14388
- right: 0;
14389
- border-top: 2px dashed var(--loki-red, #C45B5B);
14390
- z-index: 1;
14391
- }
14392
-
14393
- .budget-label {
14394
- position: absolute;
14395
- right: 0;
14396
- top: -16px;
14397
- font-size: 10px;
14398
- font-family: 'JetBrains Mono', monospace;
14399
- color: var(--loki-red, #C45B5B);
14400
- font-weight: 600;
14401
- }
14402
-
14403
- .running-total-line {
14404
- position: absolute;
14405
- left: 0;
14406
- right: 0;
14407
- bottom: 40px;
14408
- height: calc(100% - 40px);
14409
- pointer-events: none;
14410
- }
14411
-
14412
- .running-total-line svg {
14413
- width: 100%;
14414
- height: 100%;
14415
- }
14416
-
14417
- .tooltip {
14418
- display: none;
14419
- position: absolute;
14420
- background: var(--loki-bg-primary, #FFFEFB);
14421
- border: 1px solid var(--loki-border, #ECEAE3);
14422
- border-radius: 4px;
14423
- padding: 6px 10px;
14424
- font-size: 12px;
14425
- box-shadow: var(--loki-shadow-md, 0 4px 6px rgba(32, 21, 21, 0.06));
14426
- white-space: nowrap;
14427
- z-index: 10;
14428
- transform: translateX(-50%);
14429
- pointer-events: none;
14430
- }
14431
-
14432
- .summary-row {
14433
- display: flex;
14434
- gap: 16px;
14435
- margin-top: 16px;
14436
- flex-wrap: wrap;
14437
- }
14438
-
14439
- .summary-item {
14440
- display: flex;
14441
- align-items: center;
14442
- gap: 6px;
14443
- font-size: 12px;
14444
- }
14445
-
14446
- .summary-dot {
14447
- width: 10px;
14448
- height: 10px;
14449
- border-radius: 3px;
14450
- flex-shrink: 0;
14451
- }
14452
-
14453
- .summary-label {
14454
- color: var(--loki-text-secondary, #36342E);
14455
- font-weight: 500;
14456
- }
14457
-
14458
- .summary-value {
14459
- font-family: 'JetBrains Mono', monospace;
14460
- color: var(--loki-text-muted, #939084);
14461
- font-size: 11px;
14462
- }
14463
-
14464
- .empty-state {
14465
- text-align: center;
14466
- padding: 32px 16px;
14467
- color: var(--loki-text-muted, #939084);
14468
- font-size: 13px;
14469
- }
14470
- `}render(){let e=this.shadowRoot;if(!e)return;if(this._phases.length===0){e.innerHTML=`
14471
- <style>${this.getBaseStyles()}${this._getStyles()}</style>
14472
- <div class="waterfall-container">
14473
- <div class="header">
14474
- <h3 class="title">Cost Breakdown</h3>
14475
- </div>
14476
- <div class="empty-state">Cost details will appear once a build starts running.</div>
14477
- </div>
14478
- `;return}let t=Math.max(...this._phases.map(l=>l.cost_usd||0),.01),i=160,a=this._budget?Math.max(t,this._budget):t,s=this._budget?this._budget/a*i:null,r=this._phases.map(l=>{let c=at[l.phase]||{color:"var(--loki-text-muted)",label:l.phase},p=(l.cost_usd||0)/a*i,u=this._hoveredPhase===l.phase;return`
14479
- <div class="bar-group">
14480
- <span class="bar-value">${this._formatCost(l.cost_usd)}</span>
14481
- <div class="waterfall-bar" data-phase="${this._escapeHtml(l.phase)}"
14482
- style="height: ${Math.max(p,4)}px; background: ${c.color}; ${u?"opacity: 0.85;":""}">
14483
- </div>
14484
- <span class="bar-label">${this._escapeHtml(c.label)}</span>
14485
- </div>
14486
- `}).join(""),o=s!=null?`
14487
- <div class="budget-line" style="bottom: ${s+40}px;">
14488
- <span class="budget-label">Budget: ${this._formatCost(this._budget)}</span>
14489
- </div>
14490
- `:"",n=this._phases.map(l=>{let c=at[l.phase]||{color:"var(--loki-text-muted)",label:l.phase},p=this._totalCost>0?(l.cost_usd/this._totalCost*100).toFixed(0):0;return`<div class="summary-item">
14491
- <div class="summary-dot" style="background: ${c.color};"></div>
14492
- <span class="summary-label">${this._escapeHtml(c.label)}</span>
14493
- <span class="summary-value">${this._formatCost(l.cost_usd)} (${p}%)</span>
13676
+ `:"",c=this._phases.map(p=>{let u=Ye[p.phase]||{color:"var(--loki-text-muted)",label:p.phase},m=p.cost_usd!=null&&this._totalCost>0?` (${(p.cost_usd/this._totalCost*100).toFixed(0)}%)`:"";return`<div class="summary-item">
13677
+ <div class="summary-dot" style="background: ${u.color};"></div>
13678
+ <span class="summary-label">${this._escapeHtml(u.label)}</span>
13679
+ <span class="summary-value">${this._formatCost(p.cost_usd)}${m}</span>
14494
13680
  </div>`}).join("");e.innerHTML=`
14495
13681
  <style>${this.getBaseStyles()}${this._getStyles()}</style>
14496
13682
  <div class="waterfall-container">
14497
13683
  <div class="header">
14498
13684
  <h3 class="title">Cost Breakdown</h3>
14499
- <span class="total-cost">Total: ${this._formatCost(this._totalCost)}</span>
13685
+ <span class="total-cost">Total: ${this._formatCost(this._totalCost)}${a}</span>
14500
13686
  </div>
14501
13687
  <div class="chart-card">
14502
13688
  <div class="chart-area">
14503
- ${r}
14504
- ${o}
13689
+ ${n}
13690
+ ${l}
14505
13691
  <div class="tooltip"></div>
14506
13692
  </div>
14507
13693
  <div class="summary-row">
14508
- ${n}
14509
- </div>
14510
- </div>
14511
- </div>
14512
- `,this._bindEvents()}};customElements.get("loki-cost-waterfall")||customElements.define("loki-cost-waterfall",Te);var pi={1:{bg:"rgba(212, 160, 60, 0.15)",border:"#D4A03C",label:"1st"},2:{bg:"rgba(147, 144, 132, 0.15)",border:"#939084",label:"2nd"},3:{bg:"rgba(196, 130, 91, 0.15)",border:"#C4825B",label:"3rd"}},Le=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._agents=[],this._expandedAgent=null,this._api=null,this._pollInterval=null,this._previousRanks={}}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadData(),this._startPolling()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadData()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_startPolling(){this._poll=b({loadFn:()=>this._loadData(),intervalMs:1e4,element:this,immediate:!1})}_stopPolling(){this._poll&&(this._poll.stop(),this._poll=null)}async _loadData(){let e=this._api;try{let t=await e._get("/api/v2/agents/leaderboard");if(e!==this._api)return;let i=t.agents||[],a={};i.forEach((s,r)=>{a[s.type||s.name]=r+1}),this._previousRanks={...this._currentRanks||{}},this._currentRanks=a,this._agents=i}catch{if(e!==this._api)return;this._agents.length===0&&(this._agents=this._getDemoData(),this._currentRanks={},this._agents.forEach((t,i)=>{this._currentRanks[t.type]=i+1}),this._previousRanks={})}this.render()}_getDemoData(){return[{type:"code-generator",name:"Code Generator",tasks:24,quality:9.2,speed:"fast",cost_usd:2.4},{type:"test-writer",name:"Test Writer",tasks:18,quality:9,speed:"fast",cost_usd:1.2},{type:"code-reviewer",name:"Code Reviewer",tasks:15,quality:8.8,speed:"medium",cost_usd:1.8},{type:"architect",name:"Architect",tasks:8,quality:9.5,speed:"slow",cost_usd:3.1},{type:"debugger",name:"Debugger",tasks:12,quality:8.5,speed:"fast",cost_usd:.95},{type:"doc-writer",name:"Documentation",tasks:10,quality:8.3,speed:"fast",cost_usd:.6}]}_getRankChange(e){let t=this._currentRanks?.[e],i=this._previousRanks?.[e];return t==null||i==null?0:i-t}_escapeHtml(e){return e?String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"):""}_toggleAgent(e){this._expandedAgent=this._expandedAgent===e?null:e,this.render()}_bindEvents(){this.shadowRoot.querySelectorAll(".agent-row").forEach(t=>{t.addEventListener("click",()=>{this._toggleAgent(t.dataset.agent)})})}_getQualityColor(e){return e>=9?"var(--loki-green, #1FC5A8)":e>=8?"var(--loki-blue, #2F71E3)":e>=7?"var(--loki-yellow, #D4A03C)":"var(--loki-red, #C45B5B)"}_getSpeedLabel(e){return e==="fast"?{label:"Fast",color:"var(--loki-green, #1FC5A8)"}:e==="medium"?{label:"Medium",color:"var(--loki-yellow, #D4A03C)"}:{label:"Slow",color:"var(--loki-red, #C45B5B)"}}_getStyles(){return`
14513
- :host {
14514
- display: block;
14515
- }
14516
-
14517
- .leaderboard-container {
14518
- font-family: var(--loki-font-family, 'Inter', -apple-system, sans-serif);
14519
- color: var(--loki-text-primary, #201515);
14520
- }
14521
-
14522
- .header {
14523
- display: flex;
14524
- align-items: center;
14525
- justify-content: space-between;
14526
- margin-bottom: 16px;
14527
- }
14528
-
14529
- .title {
14530
- font-size: 16px;
14531
- font-weight: 600;
14532
- margin: 0;
14533
- }
14534
-
14535
- .agent-count {
14536
- font-size: 12px;
14537
- color: var(--loki-text-muted, #939084);
14538
- }
14539
-
14540
- .leaderboard-table {
14541
- background: var(--loki-bg-card, #ffffff);
14542
- border: 1px solid var(--loki-border, #ECEAE3);
14543
- border-radius: 5px;
14544
- overflow: hidden;
14545
- }
14546
-
14547
- .table-header {
14548
- display: grid;
14549
- grid-template-columns: 48px 1fr 80px 80px 80px;
14550
- padding: 10px 14px;
14551
- border-bottom: 1px solid var(--loki-border, #ECEAE3);
14552
- background: var(--loki-bg-secondary, #F8F4F0);
14553
- }
14554
-
14555
- .table-header span {
14556
- font-size: 10px;
14557
- font-weight: 600;
14558
- text-transform: uppercase;
14559
- letter-spacing: 0.05em;
14560
- color: var(--loki-text-muted, #939084);
14561
- }
14562
-
14563
- .agent-row {
14564
- display: grid;
14565
- grid-template-columns: 48px 1fr 80px 80px 80px;
14566
- padding: 12px 14px;
14567
- border-bottom: 1px solid var(--loki-border, #ECEAE3);
14568
- cursor: pointer;
14569
- transition: all 0.2s;
14570
- align-items: center;
14571
- }
14572
-
14573
- .agent-row:last-child {
14574
- border-bottom: none;
14575
- }
14576
-
14577
- .agent-row:hover {
14578
- background: var(--loki-bg-hover, #F3EFE9);
14579
- }
14580
-
14581
- .agent-row.top-3 {
14582
- border-left: 3px solid transparent;
14583
- }
14584
-
14585
- .rank-cell {
14586
- display: flex;
14587
- align-items: center;
14588
- gap: 4px;
14589
- }
14590
-
14591
- .rank-number {
14592
- font-size: 15px;
14593
- font-weight: 700;
14594
- font-family: 'JetBrains Mono', monospace;
14595
- min-width: 20px;
14596
- }
14597
-
14598
- .rank-badge {
14599
- display: inline-flex;
14600
- align-items: center;
14601
- justify-content: center;
14602
- width: 28px;
14603
- height: 28px;
14604
- border-radius: 50%;
14605
- font-size: 12px;
14606
- font-weight: 700;
14607
- font-family: 'JetBrains Mono', monospace;
14608
- }
14609
-
14610
- .rank-change {
14611
- font-size: 10px;
14612
- font-weight: 600;
14613
- }
14614
-
14615
- .rank-up {
14616
- color: var(--loki-green, #1FC5A8);
14617
- }
14618
-
14619
- .rank-down {
14620
- color: var(--loki-red, #C45B5B);
14621
- }
14622
-
14623
- .agent-name-cell {
14624
- display: flex;
14625
- flex-direction: column;
14626
- gap: 2px;
14627
- }
14628
-
14629
- .agent-name {
14630
- font-size: 13px;
14631
- font-weight: 600;
14632
- color: var(--loki-text-primary, #201515);
14633
- }
14634
-
14635
- .agent-type {
14636
- font-size: 10px;
14637
- font-family: 'JetBrains Mono', monospace;
14638
- color: var(--loki-text-muted, #939084);
14639
- }
14640
-
14641
- .metric-cell {
14642
- font-size: 13px;
14643
- font-family: 'JetBrains Mono', monospace;
14644
- font-weight: 600;
14645
- }
14646
-
14647
- .quality-score {
14648
- display: inline-flex;
14649
- align-items: center;
14650
- gap: 4px;
14651
- }
14652
-
14653
- .quality-bar {
14654
- width: 40px;
14655
- height: 4px;
14656
- background: var(--loki-bg-tertiary, #ECEAE3);
14657
- border-radius: 2px;
14658
- overflow: hidden;
14659
- }
14660
-
14661
- .quality-fill {
14662
- height: 100%;
14663
- border-radius: 2px;
14664
- }
14665
-
14666
- .speed-badge {
14667
- font-size: 10px;
14668
- font-weight: 600;
14669
- padding: 2px 8px;
14670
- border-radius: 4px;
14671
- text-transform: uppercase;
14672
- letter-spacing: 0.03em;
14673
- }
14674
-
14675
- .agent-detail {
14676
- grid-column: 1 / -1;
14677
- padding: 12px 14px;
14678
- background: var(--loki-bg-secondary, #F8F4F0);
14679
- border-top: 1px solid var(--loki-border, #ECEAE3);
14680
- display: grid;
14681
- grid-template-columns: 1fr 1fr 1fr;
14682
- gap: 12px;
14683
- animation: expandDetail 0.2s ease-out;
14684
- }
14685
-
14686
- @keyframes expandDetail {
14687
- from { opacity: 0; max-height: 0; }
14688
- to { opacity: 1; max-height: 100px; }
14689
- }
14690
-
14691
- .detail-metric {
14692
- display: flex;
14693
- flex-direction: column;
14694
- gap: 2px;
14695
- }
14696
-
14697
- .detail-label {
14698
- font-size: 10px;
14699
- font-weight: 600;
14700
- text-transform: uppercase;
14701
- letter-spacing: 0.05em;
14702
- color: var(--loki-text-muted, #939084);
14703
- }
14704
-
14705
- .detail-value {
14706
- font-size: 13px;
14707
- font-family: 'JetBrains Mono', monospace;
14708
- color: var(--loki-text-primary, #201515);
14709
- }
14710
-
14711
- .empty-state {
14712
- text-align: center;
14713
- padding: 32px 16px;
14714
- color: var(--loki-text-muted, #939084);
14715
- font-size: 13px;
14716
- }
14717
- `}render(){let e=this.shadowRoot;if(!e)return;if(this._agents.length===0){e.innerHTML=`
14718
- <style>${this.getBaseStyles()}${this._getStyles()}</style>
14719
- <div class="leaderboard-container">
14720
- <div class="header">
14721
- <h3 class="title">Agent Leaderboard</h3>
14722
- </div>
14723
- <div class="empty-state">No agent performance data available</div>
14724
- </div>
14725
- `;return}let t=this._agents.map((i,a)=>{let s=a+1,r=pi[s],o=i.type||i.name,n=this._getRankChange(o),l=this._expandedAgent===o,c=this._getQualityColor(i.quality),p=this._getSpeedLabel(i.speed),u=(i.quality??0)/10*100,m;r?m=`<div class="rank-badge" style="background: ${r.bg}; color: ${r.border};">${s}</div>`:m=`<span class="rank-number" style="color: var(--loki-text-muted);">${s}</span>`;let g="";n>0?g=`<span class="rank-change rank-up">+${n}</span>`:n<0&&(g=`<span class="rank-change rank-down">${n}</span>`);let x=l?`
14726
- <div class="agent-detail">
14727
- <div class="detail-metric">
14728
- <span class="detail-label">Total Cost</span>
14729
- <span class="detail-value">${B(i.cost_usd)}</span>
14730
- </div>
14731
- <div class="detail-metric">
14732
- <span class="detail-label">Avg Time/Task</span>
14733
- <span class="detail-value">${i.avg_time||Fe}</span>
14734
- </div>
14735
- <div class="detail-metric">
14736
- <span class="detail-label">Success Rate</span>
14737
- <span class="detail-value">${rt(i.success_rate)}</span>
14738
- </div>
14739
- </div>
14740
- `:"";return`
14741
- <div class="agent-row ${s<=3?"top-3":""}" data-agent="${this._escapeHtml(o)}"
14742
- style="${r?"border-left-color: "+r.border+";":""}">
14743
- <div class="rank-cell">${m}${g}</div>
14744
- <div class="agent-name-cell">
14745
- <span class="agent-name">${this._escapeHtml(i.name||i.type)}</span>
14746
- <span class="agent-type">${this._escapeHtml(i.type||"")}</span>
14747
- </div>
14748
- <div class="metric-cell">${i.tasks||0}</div>
14749
- <div class="metric-cell">
14750
- <div class="quality-score">
14751
- <span style="color: ${c};">${q(i.quality,k=>k.toFixed(1))}</span>
14752
- <div class="quality-bar"><div class="quality-fill" style="width: ${u}%; background: ${c};"></div></div>
14753
- </div>
14754
- </div>
14755
- <div class="metric-cell">
14756
- <span class="speed-badge" style="background: ${p.color}15; color: ${p.color};">${p.label}</span>
14757
- </div>
14758
- </div>
14759
- ${x}
14760
- `}).join("");e.innerHTML=`
14761
- <style>${this.getBaseStyles()}${this._getStyles()}</style>
14762
- <div class="leaderboard-container">
14763
- <div class="header">
14764
- <h3 class="title">Agent Leaderboard</h3>
14765
- <span class="agent-count">${this._agents.length} agents</span>
14766
- </div>
14767
- <div class="leaderboard-table">
14768
- <div class="table-header">
14769
- <span>Rank</span>
14770
- <span>Agent</span>
14771
- <span>Tasks</span>
14772
- <span>Quality</span>
14773
- <span>Speed</span>
13694
+ ${c}
14774
13695
  </div>
14775
- ${t}
14776
13696
  </div>
14777
13697
  </div>
14778
- `,this._bindEvents()}};customElements.get("loki-agent-leaderboard")||customElements.define("loki-agent-leaderboard",Le);var At=50,ze=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._api=null,this._statusLoading=!1,this._statusError=null,this._status=null,this._eventsLoading=!1,this._eventsError=null,this._events=[],this._eventsSource=null,this._eventsCount=0,this._lookupId="",this._lookupLoading=!1,this._lookupError=null,this._lookupResult=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadStatus()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"api-url":this._api&&(this._api=h({baseUrl:i}),this._loadStatus());break;case"theme":this._applyTheme(),this.render();break}}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_stopPolling(){}async _loadStatus(){let e=this._api;this._statusLoading=!0,this._statusError=null,this.render();try{let t=await e.get("/api/managed/status");if(e!==this._api)return;this._status=t}catch(t){if(e!==this._api)return;this._statusError=t&&t.message?t.message:"Failed to load managed status",this._status=null}finally{this._statusLoading=!1}this._status&&this._status.enabled?await this._loadEvents():this.render()}async _loadEvents(e=At){let t=this._api;this._eventsLoading=!0,this._eventsError=null,this.render();try{let i=await t.get("/api/managed/events?limit="+encodeURIComponent(e));if(t!==this._api)return;Array.isArray(i)?(this._events=i,this._eventsCount=i.length,this._eventsSource=null):i&&typeof i=="object"?(this._events=Array.isArray(i.events)?i.events:[],this._eventsCount=typeof i.count=="number"?i.count:this._events.length,this._eventsSource=i.source||null):(this._events=[],this._eventsCount=0,this._eventsSource=null)}catch(i){if(t!==this._api)return;this._eventsError=i&&i.message?i.message:"Failed to load managed events",this._events=[],this._eventsCount=0,this._eventsSource=null}finally{this._eventsLoading=!1,this.render()}}async _lookupMemoryVersion(){let e=(this._lookupId||"").trim();if(!e){this._lookupError="Enter a memory ID to look up",this._lookupResult=null,this.render();return}let t=this._api;this._lookupLoading=!0,this._lookupError=null,this._lookupResult=null,this.render();try{let i="/api/managed/memory_versions/"+encodeURIComponent(e),a=await t.get(i);if(t!==this._api)return;this._lookupResult=a}catch(i){if(t!==this._api)return;this._lookupError=i&&i.message?i.message:"Failed to load memory versions",this._lookupResult=null}finally{this._lookupLoading=!1,this.render()}}_onLookupInput(e){this._lookupId=e&&e.target?e.target.value:""}_onLookupKeyDown(e){e&&e.key==="Enter"&&(e.preventDefault(),this._lookupMemoryVersion())}_attachEventHandlers(){let e=this.shadowRoot;if(!e)return;let t=e.querySelector("#refresh-status-btn");t&&t.addEventListener("click",()=>this._loadStatus());let i=e.querySelector("#refresh-events-btn");i&&i.addEventListener("click",()=>this._loadEvents());let a=e.querySelector("#lookup-input");a&&(a.addEventListener("input",r=>this._onLookupInput(r)),a.addEventListener("keydown",r=>this._onLookupKeyDown(r)));let s=e.querySelector("#lookup-btn");s&&s.addEventListener("click",()=>this._lookupMemoryVersion())}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}_formatTimestamp(e){if(!e)return"";let t;return typeof e=="number"?t=new Date(e>1e12?e:e*1e3):t=new Date(e),Number.isNaN(t.getTime())?String(e):t.toISOString().replace("T"," ").replace(/\.\d+Z$/,"Z")}_renderStatusSection(){if(this._statusLoading)return'<div class="status-row muted">Loading managed memory status...</div>';if(this._statusError)return`
13698
+ `,this._bindEvents()}};customElements.get("loki-cost-waterfall")||customElements.define("loki-cost-waterfall",we);var vt=50,$e=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._api=null,this._statusLoading=!1,this._statusError=null,this._status=null,this._eventsLoading=!1,this._eventsError=null,this._events=[],this._eventsSource=null,this._eventsCount=0,this._lookupId="",this._lookupLoading=!1,this._lookupError=null,this._lookupResult=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadStatus()}disconnectedCallback(){super.disconnectedCallback(),this._stopPolling()}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"api-url":this._api&&(this._api=h({baseUrl:i}),this._loadStatus());break;case"theme":this._applyTheme(),this.render();break}}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_stopPolling(){}async _loadStatus(){let e=this._api;this._statusLoading=!0,this._statusError=null,this.render();try{let t=await e.get("/api/managed/status");if(e!==this._api)return;this._status=t}catch(t){if(e!==this._api)return;this._statusError=t&&t.message?t.message:"Failed to load managed status",this._status=null}finally{this._statusLoading=!1}this._status&&this._status.enabled?await this._loadEvents():this.render()}async _loadEvents(e=vt){let t=this._api;this._eventsLoading=!0,this._eventsError=null,this.render();try{let i=await t.get("/api/managed/events?limit="+encodeURIComponent(e));if(t!==this._api)return;Array.isArray(i)?(this._events=i,this._eventsCount=i.length,this._eventsSource=null):i&&typeof i=="object"?(this._events=Array.isArray(i.events)?i.events:[],this._eventsCount=typeof i.count=="number"?i.count:this._events.length,this._eventsSource=i.source||null):(this._events=[],this._eventsCount=0,this._eventsSource=null)}catch(i){if(t!==this._api)return;this._eventsError=i&&i.message?i.message:"Failed to load managed events",this._events=[],this._eventsCount=0,this._eventsSource=null}finally{this._eventsLoading=!1,this.render()}}async _lookupMemoryVersion(){let e=(this._lookupId||"").trim();if(!e){this._lookupError="Enter a memory ID to look up",this._lookupResult=null,this.render();return}let t=this._api;this._lookupLoading=!0,this._lookupError=null,this._lookupResult=null,this.render();try{let i="/api/managed/memory_versions/"+encodeURIComponent(e),a=await t.get(i);if(t!==this._api)return;this._lookupResult=a}catch(i){if(t!==this._api)return;this._lookupError=i&&i.message?i.message:"Failed to load memory versions",this._lookupResult=null}finally{this._lookupLoading=!1,this.render()}}_onLookupInput(e){this._lookupId=e&&e.target?e.target.value:""}_onLookupKeyDown(e){e&&e.key==="Enter"&&(e.preventDefault(),this._lookupMemoryVersion())}_attachEventHandlers(){let e=this.shadowRoot;if(!e)return;let t=e.querySelector("#refresh-status-btn");t&&t.addEventListener("click",()=>this._loadStatus());let i=e.querySelector("#refresh-events-btn");i&&i.addEventListener("click",()=>this._loadEvents());let a=e.querySelector("#lookup-input");a&&(a.addEventListener("input",r=>this._onLookupInput(r)),a.addEventListener("keydown",r=>this._onLookupKeyDown(r)));let s=e.querySelector("#lookup-btn");s&&s.addEventListener("click",()=>this._lookupMemoryVersion())}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}_formatTimestamp(e){if(!e)return"";let t;return typeof e=="number"?t=new Date(e>1e12?e:e*1e3):t=new Date(e),Number.isNaN(t.getTime())?String(e):t.toISOString().replace("T"," ").replace(/\.\d+Z$/,"Z")}_renderStatusSection(){if(this._statusLoading)return'<div class="status-row muted">Loading managed memory status...</div>';if(this._statusError)return`
14779
13699
  <div class="error-banner" role="alert">
14780
13700
  <strong>Status error:</strong>
14781
13701
  <span>${this._escapeHtml(this._statusError)}</span>
@@ -15154,7 +14074,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
15154
14074
  ${t?`
15155
14075
  <div class="section">
15156
14076
  <div class="panel-header">
15157
- <h3 class="section-title">Recent events (limit ${At})</h3>
14077
+ <h3 class="section-title">Recent events (limit ${vt})</h3>
15158
14078
  <button id="refresh-events-btn" class="btn" type="button">Refresh events</button>
15159
14079
  </div>
15160
14080
  ${this._renderEventsSection()}
@@ -15166,7 +14086,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
15166
14086
  </div>
15167
14087
  `:this._statusError?"":this._renderDisabledNotice()}
15168
14088
  </div>
15169
- `,this._attachEventHandlers()}};customElements.get("loki-managed-memory-panel")||customElements.define("loki-managed-memory-panel",ze);var De=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._items=[],this._loading=!1,this._error=null,this._activeFile=null,this._activeBody=null,this._activeBodyError=null,this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._ensureMarkdownStyles(),this._setupApi(),this._loadList(),this._poll=b({loadFn:()=>this._loadList(),intervalMs:1e4,element:this,immediate:!1})}disconnectedCallback(){super.disconnectedCallback(),this._poll&&(this._poll.stop(),this._poll=null)}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadList()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||(typeof window<"u"?window.location.origin:"");this._api=h({baseUrl:e})}async _loadList(){let e=this._api;this._loading=!0,this._error=null;try{let t=await e.get("/api/escalations");if(e!==this._api)return;this._items=Array.isArray(t&&t.escalations)?t.escalations:[]}catch(t){if(e!==this._api)return;this._error=t&&t.message?t.message:String(t),this._items=[]}finally{this._loading=!1,this.render()}}async _openFile(e){let t=this._api;this._activeFile=e,this._activeBody=null,this._activeBodyError=null,this.render();try{let i=(t.baseUrl||"")+"/api/escalations/"+encodeURIComponent(e),a=await fetch(i,{credentials:"include"});if(!a.ok)throw new Error("HTTP "+a.status);let s=await a.text();if(t!==this._api)return;this._activeBody=s}catch(i){if(t!==this._api)return;this._activeBodyError=i&&i.message?i.message:String(i)}this.render()}_closeFile(){this._activeFile=null,this._activeBody=null,this._activeBodyError=null,this.render()}_formatSize(e){return typeof e!="number"?"--":e<1024?e+" B":e<1024*1024?(e/1024).toFixed(1)+" KB":(e/(1024*1024)).toFixed(1)+" MB"}_formatDate(e){if(!e)return"--";try{let t=new Date(e);return isNaN(t.getTime())?e:t.toLocaleString()}catch{return e}}_ensureMarkdownStyles(){if(typeof document>"u"||!document.head||document.getElementById("loki-markdown-styles"))return;let e=document.createElement("style");e.id="loki-markdown-styles",e.textContent=L,document.head.appendChild(e)}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}render(){let e=this.shadowRoot||this;if(!e)return;let t=`
14089
+ `,this._attachEventHandlers()}};customElements.get("loki-managed-memory-panel")||customElements.define("loki-managed-memory-panel",$e);var Ee=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._items=[],this._loading=!1,this._error=null,this._activeFile=null,this._activeBody=null,this._activeBodyError=null,this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._ensureMarkdownStyles(),this._setupApi(),this._loadList(),this._poll=b({loadFn:()=>this._loadList(),intervalMs:1e4,element:this,immediate:!1})}disconnectedCallback(){super.disconnectedCallback(),this._poll&&(this._poll.stop(),this._poll=null)}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._loadList()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||(typeof window<"u"?window.location.origin:"");this._api=h({baseUrl:e})}async _loadList(){let e=this._api;this._loading=!0,this._error=null;try{let t=await e.get("/api/escalations");if(e!==this._api)return;this._items=Array.isArray(t&&t.escalations)?t.escalations:[]}catch(t){if(e!==this._api)return;this._error=t&&t.message?t.message:String(t),this._items=[]}finally{this._loading=!1,this.render()}}async _openFile(e){let t=this._api;this._activeFile=e,this._activeBody=null,this._activeBodyError=null,this.render();try{let i=(t.baseUrl||"")+"/api/escalations/"+encodeURIComponent(e),a=await fetch(i,{credentials:"include"});if(!a.ok)throw new Error("HTTP "+a.status);let s=await a.text();if(t!==this._api)return;this._activeBody=s}catch(i){if(t!==this._api)return;this._activeBodyError=i&&i.message?i.message:String(i)}this.render()}_closeFile(){this._activeFile=null,this._activeBody=null,this._activeBodyError=null,this.render()}_formatSize(e){return typeof e!="number"?"--":e<1024?e+" B":e<1024*1024?(e/1024).toFixed(1)+" KB":(e/(1024*1024)).toFixed(1)+" MB"}_formatDate(e){if(!e)return"--";try{let t=new Date(e);return isNaN(t.getTime())?e:t.toLocaleString()}catch{return e}}_ensureMarkdownStyles(){if(typeof document>"u"||!document.head||document.getElementById("loki-markdown-styles"))return;let e=document.createElement("style");e.id="loki-markdown-styles",e.textContent=z,document.head.appendChild(e)}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}render(){let e=this.shadowRoot||this;if(!e)return;let t=`
15170
14090
  <style>
15171
14091
  :host { display: block; }
15172
14092
  .esc-wrapper {
@@ -15242,7 +14162,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
15242
14162
  white-space: pre-wrap;
15243
14163
  }
15244
14164
  </style>
15245
- `,i="";this._loading&&this._items.length===0?i='<div class="esc-empty">Loading escalations...</div>':this._error?i='<div class="esc-error">Failed to load escalations: '+this._escapeHtml(this._error)+"</div>":!this._items||this._items.length===0?i='<div class="esc-empty">No handoff notes yet. If a build needs your attention, its notes will appear here.</div>':i='<div class="esc-list">'+this._items.map(n=>{let l=this._escapeHtml(n.filename||""),c=this._escapeHtml(this._formatSize(n.size_bytes)),p=this._escapeHtml(this._formatDate(n.modified_at));return'<div class="esc-item" data-filename="'+l+'"><span class="esc-name">'+l+'</span><span class="esc-meta">'+c+" &middot; "+p+"</span></div>"}).join("")+"</div>";let a="";if(this._activeFile){let o=this._escapeHtml(this._activeFile),n;this._activeBodyError?n='<div class="esc-error">Failed to load: '+this._escapeHtml(this._activeBodyError)+"</div>":this._activeBody===null?n='<div class="esc-body">Loading '+o+"...</div>":n='<div class="esc-body md-body">'+C(this._activeBody)+"</div>",a='<div class="esc-viewer"><div class="esc-viewer-header"><span class="esc-name">'+o+'</span><button class="esc-close-btn" data-action="close">Close</button></div>'+n+"</div>"}e.innerHTML=t+'<div class="esc-wrapper"><div class="esc-explain">Handoff/escalation documents written under .loki/escalations/. Click an entry to view its contents.</div>'+i+a+"</div>",e.querySelectorAll(".esc-item").forEach(o=>{o.addEventListener("click",()=>{let n=o.getAttribute("data-filename");n&&this._openFile(n)})});let r=e.querySelector('.esc-close-btn[data-action="close"]');r&&r.addEventListener("click",()=>this._closeFile())}};typeof customElements<"u"&&!customElements.get("loki-escalations")&&customElements.define("loki-escalations",De);var He=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._transcripts=[],this._hookEvents=[],this._loading=!1,this._error=null,this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._load(),this._poll=b({loadFn:()=>this._load(),intervalMs:3e4,element:this,immediate:!1})}disconnectedCallback(){super.disconnectedCallback(),this._poll&&(this._poll.stop(),this._poll=null)}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._load()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||(typeof window<"u"?window.location.origin:"");this._api=h({baseUrl:e})}async _load(){this._loading=!0,this._error=null;let e=this._api;try{let t=await e.get("/api/council/transcripts?limit=10");if(e!==this._api)return;this._transcripts=Array.isArray(t&&t.transcripts)?t.transcripts:[]}catch(t){if(e!==this._api)return;this._error=t&&t.message?t.message:String(t),this._transcripts=[]}try{let t=await e.get("/api/council/transcripts?limit=20&type_prefix=claude_hook_");if(e!==this._api)return;this._hookEvents=Array.isArray(t&&t.hook_events)?t.hook_events:[]}catch{if(e!==this._api)return;this._hookEvents=[]}finally{this._loading=!1,this.render()}}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}_formatTimestamp(e){if(!e)return"--";try{let t=new Date(e);return isNaN(t.getTime())?e:t.toLocaleString()}catch{return e}}_truncate(e,t){if(!e)return"";let i=String(e);return i.length>t?i.slice(0,t)+"...":i}_verdictBadgeHtml(e){let t=String(e||"").toUpperCase();return t==="APPROVE"?'<span class="ct-badge ct-badge-approve">APPROVE</span>':t==="REJECT"?'<span class="ct-badge ct-badge-reject">REJECT</span>':t==="CANNOT_VALIDATE"?'<span class="ct-badge ct-badge-cannot">CANNOT_VALIDATE</span>':'<span class="ct-badge ct-badge-unknown">'+this._escapeHtml(t||"UNKNOWN")+"</span>"}_outcomeBadgeHtml(e){let t=String(e||"").toUpperCase();return t==="APPROVED"?'<span class="ct-badge ct-badge-approve">APPROVED</span>':t==="REJECTED"?'<span class="ct-badge ct-badge-reject">REJECTED</span>':t==="BLOCKED_BY_GATE"?'<span class="ct-badge ct-badge-blocked">BLOCKED BY GATE</span>':'<span class="ct-badge ct-badge-unknown">'+this._escapeHtml(t||"UNKNOWN")+"</span>"}_voterRowHtml(e,t){let i=e.is_contrarian===!0,a=i&&t===!0,s="ct-voter-row";i&&(s+=" ct-voter-contrarian"),a&&(s+=" ct-voter-flipped");let r=this._escapeHtml(e.name||"unknown"),o=this._verdictBadgeHtml(e.verdict),n=this._escapeHtml(this._truncate(e.reasoning,300)),l="",c="";a?(l='<span class="ct-badge ct-badge-override">OVERRIDE</span>',c=`<div class="ct-flip-caption">Devil's Advocate flipped this outcome</div>`):i&&e.triggered&&(l=`<span class="ct-badge ct-badge-da">DEVIL'S ADVOCATE</span>`);let p="";i&&Array.isArray(e.challenges)&&e.challenges.length>0&&(p='<ul class="ct-challenges">'+e.challenges.map(g=>"<li>"+this._escapeHtml(String(g))+"</li>").join("")+"</ul>");let u="";return Array.isArray(e.issues)&&e.issues.length>0&&(u='<ul class="ct-issues">'+e.issues.map(g=>{let x=this._escapeHtml(g.severity||""),k=this._escapeHtml(g.description||"");return'<li><span class="ct-issue-sev ct-issue-sev-'+x.toLowerCase()+'">'+x+"</span> "+k+"</li>"}).join("")+"</ul>"),'<div class="'+s+'"><div class="ct-voter-header"><span class="ct-voter-name">'+r+"</span>"+o+l+"</div>"+(n?'<div class="ct-voter-reason">'+n+"</div>":"")+p+u+c+"</div>"}_transcriptCardHtml(e){let t=this._escapeHtml(String(e.iteration||"--")),i=this._escapeHtml(this._formatTimestamp(e.timestamp)),a=this._escapeHtml(this._truncate(e.task_or_prd,200)),s=this._outcomeBadgeHtml(e.outcome),r=Array.isArray(e.voters)?e.voters:[],o=r.filter(g=>!g.is_contrarian),n=r.filter(g=>g.is_contrarian),l=o.map(g=>this._voterRowHtml(g,!1)).join(""),c="";e.contrarian_triggered&&(c='<div class="ct-contrarian-section"><div class="ct-section-label">Anti-Sycophancy Check</div>'+n.map(x=>this._voterRowHtml(x,e.contrarian_flipped)).join("")+"</div>");let p=typeof e.approve_count=="number"?e.approve_count:"--",u=typeof e.reject_count=="number"?e.reject_count:"--",m=typeof e.threshold=="number"?e.threshold:"--";return'<div class="ct-card"><div class="ct-card-header"><div class="ct-card-meta"><span class="ct-iter-label">Iteration '+t+'</span><span class="ct-ts">'+i+"</span></div>"+s+"</div>"+(a?'<div class="ct-prd-preview">'+a+"</div>":"")+'<div class="ct-tally">Approve: '+p+" &middot; Reject: "+u+" &middot; Threshold: "+m+'</div><div class="ct-voters">'+l+"</div>"+c+"</div>"}render(){let e=this.shadowRoot||this;if(!e)return;let t=`
14165
+ `,i="";this._loading&&this._items.length===0?i='<div class="esc-empty">Loading escalations...</div>':this._error?i='<div class="esc-error">Failed to load escalations: '+this._escapeHtml(this._error)+"</div>":!this._items||this._items.length===0?i='<div class="esc-empty">No handoff notes yet. If a build needs your attention, its notes will appear here.</div>':i='<div class="esc-list">'+this._items.map(n=>{let l=this._escapeHtml(n.filename||""),c=this._escapeHtml(this._formatSize(n.size_bytes)),p=this._escapeHtml(this._formatDate(n.modified_at));return'<div class="esc-item" data-filename="'+l+'"><span class="esc-name">'+l+'</span><span class="esc-meta">'+c+" &middot; "+p+"</span></div>"}).join("")+"</div>";let a="";if(this._activeFile){let o=this._escapeHtml(this._activeFile),n;this._activeBodyError?n='<div class="esc-error">Failed to load: '+this._escapeHtml(this._activeBodyError)+"</div>":this._activeBody===null?n='<div class="esc-body">Loading '+o+"...</div>":n='<div class="esc-body md-body">'+C(this._activeBody)+"</div>",a='<div class="esc-viewer"><div class="esc-viewer-header"><span class="esc-name">'+o+'</span><button class="esc-close-btn" data-action="close">Close</button></div>'+n+"</div>"}e.innerHTML=t+'<div class="esc-wrapper"><div class="esc-explain">Handoff/escalation documents written under .loki/escalations/. Click an entry to view its contents.</div>'+i+a+"</div>",e.querySelectorAll(".esc-item").forEach(o=>{o.addEventListener("click",()=>{let n=o.getAttribute("data-filename");n&&this._openFile(n)})});let r=e.querySelector('.esc-close-btn[data-action="close"]');r&&r.addEventListener("click",()=>this._closeFile())}};typeof customElements<"u"&&!customElements.get("loki-escalations")&&customElements.define("loki-escalations",Ee);var Ce=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._transcripts=[],this._hookEvents=[],this._loading=!1,this._error=null,this._api=null,this._pollInterval=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._load(),this._poll=b({loadFn:()=>this._load(),intervalMs:3e4,element:this,immediate:!1})}disconnectedCallback(){super.disconnectedCallback(),this._poll&&(this._poll.stop(),this._poll=null)}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._api=h({baseUrl:i}),this._load()),e==="theme"&&this._applyTheme())}_setupApi(){let e=this.getAttribute("api-url")||(typeof window<"u"?window.location.origin:"");this._api=h({baseUrl:e})}async _load(){this._loading=!0,this._error=null;let e=this._api;try{let t=await e.get("/api/council/transcripts?limit=10");if(e!==this._api)return;this._transcripts=Array.isArray(t&&t.transcripts)?t.transcripts:[]}catch(t){if(e!==this._api)return;this._error=t&&t.message?t.message:String(t),this._transcripts=[]}try{let t=await e.get("/api/council/transcripts?limit=20&type_prefix=claude_hook_");if(e!==this._api)return;this._hookEvents=Array.isArray(t&&t.hook_events)?t.hook_events:[]}catch{if(e!==this._api)return;this._hookEvents=[]}finally{this._loading=!1,this.render()}}_escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}_formatTimestamp(e){if(!e)return"--";try{let t=new Date(e);return isNaN(t.getTime())?e:t.toLocaleString()}catch{return e}}_truncate(e,t){if(!e)return"";let i=String(e);return i.length>t?i.slice(0,t)+"...":i}_verdictBadgeHtml(e){let t=String(e||"").toUpperCase();return t==="APPROVE"?'<span class="ct-badge ct-badge-approve">APPROVE</span>':t==="REJECT"?'<span class="ct-badge ct-badge-reject">REJECT</span>':t==="CANNOT_VALIDATE"?'<span class="ct-badge ct-badge-cannot">CANNOT_VALIDATE</span>':'<span class="ct-badge ct-badge-unknown">'+this._escapeHtml(t||"UNKNOWN")+"</span>"}_outcomeBadgeHtml(e){let t=String(e||"").toUpperCase();return t==="APPROVED"?'<span class="ct-badge ct-badge-approve">APPROVED</span>':t==="REJECTED"?'<span class="ct-badge ct-badge-reject">REJECTED</span>':t==="BLOCKED_BY_GATE"?'<span class="ct-badge ct-badge-blocked">BLOCKED BY GATE</span>':'<span class="ct-badge ct-badge-unknown">'+this._escapeHtml(t||"UNKNOWN")+"</span>"}_voterRowHtml(e,t){let i=e.is_contrarian===!0,a=i&&t===!0,s="ct-voter-row";i&&(s+=" ct-voter-contrarian"),a&&(s+=" ct-voter-flipped");let r=this._escapeHtml(e.name||"unknown"),o=this._verdictBadgeHtml(e.verdict),n=this._escapeHtml(this._truncate(e.reasoning,300)),l="",c="";a?(l='<span class="ct-badge ct-badge-override">OVERRIDE</span>',c=`<div class="ct-flip-caption">Devil's Advocate flipped this outcome</div>`):i&&e.triggered&&(l=`<span class="ct-badge ct-badge-da">DEVIL'S ADVOCATE</span>`);let p="";i&&Array.isArray(e.challenges)&&e.challenges.length>0&&(p='<ul class="ct-challenges">'+e.challenges.map(g=>"<li>"+this._escapeHtml(String(g))+"</li>").join("")+"</ul>");let u="";return Array.isArray(e.issues)&&e.issues.length>0&&(u='<ul class="ct-issues">'+e.issues.map(g=>{let k=this._escapeHtml(g.severity||""),x=this._escapeHtml(g.description||"");return'<li><span class="ct-issue-sev ct-issue-sev-'+k.toLowerCase()+'">'+k+"</span> "+x+"</li>"}).join("")+"</ul>"),'<div class="'+s+'"><div class="ct-voter-header"><span class="ct-voter-name">'+r+"</span>"+o+l+"</div>"+(n?'<div class="ct-voter-reason">'+n+"</div>":"")+p+u+c+"</div>"}_transcriptCardHtml(e){let t=this._escapeHtml(String(e.iteration||"--")),i=this._escapeHtml(this._formatTimestamp(e.timestamp)),a=this._escapeHtml(this._truncate(e.task_or_prd,200)),s=this._outcomeBadgeHtml(e.outcome),r=Array.isArray(e.voters)?e.voters:[],o=r.filter(g=>!g.is_contrarian),n=r.filter(g=>g.is_contrarian),l=o.map(g=>this._voterRowHtml(g,!1)).join(""),c="";e.contrarian_triggered&&(c='<div class="ct-contrarian-section"><div class="ct-section-label">Anti-Sycophancy Check</div>'+n.map(k=>this._voterRowHtml(k,e.contrarian_flipped)).join("")+"</div>");let p=typeof e.approve_count=="number"?e.approve_count:"--",u=typeof e.reject_count=="number"?e.reject_count:"--",m=typeof e.threshold=="number"?e.threshold:"--";return'<div class="ct-card"><div class="ct-card-header"><div class="ct-card-meta"><span class="ct-iter-label">Iteration '+t+'</span><span class="ct-ts">'+i+"</span></div>"+s+"</div>"+(a?'<div class="ct-prd-preview">'+a+"</div>":"")+'<div class="ct-tally">Approve: '+p+" &middot; Reject: "+u+" &middot; Threshold: "+m+'</div><div class="ct-voters">'+l+"</div>"+c+"</div>"}render(){let e=this.shadowRoot||this;if(!e)return;let t=`
15246
14166
  <style>
15247
14167
  :host { display: block; margin-top: 24px; }
15248
14168
  .ct-wrapper {
@@ -15411,7 +14331,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
15411
14331
  .ct-badge-da { background: #fdf3d4; color: #8a6c0e; }
15412
14332
  .ct-badge-unknown { background: var(--bg-secondary, #F8F4F0); color: var(--text-muted, #939084); }
15413
14333
  </style>
15414
- `,i="";this._loading&&this._transcripts.length===0?i='<div class="ct-empty">Loading council transcripts...</div>':this._error?i='<div class="ct-error">Failed to load transcripts: '+this._escapeHtml(this._error)+"</div>":!this._transcripts||this._transcripts.length===0?i='<div class="ct-empty">No review rounds recorded yet. Transcripts appear after the first completion vote.</div>':i='<div class="ct-list">'+this._transcripts.map(s=>this._transcriptCardHtml(s)).join("")+"</div>",e.innerHTML=t+'<div class="ct-wrapper"><h3 class="ct-heading">Council Transcripts</h3><div class="ct-explain">Per-iteration voting records from .loki/council/transcripts/. Polls every 30 seconds.</div>'+i+this._hookEventsHtml()+"</div>"}_hookEventsHtml(){let e=Array.isArray(this._hookEvents)?this._hookEvents:[],t;return e.length===0?t='<div class="ct-empty">No live tool activity yet -- Claude hook events stream here while a run is active.</div>':t='<div class="ct-voters">'+e.slice(0,20).map(a=>{let s=this._escapeHtml(a.type||a.event||"event"),r=this._escapeHtml(this._formatTimestamp(a.timestamp||a.ts)),o=this._escapeHtml(this._truncate(a.tool||a.message||a.summary||(a.data?JSON.stringify(a.data):""),120));return'<div class="ct-voter-row"><span class="ct-iter-label">'+s+'</span> <span class="ct-ts">'+r+"</span>"+(o?'<div class="ct-prd-preview">'+o+"</div>":"")+"</div>"}).join("")+"</div>",'<h3 class="ct-heading" style="margin-top:24px;">Live Tool Activity</h3><div class="ct-explain">Claude hook events (PreToolUse / PostToolUse / Stop) streamed from .loki/events.jsonl. Lets you watch background tool calls as they run.</div>'+t}};typeof customElements<"u"&&!customElements.get("loki-council-transcripts")&&customElements.define("loki-council-transcripts",He);var ui=[{id:"overview",label:"Overview"},{id:"architecture",label:"Architecture"},{id:"modules",label:"Key Modules"},{id:"data-flow",label:"Data Flow"},{id:"ask",label:"Ask"}],Me=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._activeTab="overview",this._loading=!1,this._error=null,this._api=null,this._meta=null,this._metaPromise=null,this._sectionCache={},this._sectionState={},this._question="",this._answer=null,this._asking=!1,this._askError=null,this._mermaid=null,this._mermaidPromise=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadMeta()}disconnectedCallback(){super.disconnectedCallback&&super.disconnectedCallback(),this._disconnected=!0}attributeChangedCallback(e,t,i){e==="api-url"&&this._api&&(this._api=h({baseUrl:i}))}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_loadMeta(){this._loading=!0,this._error=null,this.render();let e=this._api;return this._metaPromise=(async()=>{try{let t=await e._get("/api/wiki");if(e!==this._api)return;this._meta=t}catch(t){if(e!==this._api)return;this._error=t&&t.message?t.message:"Failed to load wiki"}finally{this._loading=!1,this.render()}})(),this._metaPromise}async _loadSection(e){if(this._sectionCache[e])return this._sectionState[e]=this._sectionCache[e].error?"error":"loaded",this._sectionCache[e];this._sectionState[e]="loading";let t=this._api;try{let i=await t._get(`/api/wiki/${encodeURIComponent(e)}`);return t!==this._api?this._sectionCache[e]||{error:"stale"}:(this._sectionCache[e]=i,this._sectionState[e]=i&&i.error?"error":"loaded",i)}catch(i){if(t!==this._api)return this._sectionCache[e]||{error:"stale"};let a={error:i&&i.message||"load failed"};return this._sectionCache[e]=a,this._sectionState[e]="error",a}}async _selectTab(e){if(this._activeTab=e,e!=="architecture"&&e!=="modules"&&e!=="data-flow"){this.render();return}if(this._sectionCache[e]){this.render();return}if(this._sectionState[e]="loading",this.render(),this._metaPromise)try{await this._metaPromise}catch{}if(!(this._disconnected||this._activeTab!==e)){if(!this._meta||!this._meta.generated){delete this._sectionState[e],this.render();return}await this._loadSection(e),!(this._disconnected||this._activeTab!==e)&&this.render()}}_ensureMermaid(){return this._mermaid?Promise.resolve(this._mermaid):this._mermaidPromise?this._mermaidPromise:(this._mermaidPromise=(async()=>{try{if(typeof window<"u"&&window.mermaid)return this._mermaid=window.mermaid,this._mermaid;if(typeof window>"u"||typeof document>"u")return null;let t=`${this._api&&this._api.baseUrl||window.location.origin}/assets/mermaid.min.js`;return await new Promise((i,a)=>{let s=document.querySelector("script[data-loki-mermaid]");if(s){s.addEventListener("load",i,{once:!0}),s.addEventListener("error",a,{once:!0}),window.mermaid&&i();return}let r=document.createElement("script");r.src=t,r.async=!0,r.setAttribute("data-loki-mermaid","1"),r.addEventListener("load",i,{once:!0}),r.addEventListener("error",()=>a(new Error("mermaid load failed")),{once:!0}),document.head.appendChild(r)}),this._mermaid=typeof window<"u"&&window.mermaid||null,this._mermaid}catch{return null}})(),this._mermaidPromise)}async _maybeRenderDiagram(e){let t=this._sectionCache[e],i=this._diagramSource(t);if(!i)return;let a;try{a=await this._ensureMermaid()}catch{a=null}if(!(!a||this._disconnected||this._activeTab!==e))try{a.initialize({startOnLoad:!1,securityLevel:"strict",theme:this._mermaidTheme(),flowchart:{htmlLabels:!1,useMaxWidth:!0},deterministicIds:!0}),typeof a.parse=="function"&&await a.parse(i);let s=`wiki-mmd-${e}-${Date.now()}`,r=await a.render(s,i),o=r&&(r.svg||r);if(typeof o!="string"||o.indexOf("<svg")===-1||this._disconnected||this._activeTab!==e||!this.shadowRoot)return;let n=this.shadowRoot.getElementById("wiki-diagram");n&&(n.innerHTML=o)}catch{}}_mermaidTheme(){return(this.getAttribute("theme")||typeof document<"u"&&document.documentElement.getAttribute("data-loki-theme")||"").toLowerCase().includes("dark")?"dark":"neutral"}async _ask(){let e=(this._question||"").trim();if(!e)return;this._asking=!0,this._askError=null,this._answer=null,this.render();let t=this._api;try{let i=await t._post("/api/wiki/ask",{question:e},{timeout:2e5});if(t!==this._api)return;this._answer=i}catch(i){if(t!==this._api)return;this._askError=i&&i.message?i.message:"Ask failed"}finally{this._asking=!1,this.render()}}_esc(e){return String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}_renderCitations(e){return!e||!e.length?"":`<div class="cites"><strong>Sources:</strong><ul>${e.map(i=>`<li><code>${this._esc(i.file)}:${this._esc(i.line)}</code></li>`).join("")}</ul></div>`}_renderNotGenerated(){return`<div class="es">
14334
+ `,i="";this._loading&&this._transcripts.length===0?i='<div class="ct-empty">Loading council transcripts...</div>':this._error?i='<div class="ct-error">Failed to load transcripts: '+this._escapeHtml(this._error)+"</div>":!this._transcripts||this._transcripts.length===0?i='<div class="ct-empty">No review rounds recorded yet. Transcripts appear after the first completion vote.</div>':i='<div class="ct-list">'+this._transcripts.map(s=>this._transcriptCardHtml(s)).join("")+"</div>",e.innerHTML=t+'<div class="ct-wrapper"><h3 class="ct-heading">Council Transcripts</h3><div class="ct-explain">Per-iteration voting records from .loki/council/transcripts/. Polls every 30 seconds.</div>'+i+this._hookEventsHtml()+"</div>"}_hookEventsHtml(){let e=Array.isArray(this._hookEvents)?this._hookEvents:[],t;return e.length===0?t='<div class="ct-empty">No live tool activity yet -- Claude hook events stream here while a run is active.</div>':t='<div class="ct-voters">'+e.slice(0,20).map(a=>{let s=this._escapeHtml(a.type||a.event||"event"),r=this._escapeHtml(this._formatTimestamp(a.timestamp||a.ts)),o=this._escapeHtml(this._truncate(a.tool||a.message||a.summary||(a.data?JSON.stringify(a.data):""),120));return'<div class="ct-voter-row"><span class="ct-iter-label">'+s+'</span> <span class="ct-ts">'+r+"</span>"+(o?'<div class="ct-prd-preview">'+o+"</div>":"")+"</div>"}).join("")+"</div>",'<h3 class="ct-heading" style="margin-top:24px;">Live Tool Activity</h3><div class="ct-explain">Claude hook events (PreToolUse / PostToolUse / Stop) streamed from .loki/events.jsonl. Lets you watch background tool calls as they run.</div>'+t}};typeof customElements<"u"&&!customElements.get("loki-council-transcripts")&&customElements.define("loki-council-transcripts",Ce);var ti=[{id:"overview",label:"Overview"},{id:"architecture",label:"Architecture"},{id:"modules",label:"Key Modules"},{id:"data-flow",label:"Data Flow"},{id:"ask",label:"Ask"}],Se=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._activeTab="overview",this._loading=!1,this._error=null,this._api=null,this._meta=null,this._metaPromise=null,this._sectionCache={},this._sectionState={},this._question="",this._answer=null,this._asking=!1,this._askError=null,this._mermaid=null,this._mermaidPromise=null}connectedCallback(){super.connectedCallback(),this._setupApi(),this._loadMeta()}disconnectedCallback(){super.disconnectedCallback&&super.disconnectedCallback(),this._disconnected=!0}attributeChangedCallback(e,t,i){e==="api-url"&&this._api&&(this._api=h({baseUrl:i}))}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}_loadMeta(){this._loading=!0,this._error=null,this.render();let e=this._api;return this._metaPromise=(async()=>{try{let t=await e._get("/api/wiki");if(e!==this._api)return;this._meta=t}catch(t){if(e!==this._api)return;this._error=t&&t.message?t.message:"Failed to load wiki"}finally{this._loading=!1,this.render()}})(),this._metaPromise}async _loadSection(e){if(this._sectionCache[e])return this._sectionState[e]=this._sectionCache[e].error?"error":"loaded",this._sectionCache[e];this._sectionState[e]="loading";let t=this._api;try{let i=await t._get(`/api/wiki/${encodeURIComponent(e)}`);return t!==this._api?this._sectionCache[e]||{error:"stale"}:(this._sectionCache[e]=i,this._sectionState[e]=i&&i.error?"error":"loaded",i)}catch(i){if(t!==this._api)return this._sectionCache[e]||{error:"stale"};let a={error:i&&i.message||"load failed"};return this._sectionCache[e]=a,this._sectionState[e]="error",a}}async _selectTab(e){if(this._activeTab=e,e!=="architecture"&&e!=="modules"&&e!=="data-flow"){this.render();return}if(this._sectionCache[e]){this.render();return}if(this._sectionState[e]="loading",this.render(),this._metaPromise)try{await this._metaPromise}catch{}if(!(this._disconnected||this._activeTab!==e)){if(!this._meta||!this._meta.generated){delete this._sectionState[e],this.render();return}await this._loadSection(e),!(this._disconnected||this._activeTab!==e)&&this.render()}}_ensureMermaid(){return this._mermaid?Promise.resolve(this._mermaid):this._mermaidPromise?this._mermaidPromise:(this._mermaidPromise=(async()=>{try{if(typeof window<"u"&&window.mermaid)return this._mermaid=window.mermaid,this._mermaid;if(typeof window>"u"||typeof document>"u")return null;let t=`${this._api&&this._api.baseUrl||window.location.origin}/assets/mermaid.min.js`;return await new Promise((i,a)=>{let s=document.querySelector("script[data-loki-mermaid]");if(s){s.addEventListener("load",i,{once:!0}),s.addEventListener("error",a,{once:!0}),window.mermaid&&i();return}let r=document.createElement("script");r.src=t,r.async=!0,r.setAttribute("data-loki-mermaid","1"),r.addEventListener("load",i,{once:!0}),r.addEventListener("error",()=>a(new Error("mermaid load failed")),{once:!0}),document.head.appendChild(r)}),this._mermaid=typeof window<"u"&&window.mermaid||null,this._mermaid}catch{return null}})(),this._mermaidPromise)}async _maybeRenderDiagram(e){let t=this._sectionCache[e],i=this._diagramSource(t);if(!i)return;let a;try{a=await this._ensureMermaid()}catch{a=null}if(!(!a||this._disconnected||this._activeTab!==e))try{a.initialize({startOnLoad:!1,securityLevel:"strict",theme:this._mermaidTheme(),flowchart:{htmlLabels:!1,useMaxWidth:!0},deterministicIds:!0}),typeof a.parse=="function"&&await a.parse(i);let s=`wiki-mmd-${e}-${Date.now()}`,r=await a.render(s,i),o=r&&(r.svg||r);if(typeof o!="string"||o.indexOf("<svg")===-1||this._disconnected||this._activeTab!==e||!this.shadowRoot)return;let n=this.shadowRoot.getElementById("wiki-diagram");n&&(n.innerHTML=o)}catch{}}_mermaidTheme(){return(this.getAttribute("theme")||typeof document<"u"&&document.documentElement.getAttribute("data-loki-theme")||"").toLowerCase().includes("dark")?"dark":"neutral"}async _ask(){let e=(this._question||"").trim();if(!e)return;this._asking=!0,this._askError=null,this._answer=null,this.render();let t=this._api;try{let i=await t._post("/api/wiki/ask",{question:e},{timeout:2e5});if(t!==this._api)return;this._answer=i}catch(i){if(t!==this._api)return;this._askError=i&&i.message?i.message:"Ask failed"}finally{this._asking=!1,this.render()}}_esc(e){return String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}_renderCitations(e){return!e||!e.length?"":`<div class="cites"><strong>Sources:</strong><ul>${e.map(i=>`<li><code>${this._esc(i.file)}:${this._esc(i.line)}</code></li>`).join("")}</ul></div>`}_renderNotGenerated(){return`<div class="es">
15415
14335
  <div class="es-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg></div>
15416
14336
  <div class="es-title">No wiki generated yet</div>
15417
14337
  <div class="es-desc">Generate a cited codebase wiki to browse architecture, modules, and data flow. Every section links to real file:line locations.</div>
@@ -15450,11 +14370,11 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
15450
14370
  <div class="es-title">Couldn't load wiki</div>
15451
14371
  <div class="es-desc">${this._esc(e)}</div>
15452
14372
  <button class="es-cta" id="wiki-retry-btn">Retry</button>
15453
- </div>`}_renderBody(){if(this._loading)return'<div class="es-loading"><span class="es-spinner"></span> Loading wiki...</div>';if(this._error)return this._renderError(this._error);switch(this._activeTab){case"overview":return this._renderOverview();case"architecture":return this._renderSection("architecture");case"modules":return this._renderSection("modules");case"data-flow":return this._renderSection("data-flow");case"ask":return this._renderAsk();default:return this._renderOverview()}}render(){if(!this.shadowRoot)return;let e=ui.map(o=>`<button class="tab ${o.id===this._activeTab?"active":""}"
14373
+ </div>`}_renderBody(){if(this._loading)return'<div class="es-loading"><span class="es-spinner"></span> Loading wiki...</div>';if(this._error)return this._renderError(this._error);switch(this._activeTab){case"overview":return this._renderOverview();case"architecture":return this._renderSection("architecture");case"modules":return this._renderSection("modules");case"data-flow":return this._renderSection("data-flow");case"ask":return this._renderAsk();default:return this._renderOverview()}}render(){if(!this.shadowRoot)return;let e=ti.map(o=>`<button class="tab ${o.id===this._activeTab?"active":""}"
15454
14374
  data-tab="${o.id}">${this._esc(o.label)}</button>`).join("");this.shadowRoot.innerHTML=`
15455
14375
  <style>
15456
14376
  ${this.getBaseStyles()}
15457
- ${L}
14377
+ ${z}
15458
14378
  :host { display: block; }
15459
14379
  .tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--loki-border);
15460
14380
  margin-bottom: 12px; flex-wrap: wrap; }
@@ -15568,7 +14488,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
15568
14488
  </style>
15569
14489
  <div class="tabs">${e}</div>
15570
14490
  <div class="content">${this._renderBody()}</div>
15571
- `,this.shadowRoot.querySelectorAll(".tab").forEach(o=>{o.addEventListener("click",()=>this._selectTab(o.dataset.tab))});let t=this.shadowRoot.getElementById("wiki-q");t&&(t.addEventListener("input",o=>{this._question=o.target.value}),t.addEventListener("keydown",o=>{o.key==="Enter"&&this._ask()}));let i=this.shadowRoot.getElementById("wiki-ask-btn");i&&i.addEventListener("click",()=>this._ask());let a=this.shadowRoot.getElementById("wiki-gen-copy");a&&a.addEventListener("click",()=>this._copyGenerateCmd(a));let s=this.shadowRoot.getElementById("wiki-retry-btn");s&&s.addEventListener("click",()=>{this._sectionCache={},this._sectionState={},this._loadMeta()});let r=this._activeTab;(r==="architecture"||r==="data-flow")&&this._sectionCache[r]&&!this._sectionCache[r].error&&this.shadowRoot.getElementById("wiki-diagram")&&this._maybeRenderDiagram(r)}_copyGenerateCmd(e){let t="loki wiki generate",i=()=>{let a=e.innerHTML;e.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',setTimeout(()=>{e.innerHTML=a},1500)};navigator.clipboard&&navigator.clipboard.writeText&&navigator.clipboard.writeText(t).then(i).catch(()=>{})}};customElements.get("loki-wiki-browser")||customElements.define("loki-wiki-browser",Me);var Tt={prd:"PRD file",spec:"Generated spec",issue:"GitHub issue",brief:"One-line brief","codebase-analysis":"Codebase analysis",none:"No spec yet",unknown:"Unknown spec"},Re=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._api=null,this._spec=null,this._history=null,this._loading=!1,this._error=null,this._historyError=null,this._historyOpen=!1}connectedCallback(){super.connectedCallback(),this._setupApi(),this._load()}attributeChangedCallback(e,t,i){e==="api-url"&&this._api&&(this._api=h({baseUrl:i}))}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _load(){let e=this._api;this._loading=!0,this._error=null,this.render();try{let t=await e._get("/api/spec");if(e!==this._api)return;this._spec=t}catch(t){if(e!==this._api)return;this._error=t&&t.message?t.message:"Failed to load spec"}finally{e===this._api&&(this._loading=!1,this.render())}try{let t=await e._get("/api/spec/history");if(e!==this._api)return;this._history=t&&Array.isArray(t.history)?t.history:[]}catch(t){if(e!==this._api)return;this._historyError=t&&t.message?t.message:"Failed to load history",this._history=[]}this.render()}_esc(e){return String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}_when(e){if(!e)return"unknown time";let t=new Date(e);if(isNaN(t.getTime()))return this._esc(e);try{return t.toLocaleString()}catch{return this._esc(e)}}_typeLabel(e){return Tt[e]||Tt.unknown}_typeBadge(e){return`<span class="badge badge-${this._esc(e)}">${this._esc(this._typeLabel(e))}</span>`}_renderActive(){if(this._loading)return'<div class="es-loading"><span class="es-spinner"></span> Loading active spec...</div>';if(this._error)return this._renderError(this._error);let e=this._spec;if(!e||!e.type||e.type==="none")return this._renderEmpty();let t=this._typeBadge(e.type),i="",a="";if(e.type==="prd"||e.type==="spec"){e.path&&(i=`<code class="src">${this._esc(e.path)}</code>`);let s=e.content||"";s.trim()?a=`<div class="body md-body">${C(s)}</div>`+(e.truncated?'<p class="dim">Preview truncated -- see the full file on disk.</p>':""):a='<p class="dim">No content available.</p>'}else if(e.type==="issue"){i=e.ref?`<code class="src">${this._esc(e.ref)}</code>`:"";let r=e.title?`<p class="issue-title">${this._esc(e.title)}</p>`:"",o=(e.body||"").trim()?`<div class="body md-body">${C(e.body)}</div>`+(e.truncated?'<p class="dim">Preview truncated.</p>':""):"";a=`${r}${o}`}else if(e.type==="brief"){let s=(e.text||"").trim();a=s?`<pre class="body brief">${this._esc(s)}</pre>`+(e.truncated?'<p class="dim">Preview truncated.</p>':""):'<p class="dim">No brief recorded.</p>'}else e.type==="codebase-analysis"?a='<p class="dim">No explicit spec. Loki is building from an analysis of the existing codebase.</p>':a='<p class="dim">The spec source could not be resolved.</p>';return`<div class="active">
14491
+ `,this.shadowRoot.querySelectorAll(".tab").forEach(o=>{o.addEventListener("click",()=>this._selectTab(o.dataset.tab))});let t=this.shadowRoot.getElementById("wiki-q");t&&(t.addEventListener("input",o=>{this._question=o.target.value}),t.addEventListener("keydown",o=>{o.key==="Enter"&&this._ask()}));let i=this.shadowRoot.getElementById("wiki-ask-btn");i&&i.addEventListener("click",()=>this._ask());let a=this.shadowRoot.getElementById("wiki-gen-copy");a&&a.addEventListener("click",()=>this._copyGenerateCmd(a));let s=this.shadowRoot.getElementById("wiki-retry-btn");s&&s.addEventListener("click",()=>{this._sectionCache={},this._sectionState={},this._loadMeta()});let r=this._activeTab;(r==="architecture"||r==="data-flow")&&this._sectionCache[r]&&!this._sectionCache[r].error&&this.shadowRoot.getElementById("wiki-diagram")&&this._maybeRenderDiagram(r)}_copyGenerateCmd(e){let t="loki wiki generate",i=()=>{let a=e.innerHTML;e.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',setTimeout(()=>{e.innerHTML=a},1500)};navigator.clipboard&&navigator.clipboard.writeText&&navigator.clipboard.writeText(t).then(i).catch(()=>{})}};customElements.get("loki-wiki-browser")||customElements.define("loki-wiki-browser",Se);var ft={prd:"PRD file",spec:"Generated spec",issue:"GitHub issue",brief:"One-line brief","codebase-analysis":"Codebase analysis",none:"No spec yet",unknown:"Unknown spec"},Ae=class extends v{static get observedAttributes(){return["api-url","theme"]}constructor(){super(),this._api=null,this._spec=null,this._history=null,this._loading=!1,this._error=null,this._historyError=null,this._historyOpen=!1}connectedCallback(){super.connectedCallback(),this._setupApi(),this._load()}attributeChangedCallback(e,t,i){e==="api-url"&&this._api&&(this._api=h({baseUrl:i}))}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e})}async _load(){let e=this._api;this._loading=!0,this._error=null,this.render();try{let t=await e._get("/api/spec");if(e!==this._api)return;this._spec=t}catch(t){if(e!==this._api)return;this._error=t&&t.message?t.message:"Failed to load spec"}finally{e===this._api&&(this._loading=!1,this.render())}try{let t=await e._get("/api/spec/history");if(e!==this._api)return;this._history=t&&Array.isArray(t.history)?t.history:[]}catch(t){if(e!==this._api)return;this._historyError=t&&t.message?t.message:"Failed to load history",this._history=[]}this.render()}_esc(e){return String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}_when(e){if(!e)return"unknown time";let t=new Date(e);if(isNaN(t.getTime()))return this._esc(e);try{return t.toLocaleString()}catch{return this._esc(e)}}_typeLabel(e){return ft[e]||ft.unknown}_typeBadge(e){return`<span class="badge badge-${this._esc(e)}">${this._esc(this._typeLabel(e))}</span>`}_renderActive(){if(this._loading)return'<div class="es-loading"><span class="es-spinner"></span> Loading active spec...</div>';if(this._error)return this._renderError(this._error);let e=this._spec;if(!e||!e.type||e.type==="none")return this._renderEmpty();let t=this._typeBadge(e.type),i="",a="";if(e.type==="prd"||e.type==="spec"){e.path&&(i=`<code class="src">${this._esc(e.path)}</code>`);let s=e.content||"";s.trim()?a=`<div class="body md-body">${C(s)}</div>`+(e.truncated?'<p class="dim">Preview truncated -- see the full file on disk.</p>':""):a='<p class="dim">No content available.</p>'}else if(e.type==="issue"){i=e.ref?`<code class="src">${this._esc(e.ref)}</code>`:"";let r=e.title?`<p class="issue-title">${this._esc(e.title)}</p>`:"",o=(e.body||"").trim()?`<div class="body md-body">${C(e.body)}</div>`+(e.truncated?'<p class="dim">Preview truncated.</p>':""):"";a=`${r}${o}`}else if(e.type==="brief"){let s=(e.text||"").trim();a=s?`<pre class="body brief">${this._esc(s)}</pre>`+(e.truncated?'<p class="dim">Preview truncated.</p>':""):'<p class="dim">No brief recorded.</p>'}else e.type==="codebase-analysis"?a='<p class="dim">No explicit spec. Loki is building from an analysis of the existing codebase.</p>':a='<p class="dim">The spec source could not be resolved.</p>';return`<div class="active">
15572
14492
  <div class="active-head">
15573
14493
  <span class="active-label">Building from</span>
15574
14494
  ${t}
@@ -15598,7 +14518,7 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
15598
14518
  </div>`}render(){if(!this.shadowRoot)return;this.shadowRoot.innerHTML=`
15599
14519
  <style>
15600
14520
  ${this.getBaseStyles()}
15601
- ${L}
14521
+ ${z}
15602
14522
  :host { display: block; }
15603
14523
  .active { background: var(--loki-bg-secondary); border: 1px solid var(--loki-border);
15604
14524
  border-radius: var(--loki-radius-lg, 5px); padding: 16px; }
@@ -15670,13 +14590,13 @@ var LokiDashboard=(()=>{var Ie=Object.defineProperty;var zt=Object.getOwnPropert
15670
14590
  </style>
15671
14591
  <div class="active-wrap">${this._renderActive()}</div>
15672
14592
  ${this._error||this._spec&&this._spec.type==="none"?"":this._renderHistory()}
15673
- `;let e=this.shadowRoot.getElementById("spec-retry-btn");e&&e.addEventListener("click",()=>this._load());let t=this.shadowRoot.getElementById("hist-toggle");t&&t.addEventListener("click",()=>{this._historyOpen=!this._historyOpen,this.render()})}};customElements.get("loki-spec-panel")||customElements.define("loki-spec-panel",Re);(function(){"use strict";if(typeof window>"u"||typeof customElements>"u")return;var d={open:'<circle cx="178" cy="214" r="7" class="fillInk"/><circle cx="244" cy="214" r="7" class="fillInk"/><circle cx="180.5" cy="211.5" r="2" class="fillHi"/><circle cx="246.5" cy="211.5" r="2" class="fillHi"/>',happy:'<path class="ink" d="M171 216c4-6 10-6 14 0"/><path class="ink" d="M237 216c4-6 10-6 14 0"/>',lookUp:'<circle cx="178" cy="214" r="7" class="fillInk"/><circle cx="244" cy="214" r="7" class="fillInk"/><circle cx="180" cy="210" r="2.4" class="fillHi"/><circle cx="246" cy="210" r="2.4" class="fillHi"/>',wide:'<circle cx="178" cy="213" r="8.5" class="fillInk"/><circle cx="244" cy="213" r="8.5" class="fillInk"/><circle cx="181" cy="210" r="2.6" class="fillHi"/><circle cx="247" cy="210" r="2.6" class="fillHi"/>',focused:'<path class="inkBold" d="M170 214h16"/><path class="inkBold" d="M236 214h16"/>',closed:'<path class="ink" d="M170 214c4 5 10 5 14 0"/><path class="ink" d="M236 214c4 5 10 5 14 0"/>',worried:'<circle cx="178" cy="216" r="6" class="fillInk"/><circle cx="244" cy="216" r="6" class="fillInk"/><circle cx="180" cy="213.5" r="1.8" class="fillHi"/><circle cx="246" cy="213.5" r="1.8" class="fillHi"/>',wink:'<path class="ink" d="M171 214c4-5 10-5 14 0"/><circle cx="244" cy="214" r="7" class="fillInk"/><circle cx="246.5" cy="211.5" r="2" class="fillHi"/>'},e={none:"",raised:'<path class="inkThin" d="M168 198c5-3 12-3 17 0"/><path class="inkThin" d="M237 198c5-3 12-3 17 0"/>',furrow:'<path class="inkThin" d="M168 199l16 3"/><path class="inkThin" d="M254 199l-16 3"/>',worried:'<path class="inkThin" d="M168 201l16-4"/><path class="inkThin" d="M254 201l-16-4"/>'},t={smile:'<path class="ink" d="M192 244c12 12 26 12 38 0"/>',openSmile:'<path class="fillInk" d="M194 243c8 16 26 16 34 0c-10 6-24 6-34 0z"/>',flat:'<path class="ink" d="M198 248h26"/>',o:'<ellipse cx="211" cy="248" rx="6" ry="7" class="ink"/>',frown:'<path class="ink" d="M192 250c12-12 26-12 38 0"/>',soft:'<path class="ink" d="M196 246c9 7 19 7 28 0"/>',proud:'<path class="ink" d="M194 245c10 9 24 9 32 -2"/>'},i={none:"",wave:'<g class="prop-wave"><path class="ink" d="M318 250c14-2 26 6 28 20"/><circle cx="348" cy="276" r="9" class="fillPaper ink"/></g>',zzz:'<g class="ink prop-zzz"><text x="300" y="150" class="zzz z1">z</text><text x="322" y="128" class="zzz z2">z</text><text x="344" y="110" class="zzz z3">z</text></g>',thoughtDots:'<g class="prop-think"><circle cx="300" cy="170" r="4" class="fillInk d1"/><circle cx="316" cy="150" r="5.5" class="fillInk d2"/><circle cx="336" cy="126" r="7" class="fillInk d3"/></g>',magnifier:'<g class="prop-magnifier"><circle cx="332" cy="250" r="18" class="fillGlass ink"/><path class="inkBold" d="M345 263l16 16"/><path class="inkThin" d="M325 244a10 10 0 0 1 8 4"/></g>',check:'<g class="prop-check"><circle cx="332" cy="246" r="17" class="fillSeal"/><path class="checkMark" d="M324 246l6 6 11 -13"/></g>',confetti:'<g class="prop-confetti"><rect x="110" y="120" width="7" height="7" class="fillInk c1" transform="rotate(20 113 123)"/><rect x="300" y="110" width="7" height="7" class="fillGlow c2" transform="rotate(-15 303 113)"/><rect x="140" y="96" width="6" height="6" class="fillSeal c3"/><circle cx="330" cy="150" r="4" class="fillInk c4"/><circle cx="96" cy="170" r="4" class="fillGlow c5"/><rect x="270" y="140" width="6" height="6" class="fillInk c6" transform="rotate(40 273 143)"/><path class="inkViolet c7" d="M210 92l0 12M204 98l12 0"/></g>',parcel:'<g class="prop-parcel"><rect x="316" y="244" width="40" height="34" rx="3" class="fillPaper ink"/><path class="ink" d="M316 256h40"/><path class="inkViolet" d="M336 244v34"/></g>',spinner:'<g class="prop-spinner"><path class="inkBold spin" d="M332 230a20 20 0 1 1 -14 6"/></g>'},a={idle:{eyes:"open",mouth:"smile",motion:"breathe",label:"Loki, resting",blink:!0},happy:{eyes:"happy",mouth:"smile",motion:"bob",label:"Loki, happy"},thinking:{eyes:"lookUp",brow:"raised",mouth:"flat",prop:"thoughtDots",motion:"wiggle",label:"Loki, thinking"},building:{eyes:"focused",brow:"furrow",mouth:"flat",motion:"work",label:"Loki, building"},reviewing:{eyes:"focused",brow:"furrow",mouth:"soft",prop:"magnifier",motion:"inspect",label:"Loki, reviewing the work"},verifying:{eyes:"open",mouth:"soft",prop:"check",motion:"bob",label:"Loki, verifying",blink:!0},celebrating:{eyes:"wide",mouth:"openSmile",prop:"confetti",motion:"bounce",label:"Loki, celebrating a verified result"},proud:{eyes:"happy",mouth:"proud",prop:"check",motion:"bob",label:"Loki, proud"},waving:{eyes:"wink",mouth:"smile",prop:"wave",motion:"wave",label:"Loki, waving hello"},sleeping:{eyes:"closed",mouth:"soft",prop:"zzz",motion:"sleep",label:"Loki, sleeping"},concerned:{eyes:"worried",brow:"worried",mouth:"frown",motion:"shake",label:"Loki, something went wrong"},shipping:{eyes:"happy",mouth:"smile",prop:"parcel",motion:"launch",label:"Loki, shipping"},loading:{eyes:"open",mouth:"flat",prop:"spinner",motion:"breathe",label:"Loki, loading",blink:!0},curious:{eyes:"lookUp",brow:"raised",mouth:"o",prop:"thoughtDots",motion:"tilt",label:"Loki, curious"},blinking:{eyes:"open",mouth:"smile",motion:"breathe",label:"Loki",blink:!0},walking:{eyes:"open",mouth:"soft",motion:"walk",label:"Loki, walking",blink:!0},running:{eyes:"focused",mouth:"soft",motion:"run",label:"Loki, running"}},s="idle";function r(){return'<g class="legs"><path class="ink leg legL" d="M168 318v18"/><path class="ink foot footL" d="M158 336h20"/><path class="ink leg legR" d="M252 318v18"/><path class="ink foot footR" d="M242 336h20"/></g>'}function o(u,m,g){return m&&Object.prototype.hasOwnProperty.call(u,m)?u[m]:g||""}function n(u){var m=u.blink?" blink":"";return'<svg class="figure" viewBox="0 0 420 380" aria-hidden="true" focusable="false"><ellipse cx="210" cy="338" rx="120" ry="16" class="fillInkWash"/><g class="creature">'+r()+'<path class="fillPaper ink" d="M120 132c0-22 16-36 40-37 38-2 82-2 120 0 24 1 40 15 40 38v118c0 24-16 39-41 40-40 2-78 2-118 0-25-1-41-16-41-40z"/><path class="inkThin" d="M124 168c54-4 118-4 172 0"/><circle cx="146" cy="150" r="4.5" class="inkViolet"/><circle cx="164" cy="150" r="4.5" class="inkThinDot"/><circle cx="182" cy="150" r="4.5" class="inkThinDot"/><circle cx="170" cy="232" r="9" class="fillGlow"/><circle cx="252" cy="232" r="9" class="fillGlow"/>'+o(e,u.brow,"")+'<g class="eyes'+m+'">'+o(d,u.eyes,d.open)+"</g>"+o(t,u.mouth,t.smile)+'<path class="inkViolet" d="M150 280h120"/><path class="inkThin" d="M150 296h84"/>'+o(i,u.prop,"")+"</g></svg>"}var l=[":host{display:inline-block;line-height:0;","--lm-ink:var(--color-ink,#553de9);","--lm-ink-wash:var(--color-ink-wash,rgba(85,61,233,0.08));","--lm-text:var(--color-text,#201515);","--lm-paper:var(--color-paper-card,#fffdf8);","--lm-glow:var(--color-glow,#e8a33d);","--lm-glow-wash:var(--color-glow-wash,rgba(232,163,61,0.14));","--lm-seal:var(--color-seal,#1f8a52);","}",".figure{display:block;width:100%;height:auto;overflow:visible}",".ink{fill:none;stroke:var(--lm-text);stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}",".inkBold{fill:none;stroke:var(--lm-text);stroke-width:3.4;stroke-linecap:round;stroke-linejoin:round}",".inkThin{fill:none;stroke:var(--lm-text);stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}",".inkThinDot{fill:none;stroke:var(--lm-text);stroke-width:1.6}",".inkViolet{fill:none;stroke:var(--lm-ink);stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}",".fillPaper{fill:var(--lm-paper)}",".fillInk{fill:var(--lm-ink)}",".fillInkWash{fill:var(--lm-ink-wash)}",".fillGlow{fill:var(--lm-glow)}",".fillSeal{fill:var(--lm-seal)}",".fillGlass{fill:rgba(85,61,233,0.06)}",".fillHi{fill:var(--lm-paper)}",".prop-wave .fillPaper{fill:var(--lm-paper)}",".checkMark{fill:none;stroke:#fff;stroke-width:3.2;stroke-linecap:round;stroke-linejoin:round}",".zzz{font:600 26px var(--font-sans,system-ui,sans-serif);fill:var(--lm-ink)}",".m-breathe .creature{transform-box:fill-box;transform-origin:center;animation:lm-breathe 4.5s ease-in-out infinite}","@keyframes lm-breathe{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-2px) scale(1.012)}}",".m-bob .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-bob 2.2s ease-in-out infinite}","@keyframes lm-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-7px)}}",".m-bounce .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-bounce 0.9s cubic-bezier(.3,.7,.4,1) infinite}","@keyframes lm-bounce{0%,100%{transform:translateY(0) scaleY(1)}30%{transform:translateY(-22px) scaleY(1.05)}55%{transform:translateY(0) scaleY(.94)}70%{transform:translateY(-6px)}}",".m-wiggle .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-wiggle 3s ease-in-out infinite}","@keyframes lm-wiggle{0%,100%{transform:rotate(-1.5deg)}50%{transform:rotate(1.5deg)}}",".m-tilt .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-tilt 3.4s ease-in-out infinite}","@keyframes lm-tilt{0%,100%{transform:rotate(-4deg)}50%{transform:rotate(4deg)}}",".m-work .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-work 0.7s ease-in-out infinite}","@keyframes lm-work{0%,100%{transform:translateX(0) rotate(0)}25%{transform:translateX(-1.5px) rotate(-1deg)}75%{transform:translateX(1.5px) rotate(1deg)}}",".m-inspect .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-inspect 3.2s ease-in-out infinite}","@keyframes lm-inspect{0%,100%{transform:translate(0,0)}50%{transform:translate(6px,-2px)}}",".m-inspect .prop-magnifier{transform-box:fill-box;transform-origin:332px 250px;animation:lm-inspect-mag 3.2s ease-in-out infinite}","@keyframes lm-inspect-mag{0%,100%{transform:translate(0,0) scale(1)}50%{transform:translate(4px,4px) scale(1.08)}}",".m-shake .creature{transform-box:fill-box;transform-origin:center;animation:lm-shake 0.5s ease-in-out infinite}","@keyframes lm-shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-4px)}75%{transform:translateX(4px)}}",".m-launch .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-launch 1.6s ease-in-out infinite}","@keyframes lm-launch{0%{transform:translateY(0)}40%{transform:translateY(-3px)}70%{transform:translateY(-14px) rotate(-2deg)}100%{transform:translateY(0)}}",".m-wave .creature{transform-box:fill-box;transform-origin:center;animation:lm-breathe 4.5s ease-in-out infinite}",".m-sleep .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-sleep 5.5s ease-in-out infinite}","@keyframes lm-sleep{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-1px) scale(1.02)}}",".prop-wave{transform-box:fill-box;transform-origin:50% 100%;animation:lm-sway 1.1s ease-in-out infinite}","@keyframes lm-sway{0%,100%{transform:rotate(-8deg)}50%{transform:rotate(14deg)}}",".prop-think .d1{transform-box:fill-box;transform-origin:center;animation:lm-rise 2.4s ease-in-out infinite}",".prop-think .d2{transform-box:fill-box;transform-origin:center;animation:lm-rise 2.4s ease-in-out infinite .3s}",".prop-think .d3{transform-box:fill-box;transform-origin:center;animation:lm-rise 2.4s ease-in-out infinite .6s}","@keyframes lm-rise{0%{opacity:.2;transform:translateY(4px) scale(.7)}50%{opacity:1;transform:translateY(0) scale(1)}100%{opacity:.2;transform:translateY(-4px) scale(.7)}}",".zzz{opacity:0;transform-box:fill-box;transform-origin:center}",".prop-zzz .z1{animation:lm-zfloat 3s ease-in-out infinite}",".prop-zzz .z2{animation:lm-zfloat 3s ease-in-out infinite 1s}",".prop-zzz .z3{animation:lm-zfloat 3s ease-in-out infinite 2s}","@keyframes lm-zfloat{0%{opacity:0;transform:translateY(6px) scale(.7)}40%{opacity:1}100%{opacity:0;transform:translateY(-16px) scale(1.1)}}",".spin{transform-box:fill-box;transform-origin:332px 250px;animation:lm-spin 1s linear infinite}","@keyframes lm-spin{to{transform:rotate(360deg)}}",".prop-confetti>*{transform-box:fill-box;transform-origin:center;animation:lm-confetti 1.4s ease-in infinite}",".prop-confetti .c2{animation-delay:.15s}.prop-confetti .c3{animation-delay:.3s}",".prop-confetti .c4{animation-delay:.45s}.prop-confetti .c5{animation-delay:.2s}",".prop-confetti .c6{animation-delay:.5s}.prop-confetti .c7{animation-delay:.1s}","@keyframes lm-confetti{0%{opacity:0;transform:translateY(0) rotate(0)}20%{opacity:1}100%{opacity:0;transform:translateY(34px) rotate(180deg)}}",".prop-check{transform-box:fill-box;transform-origin:332px 246px;animation:lm-pop 2.4s ease-in-out infinite}","@keyframes lm-pop{0%,70%,100%{transform:scale(1)}80%{transform:scale(1.18)}}",".m-launch .prop-parcel{transform-box:fill-box;transform-origin:center;animation:lm-bob 1.6s ease-in-out infinite}",".m-walk .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-walkbody 0.8s ease-in-out infinite}","@keyframes lm-walkbody{0%,100%{transform:translateY(0) rotate(-1deg)}50%{transform:translateY(-4px) rotate(1deg)}}",".m-walk .legL{transform-box:fill-box;transform-origin:168px 318px;animation:lm-legswing 0.8s ease-in-out infinite}",".m-walk .footL{transform-box:fill-box;transform-origin:168px 336px;animation:lm-legswing 0.8s ease-in-out infinite}",".m-walk .legR{transform-box:fill-box;transform-origin:252px 318px;animation:lm-legswing 0.8s ease-in-out infinite .4s}",".m-walk .footR{transform-box:fill-box;transform-origin:252px 336px;animation:lm-legswing 0.8s ease-in-out infinite .4s}","@keyframes lm-legswing{0%,100%{transform:rotate(-16deg)}50%{transform:rotate(16deg)}}",".m-run .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-runbody 0.42s ease-in-out infinite}","@keyframes lm-runbody{0%,100%{transform:translateY(0) rotate(-4deg)}50%{transform:translateY(-7px) rotate(2deg)}}",".m-run .legL{transform-box:fill-box;transform-origin:168px 318px;animation:lm-runleg 0.42s ease-in-out infinite}",".m-run .footL{transform-box:fill-box;transform-origin:168px 336px;animation:lm-runleg 0.42s ease-in-out infinite}",".m-run .legR{transform-box:fill-box;transform-origin:252px 318px;animation:lm-runleg 0.42s ease-in-out infinite .21s}",".m-run .footR{transform-box:fill-box;transform-origin:252px 336px;animation:lm-runleg 0.42s ease-in-out infinite .21s}","@keyframes lm-runleg{0%,100%{transform:rotate(-30deg)}50%{transform:rotate(30deg)}}",".eyes.blink{transform-box:fill-box;transform-origin:center;animation:lm-blink 6s steps(1,end) infinite}","@keyframes lm-blink{0%,92%,100%{transform:scaleY(1)}95%{transform:scaleY(.1)}}","@media (prefers-reduced-motion: reduce){",".figure *{animation:none !important}",".eyes.blink{transform:scaleY(1) !important}",".zzz{opacity:1}",".prop-confetti>*{opacity:1}",".prop-think .d1,.prop-think .d2,.prop-think .d3{opacity:1}","}"].join("");function c(u){var m=parseFloat(u);return!isFinite(m)||m<=0?132:m<16?16:m>1024?1024:m}var p=function(){function u(){return class extends HTMLElement{static get observedAttributes(){return["emotion","size","motion"]}constructor(){super(),this.attachShadow({mode:"open"}),this._styleEl=document.createElement("style"),this._styleEl.textContent=l,this._wrap=document.createElement("div"),this._wrap.className="lm-root",this.shadowRoot.appendChild(this._styleEl),this.shadowRoot.appendChild(this._wrap)}connectedCallback(){this._render()}attributeChangedCallback(){this.shadowRoot&&this._render()}_render(){var g=(this.getAttribute("emotion")||s).toLowerCase(),x=a[g]||a[s],k=(this.getAttribute("motion")||x.motion||"breathe").toLowerCase(),_=c(this.getAttribute("size")||"132");this.style.width=_+"px",this.setAttribute("role","img"),this.setAttribute("aria-label",x.label||"Loki"),this._wrap.className="lm-root m-"+k,this._wrap.innerHTML=n(x)}}}return customElements.get("loki-mascot")||customElements.define("loki-mascot",u()),customElements.get("loki-mascot")}();try{p.emotions=Object.keys(a),p.getEmotion=function(u){var m=(u||s).toLowerCase(),g=a[m]||a[s];return Object.assign({name:m},g)},p.renderStandaloneSVG=function(u){var m=p.getEmotion(u),g=m.motion||"breathe",x=l.replace(":host{","svg.loki-figure{"),k=n(m).replace('<svg class="figure"','<svg xmlns="http://www.w3.org/2000/svg" class="figure loki-figure m-'+g+'" role="img" aria-label="'+(m.label||"Loki")+'"').replace('aria-hidden="true" focusable="false"','focusable="false"');return k.replace("</svg>","<style>"+x+"</style></svg>")}}catch{}})();function hi(d){switch((d||"").toLowerCase()){case"running":case"autonomous":return"building";case"paused":return"sleeping";default:return"idle"}}var Pe=class extends HTMLElement{static get observedAttributes(){return["api-url","size"]}constructor(){super(),this.attachShadow({mode:"open"}),this._status="idle",this._api=null,this._statusHandler=null,this._discHandler=null,this._poll=null}connectedCallback(){this._setupApi(),this._loadStatus(),this._startPolling(),this.render()}disconnectedCallback(){this._poll&&(this._poll.stop(),this._poll=null),this._teardownApiListeners()}_teardownApiListeners(){this._api&&(this._statusHandler&&this._api.removeEventListener(f.STATUS_UPDATE,this._statusHandler),this._discHandler&&this._api.removeEventListener(f.DISCONNECTED,this._discHandler))}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._teardownApiListeners(),this._setupApi(),this._loadStatus()),e==="size"&&this.render())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e}),this._statusHandler=t=>this._updateFromStatus(t.detail),this._discHandler=()=>{this._status="offline",this.render()},this._api.addEventListener(f.STATUS_UPDATE,this._statusHandler),this._api.addEventListener(f.DISCONNECTED,this._discHandler)}_startPolling(){this._poll=b({loadFn:()=>this._loadStatus(),intervalMs:1e4,sectionId:null,immediate:!1})}async _loadStatus(){let e=this._api;try{let t=await e.getStatus();if(e!==this._api)return;this._updateFromStatus(t)}catch{if(e!==this._api)return;this._status="offline",this.render()}}_updateFromStatus(e){if(!e)return;let t=e.status||"idle";t!==this._status&&(this._status=t,this.render())}render(){if(!this.shadowRoot)return;let e=this.getAttribute("size")||"34",t=hi(this._status);this.shadowRoot.innerHTML=`
14593
+ `;let e=this.shadowRoot.getElementById("spec-retry-btn");e&&e.addEventListener("click",()=>this._load());let t=this.shadowRoot.getElementById("hist-toggle");t&&t.addEventListener("click",()=>{this._historyOpen=!this._historyOpen,this.render()})}};customElements.get("loki-spec-panel")||customElements.define("loki-spec-panel",Ae);(function(){"use strict";if(typeof window>"u"||typeof customElements>"u")return;var d={open:'<circle cx="178" cy="214" r="7" class="fillInk"/><circle cx="244" cy="214" r="7" class="fillInk"/><circle cx="180.5" cy="211.5" r="2" class="fillHi"/><circle cx="246.5" cy="211.5" r="2" class="fillHi"/>',happy:'<path class="ink" d="M171 216c4-6 10-6 14 0"/><path class="ink" d="M237 216c4-6 10-6 14 0"/>',lookUp:'<circle cx="178" cy="214" r="7" class="fillInk"/><circle cx="244" cy="214" r="7" class="fillInk"/><circle cx="180" cy="210" r="2.4" class="fillHi"/><circle cx="246" cy="210" r="2.4" class="fillHi"/>',wide:'<circle cx="178" cy="213" r="8.5" class="fillInk"/><circle cx="244" cy="213" r="8.5" class="fillInk"/><circle cx="181" cy="210" r="2.6" class="fillHi"/><circle cx="247" cy="210" r="2.6" class="fillHi"/>',focused:'<path class="inkBold" d="M170 214h16"/><path class="inkBold" d="M236 214h16"/>',closed:'<path class="ink" d="M170 214c4 5 10 5 14 0"/><path class="ink" d="M236 214c4 5 10 5 14 0"/>',worried:'<circle cx="178" cy="216" r="6" class="fillInk"/><circle cx="244" cy="216" r="6" class="fillInk"/><circle cx="180" cy="213.5" r="1.8" class="fillHi"/><circle cx="246" cy="213.5" r="1.8" class="fillHi"/>',wink:'<path class="ink" d="M171 214c4-5 10-5 14 0"/><circle cx="244" cy="214" r="7" class="fillInk"/><circle cx="246.5" cy="211.5" r="2" class="fillHi"/>'},e={none:"",raised:'<path class="inkThin" d="M168 198c5-3 12-3 17 0"/><path class="inkThin" d="M237 198c5-3 12-3 17 0"/>',furrow:'<path class="inkThin" d="M168 199l16 3"/><path class="inkThin" d="M254 199l-16 3"/>',worried:'<path class="inkThin" d="M168 201l16-4"/><path class="inkThin" d="M254 201l-16-4"/>'},t={smile:'<path class="ink" d="M192 244c12 12 26 12 38 0"/>',openSmile:'<path class="fillInk" d="M194 243c8 16 26 16 34 0c-10 6-24 6-34 0z"/>',flat:'<path class="ink" d="M198 248h26"/>',o:'<ellipse cx="211" cy="248" rx="6" ry="7" class="ink"/>',frown:'<path class="ink" d="M192 250c12-12 26-12 38 0"/>',soft:'<path class="ink" d="M196 246c9 7 19 7 28 0"/>',proud:'<path class="ink" d="M194 245c10 9 24 9 32 -2"/>'},i={none:"",wave:'<g class="prop-wave"><path class="ink" d="M318 250c14-2 26 6 28 20"/><circle cx="348" cy="276" r="9" class="fillPaper ink"/></g>',zzz:'<g class="ink prop-zzz"><text x="300" y="150" class="zzz z1">z</text><text x="322" y="128" class="zzz z2">z</text><text x="344" y="110" class="zzz z3">z</text></g>',thoughtDots:'<g class="prop-think"><circle cx="300" cy="170" r="4" class="fillInk d1"/><circle cx="316" cy="150" r="5.5" class="fillInk d2"/><circle cx="336" cy="126" r="7" class="fillInk d3"/></g>',magnifier:'<g class="prop-magnifier"><circle cx="332" cy="250" r="18" class="fillGlass ink"/><path class="inkBold" d="M345 263l16 16"/><path class="inkThin" d="M325 244a10 10 0 0 1 8 4"/></g>',check:'<g class="prop-check"><circle cx="332" cy="246" r="17" class="fillSeal"/><path class="checkMark" d="M324 246l6 6 11 -13"/></g>',confetti:'<g class="prop-confetti"><rect x="110" y="120" width="7" height="7" class="fillInk c1" transform="rotate(20 113 123)"/><rect x="300" y="110" width="7" height="7" class="fillGlow c2" transform="rotate(-15 303 113)"/><rect x="140" y="96" width="6" height="6" class="fillSeal c3"/><circle cx="330" cy="150" r="4" class="fillInk c4"/><circle cx="96" cy="170" r="4" class="fillGlow c5"/><rect x="270" y="140" width="6" height="6" class="fillInk c6" transform="rotate(40 273 143)"/><path class="inkViolet c7" d="M210 92l0 12M204 98l12 0"/></g>',parcel:'<g class="prop-parcel"><rect x="316" y="244" width="40" height="34" rx="3" class="fillPaper ink"/><path class="ink" d="M316 256h40"/><path class="inkViolet" d="M336 244v34"/></g>',spinner:'<g class="prop-spinner"><path class="inkBold spin" d="M332 230a20 20 0 1 1 -14 6"/></g>'},a={idle:{eyes:"open",mouth:"smile",motion:"breathe",label:"Loki, resting",blink:!0},happy:{eyes:"happy",mouth:"smile",motion:"bob",label:"Loki, happy"},thinking:{eyes:"lookUp",brow:"raised",mouth:"flat",prop:"thoughtDots",motion:"wiggle",label:"Loki, thinking"},building:{eyes:"focused",brow:"furrow",mouth:"flat",motion:"work",label:"Loki, building"},reviewing:{eyes:"focused",brow:"furrow",mouth:"soft",prop:"magnifier",motion:"inspect",label:"Loki, reviewing the work"},verifying:{eyes:"open",mouth:"soft",prop:"check",motion:"bob",label:"Loki, verifying",blink:!0},celebrating:{eyes:"wide",mouth:"openSmile",prop:"confetti",motion:"bounce",label:"Loki, celebrating a verified result"},proud:{eyes:"happy",mouth:"proud",prop:"check",motion:"bob",label:"Loki, proud"},waving:{eyes:"wink",mouth:"smile",prop:"wave",motion:"wave",label:"Loki, waving hello"},sleeping:{eyes:"closed",mouth:"soft",prop:"zzz",motion:"sleep",label:"Loki, sleeping"},concerned:{eyes:"worried",brow:"worried",mouth:"frown",motion:"shake",label:"Loki, something went wrong"},shipping:{eyes:"happy",mouth:"smile",prop:"parcel",motion:"launch",label:"Loki, shipping"},loading:{eyes:"open",mouth:"flat",prop:"spinner",motion:"breathe",label:"Loki, loading",blink:!0},curious:{eyes:"lookUp",brow:"raised",mouth:"o",prop:"thoughtDots",motion:"tilt",label:"Loki, curious"},blinking:{eyes:"open",mouth:"smile",motion:"breathe",label:"Loki",blink:!0},walking:{eyes:"open",mouth:"soft",motion:"walk",label:"Loki, walking",blink:!0},running:{eyes:"focused",mouth:"soft",motion:"run",label:"Loki, running"}},s="idle";function r(){return'<g class="legs"><path class="ink leg legL" d="M168 318v18"/><path class="ink foot footL" d="M158 336h20"/><path class="ink leg legR" d="M252 318v18"/><path class="ink foot footR" d="M242 336h20"/></g>'}function o(u,m,g){return m&&Object.prototype.hasOwnProperty.call(u,m)?u[m]:g||""}function n(u){var m=u.blink?" blink":"";return'<svg class="figure" viewBox="0 0 420 380" aria-hidden="true" focusable="false"><ellipse cx="210" cy="338" rx="120" ry="16" class="fillInkWash"/><g class="creature">'+r()+'<path class="fillPaper ink" d="M120 132c0-22 16-36 40-37 38-2 82-2 120 0 24 1 40 15 40 38v118c0 24-16 39-41 40-40 2-78 2-118 0-25-1-41-16-41-40z"/><path class="inkThin" d="M124 168c54-4 118-4 172 0"/><circle cx="146" cy="150" r="4.5" class="inkViolet"/><circle cx="164" cy="150" r="4.5" class="inkThinDot"/><circle cx="182" cy="150" r="4.5" class="inkThinDot"/><circle cx="170" cy="232" r="9" class="fillGlow"/><circle cx="252" cy="232" r="9" class="fillGlow"/>'+o(e,u.brow,"")+'<g class="eyes'+m+'">'+o(d,u.eyes,d.open)+"</g>"+o(t,u.mouth,t.smile)+'<path class="inkViolet" d="M150 280h120"/><path class="inkThin" d="M150 296h84"/>'+o(i,u.prop,"")+"</g></svg>"}var l=[":host{display:inline-block;line-height:0;","--lm-ink:var(--color-ink,#553de9);","--lm-ink-wash:var(--color-ink-wash,rgba(85,61,233,0.08));","--lm-text:var(--color-text,#201515);","--lm-paper:var(--color-paper-card,#fffdf8);","--lm-glow:var(--color-glow,#e8a33d);","--lm-glow-wash:var(--color-glow-wash,rgba(232,163,61,0.14));","--lm-seal:var(--color-seal,#1f8a52);","}",".figure{display:block;width:100%;height:auto;overflow:visible}",".ink{fill:none;stroke:var(--lm-text);stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}",".inkBold{fill:none;stroke:var(--lm-text);stroke-width:3.4;stroke-linecap:round;stroke-linejoin:round}",".inkThin{fill:none;stroke:var(--lm-text);stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}",".inkThinDot{fill:none;stroke:var(--lm-text);stroke-width:1.6}",".inkViolet{fill:none;stroke:var(--lm-ink);stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}",".fillPaper{fill:var(--lm-paper)}",".fillInk{fill:var(--lm-ink)}",".fillInkWash{fill:var(--lm-ink-wash)}",".fillGlow{fill:var(--lm-glow)}",".fillSeal{fill:var(--lm-seal)}",".fillGlass{fill:rgba(85,61,233,0.06)}",".fillHi{fill:var(--lm-paper)}",".prop-wave .fillPaper{fill:var(--lm-paper)}",".checkMark{fill:none;stroke:#fff;stroke-width:3.2;stroke-linecap:round;stroke-linejoin:round}",".zzz{font:600 26px var(--font-sans,system-ui,sans-serif);fill:var(--lm-ink)}",".m-breathe .creature{transform-box:fill-box;transform-origin:center;animation:lm-breathe 4.5s ease-in-out infinite}","@keyframes lm-breathe{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-2px) scale(1.012)}}",".m-bob .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-bob 2.2s ease-in-out infinite}","@keyframes lm-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-7px)}}",".m-bounce .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-bounce 0.9s cubic-bezier(.3,.7,.4,1) infinite}","@keyframes lm-bounce{0%,100%{transform:translateY(0) scaleY(1)}30%{transform:translateY(-22px) scaleY(1.05)}55%{transform:translateY(0) scaleY(.94)}70%{transform:translateY(-6px)}}",".m-wiggle .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-wiggle 3s ease-in-out infinite}","@keyframes lm-wiggle{0%,100%{transform:rotate(-1.5deg)}50%{transform:rotate(1.5deg)}}",".m-tilt .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-tilt 3.4s ease-in-out infinite}","@keyframes lm-tilt{0%,100%{transform:rotate(-4deg)}50%{transform:rotate(4deg)}}",".m-work .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-work 0.7s ease-in-out infinite}","@keyframes lm-work{0%,100%{transform:translateX(0) rotate(0)}25%{transform:translateX(-1.5px) rotate(-1deg)}75%{transform:translateX(1.5px) rotate(1deg)}}",".m-inspect .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-inspect 3.2s ease-in-out infinite}","@keyframes lm-inspect{0%,100%{transform:translate(0,0)}50%{transform:translate(6px,-2px)}}",".m-inspect .prop-magnifier{transform-box:fill-box;transform-origin:332px 250px;animation:lm-inspect-mag 3.2s ease-in-out infinite}","@keyframes lm-inspect-mag{0%,100%{transform:translate(0,0) scale(1)}50%{transform:translate(4px,4px) scale(1.08)}}",".m-shake .creature{transform-box:fill-box;transform-origin:center;animation:lm-shake 0.5s ease-in-out infinite}","@keyframes lm-shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-4px)}75%{transform:translateX(4px)}}",".m-launch .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-launch 1.6s ease-in-out infinite}","@keyframes lm-launch{0%{transform:translateY(0)}40%{transform:translateY(-3px)}70%{transform:translateY(-14px) rotate(-2deg)}100%{transform:translateY(0)}}",".m-wave .creature{transform-box:fill-box;transform-origin:center;animation:lm-breathe 4.5s ease-in-out infinite}",".m-sleep .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-sleep 5.5s ease-in-out infinite}","@keyframes lm-sleep{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-1px) scale(1.02)}}",".prop-wave{transform-box:fill-box;transform-origin:50% 100%;animation:lm-sway 1.1s ease-in-out infinite}","@keyframes lm-sway{0%,100%{transform:rotate(-8deg)}50%{transform:rotate(14deg)}}",".prop-think .d1{transform-box:fill-box;transform-origin:center;animation:lm-rise 2.4s ease-in-out infinite}",".prop-think .d2{transform-box:fill-box;transform-origin:center;animation:lm-rise 2.4s ease-in-out infinite .3s}",".prop-think .d3{transform-box:fill-box;transform-origin:center;animation:lm-rise 2.4s ease-in-out infinite .6s}","@keyframes lm-rise{0%{opacity:.2;transform:translateY(4px) scale(.7)}50%{opacity:1;transform:translateY(0) scale(1)}100%{opacity:.2;transform:translateY(-4px) scale(.7)}}",".zzz{opacity:0;transform-box:fill-box;transform-origin:center}",".prop-zzz .z1{animation:lm-zfloat 3s ease-in-out infinite}",".prop-zzz .z2{animation:lm-zfloat 3s ease-in-out infinite 1s}",".prop-zzz .z3{animation:lm-zfloat 3s ease-in-out infinite 2s}","@keyframes lm-zfloat{0%{opacity:0;transform:translateY(6px) scale(.7)}40%{opacity:1}100%{opacity:0;transform:translateY(-16px) scale(1.1)}}",".spin{transform-box:fill-box;transform-origin:332px 250px;animation:lm-spin 1s linear infinite}","@keyframes lm-spin{to{transform:rotate(360deg)}}",".prop-confetti>*{transform-box:fill-box;transform-origin:center;animation:lm-confetti 1.4s ease-in infinite}",".prop-confetti .c2{animation-delay:.15s}.prop-confetti .c3{animation-delay:.3s}",".prop-confetti .c4{animation-delay:.45s}.prop-confetti .c5{animation-delay:.2s}",".prop-confetti .c6{animation-delay:.5s}.prop-confetti .c7{animation-delay:.1s}","@keyframes lm-confetti{0%{opacity:0;transform:translateY(0) rotate(0)}20%{opacity:1}100%{opacity:0;transform:translateY(34px) rotate(180deg)}}",".prop-check{transform-box:fill-box;transform-origin:332px 246px;animation:lm-pop 2.4s ease-in-out infinite}","@keyframes lm-pop{0%,70%,100%{transform:scale(1)}80%{transform:scale(1.18)}}",".m-launch .prop-parcel{transform-box:fill-box;transform-origin:center;animation:lm-bob 1.6s ease-in-out infinite}",".m-walk .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-walkbody 0.8s ease-in-out infinite}","@keyframes lm-walkbody{0%,100%{transform:translateY(0) rotate(-1deg)}50%{transform:translateY(-4px) rotate(1deg)}}",".m-walk .legL{transform-box:fill-box;transform-origin:168px 318px;animation:lm-legswing 0.8s ease-in-out infinite}",".m-walk .footL{transform-box:fill-box;transform-origin:168px 336px;animation:lm-legswing 0.8s ease-in-out infinite}",".m-walk .legR{transform-box:fill-box;transform-origin:252px 318px;animation:lm-legswing 0.8s ease-in-out infinite .4s}",".m-walk .footR{transform-box:fill-box;transform-origin:252px 336px;animation:lm-legswing 0.8s ease-in-out infinite .4s}","@keyframes lm-legswing{0%,100%{transform:rotate(-16deg)}50%{transform:rotate(16deg)}}",".m-run .creature{transform-box:fill-box;transform-origin:center bottom;animation:lm-runbody 0.42s ease-in-out infinite}","@keyframes lm-runbody{0%,100%{transform:translateY(0) rotate(-4deg)}50%{transform:translateY(-7px) rotate(2deg)}}",".m-run .legL{transform-box:fill-box;transform-origin:168px 318px;animation:lm-runleg 0.42s ease-in-out infinite}",".m-run .footL{transform-box:fill-box;transform-origin:168px 336px;animation:lm-runleg 0.42s ease-in-out infinite}",".m-run .legR{transform-box:fill-box;transform-origin:252px 318px;animation:lm-runleg 0.42s ease-in-out infinite .21s}",".m-run .footR{transform-box:fill-box;transform-origin:252px 336px;animation:lm-runleg 0.42s ease-in-out infinite .21s}","@keyframes lm-runleg{0%,100%{transform:rotate(-30deg)}50%{transform:rotate(30deg)}}",".eyes.blink{transform-box:fill-box;transform-origin:center;animation:lm-blink 6s steps(1,end) infinite}","@keyframes lm-blink{0%,92%,100%{transform:scaleY(1)}95%{transform:scaleY(.1)}}","@media (prefers-reduced-motion: reduce){",".figure *{animation:none !important}",".eyes.blink{transform:scaleY(1) !important}",".zzz{opacity:1}",".prop-confetti>*{opacity:1}",".prop-think .d1,.prop-think .d2,.prop-think .d3{opacity:1}","}"].join("");function c(u){var m=parseFloat(u);return!isFinite(m)||m<=0?132:m<16?16:m>1024?1024:m}var p=function(){function u(){return class extends HTMLElement{static get observedAttributes(){return["emotion","size","motion"]}constructor(){super(),this.attachShadow({mode:"open"}),this._styleEl=document.createElement("style"),this._styleEl.textContent=l,this._wrap=document.createElement("div"),this._wrap.className="lm-root",this.shadowRoot.appendChild(this._styleEl),this.shadowRoot.appendChild(this._wrap)}connectedCallback(){this._render()}attributeChangedCallback(){this.shadowRoot&&this._render()}_render(){var g=(this.getAttribute("emotion")||s).toLowerCase(),k=a[g]||a[s],x=(this.getAttribute("motion")||k.motion||"breathe").toLowerCase(),_=c(this.getAttribute("size")||"132");this.style.width=_+"px",this.setAttribute("role","img"),this.setAttribute("aria-label",k.label||"Loki"),this._wrap.className="lm-root m-"+x,this._wrap.innerHTML=n(k)}}}return customElements.get("loki-mascot")||customElements.define("loki-mascot",u()),customElements.get("loki-mascot")}();try{p.emotions=Object.keys(a),p.getEmotion=function(u){var m=(u||s).toLowerCase(),g=a[m]||a[s];return Object.assign({name:m},g)},p.renderStandaloneSVG=function(u){var m=p.getEmotion(u),g=m.motion||"breathe",k=l.replace(":host{","svg.loki-figure{"),x=n(m).replace('<svg class="figure"','<svg xmlns="http://www.w3.org/2000/svg" class="figure loki-figure m-'+g+'" role="img" aria-label="'+(m.label||"Loki")+'"').replace('aria-hidden="true" focusable="false"','focusable="false"');return x.replace("</svg>","<style>"+k+"</style></svg>")}}catch{}})();function ii(d){switch((d||"").toLowerCase()){case"running":case"autonomous":return"building";case"paused":return"sleeping";default:return"idle"}}var Te=class extends HTMLElement{static get observedAttributes(){return["api-url","size"]}constructor(){super(),this.attachShadow({mode:"open"}),this._status="idle",this._api=null,this._statusHandler=null,this._discHandler=null,this._poll=null}connectedCallback(){this._setupApi(),this._loadStatus(),this._startPolling(),this.render()}disconnectedCallback(){this._poll&&(this._poll.stop(),this._poll=null),this._teardownApiListeners()}_teardownApiListeners(){this._api&&(this._statusHandler&&this._api.removeEventListener(f.STATUS_UPDATE,this._statusHandler),this._discHandler&&this._api.removeEventListener(f.DISCONNECTED,this._discHandler))}attributeChangedCallback(e,t,i){t!==i&&(e==="api-url"&&this._api&&(this._teardownApiListeners(),this._setupApi(),this._loadStatus()),e==="size"&&this.render())}_setupApi(){let e=this.getAttribute("api-url")||window.location.origin;this._api=h({baseUrl:e}),this._statusHandler=t=>this._updateFromStatus(t.detail),this._discHandler=()=>{this._status="offline",this.render()},this._api.addEventListener(f.STATUS_UPDATE,this._statusHandler),this._api.addEventListener(f.DISCONNECTED,this._discHandler)}_startPolling(){this._poll=b({loadFn:()=>this._loadStatus(),intervalMs:1e4,sectionId:null,immediate:!1})}async _loadStatus(){let e=this._api;try{let t=await e.getStatus();if(e!==this._api)return;this._updateFromStatus(t)}catch{if(e!==this._api)return;this._status="offline",this.render()}}_updateFromStatus(e){if(!e)return;let t=e.status||"idle";t!==this._status&&(this._status=t,this.render())}render(){if(!this.shadowRoot)return;let e=this.getAttribute("size")||"34",t=ii(this._status);this.shadowRoot.innerHTML=`
15674
14594
  <style>
15675
14595
  :host { display: inline-flex; align-items: center; line-height: 0; }
15676
14596
  loki-mascot { display: inline-block; }
15677
14597
  </style>
15678
14598
  <loki-mascot emotion="${t}" size="${e}"></loki-mascot>
15679
- `}};customElements.get("loki-mascot-presence")||customElements.define("loki-mascot-presence",Pe);var gi="1.4.0";function mi(d={}){return d.theme?w.setTheme(d.theme):d.autoDetectContext!==!1?w.init():U.init(),d.apiUrl&&h({baseUrl:d.apiUrl}),{theme:w.getTheme(),context:w.detectContext()}}return It(vi);})();
14599
+ `}};customElements.get("loki-mascot-presence")||customElements.define("loki-mascot-presence",Te);var ai="1.4.0";function si(d={}){return d.theme?w.setTheme(d.theme):d.autoDetectContext!==!1?w.init():U.init(),d.apiUrl&&h({baseUrl:d.apiUrl}),{theme:w.getTheme(),context:w.detectContext()}}return Et(ri);})();
15680
14600
 
15681
14601
 
15682
14602
  // Initialize dashboard when DOM is ready
@@ -16116,15 +15036,16 @@ document.addEventListener('DOMContentLoaded', function() {
16116
15036
  return;
16117
15037
  }
16118
15038
  badge.classList.remove('empty');
16119
- // "N receipts - M verified" with the verified count emphasized.
15039
+ // "N receipts - M recorded verified". The count is each receipt's own
15040
+ // recorded headline (/api/proofs/summary), not re-verified here.
16120
15041
  textEl.innerHTML = plural(total, 'receipt') + ' - '
16121
- + '<span class="receipts-verified"></span> verified';
15042
+ + '<span class="receipts-verified"></span> recorded verified';
16122
15043
  var vEl = textEl.querySelector('.receipts-verified');
16123
15044
  if (vEl) vEl.textContent = String(verified);
16124
15045
  badge.title = plural(verified, 'receipt') + ' of ' + total
16125
- + ' verified by a deterministic Evidence Receipt (re-verifiable with '
16126
- + '"loki proof verify"). "Verified" means tests passed with real '
16127
- + 'exit-code evidence, not an LLM opinion.';
15046
+ + ' recorded a VERIFIED headline (tests passed with real exit-code '
15047
+ + 'evidence, not an LLM opinion). Recorded by the generator and not '
15048
+ + 're-verified here: check one with "loki proof verify <run-id>".';
16128
15049
  badge.classList.add('show');
16129
15050
  }
16130
15051
 
@@ -16146,7 +15067,7 @@ document.addEventListener('DOMContentLoaded', function() {
16146
15067
  var lim = d.budget_limit;
16147
15068
  var cur = d.current_cost;
16148
15069
  var curTxt = (cur === null || cur === undefined) ? 'not measured'
16149
- : ('$' + Number(cur).toFixed(2));
15070
+ : ('$' + Number(cur).toFixed(2) + (d.partial ? ' (partial)' : ''));
16150
15071
  if (lim === null || lim === undefined) {
16151
15072
  el.style.borderColor = 'var(--loki-warning)';
16152
15073
  el.innerHTML = '<strong>No spend cap set.</strong> This run will not stop on cost. '
@@ -16158,7 +15079,7 @@ document.addEventListener('DOMContentLoaded', function() {
16158
15079
  + ', spent ' + curTxt + '.';
16159
15080
  } else {
16160
15081
  var rem = (d.remaining === null || d.remaining === undefined)
16161
- ? 'not measured' : ('$' + Number(d.remaining).toFixed(2));
15082
+ ? 'not measured' : ((d.partial ? 'at most ' : '') + '$' + Number(d.remaining).toFixed(2));
16162
15083
  el.style.borderColor = 'var(--loki-border)';
16163
15084
  el.innerHTML = 'Spend cap $' + Number(lim).toFixed(2)
16164
15085
  + '. Spent ' + curTxt + ', remaining ' + rem + '.';
@@ -16189,6 +15110,9 @@ document.addEventListener('DOMContentLoaded', function() {
16189
15110
  var rows = Array.isArray(d) ? d : (d.learnings || []);
16190
15111
  if (!rows.length) return; // nothing learned yet: say nothing
16191
15112
  rows = rows.slice().reverse().slice(0, 8);
15113
+ // Every field is untrusted text (written by the run) going into
15114
+ // innerHTML, so each one is escaped.
15115
+ var esc = function (v) { var e = document.createElement('div'); e.textContent = String(v); return e.innerHTML; };
16192
15116
  var html = '';
16193
15117
  for (var i = 0; i < rows.length; i++) {
16194
15118
  var x = rows[i] || {};
@@ -16196,13 +15120,13 @@ document.addEventListener('DOMContentLoaded', function() {
16196
15120
  var iter = (x.iteration === null || x.iteration === undefined) ? '-' : ('iter ' + x.iteration);
16197
15121
  html += '<div style="padding:8px;border-bottom:1px solid var(--loki-border);font-size:12px;">'
16198
15122
  + '<div style="display:flex;gap:10px;color:var(--loki-text-muted);margin-bottom:4px;">'
16199
- + '<span>' + when + '</span><span>' + iter + '</span>'
16200
- + '<span>' + String(x.trigger || 'unknown trigger') + '</span></div>'
15123
+ + '<span>' + esc(when) + '</span><span>' + esc(iter) + '</span>'
15124
+ + '<span>' + esc(x.trigger || 'unknown trigger') + '</span></div>'
16201
15125
  + '<div style="margin-bottom:3px;"><strong>cause:</strong> '
16202
- + String(x.rootCause || 'not recorded') + '</div>'
16203
- + (x.fix ? '<div style="margin-bottom:3px;"><strong>fix:</strong> ' + String(x.fix) + '</div>' : '')
15126
+ + esc(x.rootCause || 'not recorded') + '</div>'
15127
+ + (x.fix ? '<div style="margin-bottom:3px;"><strong>fix:</strong> ' + esc(x.fix) + '</div>' : '')
16204
15128
  + (x.preventInFuture ? '<div style="color:var(--loki-text-muted);"><strong>prevent:</strong> '
16205
- + String(x.preventInFuture) + '</div>' : '')
15129
+ + esc(x.preventInFuture) + '</div>' : '')
16206
15130
  + '</div>';
16207
15131
  }
16208
15132
  list.innerHTML = html;
@@ -16231,11 +15155,18 @@ document.addEventListener('DOMContentLoaded', function() {
16231
15155
  var rows = Array.isArray(d) ? d : (d.proofs || d.receipts || []);
16232
15156
  if (!rows.length) return; // no receipts yet: say nothing
16233
15157
  rows = rows.slice().reverse().slice(0, 10);
15158
+ // Every field is untrusted text (written by the run) going into
15159
+ // innerHTML, so each one is escaped.
15160
+ var esc = function (v) { var e = document.createElement('div'); e.textContent = String(v); return e.innerHTML; };
16234
15161
  var html = '';
16235
15162
  for (var i = 0; i < rows.length; i++) {
16236
15163
  var x = rows[i] || {};
16237
- var verdict = x.headline || x.final_verdict || 'UNKNOWN';
16238
- var verified = /^VERIFIED/i.test(verdict);
15164
+ // Recorded values, labelled: the receipt's own headline, else the
15165
+ // council vote. Success colour only for an exact VERIFIED headline
15166
+ // ("VERIFIED WITH GAPS" is not a success).
15167
+ var verdict = x.headline ? x.headline
15168
+ : (x.final_verdict ? 'council ' + x.final_verdict : 'UNKNOWN');
15169
+ var verified = x.headline === 'VERIFIED';
16239
15170
  var col = verified ? 'var(--loki-success)' : 'var(--loki-text-muted)';
16240
15171
  var files = (x.files_changed === null || x.files_changed === undefined)
16241
15172
  ? '-' : String(x.files_changed);
@@ -16249,9 +15180,9 @@ document.addEventListener('DOMContentLoaded', function() {
16249
15180
  html += '<div style="display:flex;gap:12px;align-items:center;padding:6px 8px;'
16250
15181
  + 'border-bottom:1px solid var(--loki-border);font-size:12px;">'
16251
15182
  + '<span style="color:' + col + ';font-weight:600;min-width:130px;">'
16252
- + String(verdict).slice(0, 22) + '</span>'
16253
- + '<span style="color:var(--loki-text-muted);min-width:120px;">' + when + '</span>'
16254
- + '<span style="min-width:90px;">' + files + ' files</span>'
15183
+ + esc(String(verdict).slice(0, 22)) + '</span>'
15184
+ + '<span style="color:var(--loki-text-muted);min-width:120px;">' + esc(when) + '</span>'
15185
+ + '<span style="min-width:90px;">' + esc(files) + ' files</span>'
16255
15186
  + '<span style="min-width:70px;">' + cost + '</span>'
16256
15187
  + link + '</div>';
16257
15188
  }
@@ -16306,11 +15237,11 @@ document.addEventListener('DOMContentLoaded', function() {
16306
15237
  var html = '';
16307
15238
  for (var i = 0; i < rows.length; i++) {
16308
15239
  var x = rows[i] || {};
16309
- // ESCAPED, unlike the verdict in loadReceipts. That comes from a
16310
- // controlled set; a phase name does not -- api_phases.py passes
16311
- // names through verbatim and _advance_current_phase accepts ANY
16312
- // string, so the set is open and this is untrusted text going into
16313
- // innerHTML on a dashboard that can be bound remotely.
15240
+ // ESCAPED, like every field in loadReceipts and loadLearnings.
15241
+ // api_phases.py passes names through verbatim and
15242
+ // _advance_current_phase accepts ANY string, so this is untrusted
15243
+ // text going into innerHTML on a dashboard that can be bound
15244
+ // remotely.
16314
15245
  var raw = String(x.phase || 'UNKNOWN');
16315
15246
  var _d = document.createElement('div');
16316
15247
  _d.textContent = raw;