claude-code-hub 1.0.3 → 1.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": "claude-code-hub",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "Unified hub for Claude Code tools — Marketplace + Kanban in one PWA",
5
5
  "main": "server.js",
6
6
  "bin": {
@@ -45,10 +45,10 @@
45
45
  },
46
46
  "homepage": "https://github.com/NikiforovAll/claude-code-hub#readme",
47
47
  "dependencies": {
48
- "claude-code-cost": "1.0.0",
49
- "claude-code-kanban": "5.1.1",
50
- "claude-code-marketplace": "1.0.0",
51
- "claude-code-memory-explorer": "1.0.0",
48
+ "claude-code-cost": "1.1.0",
49
+ "claude-code-kanban": "5.2.0",
50
+ "claude-code-marketplace": "1.1.0",
51
+ "claude-code-memory-explorer": "1.1.0",
52
52
  "express": "^4.21.0",
53
53
  "open": "^10.1.0"
54
54
  },
package/public/app.js CHANGED
@@ -229,6 +229,7 @@ async function init() {
229
229
  listenKeys();
230
230
  bindPalette();
231
231
  registerSW();
232
+ bindErrorToast();
232
233
  showUpdateToast();
233
234
  }
234
235
 
@@ -273,6 +274,37 @@ async function showUpdateToast() {
273
274
  arm();
274
275
  }
275
276
 
277
+ const ERROR_TOAST_MS = 8_000;
278
+ let errorToastTimer = 0;
279
+
280
+ function hideErrorToast() {
281
+ clearTimeout(errorToastTimer);
282
+ const toast = document.getElementById('error-toast');
283
+ toast.classList.add('leaving');
284
+ setTimeout(() => (toast.hidden = true), 200);
285
+ }
286
+
287
+ // A 401 means the hub_token cookie no longer matches the token file. Opening /?token=… sets a new
288
+ // cookie; reloading lands on the locked page, where the token can be pasted instead.
289
+ function showErrorToast(action, err) {
290
+ const unauthorized = err.status === 401;
291
+ document.getElementById('error-title').textContent = unauthorized ? `${action}: hub token rejected` : action;
292
+ document.getElementById('error-detail').textContent = unauthorized
293
+ ? `This browser has an old hub token. Open the link the hub printed in the terminal (${location.origin}/?token=…) to renew it.`
294
+ : err.message;
295
+ document.getElementById('error-actions').hidden = !unauthorized;
296
+ const toast = document.getElementById('error-toast');
297
+ toast.classList.remove('leaving');
298
+ toast.hidden = false;
299
+ clearTimeout(errorToastTimer);
300
+ if (!unauthorized) errorToastTimer = setTimeout(hideErrorToast, ERROR_TOAST_MS);
301
+ }
302
+
303
+ function bindErrorToast() {
304
+ document.getElementById('error-close').addEventListener('click', hideErrorToast);
305
+ document.getElementById('error-reload').addEventListener('click', () => location.reload());
306
+ }
307
+
276
308
  // The hub has no visible chrome, so the window/tab title is the only place the active config dir
277
309
  // shows. Only a non-default dir is named, and by basename alone — the PWA window prepends the
278
310
  // manifest name, so a product name here would read as "Claude Code Hub - .claude-eom · Hub".
@@ -722,7 +754,7 @@ async function removeConfigDir(dirPath) {
722
754
  try {
723
755
  palette.configDirs = await sendJson('DELETE', '/api/config-dirs', { path: dirPath });
724
756
  } catch (err) {
725
- console.warn('remove config dir failed:', err.message);
757
+ showErrorToast('Could not remove config dir', err);
726
758
  return;
727
759
  }
728
760
  if (dirPath in themeState.colorThemes) {
@@ -993,7 +1025,10 @@ function openPalette(mode) {
993
1025
  .then(() => {
994
1026
  if (palette.open && palette.mode === mode) renderPalette();
995
1027
  })
996
- .catch((err) => console.warn(`${mode} list unavailable:`, err.message));
1028
+ .catch((err) => {
1029
+ if (err.status === 401) showErrorToast('Could not load the list', err);
1030
+ else console.warn(`${mode} list unavailable:`, err.message);
1031
+ });
997
1032
  }
998
1033
 
999
1034
  function closePalette() {
@@ -1057,7 +1092,7 @@ async function commitConfigDir(row) {
1057
1092
  try {
1058
1093
  target = (await withPaletteBusy(() => sendJson('POST', '/api/config-dirs', { path: row.path }))).path;
1059
1094
  } catch (err) {
1060
- console.warn('add config dir failed:', err.message);
1095
+ showErrorToast('Could not add config dir', err);
1061
1096
  return;
1062
1097
  }
1063
1098
  }
@@ -1075,7 +1110,7 @@ async function commitConfigDir(row) {
1075
1110
  applyHubTheme();
1076
1111
  reloadIframes();
1077
1112
  } catch (err) {
1078
- console.warn('config dir switch failed:', err.message);
1113
+ showErrorToast('Could not switch config dir', err);
1079
1114
  hideLoading();
1080
1115
  }
1081
1116
  }
package/public/index.html CHANGED
@@ -376,6 +376,7 @@
376
376
  }
377
377
 
378
378
  .update-toast-close:hover { color: var(--text); }
379
+ .error-toast { z-index: 25; border-left-color: #e5484d; }
379
380
  </style>
380
381
  </head>
381
382
  <body>
@@ -448,6 +449,17 @@
448
449
  <button class="update-toast-close" id="update-close" type="button" aria-label="Close">×</button>
449
450
  </div>
450
451
 
452
+ <div class="update-toast error-toast" id="error-toast" role="alert" hidden>
453
+ <div class="update-toast-body">
454
+ <div class="update-toast-title" id="error-title"></div>
455
+ <div class="update-toast-meta" id="error-detail"></div>
456
+ <div class="update-toast-actions" id="error-actions" hidden>
457
+ <button class="update-toast-skip" id="error-reload" type="button">Paste token instead</button>
458
+ </div>
459
+ </div>
460
+ <button class="update-toast-close" id="error-close" type="button" aria-label="Close">×</button>
461
+ </div>
462
+
451
463
  <script src="/app.js"></script>
452
464
  </body>
453
465
  </html>