@cecwxf/dsh-room 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -37,17 +37,32 @@ var import_react = require("react");
37
37
  var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
38
38
 
39
39
  // src/client/rooms.css
40
- var rooms_default = '/* Collab Rooms UI \u2014 original surface inside the dsh shell. Uses only dsh --dsw-* tokens.\n Independent Rooms surface. Prefix: rm- (rooms). */\n\n.rm-root {\n --rm-accent: var(--dsw-alias-state-business-primary);\n --rm-hover: var(--dsw-alias-interactive-bg-hover);\n --rm-border: var(--dsw-alias-border-l2);\n --rm-bg: var(--dsw-alias-bg-base);\n --rm-panel: var(--dsw-alias-bg-module-platform);\n --rm-label: var(--dsw-alias-label-primary);\n --rm-muted: var(--dsw-alias-label-secondary);\n --rm-quiet: var(--dsw-alias-label-tertiary);\n font: 13px/1.5 var(--dsw-font-family);\n color: var(--rm-label);\n box-sizing: border-box;\n}\n.rm-root *, .rm-root *::before, .rm-root *::after { box-sizing: border-box; }\n.rm-root button, .rm-root input, .rm-root textarea { font: inherit; }\n\n/* \u2500\u2500 sidebar (joined rooms + public search) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-side {\n display: flex; flex-direction: column; height: 100%; min-height: 0;\n padding: 0 8px 8px 0; gap: 8px;\n}\n.rm-side-toolbar {\n display: flex; align-items: center; gap: 6px; flex: none; padding: 4px 0 2px;\n}\n.rm-side-title {\n flex: 1; font-size: 12px; font-weight: 600; letter-spacing: .04em;\n text-transform: uppercase; color: var(--rm-quiet);\n}\n.rm-icon-btn {\n width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;\n border: 0; border-radius: 8px; background: transparent; color: var(--rm-muted); cursor: pointer; padding: 0;\n}\n.rm-icon-btn:hover { background: var(--rm-hover); color: var(--rm-label); }\n.rm-search {\n display: flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px;\n border: .5px solid var(--rm-border); border-radius: 8px; background: var(--rm-panel);\n}\n.rm-search input {\n flex: 1; min-width: 0; border: 0; background: transparent; outline: none; color: var(--rm-label); font-size: 13px;\n}\n.rm-search input::placeholder { color: var(--rm-quiet); }\n.rm-side-scroll { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 12px; }\n.rm-group-label { font-size: 11px; font-weight: 600; color: var(--rm-quiet); padding: 0 4px 4px; text-transform: uppercase; letter-spacing: .03em; }\n.rm-room-list { display: flex; flex-direction: column; gap: 2px; }\n.rm-room-item {\n display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 10px;\n border: 0; border-radius: 10px; background: transparent; color: inherit; cursor: pointer; text-align: left;\n}\n.rm-room-item:hover { background: var(--rm-hover); }\n.rm-room-item[aria-current="true"] { background: var(--rm-hover); }\n.rm-room-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }\n.rm-room-item-name { font-weight: 600; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-room-item-meta { font-size: 11.5px; color: var(--rm-quiet); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-room-item-trail { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }\n.rm-badge {\n display: inline-flex; align-items: center; gap: 3px; height: 18px; padding: 0 6px;\n border-radius: 999px; font-size: 10.5px; font-weight: 500; background: var(--rm-panel); color: var(--rm-muted);\n border: .5px solid var(--rm-border);\n}\n.rm-badge-public { color: var(--rm-accent); border-color: color-mix(in srgb, var(--rm-accent) 35%, transparent); background: color-mix(in srgb, var(--rm-accent) 8%, transparent); }\n.rm-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--rm-quiet); }\n.rm-dot-online { background: var(--dsw-alias-state-success-primary, #2bb673); }\n.rm-dot-connecting { background: var(--dsw-alias-state-warn-primary, #e9a23b); }\n.rm-dot-offline { background: var(--dsw-alias-state-error-primary, #e5484d); }\n.rm-empty-hint { padding: 8px 10px; font-size: 12px; color: var(--rm-quiet); line-height: 1.45; }\n.rm-dir-item {\n display: flex; align-items: flex-start; gap: 10px; padding: 10px; border-radius: 10px;\n border: .5px solid var(--rm-border); background: var(--rm-bg); margin-bottom: 6px;\n}\n.rm-dir-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }\n.rm-dir-tags { display: flex; flex-wrap: wrap; gap: 4px; }\n.rm-tag { font-size: 11px; color: var(--rm-muted); background: var(--rm-hover); border-radius: 4px; padding: 0 5px; }\n.rm-menu {\n position: fixed; z-index: 1000; min-width: 180px; padding: 4px;\n border-radius: 10px; background: var(--dsw-alias-bg-layer-1, var(--rm-bg));\n border: .5px solid var(--rm-border);\n box-shadow: 0 8px 24px color-mix(in srgb, var(--rm-label) 12%, transparent);\n display: flex; flex-direction: column;\n}\n.rm-menu button {\n display: flex; align-items: center; gap: 8px; height: 32px; padding: 0 10px;\n border: 0; border-radius: 6px; background: transparent; color: var(--rm-label); cursor: pointer; text-align: left;\n}\n.rm-menu button:hover { background: var(--rm-hover); }\n\n/* \u2500\u2500 main: room workspace \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-main { display: flex; flex: 1; min-height: 0; height: 100%; width: 100%; background: var(--rm-bg); }\n.rm-workspace { display: flex; flex: 1; min-width: 0; min-height: 0; }\n.rm-chat { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; }\n.rm-chat-header {\n flex: none; display: flex; align-items: center; gap: 10px; height: 48px;\n padding: 0 16px; border-bottom: .5px solid var(--rm-border);\n}\n.rm-chat-header-title { font-size: 14px; font-weight: 600; }\n.rm-chat-header-sub { font-size: 12px; color: var(--rm-quiet); }\n.rm-messages {\n flex: 1; min-height: 0; overflow: auto; padding: 16px 18px 8px;\n display: flex; flex-direction: column; gap: 2px;\n}\n.rm-day {\n align-self: center; margin: 10px 0 12px; padding: 2px 10px; border-radius: 999px;\n font-size: 11px; color: var(--rm-quiet); background: var(--dsw-alias-button-elevated-fill, var(--rm-panel));\n}\n.rm-msg {\n display: grid; grid-template-columns: 32px 1fr; gap: 0 10px; padding: 4px 6px; border-radius: 8px;\n max-width: 720px;\n}\n.rm-msg:hover { background: color-mix(in srgb, var(--rm-hover) 60%, transparent); }\n.rm-msg-self { margin-left: auto; grid-template-columns: 1fr; max-width: 640px; }\n.rm-msg-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 1px; }\n.rm-msg-author { font-size: 12px; font-weight: 600; color: var(--rm-muted); }\n.rm-msg-time { font-size: 11px; color: var(--rm-quiet); }\n.rm-msg-body { font-size: 13.5px; line-height: 1.55; white-space: pre-wrap; word-break: break-word; }\n.rm-msg-self .rm-msg-body {\n background: var(--dsw-alias-label-primary); color: var(--dsw-alias-label-primary-foreground);\n padding: 8px 12px; border-radius: 12px 12px 4px 12px; width: fit-content; margin-left: auto;\n}\n.rm-msg-event {\n grid-template-columns: 1fr; max-width: 560px; margin: 6px 0;\n padding: 8px 12px; border: .5px solid var(--rm-border); border-radius: 10px; background: var(--rm-panel);\n}\n.rm-mention { color: var(--rm-accent); font-weight: 500; }\n.rm-msg-self .rm-mention { color: inherit; text-decoration: underline; text-underline-offset: 2px; }\n.rm-task-card { display: flex; flex-direction: column; gap: 4px; }\n.rm-task-head { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--rm-muted); }\n.rm-task-title { font-weight: 600; font-size: 13.5px; }\n.rm-composer {\n flex: none; display: flex; align-items: flex-end; gap: 8px; padding: 10px 16px 14px;\n border-top: .5px solid var(--rm-border);\n}\n.rm-composer-box {\n flex: 1; display: flex; align-items: flex-end; gap: 6px; min-height: 44px;\n padding: 8px 10px; border: .5px solid var(--rm-border); border-radius: 12px; background: var(--rm-panel);\n}\n.rm-composer-box:focus-within { border-color: color-mix(in srgb, var(--rm-accent) 50%, var(--rm-border)); }\n.rm-composer-box textarea {\n flex: 1; min-height: 28px; max-height: 120px; border: 0; background: transparent; outline: none;\n resize: none; color: var(--rm-label); line-height: 1.45;\n}\n.rm-composer-box textarea::placeholder { color: var(--rm-quiet); }\n.rm-composer-mode {\n width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;\n border: 0; border-radius: 8px; background: transparent; color: var(--rm-muted); cursor: pointer; flex: none;\n}\n.rm-composer-mode:hover, .rm-composer-mode[aria-pressed="true"] {\n color: var(--rm-accent); background: color-mix(in srgb, var(--rm-accent) 12%, transparent);\n}\n.rm-chat-hint { margin: 48px auto; text-align: center; color: var(--rm-quiet); font-size: 13px; max-width: 360px; line-height: 1.5; }\n\n/* \u2500\u2500 detail column (members / invite / about) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-detail {\n flex: 0 0 280px; width: 280px; display: flex; flex-direction: column; min-height: 0;\n border-left: .5px solid var(--rm-border); background: var(--rm-bg); overflow: auto;\n}\n.rm-detail-section { padding: 14px 14px 8px; border-bottom: .5px solid var(--rm-border); }\n.rm-detail-section:last-child { border-bottom: 0; }\n.rm-detail-h {\n display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600;\n text-transform: uppercase; letter-spacing: .04em; color: var(--rm-quiet); margin-bottom: 8px;\n}\n.rm-member {\n display: flex; align-items: center; gap: 8px; padding: 5px 4px; border-radius: 8px; min-height: 34px;\n}\n.rm-member:hover { background: var(--rm-hover); }\n.rm-member-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }\n.rm-member-actions { display: none; gap: 2px; }\n.rm-member:hover .rm-member-actions, .rm-member:focus-within .rm-member-actions { display: inline-flex; }\n.rm-mini {\n width: 24px; height: 24px; display: inline-flex; align-items: center; justify-content: center;\n border: 0; border-radius: 6px; background: transparent; color: var(--rm-muted); cursor: pointer; font-size: 12px;\n}\n.rm-mini:hover { background: var(--dsw-alias-interactive-bg-active); color: var(--rm-label); }\n.rm-task-row { display: flex; align-items: center; gap: 6px; padding: 4px; font-size: 12.5px; }\n.rm-task-row-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-about { display: grid; grid-template-columns: 88px 1fr; gap: 6px 8px; font-size: 12.5px; margin: 0; }\n.rm-about dt { color: var(--rm-quiet); margin: 0; }\n.rm-about dd { margin: 0; min-width: 0; overflow-wrap: anywhere; display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }\n.rm-mono { font-family: var(--dsw-font-markdown-code-block-font-family, ui-monospace, monospace); font-size: 11.5px; }\n.rm-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }\n.rm-danger { color: var(--dsw-alias-state-error-primary, #e5484d) !important; }\n.rm-note { font-size: 12px; color: var(--rm-quiet); line-height: 1.45; margin: 0 0 8px; }\n\n/* \u2500\u2500 empty / welcome \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-welcome-wrap {\n flex: 1; display: flex; align-items: center; justify-content: center; padding: 32px; background: var(--rm-bg);\n}\n.rm-welcome {\n width: min(420px, 100%); display: flex; flex-direction: column; gap: 10px;\n padding: 20px; border-radius: 14px; border: .5px solid var(--rm-border); background: var(--rm-panel);\n}\n.rm-welcome h1 { margin: 0; font-size: 16px; font-weight: 600; }\n.rm-welcome p { margin: 0; font-size: 13px; color: var(--rm-muted); line-height: 1.5; }\n.rm-welcome-actions { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; }\n.rm-welcome-action {\n display: flex; align-items: flex-start; gap: 10px; width: 100%; padding: 10px 12px;\n border: .5px solid var(--rm-border); border-radius: 10px; background: var(--rm-bg);\n color: var(--rm-label); cursor: pointer; text-align: left;\n}\n.rm-welcome-action:hover { background: var(--rm-hover); }\n.rm-welcome-action b { display: block; font-size: 13px; }\n.rm-welcome-action span { display: block; font-size: 12px; color: var(--rm-quiet); margin-top: 2px; }\n\n/* \u2500\u2500 avatars \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-avatar {\n display: inline-flex; align-items: center; justify-content: center; flex: none;\n font-weight: 600; letter-spacing: .02em; user-select: none;\n}\n.rm-avatar-wrap { position: relative; display: inline-flex; flex: none; }\n\n/* \u2500\u2500 dialogs (inside dsh Modal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-form { display: flex; flex-direction: column; gap: 14px; }\n.rm-field { display: flex; flex-direction: column; gap: 6px; }\n.rm-field-label { font-size: 13px; font-weight: 500; }\n.rm-field-hint { font-size: 12px; color: var(--rm-quiet); }\n.rm-name-row { display: flex; align-items: center; gap: 10px; }\n.rm-name-row > :last-child { flex: 1; }\n.rm-switch-row {\n display: flex; align-items: center; justify-content: space-between; gap: 14px;\n padding: 10px 12px; border-radius: 10px; background: var(--rm-panel);\n}\n.rm-error { color: var(--dsw-alias-state-error-primary, #e5484d); font-size: 12.5px; }\n.rm-invite {\n display: block; padding: 10px 12px; border-radius: 8px; background: var(--rm-panel);\n font-family: var(--dsw-font-markdown-code-block-font-family, ui-monospace, monospace);\n font-size: 12px; word-break: break-all; user-select: all;\n}\n\n/* Dual transport + approvals + agent config */\n.rm-mode-row { display: flex; gap: 8px; }\n.rm-mode-btn {\n flex: 1; padding: 10px 12px; border-radius: 10px; border: 1px solid var(--rm-border, #2a2f3a);\n background: transparent; color: inherit; cursor: pointer; font: inherit;\n}\n.rm-mode-btn.is-on { border-color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 16%, transparent); }\n.rm-lan-browse { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; align-items: center; }\n.rm-lan-peer {\n font-size: 12px; padding: 4px 8px; border-radius: 999px; border: 1px solid var(--rm-border, #2a2f3a);\n background: transparent; color: inherit; cursor: pointer;\n}\n.rm-approvals { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--rm-border, #2a2f3a); background: color-mix(in srgb, #f5a524 12%, transparent); }\n.rm-approval { display: flex; gap: 12px; align-items: center; justify-content: space-between; }\n.rm-approval-body { font-size: 13px; }\n.rm-approval-actions { display: flex; gap: 6px; flex-shrink: 0; }\n.rm-input { width: 100%; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--rm-border, #2a2f3a); background: transparent; color: inherit; font: inherit; }\n\n.rm-ws-bar { display: flex; flex-direction: column; gap: 4px; padding: 8px 12px; border-bottom: 1px solid var(--rm-border, #2a2f3a); }\n.rm-ws-chip { display: inline-flex; align-items: center; gap: 6px; align-self: flex-start; padding: 4px 10px; border-radius: 999px; border: 1px solid var(--rm-border, #2a2f3a); background: transparent; color: inherit; cursor: pointer; font: inherit; font-size: 12.5px; }\n.rm-ws-path { font-size: 11px; color: var(--rm-quiet, #8b93a7); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-room-item.is-active { background: color-mix(in srgb, var(--rm-accent, #5b8cff) 12%, transparent); }\n\n/* Native-aligned room composer (mirrors dsh conversation control row) */\n.rm-composer-card {\n box-sizing: border-box;\n width: 100%;\n max-width: 920px;\n margin: 0 auto;\n border-radius: 16px;\n background: var(--rm-elev, var(--rm-panel, #12151c));\n border: 1px solid var(--rm-border, #2a2f3a);\n box-shadow: 0 1px 2px rgba(0,0,0,.06);\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px 0 6px;\n}\n.rm-composer-grow { position: relative; padding: 0 4px; }\n.rm-composer-grow textarea {\n box-sizing: border-box; width: 100%; min-height: 36px; max-height: 160px;\n resize: none; border: none; outline: none; background: transparent;\n color: inherit; font: inherit; font-size: 14px; line-height: 22px;\n padding: 4px 12px 0 14px;\n}\n.rm-composer-grow textarea:disabled { opacity: .55; cursor: not-allowed; }\n.rm-composer-row {\n display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;\n gap: 10px; min-width: 0; padding: 2px 8px 4px;\n}\n.rm-composer-tools, .rm-composer-modes, .rm-composer-trailing {\n display: flex; align-items: center; min-width: 0; gap: 8px;\n}\n.rm-composer-trailing { flex: none; margin-left: auto; }\n.rm-composer-add {\n width: 28px; height: 28px; border: none; border-radius: 999px;\n background: color-mix(in srgb, var(--rm-fg, #e8eaed) 8%, transparent);\n color: inherit; cursor: pointer; display: grid; place-items: center;\n}\n.rm-composer-add:hover, .rm-composer-add[aria-pressed="true"] {\n background: color-mix(in srgb, var(--rm-accent, #5b8cff) 22%, transparent);\n}\n.rm-composer-select {\n max-width: 220px; height: 28px; border: none; border-radius: 8px;\n background: transparent; color: var(--rm-quiet, #8b93a7);\n font: inherit; font-size: 13px; font-weight: 500; line-height: 20px;\n padding: 0 8px; cursor: pointer; white-space: nowrap;\n}\n.rm-composer-select:hover:not(:disabled) {\n background: color-mix(in srgb, var(--rm-fg, #e8eaed) 8%, transparent);\n}\n.rm-composer-select:disabled { opacity: .5; cursor: default; }\n.rm-composer-model-text { display: inline; }\n.rm-composer-model-icon { display: none; font-size: 10px; }\n.rm-composer-effort {\n margin-left: 6px; font-size: 11px; opacity: .75;\n text-transform: uppercase; letter-spacing: .02em;\n}\n.rm-composer-send {\n width: 34px; height: 34px; border: none; border-radius: 999px;\n background: var(--rm-accent, #5b8cff); color: #fff; cursor: pointer;\n display: grid; place-items: center; transform: translateY(-2px);\n}\n.rm-composer-send:hover:not(:disabled) { filter: brightness(1.08); }\n.rm-composer-send:disabled { opacity: .4; cursor: default; }\n.rm-composer-popwrap { position: relative; }\n.rm-composer-menu {\n position: absolute; bottom: calc(100% + 6px); left: 0; z-index: 40;\n min-width: 200px; max-height: 320px; overflow: auto;\n border: 1px solid var(--rm-border, #2a2f3a); border-radius: 12px;\n background: var(--rm-elev, #12151c); box-shadow: 0 8px 24px rgba(0,0,0,.28);\n padding: 6px; display: flex; flex-direction: column; gap: 2px;\n}\n.rm-composer-menu-wide { min-width: 280px; max-width: 340px; }\n.rm-composer-menu-label {\n font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em;\n color: var(--rm-quiet, #8b93a7); padding: 6px 8px 2px;\n}\n.rm-composer-menu button[role="menuitem"] {\n text-align: left; border: none; background: transparent; color: inherit;\n font: inherit; font-size: 13px; padding: 6px 8px; border-radius: 8px; cursor: pointer;\n}\n.rm-composer-menu button[role="menuitem"]:hover,\n.rm-composer-menu button[role="menuitem"].is-active {\n background: color-mix(in srgb, var(--rm-accent, #5b8cff) 16%, transparent);\n}\n.rm-composer-check {\n display: flex; align-items: center; gap: 8px; font-size: 13px; padding: 4px 8px; cursor: pointer;\n}\n.rm-grant-row {\n display: flex; align-items: center; justify-content: space-between; gap: 8px;\n padding: 2px 8px; font-size: 12.5px;\n}\n.rm-grant-row select {\n font: inherit; font-size: 12px; border-radius: 6px;\n border: 1px solid var(--rm-border, #2a2f3a); background: transparent; color: inherit; padding: 2px 6px;\n}\n.rm-peer-grant-block { border-top: 1px solid var(--rm-border, #2a2f3a); padding-top: 4px; margin-top: 4px; }\n.rm-peer-grant-name { font-size: 12px; font-weight: 600; padding: 4px 8px; overflow: hidden; text-overflow: ellipsis; }\n\n/* Hide legacy tight composer if still referenced */\n.rm-composer { display: none; }\n\n.rm-composer-grow { position: relative; }\n.rm-mention-menu {\n position: absolute; left: 8px; right: 8px; bottom: calc(100% + 6px); z-index: 50;\n max-height: 240px; overflow: auto;\n border: 1px solid var(--rm-border, #2a2f3a); border-radius: 12px;\n background: var(--rm-elev, #12151c); box-shadow: 0 10px 28px rgba(0,0,0,.32);\n padding: 4px; display: flex; flex-direction: column; gap: 2px;\n}\n.rm-mention-item {\n display: flex; align-items: center; gap: 8px; text-align: left;\n border: none; background: transparent; color: inherit; font: inherit;\n padding: 6px 8px; border-radius: 8px; cursor: pointer;\n}\n.rm-mention-item:hover, .rm-mention-item.is-active {\n background: color-mix(in srgb, var(--rm-accent, #5b8cff) 18%, transparent);\n}\n.rm-mention-item-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }\n.rm-mention-item-name { font-size: 13px; font-weight: 600; }\n.rm-mention-item-meta { font-size: 11px; color: var(--rm-quiet, #8b93a7); }\n\n\n/* New Room shortcut under workspace (mirrors New Session affordance) */\n.rm-new-room {\n display: flex; align-items: center; justify-content: center; gap: 6px;\n width: 100%; height: 36px; margin-top: 8px;\n border: .5px solid var(--rm-border); border-radius: 10px;\n background: var(--dsw-alias-button-elevated-fill, var(--rm-panel));\n color: var(--rm-label); cursor: pointer; font-weight: 500; font-size: 13.5px;\n}\n.rm-new-room:hover { background: var(--dsw-alias-button-floating-hover, var(--rm-hover)); }\n.rm-new-room svg { flex: none; }\n\n/* Wide / landscape create + browse modals (overrides default 380px Modal card) */\n.rm-modal-wide {\n width: min(720px, calc(100vw - 48px)) !important;\n max-height: min(640px, calc(100vh - 48px));\n}\n.rm-form-wide {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px 18px;\n align-items: start;\n}\n.rm-form-wide .rm-span-2 { grid-column: 1 / -1; }\n.rm-browse { display: flex; flex-direction: column; gap: 12px; min-height: 280px; max-height: 420px; }\n.rm-browse-search { flex: none; }\n.rm-browse-status { font-size: 11.5px; color: var(--rm-quiet); white-space: nowrap; }\n.rm-browse-list { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 6px; }\n@media (max-width: 640px) {\n .rm-form-wide { grid-template-columns: 1fr; }\n .rm-modal-wide { width: min(420px, calc(100vw - 32px)) !important; }\n}\n\n\n/* \u2500\u2500 panel layout: rooms nav (grouped by native dsh workspace) + content \u2500\u2500 */\n.rm-main { flex-direction: row; }\n.rm-main-body { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; }\n.rm-main-body > .rm-welcome-wrap { flex: 1; }\n.rm-main-body > .rm-workspace { flex: 1; }\n.rm-nav {\n flex: 0 0 248px; width: 248px; display: flex; flex-direction: column; gap: 8px; min-height: 0;\n padding: 10px 8px; border-right: .5px solid var(--rm-border); background: var(--rm-bg);\n}\n.rm-nav-head { display: flex; align-items: center; gap: 4px; padding: 0 4px; }\n.rm-nav-scroll { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 10px; }\n.rm-ws-group { display: flex; flex-direction: column; gap: 2px; }\n.rm-ws-head {\n display: flex; align-items: center; gap: 6px; height: 30px; padding: 0 2px 0 8px;\n font-size: 12.5px; font-weight: 600; color: var(--rm-muted);\n}\n.rm-ws-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-ws-add { width: 24px; height: 24px; }\n.rm-ws-empty { padding: 2px 10px 6px 30px; font-size: 11.5px; }\n.rm-nav .rm-room-item { padding: 6px 8px 6px 14px; }\n.rm-session-mark { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; color: var(--rm-accent, var(--dsw-alias-state-business-primary)); }\n\n/* \u2500\u2500 local multi-agent (0.3) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-dot-busy { background: var(--dsw-alias-state-warning-primary, #f0a020); }\n.rm-agent-tag { display: inline-flex; align-items: center; gap: 3px; margin-left: 6px; padding: 0 6px; border-radius: 999px; font-size: 10.5px; line-height: 17px; color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 12%, transparent); white-space: nowrap; }\n.rm-msg-id { margin-left: 6px; font-size: 11px; color: var(--rm-quiet); font-family: var(--dsw-font-mono, ui-monospace, monospace); }\n.rm-agent-row { display: flex; align-items: center; gap: 8px; padding: 6px 4px; border-radius: 8px; }\n.rm-agent-row:hover { background: var(--rm-hover); }\n.rm-agent-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }\n.rm-agent-name { font-size: 13px; font-weight: 600; color: var(--rm-label); display: flex; align-items: center; }\n.rm-agent-sub { font-size: 11px; color: var(--rm-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.rm-agent-row .rm-member-actions { display: inline-flex !important; opacity: 0.65; }\n.rm-agent-row:hover .rm-member-actions { opacity: 1; }\n.rm-num-row { display: flex; gap: 8px; margin: 4px 0 8px; }\n.rm-num-setting { flex: 1; display: flex; flex-direction: column; gap: 3px; font-size: 11px; color: var(--rm-muted); }\n.rm-num-setting input { width: 100%; box-sizing: border-box; padding: 5px 8px; border: 1px solid var(--rm-border); border-radius: 7px; background: var(--rm-bg); color: var(--rm-label); font: inherit; font-size: 13px; }\n.rm-runs { display: flex; flex-direction: column; gap: 4px; }\n.rm-run { display: grid; grid-template-columns: 22px auto 1fr auto; align-items: center; gap: 6px; padding: 5px 6px; border-radius: 7px; font-size: 12px; border: 1px solid var(--rm-border); }\n.rm-run-running { border-color: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #f0a020) 55%, transparent); background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #f0a020) 8%, transparent); }\n.rm-run-queued, .rm-run-approval { border-style: dashed; }\n.rm-run-done, .rm-run-stopped, .rm-run-failed { opacity: 0.7; }\n.rm-run-pos { font-size: 11px; color: var(--rm-quiet); text-align: center; font-variant-numeric: tabular-nums; }\n.rm-run-who { font-weight: 600; color: var(--rm-label); white-space: nowrap; }\n.rm-run-what { color: var(--rm-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }\n.rm-stop-btn { display: inline-flex; align-items: center; gap: 5px; height: 26px; padding: 0 10px; border-radius: 999px; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-danger-primary, #e5484d) 60%, transparent); background: color-mix(in srgb, var(--dsw-alias-state-danger-primary, #e5484d) 10%, transparent); color: var(--dsw-alias-state-danger-primary, #e5484d); font-size: 12px; cursor: pointer; white-space: nowrap; }\n.rm-stop-btn:hover { background: color-mix(in srgb, var(--dsw-alias-state-danger-primary, #e5484d) 18%, transparent); }\n.rm-badge-local { color: var(--dsw-alias-state-success-primary, #2bb673); }\n.rm-session-agent { color: var(--rm-accent, #5b8cff); }\n.rm-preset-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }\n.rm-preset { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 150px; flex: 1; padding: 8px 10px; border: 1px solid var(--rm-border); border-radius: 10px; background: transparent; color: var(--rm-label); text-align: left; cursor: pointer; font: inherit; font-size: 12px; }\n.rm-preset span { color: var(--rm-muted); font-size: 11px; line-height: 1.35; }\n.rm-preset.is-on { border-color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 12%, transparent); }\n.rm-preset-check { flex-direction: row; align-items: center; gap: 8px; min-width: 120px; flex: 0 1 auto; }\n.rm-local-box { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; border: 1px dashed var(--rm-border); border-radius: 12px; }\n.rm-textarea { width: 100%; box-sizing: border-box; min-height: 84px; resize: vertical; font: inherit; font-size: 13px; padding: 8px 10px; }\n.rm-switch-col { display: flex; flex-direction: column; gap: 6px; }\n.rm-modal-xl { width: min(1180px, 96vw) !important; max-width: 96vw !important; }\n.rm-merge { display: grid; grid-template-columns: 260px 1fr; gap: 14px; min-height: 420px; }\n.rm-merge-list { display: flex; flex-direction: column; gap: 6px; border-right: 1px solid var(--rm-border); padding-right: 12px; }\n.rm-merge-agent { display: flex; align-items: center; gap: 8px; padding: 8px; border: 1px solid transparent; border-radius: 10px; background: transparent; color: var(--rm-label); cursor: pointer; text-align: left; font: inherit; }\n.rm-merge-agent:hover { background: var(--rm-hover); }\n.rm-merge-agent.is-on { border-color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 10%, transparent); }\n.rm-merge-agent-body { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: 12px; }\n.rm-merge-agent-body .rm-mono { font-size: 10.5px; color: var(--rm-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.rm-merge-main { min-width: 0; display: flex; flex-direction: column; gap: 8px; }\n.rm-merge-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; font-size: 13px; }\n.rm-merge-files { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12px; }\n.rm-confirm-text { font-size: 12px; color: var(--rm-label); margin-right: 4px; }\n.rm-diff { margin: 0; max-height: 52vh; overflow: auto; padding: 8px 0; border: 1px solid var(--rm-border); border-radius: 10px; background: var(--rm-panel); font-family: var(--dsw-font-mono, ui-monospace, monospace); font-size: 12px; line-height: 1.5; }\n.rm-diff > div { padding: 0 12px; white-space: pre; }\n.rm-diff-add { background: color-mix(in srgb, #2bb673 16%, transparent); }\n.rm-diff-del { background: color-mix(in srgb, #e5484d 16%, transparent); }\n.rm-diff-hunk { color: var(--rm-accent, #5b8cff); }\n.rm-diff-head, .rm-diff-file { color: var(--rm-muted); font-weight: 600; }\n.rm-diff-addn { color: #2bb673; }\n.rm-diff-deln { color: #e5484d; }\n.rm-ok { padding: 8px 10px; border-radius: 8px; font-size: 12.5px; color: var(--dsw-alias-state-success-primary, #2bb673); background: color-mix(in srgb, #2bb673 10%, transparent); }\n';
40
+ var rooms_default = '/* Collab Rooms UI \u2014 original surface inside the dsh shell. Uses only dsh --dsw-* tokens.\n Independent Rooms surface. Prefix: rm- (rooms). */\n\n.rm-root {\n --rm-accent: var(--dsw-alias-state-business-primary);\n --rm-hover: var(--dsw-alias-interactive-bg-hover);\n --rm-border: var(--dsw-alias-border-l2);\n --rm-bg: var(--dsw-alias-bg-base);\n --rm-panel: var(--dsw-alias-bg-module-platform);\n --rm-label: var(--dsw-alias-label-primary);\n --rm-muted: var(--dsw-alias-label-secondary);\n --rm-quiet: var(--dsw-alias-label-tertiary);\n font: 13px/1.5 var(--dsw-font-family);\n color: var(--rm-label);\n box-sizing: border-box;\n}\n.rm-root *, .rm-root *::before, .rm-root *::after { box-sizing: border-box; }\n.rm-root button, .rm-root input, .rm-root textarea { font: inherit; }\n\n/* \u2500\u2500 sidebar (joined rooms + public search) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-side {\n display: flex; flex-direction: column; height: 100%; min-height: 0;\n padding: 0 8px 8px 0; gap: 8px;\n}\n.rm-side-toolbar {\n display: flex; align-items: center; gap: 6px; flex: none; padding: 4px 0 2px;\n}\n.rm-side-title {\n flex: 1; font-size: 12px; font-weight: 600; letter-spacing: .04em;\n text-transform: uppercase; color: var(--rm-quiet);\n}\n.rm-icon-btn {\n width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;\n border: 0; border-radius: 8px; background: transparent; color: var(--rm-muted); cursor: pointer; padding: 0;\n}\n.rm-icon-btn:hover { background: var(--rm-hover); color: var(--rm-label); }\n.rm-search {\n display: flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px;\n border: .5px solid var(--rm-border); border-radius: 8px; background: var(--rm-panel);\n}\n.rm-search input {\n flex: 1; min-width: 0; border: 0; background: transparent; outline: none; color: var(--rm-label); font-size: 13px;\n}\n.rm-search input::placeholder { color: var(--rm-quiet); }\n.rm-side-scroll { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 12px; }\n.rm-group-label { font-size: 11px; font-weight: 600; color: var(--rm-quiet); padding: 0 4px 4px; text-transform: uppercase; letter-spacing: .03em; }\n.rm-room-list { display: flex; flex-direction: column; gap: 2px; }\n.rm-room-item {\n display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 10px;\n border: 0; border-radius: 10px; background: transparent; color: inherit; cursor: pointer; text-align: left;\n}\n.rm-room-item:hover { background: var(--rm-hover); }\n.rm-room-item[aria-current="true"] { background: var(--rm-hover); }\n.rm-room-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }\n.rm-room-item-name { font-weight: 600; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-room-item-meta { font-size: 11.5px; color: var(--rm-quiet); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-room-item-trail { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }\n.rm-badge {\n display: inline-flex; align-items: center; gap: 3px; height: 18px; padding: 0 6px;\n border-radius: 999px; font-size: 10.5px; font-weight: 500; background: var(--rm-panel); color: var(--rm-muted);\n border: .5px solid var(--rm-border);\n}\n.rm-badge-public { color: var(--rm-accent); border-color: color-mix(in srgb, var(--rm-accent) 35%, transparent); background: color-mix(in srgb, var(--rm-accent) 8%, transparent); }\n.rm-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--rm-quiet); }\n.rm-dot-online { background: var(--dsw-alias-state-success-primary, #2bb673); }\n.rm-dot-connecting { background: var(--dsw-alias-state-warn-primary, #e9a23b); }\n.rm-dot-offline { background: var(--dsw-alias-state-error-primary, #e5484d); }\n.rm-empty-hint { padding: 8px 10px; font-size: 12px; color: var(--rm-quiet); line-height: 1.45; }\n.rm-dir-item {\n display: flex; align-items: flex-start; gap: 10px; padding: 10px; border-radius: 10px;\n border: .5px solid var(--rm-border); background: var(--rm-bg); margin-bottom: 6px;\n}\n.rm-dir-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }\n.rm-dir-tags { display: flex; flex-wrap: wrap; gap: 4px; }\n.rm-tag { font-size: 11px; color: var(--rm-muted); background: var(--rm-hover); border-radius: 4px; padding: 0 5px; }\n.rm-menu {\n position: fixed; z-index: 1000; min-width: 180px; padding: 4px;\n border-radius: 10px; background: var(--dsw-alias-bg-layer-1, var(--rm-bg));\n border: .5px solid var(--rm-border);\n box-shadow: 0 8px 24px color-mix(in srgb, var(--rm-label) 12%, transparent);\n display: flex; flex-direction: column;\n}\n.rm-menu button {\n display: flex; align-items: center; gap: 8px; height: 32px; padding: 0 10px;\n border: 0; border-radius: 6px; background: transparent; color: var(--rm-label); cursor: pointer; text-align: left;\n}\n.rm-menu button:hover { background: var(--rm-hover); }\n\n/* \u2500\u2500 main: room workspace \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-main { display: flex; flex: 1; min-height: 0; height: 100%; width: 100%; background: var(--rm-bg); }\n.rm-workspace { display: flex; flex: 1; min-width: 0; min-height: 0; }\n.rm-chat { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; }\n.rm-chat-header {\n flex: none; display: flex; align-items: center; gap: 10px; height: 48px;\n padding: 0 16px; border-bottom: .5px solid var(--rm-border);\n}\n.rm-chat-header-title { font-size: 14px; font-weight: 600; }\n.rm-chat-header-sub { font-size: 12px; color: var(--rm-quiet); }\n.rm-messages {\n flex: 1; min-height: 0; overflow: auto; padding: 16px 18px 8px;\n display: flex; flex-direction: column; gap: 2px;\n}\n.rm-day {\n align-self: center; margin: 10px 0 12px; padding: 2px 10px; border-radius: 999px;\n font-size: 11px; color: var(--rm-quiet); background: var(--dsw-alias-button-elevated-fill, var(--rm-panel));\n}\n.rm-msg {\n display: grid; grid-template-columns: 32px 1fr; gap: 0 10px; padding: 4px 6px; border-radius: 8px;\n max-width: 720px;\n}\n.rm-msg:hover { background: color-mix(in srgb, var(--rm-hover) 60%, transparent); }\n.rm-msg-self { margin-left: auto; grid-template-columns: 1fr; max-width: 640px; }\n.rm-msg-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 1px; }\n.rm-msg-author { font-size: 12px; font-weight: 600; color: var(--rm-muted); }\n.rm-msg-time { font-size: 11px; color: var(--rm-quiet); }\n.rm-msg-body { font-size: 13.5px; line-height: 1.55; white-space: pre-wrap; word-break: break-word; }\n.rm-msg-self .rm-msg-body {\n background: var(--dsw-alias-label-primary); color: var(--dsw-alias-label-primary-foreground);\n padding: 8px 12px; border-radius: 12px 12px 4px 12px; width: fit-content; margin-left: auto;\n}\n.rm-msg-event {\n grid-template-columns: 1fr; max-width: 560px; margin: 6px 0;\n padding: 8px 12px; border: .5px solid var(--rm-border); border-radius: 10px; background: var(--rm-panel);\n}\n.rm-mention { color: var(--rm-accent); font-weight: 500; }\n.rm-msg-self .rm-mention { color: inherit; text-decoration: underline; text-underline-offset: 2px; }\n.rm-task-card { display: flex; flex-direction: column; gap: 4px; }\n.rm-task-head { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--rm-muted); }\n.rm-task-title { font-weight: 600; font-size: 13.5px; }\n.rm-composer {\n flex: none; display: flex; align-items: flex-end; gap: 8px; padding: 10px 16px 14px;\n border-top: .5px solid var(--rm-border);\n}\n.rm-composer-box {\n flex: 1; display: flex; align-items: flex-end; gap: 6px; min-height: 44px;\n padding: 8px 10px; border: .5px solid var(--rm-border); border-radius: 12px; background: var(--rm-panel);\n}\n.rm-composer-box:focus-within { border-color: color-mix(in srgb, var(--rm-accent) 50%, var(--rm-border)); }\n.rm-composer-box textarea {\n flex: 1; min-height: 28px; max-height: 120px; border: 0; background: transparent; outline: none;\n resize: none; color: var(--rm-label); line-height: 1.45;\n}\n.rm-composer-box textarea::placeholder { color: var(--rm-quiet); }\n.rm-composer-mode {\n width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;\n border: 0; border-radius: 8px; background: transparent; color: var(--rm-muted); cursor: pointer; flex: none;\n}\n.rm-composer-mode:hover, .rm-composer-mode[aria-pressed="true"] {\n color: var(--rm-accent); background: color-mix(in srgb, var(--rm-accent) 12%, transparent);\n}\n.rm-chat-hint { margin: 48px auto; text-align: center; color: var(--rm-quiet); font-size: 13px; max-width: 360px; line-height: 1.5; }\n\n/* \u2500\u2500 detail column (members / invite / about) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-detail {\n flex: 0 0 280px; width: 280px; display: flex; flex-direction: column; min-height: 0;\n border-left: .5px solid var(--rm-border); background: var(--rm-bg); overflow: auto;\n}\n.rm-detail-section { padding: 14px 14px 8px; border-bottom: .5px solid var(--rm-border); }\n.rm-detail-section:last-child { border-bottom: 0; }\n.rm-detail-h {\n display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600;\n text-transform: uppercase; letter-spacing: .04em; color: var(--rm-quiet); margin-bottom: 8px;\n}\n.rm-member {\n display: flex; align-items: center; gap: 8px; padding: 5px 4px; border-radius: 8px; min-height: 34px;\n}\n.rm-member:hover { background: var(--rm-hover); }\n.rm-member-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }\n.rm-member-actions { display: none; gap: 2px; }\n.rm-member:hover .rm-member-actions, .rm-member:focus-within .rm-member-actions { display: inline-flex; }\n.rm-mini {\n width: 24px; height: 24px; display: inline-flex; align-items: center; justify-content: center;\n border: 0; border-radius: 6px; background: transparent; color: var(--rm-muted); cursor: pointer; font-size: 12px;\n}\n.rm-mini:hover { background: var(--dsw-alias-interactive-bg-active); color: var(--rm-label); }\n.rm-task-row { display: flex; align-items: center; gap: 6px; padding: 4px; font-size: 12.5px; }\n.rm-task-row-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-about { display: grid; grid-template-columns: 88px 1fr; gap: 6px 8px; font-size: 12.5px; margin: 0; }\n.rm-about dt { color: var(--rm-quiet); margin: 0; }\n.rm-about dd { margin: 0; min-width: 0; overflow-wrap: anywhere; display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }\n.rm-mono { font-family: var(--dsw-font-markdown-code-block-font-family, ui-monospace, monospace); font-size: 11.5px; }\n.rm-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }\n.rm-danger { color: var(--dsw-alias-state-error-primary, #e5484d) !important; }\n.rm-note { font-size: 12px; color: var(--rm-quiet); line-height: 1.45; margin: 0 0 8px; }\n\n/* \u2500\u2500 empty / welcome \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-welcome-wrap {\n flex: 1; display: flex; align-items: center; justify-content: center; padding: 32px; background: var(--rm-bg);\n}\n.rm-welcome {\n width: min(420px, 100%); display: flex; flex-direction: column; gap: 10px;\n padding: 20px; border-radius: 14px; border: .5px solid var(--rm-border); background: var(--rm-panel);\n}\n.rm-welcome h1 { margin: 0; font-size: 16px; font-weight: 600; }\n.rm-welcome p { margin: 0; font-size: 13px; color: var(--rm-muted); line-height: 1.5; }\n.rm-welcome-actions { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; }\n.rm-welcome-action {\n display: flex; align-items: flex-start; gap: 10px; width: 100%; padding: 10px 12px;\n border: .5px solid var(--rm-border); border-radius: 10px; background: var(--rm-bg);\n color: var(--rm-label); cursor: pointer; text-align: left;\n}\n.rm-welcome-action:hover { background: var(--rm-hover); }\n.rm-welcome-action b { display: block; font-size: 13px; }\n.rm-welcome-action span { display: block; font-size: 12px; color: var(--rm-quiet); margin-top: 2px; }\n\n/* \u2500\u2500 avatars \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-avatar {\n display: inline-flex; align-items: center; justify-content: center; flex: none;\n font-weight: 600; letter-spacing: .02em; user-select: none;\n}\n.rm-avatar-wrap { position: relative; display: inline-flex; flex: none; }\n\n/* \u2500\u2500 dialogs (inside dsh Modal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-form { display: flex; flex-direction: column; gap: 14px; }\n.rm-field { display: flex; flex-direction: column; gap: 6px; }\n.rm-field-label { font-size: 13px; font-weight: 500; }\n.rm-field-hint { font-size: 12px; color: var(--rm-quiet); }\n.rm-name-row { display: flex; align-items: center; gap: 10px; }\n.rm-name-row > :last-child { flex: 1; }\n.rm-switch-row {\n display: flex; align-items: center; justify-content: space-between; gap: 14px;\n padding: 10px 12px; border-radius: 10px; background: var(--rm-panel);\n}\n.rm-error { color: var(--dsw-alias-state-error-primary, #e5484d); font-size: 12.5px; }\n.rm-invite {\n display: block; padding: 10px 12px; border-radius: 8px; background: var(--rm-panel);\n font-family: var(--dsw-font-markdown-code-block-font-family, ui-monospace, monospace);\n font-size: 12px; word-break: break-all; user-select: all;\n}\n\n/* Dual transport + approvals + agent config */\n.rm-mode-row { display: flex; gap: 8px; }\n.rm-mode-btn {\n flex: 1; padding: 10px 12px; border-radius: 10px; border: 1px solid var(--rm-border, #2a2f3a);\n background: transparent; color: inherit; cursor: pointer; font: inherit;\n}\n.rm-mode-btn.is-on { border-color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 16%, transparent); }\n.rm-lan-browse { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; align-items: center; }\n.rm-lan-peer {\n font-size: 12px; padding: 4px 8px; border-radius: 999px; border: 1px solid var(--rm-border, #2a2f3a);\n background: transparent; color: inherit; cursor: pointer;\n}\n.rm-approvals { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--rm-border, #2a2f3a); background: color-mix(in srgb, #f5a524 12%, transparent); }\n.rm-approval { display: flex; gap: 12px; align-items: center; justify-content: space-between; }\n.rm-approval-body { font-size: 13px; }\n.rm-approval-actions { display: flex; gap: 6px; flex-shrink: 0; }\n.rm-input { width: 100%; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--rm-border, #2a2f3a); background: transparent; color: inherit; font: inherit; }\n\n.rm-ws-bar { display: flex; flex-direction: column; gap: 4px; padding: 8px 12px; border-bottom: 1px solid var(--rm-border, #2a2f3a); }\n.rm-ws-chip { display: inline-flex; align-items: center; gap: 6px; align-self: flex-start; padding: 4px 10px; border-radius: 999px; border: 1px solid var(--rm-border, #2a2f3a); background: transparent; color: inherit; cursor: pointer; font: inherit; font-size: 12.5px; }\n.rm-ws-path { font-size: 11px; color: var(--rm-quiet, #8b93a7); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-room-item.is-active { background: color-mix(in srgb, var(--rm-accent, #5b8cff) 12%, transparent); }\n\n/* Native-aligned room composer (mirrors dsh conversation control row) */\n.rm-composer-card {\n box-sizing: border-box;\n width: 100%;\n max-width: 920px;\n margin: 0 auto;\n border-radius: 16px;\n background: var(--rm-elev, var(--rm-panel, #12151c));\n border: 1px solid var(--rm-border, #2a2f3a);\n box-shadow: 0 1px 2px rgba(0,0,0,.06);\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px 0 6px;\n}\n.rm-composer-grow { position: relative; padding: 0 4px; }\n.rm-composer-grow textarea {\n box-sizing: border-box; width: 100%; min-height: 36px; max-height: 160px;\n resize: none; border: none; outline: none; background: transparent;\n color: inherit; font: inherit; font-size: 14px; line-height: 22px;\n padding: 4px 12px 0 14px;\n}\n.rm-composer-grow textarea:disabled { opacity: .55; cursor: not-allowed; }\n.rm-composer-row {\n display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;\n gap: 10px; min-width: 0; padding: 2px 8px 4px;\n}\n.rm-composer-tools, .rm-composer-modes, .rm-composer-trailing {\n display: flex; align-items: center; min-width: 0; gap: 8px;\n}\n.rm-composer-trailing { flex: none; margin-left: auto; }\n.rm-composer-add {\n width: 28px; height: 28px; border: none; border-radius: 999px;\n background: color-mix(in srgb, var(--rm-fg, #e8eaed) 8%, transparent);\n color: inherit; cursor: pointer; display: grid; place-items: center;\n}\n.rm-composer-add:hover, .rm-composer-add[aria-pressed="true"] {\n background: color-mix(in srgb, var(--rm-accent, #5b8cff) 22%, transparent);\n}\n.rm-composer-select {\n max-width: 220px; height: 28px; border: none; border-radius: 8px;\n background: transparent; color: var(--rm-quiet, #8b93a7);\n font: inherit; font-size: 13px; font-weight: 500; line-height: 20px;\n padding: 0 8px; cursor: pointer; white-space: nowrap;\n}\n.rm-composer-select:hover:not(:disabled) {\n background: color-mix(in srgb, var(--rm-fg, #e8eaed) 8%, transparent);\n}\n.rm-composer-select:disabled { opacity: .5; cursor: default; }\n.rm-composer-model-text { display: inline; }\n.rm-composer-model-icon { display: none; font-size: 10px; }\n.rm-composer-effort {\n margin-left: 6px; font-size: 11px; opacity: .75;\n text-transform: uppercase; letter-spacing: .02em;\n}\n.rm-composer-send {\n width: 34px; height: 34px; border: none; border-radius: 999px;\n background: var(--rm-accent, #5b8cff); color: #fff; cursor: pointer;\n display: grid; place-items: center; transform: translateY(-2px);\n}\n.rm-composer-send:hover:not(:disabled) { filter: brightness(1.08); }\n.rm-composer-send:disabled { opacity: .4; cursor: default; }\n.rm-composer-popwrap { position: relative; }\n.rm-composer-menu {\n position: absolute; bottom: calc(100% + 6px); left: 0; z-index: 40;\n min-width: 200px; max-height: 320px; overflow: auto;\n border: 1px solid var(--rm-border, #2a2f3a); border-radius: 12px;\n background: var(--rm-elev, #12151c); box-shadow: 0 8px 24px rgba(0,0,0,.28);\n padding: 6px; display: flex; flex-direction: column; gap: 2px;\n}\n.rm-composer-menu-wide { min-width: 280px; max-width: 340px; }\n.rm-composer-menu-label {\n font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em;\n color: var(--rm-quiet, #8b93a7); padding: 6px 8px 2px;\n}\n.rm-composer-menu button[role="menuitem"] {\n text-align: left; border: none; background: transparent; color: inherit;\n font: inherit; font-size: 13px; padding: 6px 8px; border-radius: 8px; cursor: pointer;\n}\n.rm-composer-menu button[role="menuitem"]:hover,\n.rm-composer-menu button[role="menuitem"].is-active {\n background: color-mix(in srgb, var(--rm-accent, #5b8cff) 16%, transparent);\n}\n.rm-composer-check {\n display: flex; align-items: center; gap: 8px; font-size: 13px; padding: 4px 8px; cursor: pointer;\n}\n.rm-grant-row {\n display: flex; align-items: center; justify-content: space-between; gap: 8px;\n padding: 2px 8px; font-size: 12.5px;\n}\n.rm-grant-row select {\n font: inherit; font-size: 12px; border-radius: 6px;\n border: 1px solid var(--rm-border, #2a2f3a); background: transparent; color: inherit; padding: 2px 6px;\n}\n.rm-peer-grant-block { border-top: 1px solid var(--rm-border, #2a2f3a); padding-top: 4px; margin-top: 4px; }\n.rm-peer-grant-name { font-size: 12px; font-weight: 600; padding: 4px 8px; overflow: hidden; text-overflow: ellipsis; }\n\n/* Hide legacy tight composer if still referenced */\n.rm-composer { display: none; }\n\n.rm-composer-grow { position: relative; }\n.rm-mention-menu {\n position: absolute; left: 8px; right: 8px; bottom: calc(100% + 6px); z-index: 50;\n max-height: 240px; overflow: auto;\n border: 1px solid var(--rm-border, #2a2f3a); border-radius: 12px;\n background: var(--rm-elev, #12151c); box-shadow: 0 10px 28px rgba(0,0,0,.32);\n padding: 4px; display: flex; flex-direction: column; gap: 2px;\n}\n.rm-mention-item {\n display: flex; align-items: center; gap: 8px; text-align: left;\n border: none; background: transparent; color: inherit; font: inherit;\n padding: 6px 8px; border-radius: 8px; cursor: pointer;\n}\n.rm-mention-item:hover, .rm-mention-item.is-active {\n background: color-mix(in srgb, var(--rm-accent, #5b8cff) 18%, transparent);\n}\n.rm-mention-item-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }\n.rm-mention-item-name { font-size: 13px; font-weight: 600; }\n.rm-mention-item-meta { font-size: 11px; color: var(--rm-quiet, #8b93a7); }\n\n\n/* New Room shortcut under workspace (mirrors New Session affordance) */\n.rm-new-room {\n display: flex; align-items: center; justify-content: center; gap: 6px;\n width: 100%; height: 36px; margin-top: 8px;\n border: .5px solid var(--rm-border); border-radius: 10px;\n background: var(--dsw-alias-button-elevated-fill, var(--rm-panel));\n color: var(--rm-label); cursor: pointer; font-weight: 500; font-size: 13.5px;\n}\n.rm-new-room:hover { background: var(--dsw-alias-button-floating-hover, var(--rm-hover)); }\n.rm-new-room svg { flex: none; }\n\n/* Wide / landscape create + browse modals (overrides default 380px Modal card) */\n.rm-modal-wide {\n width: min(720px, calc(100vw - 48px)) !important;\n max-height: min(640px, calc(100vh - 48px));\n}\n.rm-form-wide {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px 18px;\n align-items: start;\n}\n.rm-form-wide .rm-span-2 { grid-column: 1 / -1; }\n.rm-browse { display: flex; flex-direction: column; gap: 12px; min-height: 280px; max-height: 420px; }\n.rm-browse-search { flex: none; }\n.rm-browse-status { font-size: 11.5px; color: var(--rm-quiet); white-space: nowrap; }\n.rm-browse-list { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 6px; }\n@media (max-width: 640px) {\n .rm-form-wide { grid-template-columns: 1fr; }\n .rm-modal-wide { width: min(420px, calc(100vw - 32px)) !important; }\n}\n\n\n/* \u2500\u2500 panel layout: rooms nav (grouped by native dsh workspace) + content \u2500\u2500 */\n.rm-main { flex-direction: row; }\n.rm-main-body { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; }\n.rm-main-body > .rm-welcome-wrap { flex: 1; }\n.rm-main-body > .rm-workspace { flex: 1; }\n.rm-nav {\n flex: 0 0 248px; width: 248px; display: flex; flex-direction: column; gap: 8px; min-height: 0;\n padding: 10px 8px; border-right: .5px solid var(--rm-border); background: var(--rm-bg);\n}\n.rm-nav-head { display: flex; align-items: center; gap: 4px; padding: 0 4px; }\n.rm-nav-scroll { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 10px; }\n.rm-ws-group { display: flex; flex-direction: column; gap: 2px; }\n.rm-ws-head {\n display: flex; align-items: center; gap: 6px; height: 30px; padding: 0 2px 0 8px;\n font-size: 12.5px; font-weight: 600; color: var(--rm-muted);\n}\n.rm-ws-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-ws-add { width: 24px; height: 24px; }\n.rm-ws-empty { padding: 2px 10px 6px 30px; font-size: 11.5px; }\n.rm-nav .rm-room-item { padding: 6px 8px 6px 14px; }\n.rm-session-mark { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; color: var(--rm-accent, var(--dsw-alias-state-business-primary)); }\n\n/* \u2500\u2500 local multi-agent (0.3) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-dot-busy { background: var(--dsw-alias-state-warning-primary, #f0a020); }\n.rm-agent-tag { display: inline-flex; align-items: center; gap: 3px; margin-left: 6px; padding: 0 6px; border-radius: 999px; font-size: 10.5px; line-height: 17px; color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 12%, transparent); white-space: nowrap; }\n.rm-msg-id { margin-left: 6px; font-size: 11px; color: var(--rm-quiet); font-family: var(--dsw-font-mono, ui-monospace, monospace); }\n.rm-agent-row { display: flex; align-items: center; gap: 8px; padding: 6px 4px; border-radius: 8px; }\n.rm-agent-row:hover { background: var(--rm-hover); }\n.rm-agent-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }\n.rm-agent-name { font-size: 13px; font-weight: 600; color: var(--rm-label); display: flex; align-items: center; }\n.rm-agent-sub { font-size: 11px; color: var(--rm-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.rm-agent-row .rm-member-actions { display: inline-flex !important; opacity: 0.65; }\n.rm-agent-row:hover .rm-member-actions { opacity: 1; }\n.rm-num-row { display: flex; gap: 8px; margin: 4px 0 8px; }\n.rm-num-setting { flex: 1; display: flex; flex-direction: column; gap: 3px; font-size: 11px; color: var(--rm-muted); }\n.rm-num-setting input { width: 100%; box-sizing: border-box; padding: 5px 8px; border: 1px solid var(--rm-border); border-radius: 7px; background: var(--rm-bg); color: var(--rm-label); font: inherit; font-size: 13px; }\n.rm-runs { display: flex; flex-direction: column; gap: 4px; }\n.rm-run { display: grid; grid-template-columns: 22px auto 1fr auto; align-items: center; gap: 6px; padding: 5px 6px; border-radius: 7px; font-size: 12px; border: 1px solid var(--rm-border); }\n.rm-run-running { border-color: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #f0a020) 55%, transparent); background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #f0a020) 8%, transparent); }\n.rm-run-queued, .rm-run-approval { border-style: dashed; }\n.rm-run-done, .rm-run-stopped, .rm-run-failed { opacity: 0.7; }\n.rm-run-pos { font-size: 11px; color: var(--rm-quiet); text-align: center; font-variant-numeric: tabular-nums; }\n.rm-run-who { font-weight: 600; color: var(--rm-label); white-space: nowrap; }\n.rm-run-what { color: var(--rm-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }\n.rm-stop-btn { display: inline-flex; align-items: center; gap: 5px; height: 26px; padding: 0 10px; border-radius: 999px; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-danger-primary, #e5484d) 60%, transparent); background: color-mix(in srgb, var(--dsw-alias-state-danger-primary, #e5484d) 10%, transparent); color: var(--dsw-alias-state-danger-primary, #e5484d); font-size: 12px; cursor: pointer; white-space: nowrap; }\n.rm-stop-btn:hover { background: color-mix(in srgb, var(--dsw-alias-state-danger-primary, #e5484d) 18%, transparent); }\n.rm-badge-local { color: var(--dsw-alias-state-success-primary, #2bb673); }\n.rm-session-agent { color: var(--rm-accent, #5b8cff); }\n.rm-preset-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }\n.rm-preset { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 150px; flex: 1; padding: 8px 10px; border: 1px solid var(--rm-border); border-radius: 10px; background: transparent; color: var(--rm-label); text-align: left; cursor: pointer; font: inherit; font-size: 12px; }\n.rm-preset span { color: var(--rm-muted); font-size: 11px; line-height: 1.35; }\n.rm-preset.is-on { border-color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 12%, transparent); }\n.rm-preset-check { flex-direction: row; align-items: center; gap: 8px; min-width: 120px; flex: 0 1 auto; }\n.rm-local-box { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; border: 1px dashed var(--rm-border); border-radius: 12px; }\n.rm-textarea { width: 100%; box-sizing: border-box; min-height: 84px; resize: vertical; font: inherit; font-size: 13px; padding: 8px 10px; }\n.rm-switch-col { display: flex; flex-direction: column; gap: 6px; }\n.rm-modal-xl { width: min(1180px, 96vw) !important; max-width: 96vw !important; }\n.rm-merge { display: grid; grid-template-columns: 260px 1fr; gap: 14px; min-height: 420px; }\n.rm-merge-list { display: flex; flex-direction: column; gap: 6px; border-right: 1px solid var(--rm-border); padding-right: 12px; }\n.rm-merge-agent { display: flex; align-items: center; gap: 8px; padding: 8px; border: 1px solid transparent; border-radius: 10px; background: transparent; color: var(--rm-label); cursor: pointer; text-align: left; font: inherit; }\n.rm-merge-agent:hover { background: var(--rm-hover); }\n.rm-merge-agent.is-on { border-color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 10%, transparent); }\n.rm-merge-agent-body { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: 12px; }\n.rm-merge-agent-body .rm-mono { font-size: 10.5px; color: var(--rm-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.rm-merge-main { min-width: 0; display: flex; flex-direction: column; gap: 8px; }\n.rm-merge-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; font-size: 13px; }\n.rm-merge-files { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12px; }\n.rm-confirm-text { font-size: 12px; color: var(--rm-label); margin-right: 4px; }\n.rm-diff { margin: 0; max-height: 52vh; overflow: auto; padding: 8px 0; border: 1px solid var(--rm-border); border-radius: 10px; background: var(--rm-panel); font-family: var(--dsw-font-mono, ui-monospace, monospace); font-size: 12px; line-height: 1.5; }\n.rm-diff > div { padding: 0 12px; white-space: pre; }\n.rm-diff-add { background: color-mix(in srgb, #2bb673 16%, transparent); }\n.rm-diff-del { background: color-mix(in srgb, #e5484d 16%, transparent); }\n.rm-diff-hunk { color: var(--rm-accent, #5b8cff); }\n.rm-diff-head, .rm-diff-file { color: var(--rm-muted); font-weight: 600; }\n.rm-diff-addn { color: #2bb673; }\n.rm-diff-deln { color: #e5484d; }\n.rm-ok { padding: 8px 10px; border-radius: 8px; font-size: 12.5px; color: var(--dsw-alias-state-success-primary, #2bb673); background: color-mix(in srgb, #2bb673 10%, transparent); }\n\n/* \u2500\u2500 create-room dialog (0.3.1): wide, scrollable, tabbed \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-modal-scrollable {\n width: min(920px, calc(100vw - 48px)) !important;\n max-width: 96vw !important;\n /* Bound height so the flex child (.rm-modal-scroll) can scroll instead of clipping. */\n height: min(720px, 100%) !important;\n max-height: 100% !important;\n}\n.rm-modal-create { width: min(960px, calc(100vw - 48px)) !important; }\n.rm-modal-scroll {\n flex: 1 1 auto;\n min-height: 0;\n overflow-x: hidden;\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n.rm-create { display: flex; flex-direction: column; gap: 12px; }\n.rm-tabs {\n display: flex; gap: 4px; padding: 2px; border-radius: 10px;\n background: color-mix(in srgb, var(--rm-border) 55%, transparent);\n flex-wrap: wrap;\n}\n.rm-tab {\n flex: 1 1 auto; min-width: 88px; height: 32px; padding: 0 12px; border: 0; border-radius: 8px;\n background: transparent; color: var(--rm-muted); font: inherit; font-size: 13px; font-weight: 560;\n cursor: pointer;\n}\n.rm-tab.is-on { background: var(--rm-panel, var(--dsw-alias-bg-layer-2)); color: var(--rm-label); box-shadow: 0 0 0 1px var(--rm-border); }\n.rm-create-pane { min-height: 280px; }\n.rm-mode-wrap { flex-wrap: wrap; }\n.rm-preset-sub { display: block; color: var(--rm-muted); font-size: 11px; font-weight: 400; line-height: 1.35; margin-top: 1px; }\n.rm-create-custom {\n margin-top: 14px; padding: 12px; border: 1px dashed var(--rm-border); border-radius: 12px;\n display: flex; flex-direction: column; gap: 10px;\n}\n.rm-create-custom-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }\n.rm-draft-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }\n.rm-draft-item {\n display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 8px;\n border: 1px solid var(--rm-border); background: var(--rm-panel);\n}\n.rm-draft-main { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: 12.5px; }\n.rm-draft-main span { color: var(--rm-muted); font-size: 11px; }\n.rm-draft-form { margin-top: 4px; padding-top: 10px; border-top: 1px dashed var(--rm-border); }\n.rm-linkish { background: none; border: 0; color: var(--rm-accent, #5b8cff); cursor: pointer; font: inherit; font-size: inherit; padding: 0; text-decoration: underline; }\n@media (max-width: 720px) {\n .rm-modal-create, .rm-modal-scrollable { width: min(100vw - 24px, 520px) !important; }\n}\n';
41
41
 
