dsh-zen-remote 2.3.8 → 2.3.9

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +2 -2
  3. package/README.zh-CN.md +2 -2
  4. package/docs/interface.md +1 -1
  5. package/docs/remote-access.en.md +1 -1
  6. package/docs/remote-access.md +1 -1
  7. package/lib/adapters/dsh-better-sidebar/index.js +21 -3
  8. package/lib/adapters/dsh-better-sidebar/index.js.map +1 -1
  9. package/lib/client.js +470 -81
  10. package/lib/types/adapters/dsh-better-sidebar/index.d.ts +1 -1
  11. package/lib/types/adapters/dsh-better-sidebar/index.d.ts.map +1 -1
  12. package/lib/types/client/MobileHome.d.ts.map +1 -1
  13. package/lib/types/client/MobileSessionHeader.d.ts.map +1 -1
  14. package/lib/types/client/effects/native-trigger-overlay.d.ts.map +1 -1
  15. package/lib/types/client/effects/permission-sheet.d.ts +51 -10
  16. package/lib/types/client/effects/permission-sheet.d.ts.map +1 -1
  17. package/lib/types/client/locales.d.ts +1 -0
  18. package/lib/types/client/locales.d.ts.map +1 -1
  19. package/lib/types/client/settings/SettingsSection.d.ts.map +1 -1
  20. package/lib/types/client/styles/composer.css.d.ts +1 -1
  21. package/lib/types/client/styles/composer.css.d.ts.map +1 -1
  22. package/lib/types/client/styles/header.css.d.ts +1 -1
  23. package/lib/types/client/styles/header.css.d.ts.map +1 -1
  24. package/lib/types/client/styles/layout.css.d.ts +1 -1
  25. package/lib/types/client/styles/layout.css.d.ts.map +1 -1
  26. package/lib/types/client/wizard/GatewayWizard.d.ts.map +1 -1
  27. package/lib/types/client-data/new-session.d.ts +26 -0
  28. package/lib/types/client-data/new-session.d.ts.map +1 -0
  29. package/lib/types/client-data/settings-form.d.ts +36 -0
  30. package/lib/types/client-data/settings-form.d.ts.map +1 -1
  31. package/package.json +1 -1
  32. package/scripts/check-settings-form.mjs +63 -0
  33. package/src/adapters/dsh-better-sidebar/index.ts +23 -3
  34. package/src/client/MobileHome.tsx +44 -7
  35. package/src/client/MobileSessionHeader.tsx +7 -1
  36. package/src/client/effects/native-trigger-overlay.ts +50 -11
  37. package/src/client/effects/permission-sheet.ts +199 -22
  38. package/src/client/locales.ts +2 -0
  39. package/src/client/settings/SettingsSection.tsx +43 -1
  40. package/src/client/styles/composer.css.ts +24 -0
  41. package/src/client/styles/header.css.ts +58 -46
  42. package/src/client/styles/layout.css.ts +25 -0
  43. package/src/client/wizard/GatewayWizard.tsx +23 -1
  44. package/src/client-data/new-session.ts +30 -0
  45. package/src/client-data/settings-form.ts +57 -0
