@0xmaxma/claude-gateway 2.0.5 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dist/agent/runner.d.ts +14 -0
  2. package/dist/agent/runner.d.ts.map +1 -1
  3. package/dist/agent/runner.js +75 -71
  4. package/dist/agent/runner.js.map +1 -1
  5. package/dist/agent/session-compaction-scheduler.d.ts +22 -0
  6. package/dist/agent/session-compaction-scheduler.d.ts.map +1 -0
  7. package/dist/agent/session-compaction-scheduler.js +40 -0
  8. package/dist/agent/session-compaction-scheduler.js.map +1 -0
  9. package/dist/api/gateway-router.d.ts.map +1 -1
  10. package/dist/api/gateway-router.js +100 -10
  11. package/dist/api/gateway-router.js.map +1 -1
  12. package/dist/api/memory-activity.d.ts +18 -0
  13. package/dist/api/memory-activity.d.ts.map +1 -0
  14. package/dist/api/memory-activity.js +97 -0
  15. package/dist/api/memory-activity.js.map +1 -0
  16. package/dist/orchestration/agent-tool-schemas.js +1 -1
  17. package/dist/orchestration/agent-tool-schemas.js.map +1 -1
  18. package/dist/orchestration/bridge.js +1 -1
  19. package/dist/orchestration/bridge.js.map +1 -1
  20. package/dist/orchestration/compact-measurements.d.ts +21 -0
  21. package/dist/orchestration/compact-measurements.d.ts.map +1 -0
  22. package/dist/orchestration/compact-measurements.js +62 -0
  23. package/dist/orchestration/compact-measurements.js.map +1 -0
  24. package/dist/orchestration/config.d.ts +4 -0
  25. package/dist/orchestration/config.d.ts.map +1 -1
  26. package/dist/orchestration/config.js +1 -1
  27. package/dist/orchestration/config.js.map +1 -1
  28. package/dist/orchestration/context-delivery.d.ts +32 -0
  29. package/dist/orchestration/context-delivery.d.ts.map +1 -0
  30. package/dist/orchestration/context-delivery.js +101 -0
  31. package/dist/orchestration/context-delivery.js.map +1 -0
  32. package/dist/orchestration/conversation-intake.d.ts +10 -6
  33. package/dist/orchestration/conversation-intake.d.ts.map +1 -1
  34. package/dist/orchestration/conversation-intake.js +22 -8
  35. package/dist/orchestration/conversation-intake.js.map +1 -1
  36. package/dist/orchestration/dashboard-charts.d.ts +32 -0
  37. package/dist/orchestration/dashboard-charts.d.ts.map +1 -0
  38. package/dist/orchestration/dashboard-charts.js +77 -0
  39. package/dist/orchestration/dashboard-charts.js.map +1 -0
  40. package/dist/orchestration/dashboard-reader-worker.js +21 -3
  41. package/dist/orchestration/dashboard-reader-worker.js.map +1 -1
  42. package/dist/orchestration/dashboard-reader.d.ts +1 -1
  43. package/dist/orchestration/dashboard-reader.d.ts.map +1 -1
  44. package/dist/orchestration/dashboard-reader.js +2 -2
  45. package/dist/orchestration/dashboard-reader.js.map +1 -1
  46. package/dist/orchestration/decision-context.d.ts +1 -1
  47. package/dist/orchestration/decision-context.d.ts.map +1 -1
  48. package/dist/orchestration/decision-context.js +2 -2
  49. package/dist/orchestration/decision-context.js.map +1 -1
  50. package/dist/orchestration/mutation-recovery.d.ts +3 -2
  51. package/dist/orchestration/mutation-recovery.d.ts.map +1 -1
  52. package/dist/orchestration/mutation-recovery.js +8 -0
  53. package/dist/orchestration/mutation-recovery.js.map +1 -1
  54. package/dist/orchestration/native-compact.d.ts +4 -1
  55. package/dist/orchestration/native-compact.d.ts.map +1 -1
  56. package/dist/orchestration/native-compact.js +6 -2
  57. package/dist/orchestration/native-compact.js.map +1 -1
  58. package/dist/orchestration/process-turn.d.ts +1 -0
  59. package/dist/orchestration/process-turn.d.ts.map +1 -1
  60. package/dist/orchestration/process-turn.js +1 -1
  61. package/dist/orchestration/process-turn.js.map +1 -1
  62. package/dist/orchestration/runtime.d.ts +13 -1
  63. package/dist/orchestration/runtime.d.ts.map +1 -1
  64. package/dist/orchestration/runtime.js +161 -18
  65. package/dist/orchestration/runtime.js.map +1 -1
  66. package/dist/orchestration/session-compaction.d.ts +59 -0
  67. package/dist/orchestration/session-compaction.d.ts.map +1 -0
  68. package/dist/orchestration/session-compaction.js +212 -0
  69. package/dist/orchestration/session-compaction.js.map +1 -0
  70. package/dist/orchestration/tasks/driver.js +1 -1
  71. package/dist/orchestration/tasks/driver.js.map +1 -1
  72. package/dist/orchestration/token-ledger.d.ts +7 -0
  73. package/dist/orchestration/token-ledger.d.ts.map +1 -1
  74. package/dist/orchestration/token-ledger.js +1 -0
  75. package/dist/orchestration/token-ledger.js.map +1 -1
  76. package/dist/types.d.ts +3 -0
  77. package/dist/types.d.ts.map +1 -1
  78. package/dist/ui/dashboard-charts.d.ts +3 -0
  79. package/dist/ui/dashboard-charts.d.ts.map +1 -0
  80. package/dist/ui/dashboard-charts.js +130 -0
  81. package/dist/ui/dashboard-charts.js.map +1 -0
  82. package/dist/ui/dashboard-client.d.ts.map +1 -1
  83. package/dist/ui/dashboard-client.js +10 -14
  84. package/dist/ui/dashboard-client.js.map +1 -1
  85. package/dist/ui/dashboard-controls.d.ts +4 -0
  86. package/dist/ui/dashboard-controls.d.ts.map +1 -0
  87. package/dist/ui/dashboard-controls.js +27 -0
  88. package/dist/ui/dashboard-controls.js.map +1 -0
  89. package/dist/ui/dashboard-presentation.d.ts +3 -0
  90. package/dist/ui/dashboard-presentation.d.ts.map +1 -1
  91. package/dist/ui/dashboard-presentation.js +11 -5
  92. package/dist/ui/dashboard-presentation.js.map +1 -1
  93. package/dist/ui/dashboard-range.d.ts +3 -3
  94. package/dist/ui/dashboard-range.d.ts.map +1 -1
  95. package/dist/ui/dashboard-range.js +21 -5
  96. package/dist/ui/dashboard-range.js.map +1 -1
  97. package/dist/ui/dashboard-theme.d.ts +3 -1
  98. package/dist/ui/dashboard-theme.d.ts.map +1 -1
  99. package/dist/ui/dashboard-theme.js +80 -3
  100. package/dist/ui/dashboard-theme.js.map +1 -1
  101. package/dist/ui/memory-activity.d.ts +4 -0
  102. package/dist/ui/memory-activity.d.ts.map +1 -0
  103. package/dist/ui/memory-activity.js +115 -0
  104. package/dist/ui/memory-activity.js.map +1 -0
  105. package/dist/ui/token-report-client.d.ts +1 -1
  106. package/dist/ui/token-report-client.d.ts.map +1 -1
  107. package/dist/ui/token-report-client.js +1 -1
  108. package/dist/ui/token-report.d.ts +1 -0
  109. package/dist/ui/token-report.d.ts.map +1 -1
  110. package/dist/ui/token-report.js +18 -15
  111. package/dist/ui/token-report.js.map +1 -1
  112. package/dist/ui/web-ui.d.ts +1 -1
  113. package/dist/ui/web-ui.d.ts.map +1 -1
  114. package/dist/ui/web-ui.js +15 -238
  115. package/dist/ui/web-ui.js.map +1 -1
  116. package/mcp/tools/telegram/receiver-server.ts +31 -17
  117. package/mcp/tools/telegram/session-browser.ts +10 -0
  118. package/package.json +1 -1
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dashboardChartsClient = void 0;
4
+ exports.dashboardChartsHtml = dashboardChartsHtml;
5
+ function dashboardChartsHtml(timezone) {
6
+ const zone = timezone.replace(/[^A-Za-z0-9_+\/.-]/g, '');
7
+ return '<div id="overview-charts" class="overview-chart-grid">' + [
8
+ ['activity', 'Token activity'], ['agents', 'Tokens by agent'], ['models', 'Tokens by model'], ['reuse', 'Context reuse'],
9
+ ].map(([key, title]) => '<section class="dash-panel overview-chart-card" data-chart="' + key + '"><div class="chart-card-header"><h2>' + title + '</h2><div class="range-toggle chart-range" role="group" aria-label="' + title + ' date range">' + ['24h', '7d', '30d', '90d'].map(range => '<button type="button" data-chart-range="' + range + '" aria-pressed="' + (range === '24h') + '" title="' + (range === '24h' ? 'Today from 00:00 ' : range + ' including today · ') + zone + '">' + range + '</button>').join('') + '</div></div><p class="live-note chart-period"></p><div class="chart-content" id="chart-' + key + '"><p class="empty">Loading recorded usage…</p></div><p class="live-note chart-status" role="status"></p></section>').join('') + '</div>';
10
+ }
11
+ exports.dashboardChartsClient = String.raw `
12
+ const overviewChartRanges={activity:'24h',agents:'24h',models:'24h',reuse:'24h'};
13
+ const overviewChartSnapshots=new Map(),overviewChartInflight=new Map();
14
+ const chartColors=dashboardChartPalette;
15
+ const chartRendered=new WeakMap();
16
+ let chartPointer=null;
17
+ document.addEventListener('pointermove',event=>{chartPointer={x:event.clientX,y:event.clientY};});
18
+ document.addEventListener('pointerout',event=>{if(!event.relatedTarget)chartPointer=null;});
19
+ const chartPreferenceKey='gateway-overview-charts:'+location.pathname.replace(/\/$/,'');
20
+ try{
21
+ const saved=JSON.parse(localStorage.getItem(chartPreferenceKey)||'{}');
22
+ Object.keys(overviewChartRanges).forEach(key=>{if(['24h','7d','30d','90d'].includes(saved?.[key]))overviewChartRanges[key]=saved[key];});
23
+ }catch{}
24
+ // Restore controls before the first fetch, including when Overview is initially hidden.
25
+ Object.keys(overviewChartRanges).forEach(key=>document.querySelectorAll('[data-chart="'+key+'"] [data-chart-range]').forEach(button=>button.setAttribute('aria-pressed',String(button.dataset.chartRange===overviewChartRanges[key]))));
26
+ function chartPeriod(data){const fmt=new Intl.DateTimeFormat('en-GB',{timeZone:data.timezone,day:'numeric',month:'short'});return (data.scope==='24h'?'Today · from 00:00':fmt.format(data.since)+' – '+fmt.format(data.asOf))+' · '+data.timezone;}
27
+ function chartEmpty(){return '<p class="empty">No recorded token usage in this period.</p>';}
28
+ function chartTooltipRow(label,value,color='var(--text)',detail){
29
+ return '<span class="chart-tooltip-row"><span>'+escHtml(label)+'</span><strong style="color:'+color+'">'+escHtml(value)+(detail==null?'':' <span class="chart-tooltip-detail">('+escHtml(detail)+')</span>')+'</strong></span>';
30
+ }
31
+ function chartInputShare(value,total){return total>0?(value/total*100).toFixed(1)+'%':'—';}
32
+ function chartActivity(data,reuse=false){
33
+ const reuseLegend={read:'Reused (Cached Read)',write:'New saved (Cached write)',fresh:'New not cached (Input)'};
34
+ const series=reuse?[['read','Reused','var(--token-agent)'],['write','New · saved','var(--token-worker)'],['fresh','New · not cached','var(--token-report)']]:[['agent','Agent','var(--token-agent)'],['worker','Workers','var(--token-worker)']];
35
+ const blank=()=>Object.fromEntries(series.map(([key])=>[key,0]));
36
+ const slots=new Map();
37
+ if(data.scope==='24h')for(let i=0;i<24;i++)slots.set(String(i).padStart(2,'0'),blank());
38
+ else{
39
+ const fmt=new Intl.DateTimeFormat('en-CA',{timeZone:data.timezone,year:'numeric',month:'2-digit',day:'2-digit'});
40
+ const parts=fmt.formatToParts(data.asOf),v=k=>Number(parts.find(p=>p.type===k).value),end=Date.UTC(v('year'),v('month')-1,v('day'));
41
+ for(let i=Number(data.scope.slice(0,-1))-1;i>=0;i--)slots.set(new Date(end-i*86400000).toISOString().slice(0,10),blank());
42
+ }
43
+ data.agents.forEach(a=>a.buckets.forEach(b=>{if(slots.has(b.key)){const slot=slots.get(b.key);series.forEach(([key])=>slot[key]+=Number(b[key]||0));}}));
44
+ const values=[...slots].map(([key,value])=>({key,...value})),peak=Math.max(0,...values.flatMap(v=>series.map(([key])=>v[key])));
45
+ if(!peak)return chartEmpty();
46
+ const label=key=>data.scope==='24h'?key+':00':key.slice(8,10)+'/'+key.slice(5,7);
47
+ const points=role=>values.map((v,i)=>(i*600/(values.length-1)).toFixed(2)+','+(180-v[role]/peak*170).toFixed(2)).join(' ');
48
+ return '<div class="activity-frame"><div class="chart-y-labels"><span>'+compactNumber(peak)+'</span><span>'+compactNumber(peak/2)+'</span><span>0</span></div><div class="activity-plot"><svg viewBox="0 0 600 190" preserveAspectRatio="none" aria-label="'+(reuse?'Recorded input reuse':'Agent and worker recorded token activity')+'" role="img"><path d="M0 10H600M0 95H600M0 180H600" fill="none" stroke="var(--line)" stroke-dasharray="3 5" vector-effect="non-scaling-stroke"/>'+series.map(([role,label,color])=>'<polyline points="'+points(role)+'" fill="none" stroke="'+color+'" stroke-width="1.5" vector-effect="non-scaling-stroke"/>').join('')+'</svg><div class="chart-hit-grid" style="grid-template-columns:repeat('+values.length+',minmax(0,1fr))">'+values.map((v,i)=>'<div class="chart-hit" data-chart-point="'+escHtml(v.key)+'" tabindex="0" role="img" aria-label="'+escHtml(label(v.key)+': '+series.map(([key,label])=>label+' '+compactNumber(v[key])).join(', '))+'">'+series.map(([role,label,color])=>'<i class="chart-line-dot" style="top:'+((180-v[role]/peak*170)/190*100)+'%;left:'+((i/(values.length-1)*values.length-i)*100)+'%;--dot-color:'+color+'"></i>').join('')+'<span class="chart-popover '+(i>values.length/2?'align-right':'align-left')+'"><strong>'+label(v.key)+'</strong>'+series.map(([key,label,color])=>chartTooltipRow(label,reuse?chartInputShare(v[key],v.read+v.write+v.fresh):compactNumber(v[key]),color,reuse&&v.read+v.write+v.fresh>0?compactNumber(v[key]):undefined)).join('')+chartTooltipRow(reuse?'Total input':'Total',compactNumber(series.reduce((n,[key])=>n+v[key],0)))+'</span></div>').join('')+'</div><div class="chart-x-labels"><span>'+label(values[0].key)+'</span><span>'+label(values[Math.floor(values.length/2)].key)+'</span><span>'+label(values[values.length-1].key)+'</span></div></div></div><div class="chart-key reuse-key">'+series.map(([key,label,color])=>'<span><i style="background:'+color+'"></i>'+(reuse?reuseLegend[key]:label)+'</span>').join('')+'</div><p class="live-note">'+(reuse?'Input tokens only. Not billing savings.':'Recorded tokens, including cache. Not billing cost.')+'</p>';
49
+ }
50
+ function chartAgents(data,element){
51
+ const agents=data.agents.map(a=>({...a,total:a.agent+a.worker})).filter(a=>a.total>0).sort((a,b)=>b.total-a.total||a.id.localeCompare(b.id));
52
+ if(!agents.length)return chartEmpty();
53
+ const capacity=Math.max(2,Math.min(8,Math.floor((element.clientWidth-40)/76))),top=agents.slice(0,capacity),peak=top[0].total;
54
+ return '<div class="agent-column-plot"><div class="chart-y-labels"><span>'+compactNumber(peak)+'</span><span>'+compactNumber(peak/2)+'</span><span>0</span></div><div class="agent-columns">'+top.map(a=>'<div class="agent-column" data-chart-point="'+escHtml(a.id)+'" style="--agent-hue:'+agentHue(a.id)+'" tabindex="0" role="img" aria-label="'+escHtml(a.id+': Agent '+compactNumber(a.agent)+', workers '+compactNumber(a.worker)+', total '+compactNumber(a.total))+'"><div class="agent-bar-space"><div class="agent-bar" style="height:'+Math.max(1,a.total/peak*100)+'%"><span class="agent-bar-total">'+compactNumber(a.total)+'</span></div></div><span class="agent-bar-label" title="'+escHtml(a.id)+'"><i></i><span>'+escHtml(a.id)+'</span></span><span class="chart-popover"><strong>'+escHtml(a.id)+'</strong>'+chartTooltipRow('Agent',compactNumber(a.agent),'var(--token-agent)')+chartTooltipRow('Workers',compactNumber(a.worker),'var(--token-worker)')+chartTooltipRow('Total',compactNumber(a.total),'var(--agent-chart-color)')+'</span></div>').join('')+'</div></div><div class="chart-key"><span>Agent + worker tokens · colors match Agents below</span></div><p class="live-note">Top '+top.length+' of '+agents.length+' active agents · ranked by recorded tokens.</p>';
55
+ }
56
+ function chartModels(data){
57
+ const models=new Map();data.agents.forEach(a=>a.models.forEach(m=>models.set(m.name,(models.get(m.name)||0)+m.tokens)));
58
+ const sorted=[...models].map(([name,tokens])=>({name,tokens})).sort((a,b)=>b.tokens-a.tokens||a.name.localeCompare(b.name));
59
+ const total=sorted.reduce((n,m)=>n+m.tokens,0);if(!total)return chartEmpty();
60
+ const top=sorted.slice(0,5);if(sorted.length>5)top.push({name:'Other models ('+(sorted.length-5)+')',tokens:sorted.slice(5).reduce((n,m)=>n+m.tokens,0)});
61
+ let offset=0;const circumference=2*Math.PI*72;
62
+ const arcs=top.map((m,i)=>{const length=m.tokens/total*circumference,arc='<circle cx="100" cy="100" r="72" fill="none" stroke="'+chartColors[i]+'" stroke-width="22" stroke-dasharray="'+length+' '+(circumference-length)+'" stroke-dashoffset="'+(-offset)+'" transform="rotate(-90 100 100)" tabindex="0" data-chart-point="'+escHtml(m.name)+'" data-model-name="'+escHtml(m.name)+'" data-model-tokens="'+compactNumber(m.tokens)+'" data-model-share="'+(m.tokens/total*100).toFixed(1)+'%" aria-label="'+escHtml(m.name)+' · '+compactNumber(m.tokens)+' · '+(m.tokens/total*100).toFixed(1)+'%"></circle>';offset+=length;return arc;}).join('');
63
+ return '<div class="model-donut-layout"><div class="model-donut"><svg viewBox="0 0 200 200" role="img" aria-label="Recorded tokens by model">'+arcs+'</svg><span class="chart-popover model-tooltip" role="tooltip"></span><div class="donut-center"><strong>'+compactNumber(total)+'</strong><span>Total tokens</span></div></div><ul class="model-chart-legend">'+top.map((m,i)=>'<li><i style="background:'+chartColors[i]+'"></i><span title="'+escHtml(m.name)+'">'+escHtml(m.name)+'</span><strong>'+compactNumber(m.tokens)+'</strong><small>'+(m.tokens/total*100).toFixed(1)+'%</small></li>').join('')+'</ul></div><p class="live-note">Agent + worker tokens · includes cache reads and writes.</p>';
64
+ }
65
+ function chartReuse(data){
66
+ const day=key=>data.agents.reduce((r,a)=>{const value=a.reuseComparison?.[key];if(value)Object.keys(r).forEach(k=>r[k]+=value[k]||0);return r;},{fresh:0,write:0,read:0,missingTurns:0});
67
+ const today=day('today'),yesterday=day('yesterday');
68
+ const rate=d=>{const total=d.fresh+d.write+d.read;return total>0?100*d.read/total:null;};
69
+ const current=rate(today),previous=rate(yesterday),delta=current!==null&&previous!==null?current-previous:null;
70
+ const comparison=delta===null?'Yesterday: no measured input to compare.':(delta===0?'Unchanged':(delta>0?'Up ':'Down ')+Math.abs(delta).toFixed(1)+' percentage points')+' vs yesterday ('+previous.toFixed(1)+'%).';
71
+ return chartActivity(data,true)+'<p class="reuse-summary"><strong>'+(current===null?'—':current.toFixed(1)+'%')+'</strong> of today’s measured input reused</p><p class="live-note">'+(current===null?'No measured input today.':comparison)+' Today so far vs yesterday’s full day · '+escHtml(data.timezone)+(today.missingTurns?' · '+compactNumber(today.missingTurns)+' turns excluded today: incomplete measurements.':'')+'</p>';
72
+ }
73
+ function drawOverviewChart(key,data){
74
+ const card=document.querySelector('[data-chart="'+key+'"]'),element=card.querySelector('.chart-content');
75
+ const sameScope=element.dataset.scope===data.scope;
76
+ const html=key==='activity'?chartActivity(data):key==='agents'?chartAgents(data,element):key==='models'?chartModels(data):chartReuse(data);
77
+ card.querySelector('.chart-period').textContent=chartPeriod(data);
78
+ if(chartRendered.get(element)!==html){
79
+ const active=document.activeElement,hadFocus=element.contains(active);
80
+ const point=hadFocus&&sameScope?active.closest('[data-chart-point]')?.dataset.chartPoint:null;
81
+ element.innerHTML=html;chartRendered.set(element,html);
82
+ if(hadFocus){
83
+ const replacement=point==null?null:[...element.querySelectorAll('[data-chart-point]')].find(node=>node.dataset.chartPoint===point);
84
+ (replacement||card.querySelector('[data-chart-range="'+data.scope+'"]')).focus({preventScroll:true});
85
+ }
86
+ // A stationary pointer does not emit pointerover after replacing SVG nodes.
87
+ if(chartPointer){const hovered=document.elementFromPoint(chartPointer.x,chartPointer.y);if(hovered&&element.contains(hovered))showModelTooltip(hovered);}
88
+ }
89
+ element.dataset.scope=data.scope;
90
+ card.querySelector('.chart-status').textContent='';
91
+ }
92
+ function refreshOverviewCharts(force=false){
93
+ if(document.hidden||document.getElementById('view-overview').style.display==='none')return;
94
+ Object.keys(overviewChartRanges).forEach(key=>document.querySelectorAll('[data-chart="'+key+'"] [data-chart-range]').forEach(b=>b.setAttribute('aria-pressed',String(b.dataset.chartRange===overviewChartRanges[key]))));
95
+ [...new Set(Object.values(overviewChartRanges))].forEach(scope=>{
96
+ const old=overviewChartSnapshots.get(scope);if(!force&&old&&Date.now()-old.at<10000)return;
97
+ if(overviewChartInflight.has(scope))return;
98
+ const request=fetch(apiUrl('/dashboard/charts')+'?scope='+scope,{signal:AbortSignal.timeout(15000)}).then(async response=>{if(!response.ok)throw Error('Chart data temporarily unavailable');return response.json();}).then(data=>{
99
+ overviewChartSnapshots.set(scope,{data,at:Date.now()});Object.keys(overviewChartRanges).forEach(key=>{if(overviewChartRanges[key]===scope)drawOverviewChart(key,data);});
100
+ }).catch(()=>Object.keys(overviewChartRanges).forEach(key=>{if(overviewChartRanges[key]===scope)document.querySelector('[data-chart="'+key+'"] .chart-status').textContent='Could not refresh. Retrying automatically.';})).finally(()=>overviewChartInflight.delete(scope));
101
+ overviewChartInflight.set(scope,request);
102
+ });
103
+ }
104
+ function showModelTooltip(target){
105
+ const arc=target.closest('[data-model-name]');if(!arc)return;
106
+ const tip=arc.closest('.model-donut').querySelector('.model-tooltip');
107
+ const color=arc.getAttribute('stroke');
108
+ // Stroke comes only from our fixed chart palette, never provider metadata.
109
+ tip.innerHTML='<strong>'+escHtml(arc.dataset.modelName)+'</strong>'+chartTooltipRow('Tokens',arc.dataset.modelShare,color,arc.dataset.modelTokens);
110
+ tip.style.display='block';
111
+ }
112
+ document.addEventListener('pointerover',event=>showModelTooltip(event.target));
113
+ document.addEventListener('focusin',event=>showModelTooltip(event.target));
114
+ function hideModelTooltip(event){const arc=event.target.closest('[data-model-name]');if(arc)arc.closest('.model-donut').querySelector('.model-tooltip').style.display='none';}
115
+ document.addEventListener('pointerout',hideModelTooltip);
116
+ document.addEventListener('focusout',hideModelTooltip);
117
+ document.addEventListener('click',event=>{
118
+ const button=event.target.closest('[data-chart-range]');if(button){
119
+ const key=button.closest('[data-chart]').dataset.chart,scope=button.dataset.chartRange;overviewChartRanges[key]=scope;
120
+ try{localStorage.setItem(chartPreferenceKey,JSON.stringify(overviewChartRanges));}catch{}
121
+ const cached=overviewChartSnapshots.get(scope);if(cached)drawOverviewChart(key,cached.data);else {chartRendered.delete(document.getElementById('chart-'+key));document.getElementById('chart-'+key).innerHTML='<p class="empty">Loading recorded usage…</p>';document.querySelector('[data-chart="'+key+'"] .chart-period').textContent='';}
122
+ refreshOverviewCharts();
123
+ }else if(event.target.closest('#tab-overview'))refreshOverviewCharts();
124
+ });
125
+ document.addEventListener('DOMContentLoaded',()=>refreshOverviewCharts());
126
+ document.addEventListener('visibilitychange',()=>{if(!document.hidden)refreshOverviewCharts();});
127
+ setInterval(()=>refreshOverviewCharts(true),10000);
128
+ let chartResizeWidth=0;new ResizeObserver(entries=>{const width=Math.round(entries[0].contentRect.width);if(width===chartResizeWidth)return;chartResizeWidth=width;const snapshot=overviewChartSnapshots.get(overviewChartRanges.agents);if(snapshot)drawOverviewChart('agents',snapshot.data);}).observe(document.getElementById('chart-agents'));
129
+ `;
130
+ //# sourceMappingURL=dashboard-charts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-charts.js","sourceRoot":"","sources":["../../src/ui/dashboard-charts.ts"],"names":[],"mappings":";;;AAAA,kDAKC;AALD,SAAgB,mBAAmB,CAAC,QAAgB;IAClD,MAAM,IAAI,GAAC,QAAQ,CAAC,OAAO,CAAC,qBAAqB,EAAC,EAAE,CAAC,CAAC;IACtD,OAAO,wDAAwD,GAAC;QAC9D,CAAC,UAAU,EAAC,gBAAgB,CAAC,EAAC,CAAC,QAAQ,EAAC,iBAAiB,CAAC,EAAC,CAAC,QAAQ,EAAC,iBAAiB,CAAC,EAAC,CAAC,OAAO,EAAC,eAAe,CAAC;KAClH,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAC,KAAK,CAAC,EAAC,EAAE,CAAA,8DAA8D,GAAC,GAAG,GAAC,uCAAuC,GAAC,KAAK,GAAC,sEAAsE,GAAC,KAAK,GAAC,eAAe,GAAC,CAAC,KAAK,EAAC,IAAI,EAAC,KAAK,EAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAA,EAAE,CAAA,0CAA0C,GAAC,KAAK,GAAC,kBAAkB,GAAC,CAAC,KAAK,KAAG,KAAK,CAAC,GAAC,WAAW,GAAC,CAAC,KAAK,KAAG,KAAK,CAAA,CAAC,CAAA,mBAAmB,CAAA,CAAC,CAAA,KAAK,GAAC,qBAAqB,CAAC,GAAC,IAAI,GAAC,IAAI,GAAC,KAAK,GAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAC,yFAAyF,GAAC,GAAG,GAAC,oHAAoH,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAC,QAAQ,CAAC;AACrrB,CAAC;AAEY,QAAA,qBAAqB,GAAC,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsH5C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-client.d.ts","sourceRoot":"","sources":["../../src/ui/dashboard-client.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,eAAO,MAAM,eAAe,QAoL3B,CAAC"}
1
+ {"version":3,"file":"dashboard-client.d.ts","sourceRoot":"","sources":["../../src/ui/dashboard-client.ts"],"names":[],"mappings":"AAGA,gFAAgF;AAChF,eAAO,MAAM,eAAe,QA+K3B,CAAC"}
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dashboardClient = void 0;
4
+ const dashboard_charts_1 = require("./dashboard-charts");
4
5
  const dashboard_range_1 = require("./dashboard-range");