42
42
  // src/client/store.js
43
43
  var API = "/api/collab";
44
44
  async function call(path, init) {
45
- const res = await fetch(API + path, { credentials: "same-origin", ...init, headers: { ...init && init.body ? { "content-type": "application/json" } : {}, ...init && init.headers || {} } });
46
- const body = await res.json().catch(() => ({}));
47
- if (!res.ok) throw new Error(body.error || `${res.status} ${res.statusText}`);
45
+ let res;
46
+ try {
47
+ res = await fetch(API + path, { credentials: "same-origin", ...init, headers: { ...init && init.body ? { "content-type": "application/json" } : {}, ...init && init.headers || {} } });
48
+ } catch (e) {
49
+ const msg = e && e.name === "AbortError" ? "Request timed out or was cancelled" : e && e.message || "network error";
50
+ throw new Error(msg);
51
+ }
52
+ const text = await res.text();
53
+ let body = {};
54
+ try {
55
+ body = text ? JSON.parse(text) : {};
56
+ } catch {
57
+ body = { error: text.slice(0, 300) || res.statusText };
58
+ }
59
+ if (!res.ok) {
60
+ const detail = body.error || body.message || (typeof body.raw === "string" ? body.raw : "") || `${res.status} ${res.statusText}`;
61
+ throw new Error(detail);
62
+ }
48
63
  return body;
49
64
  }
