@dollhousemcp/mcp-server 2.0.26 → 2.0.27-rc.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.
@@ -13,10 +13,14 @@
13
13
 
14
14
  (() => {
15
15
  const BUFFER_SIZE = 10000;
16
- const ROW_HEIGHT = 22;
16
+ const DEFAULT_ROW_HEIGHT = 22;
17
+ const COMPACT_ROW_HEIGHT = 74;
18
+ const EXTRA_COMPACT_ROW_HEIGHT = 96;
17
19
  const OVERSCAN = 5;
18
20
  const RECONNECT_DELAY_MS = 3000;
19
21
  const SEARCH_DEBOUNCE_MS = 300;
22
+ const COMPACT_LOG_LAYOUT_QUERY = '(max-width: 48rem)';
23
+ const EXTRA_COMPACT_LOG_LAYOUT_QUERY = '(max-width: 32rem)';
20
24
 
21
25
  // ── State ────────────────────────────────────────────────────────────────
22
26
  const buffer = [];
@@ -27,6 +31,8 @@
27
31
  let searchTimer = null;
28
32
  let pendingEntries = [];
29
33
  let rafScheduled = false;
34
+ let compactLogLayoutMedia = null;
35
+ let extraCompactLogLayoutMedia = null;
30
36
 
31
37
  // Selection state
32
38
  const selectedIds = new Set();
@@ -78,6 +84,7 @@
78
84
  if (urlParams) applyLogUrlParams(urlParams);
79
85
 
80
86
  bindEvents();
87
+ bindResponsiveLayout();
81
88
  connectSSE();
82
89
 
83
90
  requestAnimationFrame(() => {
@@ -142,6 +149,14 @@
142
149
  eventSource.close();
143
150
  eventSource = null;
144
151
  }
152
+ if (compactLogLayoutMedia) {
153
+ compactLogLayoutMedia.removeEventListener?.('change', handleResponsiveLayoutChange);
154
+ compactLogLayoutMedia = null;
155
+ }
156
+ if (extraCompactLogLayoutMedia) {
157
+ extraCompactLogLayoutMedia.removeEventListener?.('change', handleResponsiveLayoutChange);
158
+ extraCompactLogLayoutMedia = null;
159
+ }
145
160
  }
146
161
 
147
162
  // ── DOM construction ─────────────────────────────────────────────────────
@@ -287,6 +302,35 @@
287
302
  document.getElementById('log-trace-clear').addEventListener('click', clearTraceFilter);
288
303
  }
289
304
 
305
+ function isCompactLogLayout() {
306
+ return !!compactLogLayoutMedia?.matches;
307
+ }
308
+
309
+ function isExtraCompactLogLayout() {
310
+ return !!extraCompactLogLayoutMedia?.matches;
311
+ }
312
+
313
+ function getRowHeight() {
314
+ if (isExtraCompactLogLayout()) return EXTRA_COMPACT_ROW_HEIGHT;
315
+ if (isCompactLogLayout()) return COMPACT_ROW_HEIGHT;
316
+ return DEFAULT_ROW_HEIGHT;
317
+ }
318
+
319
+ function handleResponsiveLayoutChange() {
320
+ requestAnimationFrame(() => {
321
+ renderViewport();
322
+ if (autoScroll) scrollToBottom();
323
+ });
324
+ }
325
+
326
+ function bindResponsiveLayout() {
327
+ if (typeof globalThis.matchMedia !== 'function') return;
328
+ compactLogLayoutMedia = globalThis.matchMedia(COMPACT_LOG_LAYOUT_QUERY);
329
+ extraCompactLogLayoutMedia = globalThis.matchMedia(EXTRA_COMPACT_LOG_LAYOUT_QUERY);
330
+ compactLogLayoutMedia.addEventListener?.('change', handleResponsiveLayoutChange);
331
+ extraCompactLogLayoutMedia.addEventListener?.('change', handleResponsiveLayoutChange);
332
+ }
333
+
290
334
  function setTraceFilter(correlationId) {
291
335
  filterCorrelationId = correlationId;
292
336
  const banner = document.getElementById('log-trace-banner');
@@ -415,14 +459,15 @@
415
459
 
416
460
  function renderViewport() {
417
461
  const totalItems = getVisibleCount();
418
- scrollSpacer.style.height = (totalItems * ROW_HEIGHT) + 'px';
462
+ const rowHeight = getRowHeight();
463
+ scrollSpacer.style.height = (totalItems * rowHeight) + 'px';
419
464
 
420
465
  const scrollTop = viewport.scrollTop;
421
466
  let viewHeight = viewport.clientHeight;
422
467
  if (viewHeight === 0) viewHeight = 600;
423
468
 
424
- const startIdx = Math.max(0, Math.floor(scrollTop / ROW_HEIGHT) - OVERSCAN);
425
- const endIdx = Math.min(totalItems, Math.ceil((scrollTop + viewHeight) / ROW_HEIGHT) + OVERSCAN);
469
+ const startIdx = Math.max(0, Math.floor(scrollTop / rowHeight) - OVERSCAN);
470
+ const endIdx = Math.min(totalItems, Math.ceil((scrollTop + viewHeight) / rowHeight) + OVERSCAN);
426
471
  const needed = endIdx - startIdx;
427
472
 
428
473
  while (rowPool.length < needed) {
@@ -452,8 +497,9 @@
452
497
 
453
498
  function updateRow(row, entry, visibleIndex) {
454
499
  const isSelected = selectedIds.has(entry.id);
455
- row.style.top = (visibleIndex * ROW_HEIGHT) + 'px';
456
- row.style.height = ROW_HEIGHT + 'px';
500
+ const rowHeight = getRowHeight();
501
+ row.style.top = (visibleIndex * rowHeight) + 'px';
502
+ row.style.height = rowHeight + 'px';
457
503
  row.dataset.entryId = entry.id;
458
504
  row.dataset.visibleIndex = visibleIndex;
459
505
  row.className = 'log-entry level-' + escapeHtml(entry.level) + (isSelected ? ' selected' : '');
@@ -622,7 +668,8 @@
622
668
 
623
669
  // ── Scroll & status ──────────────────────────────────────────────────────
624
670
  function onScroll() {
625
- const atBottom = viewport.scrollTop + viewport.clientHeight >= viewport.scrollHeight - ROW_HEIGHT * 2;
671
+ const rowHeight = getRowHeight();
672
+ const atBottom = viewport.scrollTop + viewport.clientHeight >= viewport.scrollHeight - rowHeight * 2;
626
673
  autoScroll = atBottom;
627
674
  jumpBtn.classList.toggle('visible', !atBottom && getVisibleCount() > 0);
628
675
  renderViewport();
@@ -634,8 +681,8 @@
634
681
  requestAnimationFrame(() => {
635
682
  rafScheduled = false;
636
683
  updateEntryCount();
637
- renderViewport();
638
684
  if (autoScroll) scrollToBottom();
685
+ else renderViewport();
639
686
  });
640
687
  }
641
688
  }
@@ -643,6 +690,7 @@
643
690
  // ── Helpers ──────────────────────────────────────────────────────────────
644
691
  function scrollToBottom() {
645
692
  viewport.scrollTop = viewport.scrollHeight;
693
+ renderViewport();
646
694
  }
647
695
 
648
696
  function setStatus(status) {
@@ -66,7 +66,8 @@
66
66
  position: absolute;
67
67
  top: calc(100% + 0.4rem);
68
68
  right: 0;
69
- min-width: 480px;
69
+ min-width: min(480px, calc(100vw - (2 * var(--gutter, 1rem))));
70
+ max-width: calc(100vw - (2 * var(--gutter, 1rem)));
70
71
  background: var(--paper-strong, #fff);
71
72
  border: 1px solid var(--line, #c8d5e9);
72
73
  border-radius: var(--radius-md, 0.85rem);
@@ -146,11 +146,15 @@ p, li { max-width: 69ch; }
146
146
  position: sticky;
147
147
  top: 0;
148
148
  z-index: 35;
149
- display: flex;
149
+ display: grid;
150
+ grid-template-columns: auto minmax(0, 1fr);
151
+ grid-template-areas:
152
+ "brand controls"
153
+ "nav nav";
150
154
  align-items: center;
151
- justify-content: space-between;
152
- gap: 1rem;
153
- padding: 0.55rem var(--gutter);
155
+ column-gap: 1rem;
156
+ row-gap: 0.12rem;
157
+ padding: 0.44rem var(--gutter) 0.4rem;
154
158
  border-bottom: 1px solid var(--line);
155
159
  background: color-mix(in srgb, var(--paper-strong) 90%, transparent);
156
160
  backdrop-filter: blur(8px);
@@ -168,8 +172,8 @@ p, li { max-width: 69ch; }
168
172
  pointer-events: none;
169
173
  }
170
174
 
171
- .header-brand { display: flex; flex-direction: row; align-items: center; gap: 0.6rem; }
172
- .header-brand-text { display: flex; flex-direction: column; gap: 0.05rem; }
175
+ .header-brand { grid-area: brand; display: flex; flex-direction: row; align-items: center; gap: 0.6rem; min-width: 0; min-height: 2.35rem; }
176
+ .header-brand-text { display: flex; flex-direction: column; justify-content: center; gap: 0.05rem; min-width: 0; min-height: 2.35rem; }
173
177
  .header-logo { width: 32px; height: 32px; flex-shrink: 0; }
174
178
 
175
179
  .site-title {
@@ -186,22 +190,49 @@ p, li { max-width: 69ch; }
186
190
  font-size: var(--step--1);
187
191
  color: var(--ink-700);
188
192
  max-width: none;
193
+ line-height: 1.15;
189
194
  }
190
195
 
191
- .header-right {
196
+ .header-controls {
197
+ grid-area: controls;
192
198
  display: flex;
193
199
  align-items: center;
200
+ justify-content: flex-end;
201
+ flex-wrap: wrap;
194
202
  gap: 0.65rem;
203
+ width: auto;
204
+ max-width: 100%;
205
+ min-width: 0;
206
+ }
207
+
208
+ .header-nav-row {
209
+ grid-area: nav;
210
+ display: flex;
211
+ align-items: center;
212
+ justify-content: flex-end;
213
+ flex-wrap: nowrap;
214
+ gap: 0.55rem;
215
+ width: 100%;
216
+ min-width: 0;
217
+ }
218
+
219
+ .console-tab-menu-shell {
220
+ position: relative;
221
+ display: flex;
222
+ align-items: center;
195
223
  flex-shrink: 0;
196
224
  }
197
225
 
198
226
  .site-stats {
199
227
  display: flex;
200
228
  align-items: center;
229
+ flex-wrap: wrap;
230
+ justify-content: flex-end;
201
231
  gap: 0.5rem;
202
232
  font-family: var(--font-mono);
203
233
  font-size: 0.72rem;
204
234
  color: var(--ink-500);
235
+ min-width: 0;
205
236
  }
206
237
 
207
238
  .stat {
@@ -735,12 +766,6 @@ p, li { max-width: 69ch; }
735
766
  color: var(--ink-500);
736
767
  }
737
768
 
738
- /* "by" prefix handled by CSS so JS can pass raw author value */
739
- .meta-author::before {
740
- content: "by\00a0";
741
- opacity: 0.65;
742
- }
743
-
744
769
  .meta-version {
745
770
  border: 1px solid color-mix(in srgb, var(--line) 82%, var(--paper-strong));
746
771
  border-radius: 0.24rem;
@@ -1338,6 +1363,86 @@ body.modal-open { overflow: hidden; }
1338
1363
  background: var(--surface-1);
1339
1364
  border-radius: var(--radius-sm);
1340
1365
  padding: 2px;
1366
+ min-width: 0;
1367
+ width: fit-content;
1368
+ max-width: 100%;
1369
+ flex-wrap: wrap;
1370
+ }
1371
+
1372
+ .console-tab-menu-toggle {
1373
+ display: none;
1374
+ align-items: center;
1375
+ gap: 0.42rem;
1376
+ border: 1px solid color-mix(in srgb, var(--signal) 24%, var(--line));
1377
+ border-radius: 999px;
1378
+ background: color-mix(in srgb, var(--surface-1) 70%, var(--paper-strong));
1379
+ color: var(--ink-700);
1380
+ font-family: var(--font-mono);
1381
+ font-size: 0.72rem;
1382
+ font-weight: 700;
1383
+ line-height: 1;
1384
+ padding: 0.48rem 0.78rem;
1385
+ cursor: pointer;
1386
+ white-space: nowrap;
1387
+ }
1388
+
1389
+ .console-tab-menu-toggle:hover,
1390
+ .console-tab-menu-toggle:focus-visible {
1391
+ background: color-mix(in srgb, var(--surface-1) 88%, var(--paper-strong));
1392
+ outline: 2px solid var(--signal);
1393
+ outline-offset: 2px;
1394
+ }
1395
+
1396
+ .console-tab-menu-icon {
1397
+ font-size: 0.95rem;
1398
+ line-height: 1;
1399
+ }
1400
+
1401
+ .console-tab-menu {
1402
+ position: absolute;
1403
+ top: calc(100% + 0.4rem);
1404
+ right: 0;
1405
+ min-width: 13rem;
1406
+ max-width: min(18rem, calc(100vw - (2 * var(--gutter, 1rem))));
1407
+ background: var(--paper-strong);
1408
+ border: 1px solid var(--line);
1409
+ border-radius: var(--radius-md);
1410
+ box-shadow: var(--shadow-soft);
1411
+ padding: 0.3rem;
1412
+ z-index: 200;
1413
+ }
1414
+
1415
+ .console-tab-menu-item {
1416
+ width: 100%;
1417
+ border: none;
1418
+ border-radius: var(--radius-sm);
1419
+ background: transparent;
1420
+ color: var(--ink-700);
1421
+ font-family: var(--font-body);
1422
+ font-size: var(--step--1);
1423
+ font-weight: 600;
1424
+ text-align: left;
1425
+ padding: 0.52rem 0.68rem;
1426
+ cursor: pointer;
1427
+ }
1428
+
1429
+ .console-tab-menu-item:hover,
1430
+ .console-tab-menu-item:focus-visible {
1431
+ background: var(--surface-1);
1432
+ outline: none;
1433
+ }
1434
+
1435
+ .console-tab-menu-item.active {
1436
+ background: color-mix(in srgb, var(--signal-2) 10%, var(--paper-strong));
1437
+ color: var(--signal);
1438
+ }
1439
+
1440
+ .header-nav-row--collapsed .console-tabs {
1441
+ display: none;
1442
+ }
1443
+
1444
+ .header-nav-row--collapsed .console-tab-menu-toggle:not([hidden]) {
1445
+ display: inline-flex;
1341
1446
  }
1342
1447
 
1343
1448
  .console-tab {
@@ -1365,13 +1470,153 @@ body.modal-open { overflow: hidden; }
1365
1470
  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
1366
1471
  }
1367
1472
 
1473
+ @media (max-width: 960px) {
1474
+ .header-controls {
1475
+ align-items: center;
1476
+ justify-content: flex-end;
1477
+ width: auto;
1478
+ max-width: 100%;
1479
+ gap: 0.5rem;
1480
+ }
1481
+
1482
+ .site-stats {
1483
+ flex: 0 1 auto;
1484
+ width: auto;
1485
+ justify-content: flex-end;
1486
+ }
1487
+ }
1488
+
1489
+ @media (max-width: 860px) {
1490
+ .site-header {
1491
+ column-gap: 0.7rem;
1492
+ }
1493
+
1494
+ .header-brand {
1495
+ gap: 0.5rem;
1496
+ min-height: 0;
1497
+ }
1498
+
1499
+ .header-brand-text {
1500
+ min-height: 0;
1501
+ gap: 0;
1502
+ }
1503
+
1504
+ .header-brand .site-tagline {
1505
+ display: none;
1506
+ }
1507
+
1508
+ .header-controls,
1509
+ .site-stats {
1510
+ gap: 0.35rem;
1511
+ }
1512
+
1513
+ .header-controls {
1514
+ align-items: center;
1515
+ }
1516
+
1517
+ .stat {
1518
+ padding: 0.12rem 0.34rem;
1519
+ }
1520
+
1521
+ .stat strong {
1522
+ font-size: 0.92rem;
1523
+ }
1524
+
1525
+ .stat--session strong {
1526
+ font-size: 0.74rem;
1527
+ }
1528
+
1529
+ .theme-toggle {
1530
+ width: 1.85rem;
1531
+ height: 1.85rem;
1532
+ }
1533
+
1534
+ .console-tab {
1535
+ padding: 4px 11px;
1536
+ }
1537
+ }
1538
+
1539
+ @media (max-width: 46rem) {
1540
+ .stat--session {
1541
+ display: none;
1542
+ }
1543
+ }
1544
+
1545
+ @media (max-width: 31rem) {
1546
+ .site-stats .stat:nth-child(2) {
1547
+ display: none;
1548
+ }
1549
+ }
1550
+
1551
+ @media (max-width: 28rem) {
1552
+ .site-header {
1553
+ grid-template-columns: minmax(0, 1fr) auto auto;
1554
+ grid-template-areas: "brand nav controls";
1555
+ column-gap: 0.45rem;
1556
+ }
1557
+
1558
+ .header-brand {
1559
+ gap: 0;
1560
+ min-width: 0;
1561
+ }
1562
+
1563
+ .header-logo {
1564
+ display: block;
1565
+ width: 28px;
1566
+ height: 28px;
1567
+ }
1568
+
1569
+ .header-brand-text {
1570
+ display: none;
1571
+ }
1572
+
1573
+ .site-stats {
1574
+ display: none;
1575
+ }
1576
+
1577
+ .header-controls {
1578
+ width: auto;
1579
+ justify-content: flex-end;
1580
+ }
1581
+
1582
+ .header-nav-row {
1583
+ width: auto;
1584
+ min-width: 0;
1585
+ justify-content: flex-end;
1586
+ gap: 0.4rem;
1587
+ }
1588
+ }
1589
+
1590
+ @media (max-width: 24rem) {
1591
+ .site-header {
1592
+ grid-template-columns: 1fr;
1593
+ grid-template-areas:
1594
+ "brand"
1595
+ "controls"
1596
+ "nav";
1597
+ }
1598
+
1599
+ .header-controls {
1600
+ justify-content: flex-end;
1601
+ width: 100%;
1602
+ }
1603
+
1604
+ .site-stats {
1605
+ justify-content: flex-end;
1606
+ }
1607
+
1608
+ .header-nav-row {
1609
+ width: 100%;
1610
+ justify-content: flex-end;
1611
+ }
1612
+ }
1613
+
1368
1614
  @media (max-width: 640px) {
1369
1615
  .console-tabs {
1370
- order: -1;
1371
- width: 100%;
1616
+ width: fit-content;
1617
+ max-width: 100%;
1372
1618
  }
1373
1619
  .console-tab {
1374
- flex: 1;
1375
1620
  text-align: center;
1376
1621
  }
1377
1622
  }
@@ -1430,13 +1675,17 @@ body.modal-open { overflow: hidden; }
1430
1675
  margin-left: auto;
1431
1676
  }
1432
1677
 
1678
+ .footer-version,
1433
1679
  .footer-updated {
1434
- margin-left: auto;
1435
1680
  font-family: var(--font-mono);
1436
1681
  font-size: 0.72rem;
1437
1682
  color: var(--ink-500);
1438
1683
  }
1439
1684
 
1685
+ .footer-updated {
1686
+ margin-left: auto;
1687
+ }
1688
+
1440
1689
  /* ── Topic filters ───────────────────────────────────────────────────────── */
1441
1690
 
1442
1691
  fieldset.topic-filters {
@@ -1684,10 +1933,9 @@ fieldset.topic-filters {
1684
1933
 
1685
1934
  /* ── Responsive ──────────────────────────────────────────────────────────── */
1686
1935
 
1687
- @media (max-width: 52rem) {
1936
+ @media (max-width: 40rem) {
1688
1937
  .header-brand .site-tagline { display: none; }
1689
- .stat { display: none; }
1690
- .stat:first-child { display: inline-flex; }
1938
+ .stat--session { display: none; }
1691
1939
  .elements-grid { grid-template-columns: repeat(auto-fill, minmax(min(100%, 11.5rem), 1fr)); }
1692
1940
  .elements-grid[data-view="detail"] { grid-template-columns: 1fr; }
1693
1941
  .modal-dialog { height: calc(100vh - 0.5rem); border-radius: 0; }
@@ -1696,6 +1944,10 @@ fieldset.topic-filters {
1696
1944
  .elements-grid[data-view="list"] .card-description { display: none; }
1697
1945
  }
1698
1946
 
1947
+ @media (max-width: 30rem) {
1948
+ .stat:nth-child(2) { display: none; }
1949
+ }
1950
+
1699
1951
  /* ── Directive-style instructions ─────────────────────────────────── */
1700
1952
 
1701
1953
  .directive-list {
@@ -1 +1 @@
1
- {"version":3,"file":"permissionRoutes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/permissionRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAgB,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAG1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AA8T7E;;;GAGG;AACH,MAAM,WAAW,+BAA+B;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE,+BAAoC,GAC5C,IAAI,CA+NN"}
1
+ {"version":3,"file":"permissionRoutes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/permissionRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAgB,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAG1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAwV7E;;;GAGG;AACH,MAAM,WAAW,+BAA+B;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE,+BAAoC,GAC5C,IAAI,CAkON"}