@cplieger/web-terminal-ui 5.6.0 → 5.6.2

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": "@cplieger/web-terminal-ui",
3
- "version": "5.6.0",
3
+ "version": "5.6.2",
4
4
  "type": "module",
5
5
  "description": "Reference touch-first browser UI for @cplieger/web-terminal-engine: a composable kernel + feature modules (tabs, activity monitor, mobile toolbar, context menu, IME, predictive echo, viewport handling) and CSS. One createTerminal() call.",
6
6
  "license": "MPL-2.0",
@@ -57,7 +57,7 @@
57
57
  "fast-check": "4.9.0",
58
58
  "happy-dom": "20.11.2",
59
59
  "html-validate": "11.6.2",
60
- "knip": "6.32.1",
60
+ "knip": "6.32.2",
61
61
  "prettier": "3.9.6",
62
62
  "stylelint": "17.14.1",
63
63
  "stylelint-config-standard": "40.0.0",
@@ -95,6 +95,6 @@
95
95
  "LICENSE",
96
96
  "README.md",
97
97
  "!src/**/*.test.ts",
98
- "!src/**/fc-strict-setup.ts"
98
+ "!src/**/*-setup.ts"
99
99
  ]
100
100
  }
@@ -2561,6 +2561,20 @@ export function tabs(opts: TabsOptions = {}): TerminalFeature<TabsApi> {
2561
2561
  if (activeId !== null) {
2562
2562
  return;
2563
2563
  }
2564
+ // ...but only once the bootstrap has adopted its list. Before that the
2565
+ // view is PARTIAL, and deterministically so: tabs subscribes to the status
2566
+ // stream during setup, before resolveInitialSession issues its
2567
+ // GET /api/sessions, so the SSE snapshot's one-event-per-session arrives
2568
+ // first and this ran on a strip holding only whichever session the server
2569
+ // sent first. Activating it both picked a tab on incomplete information and
2570
+ // silently disabled the saved-tab restore: the bootstrap ladder's first act
2571
+ // is to return early when activeId is already set, so localStorage was
2572
+ // never read and every reload landed on the oldest tab. Boot activation
2573
+ // belongs to that ladder alone, which is the only site with the whole list
2574
+ // AND the saved id; this stays the runtime repair it was written to be.
2575
+ if (!started) {
2576
+ return;
2577
+ }
2564
2578
  const first = tabList.find((t) => !isEndedStatus(statusOf(t))) ?? tabList[0];
2565
2579
  if (first) {
2566
2580
  switchTo(first.id);
@@ -4025,10 +4039,14 @@ export function tabs(opts: TabsOptions = {}): TerminalFeature<TabsApi> {
4025
4039
  }
4026
4040
  // From here on, tabs added at runtime (create / adopt) animate in.
4027
4041
  started = true;
4028
- // The SSE snapshot may have raced this bootstrap and already activated
4029
- // a tab (ensureActive during the await above). The switch is then
4030
- // already in flight — return null; the kernel sees connectionInitiated
4031
- // and leaves the loading overlay to the normal ready path.
4042
+ // Something already activated a tab while the list was in flight. The
4043
+ // chrome mounts synchronously, so a user can tap a chip (or a delivered
4044
+ // notification can be clicked) before this resolves, and an explicit
4045
+ // gesture outranks the saved id — return null and leave that switch alone;
4046
+ // the kernel sees connectionInitiated and leaves the loading overlay to
4047
+ // the normal ready path. ensureActive is deliberately NOT one of these
4048
+ // callers during boot (see its `started` gate): when it was, the SSE
4049
+ // snapshot won this race on every load and the ladder below never ran.
4032
4050
  if (activeId !== null) {
4033
4051
  return null;
4034
4052
  }