50
- var post = (path, body) => call(path, { method: "POST", body: JSON.stringify(body || {}) });
65
+ var post = (path, body, init) => call(path, { method: "POST", body: JSON.stringify(body || {}), ...init || {} });
51
66
  function createRoomsStore() {
52
67
  let snap = {
53
68
  self: null,
@@ -152,15 +167,22 @@ function createRoomsStore() {
152
167
  clearTimeout(searchTimer);
153
168
  searchTimer = setTimeout(() => void runSearch(query), 300);
154
169
  },
155
- async create(form) {
156
- const r = await post("/rooms", { ...form, workspaceId: form.workspacePath ? void 0 : form.workspaceId || snap.activeWorkspaceId });
170
+ async create(form, opts) {
171
+ const ac = opts && opts.signal ? null : new AbortController();
172
+ const signal = opts && opts.signal || ac.signal;
173
+ const timer = ac ? setTimeout(() => ac.abort(), opts && opts.timeoutMs || 3e4) : null;
157
174
  try {
158
- api.onRoomOpened && api.onRoomOpened();
159
- } catch {
175
+ const r = await post("/rooms", { ...form, workspaceId: form.workspacePath ? void 0 : form.workspaceId || snap.activeWorkspaceId }, { signal });
176
+ try {
177
+ api.onRoomOpened && api.onRoomOpened();
178
+ } catch {
179
+ }
180
+ set({ selected: r.roomId, dialog: { kind: "invite", roomId: r.roomId, name: r.name, invite: r.invite, public: r.public, listed: r.listed } });
181
+ void loadMessages(r.roomId);
182
+ return r;
183
+ } finally {
184
+ if (timer) clearTimeout(timer);
160
185
  }
161
- set({ selected: r.roomId, dialog: { kind: "invite", roomId: r.roomId, name: r.name, invite: r.invite, public: r.public, listed: r.listed } });
162
- void loadMessages(r.roomId);
163
- return r;
164
186
  },
165
187
  async join(invite, info) {
166
188
  const r = await post("/join", { invite, ...info && info.workspacePath ? {} : { workspaceId: snap.activeWorkspaceId }, ...info || {} });
@@ -979,8 +1001,8 @@ function LocalAgentsSection({ room, store, mention }) {
979
1001
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mini", title: `Edit ${ag.name}`, "aria-label": `Edit ${ag.name}`, onClick: () => a.openDialog({ kind: "agent", roomId: room.roomId, agentId: ag.agentId }), children: "\u270E" })
980
1002
  ] })
981
1003
  ] }, ag.agentId)),
982
- !local.agents.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "rm-note", children: "Host several agents from this dsh as separate members \u2014 each with its own identity, session and scope." }) : null,
983
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-actions", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlusIcon, {}), onClick: () => a.openDialog({ kind: "agent", roomId: room.roomId }), children: "Add local agent" }) })
1004
+ !local.agents.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "rm-note", children: "Add a custom agent (free-form name, prompt, model, scope) or start from a preset. Each gets its own identity, session and scope." }) : null,
1005
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-actions", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlusIcon, {}), onClick: () => a.openDialog({ kind: "agent", roomId: room.roomId }), children: "Add agent" }) })
984
1006
  ] });
985
1007
  }
986
1008
  function NumberSetting({ label, value, min, max, onSave, hint }) {
@@ -1095,14 +1117,16 @@ function AgentDialog({ store, d }) {
1095
1117
  const room = (s.rooms || []).find((r) => r.roomId === d.roomId);
1096
1118
  const existing = room && room.local ? room.local.agents.find((x) => x.agentId === d.agentId) : null;
1097
1119
  const [presets, setPresets] = (0, import_react.useState)([]);
1098
- const [f, setF] = (0, import_react.useState)(() => existing ? { name: existing.name, persona: existing.persona || "", systemPrompt: existing.systemPrompt || "", model: existing.model || "", reasoningEffort: existing.reasoningEffort || "medium", scope: existing.scope, approvalRequired: !!existing.approvalRequired, moderator: !!existing.moderator } : { preset: "", name: "", persona: "", systemPrompt: "", model: "", reasoningEffort: "medium", scope: "read", approvalRequired: false, moderator: false });
1120
+ const blank = () => ({ preset: "", name: "", persona: "", systemPrompt: "", model: "", reasoningEffort: "medium", scope: "read", approvalRequired: false, moderator: false });
1121
+ const [f, setF] = (0, import_react.useState)(() => existing ? { preset: "", name: existing.name, persona: existing.persona || "", systemPrompt: existing.systemPrompt || "", model: existing.model || "", reasoningEffort: existing.reasoningEffort || "medium", scope: existing.scope, approvalRequired: !!existing.approvalRequired, moderator: !!existing.moderator } : blank());
1099
1122
  const [err, setErr] = (0, import_react.useState)(null);
1100
1123
  const [busy, setBusy] = (0, import_react.useState)(false);
1101
1124
  (0, import_react.useEffect)(() => {
1102
1125
  a.presets().then(setPresets).catch(() => {
1103
1126
  });
1104
1127
  }, []);
1105
- const pick = (p) => setF({ ...f, preset: p.key, name: p.name, persona: p.persona, systemPrompt: p.systemPrompt, scope: p.scope, moderator: !!p.moderator, reasoningEffort: p.reasoningEffort || "medium" });
1128
+ const pick = (p) => setF({ ...f, preset: p.key, name: p.name, persona: p.persona || "", systemPrompt: p.systemPrompt || "", scope: p.scope, moderator: !!p.moderator, reasoningEffort: p.reasoningEffort || "medium" });
1129
+ const clearPreset = () => setF({ ...f, preset: "" });
1106
1130
  const submit = async () => {
1107
1131
  if (!f.name.trim()) {
1108
1132
  setErr("Name required");
@@ -1111,15 +1135,16 @@ function AgentDialog({ store, d }) {
1111
1135
  setBusy(true);
1112
1136
  setErr(null);
1113
1137
  try {
1114
- const body = { name: f.name, persona: f.persona, systemPrompt: f.systemPrompt, model: f.model, reasoningEffort: f.reasoningEffort, scope: f.scope, approvalRequired: f.approvalRequired, moderator: f.moderator, preset: f.preset || void 0 };
1138
+ const body = { name: f.name.trim(), persona: f.persona, systemPrompt: f.systemPrompt, model: f.model || void 0, reasoningEffort: f.reasoningEffort, scope: f.scope, approvalRequired: f.approvalRequired, moderator: f.moderator };
1115
1139
  if (existing) await a.updateAgent(d.roomId, existing.agentId, body);
1116
1140
  else {
1117
- const r = await a.addAgent(d.roomId, body);
1118
- a.toast(`${r.name} joined as @${r.agentId}`);
1141
+ const r = await a.addAgent(d.roomId, f.preset ? { ...body, preset: f.preset } : body);
1142
+ a.toast(`${r.name} added as @${r.agentId} (joining in background)`);
1119
1143
  }
1120
1144
  a.closeDialog();
1121
1145
  } catch (e) {
1122
1146
  setErr(e.message);
1147
+ } finally {
1123
1148
  setBusy(false);
1124
1149
  }
1125
1150
  };
@@ -1141,8 +1166,9 @@ function AgentDialog({ store, d }) {
1141
1166
  onClose: a.closeDialog,
1142
1167
  title: existing ? `Edit ${existing.name}` : "Add local agent",
1143
1168
  closeLabel: "Close",
1144
- className: "rm-modal-wide",
1145
- description: existing ? `Member @${existing.agentId} \xB7 own identity and dsh session in this room's workspace.` : "Runs on this dsh as a separate room member: own keypair, own session, own scope. Remote peers see it as a member.",
1169
+ className: "rm-modal-wide rm-modal-scrollable",
1170
+ contentClassName: "rm-modal-scroll",
1171
+ description: existing ? `Member @${existing.agentId} \xB7 own identity and dsh session in this room's workspace.` : "Free-form agent: own name, persona, prompt, model, scope. Presets only fill the form \u2014 you can edit every field. Remote peers see it as a separate member.",
1146
1172
  footer: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1147
1173
  existing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "ghost", className: "rm-danger", disabled: busy, onClick: remove, children: "Remove" }) : null,
1148
1174
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1 } }),
@@ -1151,15 +1177,26 @@ function AgentDialog({ store, d }) {
1151
1177
  ] }),
1152
1178
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-root rm-form rm-form-wide", "data-rm-agent-form": "", children: [
1153
1179
  !existing ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-span-2", children: [
1154
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Preset" }),
1155
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-preset-row", children: presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "rm-preset" + (f.preset === p.key ? " is-on" : ""), onClick: () => pick(p), children: [
1156
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: p.name }),
1157
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: p.persona })
1158
- ] }, p.key)) })
1180
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Start from" }),
1181
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: "Presets fill the fields below; switch to Custom anytime and edit freely." }),
1182
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-preset-row", children: [
1183
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "rm-preset" + (!f.preset ? " is-on" : ""), onClick: () => setF(blank()), children: [
1184
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: "Custom" }),
1185
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Blank form \u2014 your name, prompt, model" })
1186
+ ] }),
1187
+ presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "rm-preset" + (f.preset === p.key ? " is-on" : ""), onClick: () => pick(p), children: [
1188
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: p.name }),
1189
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: p.persona })
1190
+ ] }, p.key))
1191
+ ] })
1159
1192
  ] }) : null,
