loki-mode 9.54.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.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/completion-council.sh +10 -1
- package/autonomy/lib/proof-generator.py +36 -5
- package/autonomy/run.sh +234 -31
- package/dashboard/__init__.py +1 -1
- package/dashboard/api_v2.py +4 -0
- package/dashboard/audit.py +9 -1
- package/dashboard/auth.py +16 -4
- package/dashboard/registry.py +34 -12
- package/dashboard/rigour_integration.py +25 -17
- package/dashboard/server.py +252 -104
- package/dashboard/static/cost.html +55 -26
- package/dashboard/static/index.html +475 -1544
- package/dashboard/static/proofs.html +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/air-gapped.md +7 -2
- package/docs/image-provenance.md +4 -2
- package/docs/v10/BACKLOG.md +41 -2
- package/docs/v10/BOARD.md +105 -0
- package/docs/v10/DECISIONS.md +71 -0
- package/docs/v10/PROGRESS.md +43 -0
- package/docs/v10/SWARM-PROMPT.md +98 -0
- package/docs/v10/SWARM.md +237 -0
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/providers/aider.sh +8 -0
- package/providers/cline.sh +8 -0
- package/providers/codex.sh +9 -0
- package/providers/opencode.sh +9 -0
- package/web-app/dist/assets/AdminPage-CZrBkzRF.js +32 -0
- package/web-app/dist/assets/Avatar-gQIp6FBI.js +11 -0
- package/web-app/dist/assets/{Badge-BF3mhT57.js → Badge-D2_fBTFY.js} +1 -1
- package/web-app/dist/assets/{Button-BDp9aJ9q.js → Button-D5qDd2ef.js} +1 -1
- package/web-app/dist/assets/CockpitPage-DVMk2RUK.js +47 -0
- package/web-app/dist/assets/ComparePage-NMLyE1xL.js +1 -0
- package/web-app/dist/assets/{ErrorBoundary-ut3wrUmu.js → ErrorBoundary-BRABI-BT.js} +1 -1
- package/web-app/dist/assets/EvidenceReceiptPanel-D2LNKqUx.js +1 -0
- package/web-app/dist/assets/GitHubIssuesPanel-BC5GzKUN.js +7 -0
- package/web-app/dist/assets/{GitHubPRsPanel-DurZgSaj.js → GitHubPRsPanel-BSlmoVTS.js} +3 -3
- package/web-app/dist/assets/HomePage-D_CDMoen.js +12 -0
- package/web-app/dist/assets/{LoginPage-HeRGJeZy.js → LoginPage-BBNA_N9t.js} +1 -1
- package/web-app/dist/assets/{MagicPage-CUKrqsZs.js → MagicPage-CnFRZCMx.js} +1 -1
- package/web-app/dist/assets/MetricsPage-CPfLMRlh.js +6 -0
- package/web-app/dist/assets/{NotFoundPage-BZDZ-B77.js → NotFoundPage-lA0XSGTz.js} +1 -1
- package/web-app/dist/assets/ProjectPage-CNAPbr9z.js +256 -0
- package/web-app/dist/assets/ProjectsPage-CMtm8goN.js +6 -0
- package/web-app/dist/assets/SettingsPage-BhIjVMYE.js +10 -0
- package/web-app/dist/assets/{ShowcasePage-BGS2jTGH.js → ShowcasePage-BndtGeYo.js} +1 -1
- package/web-app/dist/assets/SystemSettingsPage-euXI-KXE.js +1 -0
- package/web-app/dist/assets/TeamsPage-ClUKecun.js +11 -0
- package/web-app/dist/assets/TemplatesPage-BWHWVk0L.js +29 -0
- package/web-app/dist/assets/{TerminalOutput-togzv9Zl.js → TerminalOutput-Cv3N3Szf.js} +1 -1
- package/web-app/dist/assets/{activity-Dreyb_Kr.js → activity-dEhz-bXR.js} +1 -1
- package/web-app/dist/assets/{bell-DWH0drES.js → bell-B3XUMq1t.js} +1 -1
- package/web-app/dist/assets/{bot-78MoCuDl.js → bot-X-ssNlwR.js} +1 -1
- package/web-app/dist/assets/{check-ikfylPst.js → check-C_9Nx7kb.js} +1 -1
- package/web-app/dist/assets/{chevron-left-DXUqkd8J.js → chevron-left-tvNswo3A.js} +1 -1
- package/web-app/dist/assets/{circle-alert-Da74VO8P.js → circle-alert-CSB88nEs.js} +1 -1
- package/web-app/dist/assets/{clock-mlGCFq8l.js → clock-C8p2e4NI.js} +1 -1
- package/web-app/dist/assets/{cloud-B_Y5ZrIO.js → cloud-CKp2ZvhG.js} +1 -1
- package/web-app/dist/assets/{code-xml-Bbom7YWV.js → code-xml-dY70LCHD.js} +1 -1
- package/web-app/dist/assets/{database-CLcofiVp.js → database-DObn5fmn.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-C5mkjXIM.js → dollar-sign-DSu6n3K3.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-CVrkaOQP.js → file-code-corner-DpCnS73z.js} +1 -1
- package/web-app/dist/assets/{file-plus-BV9240gX.js → file-plus-D3IPKCf1.js} +1 -1
- package/web-app/dist/assets/{globe-aZ0Zso4I.js → globe-C9QXkgH_.js} +1 -1
- package/web-app/dist/assets/{hammer-EgOQNukG.js → hammer-D_FtWe1y.js} +1 -1
- package/web-app/dist/assets/index-CI54rara.css +1 -0
- package/web-app/dist/assets/{index-DvZ0Kk2x.js → index-Cz7q1bvC.js} +2 -2
- package/web-app/dist/assets/{layers-BOVKmepE.js → layers-DsW7jnJX.js} +1 -1
- package/web-app/dist/assets/{loader-circle-0K8yLgHl.js → loader-circle-B3HspjKR.js} +1 -1
- package/web-app/dist/assets/{lock-XzlDMy8M.js → lock-DSI29pct.js} +1 -1
- package/web-app/dist/assets/{package-BtXTKusI.js → package-CLNxtA2x.js} +1 -1
- package/web-app/dist/assets/{plus-PxeiD8ju.js → plus-DyI4WC4_.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-CjqzYczt.js → refresh-cw-D2dv0xA0.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-CY0os4DH.js → rotate-ccw-CBvihA-a.js} +1 -1
- package/web-app/dist/assets/scroll-text-DvoOvAl_.js +6 -0
- package/web-app/dist/assets/{server-pIIs9vNp.js → server-DenWvSUt.js} +1 -1
- package/web-app/dist/assets/{shield-alert-CsDqKXwA.js → shield-alert-40cX_FvG.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-CAh3HVzH.js → thumbs-up-BrjZ6QuV.js} +12 -7
- package/web-app/dist/assets/trash-2-C6evwkEH.js +16 -0
- package/web-app/dist/assets/{trending-down-DrtBd_C9.js → trending-down-CfbZis3O.js} +1 -1
- package/web-app/dist/assets/{trending-up-D-DbCHXm.js → trending-up-DWuEK3WC.js} +1 -1
- package/web-app/dist/assets/{upload-D4l6DCOt.js → upload-B9DFBcPG.js} +1 -1
- package/web-app/dist/assets/{usePolling-D0aoTX80.js → usePolling-BryVC-T1.js} +1 -1
- package/web-app/dist/assets/{user-BQf_XJO_.js → user-DMRXwZiw.js} +1 -1
- package/web-app/dist/index.html +2 -2
- package/web-app/server.py +122 -47
- package/web-app/dist/assets/AdminPage-y6_b2Xo4.js +0 -32
- package/web-app/dist/assets/Avatar-BFPkXhIJ.js +0 -6
- package/web-app/dist/assets/CockpitPage-5TKICCoA.js +0 -47
- package/web-app/dist/assets/ComparePage-BSuNsUHy.js +0 -1
- package/web-app/dist/assets/EvidenceReceiptPanel-CcaBwEI-.js +0 -1
- package/web-app/dist/assets/GitHubIssuesPanel-DJeYgzAa.js +0 -12
- package/web-app/dist/assets/HomePage-Bs451LAy.js +0 -28
- package/web-app/dist/assets/MetricsPage-DvY1csgz.js +0 -6
- package/web-app/dist/assets/ProjectPage-CqHkEZkl.js +0 -257
- package/web-app/dist/assets/ProjectsPage-CLvCK1Y8.js +0 -6
- package/web-app/dist/assets/SettingsPage-DP7OmdwP.js +0 -10
- package/web-app/dist/assets/SystemSettingsPage-P_rlLh0x.js +0 -1
- package/web-app/dist/assets/TeamsPage-DxtBDcBC.js +0 -11
- package/web-app/dist/assets/TemplatesPage-5e-faH3W.js +0 -29
- package/web-app/dist/assets/folder-open-D_6yV78G.js +0 -11
- package/web-app/dist/assets/index-BSgmPwC0.css +0 -1
- package/web-app/dist/assets/lightbulb-DdASgqOG.js +0 -6
- package/web-app/dist/assets/mail-COu670_W.js +0 -6
- package/web-app/dist/assets/minus-bQpUt9ff.js +0 -6
- package/web-app/dist/assets/save-v8qep5cY.js +0 -6
- 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
|
-
|
|
1367
|
-
|
|
1368
|
-
if (
|
|
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 =
|
|
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
|
|
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: ${
|
|
1862
|
-
--loki-space-sm: ${
|
|
1863
|
-
--loki-space-md: ${
|
|
1864
|
-
--loki-space-lg: ${
|
|
1865
|
-
--loki-space-xl: ${
|
|
1866
|
-
--loki-space-2xl: ${
|
|
1867
|
-
--loki-space-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: ${
|
|
1871
|
-
--loki-radius-sm: ${
|
|
1872
|
-
--loki-radius-md: ${
|
|
1873
|
-
--loki-radius-lg: ${
|
|
1874
|
-
--loki-radius-xl: ${
|
|
1875
|
-
--loki-radius-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: ${
|
|
1892
|
-
--loki-duration-normal: ${
|
|
1893
|
-
--loki-duration-slow: ${
|
|
1894
|
-
--loki-easing-default: ${
|
|
1895
|
-
--loki-transition: ${
|
|
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: ${
|
|
1899
|
-
--loki-z-sticky: ${
|
|
1900
|
-
--loki-z-modal: ${
|
|
1901
|
-
--loki-z-popover: ${
|
|
1902
|
-
--loki-z-tooltip: ${
|
|
1903
|
-
--loki-z-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
|
|
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: ${
|
|
2187
|
+
@media (max-width: ${ze.md}) {
|
|
2186
2188
|
.hide-mobile { display: none !important; }
|
|
2187
2189
|
}
|
|
2188
2190
|
|
|
2189
|
-
@media (min-width: ${
|
|
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
|
-
${
|
|
2197
|
+
${K()}
|
|
2196
2198
|
}
|
|
2197
|
-
${
|
|
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=
|
|
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
|
-
`,
|
|
2295
|
-
`)}static applyToElement(e,t=null){let i=
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}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>${
|
|
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(),
|
|
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
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}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(/^>\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
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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
|
|
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 ${
|
|
2427
|
-
${
|
|
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
|
|
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
|
-
${
|
|
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"?"
|
|
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,
|
|
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):"
|
|
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",
|
|
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,
|
|
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(
|
|
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
|
|
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">${_?"✓":""}</span>
|
|
2744
|
-
<span class="criteria-text ${_?"done":""}">${this._escapeHtml(String(
|
|
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
|
|
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">${
|
|
2757
|
-
${
|
|
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
|
|
2771
|
-
${
|
|
2772
|
-
${
|
|
2773
|
-
${_?`<span class="log-phase ${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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",
|
|
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",
|
|
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=
|
|
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",
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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">${
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
${
|
|
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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}_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
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
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
|
|
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(([
|
|
5442
|
+
${Object.entries(t||{}).map(([r,o])=>`
|
|
5467
5443
|
<div class="breakdown-item">
|
|
5468
|
-
<span class="breakdown-label">${this._escapeHtml(
|
|
5469
|
-
<span class="breakdown-value">${this._formatNumber(
|
|
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(([
|
|
5458
|
+
${Object.entries(i||{}).map(([r,o])=>`
|
|
5483
5459
|
<div class="breakdown-item">
|
|
5484
|
-
<span class="breakdown-label source-badge ${this._escapeHtml(
|
|
5485
|
-
<span class="breakdown-value">${this._formatNumber(
|
|
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(
|
|
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: ${
|
|
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">${
|
|
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
|
|
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
|
-
|
|
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">${
|
|
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",
|
|
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
|
|
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
|
-
${
|
|
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
|
|
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
|
|
6468
|
-
${
|
|
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">${
|
|
6474
|
-
<div class="stat-sub">${
|
|
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 ${
|
|
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 ${
|
|
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">${
|
|
6489
|
-
<div class="stat-sub"
|
|
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 ${
|
|
6494
|
-
${
|
|
6469
|
+
<div class="stat-value ${o?.result==="APPROVED"?"text-green":"text-muted"}">
|
|
6470
|
+
${o?o.result:this._verdicts?"None":"--"}
|
|
6495
6471
|
</div>
|
|
6496
|
-
${
|
|
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
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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",
|
|
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:
|
|
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
|
|
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)=>(
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}};customElements.define("loki-checklist-viewer",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}};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
|
|
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
|
-
${
|
|
7472
|
+
${a?this._renderActions(t):""}
|
|
7497
7473
|
</div>
|
|
7498
|
-
${
|
|
7499
|
-
${
|
|
7500
|
-
${
|
|
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||"
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}};customElements.define("loki-app-status",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}};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||"
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}};customElements.define("loki-app-preview",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}};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:
|
|
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",
|
|
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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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: ${
|
|
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="${
|
|
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 ${
|
|
8472
|
-
cx="90" cy="90" r="${
|
|
8456
|
+
class="gauge-ring ${o}"
|
|
8457
|
+
cx="90" cy="90" r="${n}"
|
|
8473
8458
|
fill="none"
|
|
8474
|
-
stroke="${
|
|
8459
|
+
stroke="${r}"
|
|
8475
8460
|
stroke-width="12"
|
|
8476
8461
|
stroke-linecap="round"
|
|
8477
|
-
stroke-dasharray="${
|
|
8478
|
-
stroke-dashoffset="${
|
|
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
|
-
${
|
|
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(
|
|
8497
|
-
<div class="card-sub">${this._formatTokens(
|
|
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(
|
|
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">${
|
|
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">${
|
|
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(
|
|
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(
|
|
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"
|
|
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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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
|
|
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">${
|
|
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">${
|
|
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: ${
|
|
8990
|
+
<div class="card-value" style="color: ${Je.critical}">${a}</div>
|
|
9006
8991
|
</div>
|
|
9007
8992
|
</div>
|
|
9008
|
-
${
|
|
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":
|
|
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))
|
|
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?""
|
|
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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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">
|
|
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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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
|
|
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
|
-
${
|
|
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="${
|
|
9981
|
-
<span class="change-arrow ${
|
|
9982
|
-
${this._escapeHtml(
|
|
9965
|
+
<button class="change-header" data-index="${u}">
|
|
9966
|
+
<span class="change-arrow ${m?"expanded":""}">▶</span>
|
|
9967
|
+
${this._escapeHtml(p.description||p.title||"Change")}
|
|
9983
9968
|
</button>
|
|
9984
|
-
${
|
|
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"
|
|
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(
|
|
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">${
|
|
9995
|
+
<div class="info-value">${o}</div>
|
|
10011
9996
|
</div>
|
|
10012
9997
|
</div>
|
|
10013
9998
|
|
|
10014
|
-
${
|
|
9999
|
+
${l}
|
|
10015
10000
|
</div>
|
|
10016
|
-
`;let
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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
|
|
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
|
|
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[
|
|
10393
|
+
<span class="category-name">${c[x]||x}</span>
|
|
10409
10394
|
<div class="progress-bar">
|
|
10410
|
-
|
|
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(
|
|
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
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"):""}_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
|
-
${
|
|
10440
|
+
${lt[a]}
|
|
10456
10441
|
</div>
|
|
10457
10442
|
</div>
|
|
10458
|
-
`}).join("")}_renderFeatureStats(e){if(!e)return"";let t=e.
|
|
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">${
|
|
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.
|
|
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-
|
|
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||"
|
|
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>${
|
|
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",
|
|
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
|
|
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=
|
|
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
|
|
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">${
|
|
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(
|
|
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",
|
|
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} · ${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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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=
|
|
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||"
|
|
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: ${
|
|
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",
|
|
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=
|
|
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=
|
|
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">${
|
|
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">${
|
|
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">${
|
|
12069
|
-
title="Cycle ${a+1}: ${n.label} - ${
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}render(){let e=this.shadowRoot;if(!e)return;let t=this.runId,i=this._timeline,a=i?.phases||[],s=i?.current_phase||null,r=
|
|
12074
|
+
`}_escapeHtml(e){return e?String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}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}: ${
|
|
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">${
|
|
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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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||"
|
|
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>${
|
|
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(
|
|
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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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">${
|
|
12525
|
+
<div class="summary-value">${gt(e.total_cost_usd)}${t}</div>
|
|
12526
12526
|
</div>
|
|
12527
12527
|
</div>
|
|
12528
|
-
|
|
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
|
|
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">${
|
|
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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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
|
|
12835
|
-
<div class="verify-result
|
|
12836
|
-
${
|
|
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>${
|
|
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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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
|
|
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>${
|
|
13290
|
-
<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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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?
|
|
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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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
|
-
.
|
|
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:
|
|
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
|
-
.
|
|
13492
|
-
|
|
13493
|
-
|
|
13494
|
-
|
|
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:
|
|
13508
|
+
padding: 20px;
|
|
13497
13509
|
}
|
|
13498
13510
|
|
|
13499
|
-
.
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
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
|
-
.
|
|
13515
|
-
|
|
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
|
-
.
|
|
13519
|
-
|
|
13520
|
-
|
|
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
|
-
.
|
|
13524
|
-
|
|
13525
|
-
|
|
13526
|
-
|
|
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
|
-
.
|
|
13533
|
-
|
|
13534
|
-
|
|
13535
|
-
|
|
13536
|
-
|
|
13537
|
-
|
|
13538
|
-
|
|
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
|
-
.
|
|
13542
|
-
|
|
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
|
-
.
|
|
13546
|
-
|
|
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
|
-
.
|
|
13550
|
-
|
|
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
|
-
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
|
|
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
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13598
|
+
.running-total-line svg {
|
|
13599
|
+
width: 100%;
|
|
13600
|
+
height: 100%;
|
|
13567
13601
|
}
|
|
13568
13602
|
|
|
13569
|
-
.
|
|
13570
|
-
|
|
13571
|
-
|
|
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
|
-
.
|
|
13618
|
+
.summary-row {
|
|
13575
13619
|
display: flex;
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
|
|
13579
|
-
flex: 1;
|
|
13580
|
-
min-width: 0;
|
|
13620
|
+
gap: 16px;
|
|
13621
|
+
margin-top: 16px;
|
|
13622
|
+
flex-wrap: wrap;
|
|
13581
13623
|
}
|
|
13582
13624
|
|
|
13583
|
-
.
|
|
13584
|
-
width: 22px;
|
|
13585
|
-
height: 22px;
|
|
13586
|
-
border-radius: 4px;
|
|
13625
|
+
.summary-item {
|
|
13587
13626
|
display: flex;
|
|
13588
13627
|
align-items: center;
|
|
13589
|
-
|
|
13590
|
-
font-size:
|
|
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
|
-
.
|
|
13598
|
-
|
|
13599
|
-
|
|
13600
|
-
|
|
13601
|
-
|
|
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
|
-
.
|
|
13606
|
-
|
|
13607
|
-
font-
|
|
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
|
-
.
|
|
13616
|
-
font-size: 10px;
|
|
13644
|
+
.summary-value {
|
|
13617
13645
|
font-family: 'JetBrains Mono', monospace;
|
|
13618
13646
|
color: var(--loki-text-muted, #939084);
|
|
13619
|
-
|
|
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
|
-
|
|
13634
|
-
|
|
13635
|
-
|
|
13636
|
-
|
|
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
|
-
|
|
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
|
-
|
|
13672
|
-
|
|
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
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
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">✓</span>':c?'<span class="stage-check">✗</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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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">✕</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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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
|
-
${
|
|
14504
|
-
${
|
|
13689
|
+
${n}
|
|
13690
|
+
${l}
|
|
14505
13691
|
<div class="tooltip"></div>
|
|
14506
13692
|
</div>
|
|
14507
13693
|
<div class="summary-row">
|
|
14508
|
-
${
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}_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-
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}_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 ${
|
|
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"
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}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+" · "+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",
|
|
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+" · "+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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}_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+" · Reject: "+u+" · 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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}_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=
|
|
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
|
-
${
|
|
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",
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}_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
|
-
${
|
|
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",
|
|
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"
|
|
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
|
-
+ '
|
|
16126
|
-
+ '
|
|
16127
|
-
+ '
|
|
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>' +
|
|
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
|
-
+
|
|
16203
|
-
+ (x.fix ? '<div style="margin-bottom:3px;"><strong>fix:</strong> ' +
|
|
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
|
-
+
|
|
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
|
-
|
|
16238
|
-
|
|
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,
|
|
16310
|
-
//
|
|
16311
|
-
//
|
|
16312
|
-
//
|
|
16313
|
-
//
|
|
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;
|