codedash-app 3.0.2 → 3.1.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codedash-app",
3
- "version": "3.0.2",
3
+ "version": "3.1.0",
4
4
  "description": "Termius-style browser dashboard for Claude Code sessions. View, search, resume, and delete sessions with a dark-themed UI.",
5
5
  "bin": {
6
6
  "codedash": "./bin/cli.js"
@@ -236,8 +236,15 @@ async function pollActiveSessions() {
236
236
  var top = card.querySelector('.card-top');
237
237
  if (top) top.insertBefore(badge, top.firstChild);
238
238
 
239
- // Add animated border wrapper if not already wrapped
240
- if (!parent || !parent.classList.contains('card-live-wrap')) {
239
+ // Add/update animated border wrapper
240
+ if (parent && parent.classList.contains('card-live-wrap')) {
241
+ // Update status class on existing wrapper
242
+ parent.className = 'card-live-wrap' + (a.status === 'waiting' ? ' live-waiting' : '');
243
+ parent.style.setProperty('--live-color', a.status === 'waiting'
244
+ ? 'rgba(251, 191, 36, 0.5)'
245
+ : 'rgba(74, 222, 128, 0.7)');
246
+ } else {
247
+ // Create new wrapper
241
248
  var wrap = document.createElement('div');
242
249
  wrap.className = 'card-live-wrap' + (a.status === 'waiting' ? ' live-waiting' : '');
243
250
  wrap.style.setProperty('--live-color', a.status === 'waiting'
@@ -718,6 +725,11 @@ function render() {
718
725
  return;
719
726
  }
720
727
 
728
+ if (currentView === 'running') {
729
+ renderRunning(content);
730
+ return;
731
+ }
732
+
721
733
  if (currentView === 'starred') {
722
734
  var starredSessions = sessions.filter(function(s) { return stars.indexOf(s.id) >= 0; });
723
735
  if (starredSessions.length === 0) {
@@ -1426,6 +1438,64 @@ document.addEventListener('keydown', function(e) {
1426
1438
  }
1427
1439
  });
1428
1440
 
1441
+ // ── Running Sessions View ──────────────────────────────────────
1442
+
1443
+ function renderRunning(container) {
1444
+ var activeIds = Object.keys(activeSessions);
1445
+
1446
+ if (activeIds.length === 0) {
1447
+ container.innerHTML = '<div class="empty-state">No running sessions detected.<br><span style="font-size:12px;color:var(--text-muted)">Start a Claude Code or Codex session and it will appear here.</span></div>';
1448
+ return;
1449
+ }
1450
+
1451
+ var html = '<div class="running-container">';
1452
+ html += '<h2 class="heatmap-title">Running Sessions</h2>';
1453
+
1454
+ activeIds.forEach(function(sid) {
1455
+ var a = activeSessions[sid];
1456
+ var s = allSessions.find(function(x) { return x.id === sid; });
1457
+ var projName = s ? getProjectName(s.project) : (a.cwd ? a.cwd.split('/').pop() : 'unknown');
1458
+ var projColor = getProjectColor(projName);
1459
+ var statusClass = a.status === 'waiting' ? 'running-waiting' : 'running-active';
1460
+ var uptime = a.startedAt ? formatDuration(Date.now() - a.startedAt) : '';
1461
+
1462
+ html += '<div class="running-card ' + statusClass + '">';
1463
+ html += '<div class="running-card-header">';
1464
+ html += '<span class="live-badge live-' + a.status + '">' + (a.status === 'waiting' ? 'WAITING' : 'LIVE') + '</span>';
1465
+ html += '<span class="running-project" style="color:' + projColor + '">' + escHtml(projName) + '</span>';
1466
+ html += '<span class="running-tool">' + escHtml(a.entrypoint || a.kind || 'claude') + '</span>';
1467
+ html += '</div>';
1468
+
1469
+ // Stats row
1470
+ html += '<div class="running-stats">';
1471
+ html += '<div class="running-stat"><span class="running-stat-val">' + a.cpu.toFixed(1) + '%</span><span class="running-stat-label">CPU</span></div>';
1472
+ html += '<div class="running-stat"><span class="running-stat-val">' + a.memoryMB + 'MB</span><span class="running-stat-label">Memory</span></div>';
1473
+ html += '<div class="running-stat"><span class="running-stat-val">' + a.pid + '</span><span class="running-stat-label">PID</span></div>';
1474
+ if (uptime) {
1475
+ html += '<div class="running-stat"><span class="running-stat-val">' + uptime + '</span><span class="running-stat-label">Uptime</span></div>';
1476
+ }
1477
+ html += '</div>';
1478
+
1479
+ // Message preview
1480
+ if (s && s.first_message) {
1481
+ html += '<div class="running-msg">' + escHtml(s.first_message.slice(0, 150)) + '</div>';
1482
+ }
1483
+
1484
+ // Action buttons
1485
+ html += '<div class="running-actions">';
1486
+ html += '<button class="launch-btn" style="background:var(--accent-green);color:#000" onclick="focusSession(\'' + sid + '\')">Focus Terminal</button>';
1487
+ if (s) {
1488
+ html += '<button class="launch-btn btn-secondary" onclick="var ss=allSessions.find(function(x){return x.id===\'' + sid + '\'});if(ss)openDetail(ss);">Details</button>';
1489
+ }
1490
+ html += '</div>';
1491
+
1492
+ html += '</div>';
1493
+ });
1494
+
1495
+ html += '</div>';
1496
+ container.innerHTML = html;
1497
+ }
1498
+
1429
1499
  // ── Session Replay ────────────────────────────────────────────
1430
1500
 
1431
1501
  async function openReplay(sessionId, project) {
@@ -30,6 +30,10 @@
30
30
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><rect x="7" y="7" width="3" height="3"/><rect x="14" y="7" width="3" height="3"/><rect x="7" y="14" width="3" height="3"/><rect x="14" y="14" width="3" height="3"/></svg>
31
31
  Activity
32
32
  </div>
33
+ <div class="sidebar-item" data-view="running">
34
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polygon points="10 8 16 12 10 16 10 8"/></svg>
35
+ Running
36
+ </div>
33
37
  <div class="sidebar-item" data-view="analytics">
34
38
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>
35
39
  Analytics
@@ -1582,6 +1582,53 @@ body {
1582
1582
  box-shadow: 0 8px 32px rgba(0,0,0,0.12);
1583
1583
  }
1584
1584
 
1585
+ /* ── Running Sessions View ──────────────────────────────────── */
1586
+
1587
+ .running-container { padding: 20px; }
1588
+
1589
+ .running-card {
1590
+ background: var(--bg-card);
1591
+ border: 1px solid var(--border);
1592
+ border-radius: 12px;
1593
+ padding: 20px;
1594
+ margin-bottom: 12px;
1595
+ }
1596
+
1597
+ .running-active { border-left: 3px solid var(--accent-green); }
1598
+ .running-waiting { border-left: 3px solid #f59e0b; }
1599
+
1600
+ .running-card-header {
1601
+ display: flex;
1602
+ align-items: center;
1603
+ gap: 12px;
1604
+ margin-bottom: 14px;
1605
+ }
1606
+
1607
+ .running-project { font-size: 16px; font-weight: 600; }
1608
+ .running-tool { font-size: 12px; color: var(--text-muted); margin-left: auto; }
1609
+
1610
+ .running-stats {
1611
+ display: flex;
1612
+ gap: 24px;
1613
+ margin-bottom: 12px;
1614
+ }
1615
+
1616
+ .running-stat { display: flex; flex-direction: column; gap: 2px; }
1617
+ .running-stat-val { font-size: 18px; font-weight: 700; color: var(--text-primary); }
1618
+ .running-stat-label { font-size: 11px; color: var(--text-muted); }
1619
+
1620
+ .running-msg {
1621
+ font-size: 13px;
1622
+ color: var(--text-secondary);
1623
+ padding: 10px;
1624
+ background: rgba(255,255,255,0.03);
1625
+ border-radius: 8px;
1626
+ margin-bottom: 12px;
1627
+ line-height: 1.5;
1628
+ }
1629
+
1630
+ .running-actions { display: flex; gap: 8px; }
1631
+
1585
1632
  /* ── Session Replay ─────────────────────────────────────────── */
1586
1633
 
1587
1634
  .replay-container { padding: 20px; }