1160
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Name", htmlFor: "rm-ag-name", hint: "Member id is derived from it (e.g. coder.ab12).", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-ag-name", value: f.name, maxLength: 40, onChange: (e) => setF({ ...f, name: e.target.value }), placeholder: "e.g. Coder" }) }),
1161
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Persona", htmlFor: "rm-ag-persona", hint: "One line other members see.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-ag-persona", value: f.persona, maxLength: 200, onChange: (e) => setF({ ...f, persona: e.target.value }), placeholder: "e.g. Implements changes" }) }),
1162
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "System prompt", htmlFor: "rm-ag-sp", hint: "Prepended to every wake of this agent.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", { id: "rm-ag-sp", className: "rm-input rm-textarea", rows: 4, value: f.systemPrompt, maxLength: 4e3, onChange: (e) => setF({ ...f, systemPrompt: e.target.value }) }) }) }),
1193
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Name", htmlFor: "rm-ag-name", hint: "Member id is derived from it (e.g. coder.ab12).", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-ag-name", value: f.name, maxLength: 40, onChange: (e) => {
1194
+ const name2 = e.target.value;
1195
+ const presetName = (presets.find((p) => p.key === f.preset) || {}).name;
1196
+ setF({ ...f, name: name2, preset: f.preset && name2 !== presetName ? "" : f.preset });
1197
+ }, placeholder: "e.g. Data wrangler" }) }),
1198
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Persona", htmlFor: "rm-ag-persona", hint: "One line other members see.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-ag-persona", value: f.persona, maxLength: 200, onChange: (e) => setF({ ...f, persona: e.target.value, ...f.preset ? { preset: "" } : {} }), placeholder: "e.g. Cleans CSVs and writes summaries" }) }),
1199
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "System prompt", htmlFor: "rm-ag-sp", hint: "Prepended to every wake of this agent.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", { id: "rm-ag-sp", className: "rm-input rm-textarea", rows: 4, value: f.systemPrompt, maxLength: 4e3, onChange: (e) => setF({ ...f, systemPrompt: e.target.value, ...f.preset ? { preset: "" } : {} }), placeholder: "You are \u2026 Focus on \u2026 Report back with \u2026" }) }) }),
1163
1200
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Model", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { className: "rm-input", "aria-label": "Model", value: f.model, onChange: (e) => setF({ ...f, model: e.target.value }), children: [
1164
1201
  MODEL_CHOICES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: m, children: m || "dsh default model" }, m)),
1165
1202
  f.model && !MODEL_CHOICES.includes(f.model) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: f.model, children: f.model }) : null
@@ -1186,6 +1223,12 @@ function AgentDialog({ store, d }) {
1186
1223
  ] })
1187
1224
  ] }),
1188
1225
  f.scope === "write" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2 rm-note", children: "Writes go to its own git worktree (branch room/<room>/<agent>) when the workspace is a git repo; you merge from \u201CReview & merge\u201D. Non-git workspaces use file locks." }) : null,
1226
+ f.preset ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-span-2 rm-note", children: [
1227
+ "Filled from the ",
1228
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: f.preset }),
1229
+ " preset \u2014 editing any field switches to Custom. ",
1230
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-linkish", onClick: clearPreset, children: "Clear preset tag" })
1231
+ ] }) : null,
1189
1232
  err ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2 rm-error", children: err }) : null
1190
1233
  ] })
1191
1234
  }
@@ -1424,35 +1467,88 @@ function Field({ label, hint, children, htmlFor }) {
1424
1467
  function CreateDialog({ store, d }) {
1425
1468
  const s = useStore(store);
1426
1469
  const a = store.actions;
1427
- const [f, setF] = (0, import_react.useState)({ name: "", description: "", tags: "", public: false, mode: "lan", lanHostPort: "62.234.113.56:80", localOnly: false, agents: [] });
1470
+ const [tab, setTab] = (0, import_react.useState)("room");
1471
+ const [f, setF] = (0, import_react.useState)({
1472
+ name: "",
1473
+ description: "",
1474
+ tags: "",
1475
+ public: false,
1476
+ transport: "relay",
1477
+ // local | relay | lan | cloudflare
1478
+ lanHostPort: "62.234.113.56:80",
1479
+ turnLimit: 6,
1480
+ concurrency: 2,
1481
+ isolation: "auto",
1482
+ agents: []
1483
+ // draft agents: { key?, name, persona, systemPrompt, scope, moderator, reasoningEffort, approvalRequired, model }
1484
+ });
1485
+ const [draft, setDraft] = (0, import_react.useState)({ name: "", persona: "", systemPrompt: "", scope: "read", moderator: false, reasoningEffort: "medium", approvalRequired: false, model: "" });
1486
+ const [showCustom, setShowCustom] = (0, import_react.useState)(false);
1428
1487
  const [err, setErr] = (0, import_react.useState)(null);
1429
1488
  const [busy, setBusy] = (0, import_react.useState)(false);
1430
1489
  const [lanPeers, setLanPeers] = (0, import_react.useState)([]);
1490
+ const [presets, setPresets] = (0, import_react.useState)([]);
1431
1491
  const ok = f.name.trim() && !busy;
1432
1492
  const [ws, setWs] = (0, import_react.useState)(d && d.workspace ? d.workspace : null);
1493
+ (0, import_react.useEffect)(() => {
1494
+ a.presets().then(setPresets).catch(() => {
1495
+ });
1496
+ }, []);
1497
+ const togglePreset = (p) => {
1498
+ const has = f.agents.some((x) => x.key === p.key);
1499
+ setF({
1500
+ ...f,
1501
+ agents: has ? f.agents.filter((x) => x.key !== p.key) : [...f.agents, { key: p.key, name: p.name, persona: p.persona, systemPrompt: p.systemPrompt, scope: p.scope, moderator: !!p.moderator, reasoningEffort: p.reasoningEffort || "medium", approvalRequired: false, model: "" }]
1502
+ });
1503
+ };
1504
+ const addCustomDraft = () => {
1505
+ if (!draft.name.trim()) {
1506
+ setErr("Custom agent needs a name");
1507
+ setTab("agents");
1508
+ return;
1509
+ }
1510
+ setF({
1511
+ ...f,
1512
+ agents: [...f.agents, { ...draft, name: draft.name.trim(), key: void 0 }]
1513
+ });
1514
+ setDraft({ name: "", persona: "", systemPrompt: "", scope: "read", moderator: false, reasoningEffort: "medium", approvalRequired: false, model: "" });
1515
+ setShowCustom(false);
1516
+ setErr(null);
1517
+ };
1518
+ const removeDraft = (i) => setF({ ...f, agents: f.agents.filter((_, j) => j !== i) });
1433
1519
  const submit = async () => {
1434
1520
  if (!ok) return;
1435
1521
  if (!ws) {
1436
1522
  setErr("Pick a workspace");
1523
+ setTab("room");
1437
1524
  return;
1438
1525
  }
1439
1526
  setBusy(true);
1440
1527
  setErr(null);
1528
+ const transport = f.transport;
1529
+ const localOnly = transport === "local";
1530
+ const mode = transport === "cloudflare" ? "relay" : "lan";
1531
+ const lanHostPort = transport === "relay" ? f.lanHostPort.trim() || "62.234.113.56:80" : transport === "lan" ? "" : void 0;
1441
1532
  try {
1442
1533
  await a.create({
1443
1534
  name: f.name.trim(),
1444
1535
  description: f.description.trim(),
1445
1536
  tags: f.tags,
1446
- public: f.public,
1447
- mode: f.mode,
1448
- lanHostPort: f.mode === "lan" ? f.lanHostPort.trim() : void 0,
1537
+ public: localOnly ? false : f.public,
1538
+ mode,
1539
+ lanHostPort,
1449
1540
  workspacePath: ws.path,
1450
1541
  workspaceName: ws.title,
1451
- localOnly: f.localOnly,
1452
- agents: f.agents
1453
- });
1542
+ localOnly,
1543
+ turnLimit: f.turnLimit,
1544
+ concurrency: f.concurrency,
1545
+ isolation: f.isolation,
1546
+ agents: f.agents.map((ag) => ag.key ? ag.key : { name: ag.name, persona: ag.persona, systemPrompt: ag.systemPrompt, scope: ag.scope, moderator: ag.moderator, reasoningEffort: ag.reasoningEffort, approvalRequired: ag.approvalRequired, model: ag.model || void 0 })
1547
+ }, { timeoutMs: 35e3 });
1454
1548
  } catch (e) {
1455
- setErr(e.message);
1549
+ const msg = e && e.message || "Create failed";
1550
+ setErr(/timed out|timeout|abort/i.test(msg) ? `${msg}. Check transport (try Local only), relay host, and network \u2014 agent joins continue in the background after a successful create.` : msg);
1551
+ } finally {
1456
1552
  setBusy(false);
1457
1553
  }
1458
1554
  };
@@ -1464,6 +1560,11 @@ function CreateDialog({ store, d }) {
1464
1560
  setErr(e.message);
1465
1561
  }
1466
1562
  };
1563
+ const tabs = [
1564
+ { id: "room", label: "Room" },
1565
+ { id: "agents", label: `Agents${f.agents.length ? ` (${f.agents.length})` : ""}` },
1566
+ { id: "limits", label: "Limits" }
1567
+ ];
1467
1568
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1468
1569
  import_dsh_client_ui_primitives.Modal,
1469
1570
  {
@@ -1471,59 +1572,128 @@ function CreateDialog({ store, d }) {
1471
1572
  onClose: a.closeDialog,
1472
1573
  title: "Create room",
1473
1574
  closeLabel: "Close",
1474
- className: "rm-modal-wide",
1475
- description: ws ? `In workspace \u201C${ws.title}\u201D (${ws.path}). Agent cwd + MCP sandbox = this path. Default relay 62.234.113.56:80 \xB7 E2EE.` : "Pick a dsh workspace. Default relay 62.234.113.56:80 \xB7 E2EE.",
1575
+ className: "rm-modal-wide rm-modal-create rm-modal-scrollable",
1576
+ contentClassName: "rm-modal-scroll",
1577
+ description: ws ? `Workspace \u201C${ws.title}\u201D \xB7 default VPS relay 62.234.113.56:80 \xB7 E2EE. Every option below is editable.` : "Pick a dsh workspace. Every create option is on these tabs \u2014 nothing is hidden off-screen.",
1476
1578
  footer: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1477
1579
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "outline", onClick: a.closeDialog, children: "Cancel" }),
1478
1580
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "primary", disabled: !ok, onClick: submit, children: busy ? "Creating\u2026" : "Create" })
1479
1581
  ] }),
1480
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-root rm-form rm-form-wide", onKeyDown: (e) => e.key === "Enter" && e.target.tagName === "INPUT" && submit(), children: [
1481
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Workspace", htmlFor: "rm-create-ws", hint: "Native dsh workspace this room belongs to.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceSelect, { store, id: "rm-create-ws", value: ws, onChange: setWs }) }),
1482
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Name", htmlFor: "rm-create-name", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-name-row", children: [
1483
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Avatar, { name: f.name || "room", size: 36 }),
1484
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-name", autoFocus: true, placeholder: "e.g. release-crew", maxLength: 60, value: f.name, onChange: (e) => setF({ ...f, name: e.target.value }) })
1485
- ] }) }),
1486
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Transport", hint: "VPS directory works on LAN/VPS. Cloudflare is optional.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-mode-row", children: [
1487
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (f.mode === "lan" ? " is-on" : ""), onClick: () => setF({ ...f, mode: "lan", lanHostPort: f.lanHostPort || "62.234.113.56:80" }), children: "LAN / VPS" }),
1488
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (f.mode === "relay" ? " is-on" : ""), onClick: () => setF({ ...f, mode: "relay" }), children: "Cloudflare" })
1489
- ] }) }),
1490
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Description", htmlFor: "rm-create-desc", hint: "Shown to members and in public search.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-desc", placeholder: "e.g. Agents that review and ship releases", maxLength: 280, value: f.description, onChange: (e) => setF({ ...f, description: e.target.value }) }) }),
1491
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Tags", htmlFor: "rm-create-tags", hint: "Spaces or commas, up to 8.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-tags", placeholder: "e.g. review rust", value: f.tags, onChange: (e) => setF({ ...f, tags: e.target.value }) }) }),
1492
- f.mode === "lan" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Field, { label: "Relay host:port", htmlFor: "rm-lan-hp", hint: "Default 62.234.113.56:80. Blank = this machine + mDNS.", children: [
1493
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-lan-hp", placeholder: "62.234.113.56:80 or 100.x.x.x:7421", value: f.lanHostPort, onChange: (e) => setF({ ...f, lanHostPort: e.target.value }) }),
1494
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-lan-browse", children: [
1582
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-root rm-create", "data-rm-create": "", onKeyDown: (e) => e.key === "Enter" && e.target.tagName === "INPUT" && tab === "room" && submit(), children: [
1583
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-tabs", role: "tablist", "aria-label": "Create room sections", children: tabs.map((t) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", role: "tab", "aria-selected": tab === t.id, className: "rm-tab" + (tab === t.id ? " is-on" : ""), onClick: () => setTab(t.id), children: t.label }, t.id)) }),
1584
+ tab === "room" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-form rm-form-wide rm-create-pane", role: "tabpanel", children: [
1585
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Workspace", htmlFor: "rm-create-ws", hint: "Native dsh workspace this room belongs to.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceSelect, { store, id: "rm-create-ws", value: ws, onChange: setWs }) }),
1586
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Name", htmlFor: "rm-create-name", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-name-row", children: [
1587
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Avatar, { name: f.name || "room", size: 36 }),
1588
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-name", autoFocus: true, placeholder: "e.g. release-crew", maxLength: 60, value: f.name, onChange: (e) => setF({ ...f, name: e.target.value }) })
1589
+ ] }) }),
1590
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Transport", hint: "Local only = in-process (no network). Relay / LAN / Cloudflare for remote hosts.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-mode-row rm-mode-wrap", children: [
1591
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (f.transport === "local" ? " is-on" : ""), onClick: () => setF({ ...f, transport: "local", public: false }), children: "Local only" }),
1592
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (f.transport === "relay" ? " is-on" : ""), onClick: () => setF({ ...f, transport: "relay", lanHostPort: f.lanHostPort || "62.234.113.56:80" }), children: "Relay (VPS)" }),
1593
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (f.transport === "lan" ? " is-on" : ""), onClick: () => setF({ ...f, transport: "lan" }), children: "LAN (this machine)" }),
1594
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (f.transport === "cloudflare" ? " is-on" : ""), onClick: () => setF({ ...f, transport: "cloudflare" }), children: "Cloudflare" })
1595
+ ] }) }) }),
1596
+ f.transport === "relay" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Relay host:port", htmlFor: "rm-lan-hp", hint: "Default 62.234.113.56:80 (public directory).", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-lan-hp", placeholder: "62.234.113.56:80", value: f.lanHostPort, onChange: (e) => setF({ ...f, lanHostPort: e.target.value }) }) }) }) : null,
1597
+ f.transport === "lan" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "LAN relay", hint: "Blank host embeds a relay on this machine and advertises it over mDNS.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-lan-browse", children: [
1495
1598
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "outline", onClick: browseLan, children: "Browse mDNS" }),
1496
- lanPeers.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "rm-lan-peer", onClick: () => setF({ ...f, lanHostPort: p.hostPort }), children: [
1599
+ lanPeers.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "rm-lan-peer", onClick: () => setF({ ...f, transport: "relay", lanHostPort: p.hostPort }), children: [
1497
1600
  p.hostPort,
1498
1601
  p.name ? ` \xB7 ${p.name}` : ""
1499
1602
  ] }, p.hostPort))
1500
- ] })
1501
- ] }) }) : null,
1502
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-span-2 rm-local-box", children: [
1503
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-switch-row", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1504
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Local agents" }),
1505
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: "Host several agents from this dsh as separate members (own identity, session, scope). Edit them later in room details." })
1506
- ] }) }),
1507
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-preset-row", children: [["moderator", "Moderator"], ["architect", "Architect"], ["coder", "Coder"], ["reviewer", "Reviewer"]].map(([k, label]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "rm-preset rm-preset-check" + (f.agents.includes(k) ? " is-on" : ""), children: [
1508
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: f.agents.includes(k), onChange: (e) => setF({ ...f, agents: e.target.checked ? [...f.agents, k] : f.agents.filter((x) => x !== k) }) }),
1509
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: label })
1510
- ] }, k)) }),
1511
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-switch-row", children: [
1603
+ ] }) }) }) : null,
1604
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Description", htmlFor: "rm-create-desc", hint: "Shown to members and in public search.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-desc", placeholder: "e.g. Agents that review and ship releases", maxLength: 280, value: f.description, onChange: (e) => setF({ ...f, description: e.target.value }) }) }),
1605
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Tags", htmlFor: "rm-create-tags", hint: "Spaces or commas, up to 8.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-tags", placeholder: "e.g. review rust", value: f.tags, onChange: (e) => setF({ ...f, tags: e.target.value }) }) }),
1606
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-span-2 rm-switch-row", children: [
1512
1607
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1513
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Local only (no network)" }),
1514
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: "In-process loopback \u2014 nothing leaves this machine. One click to switch to Relay/LAN later." })
1608
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "List in public directory" }),
1609
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: f.transport === "local" ? "Local-only rooms stay private (no network)." : f.public ? "Anyone can find and join \u2014 key is published with the listing." : "Private: invite only." })
1515
1610
  ] }),
1516
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Switch, { checked: f.localOnly, onChange: (v) => setF({ ...f, localOnly: v, public: v ? false : f.public }), label: "Local only" })
1611
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Switch, { checked: f.public && f.transport !== "local", onChange: (v) => setF({ ...f, public: v }), label: "List in public directory", disabled: f.transport === "local", title: f.transport === "local" ? "Local-only rooms stay private" : void 0 })
1517
1612
  ] })
1518
- ] }),
1519
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-span-2 rm-switch-row", children: [
1520
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1521
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "List in public directory" }),
1522
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: f.public ? "Anyone can find and join \u2014 key is published with the listing." : "Private: invite only." })
1613
+ ] }) : null,
1614
+ tab === "agents" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-create-pane", role: "tabpanel", children: [
1615
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Presets" }),
1616
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: "Shortcuts that seed a local agent. You can still add free-form agents below, and edit anyone after create." }),
1617
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-preset-row", children: (presets.length ? presets : [
1618
+ { key: "moderator", name: "Moderator", persona: "Breaks requests into tasks and summarizes", scope: "read", moderator: true, reasoningEffort: "medium", systemPrompt: "" },
1619
+ { key: "architect", name: "Architect", persona: "Designs the approach", scope: "read", reasoningEffort: "high", systemPrompt: "" },
1620
+ { key: "coder", name: "Coder", persona: "Implements in its own worktree", scope: "write", reasoningEffort: "medium", systemPrompt: "" },
1621
+ { key: "reviewer", name: "Reviewer", persona: "Reviews diffs", scope: "read", reasoningEffort: "high", systemPrompt: "" }
1622
+ ]).map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "rm-preset rm-preset-check" + (f.agents.some((x) => x.key === p.key) ? " is-on" : ""), children: [
1623
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: f.agents.some((x) => x.key === p.key), onChange: () => togglePreset(p) }),
1624
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
1625
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: p.name }),
1626
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "rm-preset-sub", children: p.persona })
1627
+ ] })
1628
+ ] }, p.key)) }),
1629
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-create-custom", children: [
1630
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-create-custom-head", children: [
1631
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1632
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Custom agents" }),
1633
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: "Free-form name, persona, system prompt, model, scope, approval, moderator." })
1634
+ ] }),
1635
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlusIcon, {}), onClick: () => {
1636
+ setShowCustom(true);
1637
+ setErr(null);
1638
+ }, children: "Add custom" })
1639
+ ] }),
1640
+ f.agents.filter((x) => !x.key).length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "rm-draft-list", children: f.agents.map((ag, i) => ag.key ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "rm-draft-item", children: [
1641
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Avatar, { name: ag.name, size: 24 }),
1642
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "rm-draft-main", children: [
1643
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: ag.name }),
1644
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
1645
+ ag.persona || "custom",
1646
+ " \xB7 ",
1647
+ ag.scope,
1648
+ ag.moderator ? " \xB7 moderator" : ""
1649
+ ] })
1650
+ ] }),
1651
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mini", "aria-label": `Remove ${ag.name}`, onClick: () => removeDraft(i), children: "\xD7" })
1652
+ ] }, i)) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "rm-note", children: "No custom agents yet \u2014 presets above, or Add custom." }),
1653
+ showCustom ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-draft-form rm-form rm-form-wide", children: [
1654
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Name", htmlFor: "rm-create-ag-name", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-ag-name", value: draft.name, maxLength: 40, onChange: (e) => setDraft({ ...draft, name: e.target.value }), placeholder: "e.g. Data wrangler" }) }),
1655
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Persona", htmlFor: "rm-create-ag-persona", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-ag-persona", value: draft.persona, maxLength: 200, onChange: (e) => setDraft({ ...draft, persona: e.target.value }), placeholder: "One-line role" }) }),
1656
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "System prompt", htmlFor: "rm-create-ag-sp", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", { id: "rm-create-ag-sp", className: "rm-input rm-textarea", rows: 3, value: draft.systemPrompt, maxLength: 4e3, onChange: (e) => setDraft({ ...draft, systemPrompt: e.target.value }) }) }) }),
1657
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Model", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { className: "rm-input", "aria-label": "Model", value: draft.model, onChange: (e) => setDraft({ ...draft, model: e.target.value }), children: MODEL_CHOICES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: m, children: m || "dsh default model" }, m)) }) }),
1658
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Reasoning effort", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { className: "rm-input", "aria-label": "Reasoning effort", value: draft.reasoningEffort, onChange: (e) => setDraft({ ...draft, reasoningEffort: e.target.value }), children: ["low", "medium", "high", "max"].map((x) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: x, children: x }, x)) }) }),
1659
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Workspace scope", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-mode-row", children: [
1660
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (draft.scope === "read" ? " is-on" : ""), onClick: () => setDraft({ ...draft, scope: "read" }), children: "Read-only" }),
1661
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (draft.scope === "write" ? " is-on" : ""), onClick: () => setDraft({ ...draft, scope: "write" }), children: "Read + write" })
1662
+ ] }) }),
1663
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-switch-col", children: [
1664
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-switch-row", children: [
1665
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Approval required" }) }),
1666
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Switch, { checked: draft.approvalRequired, onChange: (v) => setDraft({ ...draft, approvalRequired: v }), label: "Approval required" })
1667
+ ] }),
1668
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-switch-row", children: [
1669
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Moderator" }) }),
1670
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Switch, { checked: draft.moderator, onChange: (v) => setDraft({ ...draft, moderator: v }), label: "Moderator" })
1671
+ ] })
1672
+ ] }),
1673
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-span-2 rm-actions", children: [
1674
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "outline", onClick: () => setShowCustom(false), children: "Cancel" }),
1675
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "primary", onClick: addCustomDraft, children: "Add to room" })
1676
+ ] })
1677
+ ] }) : null
1523
1678
  ] }),
1524
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Switch, { checked: f.public, onChange: (v) => setF({ ...f, public: v, localOnly: v ? false : f.localOnly }), label: "List in public directory" })
1525
- ] }),
1526
- err ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2 rm-error", children: err }) : null
1679
+ f.agents.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-note", style: { marginTop: 10 }, children: [
1680
+ "Will create: ",
1681
+ f.agents.map((x) => x.name).join(", "),
1682
+ ". Edit or add more after create from Local agents \u2192 Add local agent."
1683
+ ] }) : null
1684
+ ] }) : null,
1685
+ tab === "limits" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-form rm-form-wide rm-create-pane", role: "tabpanel", children: [
1686
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Parallel runs", htmlFor: "rm-create-conc", hint: "Max local agent runs at once (1\u201316). The rest wait in a visible queue.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-conc", type: "number", min: 1, max: 16, value: String(f.concurrency), onChange: (e) => setF({ ...f, concurrency: Math.min(16, Math.max(1, Number(e.target.value) || 1)) }) }) }),
1687
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Turn limit", htmlFor: "rm-create-turns", hint: "Max agent-to-agent hand-offs per task/thread (1\u2013100). A human message resets it.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-turns", type: "number", min: 1, max: 100, value: String(f.turnLimit), onChange: (e) => setF({ ...f, turnLimit: Math.min(100, Math.max(1, Number(e.target.value) || 6)) }) }) }),
1688
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Workspace isolation", hint: "Writing agents get their own git worktree by default when the workspace is a git repo.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { className: "rm-input", "aria-label": "Isolation mode", value: f.isolation, onChange: (e) => setF({ ...f, isolation: e.target.value }), children: [
1689
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "auto", children: "Auto \u2014 git worktree per writing agent, else file locks" }),
1690
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "worktree", children: "Git worktree per agent" }),
1691
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "locks", children: "File locks (shared workspace)" }),
1692
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "off", children: "Off (shared, no locks)" })
1693
+ ] }) }) }),
1694
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2 rm-note", children: "These apply as soon as the room has local agents. Change them later under Runs / Workspace isolation in the room panel." })
1695
+ ] }) : null,
1696
+ err ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-error", style: { marginTop: 10 }, children: err }) : null
1527
1697
  ] })
1528
1698
  }
1529
1699
  );
@@ -2047,17 +2217,32 @@ var import_react = require("react");
2047
2217
  var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
2048
2218
 
2049
2219
  // src/client/rooms.css