@@ -1,2 +1,2 @@
1
- export declare const LAYOUT_CSS = "/* ---------- mobile-only layout ---------- */\n\n@media (max-width: 1023px) {\n /* --- Phone chrome ---\n The system status bar stays visible (no fullscreen). Two adjustments\n make it behave:\n - touch-action: manipulation kills double-tap-to-zoom (and the 300ms\n tap delay) while keeping pan and pinch zoom; the client also\n suppresses legacy-iOS gesturestart as a fallback.\n - With the client's viewport-fit=cover, env(safe-area-inset-top) is the\n status bar / notch height; the rules below push the app content below\n it so the status bar never covers anything. Off notched phones (or in\n a normal browser tab where the layout viewport already sits below the\n status bar) the inset is 0 and nothing shifts. */\n html,\n body {\n touch-action: manipulation !important;\n }\n\n /* AppFrame: the drawer takes the sidebar column out of grid flow, so the\n remaining in-flow items (center, details) land in tracks 1..2: give the\n center every pixel and keep the details track at zero. The top padding\n clears the status bar / notch for every in-flow surface (session header,\n messages, composer); the absolutely-positioned drawer is unaffected (its\n containing block is the frame's padding box, i.e. still the frame top). */\n /* box-sizing: border-box is load-bearing (S2.1, 2026-08-17). The official\n frame carries height: 100% with the default content-box, so the\n safe-area padding ADDED 54px to its height instead of taking 54px out\n of the content area: the frame grew past the viewport, the document\n became scrollable by exactly the inset, and the very first scroll put\n the header right back under the notch \u2014 measured with\n ?mobile-nav-inset=54 (frame 898px tall inside an 844px root, html at\n y=-54). Invisible on every desktop browser because the inset is 0\n there, which is how it shipped. */\n [data-mobile-nav=\"frame\"] {\n position: relative !important;\n box-sizing: border-box !important;\n grid-template-columns: minmax(0, 1fr) 0 0 !important;\n padding-top: var(--mnav-sat) !important;\n }\n\n /* The sidebar column (first grid child) becomes a left drawer. The drawer\n hugs the sidebar content exactly (the wide sidebar carries an inline\n width, ~280px): a fixed 92vw box would leave a white strip where the\n container background shows beside the content.\n Closed state: translateX(-110%) \u2014 more than -100% of the max-content\n width \u2014 guarantees the whole drawer (and its shadow, had it one) leaves\n the viewport. A mere -100% leaves a sliver on screen; -105% (as used\n before) left 14px of the drawer plus a long 32px-blur shadow gradient\n visible along the left edge of the main UI. No box-shadow at all: the\n dimmed backdrop already separates drawer from content. */\n [data-mobile-nav=\"frame\"] > :first-child {\n position: absolute !important;\n inset: 0 auto 0 0 !important;\n width: max-content !important;\n max-width: 92vw !important;\n z-index: 40 !important;\n transform: translateX(-110%);\n transition: transform .28s var(--ds-ease-in-out, ease-in-out);\n background: var(--dsw-alias-bg-base, #ffffff);\n /* Keep the drawer's own content below the status bar / notch: the drawer\n spans the full frame height (its absolute containing block is the\n frame's padding box, so the frame's own safe-area padding does NOT\n reach it). The drawer background paints the status-bar strip, which\n the client's theme-color meta matches, so the strip reads seamless. */\n padding-top: var(--mnav-sat) !important;\n /* Kill the official sidebarCol right border: with the backdrop the edge\n reads cleanly, and the settings dialog (width:100% of this box) stays\n pixel-flush with the drawer. */\n border-right: none !important;\n }\n\n /* The official right sidebar (DSH 0.1.5+) in its full-screen mode \u2014 the\n one the phone's header sidebar button opens (sidebar-panels.ts). The\n host promotes the panel to position:fixed; inset:0 there, so exactly\n like the drawer above it escapes the frame's safe-area padding and its\n tab strip + chrome buttons landed under the status bar (real-device\n report, 2026-09-21). Both insets: the status bar / notch on top, the\n home indicator at the bottom. Padding, no box-sizing change: fixed\n with both top and bottom set resolves its used height from the\n containing block minus padding (CSS 2.1 10.6.4), so the content box\n shrinks by itself \u2014 the same reasoning the legacy better-sidebar panel\n rule in compat.css.ts spells out. `fullscreen` is the host's own\n attribute value (`push` while docked, dsh-client-ui-sidebar-right), so\n the docked panel is untouched; a manual full-screen on desktop is\n outside this media block anyway. Verify with ?mobile-nav-inset=54,34 \u2014\n env() is 0 in every desktop browser. */\n [data-sidebar-right-panel=\"fullscreen\"] {\n padding-top: var(--mnav-sat) !important;\n padding-bottom: var(--mnav-sab) !important;\n }\n\n /* Expanded state (frame without data-sidebar-collapsed) slides the drawer in.\n The open state must be transform:none \u2014 NOT translateX(0): an identity\n transform still makes the drawer the containing block for fixed-position\n descendants (the settings dialog's .VOzbGW_overlay is portaled into the\n sidebar DOM). With the identity transform the wide settings sheet\n (100vw-16) overflows the 280px drawer, the dialog's focus scrolls the\n overflow:hidden drawer to scrollLeft=102, and every static child (plus the\n fixed overlay) shifts 102px off-screen. With transform:none the overlay is\n viewport-anchored: it dims the full screen and the sheet sits at left:8. */\n [data-mobile-nav=\"frame\"]:not([data-sidebar-collapsed]) > :first-child {\n transform: none !important;\n }\n\n /* Drag handles are useless on touch and would float over the drawer. */\n [data-side=\"sidebar\"],\n [data-side=\"details\"] {\n display: none !important;\n }\n\n /* --- Conversation text on mobile ---\n The official message flow keeps desktop's 32px side gutters and 16px\n type. On a phone: shrink the type a notch and widen the lines by\n trimming the gutters (the sidebar drawer list keeps its size). The\n flow's scroll container is the only _scroll element holding markdown\n <p> paragraphs \u2014 the composer's own scroll (textarea) is excluded\n via :has(p). */\n /* The official main scroll body reserves scrollbar-gutter for desktop\n scrollbars (8px), which shoves every column off-center on a phone.\n Classic desktop scrollbars (Edge/Chrome) also occupy ~8-17px in a\n phone-sized viewport, shifting the column further. Mobile scrolling\n is touch/wheel, so remove the scrollbar entirely on phones: the\n column is then exactly centered in every browser. */\n [data-phase] [class$=\"_scrollBody\"] {\n scrollbar-gutter: auto !important;\n scrollbar-width: none !important;\n }\n [data-phase] [class$=\"_scrollBody\"]::-webkit-scrollbar {\n display: none !important;\n width: 0 !important;\n height: 0 !important;\n }\n /* Message action rows (copy / run-time badges) can overflow the right\n edge on narrow screens \u2014 keep them inside the message width. */\n [data-phase] [class$=\"_actions\"] {\n overflow: hidden !important;\n }\n /* The 24h clock (\"18:06\" / \"MM-DD 18:06\") is a fixed-size item: it must\n never be the thing that shrinks. DSH 0.2.x wraps it with the usage\n button in an inline-flex _endInfo (min-width: 0), so a shrinkable\n time (the old flex: 0 1 auto + min-width: 0) got squeezed inside that\n non-wrapping box and \"18:06\" broke into two lines. flex: none pins its\n width; the turn-tail rules in content.css.ts let _endInfo wrap as a\n whole instead. */\n [data-phase] [class$=\"_actions\"] [class$=\"_timeEnd\"] {\n flex: none !important;\n white-space: nowrap !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n }\n\n [data-phase] [class$=\"_scroll\"]:has(p) {\n padding-left: 20px !important;\n padding-right: 20px !important;\n font-size: 15px !important;\n }\n /* The official markdown styles set an explicit 16px on paragraphs and\n list items, so the container's inherited 15px is not enough. User\n messages render their text in a div whose class carries _text_\n (16px too) \u2014 cover it as well. */\n [data-phase] [class$=\"_scroll\"]:has(p) p,\n [data-phase] [class$=\"_scroll\"]:has(p) li,\n [data-phase] [class$=\"_scroll\"]:has(p) [class*=\"_text_\"] {\n font-size: 15px !important;\n }\n\n /* Markdown tables: the official table uses width:max-content, so on a phone\n it hugs the content and leaves dead space beside/inside the table. Force\n the table to fill the message column and let the table wrapper handle\n overflow if a cell is genuinely too wide. */\n [data-phase] table {\n width: 100% !important;\n max-width: 100% !important;\n }\n [data-phase] th,\n [data-phase] td {\n max-width: none !important;\n min-width: 0 !important;\n }\n\n /* User bubbles: the official stack is capped at min(525px, 82%), which on a\n phone leaves a large blank strip on the left and pushes the bubble high.\n On mobile let the user message fill the same full width as assistant\n messages (the bubble background then spans the whole message column). */\n [data-phase] [class$=\"_userStack\"],\n [data-phase] [class$=\"_userStack\"] [class$=\"_bubble\"] {\n box-sizing: border-box !important;\n width: fit-content !important;\n max-width: 100% !important;\n }\n\n /* --- Composer bottom row on mobile ---\n The official row gives the model pill (trailing) flex:0 0 auto, which\n squeezes the agent-permission pill (modes) down to 15px: the pill's\n chevron then overflows on top of the model name. Let the permission\n pill keep its natural width and let the model pill shrink instead.\n Anchored by the composer card (:has(textarea)): row = the _row class\n containing a _trailing group, tools = its first child, permission pill\n = its 2nd child, model pill = the _trailing group.\n NOTE: do NOT anchor these by the card's :last-child \u2014 a client effect\n moves the git-graph branch chip INTO the card, which becomes the card's\n new last child and silently disables every :last-child rule (the model\n pill then falls back to the official fixed layout and long model IDs\n overflow instead of ellipsizing). Structural anchors only. */\n /* The official row pads every group with 12px gaps, which on a phone eats\n width the model pill needs for the full model ID. Tighten the row to 8px\n gaps (the modes pill keeps its natural width) so the model name gets\n every spare pixel. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_row\"]:has([class$=\"_trailing\"]) {\n gap: 8px !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_row\"]:has([class$=\"_trailing\"]) > :first-child {\n gap: 8px !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_row\"]:has([class$=\"_trailing\"]) > :first-child > :nth-child(2) {\n flex: 0 0 auto !important;\n gap: 8px !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_trailing\"] {\n flex: 1 1 auto !important;\n gap: 8px !important;\n min-width: 0 !important;\n }\n /* Let the model selector take the free space in the trailing group so the\n model name is not squeezed/truncated; the context meter stays fixed. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"][aria-haspopup=\"menu\"]) {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"][aria-haspopup=\"menu\"]) > [class$=\"_trigger\"] {\n width: 100% !important;\n max-width: 100% !important;\n }\n /* The model label must absorb the trigger's free width: officially it is a\n fixed-content flex item, so the spare width of a grown pill sits unused\n between the chevron and the pill edge. Let the label grow and shrink:\n the full model ID shows whenever the row can fit it, and the ellipsis\n lands exactly at the available width otherwise. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"][aria-haspopup=\"menu\"]) > [class$=\"_trigger\"] > [class$=\"_triggerLabel\"] {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"]:not([aria-haspopup=\"menu\"])) {\n flex: 0 0 auto !important;\n }\n\n /* Model switcher menu: the official dropdown is right-aligned to the\n trigger (right:0). The model pill sits near the center of the composer,\n so on a phone the 240px menu overflows the left edge and looks off-center.\n Center the menu on the trigger instead. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"]) > [class$=\"_menu\"] {\n left: 50% !important;\n right: auto !important;\n transform: translateX(-50%) !important;\n }\n\n /* --- Session header on mobile ---\n Layout goal: [toggle] [session title] [mode badge] in a row, with the\n Session log capsule removed from the header (relocated to the drawer\n footer). Stable structural hooks only:\n [data-phase] header the session header element\n header > :first-child titleRow (titleCluster + utilities)\n header > :first-child > :last-child headerUtilities (Session log seat) */\n [data-phase] header {\n padding-right: 12px !important;\n }\n /* Give the title row a lane clear of the absolutely-placed toggle, then\n balance the header: with header padding-right 12px, a 20px left\n padding puts the title's geometric center exactly on the viewport\n center (measured 195/195 at 390px). */\n [data-phase] header > :first-child {\n padding-left: 20px !important;\n }\n /* The directory toggle sits at the far left of the header (the header\n is position:relative; the data-slot wrappers are display:contents). */\n [data-mobile-nav=\"toggle\"] {\n position: absolute !important;\n left: 8px !important;\n top: 12px !important;\n z-index: 2 !important;\n }\n /* The Files action stays in-flow inside headerActions. On mobile headerActions\n does not expand to fill the row: it is pushed to the right edge and keeps\n its content size, so [mode] [subagent/jobs] [files] sit close together\n with the normal 8px gaps \u2014 compact, no artificial blank columns. Explicit\n flex order keeps Files rightmost regardless of DOM order. */\n [data-mobile-nav=\"files\"] {\n position: static !important;\n left: auto !important;\n right: auto !important;\n top: auto !important;\n z-index: auto !important;\n }\n [data-phase] header [class$=\"_headerActions\"] {\n flex: 0 1 auto !important;\n min-width: 0 !important;\n margin-left: auto !important;\n justify-content: flex-end !important;\n }\n /* The session title/crumb must yield space on mobile so the mode label and\n subagent cluster are not squeezed to a single letter. Cap it at ~24vw and\n let it truncate with ellipsis. */\n [data-phase] header [class$=\"_crumbs\"] {\n flex: 0 1 auto !important;\n min-width: 0 !important;\n max-width: 24vw !important;\n }\n /* Mode label (AgentPresetLabel): the official pill uses inline-flex, whose\n direct text node is only clipped \u2014 no ellipsis. Convert the pill to a\n block container, keep its icon absolutely positioned on the left, and let\n it size naturally up to 42vw so the mode name stays readable while the\n subagent/Files cluster still fits on a phone. */\n [data-phase] header [class$=\"_label\"]:has(> svg) {\n order: 1 !important;\n flex: 0 1 auto !important;\n min-width: 0 !important;\n max-width: 42vw !important;\n display: block !important;\n position: relative !important;\n box-sizing: border-box !important;\n padding-left: 18px !important;\n padding-right: 2px !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n white-space: nowrap !important;\n }\n [data-phase] header [class$=\"_label\"]:has(> svg) > svg {\n position: absolute !important;\n left: 0 !important;\n top: 50% !important;\n transform: translateY(-50%) !important;\n }\n /* Subagent/jobs helpers: keep their triggers on one line and never let the\n row grow artificial empty space. */\n [data-phase] header [class$=\"_root\"]:has(> button[class$=\"_trigger\"]) {\n order: 2 !important;\n flex: 0 0 auto !important;\n min-width: max-content !important;\n max-width: none !important;\n white-space: nowrap !important;\n /* On mobile the popover is anchored to the header (viewport-width\n containing block) instead of the trigger, so a small left inset keeps it\n fully on screen and never clips the tree's status dots. */\n position: static !important;\n }\n [data-phase] header [class$=\"_root\"]:has(> button[class$=\"_trigger\"]) > button,\n [data-phase] header [class$=\"_root\"]:has(> button[class$=\"_trigger\"]) > button * {\n white-space: nowrap !important;\n }\n [data-phase] header [data-mobile-nav=\"files\"] {\n order: 3 !important;\n flex: 0 0 auto !important;\n }\n /* Session log download: gone from the header row on mobile (the utilities\n seat holds only the session-log-export capsule). */\n [data-phase] header > :first-child > :last-child {\n display: none !important;\n }\n\n /* --- Header popovers on mobile (dsh-client-ui-jobs / dsh-client-ui-subagent) ---\n The official entries sit in the session header actions. Their popovers\n are anchored to the trigger's LEFT edge (left: 0), so from a right-edge\n trigger the 336px panel spills past the viewport. Re-anchor them to the\n trigger's right edge instead. The popover classes are hashed CSS-module\n names, so target them by the stable _menu suffix inside the header. */\n /* Header popovers on mobile: anchor to the left edge with a small inset and\n clamp the width, instead of right-aligning to a trigger near the right\n edge (which pushed the panel left off-screen and clipped the status dots).\n Also cap the height so the panel does not run into the composer/task bar. */\n [data-phase] header [class$=\"_menu\"] {\n left: 8px !important;\n right: auto !important;\n width: min(336px, calc(100vw - 16px)) !important;\n max-width: none !important;\n max-height: min(420px, calc(100dvh - 120px)) !important;\n }\n /* --- Settings dialog on mobile ---\n Desktop: 800px two-column flex (188px nav + content). Mobile: a\n near-full-width sheet \u2014 nav tabs wrap into rows on top, option rows\n stay horizontal (title+description left, control right). Structural\n selectors are scoped to the unique aria-modal dialog; every\n settings-specific rule is gated with\n :has(> :first-child > :last-child > button) \u2014 the settings nav tab\n list holds <button> tabs, so the transient export dialog (the same\n primitives Modal, header(title+close)+description+body) keeps its\n official centered card layout. Requires :has() support\n (Chromium 105+, 2022).\n\n The directory picker (dsh-client-ui-directory-picker-browse) must be\n excluded too: its footer bar holds <button> children AND its breadcrumb\n trail (role=\"navigation\") \u2014 which the role gate relies on to exclude\n it \u2014 is REPLACED by the path input in edit mode (pencil button), so\n without the ZuhsRW exclusion clicking the pencil would suddenly match\n this sheet rule: the dialog jumps to the top of the screen, the header\n (with the path input) is hidden by the > :first-child > :first-child\n display:none rule below, and the user can no longer type a path\n (issue #12, 2026-08-16). The picker family keeps the official layout\n on mobile in every mode. */\n /* DSH 0.2.1-rc.2 renders this dialog as a body PORTAL\n (body > overlay > panel), so the placement below must key off the nav\n list the panel owns, not off a guessed child depth: that is both the\n stable \"this is the settings sheet\" anchor and the reason the safe-area\n offset below still applies inside the portal (the constants live on\n :root, so they cross the portal boundary). The bottom inset is\n subtracted too \u2014 a tall panel must not run under the home indicator. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])):has([class$=\"_navList\"]) {\n position: absolute !important;\n left: 8px !important;\n /* Fixed top (no translateY): a transform on the panel combined with the\n panel overflowing the max-content drawer shifts the fixed overlay's\n coordinate frame, dragging the whole sidebar content off-screen. The\n safe-area inset keeps the sheet below the status bar / notch. */\n top: calc(var(--mnav-sat) + 12px) !important;\n width: calc(100vw - 16px) !important;\n max-width: calc(100vw - 16px) !important;\n /* Height follows the content (no dead space under a short page); it\n caps at 100dvh-24 (less both safe-area insets) and the options area\n scrolls only then. */\n height: auto !important;\n max-height: min(800px, calc(100vh - 24px - var(--mnav-sat) - var(--mnav-sab))) !important;\n max-height: min(800px, calc(100dvh - 24px - var(--mnav-sat) - var(--mnav-sab))) !important;\n flex-direction: column !important;\n border-radius: 14px !important;\n animation: dsh-mobile-nav-sheet-in .22s var(--ds-ease-out, ease-in-out);\n }\n /* The settings sheet's dimmed mask fades in with the panel (the mask is\n the first child of the overlay that directly contains the sheet). */\n :has(> [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"]))) > :first-child {\n animation: dsh-mobile-nav-fade .18s var(--ds-ease-out, ease-in-out);\n }\n @media (prefers-reduced-motion: reduce) {\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])),\n :has(> [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"]))) > :first-child {\n animation: none !important;\n }\n }\n /* The export dialog (not the settings sheet) must never overflow the\n viewport: the official centered card can be wider than 390px.\n :not([data-mobile-nav=\"info-sheet\"]) (S4, 2026-08-17): the session-info\n sheet also carries role=\"dialog\" aria-modal=\"true\" (correct a11y\n semantics for a bottom sheet with a scrim) and has no button as its\n first-child's last-child, so without this exclusion it silently matched\n this generic selector too \u2014 measured 358px (100vw-32px) instead of the\n 374px its own left:8px/right:8px margins specify. Same category of bug\n as the ZuhsRW directory-picker collision below; same fix shape.\n :not([data-mobile-nav=\"share-range-sheet\"]) (share-image, 2026-09-10):\n the share range picker rides the same role=\"dialog\" aria-modal bottom\n -sheet shape and the same margins, so it hit the identical clamp. */\n [aria-modal=\"true\"]:not(:has(> :first-child > :last-child > button)):not([data-mobile-nav=\"info-sheet\"]):not([data-mobile-nav=\"share-range-sheet\"]) {\n max-width: calc(100vw - 32px) !important;\n }\n /* Nav bar: hide the \"Settings\" caption (redundant on a full-width sheet)\n and wrap the tab list so every tab is visible \u2014 a horizontal scroll cut\n the last tab (\"Plugins\") off with no affordance to scroll. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :first-child {\n width: 100% !important;\n flex-direction: row !important;\n align-items: center !important;\n gap: 6px !important;\n padding: 10px 12px 8px !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :first-child > :first-child {\n display: none !important;\n }\n /* The tab list scrolls in the space left by the toolbar: the toolbar\n (config file + close) is reparented INTO this nav row by a client\n effect (MobileNavOverlay), so the tab list must be anchored by its\n class, NOT by :last-child (the reparented toolbar becomes the nav's\n new last child).\n\n 2026-10-21 (DSH 0.2.1-rc.2): this rule used to declare\n \"flex-wrap: wrap; overflow: visible\" on top of the flex/min-width/gap\n above. Because it is one class-anchored compound selector with a much\n higher specificity than compat.css.ts's portal-scoped navList rule, it\n silently won the tie and the tab list wrapped into two rows \u2014 with the\n reparented \u2715 vertically centred across both of them. Measured on a\n phone shell: the list was 86px tall (two rows) instead of one 40px row,\n and it scrolled nowhere. The wrap was a 2026-08-16 trade-off (show every\n tab, no hidden scroll cut-off); with the thin scrollbar affordance now\n in compat.css.ts the single scrolling row is the better trade, so the\n two declarations live there and this rule no longer contradicts them. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :first-child [class$=\"_navList\"] {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n flex-direction: row !important;\n gap: 6px !important;\n }\n /* Content toolbar (Open configuration file + close): grouped flush to\n the right edge, and reparented INTO the nav row on mobile so it shares\n one line with the tabs (user feedback 2026-08-16 \u2014 the toolbar's own\n row left a full-width dead gap under the tabs). Anchored by class: the\n header leaves the content subtree, so :first-child/:last-child anchors\n would now hit the options area. Children carry official auto-margins\n that would defeat flex-end, so neutralize them. The close button gets\n a round tappable base so it reads as its own control, not part of the\n outline button. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) [class$=\"_header\"] {\n flex: 0 0 auto !important;\n justify-content: flex-end !important;\n align-items: center !important;\n gap: 8px !important;\n padding: 0 0 0 4px !important;\n min-height: 40px !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) [class$=\"_header\"] > * {\n margin-left: 0 !important;\n margin-right: 0 !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) [class$=\"_header\"] > :last-child {\n width: 32px !important;\n height: 32px !important;\n border-radius: 50% !important;\n display: inline-flex !important;\n align-items: center !important;\n justify-content: center !important;\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06)) !important;\n }\n /* Appearance mode cards: the official cube row renders three tall\n vertical cards (~268px) that eat half the sheet. Turn them into a\n compact horizontal trio (icon + label inline, equal widths).\n Relies on the official cube-row class name of this version. */\n [aria-modal=\"true\"] [class$=\"_cubeRow\"] {\n gap: 6px !important;\n }\n [aria-modal=\"true\"] [class$=\"_cubeRow\"] > * {\n flex: 1 1 0 !important;\n flex-direction: row !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 6px !important;\n padding: 10px 8px !important;\n min-height: 0 !important;\n }\n /* Content: the options scroll area gets bottom breathing room so the last\n row never sits flush against the sheet's rounded corner. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :last-child {\n flex: 1 1 auto !important;\n min-height: 0 !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :last-child > :last-child {\n padding: 0 12px 24px !important;\n }\n";
1
+ export declare const LAYOUT_CSS = "/* ---------- mobile-only layout ---------- */\n\n@media (max-width: 1023px) {\n /* --- Phone chrome ---\n The system status bar stays visible (no fullscreen). Two adjustments\n make it behave:\n - touch-action: manipulation kills double-tap-to-zoom (and the 300ms\n tap delay) while keeping pan and pinch zoom; the client also\n suppresses legacy-iOS gesturestart as a fallback.\n - With the client's viewport-fit=cover, env(safe-area-inset-top) is the\n status bar / notch height; the rules below push the app content below\n it so the status bar never covers anything. Off notched phones (or in\n a normal browser tab where the layout viewport already sits below the\n status bar) the inset is 0 and nothing shifts. */\n html,\n body {\n touch-action: manipulation !important;\n }\n\n /* AppFrame: the drawer takes the sidebar column out of grid flow, so the\n remaining in-flow items (center, details) land in tracks 1..2: give the\n center every pixel and keep the details track at zero. The top padding\n clears the status bar / notch for every in-flow surface (session header,\n messages, composer); the absolutely-positioned drawer is unaffected (its\n containing block is the frame's padding box, i.e. still the frame top). */\n /* box-sizing: border-box is load-bearing (S2.1, 2026-08-17). The official\n frame carries height: 100% with the default content-box, so the\n safe-area padding ADDED 54px to its height instead of taking 54px out\n of the content area: the frame grew past the viewport, the document\n became scrollable by exactly the inset, and the very first scroll put\n the header right back under the notch \u2014 measured with\n ?mobile-nav-inset=54 (frame 898px tall inside an 844px root, html at\n y=-54). Invisible on every desktop browser because the inset is 0\n there, which is how it shipped. */\n [data-mobile-nav=\"frame\"] {\n position: relative !important;\n box-sizing: border-box !important;\n grid-template-columns: minmax(0, 1fr) 0 0 !important;\n padding-top: var(--mnav-sat) !important;\n }\n\n /* The sidebar column (first grid child) becomes a left drawer. The drawer\n hugs the sidebar content exactly (the wide sidebar carries an inline\n width, ~280px): a fixed 92vw box would leave a white strip where the\n container background shows beside the content.\n Closed state: translateX(-110%) \u2014 more than -100% of the max-content\n width \u2014 guarantees the whole drawer (and its shadow, had it one) leaves\n the viewport. A mere -100% leaves a sliver on screen; -105% (as used\n before) left 14px of the drawer plus a long 32px-blur shadow gradient\n visible along the left edge of the main UI. No box-shadow at all: the\n dimmed backdrop already separates drawer from content. */\n [data-mobile-nav=\"frame\"] > :first-child {\n position: absolute !important;\n inset: 0 auto 0 0 !important;\n width: max-content !important;\n max-width: 92vw !important;\n z-index: 40 !important;\n transform: translateX(-110%);\n transition: transform .28s var(--ds-ease-in-out, ease-in-out);\n background: var(--dsw-alias-bg-base, #ffffff);\n /* Keep the drawer's own content below the status bar / notch: the drawer\n spans the full frame height (its absolute containing block is the\n frame's padding box, so the frame's own safe-area padding does NOT\n reach it). The drawer background paints the status-bar strip, which\n the client's theme-color meta matches, so the strip reads seamless. */\n padding-top: var(--mnav-sat) !important;\n /* Kill the official sidebarCol right border: with the backdrop the edge\n reads cleanly, and the settings dialog (width:100% of this box) stays\n pixel-flush with the drawer. */\n border-right: none !important;\n }\n\n /* The official right sidebar (DSH 0.1.5+) in its full-screen mode \u2014 the\n one the phone's header sidebar button opens (sidebar-panels.ts). The\n host promotes the panel to position:fixed; inset:0 there, so exactly\n like the drawer above it escapes the frame's safe-area padding and its\n tab strip + chrome buttons landed under the status bar (real-device\n report, 2026-09-21). Both insets: the status bar / notch on top, the\n home indicator at the bottom. Padding, no box-sizing change: fixed\n with both top and bottom set resolves its used height from the\n containing block minus padding (CSS 2.1 10.6.4), so the content box\n shrinks by itself \u2014 the same reasoning the legacy better-sidebar panel\n rule in compat.css.ts spells out. `fullscreen` is the host's own\n attribute value (`push` while docked, dsh-client-ui-sidebar-right), so\n the docked panel is untouched; a manual full-screen on desktop is\n outside this media block anyway. Verify with ?mobile-nav-inset=54,34 \u2014\n env() is 0 in every desktop browser. */\n [data-sidebar-right-panel=\"fullscreen\"] {\n padding-top: var(--mnav-sat) !important;\n padding-bottom: var(--mnav-sab) !important;\n }\n /* Right sidebar start/guide page (dsh-client-ui-sidebar-right GuideBody):\n the host sets .Dv5QdW_tabBody { height: 100%; overflow: hidden } and\n .F6Huca_guide { min-height: 100%; justify-content: center } with no\n overflow-y. When many tab entries are registered (e.g. better-sidebar +\n plugins), the centered flex column overflows equally out the top and\n bottom of the locked 100%-height box \u2014 clipping the leading entries\n (\"\u6587\u4EF6\", \"Git\") above y=0 with no way to scroll. Make the guide itself\n the scroll container and replace justify-content:center with auto\n margins on the first item and ::after so short lists stay centered\n while long lists start cleanly at the top and scroll end-to-end. */\n [data-sidebar-right-guide] {\n flex: 1 1 0 !important;\n min-height: 0 !important;\n justify-content: flex-start !important;\n overflow-y: auto !important;\n -webkit-overflow-scrolling: touch;\n padding-top: 24px !important;\n padding-bottom: 24px !important;\n }\n [data-sidebar-right-guide] > :first-child {\n margin-top: auto !important;\n }\n [data-sidebar-right-guide]::after {\n margin-bottom: auto !important;\n }\n\n /* Expanded state (frame without data-sidebar-collapsed) slides the drawer in.\n The open state must be transform:none \u2014 NOT translateX(0): an identity\n transform still makes the drawer the containing block for fixed-position\n descendants (the settings dialog's .VOzbGW_overlay is portaled into the\n sidebar DOM). With the identity transform the wide settings sheet\n (100vw-16) overflows the 280px drawer, the dialog's focus scrolls the\n overflow:hidden drawer to scrollLeft=102, and every static child (plus the\n fixed overlay) shifts 102px off-screen. With transform:none the overlay is\n viewport-anchored: it dims the full screen and the sheet sits at left:8. */\n [data-mobile-nav=\"frame\"]:not([data-sidebar-collapsed]) > :first-child {\n transform: none !important;\n }\n\n /* Drag handles are useless on touch and would float over the drawer. */\n [data-side=\"sidebar\"],\n [data-side=\"details\"] {\n display: none !important;\n }\n\n /* --- Conversation text on mobile ---\n The official message flow keeps desktop's 32px side gutters and 16px\n type. On a phone: shrink the type a notch and widen the lines by\n trimming the gutters (the sidebar drawer list keeps its size). The\n flow's scroll container is the only _scroll element holding markdown\n <p> paragraphs \u2014 the composer's own scroll (textarea) is excluded\n via :has(p). */\n /* The official main scroll body reserves scrollbar-gutter for desktop\n scrollbars (8px), which shoves every column off-center on a phone.\n Classic desktop scrollbars (Edge/Chrome) also occupy ~8-17px in a\n phone-sized viewport, shifting the column further. Mobile scrolling\n is touch/wheel, so remove the scrollbar entirely on phones: the\n column is then exactly centered in every browser. */\n [data-phase] [class$=\"_scrollBody\"] {\n scrollbar-gutter: auto !important;\n scrollbar-width: none !important;\n }\n [data-phase] [class$=\"_scrollBody\"]::-webkit-scrollbar {\n display: none !important;\n width: 0 !important;\n height: 0 !important;\n }\n /* Message action rows (copy / run-time badges) can overflow the right\n edge on narrow screens \u2014 keep them inside the message width. */\n [data-phase] [class$=\"_actions\"] {\n overflow: hidden !important;\n }\n /* The 24h clock (\"18:06\" / \"MM-DD 18:06\") is a fixed-size item: it must\n never be the thing that shrinks. DSH 0.2.x wraps it with the usage\n button in an inline-flex _endInfo (min-width: 0), so a shrinkable\n time (the old flex: 0 1 auto + min-width: 0) got squeezed inside that\n non-wrapping box and \"18:06\" broke into two lines. flex: none pins its\n width; the turn-tail rules in content.css.ts let _endInfo wrap as a\n whole instead. */\n [data-phase] [class$=\"_actions\"] [class$=\"_timeEnd\"] {\n flex: none !important;\n white-space: nowrap !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n }\n\n [data-phase] [class$=\"_scroll\"]:has(p) {\n padding-left: 20px !important;\n padding-right: 20px !important;\n font-size: 15px !important;\n }\n /* The official markdown styles set an explicit 16px on paragraphs and\n list items, so the container's inherited 15px is not enough. User\n messages render their text in a div whose class carries _text_\n (16px too) \u2014 cover it as well. */\n [data-phase] [class$=\"_scroll\"]:has(p) p,\n [data-phase] [class$=\"_scroll\"]:has(p) li,\n [data-phase] [class$=\"_scroll\"]:has(p) [class*=\"_text_\"] {\n font-size: 15px !important;\n }\n\n /* Markdown tables: the official table uses width:max-content, so on a phone\n it hugs the content and leaves dead space beside/inside the table. Force\n the table to fill the message column and let the table wrapper handle\n overflow if a cell is genuinely too wide. */\n [data-phase] table {\n width: 100% !important;\n max-width: 100% !important;\n }\n [data-phase] th,\n [data-phase] td {\n max-width: none !important;\n min-width: 0 !important;\n }\n\n /* User bubbles: the official stack is capped at min(525px, 82%), which on a\n phone leaves a large blank strip on the left and pushes the bubble high.\n On mobile let the user message fill the same full width as assistant\n messages (the bubble background then spans the whole message column). */\n [data-phase] [class$=\"_userStack\"],\n [data-phase] [class$=\"_userStack\"] [class$=\"_bubble\"] {\n box-sizing: border-box !important;\n width: fit-content !important;\n max-width: 100% !important;\n }\n\n /* --- Composer bottom row on mobile ---\n The official row gives the model pill (trailing) flex:0 0 auto, which\n squeezes the agent-permission pill (modes) down to 15px: the pill's\n chevron then overflows on top of the model name. Let the permission\n pill keep its natural width and let the model pill shrink instead.\n Anchored by the composer card (:has(textarea)): row = the _row class\n containing a _trailing group, tools = its first child, permission pill\n = its 2nd child, model pill = the _trailing group.\n NOTE: do NOT anchor these by the card's :last-child \u2014 a client effect\n moves the git-graph branch chip INTO the card, which becomes the card's\n new last child and silently disables every :last-child rule (the model\n pill then falls back to the official fixed layout and long model IDs\n overflow instead of ellipsizing). Structural anchors only. */\n /* The official row pads every group with 12px gaps, which on a phone eats\n width the model pill needs for the full model ID. Tighten the row to 8px\n gaps (the modes pill keeps its natural width) so the model name gets\n every spare pixel. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_row\"]:has([class$=\"_trailing\"]) {\n gap: 8px !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_row\"]:has([class$=\"_trailing\"]) > :first-child {\n gap: 8px !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_row\"]:has([class$=\"_trailing\"]) > :first-child > :nth-child(2) {\n flex: 0 0 auto !important;\n gap: 8px !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_trailing\"] {\n flex: 1 1 auto !important;\n gap: 8px !important;\n min-width: 0 !important;\n }\n /* Let the model selector take the free space in the trailing group so the\n model name is not squeezed/truncated; the context meter stays fixed. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"][aria-haspopup=\"menu\"]) {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"][aria-haspopup=\"menu\"]) > [class$=\"_trigger\"] {\n width: 100% !important;\n max-width: 100% !important;\n }\n /* The model label must absorb the trigger's free width: officially it is a\n fixed-content flex item, so the spare width of a grown pill sits unused\n between the chevron and the pill edge. Let the label grow and shrink:\n the full model ID shows whenever the row can fit it, and the ellipsis\n lands exactly at the available width otherwise. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"][aria-haspopup=\"menu\"]) > [class$=\"_trigger\"] > [class$=\"_triggerLabel\"] {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n }\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"]:not([aria-haspopup=\"menu\"])) {\n flex: 0 0 auto !important;\n }\n\n /* Model switcher menu: the official dropdown is right-aligned to the\n trigger (right:0). The model pill sits near the center of the composer,\n so on a phone the 240px menu overflows the left edge and looks off-center.\n Center the menu on the trigger instead. */\n [data-phase] [class*=\"_card\"]:has(textarea) [class$=\"_root\"]:has(> [class$=\"_trigger\"]) > [class$=\"_menu\"] {\n left: 50% !important;\n right: auto !important;\n transform: translateX(-50%) !important;\n }\n\n /* --- Session header on mobile ---\n Layout goal: [toggle] [session title] [mode badge] in a row, with the\n Session log capsule removed from the header (relocated to the drawer\n footer). Stable structural hooks only:\n [data-phase] header the session header element\n header > :first-child titleRow (titleCluster + utilities)\n header > :first-child > :last-child headerUtilities (Session log seat) */\n [data-phase] header {\n padding-right: 12px !important;\n }\n /* Give the title row a lane clear of the absolutely-placed toggle, then\n balance the header: with header padding-right 12px, a 20px left\n padding puts the title's geometric center exactly on the viewport\n center (measured 195/195 at 390px). */\n [data-phase] header > :first-child {\n padding-left: 20px !important;\n }\n /* The directory toggle sits at the far left of the header (the header\n is position:relative; the data-slot wrappers are display:contents). */\n [data-mobile-nav=\"toggle\"] {\n position: absolute !important;\n left: 8px !important;\n top: 12px !important;\n z-index: 2 !important;\n }\n /* The Files action stays in-flow inside headerActions. On mobile headerActions\n does not expand to fill the row: it is pushed to the right edge and keeps\n its content size, so [mode] [subagent/jobs] [files] sit close together\n with the normal 8px gaps \u2014 compact, no artificial blank columns. Explicit\n flex order keeps Files rightmost regardless of DOM order. */\n [data-mobile-nav=\"files\"] {\n position: static !important;\n left: auto !important;\n right: auto !important;\n top: auto !important;\n z-index: auto !important;\n }\n [data-phase] header [class$=\"_headerActions\"] {\n flex: 0 1 auto !important;\n min-width: 0 !important;\n margin-left: auto !important;\n justify-content: flex-end !important;\n }\n /* The session title/crumb must yield space on mobile so the mode label and\n subagent cluster are not squeezed to a single letter. Cap it at ~24vw and\n let it truncate with ellipsis. */\n [data-phase] header [class$=\"_crumbs\"] {\n flex: 0 1 auto !important;\n min-width: 0 !important;\n max-width: 24vw !important;\n }\n /* Mode label (AgentPresetLabel): the official pill uses inline-flex, whose\n direct text node is only clipped \u2014 no ellipsis. Convert the pill to a\n block container, keep its icon absolutely positioned on the left, and let\n it size naturally up to 42vw so the mode name stays readable while the\n subagent/Files cluster still fits on a phone. */\n [data-phase] header [class$=\"_label\"]:has(> svg) {\n order: 1 !important;\n flex: 0 1 auto !important;\n min-width: 0 !important;\n max-width: 42vw !important;\n display: block !important;\n position: relative !important;\n box-sizing: border-box !important;\n padding-left: 18px !important;\n padding-right: 2px !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n white-space: nowrap !important;\n }\n [data-phase] header [class$=\"_label\"]:has(> svg) > svg {\n position: absolute !important;\n left: 0 !important;\n top: 50% !important;\n transform: translateY(-50%) !important;\n }\n /* Subagent/jobs helpers: keep their triggers on one line and never let the\n row grow artificial empty space. */\n [data-phase] header [class$=\"_root\"]:has(> button[class$=\"_trigger\"]) {\n order: 2 !important;\n flex: 0 0 auto !important;\n min-width: max-content !important;\n max-width: none !important;\n white-space: nowrap !important;\n /* On mobile the popover is anchored to the header (viewport-width\n containing block) instead of the trigger, so a small left inset keeps it\n fully on screen and never clips the tree's status dots. */\n position: static !important;\n }\n [data-phase] header [class$=\"_root\"]:has(> button[class$=\"_trigger\"]) > button,\n [data-phase] header [class$=\"_root\"]:has(> button[class$=\"_trigger\"]) > button * {\n white-space: nowrap !important;\n }\n [data-phase] header [data-mobile-nav=\"files\"] {\n order: 3 !important;\n flex: 0 0 auto !important;\n }\n /* Session log download: gone from the header row on mobile (the utilities\n seat holds only the session-log-export capsule). */\n [data-phase] header > :first-child > :last-child {\n display: none !important;\n }\n\n /* --- Header popovers on mobile (dsh-client-ui-jobs / dsh-client-ui-subagent) ---\n The official entries sit in the session header actions. Their popovers\n are anchored to the trigger's LEFT edge (left: 0), so from a right-edge\n trigger the 336px panel spills past the viewport. Re-anchor them to the\n trigger's right edge instead. The popover classes are hashed CSS-module\n names, so target them by the stable _menu suffix inside the header. */\n /* Header popovers on mobile: anchor to the left edge with a small inset and\n clamp the width, instead of right-aligning to a trigger near the right\n edge (which pushed the panel left off-screen and clipped the status dots).\n Also cap the height so the panel does not run into the composer/task bar. */\n [data-phase] header [class$=\"_menu\"] {\n left: 8px !important;\n right: auto !important;\n width: min(336px, calc(100vw - 16px)) !important;\n max-width: none !important;\n max-height: min(420px, calc(100dvh - 120px)) !important;\n }\n /* --- Settings dialog on mobile ---\n Desktop: 800px two-column flex (188px nav + content). Mobile: a\n near-full-width sheet \u2014 nav tabs wrap into rows on top, option rows\n stay horizontal (title+description left, control right). Structural\n selectors are scoped to the unique aria-modal dialog; every\n settings-specific rule is gated with\n :has(> :first-child > :last-child > button) \u2014 the settings nav tab\n list holds <button> tabs, so the transient export dialog (the same\n primitives Modal, header(title+close)+description+body) keeps its\n official centered card layout. Requires :has() support\n (Chromium 105+, 2022).\n\n The directory picker (dsh-client-ui-directory-picker-browse) must be\n excluded too: its footer bar holds <button> children AND its breadcrumb\n trail (role=\"navigation\") \u2014 which the role gate relies on to exclude\n it \u2014 is REPLACED by the path input in edit mode (pencil button), so\n without the ZuhsRW exclusion clicking the pencil would suddenly match\n this sheet rule: the dialog jumps to the top of the screen, the header\n (with the path input) is hidden by the > :first-child > :first-child\n display:none rule below, and the user can no longer type a path\n (issue #12, 2026-08-16). The picker family keeps the official layout\n on mobile in every mode. */\n /* DSH 0.2.1-rc.2 renders this dialog as a body PORTAL\n (body > overlay > panel), so the placement below must key off the nav\n list the panel owns, not off a guessed child depth: that is both the\n stable \"this is the settings sheet\" anchor and the reason the safe-area\n offset below still applies inside the portal (the constants live on\n :root, so they cross the portal boundary). The bottom inset is\n subtracted too \u2014 a tall panel must not run under the home indicator. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])):has([class$=\"_navList\"]) {\n position: absolute !important;\n left: 8px !important;\n /* Fixed top (no translateY): a transform on the panel combined with the\n panel overflowing the max-content drawer shifts the fixed overlay's\n coordinate frame, dragging the whole sidebar content off-screen. The\n safe-area inset keeps the sheet below the status bar / notch. */\n top: calc(var(--mnav-sat) + 12px) !important;\n width: calc(100vw - 16px) !important;\n max-width: calc(100vw - 16px) !important;\n /* Height follows the content (no dead space under a short page); it\n caps at 100dvh-24 (less both safe-area insets) and the options area\n scrolls only then. */\n height: auto !important;\n max-height: min(800px, calc(100vh - 24px - var(--mnav-sat) - var(--mnav-sab))) !important;\n max-height: min(800px, calc(100dvh - 24px - var(--mnav-sat) - var(--mnav-sab))) !important;\n flex-direction: column !important;\n border-radius: 14px !important;\n animation: dsh-mobile-nav-sheet-in .22s var(--ds-ease-out, ease-in-out);\n }\n /* The settings sheet's dimmed mask fades in with the panel (the mask is\n the first child of the overlay that directly contains the sheet). */\n :has(> [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"]))) > :first-child {\n animation: dsh-mobile-nav-fade .18s var(--ds-ease-out, ease-in-out);\n }\n @media (prefers-reduced-motion: reduce) {\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])),\n :has(> [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"]))) > :first-child {\n animation: none !important;\n }\n }\n /* The export dialog (not the settings sheet) must never overflow the\n viewport: the official centered card can be wider than 390px.\n :not([data-mobile-nav=\"info-sheet\"]) (S4, 2026-08-17): the session-info\n sheet also carries role=\"dialog\" aria-modal=\"true\" (correct a11y\n semantics for a bottom sheet with a scrim) and has no button as its\n first-child's last-child, so without this exclusion it silently matched\n this generic selector too \u2014 measured 358px (100vw-32px) instead of the\n 374px its own left:8px/right:8px margins specify. Same category of bug\n as the ZuhsRW directory-picker collision below; same fix shape.\n :not([data-mobile-nav=\"share-range-sheet\"]) (share-image, 2026-09-10):\n the share range picker rides the same role=\"dialog\" aria-modal bottom\n -sheet shape and the same margins, so it hit the identical clamp. */\n [aria-modal=\"true\"]:not(:has(> :first-child > :last-child > button)):not([data-mobile-nav=\"info-sheet\"]):not([data-mobile-nav=\"share-range-sheet\"]) {\n max-width: calc(100vw - 32px) !important;\n }\n /* Nav bar: hide the \"Settings\" caption (redundant on a full-width sheet)\n and wrap the tab list so every tab is visible \u2014 a horizontal scroll cut\n the last tab (\"Plugins\") off with no affordance to scroll. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :first-child {\n width: 100% !important;\n flex-direction: row !important;\n align-items: center !important;\n gap: 6px !important;\n padding: 10px 12px 8px !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :first-child > :first-child {\n display: none !important;\n }\n /* The tab list scrolls in the space left by the toolbar: the toolbar\n (config file + close) is reparented INTO this nav row by a client\n effect (MobileNavOverlay), so the tab list must be anchored by its\n class, NOT by :last-child (the reparented toolbar becomes the nav's\n new last child).\n\n 2026-10-21 (DSH 0.2.1-rc.2): this rule used to declare\n \"flex-wrap: wrap; overflow: visible\" on top of the flex/min-width/gap\n above. Because it is one class-anchored compound selector with a much\n higher specificity than compat.css.ts's portal-scoped navList rule, it\n silently won the tie and the tab list wrapped into two rows \u2014 with the\n reparented \u2715 vertically centred across both of them. Measured on a\n phone shell: the list was 86px tall (two rows) instead of one 40px row,\n and it scrolled nowhere. The wrap was a 2026-08-16 trade-off (show every\n tab, no hidden scroll cut-off); with the thin scrollbar affordance now\n in compat.css.ts the single scrolling row is the better trade, so the\n two declarations live there and this rule no longer contradicts them. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :first-child [class$=\"_navList\"] {\n flex: 1 1 auto !important;\n min-width: 0 !important;\n flex-direction: row !important;\n gap: 6px !important;\n }\n /* Content toolbar (Open configuration file + close): grouped flush to\n the right edge, and reparented INTO the nav row on mobile so it shares\n one line with the tabs (user feedback 2026-08-16 \u2014 the toolbar's own\n row left a full-width dead gap under the tabs). Anchored by class: the\n header leaves the content subtree, so :first-child/:last-child anchors\n would now hit the options area. Children carry official auto-margins\n that would defeat flex-end, so neutralize them. The close button gets\n a round tappable base so it reads as its own control, not part of the\n outline button. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) [class$=\"_header\"] {\n flex: 0 0 auto !important;\n justify-content: flex-end !important;\n align-items: center !important;\n gap: 8px !important;\n padding: 0 0 0 4px !important;\n min-height: 40px !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) [class$=\"_header\"] > * {\n margin-left: 0 !important;\n margin-right: 0 !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) [class$=\"_header\"] > :last-child {\n width: 32px !important;\n height: 32px !important;\n border-radius: 50% !important;\n display: inline-flex !important;\n align-items: center !important;\n justify-content: center !important;\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06)) !important;\n }\n /* Appearance mode cards: the official cube row renders three tall\n vertical cards (~268px) that eat half the sheet. Turn them into a\n compact horizontal trio (icon + label inline, equal widths).\n Relies on the official cube-row class name of this version. */\n [aria-modal=\"true\"] [class$=\"_cubeRow\"] {\n gap: 6px !important;\n }\n [aria-modal=\"true\"] [class$=\"_cubeRow\"] > * {\n flex: 1 1 0 !important;\n flex-direction: row !important;\n align-items: center !important;\n justify-content: center !important;\n gap: 6px !important;\n padding: 10px 8px !important;\n min-height: 0 !important;\n }\n /* Content: the options scroll area gets bottom breathing room so the last\n row never sits flush against the sheet's rounded corner. */\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :last-child {\n flex: 1 1 auto !important;\n min-height: 0 !important;\n }\n [aria-modal=\"true\"]:has(> :first-child > :last-child > button):not(:has([role=\"navigation\"])):not(:has([class*=\"ZuhsRW\"])) > :last-child > :last-child {\n padding: 0 12px 24px !important;\n }\n";
2
2
  //# sourceMappingURL=layout.css.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout.css.d.ts","sourceRoot":"","sources":["../../../../src/client/styles/layout.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,UAAU,+p5BA+hBtB,CAAA"}
1
+ {"version":3,"file":"layout.css.d.ts","sourceRoot":"","sources":["../../../../src/client/styles/layout.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,UAAU,s27BAwjBtB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"GatewayWizard.d.ts","sourceRoot":"","sources":["../../../../src/client/wizard/GatewayWizard.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACjF,OAAO,KAAK,EAMV,qBAAqB,EACtB,MAAM,oCAAoC,CAAA;AAmD3C,OAAO,EAAE,EAAE,EAAE,MAAM,eAAe,CAAA;AAMlC,MAAM,WAAW,kBAAmB,SAAQ,YAAY,CAAC,uBAAuB,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC;IACvG,qEAAqE;IACrE,MAAM,EAAE,qBAAqB,CAAA;IAC7B,2EAA2E;IAC3E,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3G;AAoGD,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,SAAS,CAm/DlE"}
1
+ {"version":3,"file":"GatewayWizard.d.ts","sourceRoot":"","sources":["../../../../src/client/wizard/GatewayWizard.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACjF,OAAO,KAAK,EAMV,qBAAqB,EACtB,MAAM,oCAAoC,CAAA;AAqD3C,OAAO,EAAE,EAAE,EAAE,MAAM,eAAe,CAAA;AAMlC,MAAM,WAAW,kBAAmB,SAAQ,YAAY,CAAC,uBAAuB,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC;IACvG,qEAAqE;IACrE,MAAM,EAAE,qBAAqB,CAAA;IAC7B,2EAA2E;IAC3E,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3G;AAoGD,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,SAAS,CAugElE"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * UX-3 — what tapping the phone home screen's "+ 新建会话" FAB should do.
3
+ *
4
+ * Entering a blank session with NO workspace leaves the phone dangling in
5
+ * the hero's inert "choose a workspace" state (the host's `marshal-main`
6
+ * belongs to no workspace, so the "all" filter often resolves to
7
+ * `undefined`). Decide BEFORE entering:
8
+ *
9
+ * - a workspace is already selected → start there;
10
+ * - exactly one workspace exists (or none at all) → start with it
11
+ * (`undefined` keeps a no-workspace host usable);
12
+ * - several workspaces and none selected → the FAB opens the same
13
+ * bottom-sheet workspace drawer the title bar uses, and the session only
14
+ * starts once one is picked.
15
+ *
16
+ * Pure: no DOM, no imports — MobileHome calls it inside the FAB's onClick
17
+ * and test/permission-sheet.test.cjs drives it directly.
18
+ */
19
+ export type NewSessionAction<W extends string> = {
20
+ kind: 'start';
21
+ workspaceId: W | undefined;
22
+ } | {
23
+ kind: 'pick-workspace';
24
+ };
25
+ export declare function decideNewSessionAction<W extends string>(selectedWorkspaceId: W | undefined, workspaceIds: readonly W[]): NewSessionAction<W>;
26
+ //# sourceMappingURL=new-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new-session.d.ts","sourceRoot":"","sources":["../../../src/client-data/new-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,IACzC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,CAAC,GAAG,SAAS,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAA;AAE9B,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,MAAM,EACrD,mBAAmB,EAAE,CAAC,GAAG,SAAS,EAClC,YAAY,EAAE,SAAS,CAAC,EAAE,GACzB,gBAAgB,CAAC,CAAC,CAAC,CAIrB"}
@@ -282,6 +282,42 @@ export declare function normalizePairingCode(input: string): string;
282
282
  * save — a follow mid-typing would clobber it).
283
283
  */
284
284
  export declare function shouldFollowServerDeviceName(deviceName: string, rowName: string, hasDraft: boolean): boolean;
285
+ /**
286
+ * Whether one successful client-side activation (a staged-save role switch, a
287
+ * first pairing) needs a page reload: the backend's restart-watcher only
288
+ * installs the stream interceptor when the row reloads into client mode, and
289
+ * the page's three resident global streams were opened under whatever gateway
290
+ * object was current AT LOAD TIME. Without a reload they stay unwrapped and
291
+ * the server's remote sessions never enter the merged sidebar lists.
292
+ *
293
+ * - A write that did not land, or a save that is not heading to `client`,
294
+ * never reloads.
295
+ * - A host→client switch always reloads: the streams predate the interceptor.
296
+ * - An already-client page reloads only when the diagnostics say the
297
+ * interceptor was NOT yet active (`streamInterceptAlreadyActive === false`).
298
+ * `undefined` — an older server that answers no diagnostics — is UNKNOWN and
299
+ * stays on the safe no-reload side (a re-pairing must not needlessly reload).
300
+ */
301
+ export interface ClientActivationReloadInput {
302
+ /** Whether the page was ALREADY an effective client before this operation. */
303
+ wasEffectiveClient: boolean;
304
+ /** Whether the role after the operation is (or is switching to) client. */
305
+ nowClientRole: boolean;
306
+ /** Whether this operation actually landed (the save / pairing write). */
307
+ savedOrPaired: boolean;
308
+ /** The client/status diagnostics' interceptor flag before the operation
309
+ * (derived by the caller); `undefined` when unknown. */
310
+ streamInterceptAlreadyActive?: boolean;
311
+ }
312
+ export declare function shouldReloadAfterClientActivation(input: ClientActivationReloadInput): boolean;
313
+ /**
314
+ * Poll {@link CLIENT_STATUS_ROUTE} until the backend answers ok — the bounded
315
+ * wait before the post-activation reload, covering the restart-watcher's row
316
+ * reload window (the route 404s / fails while the row restarts). Resolves
317
+ * after `maxMs` regardless, so the reload always fires. Injectable fetch and
318
+ * timings keep the check script fast; defaults are the page's 3 s / 250 ms.
319
+ */
320
+ export declare function awaitClientStatusReady(fetchFn?: typeof fetch, maxMs?: number, intervalMs?: number): Promise<void>;
285
321
  /**
286
322
  * Latest-wins sequencing for the status loads: every request takes a ticket,
287
323
  * and only the newest ticket may still apply its result. An earlier request
@@ -1 +1 @@
1
- {"version":3,"file":"settings-form.d.ts","sourceRoot":"","sources":["../../../src/client-data/settings-form.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings-form.d.ts","sourceRoot":"","sources":["../../../src/client-data/settings-form.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-zen-remote",
3
- "version": "2.3.8",
3
+ "version": "2.3.9",
4
4
  "description": "一个插件、两种角色:主服务端把 DeepSeek Harness 变成手机能安全访问的 PWA(移动端界面、配对码网关、Web Push),并把选定会话共享给已配对的桌面端;子客户端在另一台 DSH 桌面端的侧边栏里远程使用这些会话。One DSH plugin, two roles: the host turns DeepSeek Harness into a phone-reachable PWA (mobile UI, pairing-code gateway behind your own reverse proxy, Web Push) and shares chosen sessions to paired desktops; the client uses those sessions remotely from another DSH desktop app's sidebar.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -18,8 +18,11 @@
18
18
  import assert from 'node:assert/strict'
19
19
  import {
20
20
  CLIENT_RECONNECT_ROUTE,
21
+ CLIENT_STATUS_ROUTE,
22
+ awaitClientStatusReady,
21
23
  claimDeviceNameOf,
22
24
  shouldFollowServerDeviceName,
25
+ shouldReloadAfterClientActivation,
23
26
  createLatestGate,
24
27
  clientStatusLineOf,
25
28
  deriveClientStatusView,
@@ -935,3 +938,63 @@ test('T59: hasDraft tracks the staged map; writeDeviceName lands one serverName
935
938
  assert.deepEqual(state.mutateCalls.at(-1).ops, [{ op: 'set', path: ['serverName'], value: '服务端的名' }])
936
939
  assert.equal(state.mutateCalls.at(-1).expectedRevision, 8, 'fenced like every direct write')
937
940
  })
941
+
942
+ // ---- UX-1: the reload-after-first-client-activation decision -----------------
943
+
944
+ test('shouldReloadAfterClientActivation truth table: nothing saved or not client never reloads', () => {
945
+ // The write did not land — nothing changed, no reload ever.
946
+ assert.equal(shouldReloadAfterClientActivation({ wasEffectiveClient: false, nowClientRole: true, savedOrPaired: false }), false)
947
+ assert.equal(shouldReloadAfterClientActivation({ wasEffectiveClient: true, nowClientRole: true, savedOrPaired: false }), false)
948
+ // The role is not (or not becoming) client — no reload even though it saved.
949
+ assert.equal(shouldReloadAfterClientActivation({ wasEffectiveClient: false, nowClientRole: false, savedOrPaired: true }), false)
950
+ assert.equal(shouldReloadAfterClientActivation({ wasEffectiveClient: true, nowClientRole: false, savedOrPaired: true }), false)
951
+ })
952
+
953
+ test('shouldReloadAfterClientActivation: a host→client switch always reloads', () => {
954
+ // The page opened while 'host': its three global streams are unwrapped, so
955
+ // the switch must reload no matter what the (absent) diagnostics said.
956
+ assert.equal(shouldReloadAfterClientActivation({ wasEffectiveClient: false, nowClientRole: true, savedOrPaired: true }), true)
957
+ assert.equal(shouldReloadAfterClientActivation({ wasEffectiveClient: false, nowClientRole: true, savedOrPaired: true, streamInterceptAlreadyActive: false }), true)
958
+ assert.equal(shouldReloadAfterClientActivation({ wasEffectiveClient: false, nowClientRole: true, savedOrPaired: true, streamInterceptAlreadyActive: true }), true, 'a stale positive flag cannot beat the switch')
959
+ assert.equal(shouldReloadAfterClientActivation({ wasEffectiveClient: false, nowClientRole: true, savedOrPaired: true, streamInterceptAlreadyActive: undefined }), true, 'unknown diagnostics still reloads on a role switch')
960
+ })
961
+
962
+ test('shouldReloadAfterClientActivation: already client reloads only when the intercept was NOT active', () => {
963
+ // First pairing completed on an already-client page whose backend
964
+ // interceptor had not installed yet (openWireStream never wrapped) — reload.
965
+ assert.equal(shouldReloadAfterClientActivation({ wasEffectiveClient: true, nowClientRole: true, savedOrPaired: true, streamInterceptAlreadyActive: false }), true)
966
+ // Re-pairing / renaming on an already-active client — NO reload (the
967
+ // restart-watcher rewraps in place, the open streams keep working).
968
+ assert.equal(shouldReloadAfterClientActivation({ wasEffectiveClient: true, nowClientRole: true, savedOrPaired: true, streamInterceptAlreadyActive: true }), false)
969
+ // Unknown diagnostics (an older server without the intercept field) never
970
+ // reloads by itself — the flag must be an explicit false.
971
+ assert.equal(shouldReloadAfterClientActivation({ wasEffectiveClient: true, nowClientRole: true, savedOrPaired: true, streamInterceptAlreadyActive: undefined }), false)
972
+ })
973
+
974
+ test('CLIENT_STATUS_ROUTE is the poll target for the post-activation wait', () => {
975
+ assert.equal(CLIENT_STATUS_ROUTE, '/_dsh/zen-remote/client/status')
976
+ })
977
+
978
+ test('awaitClientStatusReady resolves on the first ok answer', async () => {
979
+ let calls = 0
980
+ const fetchFn = async () => { calls += 1; return { ok: true } }
981
+ await awaitClientStatusReady(fetchFn, 5_000, 10)
982
+ assert.equal(calls, 1, 'one ok answer ends the wait immediately')
983
+ })
984
+
985
+ test('awaitClientStatusReady keeps polling until an ok answer arrives', async () => {
986
+ let calls = 0
987
+ const fetchFn = async () => { calls += 1; return calls < 3 ? { ok: false } : { ok: true } }
988
+ await awaitClientStatusReady(fetchFn, 5_000, 5)
989
+ assert.equal(calls, 3, 'polls through the not-ready answers')
990
+ })
991
+
992
+ test('awaitClientStatusReady gives up after the deadline and still resolves', async () => {
993
+ let calls = 0
994
+ const fetchFn = async () => { calls += 1; throw new Error('row reloading') }
995
+ const started = Date.now()
996
+ await assert.doesNotReject(awaitClientStatusReady(fetchFn, 60, 10))
997
+ const elapsed = Date.now() - started
998
+ assert.ok(elapsed >= 50, `waited out the deadline (elapsed ${elapsed}ms)`)
999
+ assert.ok(calls >= 2, `polled more than once before giving up (${calls} calls)`)
1000
+ })
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The dsh-better-sidebar adapter (PB-12), written against EXACTLY
3
- * versions 0.25.0, 0.26.0, 0.26.1, 0.28.0-alpha.0, 0.28.0, 0.28.1 and 0.28.2 (PB-15 widened the list; 0.26.1 is a
3
+ * versions 0.25.0, 0.26.0, 0.26.1, 0.28.0-alpha.0, 0.28.0, 0.28.1, 0.28.2 and 0.30.0 (PB-15 widened the list; 0.26.1 is a
4
4
  * perf-only patch with the same wire surface as 0.26.0; 0.26.0 is a JSON-api
5
5
  * superset of 0.25.0 — it grows fs.readPage and the sidechat dequeue/model/
6
6
  * models methods, and moves fs.write's content onto the new raw-text
@@ -42,6 +42,15 @@ import { SIDEBAR_METHODS, sidebarMethodNameOf } from './methods.js'
42
42
  * backend would accept anyway. */
43
43
  const SIDEBAR_MAX_BODY_BYTES = 1024 * 1024
44
44
 
45
+ /** 0.30.0: a `sidechat.prompt` carrying images reads its body under
46
+ * `sidechatPromptBodyLimit` (lib/index.js:7004) — 1 MiB of metadata plus the
47
+ * base64 of at most SIDECHAT_MAX_MESSAGE_IMAGE_BYTES = 20 MiB of images and
48
+ * 4 bytes per image (≤ 8). Every other method keeps the plugin's own 1 MiB
49
+ * (`readJsonBody`'s default), so the route cap only has to admit this one
50
+ * ceiling; the backend still enforces the per-method limit itself. */
51
+ const SIDEBAR_IMAGE_PROMPT_MAX_BODY_BYTES =
52
+ SIDEBAR_MAX_BODY_BYTES + 4 * Math.ceil((20 * 1024 * 1024) / 3) + 4 * 8
53
+
45
54
  /** The method name out of a `/sidebar/api/*` pathname, or `''`. */
46
55
  const apiMethodOf = (pathname: string): string => sidebarMethodNameOf(pathname) ?? ''
47
56
 
@@ -70,7 +79,13 @@ export const dshBetterSidebarAdapter: BridgeAdapter = {
70
79
  // full-log `sessionQuery.observeSession`, then the host defaultDirectory,
71
80
  // and only then a client `cwd` hint — so the server hook's cwd stripping
72
81
  // below stays correct (if anything, the client hint matters less).
73
- versions: ['0.25.0', '0.26.0', '0.26.1', '0.28.0-alpha.0', '0.28.0', '0.28.1', '0.28.2'],
82
+ // 0.30.0 (DSH 0.2.2-rc.1+): same JSON-api method set and WebSockets; one
83
+ // new EXACT GET route, `/sidebar/sidechat-image?childId&messageId&blockIndex`
84
+ // (lib/index.js:9869-9896), which streams a saved side-chat image — bridged
85
+ // below on its `childId`. `sidechat.prompt` grows an `images` array (base64,
86
+ // up to ~27.7 MiB body) — the api route cap widens to that. GenUI, quote
87
+ // chips and editor draft backup are client-only (no new host routes).
88
+ versions: ['0.25.0', '0.26.0', '0.26.1', '0.28.0-alpha.0', '0.28.0', '0.28.1', '0.28.2', '0.30.0'],
74
89
  // PB-19 (ADR-0003): the wire-surface whitelist. Keys are digest16 over the
75
90
  // PB-18 extractor's reduction (`surface.ts` beside this file) of the npm
76
91
  // builds' lib/index.js, computed off /tmp/bs-versions/{version}/lib/index.js:
@@ -78,6 +93,7 @@ export const dshBetterSidebarAdapter: BridgeAdapter = {
78
93
  // 96465143373a31a7 — the 0.26.0 generation (0.26.1 hashes identically)
79
94
  // 6ed29a896101e681 — the 0.28.0 generation (0.28.0-alpha.0 identically)
80
95
  // 65a0acaeb56f87d9 — the 0.28.1 generation (0.28.2 identically)
96
+ // 394de9f588d37092 — the 0.30.0 generation (+ /sidebar/sidechat-image)
81
97
  // An installed version outside `versions` still registers when its build
82
98
  // hashes into one of these (a wire-identical patch release bridges without
83
99
  // a zen-remote release); anything else fails closed to the unlisted-version
@@ -88,6 +104,7 @@ export const dshBetterSidebarAdapter: BridgeAdapter = {
88
104
  '96465143373a31a7': 'the 0.26.0 generation (0.26.1 identical)',
89
105
  '6ed29a896101e681': 'the 0.28.0 generation (0.28.0-alpha.0 identical)',
90
106
  '65a0acaeb56f87d9': 'the 0.28.1 generation (0.28.2 identical)',
107
+ '394de9f588d37092': 'the 0.30.0 generation',
91
108
  },
92
109
  routes: [
93
110
  {
@@ -97,7 +114,7 @@ export const dshBetterSidebarAdapter: BridgeAdapter = {
97
114
  path: '/sidebar/api',
98
115
  match: 'prefix',
99
116
  methods: ['POST'],
100
- maxBody: SIDEBAR_MAX_BODY_BYTES,
117
+ maxBody: SIDEBAR_IMAGE_PROMPT_MAX_BODY_BYTES,
101
118
  locator: { in: 'json-body', fields: ['sessionId', 'rootSessionId', 'childId'] },
102
119
  deny: ({ pathname, currentSessionId }) => {
103
120
  const name = apiMethodOf(pathname)
@@ -121,6 +138,9 @@ export const dshBetterSidebarAdapter: BridgeAdapter = {
121
138
  // claims the EXACT documented path — a sub-path (if a future version
122
139
  // grows one) stays local rather than being guessed at.
123
140
  { path: '/sidebar/file', match: 'exact', methods: ['GET'], locator: { in: 'query', name: 'sessionId' } },
141
+ // 0.30.0: a saved side-chat image (lib/index.js:9869-9896) — the child
142
+ // session id rides the query; the answer is raw image bytes with no ids.
143
+ { path: '/sidebar/sidechat-image', match: 'exact', methods: ['GET'], locator: { in: 'query', name: 'childId' } },
124
144
  // The archive download (lib/index.js:6949-6985).
125
145
  { path: '/sidebar/archive', match: 'exact', methods: ['GET'], locator: { in: 'query', name: 'sessionId' } },
126
146
  // The raw upload (lib/index.js:6905-6948): binary bytes, capped by the
@@ -21,6 +21,7 @@ import type { createNavStore } from './nav-store.ts'
21
21
  import type { WorkspaceFilter } from './nav-store.ts'
22
22
  import type { MobileNavKey } from './locales.ts'
23
23
  import { dotState } from './session-dot.ts'
24
+ import { decideNewSessionAction } from '../client-data/new-session.ts'
24
25
  import { MobileHomeChips, MobileHomeChipsSheetBody } from './MobileHomeChips.tsx'
25
26
 
26
27
  /** Full props for the phone home screen (shell.overlay entry). */
@@ -280,7 +281,7 @@ export function MobileHome({
280
281
  // list re-renders on any session change anyway (the running dots live here).
281
282
  const sessions = useSessions((s) => s)
282
283
  const workspaces = useWorkspaces((s) => s)
283
- const [sheet, setSheet] = useState<'filter' | 'chips' | null>(null)
284
+ const [sheet, setSheet] = useState<'filter' | 'chips' | 'new-session' | null>(null)
284
285
  /** The one row whose archive action is swiped open (null = none). */
285
286
  const [swipeOpen, setSwipeOpen] = useState<SessionId | null>(null)
286
287
  // 0.1.2 的待处理交互来源;0.1.1 没有这个标准 prop,读到 undefined 时用一个
@@ -560,7 +561,19 @@ export function MobileHome({
560
561
  data-mobile-nav="home-fab"
561
562
  aria-label={t('newSession')}
562
563
  title={t('newSession')}
563
- onClick={() => enter(() => startSession(selectedWorkspace?.workspaceId))}
564
+ onClick={() => {
565
+ // UX-3: never enter a dangling no-workspace session. With "all"
566
+ // selected (the common case — the host's own sessions belong to no
567
+ // workspace) the decision either auto-starts the only workspace or
568
+ // opens the workspace drawer first; the session then starts with a
569
+ // workspace attached from the first frame.
570
+ const action = decideNewSessionAction(
571
+ selectedWorkspace?.workspaceId,
572
+ workspaces.items.map((item) => item.workspaceId),
573
+ )
574
+ if (action.kind === 'start') enter(() => startSession(action.workspaceId))
575
+ else setSheet('new-session')
576
+ }}
564
577
  >
565
578
  <IconPlusOutlineRegular size={18} />
566
579
  <span>{t('newSession')}</span>
@@ -575,13 +588,15 @@ export function MobileHome({
575
588
  aria-label={t('close')}
576
589
  onClick={() => setSheet(null)}
577
590
  />
578
- {/* Two sheets share this one container (chrome + S6 drag-to-close
591
+ {/* Three sheets share this one container (chrome + S6 drag-to-close
579
592
  * + mask-click-close, all keyed off data-mobile-nav="home-sheet"
580
593
  * generically — effects/gestures.ts): the workspace switcher
581
- * (role="menu", unchanged) and the S5 chip-customize toggle list
582
- * (MobileHomeChipsSheetBody, no menu semantics — its rows are
583
- * switches, not menu items that close the sheet on click). */}
584
- <div data-mobile-nav="home-sheet" role={sheet === 'filter' ? 'menu' : undefined}>
594
+ * (role="menu", unchanged), the UX-3 new-session workspace pick
595
+ * (role="menu" — its rows navigate and close), and the S5
596
+ * chip-customize toggle list (MobileHomeChipsSheetBody, no menu
597
+ * semantics — its rows are switches, not menu items that close
598
+ * the sheet on click). */}
599
+ <div data-mobile-nav="home-sheet" role={sheet === 'chips' ? undefined : 'menu'}>
585
600
  {sheet === 'filter' && (
586
601
  <>
587
602
  <div data-mobile-nav="home-sheet-title">{t('switchWorkspace')}</div>
@@ -614,6 +629,28 @@ export function MobileHome({
614
629
  ))}
615
630
  </>
616
631
  )}
632
+ {sheet === 'new-session' && (
633
+ <>
634
+ <div data-mobile-nav="home-sheet-title">{t('pickWorkspaceNew')}</div>
635
+ {workspaces.items.map((item) => (
636
+ <button
637
+ key={item.workspaceId}
638
+ type="button"
639
+ role="menuitem"
640
+ data-mobile-nav="home-sheet-item"
641
+ onClick={() => {
642
+ // Pin the list to the picked workspace (so backing out
643
+ // of the blank session lands on ITS list) and start the
644
+ // session with that workspace from the first frame.
645
+ actions.filter(item.workspaceId)
646
+ enter(() => startSession(item.workspaceId))
647
+ }}
648
+ >
649
+ {item.title}
650
+ </button>
651
+ ))}
652
+ </>
653
+ )}
617
654
  {sheet === 'chips' && <MobileHomeChipsSheetBody t={t} />}
618
655
  </div>
619
656
  </div>
@@ -74,7 +74,13 @@ type ActivityState = 'running' | 'done' | 'warning'
74
74
  * the root through `:has()` instead of naming it.
75
75
  */
76
76
  const HEADER = '[data-phase] header'
77
- const SUBAGENT_TRIGGER = `${HEADER} button[aria-haspopup="tree"]`
77
+ /* UX-2 (2026-11-04): narrowed by the action-button class tail. The bare
78
+ `button[aria-haspopup="tree"]` matched the breadcrumb's parent-session
79
+ switcher first (`…_switcherTrigger` — also a tree popup), so both the
80
+ overlay and this fallback check resolved to the wrong button. The suffix
81
+ matcher is case-sensitive and `_switcherTrigger` does not end in
82
+ `_trigger`. Must stay in lockstep with effects/native-trigger-overlay.ts. */
83
+ const SUBAGENT_TRIGGER = `${HEADER} button[class$="_trigger"][aria-haspopup="tree"]`
78
84
  const JOBS_TRIGGER = `${HEADER} button[class$="_trigger"]:not([aria-haspopup])`
79
85
 
80
86
  /** One glanceable group: icon + count + state dot; opens the official popover. */