5
6
  const dashboard_presentation_1 = require("./dashboard-presentation");
6
7
  /** Browser controller: no provider keys or model-generated HTML are trusted. */
7
- exports.dashboardClient = dashboard_presentation_1.dashboardPresentationClient + dashboard_range_1.dashboardRange.toString() + ';' + dashboard_range_1.dashboardSince.toString() + ';' + String.raw `
8
+ exports.dashboardClient = dashboard_presentation_1.dashboardPresentationClient + dashboard_range_1.dashboardRange.toString() + ';' + dashboard_range_1.dashboardSince.toString() + ';' + dashboard_charts_1.dashboardChartsClient + String.raw `
8
9
  let dashboardData = null, dashboardOffset = 0, dashboardBusy = false, dashboardSearch = '', dashboardAgent = '', dashboardScope = '24h';
9
10
  const dashboardStateKey='gateway-dashboard-view:'+location.pathname.replace(/\/$/,'');
10
11
  let savedDashboardState={};
@@ -61,15 +62,11 @@ function renderDashboard(data){
61
62
  const stats=[['Recorded sessions',sessions],['Work in progress',taskCount(['running','starting','queued','interrupting','cancel_requested'])],['Waiting for a decision',taskCount(['waiting_input'])],['Loaded agents',agents.length]];
62
63
  document.getElementById('overview-stats').innerHTML=stats.map(([label,n])=>'<div class="dash-stat"><span>'+label+'</span><strong>'+dashCount(n)+'</strong></div>').join('');
63
64
  const attention=agents.flatMap(a=>(a.orchestration?.attention||[]).map(t=>({a,s:{sessionId:t.sessionId},t})));
65
+ document.getElementById('overview-attention-panel').hidden=!attention.length;
64
66
  document.getElementById('overview-attention').innerHTML=attention.length?dashTable(['Task','Agent','Status'],attention.slice(0,8).map(({a,s,t})=>'<tr'+dashOpenAttrs(a.id,s.sessionId,t.taskId)+' tabindex="0" aria-expanded="false"><td>'+dashText(t.title)+'</td><td>'+agentBadge(a.id)+'</td><td>'+dashStatus(t.state)+'</td></tr>')):'<p class="muted">No tasks are waiting for a decision or reconciliation.</p>';
65
- const hourly=Array.from({length:24},()=>({agent:0,worker:0}));let hasUsage=false;
66
- agents.forEach(a=>(a.orchestration?.usageToday||[]).forEach(r=>{if(hourly[r.hour]&&['agent','worker'].includes(r.role)){hourly[r.hour][r.role]+=Number(r.tokens||0);hasUsage=true;}}));
67
- const peak=Math.max(1,...hourly.flatMap(h=>[h.agent,h.worker]));
68
- const points=role=>hourly.map((h,i)=>(i*600/23).toFixed(1)+','+(160-h[role]/peak*140).toFixed(1)).join(' ');
69
- document.getElementById('overview-chart').innerHTML=hasUsage?'<svg viewBox="0 0 600 180" role="img" aria-label="Recorded token activity today in UTC" style="width:100%;height:180px"><path d="M0 20H600M0 90H600M0 160H600" fill="none" stroke="var(--line)" stroke-dasharray="4 5"/><polyline points="'+points('worker')+'" fill="none" stroke="var(--accent)" stroke-width="2"/><polyline points="'+points('agent')+'" fill="none" stroke="var(--blue)" stroke-width="2"/></svg><div class="row between muted small"><span>00:00 UTC</span><span>12:00</span><span>23:00 UTC</span></div>':'<p class="empty">No recorded token usage today.</p>';
70
67
  const sessionRows=rows.map(({a,s})=>'<tr class="session-row"'+(s.orchestration?dashOpenAttrs(a.id,s.sessionId):'')+' tabindex="0" aria-expanded="false" data-row-key="'+escHtml(a.id+':'+s.sessionId)+'"><td>'+agentBadge(a.id)+'<br>'+channelBadge(s.source)+'</td><td><span class="session-id">'+dashText(s.sessionId)+'</span><br><small class="ts">Chat '+dashText(s.chatId)+'</small></td><td><span class="cell-clip" title="'+dashText(s.model)+'">'+dashText(s.model||'—')+'</span></td><td>'+dashStatus(sessionDisplayStatus(s))+'</td><td>'+ (s.orchestration?dashCount(s.tokenSummary?.agentTokens)+' / '+dashCount(s.tokenSummary?.totalTokens):dashCount(s.tokens))+'<br><small class="ts">'+(s.orchestration?'Agent / total · recorded only':'Legacy process tokens')+'</small></td><td class="dash-tools">'+toolInventory(s.loadedTools,s.usedTools,s.contextTools)+'</td><td>'+ (s.orchestration?'<a class="btn-stream" target="_blank" rel="noopener" href="'+escHtml(dashReportUrl(a.id,s.sessionId))+'">View token report ↗</a>':'')+(s.hasPtyStream&&s.isRunning&&s.mode==='pty-shell'?'<button class="btn-stream" data-agent-id="'+escHtml(a.id)+'" data-session-id="'+escHtml(s.sessionId)+'">Terminal</button>':'')+'</td></tr>');
71
68
  document.getElementById('session-results').innerHTML=dashTable(['Agent / Channel','Session / Chat','Model','Status','Tokens','Tools','Inspect'],sessionRows);
72
- const taskRows=tasks.map(({a,s,t})=>'<tr'+dashOpenAttrs(a.id,s.sessionId,t.taskId)+' tabindex="0" aria-expanded="false" data-row-key="'+escHtml(a.id+':'+t.taskId)+'"><td><strong class="dash-task-title">'+dashText(t.title)+'</strong><small class="ts">'+agentBadge(a.id)+' · '+dashId(t.taskId)+'<br>'+channelBadge(s.source)+'</small></td><td>'+dashStatus(t.state)+'</td><td class="session-id">'+dashId(t.workerSessionId)+'<br><small class="ts">Attempt '+dashId(t.attemptId)+'</small></td><td>'+dashCount(t.tokenSummary?.totalTokens)+'<br><small class="ts">Latest attempt</small></td><td>'+dashCount(t.tokenSummary?.allAttemptsTokens)+'<br><small class="ts">All recorded attempts</small></td><td class="dash-tools">'+toolInventory(t.loadedTools,t.usedTools,t.contextTools)+'</td><td><span class="cell-clip" title="'+dashText(t.lastTool?.name)+'">'+dashText(t.lastTool?.name||'No recorded tool')+'</span>'+'<br><small class="ts">'+(t.lastTool?.at?dashText(new Date(t.lastTool.at).toLocaleString()):'')+'</small></td></tr>');
69
+ const taskRows=tasks.map(({a,s,t})=>'<tr'+dashOpenAttrs(a.id,s.sessionId,t.taskId)+' tabindex="0" aria-expanded="false" data-row-key="'+escHtml(a.id+':'+t.taskId)+'"><td><strong class="dash-task-title">'+dashText(t.title)+'</strong><small class="ts">'+agentBadge(a.id)+' · '+dashId(t.taskId)+'<br>'+channelBadge(s.source)+'</small></td><td>'+dashStatus(t.state)+'</td><td class="session-id">'+dashId(t.workerSessionId)+'<br><small class="ts">Attempt '+dashId(t.attemptId)+'</small></td><td>'+dashCount(t.tokenSummary?.totalTokens)+'<br><small class="ts">Latest attempt</small></td><td>'+dashCount(t.tokenSummary?.allAttemptsTokens)+'<br><small class="ts">All recorded attempts</small></td><td class="dash-tools">'+toolInventory(t.loadedTools,t.usedTools,t.contextTools)+'</td><td><span class="cell-clip" title="'+dashText(t.lastTool?.name)+'">'+dashText(t.lastTool?.name||'No recorded tool')+'</span>'+'<br><small class="ts">'+(t.lastTool?.at?dashText(new Date(t.lastTool.at).toLocaleString('en-GB',{timeZone:dashboardTimezone})):'')+'</small></td></tr>');
73
70
  document.getElementById('task-results').innerHTML=dashTable(['Task / Agent','Status','Worker session / Attempt','Latest tokens','Task tokens','Latest attempt tools','Latest activity'],taskRows);
74
71
  const recentWork=agents.flatMap(a=>(a.orchestration?.recentWork||[]).map(t=>({a,s:{sessionId:t.sessionId},t}))).sort((x,y)=>Number(y.t.updatedAt)-Number(x.t.updatedAt)||x.t.taskId.localeCompare(y.t.taskId));
75
72
  document.getElementById('overview-tasks').innerHTML=dashTable(['Task','Agent','Status'],recentWork.slice(0,6).map(({a,s,t})=>'<tr'+dashOpenAttrs(a.id,s.sessionId,t.taskId)+' tabindex="0" aria-expanded="false"><td>'+dashText(t.title)+'</td><td>'+agentBadge(a.id)+'</td><td>'+dashStatus(t.state)+'</td></tr>'));
@@ -100,16 +97,16 @@ async function dashDetail(agentId,sessionId,taskId,offset=0){
100
97
  if(response.status===401){onUnauthorized();return;}
101
98
  if(!response.ok)throw Error('Details unavailable (HTTP '+response.status+').');
102
99
  const detail=await response.json();if(dashboardExpanded.get(key)!==record)return;
103
- let body='<h1>'+dashText(taskId?detail.snapshot.title:'Session details')+'</h1><p class="muted">'+agentBadge(agentId)+' · <span class="session-id">'+dashText(sessionId)+'</span></p><p class="live-note">Recorded snapshot · '+new Date().toLocaleTimeString()+'</p><a class="btn-stream" href="'+escHtml(dashReportUrl(agentId,sessionId))+'" target="_blank" rel="noopener">Open full token report ↗</a>';
100
+ let body='<h1>'+dashText(taskId?detail.snapshot.title:'Session details')+'</h1><p class="muted">'+agentBadge(agentId)+' · <span class="session-id">'+dashText(sessionId)+'</span></p><p class="live-note">Recorded snapshot · '+new Date().toLocaleTimeString('en-GB',{timeZone:dashboardTimezone})+'</p><a class="btn-stream" href="'+escHtml(dashReportUrl(agentId,sessionId))+'" target="_blank" rel="noopener">Open full token report ↗</a>';
104
101
  if(taskId){
105
102
  body+='<h2>Task</h2>'+dashStatus(detail.snapshot.state)+'<pre>'+dashText(detail.instructions||'No assignment text recorded for this task.')+'</pre>';
106
103
  if(detail.snapshot.result)body+='<h2>Latest result</h2><pre>'+dashText(detail.snapshot.result.summary||JSON.stringify(detail.snapshot.result,null,2))+'</pre>';
107
104
  body+='<h2>Worker attempts</h2><p class="muted">'+detail.totalAttempts+' attempts · displaying '+(offset+1)+'–'+Math.min(offset+25,detail.totalAttempts)+'</p>';
108
- body+=detail.attempts.map(a=>'<section class="detail-block"><h3>Attempt '+dashText(a.generation)+' · '+dashText(a.state)+'</h3><dl><dt>Attempt ID</dt><dd>'+dashText(a.attemptId)+'</dd><dt>Worker ID</dt><dd>'+dashText(a.workerId)+'</dd><dt>Worker session</dt><dd>'+dashText(a.sessionId)+'</dd><dt>Model</dt><dd>'+dashText(a.metrics?.model)+'</dd><dt>Recorded tokens</dt><dd>'+dashCount(a.metrics?.usage?.totalTokens)+'</dd></dl>'+toolInventory(a.metrics?.loadedTools,a.metrics?.usedTools,a.metrics?.contextTools)+(a.metrics?.contextTools?'<h3>Loaded tools</h3>'+toolNameList(a.metrics.contextTools):'')+'<h3>Used tools</h3>'+toolNameList(a.metrics?.usedTools)+'<h3>Latest recorded events</h3>'+a.events.map(e=>'<section class="detail-block"><h3>'+dashText(new Date(e.at).toLocaleString())+' · '+dashText(e.type)+'</h3><pre>'+dashText(JSON.stringify(e.payload,null,2))+'</pre></section>').join('')+'</section>').join('');
105
+ body+=detail.attempts.map(a=>'<section class="detail-block"><h3>Attempt '+dashText(a.generation)+' · '+dashText(a.state)+'</h3><dl><dt>Attempt ID</dt><dd>'+dashText(a.attemptId)+'</dd><dt>Worker ID</dt><dd>'+dashText(a.workerId)+'</dd><dt>Worker session</dt><dd>'+dashText(a.sessionId)+'</dd><dt>Model</dt><dd>'+dashText(a.metrics?.model)+'</dd><dt>Recorded tokens</dt><dd>'+dashCount(a.metrics?.usage?.totalTokens)+'</dd></dl>'+toolInventory(a.metrics?.loadedTools,a.metrics?.usedTools,a.metrics?.contextTools)+(a.metrics?.contextTools?'<h3>Loaded tools</h3>'+toolNameList(a.metrics.contextTools):'')+'<h3>Used tools</h3>'+toolNameList(a.metrics?.usedTools)+'<h3>Latest recorded events</h3>'+a.events.map(e=>'<section class="detail-block"><h3>'+dashText(new Date(e.at).toLocaleString('en-GB',{timeZone:dashboardTimezone}))+' · '+dashText(e.type)+'</h3><pre>'+dashText(JSON.stringify(e.payload,null,2))+'</pre></section>').join('')+'</section>').join('');
109
106
  if(offset>0)body+='<button data-attempt-page="'+Math.max(0,offset-25)+'">Newer attempts</button>';
110
107
  if(offset+25<detail.totalAttempts)body+='<button data-attempt-page="'+(offset+25)+'">Older attempts</button>';
111
108
  }else{
112
- body+='<h2>Session</h2><dl><dt>Channel</dt><dd>'+channelBadge(detail.session?.source)+'</dd><dt>Chat</dt><dd>'+dashText(detail.session?.chatId)+'</dd><dt>Created</dt><dd>'+dashText(detail.session?.createdAt?new Date(detail.session.createdAt).toLocaleString():null)+'</dd></dl>';
109
+ body+='<h2>Session</h2><dl><dt>Channel</dt><dd>'+channelBadge(detail.session?.source)+'</dd><dt>Chat</dt><dd>'+dashText(detail.session?.chatId)+'</dd><dt>Created</dt><dd>'+dashText(detail.session?.createdAt?new Date(detail.session.createdAt).toLocaleString('en-GB',{timeZone:dashboardTimezone}):null)+'</dd></dl>';
113
110
  var uBy=detail.usageByRole||[];
114
111
  var uAgent=uBy.find(function(u){return u.role==='agent';}),uWorker=uBy.find(function(u){return u.role==='worker';});
115
112
  var cachedLineFor=function(u){if(!u)return '';var read=Number(u.cacheReadTokens||0),base=Number(u.inputTokens||0)+read+Number(u.cacheCreationTokens||0);return '<span class="card-cached">Cached: <b>'+(base?(read/base*100).toFixed(2):'0.00')+'%</b></span>';};
@@ -119,7 +116,7 @@ async function dashDetail(agentId,sessionId,taskId,offset=0){
119
116
  var cwStopped=detailActivity==='stopped';
120
117
  body+='<div class="dash-grid session-token-totals"><div class="dash-stat box-context"><span>Context window</span><strong>'+(cwStopped?'-':(cw?dashCount(cw.used)+' / '+(cw.total==null?'—':windowCap(cw.total)):'—'))+'</strong>'+((!cwStopped&&cw&&cw.model)?'<span class="card-cached">Model: '+escHtml(cw.model)+'</span>':'')+'</div><div class="dash-stat box-agent"><span>Agent tokens</span><strong>'+dashCount(detail.totals.agentTokens)+'</strong>'+cachedLineFor(uAgent)+'</div><div class="dash-stat box-worker"><span>Worker tokens</span><strong>'+dashCount(detail.totals.workerTokens)+'</strong>'+cachedLineFor(uWorker)+'</div></div><p class="live-note">Recorded turns only. Missing measurements are shown as —, not zero. Token volume is not billing cost.</p>';
121
118
  body+='<details class="detail-block turn-disclosure session-tasks" data-detail-turn="section:tasks"><summary>Tasks ('+dashCount(detail.totalTasks)+')</summary><div class="dash-mini-list">'+(detail.tasks||[]).map(t=>'<div class="session-task-row"><span class="session-task-title">'+dashText(t.title)+'</span>'+dashStatus(t.state)+'</div>').join('')+(!detail.tasks?.length?'<p class="muted">No tasks recorded.</p>':'')+'</div></details><h2>Turns & worker attempts</h2>';
122
- body+=detail.turns.map(t=>'<details class="detail-block turn-disclosure" data-detail-turn="'+dashText(t.id)+'"><summary>'+dashText(t.role)+' · '+dashText(t.category)+' · '+dashText(new Date(t.startedAt).toLocaleString())+' · '+dashCount(t.usage?.totalTokens)+' tokens</summary><p class="live-note">'+dashText(t.id)+' · '+dashText(t.model)+' · '+dashText(t.state)+'</p>'+(t.taskId?'<p>Task '+dashText(t.taskId)+'</p>':'')+toolInventory(t.loadedTools,t.usedTools,t.contextTools)+(t.contextTools?'<h3>Loaded tools</h3>'+toolNameList(t.contextTools):'')+'<h3>Used tools</h3>'+toolNameList(t.usedTools)+(t.inputTexts||[]).map(text=>'<pre>'+dashText(text)+'</pre>').join('')+(t.responseText?'<h3>Response / result</h3><pre>'+dashText(t.responseText)+'</pre>':'')+'</details>').join('');
119
+ body+=detail.turns.map(t=>'<details class="detail-block turn-disclosure" data-detail-turn="'+dashText(t.id)+'"><summary>'+dashText(t.role)+' · '+dashText(t.category)+' · '+dashText(new Date(t.startedAt).toLocaleString('en-GB',{timeZone:dashboardTimezone}))+' · '+dashCount(t.usage?.totalTokens)+' tokens</summary><p class="live-note">'+dashText(t.id)+' · '+dashText(t.model)+' · '+dashText(t.state)+'</p>'+(t.taskId?'<p>Task '+dashText(t.taskId)+'</p>':'')+toolInventory(t.loadedTools,t.usedTools,t.contextTools)+(t.contextTools?'<h3>Loaded tools</h3>'+toolNameList(t.contextTools):'')+'<h3>Used tools</h3>'+toolNameList(t.usedTools)+(t.inputTexts||[]).map(text=>'<pre>'+dashText(text)+'</pre>').join('')+(t.responseText?'<h3>Response / result</h3><pre>'+dashText(t.responseText)+'</pre>':'')+'</details>').join('');
123
120
  if(!detail.turns.length)body+='<p class="empty">No instrumented turns recorded on this page.</p>';
124
121
  if(offset>0)body+='<button data-session-page="'+Math.max(0,offset-50)+'">Previous records</button>';
125
122
  if(offset+50<Math.max(detail.totalTasks||0,detail.pagination?.total||0))body+='<button data-session-page="'+(offset+50)+'">Next records</button>';
@@ -130,10 +127,10 @@ async function dashDetail(agentId,sessionId,taskId,offset=0){
130
127
  function restoreDashboardDetails(){
131
128
  const record=[...dashboardExpanded.values()][0];
132
129
  const back=document.getElementById('dash-drawer-back'),panel=document.getElementById('dash-drawer');
133
- back.classList.toggle('open',Boolean(record));document.body.style.overflow=record?'hidden':'';
130
+ back.classList.toggle('open',Boolean(record));document.body.style.overflow=record||document.getElementById('memory-back')?.classList.contains('open')?'hidden':'';
134
131
  document.querySelectorAll('tr[data-dash-agent]').forEach(row=>row.setAttribute('aria-expanded',String(Boolean(record&&row.dataset.dashAgent===record.agentId&&row.dataset.dashSession===record.sessionId&&(row.dataset.dashTask||'')===(record.taskId||'')))));
135
132
  if(!record){panel.innerHTML='';delete panel.dataset.html;return;}
136
- const html='<button data-dash-close aria-label="Close details">Close ×</button>'+record.html;
133
+ const html=dashboardCloseButton('dash')+record.html;
137
134
  if(panel.dataset.html!==html){
138
135
  const scroll=panel.scrollTop,focused=panel.contains(document.activeElement),closeFocused=document.activeElement?.hasAttribute('data-dash-close');
139
136
  const sameDetail=panel.dataset.agent===record.agentId&&panel.dataset.session===record.sessionId&&panel.dataset.task===(record.taskId||'');
@@ -161,7 +158,6 @@ document.addEventListener('click',function(e){
161
158
  updateSidebarToggle();
162
159
  }
163
160
  if(e.target.closest('.tab')){const view=e.target.closest('.tab').dataset.view;document.querySelector('.dash-filter').hidden=['view-overview','view-kb','view-system'].includes(view);document.getElementById('dash-search').hidden=view==='view-dreams';document.getElementById('dash-agent-filter').hidden=view==='view-dreams';document.querySelector('.dash-pager').hidden=['view-overview','view-kb','view-dreams','view-system'].includes(view);document.body.classList.remove('menuopen');updateSidebarToggle();document.getElementById('dash-current-view').textContent=e.target.closest('.tab').textContent.trim();if(e.target.closest('.tab').dataset.view==='view-system')refreshProcesses();}
164
- if(e.target.closest('#dash-theme')){const root=document.documentElement;root.dataset.theme=root.dataset.theme==='dark'?'light':'dark';}
165
161
  });
166
162
  document.addEventListener('keydown',function(e){
167
163
  if(e.target.id==='sidebar-brand'&&(e.key==='Enter'||e.key===' ')){e.preventDefault();e.target.click();return;}
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-client.js","sourceRoot":"","sources":["../../src/ui/dashboard-client.ts"],"names":[],"mappings":";;;AAAA,uDAAmE;AACnE,qEAAuE;AACvE,gFAAgF;AACnE,QAAA,eAAe,GAAG,oDAA2B,GAAG,gCAAc,CAAC,QAAQ,EAAE,GAAC,GAAG,GAAC,gCAAc,CAAC,QAAQ,EAAE,GAAC,GAAG,GAAE,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoLnI,CAAC"}
1
+ {"version":3,"file":"dashboard-client.js","sourceRoot":"","sources":["../../src/ui/dashboard-client.ts"],"names":[],"mappings":";;;AAAA,yDAA2D;AAC3D,uDAAmE;AACnE,qEAAuE;AACvE,gFAAgF;AACnE,QAAA,eAAe,GAAG,oDAA2B,GAAG,gCAAc,CAAC,QAAQ,EAAE,GAAC,GAAG,GAAC,gCAAc,CAAC,QAAQ,EAAE,GAAC,GAAG,GAAE,wCAAqB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+K3J,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** Shared controls for dashboard pages and standalone reports. */
2
+ export declare function themeButtonHtml(id: 'dash-theme' | 'report-theme'): string;
3
+ export declare const dashboardControlsClient: string;
4
+ //# sourceMappingURL=dashboard-controls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-controls.d.ts","sourceRoot":"","sources":["../../src/ui/dashboard-controls.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,wBAAgB,eAAe,CAAC,EAAE,EAAE,YAAY,GAAG,cAAc,GAAG,MAAM,CAEzE;AACD,eAAO,MAAM,uBAAuB,QAiBnC,CAAC"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dashboardControlsClient = void 0;
4
+ exports.themeButtonHtml = themeButtonHtml;
5
+ /** Shared controls for dashboard pages and standalone reports. */
6
+ function themeButtonHtml(id) {
7
+ return `<button type="button" class="theme-toggle" id="${id}" data-theme-toggle aria-label="Switch to dark theme" title="Switch to dark theme"><svg class="theme-moon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><path d="M20.5 13A8.5 8.5 0 0 1 11 3.5 8.5 8.5 0 1 0 20.5 13Z"/></svg><svg class="theme-sun" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1.5 1.5m11 11L19 19M5 19l1.5-1.5m11-11L19 5"/></svg></button>`;
8
+ }
9
+ exports.dashboardControlsClient = String.raw `
10
+ function dashboardCloseButton(action){
11
+ return '<div class="drawer-actions"><button type="button" class="drawer-close" data-'+action+'-close aria-label="Close details">Close ×</button></div>';
12
+ }
13
+ (function(){
14
+ const key='gateway-dashboard-theme';
15
+ function apply(theme){
16
+ document.documentElement.dataset.theme=theme;
17
+ document.querySelectorAll('[data-theme-toggle]').forEach(button=>{const label=theme==='dark'?'Switch to light theme':'Switch to dark theme';button.setAttribute('aria-label',label);button.title=label;});
18
+ }
19
+ try{const saved=localStorage.getItem(key);apply(saved==='dark'?'dark':'light');}catch{apply(document.documentElement.dataset.theme||'light');}
20
+ document.addEventListener('click',event=>{
21
+ if(!event.target.closest('[data-theme-toggle]'))return;
22
+ const theme=document.documentElement.dataset.theme==='dark'?'light':'dark';apply(theme);try{localStorage.setItem(key,theme);}catch{}
23
+ });
24
+ window.addEventListener('storage',event=>{if(event.key===key)apply(event.newValue==='dark'?'dark':'light');});
25
+ })();
26
+ `;
27
+ //# sourceMappingURL=dashboard-controls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-controls.js","sourceRoot":"","sources":["../../src/ui/dashboard-controls.ts"],"names":[],"mappings":";;;AACA,0CAEC;AAHD,kEAAkE;AAClE,SAAgB,eAAe,CAAC,EAAiC;IAC/D,OAAO,kDAAkD,EAAE,sjBAAsjB,CAAC;AACpnB,CAAC;AACY,QAAA,uBAAuB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;CAiBhD,CAAC"}
@@ -1,6 +1,9 @@
1
+ /** Chart palette shared with the Context bootstrap report. */
2
+ export declare const dashboardChartPalette: string[];
1
3
  /** Shared display-only formatting; stored values and identifiers remain unchanged. */
2
4
  export declare function compactNumber(value: unknown): string;
3
5
  export declare function dashboardEscape(value: unknown): string;
6
+ export declare function agentHue(value: string): number;
4
7
  export declare function agentBadge(value: string): string;
5
8
  export declare function channelBadge(value: string): string;
6
9
  export declare function taskStatusBadge(value: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-presentation.d.ts","sourceRoot":"","sources":["../../src/ui/dashboard-presentation.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMpD;AAKD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEtD;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGhD;AACD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AACD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKrD;AACD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAIvE;AACD,eAAO,MAAM,2BAA2B,QAAsO,CAAC"}
1
+ {"version":3,"file":"dashboard-presentation.d.ts","sourceRoot":"","sources":["../../src/ui/dashboard-presentation.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,eAAO,MAAM,qBAAqB,UAAsG,CAAC;AACzI,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMpD;AAKD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEtD;AACD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG9C;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AACD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AACD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKrD;AACD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAIvE;AACD,eAAO,MAAM,2BAA2B,QAAuU,CAAC"}
@@ -1,12 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.dashboardPresentationClient = void 0;
3
+ exports.dashboardPresentationClient = exports.dashboardChartPalette = void 0;
4
4
  exports.compactNumber = compactNumber;
5
5
  exports.dashboardEscape = dashboardEscape;
6
+ exports.agentHue = agentHue;
6
7
  exports.agentBadge = agentBadge;
7
8
  exports.channelBadge = channelBadge;
8
9
  exports.taskStatusBadge = taskStatusBadge;
9
10
  exports.toolNameList = toolNameList;
11
+ /** Chart palette shared with the Context bootstrap report. */
12
+ exports.dashboardChartPalette = ['#e98524', '#8e65d1', '#258fca', '#cf528b', '#359986', '#c19527', '#5c78d2', '#b66645', '#77843f', '#986499'];
10
13
  /** Shared display-only formatting; stored values and identifiers remain unchanged. */
11
14
  function compactNumber(value) {
12
15
  if (value == null)
@@ -27,11 +30,14 @@ const channelIcons = { "telegram": "<svg role=\"img\" viewBox=\"0 0 24 24\" xmln
27
30
  function dashboardEscape(value) {
28
31
  return String(value ?? '').replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
29
32
  }
30
- function agentBadge(value) {
33
+ function agentHue(value) {
31
34
  let hash = 0;
32
35
  for (const ch of value)
33
36
  hash = (hash * 31 + ch.charCodeAt(0)) >>> 0;
34
- return '<span class="identity-badge" style="--agent-hue:' + (hash % 360) + '" title="' + dashboardEscape(value) + '">' + dashboardEscape(value) + '</span>';
37
+ return hash % 360;
38
+ }
39
+ function agentBadge(value) {
40
+ return '<span class="identity-badge" style="--agent-hue:' + agentHue(value) + '" title="' + dashboardEscape(value) + '">' + dashboardEscape(value) + '</span>';
35
41
  }
36
42
  function channelBadge(value) {
37
43
  const key = String(value || 'unknown').toLowerCase();
@@ -41,7 +47,7 @@ function channelBadge(value) {
41
47
  }
42
48
  function taskStatusBadge(value) {
43
49
  const state = String(value || 'unknown');
44
- const colors = { running: '#e07a1e', working: '#e07a1e', thinking: '#d6459b', completed: '#24834a', succeeded: '#24834a', success: '#24834a', failed: '#c73946', queued: '#a16c11', starting: '#4d63c9', recovering: '#188b80', ended: '#607244', waiting_input: '#ba681c', needs_reconciliation: '#b345a4', cancel_requested: '#8c603c', interrupting: '#9e4d76', interrupted: '#7c6352', cancelled: '#657080', stopped: '#65605a', idle: '#287fc2', compacting: '#7655bd', unknown: '#737373' };
50
+ const colors = { pending: '#a16c11', skipped: '#657080', accepted: '#24834a', partial_failure: '#c73946', running: '#e07a1e', working: '#e07a1e', thinking: '#d6459b', completed: '#24834a', succeeded: '#24834a', success: '#24834a', failed: '#c73946', queued: '#a16c11', starting: '#4d63c9', recovering: '#188b80', ended: '#607244', waiting_input: '#ba681c', needs_reconciliation: '#b345a4', cancel_requested: '#8c603c', interrupting: '#9e4d76', interrupted: '#7c6352', cancelled: '#657080', stopped: '#65605a', idle: '#287fc2', compacting: '#7655bd', unknown: '#737373' };
45
51
  const color = colors[state] || '#737373';
46
52
  return '<span class="badge status-badge" style="--status-color:' + color + '">' + dashboardEscape(state.replace(/_/g, ' ').replace(/^./, c => c.toUpperCase())) + '</span>';
47
53
  }
@@ -52,5 +58,5 @@ function toolNameList(names) {
52
58
  return '<p class="muted">None</p>';
53
59
  return '<ul class="tool-name-list">' + [...new Set(names)].sort().map(name => '<li><code>' + dashboardEscape(name) + '</code></li>').join('') + '</ul>';
54
60
  }
55
- exports.dashboardPresentationClient = compactNumber.toString() + ';' + 'const channelIcons=' + JSON.stringify(channelIcons) + ';' + dashboardEscape.toString() + ';' + agentBadge.toString() + ';' + channelBadge.toString() + ';' + taskStatusBadge.toString() + ';' + toolNameList.toString() + ';';
61
+ exports.dashboardPresentationClient = 'const dashboardChartPalette=' + JSON.stringify(exports.dashboardChartPalette) + ';' + compactNumber.toString() + ';' + 'const channelIcons=' + JSON.stringify(channelIcons) + ';' + dashboardEscape.toString() + ';' + agentHue.toString() + ';' + agentBadge.toString() + ';' + channelBadge.toString() + ';' + taskStatusBadge.toString() + ';' + toolNameList.toString() + ';';
56
62
  //# sourceMappingURL=dashboard-presentation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-presentation.js","sourceRoot":"","sources":["../../src/ui/dashboard-presentation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dashboard-presentation.js","sourceRoot":"","sources":["../../src/ui/dashboard-presentation.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- /** Calendar windows include today, starting at 00:00 UTC. */
1
+ /** Calendar windows include today, starting at 00:00 in the configured timezone (UTC by default). */
2
2
  export declare function dashboardRange(value: unknown): string;
3
- export declare function dashboardSince(value: unknown, now?: number): number;
4
- export declare function rangeButtons(id: string, selected: string): string;
3
+ export declare function dashboardSince(value: unknown, now?: number, timezone?: string): number;
4
+ export declare function rangeButtons(id: string, selected: string, timezone?: string): string;
5
5
  //# sourceMappingURL=dashboard-range.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-range.d.ts","sourceRoot":"","sources":["../../src/ui/dashboard-range.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAErD;AACD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,SAAa,GAAG,MAAM,CAKvE;AACD,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjE"}
1
+ {"version":3,"file":"dashboard-range.d.ts","sourceRoot":"","sources":["../../src/ui/dashboard-range.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAErD;AACD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,SAAa,EAAE,QAAQ,SAAQ,GAAG,MAAM,CAmBzF;AACD,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,SAAQ,GAAG,MAAM,CAGnF"}
@@ -3,18 +3,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dashboardRange = dashboardRange;
4
4
  exports.dashboardSince = dashboardSince;
5
5
  exports.rangeButtons = rangeButtons;
6
- /** Calendar windows include today, starting at 00:00 UTC. */
6
+ /** Calendar windows include today, starting at 00:00 in the configured timezone (UTC by default). */
7
7
  function dashboardRange(value) {
8
8
  return typeof value === 'string' && ['24h', '7d', '30d', '90d', 'all'].includes(value) ? value : '24h';
9
9
  }
10
- function dashboardSince(value, now = Date.now()) {
10
+ function dashboardSince(value, now = Date.now(), timezone = 'UTC') {
11
11
  const range = dashboardRange(value);
12
12
  if (range === 'all')
13
13
  return 0;
14
14
  const days = range === '24h' ? 1 : Number(range.slice(0, -1));
15
- return Math.floor(now / 86400000) * 86400000 - (days - 1) * 86400000;
15
+ const parts = new Intl.DateTimeFormat('en-CA', { timeZone: timezone, year: 'numeric', month: '2-digit', day: '2-digit' }).formatToParts(now);
16
+ const part = (name) => Number(parts.find(p => p.type === name).value);
17
+ const target = Date.UTC(part('year'), part('month') - 1, part('day') - (days - 1));
18
+ // Resolve midnight in the configured zone, including changes in UTC offset.
19
+ let instant = target;
20
+ const clock = new Intl.DateTimeFormat('en-GB', { timeZone: timezone, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hourCycle: 'h23' });
21
+ for (let i = 0; i < 4; i++) {
22
+ const values = clock.formatToParts(instant);
23
+ const v = (name) => Number(values.find(p => p.type === name).value);
24
+ const local = Date.UTC(v('year'), v('month') - 1, v('day'), v('hour'), v('minute'), v('second'));
25
+ const next = instant + target - local;
26
+ if (next === instant)
27
+ break;
28
+ instant = next;
29
+ }
30
+ return instant;
16
31
  }
17
- function rangeButtons(id, selected) {
18
- return '<div id="' + id + '" class="range-toggle" role="group" aria-label="Date range, from midnight UTC">' + ['24h', '7d', '30d', '90d', 'all'].map(value => '<button type="button" data-range="' + value + '" aria-pressed="' + (value === selected) + '" title="' + (value === '24h' ? 'Today from 00:00 UTC' : value === 'all' ? 'All recorded history' : value + ' including today, from 00:00 UTC') + '">' + value + '</button>').join('') + '</div>';
32
+ function rangeButtons(id, selected, timezone = 'UTC') {
33
+ timezone = timezone.replace(/[^A-Za-z0-9_+\/.-]/g, '');
34
+ return '<div id="' + id + '" class="range-toggle" role="group" aria-label="Date range, from midnight ' + timezone + '">' + ['24h', '7d', '30d', '90d', 'all'].map(value => '<button type="button" data-range="' + value + '" aria-pressed="' + (value === selected) + '" title="' + (value === '24h' ? 'Today from 00:00 ' + timezone : value === 'all' ? 'All recorded history' : value + ' including today, from 00:00 ' + timezone) + '">' + value + '</button>').join('') + '</div>';
19
35
  }
20
36
  //# sourceMappingURL=dashboard-range.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-range.js","sourceRoot":"","sources":["../../src/ui/dashboard-range.ts"],"names":[],"mappings":";;AACA,wCAEC;AACD,wCAKC;AACD,oCAEC;AAZD,6DAA6D;AAC7D,SAAgB,cAAc,CAAC,KAAc;IAC5C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,EAAC,IAAI,EAAC,KAAK,EAAC,KAAK,EAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACpG,CAAC;AACD,SAAgB,cAAc,CAAC,KAAc,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAC9D,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,QAAQ,CAAC,GAAG,QAAQ,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;AACtE,CAAC;AACD,SAAgB,YAAY,CAAC,EAAU,EAAE,QAAgB;IACxD,OAAO,WAAW,GAAC,EAAE,GAAC,iFAAiF,GAAC,CAAC,KAAK,EAAC,IAAI,EAAC,KAAK,EAAC,KAAK,EAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAA,EAAE,CAAA,oCAAoC,GAAC,KAAK,GAAC,kBAAkB,GAAC,CAAC,KAAK,KAAG,QAAQ,CAAC,GAAC,WAAW,GAAC,CAAC,KAAK,KAAG,KAAK,CAAA,CAAC,CAAA,sBAAsB,CAAA,CAAC,CAAA,KAAK,KAAG,KAAK,CAAA,CAAC,CAAA,sBAAsB,CAAA,CAAC,CAAA,KAAK,GAAC,kCAAkC,CAAC,GAAC,IAAI,GAAC,KAAK,GAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAC,QAAQ,CAAC;AAC/Y,CAAC"}
1
+ {"version":3,"file":"dashboard-range.js","sourceRoot":"","sources":["../../src/ui/dashboard-range.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
+ /** Favicon rendered from the original main-branch brandmark (35px at 4x). */
2
+ export declare const dashboardIconUrl = "data:image/png;base64,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";
1
3
  /** Shared tokens from the approved pastel dashboard direction. */
2
4
  export declare const dashboardTheme: string;
3
- export declare const dashboardFontLink = "<script>(function(){var i=location.pathname.lastIndexOf('/dashboard');if(i<0)return;var l=document.createElement('link');l.rel='stylesheet';l.href=location.pathname.slice(0,i)+'/dashboard/fonts.css';document.head.appendChild(l);})();</script>";
5
+ export declare const dashboardFontLink: string;
4
6
  //# sourceMappingURL=dashboard-theme.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-theme.d.ts","sourceRoot":"","sources":["../../src/ui/dashboard-theme.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,eAAO,MAAM,cAAc,QA8d1B,CAAC;AACF,eAAO,MAAM,iBAAiB,uPAAuP,CAAC"}
1
+ {"version":3,"file":"dashboard-theme.d.ts","sourceRoot":"","sources":["../../src/ui/dashboard-theme.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,2snBAA2snB,CAAC;AACzunB,kEAAkE;AAClE,eAAO,MAAM,cAAc,QAyiB1B,CAAC;AACF,eAAO,MAAM,iBAAiB,QAA0T,CAAC"}