2050
- var rooms_default = '/* Collab Rooms UI \u2014 original surface inside the dsh shell. Uses only dsh --dsw-* tokens.\n Independent Rooms surface. Prefix: rm- (rooms). */\n\n.rm-root {\n --rm-accent: var(--dsw-alias-state-business-primary);\n --rm-hover: var(--dsw-alias-interactive-bg-hover);\n --rm-border: var(--dsw-alias-border-l2);\n --rm-bg: var(--dsw-alias-bg-base);\n --rm-panel: var(--dsw-alias-bg-module-platform);\n --rm-label: var(--dsw-alias-label-primary);\n --rm-muted: var(--dsw-alias-label-secondary);\n --rm-quiet: var(--dsw-alias-label-tertiary);\n font: 13px/1.5 var(--dsw-font-family);\n color: var(--rm-label);\n box-sizing: border-box;\n}\n.rm-root *, .rm-root *::before, .rm-root *::after { box-sizing: border-box; }\n.rm-root button, .rm-root input, .rm-root textarea { font: inherit; }\n\n/* \u2500\u2500 sidebar (joined rooms + public search) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-side {\n display: flex; flex-direction: column; height: 100%; min-height: 0;\n padding: 0 8px 8px 0; gap: 8px;\n}\n.rm-side-toolbar {\n display: flex; align-items: center; gap: 6px; flex: none; padding: 4px 0 2px;\n}\n.rm-side-title {\n flex: 1; font-size: 12px; font-weight: 600; letter-spacing: .04em;\n text-transform: uppercase; color: var(--rm-quiet);\n}\n.rm-icon-btn {\n width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;\n border: 0; border-radius: 8px; background: transparent; color: var(--rm-muted); cursor: pointer; padding: 0;\n}\n.rm-icon-btn:hover { background: var(--rm-hover); color: var(--rm-label); }\n.rm-search {\n display: flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px;\n border: .5px solid var(--rm-border); border-radius: 8px; background: var(--rm-panel);\n}\n.rm-search input {\n flex: 1; min-width: 0; border: 0; background: transparent; outline: none; color: var(--rm-label); font-size: 13px;\n}\n.rm-search input::placeholder { color: var(--rm-quiet); }\n.rm-side-scroll { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 12px; }\n.rm-group-label { font-size: 11px; font-weight: 600; color: var(--rm-quiet); padding: 0 4px 4px; text-transform: uppercase; letter-spacing: .03em; }\n.rm-room-list { display: flex; flex-direction: column; gap: 2px; }\n.rm-room-item {\n display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 10px;\n border: 0; border-radius: 10px; background: transparent; color: inherit; cursor: pointer; text-align: left;\n}\n.rm-room-item:hover { background: var(--rm-hover); }\n.rm-room-item[aria-current="true"] { background: var(--rm-hover); }\n.rm-room-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }\n.rm-room-item-name { font-weight: 600; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-room-item-meta { font-size: 11.5px; color: var(--rm-quiet); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-room-item-trail { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }\n.rm-badge {\n display: inline-flex; align-items: center; gap: 3px; height: 18px; padding: 0 6px;\n border-radius: 999px; font-size: 10.5px; font-weight: 500; background: var(--rm-panel); color: var(--rm-muted);\n border: .5px solid var(--rm-border);\n}\n.rm-badge-public { color: var(--rm-accent); border-color: color-mix(in srgb, var(--rm-accent) 35%, transparent); background: color-mix(in srgb, var(--rm-accent) 8%, transparent); }\n.rm-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--rm-quiet); }\n.rm-dot-online { background: var(--dsw-alias-state-success-primary, #2bb673); }\n.rm-dot-connecting { background: var(--dsw-alias-state-warn-primary, #e9a23b); }\n.rm-dot-offline { background: var(--dsw-alias-state-error-primary, #e5484d); }\n.rm-empty-hint { padding: 8px 10px; font-size: 12px; color: var(--rm-quiet); line-height: 1.45; }\n.rm-dir-item {\n display: flex; align-items: flex-start; gap: 10px; padding: 10px; border-radius: 10px;\n border: .5px solid var(--rm-border); background: var(--rm-bg); margin-bottom: 6px;\n}\n.rm-dir-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }\n.rm-dir-tags { display: flex; flex-wrap: wrap; gap: 4px; }\n.rm-tag { font-size: 11px; color: var(--rm-muted); background: var(--rm-hover); border-radius: 4px; padding: 0 5px; }\n.rm-menu {\n position: fixed; z-index: 1000; min-width: 180px; padding: 4px;\n border-radius: 10px; background: var(--dsw-alias-bg-layer-1, var(--rm-bg));\n border: .5px solid var(--rm-border);\n box-shadow: 0 8px 24px color-mix(in srgb, var(--rm-label) 12%, transparent);\n display: flex; flex-direction: column;\n}\n.rm-menu button {\n display: flex; align-items: center; gap: 8px; height: 32px; padding: 0 10px;\n border: 0; border-radius: 6px; background: transparent; color: var(--rm-label); cursor: pointer; text-align: left;\n}\n.rm-menu button:hover { background: var(--rm-hover); }\n\n/* \u2500\u2500 main: room workspace \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-main { display: flex; flex: 1; min-height: 0; height: 100%; width: 100%; background: var(--rm-bg); }\n.rm-workspace { display: flex; flex: 1; min-width: 0; min-height: 0; }\n.rm-chat { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; }\n.rm-chat-header {\n flex: none; display: flex; align-items: center; gap: 10px; height: 48px;\n padding: 0 16px; border-bottom: .5px solid var(--rm-border);\n}\n.rm-chat-header-title { font-size: 14px; font-weight: 600; }\n.rm-chat-header-sub { font-size: 12px; color: var(--rm-quiet); }\n.rm-messages {\n flex: 1; min-height: 0; overflow: auto; padding: 16px 18px 8px;\n display: flex; flex-direction: column; gap: 2px;\n}\n.rm-day {\n align-self: center; margin: 10px 0 12px; padding: 2px 10px; border-radius: 999px;\n font-size: 11px; color: var(--rm-quiet); background: var(--dsw-alias-button-elevated-fill, var(--rm-panel));\n}\n.rm-msg {\n display: grid; grid-template-columns: 32px 1fr; gap: 0 10px; padding: 4px 6px; border-radius: 8px;\n max-width: 720px;\n}\n.rm-msg:hover { background: color-mix(in srgb, var(--rm-hover) 60%, transparent); }\n.rm-msg-self { margin-left: auto; grid-template-columns: 1fr; max-width: 640px; }\n.rm-msg-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 1px; }\n.rm-msg-author { font-size: 12px; font-weight: 600; color: var(--rm-muted); }\n.rm-msg-time { font-size: 11px; color: var(--rm-quiet); }\n.rm-msg-body { font-size: 13.5px; line-height: 1.55; white-space: pre-wrap; word-break: break-word; }\n.rm-msg-self .rm-msg-body {\n background: var(--dsw-alias-label-primary); color: var(--dsw-alias-label-primary-foreground);\n padding: 8px 12px; border-radius: 12px 12px 4px 12px; width: fit-content; margin-left: auto;\n}\n.rm-msg-event {\n grid-template-columns: 1fr; max-width: 560px; margin: 6px 0;\n padding: 8px 12px; border: .5px solid var(--rm-border); border-radius: 10px; background: var(--rm-panel);\n}\n.rm-mention { color: var(--rm-accent); font-weight: 500; }\n.rm-msg-self .rm-mention { color: inherit; text-decoration: underline; text-underline-offset: 2px; }\n.rm-task-card { display: flex; flex-direction: column; gap: 4px; }\n.rm-task-head { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--rm-muted); }\n.rm-task-title { font-weight: 600; font-size: 13.5px; }\n.rm-composer {\n flex: none; display: flex; align-items: flex-end; gap: 8px; padding: 10px 16px 14px;\n border-top: .5px solid var(--rm-border);\n}\n.rm-composer-box {\n flex: 1; display: flex; align-items: flex-end; gap: 6px; min-height: 44px;\n padding: 8px 10px; border: .5px solid var(--rm-border); border-radius: 12px; background: var(--rm-panel);\n}\n.rm-composer-box:focus-within { border-color: color-mix(in srgb, var(--rm-accent) 50%, var(--rm-border)); }\n.rm-composer-box textarea {\n flex: 1; min-height: 28px; max-height: 120px; border: 0; background: transparent; outline: none;\n resize: none; color: var(--rm-label); line-height: 1.45;\n}\n.rm-composer-box textarea::placeholder { color: var(--rm-quiet); }\n.rm-composer-mode {\n width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;\n border: 0; border-radius: 8px; background: transparent; color: var(--rm-muted); cursor: pointer; flex: none;\n}\n.rm-composer-mode:hover, .rm-composer-mode[aria-pressed="true"] {\n color: var(--rm-accent); background: color-mix(in srgb, var(--rm-accent) 12%, transparent);\n}\n.rm-chat-hint { margin: 48px auto; text-align: center; color: var(--rm-quiet); font-size: 13px; max-width: 360px; line-height: 1.5; }\n\n/* \u2500\u2500 detail column (members / invite / about) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-detail {\n flex: 0 0 280px; width: 280px; display: flex; flex-direction: column; min-height: 0;\n border-left: .5px solid var(--rm-border); background: var(--rm-bg); overflow: auto;\n}\n.rm-detail-section { padding: 14px 14px 8px; border-bottom: .5px solid var(--rm-border); }\n.rm-detail-section:last-child { border-bottom: 0; }\n.rm-detail-h {\n display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600;\n text-transform: uppercase; letter-spacing: .04em; color: var(--rm-quiet); margin-bottom: 8px;\n}\n.rm-member {\n display: flex; align-items: center; gap: 8px; padding: 5px 4px; border-radius: 8px; min-height: 34px;\n}\n.rm-member:hover { background: var(--rm-hover); }\n.rm-member-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }\n.rm-member-actions { display: none; gap: 2px; }\n.rm-member:hover .rm-member-actions, .rm-member:focus-within .rm-member-actions { display: inline-flex; }\n.rm-mini {\n width: 24px; height: 24px; display: inline-flex; align-items: center; justify-content: center;\n border: 0; border-radius: 6px; background: transparent; color: var(--rm-muted); cursor: pointer; font-size: 12px;\n}\n.rm-mini:hover { background: var(--dsw-alias-interactive-bg-active); color: var(--rm-label); }\n.rm-task-row { display: flex; align-items: center; gap: 6px; padding: 4px; font-size: 12.5px; }\n.rm-task-row-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-about { display: grid; grid-template-columns: 88px 1fr; gap: 6px 8px; font-size: 12.5px; margin: 0; }\n.rm-about dt { color: var(--rm-quiet); margin: 0; }\n.rm-about dd { margin: 0; min-width: 0; overflow-wrap: anywhere; display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }\n.rm-mono { font-family: var(--dsw-font-markdown-code-block-font-family, ui-monospace, monospace); font-size: 11.5px; }\n.rm-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }\n.rm-danger { color: var(--dsw-alias-state-error-primary, #e5484d) !important; }\n.rm-note { font-size: 12px; color: var(--rm-quiet); line-height: 1.45; margin: 0 0 8px; }\n\n/* \u2500\u2500 empty / welcome \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-welcome-wrap {\n flex: 1; display: flex; align-items: center; justify-content: center; padding: 32px; background: var(--rm-bg);\n}\n.rm-welcome {\n width: min(420px, 100%); display: flex; flex-direction: column; gap: 10px;\n padding: 20px; border-radius: 14px; border: .5px solid var(--rm-border); background: var(--rm-panel);\n}\n.rm-welcome h1 { margin: 0; font-size: 16px; font-weight: 600; }\n.rm-welcome p { margin: 0; font-size: 13px; color: var(--rm-muted); line-height: 1.5; }\n.rm-welcome-actions { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; }\n.rm-welcome-action {\n display: flex; align-items: flex-start; gap: 10px; width: 100%; padding: 10px 12px;\n border: .5px solid var(--rm-border); border-radius: 10px; background: var(--rm-bg);\n color: var(--rm-label); cursor: pointer; text-align: left;\n}\n.rm-welcome-action:hover { background: var(--rm-hover); }\n.rm-welcome-action b { display: block; font-size: 13px; }\n.rm-welcome-action span { display: block; font-size: 12px; color: var(--rm-quiet); margin-top: 2px; }\n\n/* \u2500\u2500 avatars \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-avatar {\n display: inline-flex; align-items: center; justify-content: center; flex: none;\n font-weight: 600; letter-spacing: .02em; user-select: none;\n}\n.rm-avatar-wrap { position: relative; display: inline-flex; flex: none; }\n\n/* \u2500\u2500 dialogs (inside dsh Modal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-form { display: flex; flex-direction: column; gap: 14px; }\n.rm-field { display: flex; flex-direction: column; gap: 6px; }\n.rm-field-label { font-size: 13px; font-weight: 500; }\n.rm-field-hint { font-size: 12px; color: var(--rm-quiet); }\n.rm-name-row { display: flex; align-items: center; gap: 10px; }\n.rm-name-row > :last-child { flex: 1; }\n.rm-switch-row {\n display: flex; align-items: center; justify-content: space-between; gap: 14px;\n padding: 10px 12px; border-radius: 10px; background: var(--rm-panel);\n}\n.rm-error { color: var(--dsw-alias-state-error-primary, #e5484d); font-size: 12.5px; }\n.rm-invite {\n display: block; padding: 10px 12px; border-radius: 8px; background: var(--rm-panel);\n font-family: var(--dsw-font-markdown-code-block-font-family, ui-monospace, monospace);\n font-size: 12px; word-break: break-all; user-select: all;\n}\n\n/* Dual transport + approvals + agent config */\n.rm-mode-row { display: flex; gap: 8px; }\n.rm-mode-btn {\n flex: 1; padding: 10px 12px; border-radius: 10px; border: 1px solid var(--rm-border, #2a2f3a);\n background: transparent; color: inherit; cursor: pointer; font: inherit;\n}\n.rm-mode-btn.is-on { border-color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 16%, transparent); }\n.rm-lan-browse { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; align-items: center; }\n.rm-lan-peer {\n font-size: 12px; padding: 4px 8px; border-radius: 999px; border: 1px solid var(--rm-border, #2a2f3a);\n background: transparent; color: inherit; cursor: pointer;\n}\n.rm-approvals { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--rm-border, #2a2f3a); background: color-mix(in srgb, #f5a524 12%, transparent); }\n.rm-approval { display: flex; gap: 12px; align-items: center; justify-content: space-between; }\n.rm-approval-body { font-size: 13px; }\n.rm-approval-actions { display: flex; gap: 6px; flex-shrink: 0; }\n.rm-input { width: 100%; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--rm-border, #2a2f3a); background: transparent; color: inherit; font: inherit; }\n\n.rm-ws-bar { display: flex; flex-direction: column; gap: 4px; padding: 8px 12px; border-bottom: 1px solid var(--rm-border, #2a2f3a); }\n.rm-ws-chip { display: inline-flex; align-items: center; gap: 6px; align-self: flex-start; padding: 4px 10px; border-radius: 999px; border: 1px solid var(--rm-border, #2a2f3a); background: transparent; color: inherit; cursor: pointer; font: inherit; font-size: 12.5px; }\n.rm-ws-path { font-size: 11px; color: var(--rm-quiet, #8b93a7); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-room-item.is-active { background: color-mix(in srgb, var(--rm-accent, #5b8cff) 12%, transparent); }\n\n/* Native-aligned room composer (mirrors dsh conversation control row) */\n.rm-composer-card {\n box-sizing: border-box;\n width: 100%;\n max-width: 920px;\n margin: 0 auto;\n border-radius: 16px;\n background: var(--rm-elev, var(--rm-panel, #12151c));\n border: 1px solid var(--rm-border, #2a2f3a);\n box-shadow: 0 1px 2px rgba(0,0,0,.06);\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px 0 6px;\n}\n.rm-composer-grow { position: relative; padding: 0 4px; }\n.rm-composer-grow textarea {\n box-sizing: border-box; width: 100%; min-height: 36px; max-height: 160px;\n resize: none; border: none; outline: none; background: transparent;\n color: inherit; font: inherit; font-size: 14px; line-height: 22px;\n padding: 4px 12px 0 14px;\n}\n.rm-composer-grow textarea:disabled { opacity: .55; cursor: not-allowed; }\n.rm-composer-row {\n display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;\n gap: 10px; min-width: 0; padding: 2px 8px 4px;\n}\n.rm-composer-tools, .rm-composer-modes, .rm-composer-trailing {\n display: flex; align-items: center; min-width: 0; gap: 8px;\n}\n.rm-composer-trailing { flex: none; margin-left: auto; }\n.rm-composer-add {\n width: 28px; height: 28px; border: none; border-radius: 999px;\n background: color-mix(in srgb, var(--rm-fg, #e8eaed) 8%, transparent);\n color: inherit; cursor: pointer; display: grid; place-items: center;\n}\n.rm-composer-add:hover, .rm-composer-add[aria-pressed="true"] {\n background: color-mix(in srgb, var(--rm-accent, #5b8cff) 22%, transparent);\n}\n.rm-composer-select {\n max-width: 220px; height: 28px; border: none; border-radius: 8px;\n background: transparent; color: var(--rm-quiet, #8b93a7);\n font: inherit; font-size: 13px; font-weight: 500; line-height: 20px;\n padding: 0 8px; cursor: pointer; white-space: nowrap;\n}\n.rm-composer-select:hover:not(:disabled) {\n background: color-mix(in srgb, var(--rm-fg, #e8eaed) 8%, transparent);\n}\n.rm-composer-select:disabled { opacity: .5; cursor: default; }\n.rm-composer-model-text { display: inline; }\n.rm-composer-model-icon { display: none; font-size: 10px; }\n.rm-composer-effort {\n margin-left: 6px; font-size: 11px; opacity: .75;\n text-transform: uppercase; letter-spacing: .02em;\n}\n.rm-composer-send {\n width: 34px; height: 34px; border: none; border-radius: 999px;\n background: var(--rm-accent, #5b8cff); color: #fff; cursor: pointer;\n display: grid; place-items: center; transform: translateY(-2px);\n}\n.rm-composer-send:hover:not(:disabled) { filter: brightness(1.08); }\n.rm-composer-send:disabled { opacity: .4; cursor: default; }\n.rm-composer-popwrap { position: relative; }\n.rm-composer-menu {\n position: absolute; bottom: calc(100% + 6px); left: 0; z-index: 40;\n min-width: 200px; max-height: 320px; overflow: auto;\n border: 1px solid var(--rm-border, #2a2f3a); border-radius: 12px;\n background: var(--rm-elev, #12151c); box-shadow: 0 8px 24px rgba(0,0,0,.28);\n padding: 6px; display: flex; flex-direction: column; gap: 2px;\n}\n.rm-composer-menu-wide { min-width: 280px; max-width: 340px; }\n.rm-composer-menu-label {\n font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em;\n color: var(--rm-quiet, #8b93a7); padding: 6px 8px 2px;\n}\n.rm-composer-menu button[role="menuitem"] {\n text-align: left; border: none; background: transparent; color: inherit;\n font: inherit; font-size: 13px; padding: 6px 8px; border-radius: 8px; cursor: pointer;\n}\n.rm-composer-menu button[role="menuitem"]:hover,\n.rm-composer-menu button[role="menuitem"].is-active {\n background: color-mix(in srgb, var(--rm-accent, #5b8cff) 16%, transparent);\n}\n.rm-composer-check {\n display: flex; align-items: center; gap: 8px; font-size: 13px; padding: 4px 8px; cursor: pointer;\n}\n.rm-grant-row {\n display: flex; align-items: center; justify-content: space-between; gap: 8px;\n padding: 2px 8px; font-size: 12.5px;\n}\n.rm-grant-row select {\n font: inherit; font-size: 12px; border-radius: 6px;\n border: 1px solid var(--rm-border, #2a2f3a); background: transparent; color: inherit; padding: 2px 6px;\n}\n.rm-peer-grant-block { border-top: 1px solid var(--rm-border, #2a2f3a); padding-top: 4px; margin-top: 4px; }\n.rm-peer-grant-name { font-size: 12px; font-weight: 600; padding: 4px 8px; overflow: hidden; text-overflow: ellipsis; }\n\n/* Hide legacy tight composer if still referenced */\n.rm-composer { display: none; }\n\n.rm-composer-grow { position: relative; }\n.rm-mention-menu {\n position: absolute; left: 8px; right: 8px; bottom: calc(100% + 6px); z-index: 50;\n max-height: 240px; overflow: auto;\n border: 1px solid var(--rm-border, #2a2f3a); border-radius: 12px;\n background: var(--rm-elev, #12151c); box-shadow: 0 10px 28px rgba(0,0,0,.32);\n padding: 4px; display: flex; flex-direction: column; gap: 2px;\n}\n.rm-mention-item {\n display: flex; align-items: center; gap: 8px; text-align: left;\n border: none; background: transparent; color: inherit; font: inherit;\n padding: 6px 8px; border-radius: 8px; cursor: pointer;\n}\n.rm-mention-item:hover, .rm-mention-item.is-active {\n background: color-mix(in srgb, var(--rm-accent, #5b8cff) 18%, transparent);\n}\n.rm-mention-item-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }\n.rm-mention-item-name { font-size: 13px; font-weight: 600; }\n.rm-mention-item-meta { font-size: 11px; color: var(--rm-quiet, #8b93a7); }\n\n\n/* New Room shortcut under workspace (mirrors New Session affordance) */\n.rm-new-room {\n display: flex; align-items: center; justify-content: center; gap: 6px;\n width: 100%; height: 36px; margin-top: 8px;\n border: .5px solid var(--rm-border); border-radius: 10px;\n background: var(--dsw-alias-button-elevated-fill, var(--rm-panel));\n color: var(--rm-label); cursor: pointer; font-weight: 500; font-size: 13.5px;\n}\n.rm-new-room:hover { background: var(--dsw-alias-button-floating-hover, var(--rm-hover)); }\n.rm-new-room svg { flex: none; }\n\n/* Wide / landscape create + browse modals (overrides default 380px Modal card) */\n.rm-modal-wide {\n width: min(720px, calc(100vw - 48px)) !important;\n max-height: min(640px, calc(100vh - 48px));\n}\n.rm-form-wide {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px 18px;\n align-items: start;\n}\n.rm-form-wide .rm-span-2 { grid-column: 1 / -1; }\n.rm-browse { display: flex; flex-direction: column; gap: 12px; min-height: 280px; max-height: 420px; }\n.rm-browse-search { flex: none; }\n.rm-browse-status { font-size: 11.5px; color: var(--rm-quiet); white-space: nowrap; }\n.rm-browse-list { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 6px; }\n@media (max-width: 640px) {\n .rm-form-wide { grid-template-columns: 1fr; }\n .rm-modal-wide { width: min(420px, calc(100vw - 32px)) !important; }\n}\n\n\n/* \u2500\u2500 panel layout: rooms nav (grouped by native dsh workspace) + content \u2500\u2500 */\n.rm-main { flex-direction: row; }\n.rm-main-body { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; }\n.rm-main-body > .rm-welcome-wrap { flex: 1; }\n.rm-main-body > .rm-workspace { flex: 1; }\n.rm-nav {\n flex: 0 0 248px; width: 248px; display: flex; flex-direction: column; gap: 8px; min-height: 0;\n padding: 10px 8px; border-right: .5px solid var(--rm-border); background: var(--rm-bg);\n}\n.rm-nav-head { display: flex; align-items: center; gap: 4px; padding: 0 4px; }\n.rm-nav-scroll { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 10px; }\n.rm-ws-group { display: flex; flex-direction: column; gap: 2px; }\n.rm-ws-head {\n display: flex; align-items: center; gap: 6px; height: 30px; padding: 0 2px 0 8px;\n font-size: 12.5px; font-weight: 600; color: var(--rm-muted);\n}\n.rm-ws-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-ws-add { width: 24px; height: 24px; }\n.rm-ws-empty { padding: 2px 10px 6px 30px; font-size: 11.5px; }\n.rm-nav .rm-room-item { padding: 6px 8px 6px 14px; }\n.rm-session-mark { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; color: var(--rm-accent, var(--dsw-alias-state-business-primary)); }\n\n/* \u2500\u2500 local multi-agent (0.3) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-dot-busy { background: var(--dsw-alias-state-warning-primary, #f0a020); }\n.rm-agent-tag { display: inline-flex; align-items: center; gap: 3px; margin-left: 6px; padding: 0 6px; border-radius: 999px; font-size: 10.5px; line-height: 17px; color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 12%, transparent); white-space: nowrap; }\n.rm-msg-id { margin-left: 6px; font-size: 11px; color: var(--rm-quiet); font-family: var(--dsw-font-mono, ui-monospace, monospace); }\n.rm-agent-row { display: flex; align-items: center; gap: 8px; padding: 6px 4px; border-radius: 8px; }\n.rm-agent-row:hover { background: var(--rm-hover); }\n.rm-agent-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }\n.rm-agent-name { font-size: 13px; font-weight: 600; color: var(--rm-label); display: flex; align-items: center; }\n.rm-agent-sub { font-size: 11px; color: var(--rm-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.rm-agent-row .rm-member-actions { display: inline-flex !important; opacity: 0.65; }\n.rm-agent-row:hover .rm-member-actions { opacity: 1; }\n.rm-num-row { display: flex; gap: 8px; margin: 4px 0 8px; }\n.rm-num-setting { flex: 1; display: flex; flex-direction: column; gap: 3px; font-size: 11px; color: var(--rm-muted); }\n.rm-num-setting input { width: 100%; box-sizing: border-box; padding: 5px 8px; border: 1px solid var(--rm-border); border-radius: 7px; background: var(--rm-bg); color: var(--rm-label); font: inherit; font-size: 13px; }\n.rm-runs { display: flex; flex-direction: column; gap: 4px; }\n.rm-run { display: grid; grid-template-columns: 22px auto 1fr auto; align-items: center; gap: 6px; padding: 5px 6px; border-radius: 7px; font-size: 12px; border: 1px solid var(--rm-border); }\n.rm-run-running { border-color: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #f0a020) 55%, transparent); background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #f0a020) 8%, transparent); }\n.rm-run-queued, .rm-run-approval { border-style: dashed; }\n.rm-run-done, .rm-run-stopped, .rm-run-failed { opacity: 0.7; }\n.rm-run-pos { font-size: 11px; color: var(--rm-quiet); text-align: center; font-variant-numeric: tabular-nums; }\n.rm-run-who { font-weight: 600; color: var(--rm-label); white-space: nowrap; }\n.rm-run-what { color: var(--rm-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }\n.rm-stop-btn { display: inline-flex; align-items: center; gap: 5px; height: 26px; padding: 0 10px; border-radius: 999px; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-danger-primary, #e5484d) 60%, transparent); background: color-mix(in srgb, var(--dsw-alias-state-danger-primary, #e5484d) 10%, transparent); color: var(--dsw-alias-state-danger-primary, #e5484d); font-size: 12px; cursor: pointer; white-space: nowrap; }\n.rm-stop-btn:hover { background: color-mix(in srgb, var(--dsw-alias-state-danger-primary, #e5484d) 18%, transparent); }\n.rm-badge-local { color: var(--dsw-alias-state-success-primary, #2bb673); }\n.rm-session-agent { color: var(--rm-accent, #5b8cff); }\n.rm-preset-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }\n.rm-preset { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 150px; flex: 1; padding: 8px 10px; border: 1px solid var(--rm-border); border-radius: 10px; background: transparent; color: var(--rm-label); text-align: left; cursor: pointer; font: inherit; font-size: 12px; }\n.rm-preset span { color: var(--rm-muted); font-size: 11px; line-height: 1.35; }\n.rm-preset.is-on { border-color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 12%, transparent); }\n.rm-preset-check { flex-direction: row; align-items: center; gap: 8px; min-width: 120px; flex: 0 1 auto; }\n.rm-local-box { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; border: 1px dashed var(--rm-border); border-radius: 12px; }\n.rm-textarea { width: 100%; box-sizing: border-box; min-height: 84px; resize: vertical; font: inherit; font-size: 13px; padding: 8px 10px; }\n.rm-switch-col { display: flex; flex-direction: column; gap: 6px; }\n.rm-modal-xl { width: min(1180px, 96vw) !important; max-width: 96vw !important; }\n.rm-merge { display: grid; grid-template-columns: 260px 1fr; gap: 14px; min-height: 420px; }\n.rm-merge-list { display: flex; flex-direction: column; gap: 6px; border-right: 1px solid var(--rm-border); padding-right: 12px; }\n.rm-merge-agent { display: flex; align-items: center; gap: 8px; padding: 8px; border: 1px solid transparent; border-radius: 10px; background: transparent; color: var(--rm-label); cursor: pointer; text-align: left; font: inherit; }\n.rm-merge-agent:hover { background: var(--rm-hover); }\n.rm-merge-agent.is-on { border-color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 10%, transparent); }\n.rm-merge-agent-body { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: 12px; }\n.rm-merge-agent-body .rm-mono { font-size: 10.5px; color: var(--rm-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.rm-merge-main { min-width: 0; display: flex; flex-direction: column; gap: 8px; }\n.rm-merge-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; font-size: 13px; }\n.rm-merge-files { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12px; }\n.rm-confirm-text { font-size: 12px; color: var(--rm-label); margin-right: 4px; }\n.rm-diff { margin: 0; max-height: 52vh; overflow: auto; padding: 8px 0; border: 1px solid var(--rm-border); border-radius: 10px; background: var(--rm-panel); font-family: var(--dsw-font-mono, ui-monospace, monospace); font-size: 12px; line-height: 1.5; }\n.rm-diff > div { padding: 0 12px; white-space: pre; }\n.rm-diff-add { background: color-mix(in srgb, #2bb673 16%, transparent); }\n.rm-diff-del { background: color-mix(in srgb, #e5484d 16%, transparent); }\n.rm-diff-hunk { color: var(--rm-accent, #5b8cff); }\n.rm-diff-head, .rm-diff-file { color: var(--rm-muted); font-weight: 600; }\n.rm-diff-addn { color: #2bb673; }\n.rm-diff-deln { color: #e5484d; }\n.rm-ok { padding: 8px 10px; border-radius: 8px; font-size: 12.5px; color: var(--dsw-alias-state-success-primary, #2bb673); background: color-mix(in srgb, #2bb673 10%, transparent); }\n';
2220
+ var rooms_default = '/* Collab Rooms UI \u2014 original surface inside the dsh shell. Uses only dsh --dsw-* tokens.\n Independent Rooms surface. Prefix: rm- (rooms). */\n\n.rm-root {\n --rm-accent: var(--dsw-alias-state-business-primary);\n --rm-hover: var(--dsw-alias-interactive-bg-hover);\n --rm-border: var(--dsw-alias-border-l2);\n --rm-bg: var(--dsw-alias-bg-base);\n --rm-panel: var(--dsw-alias-bg-module-platform);\n --rm-label: var(--dsw-alias-label-primary);\n --rm-muted: var(--dsw-alias-label-secondary);\n --rm-quiet: var(--dsw-alias-label-tertiary);\n font: 13px/1.5 var(--dsw-font-family);\n color: var(--rm-label);\n box-sizing: border-box;\n}\n.rm-root *, .rm-root *::before, .rm-root *::after { box-sizing: border-box; }\n.rm-root button, .rm-root input, .rm-root textarea { font: inherit; }\n\n/* \u2500\u2500 sidebar (joined rooms + public search) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-side {\n display: flex; flex-direction: column; height: 100%; min-height: 0;\n padding: 0 8px 8px 0; gap: 8px;\n}\n.rm-side-toolbar {\n display: flex; align-items: center; gap: 6px; flex: none; padding: 4px 0 2px;\n}\n.rm-side-title {\n flex: 1; font-size: 12px; font-weight: 600; letter-spacing: .04em;\n text-transform: uppercase; color: var(--rm-quiet);\n}\n.rm-icon-btn {\n width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;\n border: 0; border-radius: 8px; background: transparent; color: var(--rm-muted); cursor: pointer; padding: 0;\n}\n.rm-icon-btn:hover { background: var(--rm-hover); color: var(--rm-label); }\n.rm-search {\n display: flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px;\n border: .5px solid var(--rm-border); border-radius: 8px; background: var(--rm-panel);\n}\n.rm-search input {\n flex: 1; min-width: 0; border: 0; background: transparent; outline: none; color: var(--rm-label); font-size: 13px;\n}\n.rm-search input::placeholder { color: var(--rm-quiet); }\n.rm-side-scroll { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 12px; }\n.rm-group-label { font-size: 11px; font-weight: 600; color: var(--rm-quiet); padding: 0 4px 4px; text-transform: uppercase; letter-spacing: .03em; }\n.rm-room-list { display: flex; flex-direction: column; gap: 2px; }\n.rm-room-item {\n display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 10px;\n border: 0; border-radius: 10px; background: transparent; color: inherit; cursor: pointer; text-align: left;\n}\n.rm-room-item:hover { background: var(--rm-hover); }\n.rm-room-item[aria-current="true"] { background: var(--rm-hover); }\n.rm-room-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }\n.rm-room-item-name { font-weight: 600; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-room-item-meta { font-size: 11.5px; color: var(--rm-quiet); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-room-item-trail { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }\n.rm-badge {\n display: inline-flex; align-items: center; gap: 3px; height: 18px; padding: 0 6px;\n border-radius: 999px; font-size: 10.5px; font-weight: 500; background: var(--rm-panel); color: var(--rm-muted);\n border: .5px solid var(--rm-border);\n}\n.rm-badge-public { color: var(--rm-accent); border-color: color-mix(in srgb, var(--rm-accent) 35%, transparent); background: color-mix(in srgb, var(--rm-accent) 8%, transparent); }\n.rm-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--rm-quiet); }\n.rm-dot-online { background: var(--dsw-alias-state-success-primary, #2bb673); }\n.rm-dot-connecting { background: var(--dsw-alias-state-warn-primary, #e9a23b); }\n.rm-dot-offline { background: var(--dsw-alias-state-error-primary, #e5484d); }\n.rm-empty-hint { padding: 8px 10px; font-size: 12px; color: var(--rm-quiet); line-height: 1.45; }\n.rm-dir-item {\n display: flex; align-items: flex-start; gap: 10px; padding: 10px; border-radius: 10px;\n border: .5px solid var(--rm-border); background: var(--rm-bg); margin-bottom: 6px;\n}\n.rm-dir-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }\n.rm-dir-tags { display: flex; flex-wrap: wrap; gap: 4px; }\n.rm-tag { font-size: 11px; color: var(--rm-muted); background: var(--rm-hover); border-radius: 4px; padding: 0 5px; }\n.rm-menu {\n position: fixed; z-index: 1000; min-width: 180px; padding: 4px;\n border-radius: 10px; background: var(--dsw-alias-bg-layer-1, var(--rm-bg));\n border: .5px solid var(--rm-border);\n box-shadow: 0 8px 24px color-mix(in srgb, var(--rm-label) 12%, transparent);\n display: flex; flex-direction: column;\n}\n.rm-menu button {\n display: flex; align-items: center; gap: 8px; height: 32px; padding: 0 10px;\n border: 0; border-radius: 6px; background: transparent; color: var(--rm-label); cursor: pointer; text-align: left;\n}\n.rm-menu button:hover { background: var(--rm-hover); }\n\n/* \u2500\u2500 main: room workspace \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-main { display: flex; flex: 1; min-height: 0; height: 100%; width: 100%; background: var(--rm-bg); }\n.rm-workspace { display: flex; flex: 1; min-width: 0; min-height: 0; }\n.rm-chat { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; }\n.rm-chat-header {\n flex: none; display: flex; align-items: center; gap: 10px; height: 48px;\n padding: 0 16px; border-bottom: .5px solid var(--rm-border);\n}\n.rm-chat-header-title { font-size: 14px; font-weight: 600; }\n.rm-chat-header-sub { font-size: 12px; color: var(--rm-quiet); }\n.rm-messages {\n flex: 1; min-height: 0; overflow: auto; padding: 16px 18px 8px;\n display: flex; flex-direction: column; gap: 2px;\n}\n.rm-day {\n align-self: center; margin: 10px 0 12px; padding: 2px 10px; border-radius: 999px;\n font-size: 11px; color: var(--rm-quiet); background: var(--dsw-alias-button-elevated-fill, var(--rm-panel));\n}\n.rm-msg {\n display: grid; grid-template-columns: 32px 1fr; gap: 0 10px; padding: 4px 6px; border-radius: 8px;\n max-width: 720px;\n}\n.rm-msg:hover { background: color-mix(in srgb, var(--rm-hover) 60%, transparent); }\n.rm-msg-self { margin-left: auto; grid-template-columns: 1fr; max-width: 640px; }\n.rm-msg-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 1px; }\n.rm-msg-author { font-size: 12px; font-weight: 600; color: var(--rm-muted); }\n.rm-msg-time { font-size: 11px; color: var(--rm-quiet); }\n.rm-msg-body { font-size: 13.5px; line-height: 1.55; white-space: pre-wrap; word-break: break-word; }\n.rm-msg-self .rm-msg-body {\n background: var(--dsw-alias-label-primary); color: var(--dsw-alias-label-primary-foreground);\n padding: 8px 12px; border-radius: 12px 12px 4px 12px; width: fit-content; margin-left: auto;\n}\n.rm-msg-event {\n grid-template-columns: 1fr; max-width: 560px; margin: 6px 0;\n padding: 8px 12px; border: .5px solid var(--rm-border); border-radius: 10px; background: var(--rm-panel);\n}\n.rm-mention { color: var(--rm-accent); font-weight: 500; }\n.rm-msg-self .rm-mention { color: inherit; text-decoration: underline; text-underline-offset: 2px; }\n.rm-task-card { display: flex; flex-direction: column; gap: 4px; }\n.rm-task-head { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--rm-muted); }\n.rm-task-title { font-weight: 600; font-size: 13.5px; }\n.rm-composer {\n flex: none; display: flex; align-items: flex-end; gap: 8px; padding: 10px 16px 14px;\n border-top: .5px solid var(--rm-border);\n}\n.rm-composer-box {\n flex: 1; display: flex; align-items: flex-end; gap: 6px; min-height: 44px;\n padding: 8px 10px; border: .5px solid var(--rm-border); border-radius: 12px; background: var(--rm-panel);\n}\n.rm-composer-box:focus-within { border-color: color-mix(in srgb, var(--rm-accent) 50%, var(--rm-border)); }\n.rm-composer-box textarea {\n flex: 1; min-height: 28px; max-height: 120px; border: 0; background: transparent; outline: none;\n resize: none; color: var(--rm-label); line-height: 1.45;\n}\n.rm-composer-box textarea::placeholder { color: var(--rm-quiet); }\n.rm-composer-mode {\n width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;\n border: 0; border-radius: 8px; background: transparent; color: var(--rm-muted); cursor: pointer; flex: none;\n}\n.rm-composer-mode:hover, .rm-composer-mode[aria-pressed="true"] {\n color: var(--rm-accent); background: color-mix(in srgb, var(--rm-accent) 12%, transparent);\n}\n.rm-chat-hint { margin: 48px auto; text-align: center; color: var(--rm-quiet); font-size: 13px; max-width: 360px; line-height: 1.5; }\n\n/* \u2500\u2500 detail column (members / invite / about) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-detail {\n flex: 0 0 280px; width: 280px; display: flex; flex-direction: column; min-height: 0;\n border-left: .5px solid var(--rm-border); background: var(--rm-bg); overflow: auto;\n}\n.rm-detail-section { padding: 14px 14px 8px; border-bottom: .5px solid var(--rm-border); }\n.rm-detail-section:last-child { border-bottom: 0; }\n.rm-detail-h {\n display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600;\n text-transform: uppercase; letter-spacing: .04em; color: var(--rm-quiet); margin-bottom: 8px;\n}\n.rm-member {\n display: flex; align-items: center; gap: 8px; padding: 5px 4px; border-radius: 8px; min-height: 34px;\n}\n.rm-member:hover { background: var(--rm-hover); }\n.rm-member-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }\n.rm-member-actions { display: none; gap: 2px; }\n.rm-member:hover .rm-member-actions, .rm-member:focus-within .rm-member-actions { display: inline-flex; }\n.rm-mini {\n width: 24px; height: 24px; display: inline-flex; align-items: center; justify-content: center;\n border: 0; border-radius: 6px; background: transparent; color: var(--rm-muted); cursor: pointer; font-size: 12px;\n}\n.rm-mini:hover { background: var(--dsw-alias-interactive-bg-active); color: var(--rm-label); }\n.rm-task-row { display: flex; align-items: center; gap: 6px; padding: 4px; font-size: 12.5px; }\n.rm-task-row-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-about { display: grid; grid-template-columns: 88px 1fr; gap: 6px 8px; font-size: 12.5px; margin: 0; }\n.rm-about dt { color: var(--rm-quiet); margin: 0; }\n.rm-about dd { margin: 0; min-width: 0; overflow-wrap: anywhere; display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }\n.rm-mono { font-family: var(--dsw-font-markdown-code-block-font-family, ui-monospace, monospace); font-size: 11.5px; }\n.rm-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }\n.rm-danger { color: var(--dsw-alias-state-error-primary, #e5484d) !important; }\n.rm-note { font-size: 12px; color: var(--rm-quiet); line-height: 1.45; margin: 0 0 8px; }\n\n/* \u2500\u2500 empty / welcome \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-welcome-wrap {\n flex: 1; display: flex; align-items: center; justify-content: center; padding: 32px; background: var(--rm-bg);\n}\n.rm-welcome {\n width: min(420px, 100%); display: flex; flex-direction: column; gap: 10px;\n padding: 20px; border-radius: 14px; border: .5px solid var(--rm-border); background: var(--rm-panel);\n}\n.rm-welcome h1 { margin: 0; font-size: 16px; font-weight: 600; }\n.rm-welcome p { margin: 0; font-size: 13px; color: var(--rm-muted); line-height: 1.5; }\n.rm-welcome-actions { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; }\n.rm-welcome-action {\n display: flex; align-items: flex-start; gap: 10px; width: 100%; padding: 10px 12px;\n border: .5px solid var(--rm-border); border-radius: 10px; background: var(--rm-bg);\n color: var(--rm-label); cursor: pointer; text-align: left;\n}\n.rm-welcome-action:hover { background: var(--rm-hover); }\n.rm-welcome-action b { display: block; font-size: 13px; }\n.rm-welcome-action span { display: block; font-size: 12px; color: var(--rm-quiet); margin-top: 2px; }\n\n/* \u2500\u2500 avatars \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-avatar {\n display: inline-flex; align-items: center; justify-content: center; flex: none;\n font-weight: 600; letter-spacing: .02em; user-select: none;\n}\n.rm-avatar-wrap { position: relative; display: inline-flex; flex: none; }\n\n/* \u2500\u2500 dialogs (inside dsh Modal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-form { display: flex; flex-direction: column; gap: 14px; }\n.rm-field { display: flex; flex-direction: column; gap: 6px; }\n.rm-field-label { font-size: 13px; font-weight: 500; }\n.rm-field-hint { font-size: 12px; color: var(--rm-quiet); }\n.rm-name-row { display: flex; align-items: center; gap: 10px; }\n.rm-name-row > :last-child { flex: 1; }\n.rm-switch-row {\n display: flex; align-items: center; justify-content: space-between; gap: 14px;\n padding: 10px 12px; border-radius: 10px; background: var(--rm-panel);\n}\n.rm-error { color: var(--dsw-alias-state-error-primary, #e5484d); font-size: 12.5px; }\n.rm-invite {\n display: block; padding: 10px 12px; border-radius: 8px; background: var(--rm-panel);\n font-family: var(--dsw-font-markdown-code-block-font-family, ui-monospace, monospace);\n font-size: 12px; word-break: break-all; user-select: all;\n}\n\n/* Dual transport + approvals + agent config */\n.rm-mode-row { display: flex; gap: 8px; }\n.rm-mode-btn {\n flex: 1; padding: 10px 12px; border-radius: 10px; border: 1px solid var(--rm-border, #2a2f3a);\n background: transparent; color: inherit; cursor: pointer; font: inherit;\n}\n.rm-mode-btn.is-on { border-color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 16%, transparent); }\n.rm-lan-browse { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; align-items: center; }\n.rm-lan-peer {\n font-size: 12px; padding: 4px 8px; border-radius: 999px; border: 1px solid var(--rm-border, #2a2f3a);\n background: transparent; color: inherit; cursor: pointer;\n}\n.rm-approvals { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--rm-border, #2a2f3a); background: color-mix(in srgb, #f5a524 12%, transparent); }\n.rm-approval { display: flex; gap: 12px; align-items: center; justify-content: space-between; }\n.rm-approval-body { font-size: 13px; }\n.rm-approval-actions { display: flex; gap: 6px; flex-shrink: 0; }\n.rm-input { width: 100%; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--rm-border, #2a2f3a); background: transparent; color: inherit; font: inherit; }\n\n.rm-ws-bar { display: flex; flex-direction: column; gap: 4px; padding: 8px 12px; border-bottom: 1px solid var(--rm-border, #2a2f3a); }\n.rm-ws-chip { display: inline-flex; align-items: center; gap: 6px; align-self: flex-start; padding: 4px 10px; border-radius: 999px; border: 1px solid var(--rm-border, #2a2f3a); background: transparent; color: inherit; cursor: pointer; font: inherit; font-size: 12.5px; }\n.rm-ws-path { font-size: 11px; color: var(--rm-quiet, #8b93a7); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-room-item.is-active { background: color-mix(in srgb, var(--rm-accent, #5b8cff) 12%, transparent); }\n\n/* Native-aligned room composer (mirrors dsh conversation control row) */\n.rm-composer-card {\n box-sizing: border-box;\n width: 100%;\n max-width: 920px;\n margin: 0 auto;\n border-radius: 16px;\n background: var(--rm-elev, var(--rm-panel, #12151c));\n border: 1px solid var(--rm-border, #2a2f3a);\n box-shadow: 0 1px 2px rgba(0,0,0,.06);\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px 0 6px;\n}\n.rm-composer-grow { position: relative; padding: 0 4px; }\n.rm-composer-grow textarea {\n box-sizing: border-box; width: 100%; min-height: 36px; max-height: 160px;\n resize: none; border: none; outline: none; background: transparent;\n color: inherit; font: inherit; font-size: 14px; line-height: 22px;\n padding: 4px 12px 0 14px;\n}\n.rm-composer-grow textarea:disabled { opacity: .55; cursor: not-allowed; }\n.rm-composer-row {\n display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;\n gap: 10px; min-width: 0; padding: 2px 8px 4px;\n}\n.rm-composer-tools, .rm-composer-modes, .rm-composer-trailing {\n display: flex; align-items: center; min-width: 0; gap: 8px;\n}\n.rm-composer-trailing { flex: none; margin-left: auto; }\n.rm-composer-add {\n width: 28px; height: 28px; border: none; border-radius: 999px;\n background: color-mix(in srgb, var(--rm-fg, #e8eaed) 8%, transparent);\n color: inherit; cursor: pointer; display: grid; place-items: center;\n}\n.rm-composer-add:hover, .rm-composer-add[aria-pressed="true"] {\n background: color-mix(in srgb, var(--rm-accent, #5b8cff) 22%, transparent);\n}\n.rm-composer-select {\n max-width: 220px; height: 28px; border: none; border-radius: 8px;\n background: transparent; color: var(--rm-quiet, #8b93a7);\n font: inherit; font-size: 13px; font-weight: 500; line-height: 20px;\n padding: 0 8px; cursor: pointer; white-space: nowrap;\n}\n.rm-composer-select:hover:not(:disabled) {\n background: color-mix(in srgb, var(--rm-fg, #e8eaed) 8%, transparent);\n}\n.rm-composer-select:disabled { opacity: .5; cursor: default; }\n.rm-composer-model-text { display: inline; }\n.rm-composer-model-icon { display: none; font-size: 10px; }\n.rm-composer-effort {\n margin-left: 6px; font-size: 11px; opacity: .75;\n text-transform: uppercase; letter-spacing: .02em;\n}\n.rm-composer-send {\n width: 34px; height: 34px; border: none; border-radius: 999px;\n background: var(--rm-accent, #5b8cff); color: #fff; cursor: pointer;\n display: grid; place-items: center; transform: translateY(-2px);\n}\n.rm-composer-send:hover:not(:disabled) { filter: brightness(1.08); }\n.rm-composer-send:disabled { opacity: .4; cursor: default; }\n.rm-composer-popwrap { position: relative; }\n.rm-composer-menu {\n position: absolute; bottom: calc(100% + 6px); left: 0; z-index: 40;\n min-width: 200px; max-height: 320px; overflow: auto;\n border: 1px solid var(--rm-border, #2a2f3a); border-radius: 12px;\n background: var(--rm-elev, #12151c); box-shadow: 0 8px 24px rgba(0,0,0,.28);\n padding: 6px; display: flex; flex-direction: column; gap: 2px;\n}\n.rm-composer-menu-wide { min-width: 280px; max-width: 340px; }\n.rm-composer-menu-label {\n font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em;\n color: var(--rm-quiet, #8b93a7); padding: 6px 8px 2px;\n}\n.rm-composer-menu button[role="menuitem"] {\n text-align: left; border: none; background: transparent; color: inherit;\n font: inherit; font-size: 13px; padding: 6px 8px; border-radius: 8px; cursor: pointer;\n}\n.rm-composer-menu button[role="menuitem"]:hover,\n.rm-composer-menu button[role="menuitem"].is-active {\n background: color-mix(in srgb, var(--rm-accent, #5b8cff) 16%, transparent);\n}\n.rm-composer-check {\n display: flex; align-items: center; gap: 8px; font-size: 13px; padding: 4px 8px; cursor: pointer;\n}\n.rm-grant-row {\n display: flex; align-items: center; justify-content: space-between; gap: 8px;\n padding: 2px 8px; font-size: 12.5px;\n}\n.rm-grant-row select {\n font: inherit; font-size: 12px; border-radius: 6px;\n border: 1px solid var(--rm-border, #2a2f3a); background: transparent; color: inherit; padding: 2px 6px;\n}\n.rm-peer-grant-block { border-top: 1px solid var(--rm-border, #2a2f3a); padding-top: 4px; margin-top: 4px; }\n.rm-peer-grant-name { font-size: 12px; font-weight: 600; padding: 4px 8px; overflow: hidden; text-overflow: ellipsis; }\n\n/* Hide legacy tight composer if still referenced */\n.rm-composer { display: none; }\n\n.rm-composer-grow { position: relative; }\n.rm-mention-menu {\n position: absolute; left: 8px; right: 8px; bottom: calc(100% + 6px); z-index: 50;\n max-height: 240px; overflow: auto;\n border: 1px solid var(--rm-border, #2a2f3a); border-radius: 12px;\n background: var(--rm-elev, #12151c); box-shadow: 0 10px 28px rgba(0,0,0,.32);\n padding: 4px; display: flex; flex-direction: column; gap: 2px;\n}\n.rm-mention-item {\n display: flex; align-items: center; gap: 8px; text-align: left;\n border: none; background: transparent; color: inherit; font: inherit;\n padding: 6px 8px; border-radius: 8px; cursor: pointer;\n}\n.rm-mention-item:hover, .rm-mention-item.is-active {\n background: color-mix(in srgb, var(--rm-accent, #5b8cff) 18%, transparent);\n}\n.rm-mention-item-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }\n.rm-mention-item-name { font-size: 13px; font-weight: 600; }\n.rm-mention-item-meta { font-size: 11px; color: var(--rm-quiet, #8b93a7); }\n\n\n/* New Room shortcut under workspace (mirrors New Session affordance) */\n.rm-new-room {\n display: flex; align-items: center; justify-content: center; gap: 6px;\n width: 100%; height: 36px; margin-top: 8px;\n border: .5px solid var(--rm-border); border-radius: 10px;\n background: var(--dsw-alias-button-elevated-fill, var(--rm-panel));\n color: var(--rm-label); cursor: pointer; font-weight: 500; font-size: 13.5px;\n}\n.rm-new-room:hover { background: var(--dsw-alias-button-floating-hover, var(--rm-hover)); }\n.rm-new-room svg { flex: none; }\n\n/* Wide / landscape create + browse modals (overrides default 380px Modal card) */\n.rm-modal-wide {\n width: min(720px, calc(100vw - 48px)) !important;\n max-height: min(640px, calc(100vh - 48px));\n}\n.rm-form-wide {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px 18px;\n align-items: start;\n}\n.rm-form-wide .rm-span-2 { grid-column: 1 / -1; }\n.rm-browse { display: flex; flex-direction: column; gap: 12px; min-height: 280px; max-height: 420px; }\n.rm-browse-search { flex: none; }\n.rm-browse-status { font-size: 11.5px; color: var(--rm-quiet); white-space: nowrap; }\n.rm-browse-list { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 6px; }\n@media (max-width: 640px) {\n .rm-form-wide { grid-template-columns: 1fr; }\n .rm-modal-wide { width: min(420px, calc(100vw - 32px)) !important; }\n}\n\n\n/* \u2500\u2500 panel layout: rooms nav (grouped by native dsh workspace) + content \u2500\u2500 */\n.rm-main { flex-direction: row; }\n.rm-main-body { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; }\n.rm-main-body > .rm-welcome-wrap { flex: 1; }\n.rm-main-body > .rm-workspace { flex: 1; }\n.rm-nav {\n flex: 0 0 248px; width: 248px; display: flex; flex-direction: column; gap: 8px; min-height: 0;\n padding: 10px 8px; border-right: .5px solid var(--rm-border); background: var(--rm-bg);\n}\n.rm-nav-head { display: flex; align-items: center; gap: 4px; padding: 0 4px; }\n.rm-nav-scroll { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 10px; }\n.rm-ws-group { display: flex; flex-direction: column; gap: 2px; }\n.rm-ws-head {\n display: flex; align-items: center; gap: 6px; height: 30px; padding: 0 2px 0 8px;\n font-size: 12.5px; font-weight: 600; color: var(--rm-muted);\n}\n.rm-ws-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.rm-ws-add { width: 24px; height: 24px; }\n.rm-ws-empty { padding: 2px 10px 6px 30px; font-size: 11.5px; }\n.rm-nav .rm-room-item { padding: 6px 8px 6px 14px; }\n.rm-session-mark { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; color: var(--rm-accent, var(--dsw-alias-state-business-primary)); }\n\n/* \u2500\u2500 local multi-agent (0.3) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-dot-busy { background: var(--dsw-alias-state-warning-primary, #f0a020); }\n.rm-agent-tag { display: inline-flex; align-items: center; gap: 3px; margin-left: 6px; padding: 0 6px; border-radius: 999px; font-size: 10.5px; line-height: 17px; color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 12%, transparent); white-space: nowrap; }\n.rm-msg-id { margin-left: 6px; font-size: 11px; color: var(--rm-quiet); font-family: var(--dsw-font-mono, ui-monospace, monospace); }\n.rm-agent-row { display: flex; align-items: center; gap: 8px; padding: 6px 4px; border-radius: 8px; }\n.rm-agent-row:hover { background: var(--rm-hover); }\n.rm-agent-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }\n.rm-agent-name { font-size: 13px; font-weight: 600; color: var(--rm-label); display: flex; align-items: center; }\n.rm-agent-sub { font-size: 11px; color: var(--rm-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.rm-agent-row .rm-member-actions { display: inline-flex !important; opacity: 0.65; }\n.rm-agent-row:hover .rm-member-actions { opacity: 1; }\n.rm-num-row { display: flex; gap: 8px; margin: 4px 0 8px; }\n.rm-num-setting { flex: 1; display: flex; flex-direction: column; gap: 3px; font-size: 11px; color: var(--rm-muted); }\n.rm-num-setting input { width: 100%; box-sizing: border-box; padding: 5px 8px; border: 1px solid var(--rm-border); border-radius: 7px; background: var(--rm-bg); color: var(--rm-label); font: inherit; font-size: 13px; }\n.rm-runs { display: flex; flex-direction: column; gap: 4px; }\n.rm-run { display: grid; grid-template-columns: 22px auto 1fr auto; align-items: center; gap: 6px; padding: 5px 6px; border-radius: 7px; font-size: 12px; border: 1px solid var(--rm-border); }\n.rm-run-running { border-color: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #f0a020) 55%, transparent); background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #f0a020) 8%, transparent); }\n.rm-run-queued, .rm-run-approval { border-style: dashed; }\n.rm-run-done, .rm-run-stopped, .rm-run-failed { opacity: 0.7; }\n.rm-run-pos { font-size: 11px; color: var(--rm-quiet); text-align: center; font-variant-numeric: tabular-nums; }\n.rm-run-who { font-weight: 600; color: var(--rm-label); white-space: nowrap; }\n.rm-run-what { color: var(--rm-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }\n.rm-stop-btn { display: inline-flex; align-items: center; gap: 5px; height: 26px; padding: 0 10px; border-radius: 999px; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-danger-primary, #e5484d) 60%, transparent); background: color-mix(in srgb, var(--dsw-alias-state-danger-primary, #e5484d) 10%, transparent); color: var(--dsw-alias-state-danger-primary, #e5484d); font-size: 12px; cursor: pointer; white-space: nowrap; }\n.rm-stop-btn:hover { background: color-mix(in srgb, var(--dsw-alias-state-danger-primary, #e5484d) 18%, transparent); }\n.rm-badge-local { color: var(--dsw-alias-state-success-primary, #2bb673); }\n.rm-session-agent { color: var(--rm-accent, #5b8cff); }\n.rm-preset-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }\n.rm-preset { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 150px; flex: 1; padding: 8px 10px; border: 1px solid var(--rm-border); border-radius: 10px; background: transparent; color: var(--rm-label); text-align: left; cursor: pointer; font: inherit; font-size: 12px; }\n.rm-preset span { color: var(--rm-muted); font-size: 11px; line-height: 1.35; }\n.rm-preset.is-on { border-color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 12%, transparent); }\n.rm-preset-check { flex-direction: row; align-items: center; gap: 8px; min-width: 120px; flex: 0 1 auto; }\n.rm-local-box { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; border: 1px dashed var(--rm-border); border-radius: 12px; }\n.rm-textarea { width: 100%; box-sizing: border-box; min-height: 84px; resize: vertical; font: inherit; font-size: 13px; padding: 8px 10px; }\n.rm-switch-col { display: flex; flex-direction: column; gap: 6px; }\n.rm-modal-xl { width: min(1180px, 96vw) !important; max-width: 96vw !important; }\n.rm-merge { display: grid; grid-template-columns: 260px 1fr; gap: 14px; min-height: 420px; }\n.rm-merge-list { display: flex; flex-direction: column; gap: 6px; border-right: 1px solid var(--rm-border); padding-right: 12px; }\n.rm-merge-agent { display: flex; align-items: center; gap: 8px; padding: 8px; border: 1px solid transparent; border-radius: 10px; background: transparent; color: var(--rm-label); cursor: pointer; text-align: left; font: inherit; }\n.rm-merge-agent:hover { background: var(--rm-hover); }\n.rm-merge-agent.is-on { border-color: var(--rm-accent, #5b8cff); background: color-mix(in srgb, var(--rm-accent, #5b8cff) 10%, transparent); }\n.rm-merge-agent-body { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: 12px; }\n.rm-merge-agent-body .rm-mono { font-size: 10.5px; color: var(--rm-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.rm-merge-main { min-width: 0; display: flex; flex-direction: column; gap: 8px; }\n.rm-merge-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; font-size: 13px; }\n.rm-merge-files { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12px; }\n.rm-confirm-text { font-size: 12px; color: var(--rm-label); margin-right: 4px; }\n.rm-diff { margin: 0; max-height: 52vh; overflow: auto; padding: 8px 0; border: 1px solid var(--rm-border); border-radius: 10px; background: var(--rm-panel); font-family: var(--dsw-font-mono, ui-monospace, monospace); font-size: 12px; line-height: 1.5; }\n.rm-diff > div { padding: 0 12px; white-space: pre; }\n.rm-diff-add { background: color-mix(in srgb, #2bb673 16%, transparent); }\n.rm-diff-del { background: color-mix(in srgb, #e5484d 16%, transparent); }\n.rm-diff-hunk { color: var(--rm-accent, #5b8cff); }\n.rm-diff-head, .rm-diff-file { color: var(--rm-muted); font-weight: 600; }\n.rm-diff-addn { color: #2bb673; }\n.rm-diff-deln { color: #e5484d; }\n.rm-ok { padding: 8px 10px; border-radius: 8px; font-size: 12.5px; color: var(--dsw-alias-state-success-primary, #2bb673); background: color-mix(in srgb, #2bb673 10%, transparent); }\n\n/* \u2500\u2500 create-room dialog (0.3.1): wide, scrollable, tabbed \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.rm-modal-scrollable {\n width: min(920px, calc(100vw - 48px)) !important;\n max-width: 96vw !important;\n /* Bound height so the flex child (.rm-modal-scroll) can scroll instead of clipping. */\n height: min(720px, 100%) !important;\n max-height: 100% !important;\n}\n.rm-modal-create { width: min(960px, calc(100vw - 48px)) !important; }\n.rm-modal-scroll {\n flex: 1 1 auto;\n min-height: 0;\n overflow-x: hidden;\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n.rm-create { display: flex; flex-direction: column; gap: 12px; }\n.rm-tabs {\n display: flex; gap: 4px; padding: 2px; border-radius: 10px;\n background: color-mix(in srgb, var(--rm-border) 55%, transparent);\n flex-wrap: wrap;\n}\n.rm-tab {\n flex: 1 1 auto; min-width: 88px; height: 32px; padding: 0 12px; border: 0; border-radius: 8px;\n background: transparent; color: var(--rm-muted); font: inherit; font-size: 13px; font-weight: 560;\n cursor: pointer;\n}\n.rm-tab.is-on { background: var(--rm-panel, var(--dsw-alias-bg-layer-2)); color: var(--rm-label); box-shadow: 0 0 0 1px var(--rm-border); }\n.rm-create-pane { min-height: 280px; }\n.rm-mode-wrap { flex-wrap: wrap; }\n.rm-preset-sub { display: block; color: var(--rm-muted); font-size: 11px; font-weight: 400; line-height: 1.35; margin-top: 1px; }\n.rm-create-custom {\n margin-top: 14px; padding: 12px; border: 1px dashed var(--rm-border); border-radius: 12px;\n display: flex; flex-direction: column; gap: 10px;\n}\n.rm-create-custom-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }\n.rm-draft-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }\n.rm-draft-item {\n display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 8px;\n border: 1px solid var(--rm-border); background: var(--rm-panel);\n}\n.rm-draft-main { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: 12.5px; }\n.rm-draft-main span { color: var(--rm-muted); font-size: 11px; }\n.rm-draft-form { margin-top: 4px; padding-top: 10px; border-top: 1px dashed var(--rm-border); }\n.rm-linkish { background: none; border: 0; color: var(--rm-accent, #5b8cff); cursor: pointer; font: inherit; font-size: inherit; padding: 0; text-decoration: underline; }\n@media (max-width: 720px) {\n .rm-modal-create, .rm-modal-scrollable { width: min(100vw - 24px, 520px) !important; }\n}\n';
2051
2221
 
