codedash-app 1.1.1 → 1.2.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": "1.1.1",
3
+ "version": "1.2.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"
@@ -829,7 +829,7 @@ function launchSession(sessionId, tool, project) {
829
829
 
830
830
  function copyResume(sessionId, tool) {
831
831
  var cmd = tool === 'codex'
832
- ? 'codex --resume ' + sessionId
832
+ ? 'codex resume ' + sessionId
833
833
  : 'claude --resume ' + sessionId;
834
834
  navigator.clipboard.writeText(cmd).then(function() {
835
835
  showToast('Copied: ' + cmd);
@@ -1099,12 +1099,44 @@ document.addEventListener('keydown', function(e) {
1099
1099
  }
1100
1100
  });
1101
1101
 
1102
+ // ── Update check ──────────────────────────────────────────────
1103
+
1104
+ async function checkForUpdates() {
1105
+ try {
1106
+ var resp = await fetch('/api/version');
1107
+ var data = await resp.json();
1108
+ if (data.updateAvailable) {
1109
+ var banner = document.getElementById('updateBanner');
1110
+ var text = document.getElementById('updateText');
1111
+ if (banner && text) {
1112
+ text.textContent = 'Update available: v' + data.current + ' → v' + data.latest;
1113
+ banner.style.display = 'flex';
1114
+ banner.dataset.cmd = 'npm update -g codedash-app && codedash run';
1115
+ }
1116
+ }
1117
+ } catch {}
1118
+ }
1119
+
1120
+ function copyUpdate() {
1121
+ var banner = document.getElementById('updateBanner');
1122
+ var cmd = banner ? banner.dataset.cmd : 'npm update -g codedash-app';
1123
+ navigator.clipboard.writeText(cmd).then(function() {
1124
+ showToast('Copied: ' + cmd);
1125
+ });
1126
+ }
1127
+
1128
+ function dismissUpdate() {
1129
+ var banner = document.getElementById('updateBanner');
1130
+ if (banner) banner.style.display = 'none';
1131
+ }
1132
+
1102
1133
  // ── Initialization ─────────────────────────────────────────────
1103
1134
 
1104
1135
  (function init() {
1105
1136
  // Load data
1106
1137
  loadSessions();
1107
1138
  loadTerminals();
1139
+ checkForUpdates();
1108
1140
 
1109
1141
  // Apply saved theme
1110
1142
  var savedTheme = localStorage.getItem('codedash-theme') || 'dark';
@@ -111,6 +111,12 @@
111
111
 
112
112
  <div class="toast" id="toast"></div>
113
113
 
114
+ <div class="update-banner" id="updateBanner" style="display:none">
115
+ <span id="updateText"></span>
116
+ <button class="update-btn" onclick="copyUpdate()">Copy update command</button>
117
+ <button class="update-dismiss" onclick="dismissUpdate()">&times;</button>
118
+ </div>
119
+
114
120
  <script>{{SCRIPT}}</script>
115
121
  </body>
116
122
  </html>
@@ -1370,6 +1370,52 @@ body {
1370
1370
  color: #fff;
1371
1371
  }
1372
1372
 
1373
+ /* ── Update banner ──────────────────────────────────────────── */
1374
+
1375
+ .update-banner {
1376
+ position: fixed;
1377
+ top: 0;
1378
+ left: 200px;
1379
+ right: 0;
1380
+ background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple));
1381
+ color: #fff;
1382
+ padding: 10px 20px;
1383
+ display: flex;
1384
+ align-items: center;
1385
+ gap: 12px;
1386
+ font-size: 13px;
1387
+ z-index: 200;
1388
+ animation: slideDown 0.3s ease;
1389
+ }
1390
+
1391
+ @keyframes slideDown {
1392
+ from { transform: translateY(-100%); }
1393
+ to { transform: translateY(0); }
1394
+ }
1395
+
1396
+ .update-btn {
1397
+ background: rgba(255,255,255,0.2);
1398
+ border: 1px solid rgba(255,255,255,0.3);
1399
+ color: #fff;
1400
+ padding: 4px 12px;
1401
+ border-radius: 6px;
1402
+ font-size: 12px;
1403
+ cursor: pointer;
1404
+ white-space: nowrap;
1405
+ }
1406
+ .update-btn:hover { background: rgba(255,255,255,0.3); }
1407
+
1408
+ .update-dismiss {
1409
+ background: none;
1410
+ border: none;
1411
+ color: rgba(255,255,255,0.7);
1412
+ font-size: 18px;
1413
+ cursor: pointer;
1414
+ margin-left: auto;
1415
+ padding: 0 4px;
1416
+ }
1417
+ .update-dismiss:hover { color: #fff; }
1418
+
1373
1419
  /* ── List view ──────────────────────────────────────────────── */
1374
1420
 
1375
1421
  .list-view {
package/src/server.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // HTTP server + API routes
2
2
  const http = require('http');
3
+ const https = require('https');
3
4
  const { URL } = require('url');
4
5
  const { exec } = require('child_process');
5
6
  const { loadSessions, loadSessionDetail, deleteSession, getGitCommits, exportSessionMarkdown } = require('./data');
@@ -103,6 +104,18 @@ function startServer(port, openBrowser = true) {
103
104
  json(res, commits);
104
105
  }
105
106
 
107
+ // ── Version check ────────────────────────
108
+ else if (req.method === 'GET' && pathname === '/api/version') {
109
+ const pkg = require('../package.json');
110
+ const current = pkg.version;
111
+ // Fetch latest from npm registry
112
+ fetchLatestVersion(pkg.name).then(latest => {
113
+ json(res, { current, latest, updateAvailable: latest && latest !== current && isNewer(latest, current) });
114
+ }).catch(() => {
115
+ json(res, { current, latest: null, updateAvailable: false });
116
+ });
117
+ }
118
+
106
119
  // ── 404 ─────────────────────────────────
107
120
  else {
108
121
  res.writeHead(404);
@@ -139,4 +152,29 @@ function readBody(req, cb) {
139
152
  req.on('end', () => cb(body));
140
153
  }
141
154
 
155
+ // ── npm version check ───────────────────
156
+ function fetchLatestVersion(packageName) {
157
+ return new Promise((resolve, reject) => {
158
+ https.get(`https://registry.npmjs.org/${packageName}/latest`, { timeout: 5000 }, (res) => {
159
+ let data = '';
160
+ res.on('data', chunk => data += chunk);
161
+ res.on('end', () => {
162
+ try {
163
+ resolve(JSON.parse(data).version);
164
+ } catch { reject(); }
165
+ });
166
+ }).on('error', reject);
167
+ });
168
+ }
169
+
170
+ function isNewer(latest, current) {
171
+ const l = latest.split('.').map(Number);
172
+ const c = current.split('.').map(Number);
173
+ for (let i = 0; i < 3; i++) {
174
+ if ((l[i] || 0) > (c[i] || 0)) return true;
175
+ if ((l[i] || 0) < (c[i] || 0)) return false;
176
+ }
177
+ return false;
178
+ }
179
+
142
180
  module.exports = { startServer };
package/src/terminals.js CHANGED
@@ -70,7 +70,7 @@ function openInTerminal(sessionId, tool, flags, projectDir, terminalId) {
70
70
  let cmd;
71
71
 
72
72
  if (tool === 'codex') {
73
- cmd = `codex --resume ${sessionId}`;
73
+ cmd = `codex resume ${sessionId}`;
74
74
  } else {
75
75
  cmd = `claude --resume ${sessionId}`;
76
76
  if (skipPerms) cmd += ' --dangerously-skip-permissions';