shell-mirror 1.5.37 → 1.5.39

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": "shell-mirror",
3
- "version": "1.5.37",
3
+ "version": "1.5.39",
4
4
  "description": "Access your Mac shell from any device securely. Perfect for mobile coding with Claude Code CLI, Gemini CLI, and any shell tool.",
5
5
  "main": "server.js",
6
6
  "bin": {
@@ -294,6 +294,10 @@ body {
294
294
  border-bottom: 1px solid #f0f0f0;
295
295
  }
296
296
 
297
+ .session-item.compact {
298
+ padding: 12px 0;
299
+ }
300
+
297
301
  .session-item:last-child {
298
302
  border-bottom: none;
299
303
  }
@@ -345,6 +349,11 @@ body {
345
349
  color: #f57c00;
346
350
  }
347
351
 
352
+ .session-status.disconnected {
353
+ background: #f5f5f5;
354
+ color: #666;
355
+ }
356
+
348
357
  /* Empty States */
349
358
  .no-data {
350
359
  text-align: center;
@@ -46,6 +46,13 @@
46
46
  <p>Loading dashboard...</p>
47
47
  </div>
48
48
 
49
+ <!-- Version Footer -->
50
+ <footer style="background: #ff6b35; color: white; text-align: center; padding: 10px 0; font-size: 0.8rem; position: fixed; bottom: 0; left: 0; right: 0; z-index: 1000;">
51
+ <div style="max-width: 1200px; margin: 0 auto;">
52
+ <p id="dashboard-version-info">Shell Mirror Dashboard • Loading version...</p>
53
+ </div>
54
+ </footer>
55
+
49
56
  <script src="dashboard.js"></script>
50
57
  </body>
51
58
  </html>
@@ -10,6 +10,7 @@ class ShellMirrorDashboard {
10
10
 
11
11
  async init() {
12
12
  this.showLoading();
13
+ this.loadVersionInfo(); // Load version info immediately
13
14
 
14
15
  try {
15
16
  const authStatus = await this.checkAuthStatus();
@@ -109,7 +110,10 @@ class ShellMirrorDashboard {
109
110
  `;
110
111
 
111
112
  // Show centered login button
112
- document.getElementById('login-button-overlay').style.display = 'flex';
113
+ const loginOverlay = document.getElementById('login-button-overlay');
114
+ if (loginOverlay) {
115
+ loginOverlay.style.display = 'flex';
116
+ }
113
117
  }
114
118
 
115
119
  renderAuthenticatedDashboard() {
@@ -137,12 +141,21 @@ class ShellMirrorDashboard {
137
141
  `;
138
142
 
139
143
  // Hide login button overlay
140
- document.getElementById('login-button-overlay').style.display = 'none';
144
+ const loginOverlay = document.getElementById('login-button-overlay');
145
+ if (loginOverlay) {
146
+ loginOverlay.style.display = 'none';
147
+ }
141
148
  }
142
149
 
143
150
  renderActiveAgents() {
144
- const agentCount = this.agents.length;
145
- const agentsHtml = this.agents.map(agent => `
151
+ // Filter for recently active agents (online or seen within last 5 minutes)
152
+ const activeAgents = this.agents.filter(agent => {
153
+ const timeSinceLastSeen = Date.now() / 1000 - agent.lastSeen;
154
+ return agent.onlineStatus === 'online' || timeSinceLastSeen < 300; // 5 minutes
155
+ });
156
+
157
+ const agentCount = activeAgents.length;
158
+ const agentsHtml = activeAgents.map(agent => `
146
159
  <div class="agent-item">
147
160
  <div class="agent-info">
148
161
  <div class="agent-name">${agent.machineName || agent.agentId}</div>
@@ -193,8 +206,31 @@ class ShellMirrorDashboard {
193
206
  }
194
207
 
195
208
  renderRecentSessions() {
196
- const sessionsHtml = this.sessions.map(session => `
197
- <div class="session-item">
209
+ // Get inactive agents (not seen in last 5 minutes and offline)
210
+ const inactiveAgents = this.agents.filter(agent => {
211
+ const timeSinceLastSeen = Date.now() / 1000 - agent.lastSeen;
212
+ return agent.onlineStatus === 'offline' && timeSinceLastSeen >= 300; // More than 5 minutes
213
+ });
214
+
215
+ // Combine real sessions with inactive agents as past connections
216
+ const allSessions = [
217
+ // Add inactive agents as past connections
218
+ ...inactiveAgents.map(agent => ({
219
+ type: 'past_agent',
220
+ agentId: agent.machineName || agent.agentId,
221
+ startTime: new Date(agent.lastSeen * 1000),
222
+ duration: 'Last connection',
223
+ status: 'disconnected'
224
+ })),
225
+ // Add actual session history
226
+ ...this.sessions
227
+ ];
228
+
229
+ // Sort by most recent
230
+ allSessions.sort((a, b) => b.startTime - a.startTime);
231
+
232
+ const sessionsHtml = allSessions.map(session => `
233
+ <div class="session-item compact">
198
234
  <div class="session-info">
199
235
  <div class="session-agent">${session.agentId}</div>
200
236
  <div class="session-time">${this.formatDate(session.startTime)}</div>
@@ -210,7 +246,7 @@ class ShellMirrorDashboard {
210
246
  <div class="dashboard-card full-width">
211
247
  <h2>📊 Recent Sessions</h2>
212
248
  <div class="card-content">
213
- ${this.sessions.length > 0 ? sessionsHtml : '<p class="no-data">No recent sessions</p>'}
249
+ ${allSessions.length > 0 ? sessionsHtml : '<p class="no-data">No recent sessions</p>'}
214
250
  </div>
215
251
  </div>
216
252
  `;
@@ -317,6 +353,30 @@ class ShellMirrorDashboard {
317
353
  }).format(date);
318
354
  }
319
355
 
356
+ // Load version info for footer
357
+ async loadVersionInfo() {
358
+ try {
359
+ const response = await fetch('/build-info.json');
360
+ const buildInfo = await response.json();
361
+ const versionElement = document.getElementById('dashboard-version-info');
362
+ const footerElement = versionElement?.parentElement?.parentElement; // Get the footer element
363
+
364
+ if (versionElement && buildInfo) {
365
+ const buildDateTime = new Date(buildInfo.buildTime).toLocaleString();
366
+ versionElement.textContent = `Shell Mirror Dashboard v${buildInfo.version} • Built ${buildDateTime}`;
367
+
368
+ // Apply random footer color from build info
369
+ if (footerElement && buildInfo.footerColor) {
370
+ footerElement.style.background = buildInfo.footerColor;
371
+ console.log(`🎨 Applied footer color: ${buildInfo.footerColor}`);
372
+ }
373
+ }
374
+ } catch (error) {
375
+ console.log('Could not load build info for dashboard:', error);
376
+ // Keep default version and color if build-info.json not available
377
+ }
378
+ }
379
+
320
380
  // Action handlers
321
381
  async connectToAgent(agentId) {
322
382
  window.location.href = `/app/terminal.html?agent=${agentId}`;
@@ -79,8 +79,8 @@ async function loadVersionInfo() {
79
79
  const footerElement = versionElement?.parentElement?.parentElement; // Get the footer element
80
80
 
81
81
  if (versionElement && buildInfo) {
82
- const buildDate = new Date(buildInfo.buildTime).toLocaleDateString();
83
- versionElement.textContent = `Terminal Mirror v${buildInfo.version} • Built ${buildDate}`;
82
+ const buildDateTime = new Date(buildInfo.buildTime).toLocaleString();
83
+ versionElement.textContent = `Terminal Mirror v${buildInfo.version} • Built ${buildDateTime}`;
84
84
 
85
85
  // Apply random footer color from build info
86
86
  if (footerElement && buildInfo.footerColor) {