2052
2222
  // src/client/store.js
2053
2223
  var API = "/api/collab";
2054
2224
  async function call(path, init) {
2055
- const res = await fetch(API + path, { credentials: "same-origin", ...init, headers: { ...init && init.body ? { "content-type": "application/json" } : {}, ...init && init.headers || {} } });
2056
- const body = await res.json().catch(() => ({}));
2057
- if (!res.ok) throw new Error(body.error || `${res.status} ${res.statusText}`);
2225
+ let res;
2226
+ try {
2227
+ res = await fetch(API + path, { credentials: "same-origin", ...init, headers: { ...init && init.body ? { "content-type": "application/json" } : {}, ...init && init.headers || {} } });
2228
+ } catch (e) {
2229
+ const msg = e && e.name === "AbortError" ? "Request timed out or was cancelled" : e && e.message || "network error";
2230
+ throw new Error(msg);
2231
+ }
2232
+ const text = await res.text();
2233
+ let body = {};
2234
+ try {
2235
+ body = text ? JSON.parse(text) : {};
2236
+ } catch {
2237
+ body = { error: text.slice(0, 300) || res.statusText };
2238
+ }
2239
+ if (!res.ok) {
2240
+ const detail = body.error || body.message || (typeof body.raw === "string" ? body.raw : "") || `${res.status} ${res.statusText}`;
2241
+ throw new Error(detail);
2242
+ }
2058
2243
  return body;
2059
2244
  }
