tabminal 1.3.9 → 1.3.11

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": "tabminal",
3
- "version": "1.3.9",
3
+ "version": "1.3.11",
4
4
  "description": "A modern, persistent web terminal with multi-tab support and real-time system monitoring.",
5
5
  "type": "module",
6
6
  "bin": {
package/public/app.js CHANGED
@@ -347,12 +347,17 @@ class ServerClient {
347
347
  handleUnauthorized(message = '') {
348
348
  this.needsAccessLogin = false;
349
349
  this.accessLoginUrl = '';
350
- this.clearAuth();
351
- setStatus(this, 'reconnecting');
352
- renderServerControls();
353
350
  if (this.isPrimary) {
351
+ this.clearAuth();
352
+ setStatus(this, 'reconnecting');
353
+ renderServerControls();
354
354
  auth.showLoginModal(message || 'Authentication required.');
355
355
  } else {
356
+ // Keep sub-host token untouched; only stop sync and require manual reconnect.
357
+ this.stopHeartbeat();
358
+ this.nextSyncAt = 0;
359
+ setStatus(this, 'reconnecting');
360
+ renderServerControls();
356
361
  alert(`${getDisplayHost(this)} needs login.`, {
357
362
  type: 'warning',
358
363
  title: 'Host'
@@ -2610,15 +2615,29 @@ function setStatus(server, status) {
2610
2615
 
2611
2616
  const activeServer = getActiveServer();
2612
2617
  if (!activeServer || activeServer.id !== server.id) return;
2618
+ const hostName = getDisplayHost(server);
2619
+ const target = hostName || 'host';
2613
2620
 
2614
2621
  if (status === 'reconnecting') {
2615
- alert('Lost connection. Reconnecting...', { type: 'warning', title: 'Connection' });
2622
+ alert(`Lost connection to ${target}. Reconnecting...`, {
2623
+ type: 'warning',
2624
+ title: 'Connection'
2625
+ });
2616
2626
  } else if (status === 'connected' && prevStatus === 'reconnecting') {
2617
- alert('Connection restored.', { type: 'success', title: 'Connection' });
2627
+ alert(`Connection to ${target} restored.`, {
2628
+ type: 'success',
2629
+ title: 'Connection'
2630
+ });
2618
2631
  } else if (status === 'terminated') {
2619
- alert('Session has ended.', { type: 'error', title: 'Connection' });
2632
+ alert(`Session on ${target} has ended.`, {
2633
+ type: 'error',
2634
+ title: 'Connection'
2635
+ });
2620
2636
  } else if (status === 'connected' && !prevStatus) {
2621
- alert('Connected to host.', { type: 'success', title: 'Connection' });
2637
+ alert(`Connected to ${target}.`, {
2638
+ type: 'success',
2639
+ title: 'Connection'
2640
+ });
2622
2641
  }
2623
2642
  }
2624
2643
 
@@ -3189,22 +3208,6 @@ let searchOptions = {
3189
3208
  wholeWord: false,
3190
3209
  regex: false
3191
3210
  };
3192
- const searchDecorations = {
3193
- matchBackground: '#ffffff',
3194
- matchBorder: '#ffffff',
3195
- matchOverviewRuler: '#ffffff',
3196
- activeMatchBackground: '#ffffff',
3197
- activeMatchBorder: '#ffffff',
3198
- activeMatchColorOverviewRuler: '#ffffff'
3199
- };
3200
-
3201
- function buildSearchRunOptions(extra = {}) {
3202
- return {
3203
- ...searchOptions,
3204
- ...extra,
3205
- decorations: searchDecorations
3206
- };
3207
- }
3208
3211
 
3209
3212
  if (searchBar) {
3210
3213
  const updateUI = (found) => {
@@ -3225,8 +3228,8 @@ if (searchBar) {
3225
3228
  const term = searchInput.value;
3226
3229
 
3227
3230
  let found = false;
3228
- if (forward) found = addon.findNext(term, buildSearchRunOptions());
3229
- else found = addon.findPrevious(term, buildSearchRunOptions());
3231
+ if (forward) found = addon.findNext(term, searchOptions);
3232
+ else found = addon.findPrevious(term, searchOptions);
3230
3233
 
3231
3234
  updateUI(found);
3232
3235
  };
@@ -3259,7 +3262,7 @@ if (searchBar) {
3259
3262
  // Incremental search
3260
3263
  const found = state.sessions.get(state.activeSessionKey).searchAddon.findNext(term, {
3261
3264
  incremental: true,
3262
- ...buildSearchRunOptions()
3265
+ ...searchOptions
3263
3266
  });
3264
3267
 
3265
3268
  updateUI(found);
package/public/index.html CHANGED
@@ -119,16 +119,26 @@
119
119
  </script>
120
120
  <script>
121
121
  (function() {
122
+ const currentUrl = new URL(window.location.href);
123
+ if (currentUrl.searchParams.has('rt')) {
124
+ currentUrl.searchParams.delete('rt');
125
+ const query = currentUrl.searchParams.toString();
126
+ const normalizedUrl = `${currentUrl.pathname}${query ? `?${query}` : ''}${currentUrl.hash}`;
127
+ window.history.replaceState(window.history.state, '', normalizedUrl);
128
+ }
129
+
122
130
  const runtimeStorageKey = 'tabminal_runtime_boot_id';
123
- let runtimeBootId = 'stable';
131
+ let runtimeBootId = '';
124
132
  try {
125
- runtimeBootId = localStorage.getItem(runtimeStorageKey) || 'stable';
133
+ runtimeBootId = localStorage.getItem(runtimeStorageKey) || '';
126
134
  } catch {
127
- runtimeBootId = 'stable';
135
+ runtimeBootId = '';
128
136
  }
137
+ const runtimeAssetKey = runtimeBootId || `cold-${Date.now()}`;
138
+ window.__tabminalRuntimeAssetKey = runtimeAssetKey;
129
139
  const link = document.createElement('link');
130
140
  link.rel = 'stylesheet';
131
- link.href = `./styles.css?v=${encodeURIComponent(runtimeBootId)}`;
141
+ link.href = `./styles.css?v=${encodeURIComponent(runtimeAssetKey)}`;
132
142
  document.head.appendChild(link);
133
143
  })();
134
144
  </script>
@@ -282,17 +292,26 @@
282
292
  </div>
283
293
  </div>
284
294
  <script>
285
- function getRuntimeBootIdForAssets() {
295
+ function getRuntimeAssetKey() {
286
296
  const runtimeStorageKey = 'tabminal_runtime_boot_id';
287
297
  try {
288
- return localStorage.getItem(runtimeStorageKey) || 'stable';
298
+ const bootId = localStorage.getItem(runtimeStorageKey) || '';
299
+ if (bootId) {
300
+ return bootId;
301
+ }
289
302
  } catch {
290
- return 'stable';
303
+ // Fall through to cold key.
304
+ }
305
+ if (window.__tabminalRuntimeAssetKey) {
306
+ return window.__tabminalRuntimeAssetKey;
291
307
  }
308
+ const coldKey = `cold-${Date.now()}`;
309
+ window.__tabminalRuntimeAssetKey = coldKey;
310
+ return coldKey;
292
311
  }
293
312
 
294
313
  (function() {
295
- const runtimeBootId = getRuntimeBootIdForAssets();
314
+ const runtimeBootId = getRuntimeAssetKey();
296
315
  const script = document.createElement('script');
297
316
  script.type = 'module';
298
317
  script.src = `./app.js?v=${encodeURIComponent(runtimeBootId)}`;
@@ -301,7 +320,7 @@
301
320
 
302
321
  if ('serviceWorker' in navigator) {
303
322
  window.addEventListener('load', () => {
304
- const runtimeBootId = getRuntimeBootIdForAssets();
323
+ const runtimeBootId = getRuntimeAssetKey();
305
324
  navigator.serviceWorker.register(
306
325
  `/sw.js?rt=${encodeURIComponent(runtimeBootId)}`
307
326
  )
package/public/styles.css CHANGED
@@ -165,6 +165,13 @@
165
165
  /* Visual center tweak */
166
166
  }
167
167
 
168
+ /* Make search selection highly visible. */
169
+ .xterm .xterm-selection div {
170
+ background-color: #ffffff !important;
171
+ mix-blend-mode: difference;
172
+ opacity: 1 !important;
173
+ }
174
+
168
175
  :root {
169
176
  color-scheme: dark;
170
177
  --bg-base: #002b36;