@@ -115,8 +115,8 @@ class Dashboard {
115115 <div class="dashboard-summary-title">Status</div>
116116 <div id="dashboard-status-summary" class="dashboard-summary-body">Loading…</div>
117117 </div>
118- <div class="dashboard-summary-card">
119- <div class="dashboard-summary-title">Telemetry</div>
118+ <div class="dashboard-summary-card">
119+ <div class="dashboard-summary-title">Telemetry</div>
120120 <div id="dashboard-telemetry-summary" class="dashboard-summary-body">Loading…</div>
121121 <div class="dashboard-summary-actions">
122122 <button class="dashboard-topbar-btn" id="dashboard-open-telemetry-details" title="View trends and histograms">📈 Details</button>
@@ -127,6 +127,13 @@ class Dashboard {
127127 <button class="dashboard-topbar-btn" id="dashboard-export-telemetry-json" title="Download telemetry JSON export">⬇ JSON</button>
128128 </div>
129129 </div>
130+ <div class="dashboard-summary-card">
131+ <div class="dashboard-summary-title">Polecats</div>
132+ <div id="dashboard-polecats-summary" class="dashboard-summary-body">Loading…</div>
133+ <div class="dashboard-summary-actions">
134+ <button class="dashboard-topbar-btn" id="dashboard-open-polecats-card" title="Open Polecats panel">🐾 Manage</button>
135+ </div>
136+ </div>
130137 <div class="dashboard-summary-card">
131138 <div class="dashboard-summary-title">Projects</div>
132139 <div id="dashboard-projects-summary" class="dashboard-summary-body">Loading…</div>
@@ -194,6 +201,7 @@ class Dashboard {
194201 async loadDashboardProcessSummary ( ) {
195202 const statusEl = document . getElementById ( 'dashboard-status-summary' ) ;
196203 const telemetryEl = document . getElementById ( 'dashboard-telemetry-summary' ) ;
204+ const polecatsEl = document . getElementById ( 'dashboard-polecats-summary' ) ;
197205 const projectsEl = document . getElementById ( 'dashboard-projects-summary' ) ;
198206 const adviceEl = document . getElementById ( 'dashboard-advice-summary' ) ;
199207 const readinessEl = document . getElementById ( 'dashboard-readiness-summary' ) ;
@@ -209,6 +217,10 @@ class Dashboard {
209217 document . getElementById ( 'dashboard-open-polecats' ) ?. addEventListener ( 'click' , ( e ) => {
210218 e . preventDefault ( ) ;
211219 this . showPolecatOverlay ( ) . catch ( ( ) => { } ) ;
220+ } ) ;
221+ document . getElementById ( 'dashboard-open-polecats-card' ) ?. addEventListener ( 'click' , ( e ) => {
222+ e . preventDefault ( ) ;
223+ this . showPolecatOverlay ( ) . catch ( ( ) => { } ) ;
212224 } ) ;
213225 document . getElementById ( 'dashboard-open-tests' ) ?. addEventListener ( 'click' , ( e ) => {
214226 e . preventDefault ( ) ;
@@ -271,6 +283,12 @@ class Dashboard {
271283 } catch { }
272284 } ) ;
273285
286+ try {
287+ this . updatePolecatSummary ( polecatsEl ) ;
288+ } catch {
289+ // ignore
290+ }
291+
274292 const escapeHtml = ( value ) => String ( value ?? '' )
275293 . replace ( / & / g, '&' )
276294 . replace ( / < / g, '<' )
@@ -467,6 +485,56 @@ class Dashboard {
467485 }
468486 }
469487
488+ updatePolecatSummary ( targetEl = null ) {
489+ const el = targetEl || document . getElementById ( 'dashboard-polecats-summary' ) ;
490+ if ( ! el ) return ;
491+
492+ const sessionsMap = this . orchestrator ?. sessions ;
493+ const sessions = sessionsMap && typeof sessionsMap . values === 'function'
494+ ? Array . from ( sessionsMap . values ( ) )
495+ : [ ] ;
496+
497+ if ( ! sessions . length ) {
498+ el . textContent = 'No sessions.' ;
499+ return ;
500+ }
501+
502+ const byType = { claude : 0 , codex : 0 , server : 0 , other : 0 } ;
503+ const byStatus = { } ;
504+
505+ for ( const s of sessions ) {
506+ const type = String ( s ?. type || '' ) . trim ( ) . toLowerCase ( ) ;
507+ if ( type === 'claude' ) byType . claude += 1 ;
508+ else if ( type === 'codex' ) byType . codex += 1 ;
509+ else if ( type === 'server' ) byType . server += 1 ;
510+ else byType . other += 1 ;
511+
512+ const status = String ( s ?. status || 'idle' ) . trim ( ) . toLowerCase ( ) || 'idle' ;
513+ byStatus [ status ] = ( byStatus [ status ] || 0 ) + 1 ;
514+ }
515+
516+ const total = sessions . length ;
517+ const busy = byStatus . busy || 0 ;
518+ const waiting = byStatus . waiting || 0 ;
519+ const idle = byStatus . idle || 0 ;
520+ const otherStatuses = Object . entries ( byStatus )
521+ . filter ( ( [ k ] ) => k !== 'busy' && k !== 'waiting' && k !== 'idle' )
522+ . sort ( ( a , b ) => ( b [ 1 ] || 0 ) - ( a [ 1 ] || 0 ) )
523+ . map ( ( [ k , v ] ) => `${ k } :${ v } ` )
524+ . slice ( 0 , 4 )
525+ . join ( ' • ' ) ;
526+
527+ el . innerHTML = `
528+ <div>Total <strong>${ total } </strong></div>
529+ <div style="opacity:0.85; margin-top:4px;">
530+ Types: claude ${ byType . claude } • codex ${ byType . codex } • server ${ byType . server } ${ byType . other ? ` • other ${ byType . other } ` : '' }
531+ </div>
532+ <div style="opacity:0.85; margin-top:4px;">
533+ Status: busy ${ busy } • waiting ${ waiting } • idle ${ idle } ${ otherStatuses ? ` • ${ otherStatuses } ` : '' }
534+ </div>
535+ ` ;
536+ }
537+
470538 downloadTelemetryCsv ( lookbackHours ) {
471539 const hours = Number ( lookbackHours ) ;
472540 const safe = Number . isFinite ( hours ) && hours > 0 ? hours : 24 ;
0 commit comments