2060
- var post = (path, body) => call(path, { method: "POST", body: JSON.stringify(body || {}) });
2245
+ var post = (path, body, init) => call(path, { method: "POST", body: JSON.stringify(body || {}), ...init || {} });
2061
2246
  function createRoomsStore() {
2062
2247
  let snap = {
2063
2248
  self: null,
@@ -2162,15 +2347,22 @@ function createRoomsStore() {
2162
2347
  clearTimeout(searchTimer);
2163
2348
  searchTimer = setTimeout(() => void runSearch(query), 300);
2164
2349
  },
2165
- async create(form) {
2166
- const r = await post("/rooms", { ...form, workspaceId: form.workspacePath ? void 0 : form.workspaceId || snap.activeWorkspaceId });
2350
+ async create(form, opts) {
2351
+ const ac = opts && opts.signal ? null : new AbortController();
2352
+ const signal = opts && opts.signal || ac.signal;
2353
+ const timer = ac ? setTimeout(() => ac.abort(), opts && opts.timeoutMs || 3e4) : null;
2167
2354
  try {
2168
- api.onRoomOpened && api.onRoomOpened();
2169
- } catch {
2355
+ const r = await post("/rooms", { ...form, workspaceId: form.workspacePath ? void 0 : form.workspaceId || snap.activeWorkspaceId }, { signal });
2356
+ try {
2357
+ api.onRoomOpened && api.onRoomOpened();
2358
+ } catch {
2359
+ }
2360
+ set({ selected: r.roomId, dialog: { kind: "invite", roomId: r.roomId, name: r.name, invite: r.invite, public: r.public, listed: r.listed } });
2361
+ void loadMessages(r.roomId);
2362
+ return r;
2363
+ } finally {
2364
+ if (timer) clearTimeout(timer);
2170
2365
  }
2171
- set({ selected: r.roomId, dialog: { kind: "invite", roomId: r.roomId, name: r.name, invite: r.invite, public: r.public, listed: r.listed } });
2172
- void loadMessages(r.roomId);
2173
- return r;
2174
2366
  },
2175
2367
  async join(invite, info) {
2176
2368
  const r = await post("/join", { invite, ...info && info.workspacePath ? {} : { workspaceId: snap.activeWorkspaceId }, ...info || {} });
@@ -2989,8 +3181,8 @@ function LocalAgentsSection({ room, store, mention }) {
2989
3181
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mini", title: `Edit ${ag.name}`, "aria-label": `Edit ${ag.name}`, onClick: () => a.openDialog({ kind: "agent", roomId: room.roomId, agentId: ag.agentId }), children: "\u270E" })
2990
3182
  ] })
2991
3183
  ] }, ag.agentId)),
2992
- !local.agents.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "rm-note", children: "Host several agents from this dsh as separate members \u2014 each with its own identity, session and scope." }) : null,
2993
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-actions", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlusIcon, {}), onClick: () => a.openDialog({ kind: "agent", roomId: room.roomId }), children: "Add local agent" }) })
3184
+ !local.agents.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "rm-note", children: "Add a custom agent (free-form name, prompt, model, scope) or start from a preset. Each gets its own identity, session and scope." }) : null,
3185
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-actions", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlusIcon, {}), onClick: () => a.openDialog({ kind: "agent", roomId: room.roomId }), children: "Add agent" }) })
2994
3186
  ] });
2995
3187
  }
2996
3188
  function NumberSetting({ label, value, min, max, onSave, hint }) {
@@ -3105,14 +3297,16 @@ function AgentDialog({ store, d }) {
3105
3297
  const room = (s.rooms || []).find((r) => r.roomId === d.roomId);
3106
3298
  const existing = room && room.local ? room.local.agents.find((x) => x.agentId === d.agentId) : null;
3107
3299
  const [presets, setPresets] = (0, import_react.useState)([]);
3108
- const [f, setF] = (0, import_react.useState)(() => existing ? { name: existing.name, persona: existing.persona || "", systemPrompt: existing.systemPrompt || "", model: existing.model || "", reasoningEffort: existing.reasoningEffort || "medium", scope: existing.scope, approvalRequired: !!existing.approvalRequired, moderator: !!existing.moderator } : { preset: "", name: "", persona: "", systemPrompt: "", model: "", reasoningEffort: "medium", scope: "read", approvalRequired: false, moderator: false });
3300
+ const blank = () => ({ preset: "", name: "", persona: "", systemPrompt: "", model: "", reasoningEffort: "medium", scope: "read", approvalRequired: false, moderator: false });
3301
+ const [f, setF] = (0, import_react.useState)(() => existing ? { preset: "", name: existing.name, persona: existing.persona || "", systemPrompt: existing.systemPrompt || "", model: existing.model || "", reasoningEffort: existing.reasoningEffort || "medium", scope: existing.scope, approvalRequired: !!existing.approvalRequired, moderator: !!existing.moderator } : blank());
3109
3302
  const [err, setErr] = (0, import_react.useState)(null);
3110
3303
  const [busy, setBusy] = (0, import_react.useState)(false);
3111
3304
  (0, import_react.useEffect)(() => {
3112
3305
  a.presets().then(setPresets).catch(() => {
3113
3306
  });
3114
3307
  }, []);
3115
- const pick = (p) => setF({ ...f, preset: p.key, name: p.name, persona: p.persona, systemPrompt: p.systemPrompt, scope: p.scope, moderator: !!p.moderator, reasoningEffort: p.reasoningEffort || "medium" });
3308
+ const pick = (p) => setF({ ...f, preset: p.key, name: p.name, persona: p.persona || "", systemPrompt: p.systemPrompt || "", scope: p.scope, moderator: !!p.moderator, reasoningEffort: p.reasoningEffort || "medium" });
3309
+ const clearPreset = () => setF({ ...f, preset: "" });
3116
3310
  const submit = async () => {
3117
3311
  if (!f.name.trim()) {
3118
3312
  setErr("Name required");
@@ -3121,15 +3315,16 @@ function AgentDialog({ store, d }) {
3121
3315
  setBusy(true);
3122
3316
  setErr(null);
3123
3317
  try {
3124
- const body = { name: f.name, persona: f.persona, systemPrompt: f.systemPrompt, model: f.model, reasoningEffort: f.reasoningEffort, scope: f.scope, approvalRequired: f.approvalRequired, moderator: f.moderator, preset: f.preset || void 0 };
3318
+ const body = { name: f.name.trim(), persona: f.persona, systemPrompt: f.systemPrompt, model: f.model || void 0, reasoningEffort: f.reasoningEffort, scope: f.scope, approvalRequired: f.approvalRequired, moderator: f.moderator };
3125
3319
  if (existing) await a.updateAgent(d.roomId, existing.agentId, body);
3126
3320
  else {
3127
- const r = await a.addAgent(d.roomId, body);
3128
- a.toast(`${r.name} joined as @${r.agentId}`);
3321
+ const r = await a.addAgent(d.roomId, f.preset ? { ...body, preset: f.preset } : body);
3322
+ a.toast(`${r.name} added as @${r.agentId} (joining in background)`);
3129
3323
  }
3130
3324
  a.closeDialog();
3131
3325
  } catch (e) {
3132
3326
  setErr(e.message);
3327
+ } finally {
3133
3328
  setBusy(false);
3134
3329
  }
3135
3330
  };
@@ -3151,8 +3346,9 @@ function AgentDialog({ store, d }) {
3151
3346
  onClose: a.closeDialog,
3152
3347
  title: existing ? `Edit ${existing.name}` : "Add local agent",
3153
3348
  closeLabel: "Close",
3154
- className: "rm-modal-wide",
3155
- description: existing ? `Member @${existing.agentId} \xB7 own identity and dsh session in this room's workspace.` : "Runs on this dsh as a separate room member: own keypair, own session, own scope. Remote peers see it as a member.",
3349
+ className: "rm-modal-wide rm-modal-scrollable",
3350
+ contentClassName: "rm-modal-scroll",
3351
+ description: existing ? `Member @${existing.agentId} \xB7 own identity and dsh session in this room's workspace.` : "Free-form agent: own name, persona, prompt, model, scope. Presets only fill the form \u2014 you can edit every field. Remote peers see it as a separate member.",
3156
3352
  footer: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
3157
3353
  existing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "ghost", className: "rm-danger", disabled: busy, onClick: remove, children: "Remove" }) : null,
3158
3354
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1 } }),
@@ -3161,15 +3357,26 @@ function AgentDialog({ store, d }) {
3161
3357
  ] }),
3162
3358
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-root rm-form rm-form-wide", "data-rm-agent-form": "", children: [
3163
3359
  !existing ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-span-2", children: [
3164
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Preset" }),
3165
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-preset-row", children: presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "rm-preset" + (f.preset === p.key ? " is-on" : ""), onClick: () => pick(p), children: [
3166
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: p.name }),
3167
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: p.persona })
3168
- ] }, p.key)) })
3360
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Start from" }),
3361
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: "Presets fill the fields below; switch to Custom anytime and edit freely." }),
3362
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-preset-row", children: [
3363
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "rm-preset" + (!f.preset ? " is-on" : ""), onClick: () => setF(blank()), children: [
3364
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: "Custom" }),
3365
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Blank form \u2014 your name, prompt, model" })
3366
+ ] }),
3367
+ presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "rm-preset" + (f.preset === p.key ? " is-on" : ""), onClick: () => pick(p), children: [
3368
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: p.name }),
3369
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: p.persona })
3370
+ ] }, p.key))
3371
+ ] })
3169
3372
  ] }) : null,
3170
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Name", htmlFor: "rm-ag-name", hint: "Member id is derived from it (e.g. coder.ab12).", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-ag-name", value: f.name, maxLength: 40, onChange: (e) => setF({ ...f, name: e.target.value }), placeholder: "e.g. Coder" }) }),
3171
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Persona", htmlFor: "rm-ag-persona", hint: "One line other members see.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-ag-persona", value: f.persona, maxLength: 200, onChange: (e) => setF({ ...f, persona: e.target.value }), placeholder: "e.g. Implements changes" }) }),
3172
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "System prompt", htmlFor: "rm-ag-sp", hint: "Prepended to every wake of this agent.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", { id: "rm-ag-sp", className: "rm-input rm-textarea", rows: 4, value: f.systemPrompt, maxLength: 4e3, onChange: (e) => setF({ ...f, systemPrompt: e.target.value }) }) }) }),
3373
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Name", htmlFor: "rm-ag-name", hint: "Member id is derived from it (e.g. coder.ab12).", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-ag-name", value: f.name, maxLength: 40, onChange: (e) => {
3374
+ const name2 = e.target.value;
3375
+ const presetName = (presets.find((p) => p.key === f.preset) || {}).name;
3376
+ setF({ ...f, name: name2, preset: f.preset && name2 !== presetName ? "" : f.preset });
3377
+ }, placeholder: "e.g. Data wrangler" }) }),
3378
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Persona", htmlFor: "rm-ag-persona", hint: "One line other members see.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-ag-persona", value: f.persona, maxLength: 200, onChange: (e) => setF({ ...f, persona: e.target.value, ...f.preset ? { preset: "" } : {} }), placeholder: "e.g. Cleans CSVs and writes summaries" }) }),
3379
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "System prompt", htmlFor: "rm-ag-sp", hint: "Prepended to every wake of this agent.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", { id: "rm-ag-sp", className: "rm-input rm-textarea", rows: 4, value: f.systemPrompt, maxLength: 4e3, onChange: (e) => setF({ ...f, systemPrompt: e.target.value, ...f.preset ? { preset: "" } : {} }), placeholder: "You are \u2026 Focus on \u2026 Report back with \u2026" }) }) }),
3173
3380
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Model", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { className: "rm-input", "aria-label": "Model", value: f.model, onChange: (e) => setF({ ...f, model: e.target.value }), children: [
3174
3381
  MODEL_CHOICES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: m, children: m || "dsh default model" }, m)),
3175
3382
  f.model && !MODEL_CHOICES.includes(f.model) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: f.model, children: f.model }) : null
@@ -3196,6 +3403,12 @@ function AgentDialog({ store, d }) {
3196
3403
  ] })
3197
3404
  ] }),
3198
3405
  f.scope === "write" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2 rm-note", children: "Writes go to its own git worktree (branch room/<room>/<agent>) when the workspace is a git repo; you merge from \u201CReview & merge\u201D. Non-git workspaces use file locks." }) : null,
3406
+ f.preset ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-span-2 rm-note", children: [
3407
+ "Filled from the ",
3408
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: f.preset }),
3409
+ " preset \u2014 editing any field switches to Custom. ",
3410
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-linkish", onClick: clearPreset, children: "Clear preset tag" })
3411
+ ] }) : null,
3199
3412
  err ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2 rm-error", children: err }) : null
3200
3413
  ] })
3201
3414
  }
@@ -3434,35 +3647,88 @@ function Field({ label, hint, children, htmlFor }) {
3434
3647
  function CreateDialog({ store, d }) {
3435
3648
  const s = useStore(store);
3436
3649
  const a = store.actions;
3437
- const [f, setF] = (0, import_react.useState)({ name: "", description: "", tags: "", public: false, mode: "lan", lanHostPort: "62.234.113.56:80", localOnly: false, agents: [] });
3650
+ const [tab, setTab] = (0, import_react.useState)("room");
3651
+ const [f, setF] = (0, import_react.useState)({
3652
+ name: "",
3653
+ description: "",
3654
+ tags: "",
3655
+ public: false,
3656
+ transport: "relay",
3657
+ // local | relay | lan | cloudflare
3658
+ lanHostPort: "62.234.113.56:80",
3659
+ turnLimit: 6,
3660
+ concurrency: 2,
3661
+ isolation: "auto",
3662
+ agents: []
3663
+ // draft agents: { key?, name, persona, systemPrompt, scope, moderator, reasoningEffort, approvalRequired, model }
3664
+ });
3665
+ const [draft, setDraft] = (0, import_react.useState)({ name: "", persona: "", systemPrompt: "", scope: "read", moderator: false, reasoningEffort: "medium", approvalRequired: false, model: "" });
3666
+ const [showCustom, setShowCustom] = (0, import_react.useState)(false);
3438
3667
  const [err, setErr] = (0, import_react.useState)(null);
3439
3668
  const [busy, setBusy] = (0, import_react.useState)(false);
3440
3669
  const [lanPeers, setLanPeers] = (0, import_react.useState)([]);
3670
+ const [presets, setPresets] = (0, import_react.useState)([]);
3441
3671
  const ok = f.name.trim() && !busy;
3442
3672
  const [ws, setWs] = (0, import_react.useState)(d && d.workspace ? d.workspace : null);
3673
+ (0, import_react.useEffect)(() => {
3674
+ a.presets().then(setPresets).catch(() => {
3675
+ });
3676
+ }, []);
3677
+ const togglePreset = (p) => {
3678
+ const has = f.agents.some((x) => x.key === p.key);
3679
+ setF({
3680
+ ...f,
3681
+ agents: has ? f.agents.filter((x) => x.key !== p.key) : [...f.agents, { key: p.key, name: p.name, persona: p.persona, systemPrompt: p.systemPrompt, scope: p.scope, moderator: !!p.moderator, reasoningEffort: p.reasoningEffort || "medium", approvalRequired: false, model: "" }]
3682
+ });
3683
+ };
3684
+ const addCustomDraft = () => {
3685
+ if (!draft.name.trim()) {
3686
+ setErr("Custom agent needs a name");
3687
+ setTab("agents");
3688
+ return;
3689
+ }
3690
+ setF({
3691
+ ...f,
3692
+ agents: [...f.agents, { ...draft, name: draft.name.trim(), key: void 0 }]
3693
+ });
3694
+ setDraft({ name: "", persona: "", systemPrompt: "", scope: "read", moderator: false, reasoningEffort: "medium", approvalRequired: false, model: "" });
3695
+ setShowCustom(false);
3696
+ setErr(null);
3697
+ };
3698
+ const removeDraft = (i) => setF({ ...f, agents: f.agents.filter((_, j) => j !== i) });
3443
3699
  const submit = async () => {
3444
3700
  if (!ok) return;
3445
3701
  if (!ws) {
3446
3702
  setErr("Pick a workspace");
3703
+ setTab("room");
3447
3704
  return;
3448
3705
  }
3449
3706
  setBusy(true);
3450
3707
  setErr(null);
3708
+ const transport = f.transport;
3709
+ const localOnly = transport === "local";
3710
+ const mode = transport === "cloudflare" ? "relay" : "lan";
3711
+ const lanHostPort = transport === "relay" ? f.lanHostPort.trim() || "62.234.113.56:80" : transport === "lan" ? "" : void 0;
3451
3712
  try {
3452
3713
  await a.create({
3453
3714
  name: f.name.trim(),
3454
3715
  description: f.description.trim(),
3455
3716
  tags: f.tags,
3456
- public: f.public,
3457
- mode: f.mode,
3458
- lanHostPort: f.mode === "lan" ? f.lanHostPort.trim() : void 0,
3717
+ public: localOnly ? false : f.public,
3718
+ mode,
3719
+ lanHostPort,
3459
3720
  workspacePath: ws.path,
3460
3721
  workspaceName: ws.title,
3461
- localOnly: f.localOnly,
3462
- agents: f.agents
3463
- });
3722
+ localOnly,
3723
+ turnLimit: f.turnLimit,
3724
+ concurrency: f.concurrency,
3725
+ isolation: f.isolation,
3726
+ agents: f.agents.map((ag) => ag.key ? ag.key : { name: ag.name, persona: ag.persona, systemPrompt: ag.systemPrompt, scope: ag.scope, moderator: ag.moderator, reasoningEffort: ag.reasoningEffort, approvalRequired: ag.approvalRequired, model: ag.model || void 0 })
3727
+ }, { timeoutMs: 35e3 });
3464
3728
  } catch (e) {
3465
- setErr(e.message);
3729
+ const msg = e && e.message || "Create failed";
3730
+ setErr(/timed out|timeout|abort/i.test(msg) ? `${msg}. Check transport (try Local only), relay host, and network \u2014 agent joins continue in the background after a successful create.` : msg);
3731
+ } finally {
3466
3732
  setBusy(false);
3467
3733
  }
3468
3734
  };
@@ -3474,6 +3740,11 @@ function CreateDialog({ store, d }) {
3474
3740
  setErr(e.message);
3475
3741
  }
3476
3742
  };
3743
+ const tabs = [
3744
+ { id: "room", label: "Room" },
3745
+ { id: "agents", label: `Agents${f.agents.length ? ` (${f.agents.length})` : ""}` },
3746
+ { id: "limits", label: "Limits" }
3747
+ ];
3477
3748
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3478
3749
  import_dsh_client_ui_primitives.Modal,
3479
3750
  {
@@ -3481,59 +3752,128 @@ function CreateDialog({ store, d }) {
3481
3752
  onClose: a.closeDialog,
3482
3753
  title: "Create room",
3483
3754
  closeLabel: "Close",
3484
- className: "rm-modal-wide",
3485
- description: ws ? `In workspace \u201C${ws.title}\u201D (${ws.path}). Agent cwd + MCP sandbox = this path. Default relay 62.234.113.56:80 \xB7 E2EE.` : "Pick a dsh workspace. Default relay 62.234.113.56:80 \xB7 E2EE.",
3755
+ className: "rm-modal-wide rm-modal-create rm-modal-scrollable",
3756
+ contentClassName: "rm-modal-scroll",
3757
+ description: ws ? `Workspace \u201C${ws.title}\u201D \xB7 default VPS relay 62.234.113.56:80 \xB7 E2EE. Every option below is editable.` : "Pick a dsh workspace. Every create option is on these tabs \u2014 nothing is hidden off-screen.",
3486
3758
  footer: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
3487
3759
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "outline", onClick: a.closeDialog, children: "Cancel" }),
3488
3760
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "primary", disabled: !ok, onClick: submit, children: busy ? "Creating\u2026" : "Create" })
3489
3761
  ] }),
3490
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-root rm-form rm-form-wide", onKeyDown: (e) => e.key === "Enter" && e.target.tagName === "INPUT" && submit(), children: [
3491
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Workspace", htmlFor: "rm-create-ws", hint: "Native dsh workspace this room belongs to.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceSelect, { store, id: "rm-create-ws", value: ws, onChange: setWs }) }),
3492
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Name", htmlFor: "rm-create-name", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-name-row", children: [
3493
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Avatar, { name: f.name || "room", size: 36 }),
3494
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-name", autoFocus: true, placeholder: "e.g. release-crew", maxLength: 60, value: f.name, onChange: (e) => setF({ ...f, name: e.target.value }) })
3495
- ] }) }),
3496
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Transport", hint: "VPS directory works on LAN/VPS. Cloudflare is optional.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-mode-row", children: [
3497
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (f.mode === "lan" ? " is-on" : ""), onClick: () => setF({ ...f, mode: "lan", lanHostPort: f.lanHostPort || "62.234.113.56:80" }), children: "LAN / VPS" }),
3498
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (f.mode === "relay" ? " is-on" : ""), onClick: () => setF({ ...f, mode: "relay" }), children: "Cloudflare" })
3499
- ] }) }),
3500
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Description", htmlFor: "rm-create-desc", hint: "Shown to members and in public search.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-desc", placeholder: "e.g. Agents that review and ship releases", maxLength: 280, value: f.description, onChange: (e) => setF({ ...f, description: e.target.value }) }) }),
3501
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Tags", htmlFor: "rm-create-tags", hint: "Spaces or commas, up to 8.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-tags", placeholder: "e.g. review rust", value: f.tags, onChange: (e) => setF({ ...f, tags: e.target.value }) }) }),
3502
- f.mode === "lan" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Field, { label: "Relay host:port", htmlFor: "rm-lan-hp", hint: "Default 62.234.113.56:80. Blank = this machine + mDNS.", children: [
3503
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-lan-hp", placeholder: "62.234.113.56:80 or 100.x.x.x:7421", value: f.lanHostPort, onChange: (e) => setF({ ...f, lanHostPort: e.target.value }) }),
3504
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-lan-browse", children: [
3762
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-root rm-create", "data-rm-create": "", onKeyDown: (e) => e.key === "Enter" && e.target.tagName === "INPUT" && tab === "room" && submit(), children: [
3763
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-tabs", role: "tablist", "aria-label": "Create room sections", children: tabs.map((t) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", role: "tab", "aria-selected": tab === t.id, className: "rm-tab" + (tab === t.id ? " is-on" : ""), onClick: () => setTab(t.id), children: t.label }, t.id)) }),
3764
+ tab === "room" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-form rm-form-wide rm-create-pane", role: "tabpanel", children: [
3765
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Workspace", htmlFor: "rm-create-ws", hint: "Native dsh workspace this room belongs to.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkspaceSelect, { store, id: "rm-create-ws", value: ws, onChange: setWs }) }),
3766
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Name", htmlFor: "rm-create-name", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-name-row", children: [
3767
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Avatar, { name: f.name || "room", size: 36 }),
3768
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-name", autoFocus: true, placeholder: "e.g. release-crew", maxLength: 60, value: f.name, onChange: (e) => setF({ ...f, name: e.target.value }) })
3769
+ ] }) }),
3770
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Transport", hint: "Local only = in-process (no network). Relay / LAN / Cloudflare for remote hosts.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-mode-row rm-mode-wrap", children: [
3771
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (f.transport === "local" ? " is-on" : ""), onClick: () => setF({ ...f, transport: "local", public: false }), children: "Local only" }),
3772
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (f.transport === "relay" ? " is-on" : ""), onClick: () => setF({ ...f, transport: "relay", lanHostPort: f.lanHostPort || "62.234.113.56:80" }), children: "Relay (VPS)" }),
3773
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (f.transport === "lan" ? " is-on" : ""), onClick: () => setF({ ...f, transport: "lan" }), children: "LAN (this machine)" }),
3774
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (f.transport === "cloudflare" ? " is-on" : ""), onClick: () => setF({ ...f, transport: "cloudflare" }), children: "Cloudflare" })
3775
+ ] }) }) }),
3776
+ f.transport === "relay" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Relay host:port", htmlFor: "rm-lan-hp", hint: "Default 62.234.113.56:80 (public directory).", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-lan-hp", placeholder: "62.234.113.56:80", value: f.lanHostPort, onChange: (e) => setF({ ...f, lanHostPort: e.target.value }) }) }) }) : null,
3777
+ f.transport === "lan" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "LAN relay", hint: "Blank host embeds a relay on this machine and advertises it over mDNS.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-lan-browse", children: [
3505
3778
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "outline", onClick: browseLan, children: "Browse mDNS" }),
3506
- lanPeers.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "rm-lan-peer", onClick: () => setF({ ...f, lanHostPort: p.hostPort }), children: [
3779
+ lanPeers.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "rm-lan-peer", onClick: () => setF({ ...f, transport: "relay", lanHostPort: p.hostPort }), children: [
3507
3780
  p.hostPort,
3508
3781
  p.name ? ` \xB7 ${p.name}` : ""
3509
3782
  ] }, p.hostPort))
3510
- ] })
3511
- ] }) }) : null,
3512
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-span-2 rm-local-box", children: [
3513
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-switch-row", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
3514
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Local agents" }),
3515
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: "Host several agents from this dsh as separate members (own identity, session, scope). Edit them later in room details." })
3516
- ] }) }),
3517
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-preset-row", children: [["moderator", "Moderator"], ["architect", "Architect"], ["coder", "Coder"], ["reviewer", "Reviewer"]].map(([k, label]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "rm-preset rm-preset-check" + (f.agents.includes(k) ? " is-on" : ""), children: [
3518
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: f.agents.includes(k), onChange: (e) => setF({ ...f, agents: e.target.checked ? [...f.agents, k] : f.agents.filter((x) => x !== k) }) }),
3519
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: label })
3520
- ] }, k)) }),
3521
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-switch-row", children: [
3783
+ ] }) }) }) : null,
3784
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Description", htmlFor: "rm-create-desc", hint: "Shown to members and in public search.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-desc", placeholder: "e.g. Agents that review and ship releases", maxLength: 280, value: f.description, onChange: (e) => setF({ ...f, description: e.target.value }) }) }),
3785
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Tags", htmlFor: "rm-create-tags", hint: "Spaces or commas, up to 8.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-tags", placeholder: "e.g. review rust", value: f.tags, onChange: (e) => setF({ ...f, tags: e.target.value }) }) }),
3786
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-span-2 rm-switch-row", children: [
3522
3787
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
3523
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Local only (no network)" }),
3524
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: "In-process loopback \u2014 nothing leaves this machine. One click to switch to Relay/LAN later." })
3788
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "List in public directory" }),
3789
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: f.transport === "local" ? "Local-only rooms stay private (no network)." : f.public ? "Anyone can find and join \u2014 key is published with the listing." : "Private: invite only." })
3525
3790
  ] }),
3526
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Switch, { checked: f.localOnly, onChange: (v) => setF({ ...f, localOnly: v, public: v ? false : f.public }), label: "Local only" })
3791
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Switch, { checked: f.public && f.transport !== "local", onChange: (v) => setF({ ...f, public: v }), label: "List in public directory", disabled: f.transport === "local", title: f.transport === "local" ? "Local-only rooms stay private" : void 0 })
3527
3792
  ] })
3528
- ] }),
3529
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-span-2 rm-switch-row", children: [
3530
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
3531
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "List in public directory" }),
3532
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: f.public ? "Anyone can find and join \u2014 key is published with the listing." : "Private: invite only." })
3793
+ ] }) : null,
3794
+ tab === "agents" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-create-pane", role: "tabpanel", children: [
3795
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Presets" }),
3796
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: "Shortcuts that seed a local agent. You can still add free-form agents below, and edit anyone after create." }),
3797
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-preset-row", children: (presets.length ? presets : [
3798
+ { key: "moderator", name: "Moderator", persona: "Breaks requests into tasks and summarizes", scope: "read", moderator: true, reasoningEffort: "medium", systemPrompt: "" },
3799
+ { key: "architect", name: "Architect", persona: "Designs the approach", scope: "read", reasoningEffort: "high", systemPrompt: "" },
3800
+ { key: "coder", name: "Coder", persona: "Implements in its own worktree", scope: "write", reasoningEffort: "medium", systemPrompt: "" },
3801
+ { key: "reviewer", name: "Reviewer", persona: "Reviews diffs", scope: "read", reasoningEffort: "high", systemPrompt: "" }
3802
+ ]).map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "rm-preset rm-preset-check" + (f.agents.some((x) => x.key === p.key) ? " is-on" : ""), children: [
3803
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: f.agents.some((x) => x.key === p.key), onChange: () => togglePreset(p) }),
3804
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
3805
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: p.name }),
3806
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "rm-preset-sub", children: p.persona })
3807
+ ] })
3808
+ ] }, p.key)) }),
3809
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-create-custom", children: [
3810
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-create-custom-head", children: [
3811
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
3812
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Custom agents" }),
3813
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-hint", children: "Free-form name, persona, system prompt, model, scope, approval, moderator." })
3814
+ ] }),
3815
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "outline", icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlusIcon, {}), onClick: () => {
3816
+ setShowCustom(true);
3817
+ setErr(null);
3818
+ }, children: "Add custom" })
3819
+ ] }),
3820
+ f.agents.filter((x) => !x.key).length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "rm-draft-list", children: f.agents.map((ag, i) => ag.key ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "rm-draft-item", children: [
3821
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Avatar, { name: ag.name, size: 24 }),
3822
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "rm-draft-main", children: [
3823
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: ag.name }),
3824
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
3825
+ ag.persona || "custom",
3826
+ " \xB7 ",
3827
+ ag.scope,
3828
+ ag.moderator ? " \xB7 moderator" : ""
3829
+ ] })
3830
+ ] }),
3831
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mini", "aria-label": `Remove ${ag.name}`, onClick: () => removeDraft(i), children: "\xD7" })
3832
+ ] }, i)) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "rm-note", children: "No custom agents yet \u2014 presets above, or Add custom." }),
3833
+ showCustom ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-draft-form rm-form rm-form-wide", children: [
3834
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Name", htmlFor: "rm-create-ag-name", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-ag-name", value: draft.name, maxLength: 40, onChange: (e) => setDraft({ ...draft, name: e.target.value }), placeholder: "e.g. Data wrangler" }) }),
3835
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Persona", htmlFor: "rm-create-ag-persona", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-ag-persona", value: draft.persona, maxLength: 200, onChange: (e) => setDraft({ ...draft, persona: e.target.value }), placeholder: "One-line role" }) }),
3836
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "System prompt", htmlFor: "rm-create-ag-sp", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", { id: "rm-create-ag-sp", className: "rm-input rm-textarea", rows: 3, value: draft.systemPrompt, maxLength: 4e3, onChange: (e) => setDraft({ ...draft, systemPrompt: e.target.value }) }) }) }),
3837
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Model", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { className: "rm-input", "aria-label": "Model", value: draft.model, onChange: (e) => setDraft({ ...draft, model: e.target.value }), children: MODEL_CHOICES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: m, children: m || "dsh default model" }, m)) }) }),
3838
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Reasoning effort", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { className: "rm-input", "aria-label": "Reasoning effort", value: draft.reasoningEffort, onChange: (e) => setDraft({ ...draft, reasoningEffort: e.target.value }), children: ["low", "medium", "high", "max"].map((x) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: x, children: x }, x)) }) }),
3839
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Workspace scope", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-mode-row", children: [
3840
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (draft.scope === "read" ? " is-on" : ""), onClick: () => setDraft({ ...draft, scope: "read" }), children: "Read-only" }),
3841
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rm-mode-btn" + (draft.scope === "write" ? " is-on" : ""), onClick: () => setDraft({ ...draft, scope: "write" }), children: "Read + write" })
3842
+ ] }) }),
3843
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-switch-col", children: [
3844
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-switch-row", children: [
3845
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Approval required" }) }),
3846
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Switch, { checked: draft.approvalRequired, onChange: (v) => setDraft({ ...draft, approvalRequired: v }), label: "Approval required" })
3847
+ ] }),
3848
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-switch-row", children: [
3849
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-field-label", children: "Moderator" }) }),
3850
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Switch, { checked: draft.moderator, onChange: (v) => setDraft({ ...draft, moderator: v }), label: "Moderator" })
3851
+ ] })
3852
+ ] }),
3853
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-span-2 rm-actions", children: [
3854
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "outline", onClick: () => setShowCustom(false), children: "Cancel" }),
3855
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "primary", onClick: addCustomDraft, children: "Add to room" })
3856
+ ] })
3857
+ ] }) : null
3533
3858
  ] }),
3534
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Switch, { checked: f.public, onChange: (v) => setF({ ...f, public: v, localOnly: v ? false : f.localOnly }), label: "List in public directory" })
3535
- ] }),
3536
- err ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2 rm-error", children: err }) : null
3859
+ f.agents.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-note", style: { marginTop: 10 }, children: [
3860
+ "Will create: ",
3861
+ f.agents.map((x) => x.name).join(", "),
3862
+ ". Edit or add more after create from Local agents \u2192 Add local agent."
3863
+ ] }) : null
3864
+ ] }) : null,
3865
+ tab === "limits" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rm-form rm-form-wide rm-create-pane", role: "tabpanel", children: [
3866
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Parallel runs", htmlFor: "rm-create-conc", hint: "Max local agent runs at once (1\u201316). The rest wait in a visible queue.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-conc", type: "number", min: 1, max: 16, value: String(f.concurrency), onChange: (e) => setF({ ...f, concurrency: Math.min(16, Math.max(1, Number(e.target.value) || 1)) }) }) }),
3867
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Turn limit", htmlFor: "rm-create-turns", hint: "Max agent-to-agent hand-offs per task/thread (1\u2013100). A human message resets it.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { id: "rm-create-turns", type: "number", min: 1, max: 100, value: String(f.turnLimit), onChange: (e) => setF({ ...f, turnLimit: Math.min(100, Math.max(1, Number(e.target.value) || 6)) }) }) }),
3868
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Workspace isolation", hint: "Writing agents get their own git worktree by default when the workspace is a git repo.", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { className: "rm-input", "aria-label": "Isolation mode", value: f.isolation, onChange: (e) => setF({ ...f, isolation: e.target.value }), children: [
3869
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "auto", children: "Auto \u2014 git worktree per writing agent, else file locks" }),
3870
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "worktree", children: "Git worktree per agent" }),
3871
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "locks", children: "File locks (shared workspace)" }),
3872
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "off", children: "Off (shared, no locks)" })
3873
+ ] }) }) }),
3874
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-span-2 rm-note", children: "These apply as soon as the room has local agents. Change them later under Runs / Workspace isolation in the room panel." })
3875
+ ] }) : null,
3876
+ err ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rm-error", style: { marginTop: 10 }, children: err }) : null
3537
3877
  ] })
3538
3878
  }
3539
3879
  );