@roaming-ai/dsh-group-chat 0.3.2 → 0.4.0

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/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["h","createElement","P","useState","useRef","P","useRef","useState","createPortal","P","useState","P","useState","useRef","useState","P","useState","P","useState","P","useState","useRef","P","P","memo","useState","P","useState","P","P","P","useState","useRef","useCallback","createRoot","createElement","FileTypeIcon","useCallback","useRef","useState","useMemo","useState","useCallback","P","useState","P","h"],"sources":["../src/client/lib/styles.ts","../src/client/lib/ui.ts","../src/core/status.ts","../src/client/lib/model.ts","../src/client/lib/api.ts","../src/client/components/RoleDrawer.tsx","../src/client/components/HoverTip.tsx","../src/client/components/NavPanel.tsx","../src/client/components/AsidePanel.tsx","../src/core/json.ts","../src/core/types.ts","../src/core/constraints.ts","../src/core/errors.ts","../src/client/components/Fold.tsx","../src/client/components/ThinkRow.tsx","../src/client/components/ToolRow.tsx","../src/client/components/FailCard.tsx","../src/client/components/MsgActions.tsx","../src/client/components/Bubble.tsx","../src/client/components/ConstraintList.tsx","../src/client/components/MessageFlow.tsx","../src/client/components/PermissionSelect.tsx","../src/client/components/Composer.tsx","../src/client/components/ChatPanel.tsx","../src/client/lib/composer-draft.ts","../src/client/hooks/useGroupChatState.ts","../src/shared/file-mention-grammar.ts","../src/client/utils/utils.ts","../src/client/hooks/useComposer.ts","../src/client/hooks/useFileSearch.ts","../src/client/hooks/useMentionState.ts","../src/client/GroupChatPanel.tsx","../src/client/components/GroupChatSettingsSection.tsx","../src/client/components/Glyph.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * 浏览器半样式:CSS 以内联字符串承载(刻意不迁移 CSS Modules 管线——\n * 类名需保持原样,侧栏入口的 “newSession” 类名是任务看板等 DOM 注入式\n * 面板识别“侧边栏导航点击”的跨插件标记,哈希化会破坏该约定)。\n * 工厂执行时幂等注入 <style>,loader 卸载时按 data-plugin 摘除标签。\n * @module dsh-group-chat/client/styles\n */\n\n/** 注入标签的唯一 id。 */\nconst TAG_ID = 'dsh-group-chat/styles.css'\n\nexport const CSS = [\n /* ===== 布局骨架:三区工作台;卡片只用于内容单元,导航用平铺行 ===== */\n '.dsgc-root{display:flex;height:100%;min-height:0;background:var(--dsw-alias-bg-base,transparent);color:var(--dsw-alias-label-primary,inherit);font-size:var(--dsh-content-font-size,14px);container-type:inline-size;position:relative}',\n '.dsgc-loading{padding:24px;color:var(--dsw-alias-label-tertiary,inherit);display:flex;gap:8px;align-items:center;opacity:0;animation:dsgc-loading-in .18s ease-out .15s forwards}',\n /* 首开加载态延迟 150ms 淡入:本机回路通常数毫秒内数据即达并卸载本元素,\n 快路径完全不可见(无闪现,等同移除);慢路径才出现反馈,空白面板不再是唯一信号 */\n '@keyframes dsgc-loading-in{to{opacity:1}}',\n '.dsgc-loading svg{animation:dsgc-spin 1s linear infinite}',\n '@keyframes dsgc-spin{to{transform:rotate(360deg)}}',\n /* ===== 左导航栏(可收起,收合动画与右栏同款配方) ===== */\n '.dsgc-nav{width:232px;flex:none;display:flex;flex-direction:column;gap:8px;border-right:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.2));padding:12px 10px;min-height:0;min-width:0;transition:width .28s cubic-bezier(.16,1,.3,1),opacity .18s ease,padding .28s cubic-bezier(.16,1,.3,1),border-right-width .28s cubic-bezier(.16,1,.3,1)}',\n /* 子元素经 flex 列默认 stretch 填满内容区(不写死宽度:内容区实宽 232px——\n 宿主无全局 border-box,面板为 content-box,旧版写死 212px 曾致右侧多出\n 20px 死区、左右内距失衡);收合动画期间内容随面板收缩,行内 ellipsis\n 渐进截断 + visibility 0.22s 切断,无溢出涂抹 */\n '.dsgc-nav>*{flex:none}',\n '.dsgc-nav.closed{width:0;opacity:0;padding-left:0;padding-right:0;border-right-width:0;visibility:hidden;transition:width .24s ease-in,opacity .16s ease-in,padding .24s ease-in,border-right-width .24s ease-in,visibility 0s .22s}',\n '.dsgc-search{flex:none}',\n '.dsgc-search input{font-size:13px}',\n '.dsgc-search:focus-within{border-color:var(--dsw-alias-state-business-primary,#4f6ef7)}',\n '.dsgc-tree{display:flex;flex-direction:column;gap:6px;flex:1;overflow-y:auto;min-height:0;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-grow-row{display:flex;align-items:center;gap:2px;min-width:0;border:none;background:none;border-radius:6px;padding:5px 6px;color:var(--dsw-alias-label-secondary,inherit);transition:background-color .12s,color .12s;cursor:pointer;font:inherit;text-align:left}',\n '.dsgc-grow-row:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.12));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-grow-row.on{color:var(--dsw-alias-label-primary,inherit);font-weight:600}',\n '.dsgc-twist{flex:none;width:16px;height:16px;border:none;background:none;color:inherit;cursor:pointer;padding:0;display:inline-flex;align-items:center;justify-content:center}',\n '.dsgc-twist svg{transition:transform .16s ease}',\n '.dsgc-twist.closed svg{transform:rotate(-90deg)}',\n '.dsgc-gname{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',\n '.dsgc-nodeops{display:none;gap:2px;flex:none}',\n '.dsgc-grow-row:hover .dsgc-nodeops,.dsgc-sess-row:hover .dsgc-nodeops{display:inline-flex}',\n '.dsgc-opbtn{border:none;background:none;color:var(--dsw-alias-label-tertiary,inherit);cursor:pointer;padding:2px;border-radius:4px;line-height:0;transition:background-color .12s,color .12s}',\n '.dsgc-opbtn:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-opbtn.danger{color:var(--dsw-alias-state-error-primary,#e5484d)}',\n '.dsgc-sess-list{display:flex;flex-direction:column;gap:2px;margin:4px 0 2px 4px;padding-left:12px;border-left:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.15))}',\n '.dsgc-sess-row{display:flex;align-items:center;gap:6px;min-width:0;border:none;background:none;border-radius:6px;padding:6px 8px;font-size:12.5px;line-height:1.5;color:var(--dsw-alias-label-secondary,inherit);transition:background-color .12s,color .12s;cursor:pointer;text-align:left;font-family:inherit}',\n '.dsgc-sess-row:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.12));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-sess-row.on{background:var(--dsw-alias-interactive-bg-active,rgba(128,128,128,.2));color:var(--dsw-alias-label-primary,inherit);font-weight:600}',\n '.dsgc-sess-status{flex:none;width:8px;height:8px;display:inline-flex;justify-content:center;align-items:center}',\n '.dsgc-sess-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',\n '.dsgc-addsess{border:none;background:none;color:var(--dsw-alias-label-tertiary,inherit);cursor:pointer;text-align:left;font-size:12px;line-height:1.5;padding:5px 8px;border-radius:6px;transition:background-color .12s,color .12s;font-family:inherit;display:flex;align-items:center;gap:5px;white-space:nowrap;overflow:hidden}',\n '.dsgc-addsess:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.12));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-rename{font:inherit;font-size:12.5px;min-width:0;flex:1;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-3,transparent));color:inherit;border-radius:6px;padding:1px 6px;outline:none;transition:border-color .16s}',\n '.dsgc-rename:focus{border-color:var(--dsw-alias-state-business-primary,#4f6ef7)}',\n '.dsgc-hint{font-size:12px;color:var(--dsw-alias-label-tertiary,inherit);line-height:1.5;text-wrap:balance}',\n /* ===== 中央会话区 ===== */\n '.dsgc-chat{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0;position:relative}',\n /* 接缝收合钮:钉在会话区两缘、垂直居中、各控其侧(图标方向相反的 chevron)。\n 宽模式下面板宽度过渡 → 中栏连续变宽,绝对定位的钮贴缘自动随接缝滑行(布局驱动);\n 窄模式右栏为覆盖层,钮用同曲线 right 过渡跟踪其左缘。浮层配方:实底 + border-l2 + 轻方向性软影 */\n '.dsgc-seambtn{position:absolute;top:50%;transform:translateY(-50%);z-index:14;width:24px;height:56px;display:flex;align-items:center;justify-content:center;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-alias-bg-layer-3,#fff);color:var(--dsw-alias-label-secondary,inherit);cursor:pointer;transition:background-color .12s,color .12s,border-color .12s,right .3s cubic-bezier(.16,1,.3,1)}',\n '.dsgc-seambtn:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15));color:var(--dsw-alias-label-primary,inherit);border-color:var(--dsw-alias-border-l3,rgba(128,128,128,.4))}',\n '.dsgc-seambtn.left{left:0;border-left:none;border-radius:0 8px 8px 0;box-shadow:3px 0 10px rgba(0,0,0,.07)}',\n '.dsgc-seambtn.right{right:0;border-right:none;border-radius:8px 0 0 8px;box-shadow:-3px 0 10px rgba(0,0,0,.07)}',\n '.dsgc-chathead{display:flex;flex-direction:column;gap:6px;padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.2))}',\n '.dsgc-chathead-row{display:flex;gap:10px;align-items:center;min-width:0}',\n '.dsgc-constraints{align-self:center;box-sizing:border-box;width:76%;max-width:76%;display:flex;flex-direction:column;gap:8px;min-width:0;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-alias-bg-layer-3,rgba(128,128,128,.06));border-radius:12px;animation:dsgc-fade-in .18s ease-out}',\n '.dsgc-chead{display:flex;flex-direction:column;gap:2px;min-width:0}',\n '.dsgc-ctitle{margin:0;font:inherit;font-size:12px;font-weight:600;line-height:1.5;color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-cdesc{margin:0;font-size:11.5px;line-height:1.5;color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-fold{display:grid;grid-template-rows:0fr;transition:grid-template-rows .16s ease-in}',\n '.dsgc-fold.open{grid-template-rows:1fr;transition:grid-template-rows .22s cubic-bezier(.16,1,.3,1)}',\n '.dsgc-fold-inner{min-height:0;overflow:hidden;display:flex;flex-direction:column;gap:2px;opacity:0;transition:opacity .12s ease-in}',\n '.dsgc-fold.open .dsgc-fold-inner{opacity:1;transition:opacity .18s cubic-bezier(.16,1,.3,1)}',\n '.dsgc-clip{--dsgc-clip-from:var(--dsw-alias-bg-layer-3,rgba(128,128,128,.18));position:relative;min-width:0}',\n '.dsgc-clip::before,.dsgc-clip::after{content:\"\";position:absolute;left:0;right:0;height:14px;pointer-events:none;z-index:1;opacity:0;transition:opacity .12s}',\n '.dsgc-clip::before{top:0;background:linear-gradient(to bottom,var(--dsgc-clip-from),transparent)}',\n '.dsgc-clip::after{bottom:0;background:linear-gradient(to top,var(--dsgc-clip-from),transparent)}',\n '.dsgc-clip.can-up::before,.dsgc-clip.can-down::after{opacity:1}',\n '.dsgc-clip-scroll{min-width:0;overflow-y:auto;overscroll-behavior:contain;overflow-anchor:none;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-clist{display:flex;flex-direction:column;gap:2px;min-width:0}',\n '.dsgc-constraint{display:flex;gap:8px;align-items:flex-start;min-width:0;font-size:11.5px;line-height:1.5}',\n '.dsgc-ckind{flex:none;font-weight:500}',\n '.dsgc-ckind.decided{color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-ckind.rejected{color:var(--dsw-alias-state-error-primary,#e5484d)}',\n '.dsgc-ckind.open{color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-ctext{min-width:0;color:var(--dsw-alias-label-primary,inherit);overflow-wrap:break-word}',\n '.dsgc-cmore{align-self:flex-start;border:none;background:none;padding:0;font:inherit;font-size:11.5px;line-height:1.5;color:var(--dsw-alias-label-tertiary,inherit);cursor:pointer}',\n '.dsgc-cmore:hover{color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-cmore:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,var(--dsw-alias-state-business-primary,#4f6ef7));outline-offset:1px}',\n '.dsgc-sess-title{flex:none;font-weight:600;font-size:14px;color:var(--dsw-alias-label-primary,inherit);max-width:30%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',\n '.dsgc-topic{flex:1;background:transparent;border:none;border-bottom:1px solid transparent;padding:2px;min-height:20px;color:var(--dsw-alias-label-secondary,inherit);font:inherit;outline:none;min-width:0;transition:color .12s,border-color .12s}',\n '.dsgc-topic:hover{border-bottom-color:var(--dsw-alias-border-l2,rgba(128,128,128,.3))}',\n '.dsgc-topic:focus{color:var(--dsw-alias-label-primary,inherit);border-bottom-color:var(--dsw-alias-state-business-primary,#4f6ef7)}',\n '.dsgc-topic::placeholder{color:var(--dsw-alias-label-tertiary,inherit)}',\n /* 清空按钮:破坏性操作的 hover/active 反馈——宿主 ghost hover 是低强度灰底(在本\n 面板底色上近透明、无感知),改为 danger 色文字 + 淡红底,与弹窗内 danger 确认\n 按钮同语言;特异性高于原语 .ghost:hover:not(:disabled) */\n '.dsgc-chathead .dsgc-clearbtn{transition:background-color .12s,color .12s}',\n '.dsgc-chathead .dsgc-clearbtn:hover:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#e5484d) 10%,transparent);color:var(--dsw-alias-state-error-primary,#e5484d)}',\n '.dsgc-chathead .dsgc-clearbtn:active:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#e5484d) 16%,transparent)}',\n '.dsgc-msgs{flex:1;overflow-y:auto;padding:20px 24px 16px;display:flex;flex-direction:column;gap:16px;min-height:0;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-msg{display:flex;gap:10px;align-items:flex-start;max-width:100%;animation:dsgc-msg-in .22s cubic-bezier(.16,1,.3,1)}',\n '.dsgc-msg.mine{flex-direction:row-reverse}',\n '.dsgc-avatar{width:28px;height:28px;box-sizing:border-box;border:2px solid var(--dsw-alias-border-l3,rgba(128,128,128,.4));border-radius:50%;background:var(--dsw-alias-bg-module-platform,rgba(128,128,128,.12));color:var(--dsw-alias-label-primary,inherit);display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;flex:none;margin-top:1px}',\n '.dsgc-avatar.mine{border-color:transparent;background:var(--dsw-alias-button-info-fill,#4f6ef7);color:var(--dsw-alias-label-primary-foreground,#fff)}',\n '.dsgc-msgbody{max-width:76%;min-width:0;display:flex;flex-direction:column;gap:5px}',\n '.dsgc-msg.mine .dsgc-msgbody{align-items:flex-end}',\n '.dsgc-msghead{display:flex;gap:6px;align-items:center;min-width:0;font-size:12px;color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-msgname{font-weight:600;color:var(--dsw-alias-label-primary,inherit);white-space:nowrap}',\n '.dsgc-msgmodel{background:var(--dsw-alias-bg-module-platform,rgba(128,128,128,.12));border-radius:999px;padding:0 7px;font-size:10.5px;font-weight:500;line-height:16px;color:var(--dsw-alias-label-secondary,inherit);white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis}',\n '.dsgc-msgtime{font-size:10.5px;color:var(--dsw-alias-label-tertiary,inherit);white-space:nowrap}',\n /* 流式「深度求索...」(对标宿主 TurnStatus「深度求索中...」签名动画):DeepSeek\n 品牌蓝渐变带扫过文字的微光——background-clip:text + background-position\n 1.8s linear 无限扫动;令牌取宿主静态品牌色 --dsw-static-deepseek-*(非主题\n 别名,回退为品牌字面值),贯穿首轮 token 前与流式全程 */\n '.dsgc-typing{background:linear-gradient(90deg,var(--dsw-static-deepseek-500,#4176e6) 0%,var(--dsw-static-deepseek-500,#4176e6) 40%,var(--dsw-static-deepseek-200,#d3e2ff) 50%,var(--dsw-static-deepseek-500,#4176e6) 60%,var(--dsw-static-deepseek-500,#4176e6) 100%);color:#0000;-webkit-text-fill-color:transparent;background-position:100% 0;background-size:250% 100%;-webkit-background-clip:text;background-clip:text;font-weight:600;animation:dsgc-typing-shimmer 1.2s linear infinite}',\n '@keyframes dsgc-typing-shimmer{to{background-position:0 0}}',\n '.dsgc-msgtext{background:var(--dsw-alias-bg-layer-3,rgba(128,128,128,.06));border:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.15));padding:10px 14px;border-radius:12px;line-height:1.6;text-align:left;color:var(--dsw-alias-label-primary,inherit);min-width:0;overflow-wrap:anywhere}',\n '.dsgc-msg.mine .dsgc-msgtext{background:var(--dsw-alias-button-info-fill,#4f6ef7);border-color:transparent;color:var(--dsw-alias-label-primary-foreground,#fff);white-space:pre-wrap;word-break:break-word}',\n '.dsgc-msgtext.live{opacity:.92}',\n '.dsgc-msg.live .dsgc-avatar{--presence-ring:color-mix(in srgb,var(--role-color,#4f6ef7) 22%,transparent);animation:dsgc-presence 1.8s ease-in-out infinite}',\n '.dsgc-think{margin:2px 0}',\n '.dsgc-think .dsgc-thinkrow{font-size:12px;color:var(--dsw-alias-label-secondary,inherit);border-radius:8px;padding:3px 8px;transition:background-color .12s}',\n '.dsgc-think .dsgc-thinkrow:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.1))}',\n '.dsgc-think .dsgc-thinksummary{color:var(--dsw-alias-label-tertiary,inherit);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:44ch;font-size:11.5px;margin-left:6px}',\n '.dsgc-think .dsgc-clip{margin:2px 0 4px;padding-left:10px;border-left:2px solid var(--dsw-alias-border-l2,rgba(128,128,128,.25))}',\n '.dsgc-think .dsgc-thinkbody{font-size:12.5px;line-height:1.7;color:var(--dsw-alias-label-secondary,inherit);white-space:pre-wrap;word-break:break-word}',\n /* 首 delta 前的「思考中」占位行:ThinkRow 同语言(思考图标 + 次要色 12px 小字)\n + 三点交错呼吸动画——深度思考模型首字节可能等数秒到数十秒,空白气泡会被\n 感知为卡死;delta 到达后被真实思考行/正文自然替换 */\n '.dsgc-pending{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-pending svg{flex:none}',\n '.dsgc-pendingdots{display:inline-flex;gap:2px;align-items:center}',\n '.dsgc-pendingdots i{width:3px;height:3px;border-radius:50%;background:currentColor;opacity:.3;animation:dsgc-dot-breathe 1.2s ease-in-out infinite}',\n '.dsgc-pendingdots i:nth-child(2){animation-delay:.2s}',\n '.dsgc-pendingdots i:nth-child(3){animation-delay:.4s}',\n '@keyframes dsgc-dot-breathe{0%,100%{opacity:.25}50%{opacity:1}}',\n '.dsgc-sysmsg{align-self:center;font-size:11.5px;color:var(--dsw-alias-label-secondary,inherit);background:var(--dsw-alias-bg-module-platform,rgba(128,128,128,.1));border-radius:999px;padding:2px 10px;text-align:center;max-width:90%;animation:dsgc-sys-in .24s ease-out}',\n /* 消息操作条:气泡外下方;角色左齐、自己右齐。占位常在,悬停显现;失败卡 always 常驻 */\n '.dsgc-msgops{display:inline-flex;align-items:center;gap:2px;margin-top:2px;min-height:24px;visibility:hidden;opacity:0;transition:opacity .12s,visibility .12s}',\n '.dsgc-msg:hover .dsgc-msgops,.dsgc-msg:focus-within .dsgc-msgops,.dsgc-msgops.always{visibility:visible;opacity:1}',\n '@media (hover:none){.dsgc-msg .dsgc-msgops{visibility:visible;opacity:1}}',\n '.dsgc-msg.mine .dsgc-msgops{justify-content:flex-end}',\n '.dsgc-msgop{border:none;background:none;color:var(--dsw-alias-label-tertiary,inherit);cursor:pointer;padding:3px 6px;border-radius:6px;display:inline-flex;align-items:center;gap:4px;font:inherit;font-size:11.5px;line-height:16px;transition:background-color .12s,color .12s}',\n '.dsgc-msgop svg{flex:none}',\n '.dsgc-msgop:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-msgop:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,var(--dsw-alias-state-business-primary,#4f6ef7));outline-offset:1px}',\n '.dsgc-msgop.done{color:var(--dsw-alias-state-success-primary,#30a46c)}',\n '.dsgc-msgop.retry{color:var(--dsw-alias-state-error-primary,#e5484d)}',\n '.dsgc-msgop.retry:hover:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#e5484d) 10%,transparent);color:var(--dsw-alias-state-error-primary,#e5484d)}',\n '.dsgc-msgop:disabled{opacity:.4;cursor:default}',\n /* 失败卡:角色消息形态,人话标题 + 可展开原文;不用左侧色条,避免 craft-floor 禁令 */\n '.dsgc-fail{background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#e5484d) 8%,var(--dsw-alias-bg-layer-3,rgba(128,128,128,.06)));border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary,#e5484d) 28%,var(--dsw-alias-border-l1,rgba(128,128,128,.15)));border-radius:12px;padding:10px 12px;display:flex;flex-direction:column;gap:6px;min-width:0;animation:dsgc-fade-in .18s ease-out}',\n '.dsgc-failhead{display:flex;align-items:flex-start;gap:8px;min-width:0}',\n '.dsgc-failicon{flex:none;width:22px;height:22px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;color:var(--dsw-alias-state-error-primary,#e5484d);background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#e5484d) 12%,transparent);margin-top:1px}',\n '.dsgc-failcopy{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}',\n '.dsgc-failtitle{font-size:13px;font-weight:600;line-height:1.4;color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-faildetail{font-size:12px;line-height:1.5;color:var(--dsw-alias-label-secondary,inherit);overflow-wrap:anywhere}',\n '.dsgc-failmore{align-self:flex-start;border:none;background:none;padding:0;font:inherit;font-size:11.5px;line-height:1.5;color:var(--dsw-alias-label-tertiary,inherit);cursor:pointer}',\n '.dsgc-failmore:hover{color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-failmore:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,var(--dsw-alias-state-business-primary,#4f6ef7));outline-offset:1px}',\n '.dsgc-fail .dsgc-clip{--dsgc-clip-from:var(--dsw-alias-bg-layer-2,rgba(128,128,128,.12));border-radius:8px}',\n '.dsgc-failraw{margin:0;font-size:11.5px;line-height:1.55;white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,transparent);color:var(--dsw-alias-label-secondary,inherit)}',\n /* ===== 工具调用行 / 确认卡片(对标思考折叠语言) ===== */\n '.dsgc-tool{margin:2px 0}',\n '.dsgc-tool .dsgc-toolrow{font-size:12px;color:var(--dsw-alias-label-secondary,inherit);border-radius:8px;padding:3px 8px;transition:background-color .12s}',\n '.dsgc-tool .dsgc-toolrow:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.1))}',\n '.dsgc-tool .dsgc-toolsummary{color:var(--dsw-alias-label-tertiary,inherit);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:40ch;font-size:11.5px;margin-left:6px}',\n '.dsgc-tool .dsgc-clip{margin:2px 0 4px;padding-left:10px;border-left:2px solid var(--dsw-alias-border-l2,rgba(128,128,128,.25))}',\n '.dsgc-tool .dsgc-toolbody{font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary,inherit);white-space:pre-wrap;word-break:break-word}',\n '.dsgc-confirm{border:1px solid var(--dsw-alias-state-business-primary,#4f6ef7);border-radius:12px;background:var(--dsw-alias-bg-layer-3,rgba(128,128,128,.06));padding:10px 12px;display:flex;flex-direction:column;gap:8px;max-width:76%;animation:dsgc-fade-in .18s ease-out}',\n '.dsgc-confirmtitle{font-size:12px;font-weight:600;color:var(--dsw-alias-label-primary,inherit);display:flex;align-items:center;gap:6px}',\n '.dsgc-confirmcmd{font-size:12px;line-height:1.6;white-space:pre-wrap;word-break:break-word;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));border-radius:8px;padding:8px 10px;background:var(--dsw-alias-bg-layer-2,transparent);color:var(--dsw-alias-label-primary,inherit);max-height:240px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-confirmops{display:flex;gap:8px;justify-content:flex-end}',\n /* 清空确认弹窗内的说明列表 */\n '.dsgc-clearnotes{margin:0;padding-left:18px;font-size:13px;line-height:1.8;color:var(--dsw-alias-label-secondary,inherit);display:flex;flex-direction:column;gap:2px}',\n '.dsgc-err{font-size:12px;color:var(--dsw-alias-state-error-primary,#e5484d);animation:dsgc-fade-in .18s ease-out}',\n '.dsgc-empty{margin:auto;display:flex;flex-direction:column;align-items:center;gap:10px;color:var(--dsw-alias-label-tertiary,inherit);text-align:center;max-width:40ch;padding:24px;animation:dsgc-fade-in .3s ease-out}',\n '.dsgc-empty svg{opacity:.5}',\n '.dsgc-empty .dsgc-emptytitle{font-size:13px;font-weight:600;color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-empty .dsgc-hint{text-wrap:balance}',\n '.dsgc-tobottom{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);z-index:12;animation:dsgc-rise-in .18s cubic-bezier(.16,1,.3,1)}',\n /* 回到底部:实底浮动胶囊(@弹层同款浮层配方——实底 + border-l2 + shadow-lv3),不与消息内容相互透底 */\n '.dsgc-tobtn{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-alias-bg-layer-3,#fff);color:var(--dsw-alias-label-secondary,inherit);border-radius:999px;padding:5px 12px;font:inherit;font-size:12px;line-height:1.4;cursor:pointer;box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.18));transition:color .12s,border-color .12s}',\n '.dsgc-tobtn:hover{color:var(--dsw-alias-label-primary,inherit);border-color:var(--dsw-alias-border-l3,rgba(128,128,128,.4))}',\n /* ===== composer ===== */\n '.dsgc-composer{padding:12px 16px 14px;display:flex;flex-direction:column;gap:10px;position:relative}',\n /* 输入卡(对标主会话 composer 卡):22px 圆角独立卡、input-major 实底、\n elevation-soft 软影(DESIGN.md 输入面豁免——输入面遵循宿主输入面语言,\n 其余静止表面仍零阴影);chips 等配置行留卡外 */\n '.dsgc-card{background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-3,transparent));--dsw-elevation-stroke-color:var(--dsw-alias-border-l2,rgba(128,128,128,.3));box-shadow:var(--dsw-elevation-soft,0 1px 3px rgba(0,0,0,.08));border-radius:22px;padding:8px 0 0;display:flex;flex-direction:column;gap:8px;position:relative}',\n /* 输入区:非受控 contenteditable(React 不管子节点);白空间与换行规则\n 与序列化契约对齐(pre-wrap + <br>→\\n) */\n '.dsgc-edit{display:block;box-sizing:border-box;width:100%;min-height:36px;max-height:180px;overflow-y:auto;outline:none;white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;font:inherit;font-size:13px;line-height:24px;color:var(--dsw-alias-label-primary,inherit);caret-color:var(--dsw-alias-state-business-primary,#4f6ef7);scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent;position:relative;z-index:1}',\n '.dsgc-card .dsgc-edit{padding:6px 8px 0 14px}',\n /* 占位符 = 独立覆盖层(对齐主会话):不用 ::before——生成内容会把聚焦光标\n 顶到占位文字之后;覆盖层 pointer-events:none 不参与光标布局,\n 与输入区同 padding 基准(左 14 / 上 6) */\n '.dsgc-ph{position:absolute;left:14px;top:6px;max-width:calc(100% - 22px);color:var(--dsw-alias-label-tertiary,inherit);pointer-events:none;user-select:none;font-size:13px;line-height:24px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',\n /* @提及芯片(输入区内原子元素):色点 + 角色色淡底胶囊——弹层候选行同语言 */\n '.dsgc-chipin{display:inline-flex;align-items:center;gap:4px;background:color-mix(in srgb,var(--role-color,#888) 15%,transparent);border-radius:999px;padding:1px 7px 1px 5px;margin:0 1px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary,inherit);white-space:nowrap;user-select:all}',\n '.dsgc-card .dsgc-sendrow{padding:0 12px 10px}',\n /* 停止/清空按钮:实心红(Button primitive outline 变体的 hover 规则\n background:interactive-bg-hover 特异度 (0,3,0) 会盖掉 (0,1,0) 的红底,\n 悬停时按钮变透明;加 button 类型选择器提为 (0,1,1)/(0,3,1),顺序无关\n 地压过变体,hover 补回红底并经 brightness 提亮) */\n 'button.dsgc-stopbtn{background:var(--dsw-alias-state-error-primary,#e5484d);border-color:transparent;color:#fff;font-weight:600}',\n 'button.dsgc-stopbtn:hover:not(:disabled){background:var(--dsw-alias-state-error-primary,#e5484d);filter:brightness(1.08);color:#fff}',\n /* 标签固定在左;芯片在右侧独立换行,后续行与首行芯片左缘对齐(不折到「参与角色」下面)。\n 单行 24px;角色过多时随内容增高,避免固定高度把后续行溢出叠到下方输入卡上 */\n '.dsgc-parts{display:flex;align-items:flex-start;gap:6px;min-height:24px}',\n '.dsgc-partslabel{font-size:12px;line-height:24px;color:var(--dsw-alias-label-tertiary,inherit);flex:none}',\n '.dsgc-partlist{display:flex;flex-wrap:wrap;align-items:center;gap:6px;row-gap:4px;flex:1;min-width:0}',\n '.dsgc-partchip{display:inline-flex;gap:6px;align-items:center;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:transparent;color:var(--dsw-alias-label-secondary,inherit);border-radius:999px;padding:2px 10px;font-size:12px;line-height:1.5;cursor:pointer;transition:background-color .12s,color .12s,border-color .12s;font-family:inherit}',\n '.dsgc-partchip:hover{color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-partchip.on{background:var(--dsw-alias-interactive-bg-active,rgba(128,128,128,.18));color:var(--dsw-alias-label-primary,inherit);border-color:var(--dsw-alias-border-l2,rgba(128,128,128,.3))}',\n '.dsgc-partchip:disabled{opacity:.5;cursor:default}',\n '.dsgc-chipdot{width:8px;height:8px;border-radius:50%;flex:none;display:inline-block}',\n '.dsgc-sendrow{display:flex;gap:8px;align-items:center;justify-content:flex-end}',\n '.dsgc-sendrow button{white-space:nowrap}',\n /* ===== 权限档位选择器(对齐主会话 composer 左下角芯片) ===== */\n '.dsgc-permtrigger{min-width:0;max-width:220px;height:28px;color:var(--dsw-alias-label-secondary,inherit);cursor:pointer;background:transparent;border:none;border-radius:999px;outline:none;align-items:center;gap:4px;padding:0 4px 0 8px;font-size:13px;font-weight:500;line-height:20px;display:inline-flex;font-family:inherit;transition:background-color .12s,color .12s}',\n '.dsgc-permtrigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-permtrigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3,rgba(128,128,128,.4))}',\n '.dsgc-permtrigger:disabled{color:var(--dsw-alias-label-dimmed,inherit);cursor:default}',\n '.dsgc-permicon{flex:none;display:inline-flex}',\n '.dsgc-permicon svg{width:14px;height:14px}',\n '.dsgc-permlabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}',\n '.dsgc-permchevron{color:var(--dsw-alias-label-caption,inherit);flex:none;transition:transform .12s;display:inline-flex}',\n '.dsgc-permchevron.open{transform:rotate(180deg)}',\n '.dsgc-rounds{display:flex;gap:2px;align-items:center;font-size:12px;color:var(--dsw-alias-label-secondary,inherit);flex:none;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));border-radius:8px;padding:2px}',\n '.dsgc-rounds .dsgc-roundbtn{border:none;background:none;color:var(--dsw-alias-label-secondary,inherit);cursor:pointer;padding:3px;border-radius:5px;line-height:0;transition:background-color .12s,color .12s}',\n '.dsgc-rounds .dsgc-roundbtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-rounds .dsgc-roundbtn:disabled{opacity:.4;cursor:default}',\n '.dsgc-rounds .dsgc-roundnum{width:26px;text-align:center;font-variant-numeric:tabular-nums;font-weight:600;color:var(--dsw-alias-label-primary,inherit)}',\n /* hover 气泡:对齐宿主 Tooltip.module.css,portal 到 body 以躲开 container-type */\n '.dsgc-hovertip{position:fixed;z-index:100;width:max-content;max-width:50vw;padding:3px 7px;border-radius:8px;background:var(--dsw-alias-tooltip-bg,#1f1f1f);color:var(--dsw-static-neutral-bluish-00,#fff);font-size:13px;line-height:20px;white-space:pre-line;overflow-wrap:break-word;pointer-events:none;animation:dsgc-hovertip-in 150ms var(--ds-ease-in-out,ease)}',\n '.dsgc-hovertip[data-side=\"right\"]{transform:translateY(-50%)}',\n '.dsgc-hovertip[data-side=\"top\"]{transform:translate(-50%,-100%)}',\n '.dsgc-hovertip[data-side=\"bottom\"]{transform:translateX(-50%)}',\n '@keyframes dsgc-hovertip-in{from{opacity:0}}',\n /* ===== @成员 / @文件弹层 ===== */\n '.dsgc-mentionwrap{position:relative}',\n '.dsgc-mention{animation:dsgc-pop-in .16s cubic-bezier(.16,1,.3,1);position:absolute;left:0;right:0;bottom:calc(100% + 6px);background:var(--dsw-alias-bg-layer-3,#fff);border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));border-radius:10px;box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.18));max-height:220px;overflow-y:auto;padding:4px;z-index:30;display:flex;flex-direction:column;gap:2px;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-mentionitem{display:flex;align-items:center;gap:8px;border:none;background:none;color:var(--dsw-alias-label-secondary,inherit);font:inherit;font-size:12.5px;text-align:left;cursor:pointer;padding:6px 8px;border-radius:6px;transition:background-color .12s,color .12s}',\n '.dsgc-mentionitem.on,.dsgc-mentionitem:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-mentionname{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}',\n '.dsgc-mentionmodel{font-size:11px;color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-mentionhint{font-size:11px;color:var(--dsw-alias-label-tertiary,inherit);padding:2px 8px 1px}',\n '.dsgc-mention-file .dsgc-mentionitem.dsgc-hint{cursor:default;color:var(--dsw-alias-label-tertiary,inherit);justify-content:center}',\n '.dsgc-mention-file .dsgc-mentionitem.dsgc-hint:hover{background:none}',\n /* 文件检索:宿主 FileTypeIcon 分色字形 + 井位底,文件夹/文件扫一眼可分 */\n '.dsgc-fileglyph{flex:none;width:22px;height:22px;display:inline-flex;align-items:center;justify-content:center;border-radius:5px}',\n '.dsgc-fileglyph.dir{background:color-mix(in srgb,var(--dsw-static-amber-400,#e8912d) 16%,transparent)}',\n '.dsgc-fileglyph.file{background:var(--dsw-alias-bg-module-platform,rgba(128,128,128,.12))}',\n '.dsgc-filedrill{flex:none;display:inline-flex;color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-mentionitem.on .dsgc-filedrill,.dsgc-mentionitem:hover .dsgc-filedrill{color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-chipin-file{background:color-mix(in srgb,var(--dsw-static-neutral-bluish-300,rgba(128,128,128,.55)) 18%,transparent)}',\n '.dsgc-chipin-file[data-dir=\"1\"]{background:color-mix(in srgb,var(--dsw-static-amber-400,#e8912d) 18%,transparent)}',\n '.dsgc-chipglyph{flex:none;width:14px;height:14px;display:inline-flex;align-items:center;justify-content:center;overflow:hidden}',\n '.dsgc-chipglyph svg{display:block}',\n /* ===== 右上下文栏 ===== */\n '.dsgc-aside{width:304px;flex:none;display:flex;flex-direction:column;gap:10px;border-left:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.2));padding:12px;min-height:0;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent;transition:width .28s cubic-bezier(.16,1,.3,1),opacity .18s ease,padding .28s cubic-bezier(.16,1,.3,1),border-left-width .28s cubic-bezier(.16,1,.3,1)}',\n /* 子元素经 flex 列默认 stretch 填满内容区(面板为 content-box、内容区实宽\n 304px;旧版写死 280px 曾致右侧多出 24px 死区) */\n '.dsgc-aside>*{flex:none}',\n '.dsgc-aside.closed{width:0;opacity:0;padding-left:0;padding-right:0;border-left-width:0;visibility:hidden;transition:width .24s ease-in,opacity .16s ease-in,padding .24s ease-in,border-left-width .24s ease-in,visibility 0s .22s}',\n '.dsgc-sec{display:flex;flex-direction:column;gap:8px;flex:none}',\n '.dsgc-sechead{display:flex;align-items:center;gap:6px;font-weight:600;font-size:12px;color:var(--dsw-alias-label-tertiary,inherit);padding-top:2px}',\n '.dsgc-sechead .dsgc-secspacer{flex:1}',\n '.dsgc-seccount{font-weight:500;color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-roles{display:flex;flex-direction:column;gap:8px}',\n '.dsgc-role{border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-alias-bg-layer-3,transparent);border-radius:12px;padding:10px 12px;display:flex;flex-direction:column;gap:7px;transition:border-color .16s,background-color .16s;list-style:none;text-align:left;font:inherit;cursor:pointer;color:inherit}',\n '.dsgc-role:hover{border-color:var(--dsw-alias-label-dimmed,rgba(128,128,128,.5))}',\n '.dsgc-rolehead{display:flex;gap:8px;align-items:center}',\n '.dsgc-roledot{width:10px;height:10px;border-radius:50%;flex:none}',\n '.dsgc-rolename{font-weight:600;font-size:13px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-role.off .dsgc-rolename{color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-rolepersona{font-size:11.5px;color:var(--dsw-alias-label-tertiary,inherit);line-height:1.5;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;min-height:0}',\n '.dsgc-rolemeta{display:flex;align-items:center;gap:6px;min-width:0;flex:1}',\n '.dsgc-rolemodel{min-width:0;flex:0 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-module-platform,rgba(128,128,128,.12));border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-rolethink{display:inline-flex;align-items:center;flex:none;color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-roleops{display:flex;gap:2px;flex:none;margin-left:auto;opacity:0;transition:opacity .12s}',\n '.dsgc-role:hover .dsgc-roleops,.dsgc-role:focus-within .dsgc-roleops{opacity:1}',\n '.dsgc-rolemenu{display:flex;align-items:center;gap:8px}',\n /* ===== 表单与控件(角色抽屉内) ===== */\n '.dsgc-field{display:flex;flex-direction:column;gap:5px}',\n '.dsgc-field>label{font-size:12px;font-weight:500;color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-input,.dsgc-select,.dsgc-textarea{background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-3,transparent));border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));color:var(--dsw-alias-label-primary,inherit);font:inherit;font-size:13px;border-radius:8px;padding:6px 10px;width:100%;box-sizing:border-box;outline:none;transition:border-color .16s,background-color .16s}',\n '.dsgc-input:focus,.dsgc-select:focus,.dsgc-textarea:focus{border-color:var(--dsw-alias-state-business-primary,#4f6ef7)}',\n '.dsgc-input::placeholder,.dsgc-textarea::placeholder{color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-textarea{resize:vertical;min-height:76px}',\n '.dsgc-palette{display:flex;gap:6px;flex-wrap:wrap}',\n '.dsgc-dot{width:18px;height:18px;border-radius:50%;border:2px solid transparent;cursor:pointer;padding:0;transition:transform .12s}',\n '.dsgc-dot:hover{transform:scale(1.12)}',\n '.dsgc-dot.on{border-color:var(--dsw-alias-label-primary,#fff)}',\n '.dsgc-form{display:flex;flex-direction:column;gap:12px}',\n '.dsgc-formerr{font-size:12px;color:var(--dsw-alias-state-error-primary,#e5484d);line-height:1.5}',\n '.dsgc-selhint{font-size:12px;color:var(--dsw-alias-label-tertiary,inherit);line-height:1.5;display:flex;gap:6px;align-items:center;flex-wrap:wrap}',\n /* ===== 角色编辑抽屉(右侧滑出) ===== */\n '.dsgc-drawer{position:absolute;top:0;right:0;bottom:0;width:380px;max-width:calc(100% - 40px);z-index:20;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#fff));border-left:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));box-shadow:-12px 0 32px rgba(0,0,0,.14);display:flex;flex-direction:column;animation:dsgc-drawer-in .22s cubic-bezier(.16,1,.3,1)}',\n '.dsgc-drawer.closing{animation:dsgc-drawer-out .14s ease-in forwards;pointer-events:none}',\n '@keyframes dsgc-drawer-in{from{transform:translateX(32px);opacity:0}to{transform:none;opacity:1}}',\n '@keyframes dsgc-drawer-out{to{transform:translateX(32px);opacity:0}}',\n '@keyframes dsgc-msg-in{from{opacity:0;transform:translateY(6px)}}',\n '@keyframes dsgc-sys-in{from{opacity:0;transform:scale(.96)}}',\n '@keyframes dsgc-pop-in{from{opacity:0;transform:translateY(4px)}}',\n '@keyframes dsgc-rise-in{from{opacity:0;transform:translate(-50%,6px)}}',\n '@keyframes dsgc-fade-in{from{opacity:0}}',\n '@keyframes dsgc-presence{0%,100%{box-shadow:0 0 0 0 color-mix(in srgb,var(--role-color,#4f6ef7) 0%,transparent)}50%{box-shadow:0 0 0 4px var(--presence-ring)}}',\n '.dsgc-drawerhead{display:flex;align-items:center;gap:8px;padding:14px 16px;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.2));flex:none}',\n '.dsgc-drawertitle{flex:1;font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-drawerbody{flex:1;overflow-y:auto;padding:16px;min-height:0;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-drawerfoot{display:flex;gap:8px;justify-content:flex-end;padding:12px 16px;border-top:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.2));flex:none}',\n /* ===== 文件浏览器(目录选择) ===== */\n '.dsgc-fb{border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-alias-bg-layer-2,transparent);border-radius:8px;display:flex;flex-direction:column;gap:6px;padding:8px;animation:dsgc-fade-in .2s ease-out}',\n '.dsgc-fbhead{display:flex;align-items:center;justify-content:space-between;gap:8px;min-width:0}',\n '.dsgc-fbhead button{flex:none;white-space:nowrap}',\n '.dsgc-wsrow{display:flex;gap:6px;align-items:center;min-width:0}',\n '.dsgc-wsrow .dsgc-input{width:auto;flex:1;min-width:0}',\n '.dsgc-wsrow>button{flex:none;white-space:nowrap}',\n '.dsgc-nav>button{white-space:nowrap;overflow:hidden}',\n '.dsgc-fbpath{flex:1;min-width:0;font-size:11px;color:var(--dsw-alias-label-secondary,inherit);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',\n '.dsgc-fblist{display:flex;flex-direction:column;gap:1px;max-height:220px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-fbrow{display:flex;align-items:center;gap:7px;width:100%;border:none;background:none;color:var(--dsw-alias-label-primary,inherit);font:inherit;font-size:12.5px;text-align:left;cursor:pointer;padding:3px 8px;border-radius:6px;transition:background-color .12s}',\n '.dsgc-fbrow:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15))}',\n '.dsgc-fbrow.dim{opacity:.55}',\n '.dsgc-fbrow.file{cursor:default}',\n '.dsgc-fbrow.file:hover{background:none}',\n '.dsgc-fbname{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',\n '.dsgc-fbsize{flex:none;font-size:10.5px;color:var(--dsw-alias-label-tertiary,inherit)}',\n /* ===== 键盘焦点 ===== */\n '.dsgc-partchip:focus-visible,.dsgc-mentionitem:focus-visible,.dsgc-dot:focus-visible,.dsgc-opbtn:focus-visible,.dsgc-twist:focus-visible,.dsgc-addsess:focus-visible,.dsgc-grow-row:focus-visible,.dsgc-sess-row:focus-visible,.dsgc-rename:focus-visible,.dsgc-fbrow:focus-visible,.dsgc-role:focus-visible,.dsgc-roundbtn:focus-visible,.dsgc-tobtn:focus-visible,.dsgc-seambtn:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,var(--dsw-alias-state-business-primary,#4f6ef7));outline-offset:1px}',\n /* ===== 窄容器:右栏覆盖式呈现 ===== */\n '@container (max-width: 880px){.dsgc-aside{position:absolute;top:0;right:0;bottom:0;z-index:15;width:min(304px,88%);box-shadow:-12px 0 32px rgba(0,0,0,.16);border-left:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));transition:transform .3s cubic-bezier(.16,1,.3,1),opacity .2s ease}.dsgc-aside.closed{width:min(304px,88%);padding-left:12px;padding-right:12px;border-left-width:1px;transform:translateX(calc(100% + 14px));opacity:0;transition:transform .26s ease-in,opacity .18s ease-in,visibility 0s .24s}.dsgc-seambtn.right:not(.closed){right:min(304px,88%)}}',\n '@container (max-width: 640px){.dsgc-nav{width:200px}.dsgc-msgbody{max-width:88%}.dsgc-constraints{width:88%;max-width:88%}}',\n /* ===== 侧边栏入口对齐(外壳将插槽内容包在 panelGlyph span 内,必须用后代 :has) ===== */\n '[class*=\"panelList\"]:has(.dsgc-entryOverlay){margin-top:4px}',\n '[class*=\"panelRow\"]:has(.dsgc-entryOverlay){position:relative;box-sizing:border-box;height:36px;min-height:36px;padding:0 10px;font-size:13px;transition:background-color .12s,color .12s}',\n '[class*=\"panelRow\"][class*=\"panelActive\"]:has(.dsgc-entryOverlay){font-weight:600}',\n /* 入口 hover:宿主 panelRow:hover 只给灰底、不变文字色(低强度到近无感);\n 对齐任务看板入口行——hover 灰底 + 文字/图标转 label-primary */\n '[class*=\"panelRow\"]:has(.dsgc-entryOverlay):hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.12));color:var(--dsw-alias-label-primary,inherit)}',\n /* DOM 注入式全幅视图(任务看板 data-dsh-taskboard-active / SSH data-dsh-ssh-active)\n 激活时接管中央列:外壳面板状态机未变(activePanelId 仍指向群聊),但视图已被\n 覆盖——群聊入口随之视觉复位,避免停留“激活”态误导当前所在视图。两行特异性\n 相同(0,4,1),hover 行在后,复位不吞 hover 反馈 */\n 'html[data-dsh-taskboard-active] [class*=\"panelRow\"][class*=\"panelActive\"]:has(.dsgc-entryOverlay),html[data-dsh-ssh-active] [class*=\"panelRow\"][class*=\"panelActive\"]:has(.dsgc-entryOverlay){background:transparent;color:var(--dsw-alias-label-secondary,inherit);font-weight:400}',\n 'html[data-dsh-taskboard-active] [class*=\"panelRow\"]:has(.dsgc-entryOverlay):hover,html[data-dsh-ssh-active] [class*=\"panelRow\"]:has(.dsgc-entryOverlay):hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.12));color:var(--dsw-alias-label-primary,inherit)}',\n /* 收起态例外:外壳把收起栏所有面板图标统一为 primary 色(激活与否不由颜色表达),\n 复位规则不得把群聊图标调暗成 secondary;仅去掉激活底色即可 */\n 'html[data-dsh-taskboard-active] [data-sidebar-collapsed] [class*=\"panelRow\"]:has(.dsgc-entryOverlay),html[data-dsh-ssh-active] [data-sidebar-collapsed] [class*=\"panelRow\"]:has(.dsgc-entryOverlay),html[data-dsh-taskboard-active] [class*=\"collapsed\"] [class*=\"panelRow\"]:has(.dsgc-entryOverlay),html[data-dsh-ssh-active] [class*=\"collapsed\"] [class*=\"panelRow\"]:has(.dsgc-entryOverlay){color:var(--dsw-alias-label-primary,inherit)}',\n '[class*=\"panelRow\"]:has(.dsgc-entryOverlay) > [class*=\"panelTitle\"]{padding-left:24px}',\n '.dsgc-entryOverlay{position:absolute;inset:0;display:flex;align-items:center;padding:0 10px;box-sizing:border-box}',\n '.dsgc-entryIcon{flex:none;width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center}',\n '.dsgc-entryIcon svg{width:18px;height:18px;display:block}',\n '[data-sidebar-collapsed] .dsgc-entryOverlay,[class*=\"collapsed\"] .dsgc-entryOverlay{justify-content:center;padding:0}',\n '[data-sidebar-collapsed] [class*=\"panelRow\"]:has(.dsgc-entryOverlay),[class*=\"collapsed\"] [class*=\"panelRow\"]:has(.dsgc-entryOverlay){margin:0 auto}',\n '@media (prefers-reduced-motion:reduce){.dsgc-dot,.dsgc-partchip,.dsgc-mentionitem,.dsgc-grow-row,.dsgc-sess-row,.dsgc-opbtn,.dsgc-addsess,.dsgc-topic,.dsgc-role,.dsgc-rename,.dsgc-input,.dsgc-select,.dsgc-textarea,.dsgc-fbrow,.dsgc-twist svg,.dsgc-roleops,.dsgc-roundbtn,.dsgc-permtrigger,.dsgc-permchevron,.dsgc-tobtn,.dsgc-seambtn,.dsgc-aside,.dsgc-aside.closed,.dsgc-nav,.dsgc-nav.closed,.dsgc-clearbtn,.dsgc-cmore,.dsgc-msgops,.dsgc-msgop,.dsgc-failmore,.dsgc-clip::before,.dsgc-clip::after,.dsgc-fold,.dsgc-fold-inner,.dsgc-fold.open,.dsgc-fold.open .dsgc-fold-inner,[class*=\"panelRow\"]:has(.dsgc-entryOverlay){transition:none}.dsgc-dot:hover{transform:none}.dsgc-drawer,.dsgc-msg,.dsgc-sysmsg,.dsgc-mention,.dsgc-tobottom,.dsgc-err,.dsgc-empty,.dsgc-fb,.dsgc-msg.live .dsgc-avatar,.dsgc-loading svg,.dsgc-pendingdots i,.dsgc-typing,.dsgc-constraints,.dsgc-hovertip,.dsgc-fail{animation:none}.dsgc-typing{background-position:0 0;background-size:100% 100%}}',\n /* ===== 设置页(同一卡片语言) ===== */\n '.dgcs-page{display:flex;flex-direction:column;gap:14px;padding:4px 0}',\n '.dgcs-head{display:flex;flex-direction:column;gap:6px}',\n '.dgcs-title{margin:0;font-size:15px;font-weight:600;line-height:1.4;color:var(--dsw-alias-label-primary,inherit)}',\n '.dgcs-desc{margin:0;font-size:13px;line-height:1.6;color:var(--dsw-alias-label-secondary,inherit)}',\n '.dgcs-card{display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-alias-bg-layer-3,transparent);border-radius:12px;padding:14px 16px;transition:border-color .16s}',\n '.dgcs-cardtext{display:flex;flex-direction:column;gap:3px;min-width:0}',\n '.dgcs-cardtitle{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,inherit)}',\n '.dgcs-cardhint{font-size:12px;color:var(--dsw-alias-label-tertiary,inherit)}',\n].join('\\n')\n\n/** 工厂执行时幂等注入样式标签(loader 卸载时按 data-plugin 摘除)。 */\nexport function injectStyles(): void {\n if (typeof document === 'undefined') return\n if (document.querySelector('style[data-plugin-css=' + JSON.stringify(TAG_ID) + ']') === null) {\n const tag = document.createElement('style')\n tag.dataset.plugin = '@roaming-ai/dsh-group-chat'\n tag.dataset.pluginCss = TAG_ID\n tag.textContent = CSS\n document.head.appendChild(tag)\n }\n}\n","/**\n * 浏览器半 UI 基座:DSW 原语(shell 静态种子模块,loader 模块表 external)\n * 与动态图标 / 命令式 createElement 辅助。组件主体已 JSX 化(.tsx);此处\n * 仅保留 slot 注册回调与动态图标表需要的少量命令式辅助。\n * @module dsh-group-chat/client/ui\n */\n\nimport { createElement, type ReactNode } from 'react'\nimport * as P from '@deepseek-ai/dsh-client-ui-primitives'\n\nexport { P }\n\n/** 命令式 createElement(仅 slot 注册回调用)。 */\nexport const h = createElement as unknown as (type: unknown, props?: Record<string, unknown> | null, ...children: unknown[]) => ReactNode\n\n/** 图标组件的调用形态。 */\nexport type IconComponent = (props: Record<string, unknown>) => ReactNode\n\n/** 按名取 DSW 原语(图标表驱动)。 */\nexport function pickPrimitive(name: string): IconComponent {\n return (P as unknown as Record<string, IconComponent>)[name]\n}\n\n/** 以统一 size 包装图标组件调用(放在 JSX 子元素位)。 */\nexport function Icon(comp: unknown, size: number, extra?: Record<string, unknown>): ReactNode {\n return h(comp as never, Object.assign({ size }, extra || {}))\n}\n","/**\n * 会话状态派生(纯函数):从快照 run 派生单个会话的列表状态,\n * 语义对齐 DSH 主会话列表(StateDot 五态取四)。\n *\n * 优先级:等待确认 > 进行中 > 已完成/已出错 > 默认(无点)。\n * - ongoing:run 进行中(含用户已点停止但未停完的 stopping 窗口)\n * - warning:run_command 确认闸门挂起(仅工作区内修改档)\n * - done/error:run 结束后的「输出完毕」标记(正常/停止 → done,发言失败 → error)\n * - idle:无任何活动(不渲染状态点,对齐主 GUI idle 隐藏)\n * @module dsh-group-chat/core/status\n */\n\nimport type { Snapshot } from './types.ts'\n\n/** 会话列表状态(取值即 StateDotState 的渲染态)。 */\nexport type SessStatus = 'idle' | 'ongoing' | 'warning' | 'done' | 'error'\n\n/** 状态点悬停/读屏文案(idle 不渲染点,无文案)。 */\nexport const SESS_STATUS_LABEL: Record<SessStatus, string> = {\n idle: '',\n ongoing: '进行中',\n warning: '等待确认',\n done: '已完成',\n error: '已出错',\n}\n\n/** 派生单个会话的列表状态(run 为快照的 run 视图)。 */\nexport function sessStatus(run: Snapshot['run'], sessionId: string): SessStatus {\n if (run.running && run.sessionId === sessionId) return run.pendingConfirm ? 'warning' : 'ongoing'\n const f = run.finished\n if (f && f.sessionId === sessionId) return f.reason === 'error' ? 'error' : 'done'\n return 'idle'\n}\n","/**\n * 浏览器半共享常量与小工具(纯函数,无 React 依赖)。\n * @module dsh-group-chat/client/model\n */\n\nimport type { Snapshot } from '../../core/types.ts'\n\n/** 会话列表状态派生与文案(core 纯函数,供 NavPanel 渲染)。 */\nexport { sessStatus, SESS_STATUS_LABEL, type SessStatus } from '../../core/status.ts'\n\n/** 角色标识色调色板(与宿主半一致)。 */\nexport const PALETTE = ['#5b8def', '#22a06b', '#e8912d', '#c678dd', '#e05661', '#56b6c2', '#98c379', '#d19a66']\n\n/** Host HTTP API 前缀。 */\nexport const API_PREFIX = '/api/group-chat'\n\n/** MarkdownText 渲染文案。 */\nexport const MD_LABELS = Object.freeze({ code: { copyLabel: '复制', copiedLabel: '已复制' }, footnotes: '脚注' })\n\n/** 快照的 wire 形态(响应里带 ok 标记)。 */\nexport type ClientSnapshot = Snapshot & { ok: boolean }\n\n/** models action 的响应形态。 */\nexport interface ModelsResponse {\n ok: boolean\n providers?: { id: string, name?: string }[]\n modelsByProvider?: Record<string, { id: string, name?: string }[]>\n error?: string\n}\n\n/** efforts action 的响应形态。 */\nexport interface EffortsResponse {\n ok: boolean\n efforts?: { id: string, name: string, description?: string }[]\n defaultEffort?: string\n error?: string\n}\n\n/** 快照内的角色/会话/群组视图行。 */\nexport type SnapshotRole = Snapshot['roles'][number]\nexport type SnapshotSession = Snapshot['sessions'][number]\nexport type SnapshotGroup = Snapshot['groups'][number]\nexport type SnapshotMessage = Snapshot['messages'][number]\n\nexport function roleById(s: ClientSnapshot, id: string | null): SnapshotRole | null {\n for (const r of s.roles) if (r.id === id) return r\n return null\n}\n\nexport function sessById(s: ClientSnapshot, id: string): SnapshotSession | null {\n for (const x of s.sessions) if (x.id === id) return x\n return null\n}\n\nexport function groupById(s: ClientSnapshot, id: string): SnapshotGroup | null {\n for (const g of s.groups) if (g.id === id) return g\n return null\n}\n\nexport function escapeRegExp(v: string): string {\n return String(v).replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nexport function firstLine(text: string): string {\n const i = text.indexOf('\\n')\n return i === -1 ? text : text.slice(0, i)\n}\n\nexport function latestLine(text: string): string {\n const visible = text.trimEnd()\n const i = visible.lastIndexOf('\\n')\n return i === -1 ? visible : visible.slice(i + 1)\n}\n\nexport function fmtTime(ts: number): string {\n const delta = Math.max(0, Date.now() - ts)\n if (delta < 60000) return '刚刚'\n if (delta < 3600000) return Math.floor(delta / 60000) + ' 分钟前'\n if (delta < 86400000) return Math.floor(delta / 3600000) + ' 小时前'\n const d = new Date(ts)\n const sameYear = d.getFullYear() === new Date().getFullYear()\n const pad = (n: number): string => (n < 10 ? '0' + n : '' + n)\n return sameYear ? (d.getMonth() + 1) + '月' + d.getDate() + '日' : d.getFullYear() + '/' + (d.getMonth() + 1) + '/' + d.getDate()\n}\n\n/** 角色编辑抽屉的草稿形态(编辑与新建共用)。 */\nexport interface RoleDraft {\n id?: string\n name: string\n color: string | null\n persona: string\n provider: string\n model: string\n temperature?: number\n reasoningEffort: string\n enabled?: boolean\n thinking: boolean\n}\n\nexport function draftFromRole(role: SnapshotRole): RoleDraft {\n return { id: role.id, name: role.name, color: role.color ?? null, persona: role.persona, provider: role.provider, model: role.model, temperature: role.temperature, reasoningEffort: role.reasoningEffort || 'default', enabled: role.enabled, thinking: role.thinking === true }\n}\n\nexport function blankDraft(): RoleDraft {\n return { name: '', color: null, persona: '', provider: '', model: '', temperature: undefined, reasoningEffort: 'default', enabled: true, thinking: false }\n}\n","/**\n * 浏览器半 transport:/api/group-chat/* 同源 JSON 端点。\n * @module dsh-group-chat/client/api\n */\n\nimport { API_PREFIX } from './model.ts'\n\nasync function readJson<T>(fetchPromise: Promise<Response>): Promise<T> {\n const response = await fetchPromise\n const body = await response.json() as { error?: string }\n if (!response.ok) throw new Error(body && body.error ? body.error : '请求失败(HTTP ' + response.status + '),请稍后重试')\n return body as unknown as T\n}\n\nexport const api = {\n state: (): Promise<unknown> => readJson(fetch(API_PREFIX + '/state', { cache: 'no-store' })),\n action: (payload: Record<string, unknown>, signal?: AbortSignal): Promise<unknown> => readJson(fetch(API_PREFIX + '/action', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n signal,\n })),\n}\n","/**\n * 角色编辑抽屉(右侧滑出,不遮挡会话流阅读)。\n * @module dsh-group-chat/client/drawer\n */\n\nimport { useEffect, useRef, useState, type ReactNode } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport { api } from '../lib/api.ts'\nimport { PALETTE, type EffortsResponse, type ModelsResponse, type RoleDraft } from '../lib/model.ts'\nimport type { MutateResponse } from '../hooks/useGroupChatState.ts'\n\nexport interface RoleDrawerProps {\n draft: RoleDraft\n set: (draft: RoleDraft) => void\n /** 保存目标群组(upsertRole 落库)。 */\n groupId: string\n models: ModelsResponse | null\n modelsError: string | null\n onRetryModels: () => void\n mutate: (args: Record<string, unknown>) => Promise<unknown>\n onCancel: () => void\n}\n\nexport function RoleDrawer(props: RoleDrawerProps): ReactNode {\n const { draft, set, groupId } = props\n const models = props.models\n const providers = (models && models.providers) || []\n const modelsOf = (models && models.modelsByProvider && models.modelsByProvider[draft.provider]) || []\n const [closing, setClosing] = useState(false)\n // Esc 监听挂在空依赖上,闭包看的是首帧 closing(恒 false)——用 ref 挡住\n // 退场动画窗口内的重复触发\n const closingRef = useRef(false)\n const [formError, setFormError] = useState('')\n const [effortsInfo, setEffortsInfo] = useState<EffortsResponse | null>(null)\n const close = (): void => {\n if (closingRef.current) return\n closingRef.current = true\n setClosing(true)\n window.setTimeout(() => props.onCancel(), 140)\n }\n const onProvider = (e: { target: { value: string } }): void => {\n const p = e.target.value\n const list = (models && models.modelsByProvider && models.modelsByProvider[p]) || []\n // 换模型路线后旧推理级别失效,重置为默认\n set(Object.assign({}, draft, { provider: p, model: list.length ? list[0].id : '', reasoningEffort: 'default' }))\n }\n /** 保存(校验在本地,落库经 mutate;失败文案与原实现逐字一致)。 */\n const save = async (): Promise<void> => {\n if (!draft.name.trim()) {\n setFormError('角色名称不能为空')\n return\n }\n if (!draft.provider || !draft.model) {\n setFormError('请选择角色绑定的模型')\n return\n }\n const res = await props.mutate({ op: 'upsertRole', groupId, role: draft }) as MutateResponse | null\n if (res && res.ok && res.snapshot && !res.snapshot.error) {\n props.onCancel()\n }\n }\n useEffect(() => {\n const onKey = (e: KeyboardEvent): void => { if (e.key === 'Escape') close() }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [])\n // 推理级别选项:跟随抽屉内 provider/model 变化重新查询(Host 60s 缓存)\n useEffect(() => {\n let live = true\n setEffortsInfo(null)\n if (!draft.provider || !draft.model) return\n api.action({ kind: 'efforts', provider: draft.provider, model: draft.model }).then((res) => {\n if (!live) return\n const r = res as EffortsResponse\n if (r && r.ok) setEffortsInfo({ ok: true, efforts: r.efforts || [], defaultEffort: r.defaultEffort })\n else setEffortsInfo({ ok: false, efforts: [], defaultEffort: undefined, error: (r && r.error) || '查询失败' })\n }).catch((e: unknown) => { if (live) setEffortsInfo({ ok: false, efforts: [], defaultEffort: undefined, error: String((e && (e as Error).message) || e) }) })\n return () => { live = false }\n }, [draft.provider, draft.model])\n return (\n <div className={'dsgc-drawer' + (closing ? ' closing' : '')} role=\"dialog\" aria-modal=\"false\" aria-label={draft.id ? '编辑角色' : '添加角色'}>\n <div className=\"dsgc-drawerhead\">\n {Icon(P.IconUserOutline16, 16)}\n <span className=\"dsgc-drawertitle\">{draft.id ? '编辑角色' : '添加角色'}</span>\n <P.Button variant=\"ghost\" size=\"sm\" onClick={close} aria-label=\"关闭\">{Icon(P.IconCloseOutline16, 16)}</P.Button>\n </div>\n <div className=\"dsgc-drawerbody\">\n <div className=\"dsgc-form\">\n <div className=\"dsgc-field\">\n <label>名称</label>\n <input\n className=\"dsgc-input\"\n value={draft.name}\n autoFocus={!draft.id}\n onChange={(e) => { set(Object.assign({}, draft, { name: e.target.value })) }}\n placeholder=\"例如:产品经理\"\n />\n </div>\n <div className=\"dsgc-field\">\n <label>标识色</label>\n <div className=\"dsgc-palette\">\n {PALETTE.map((c) => (\n <button\n key={c}\n type=\"button\"\n className={'dsgc-dot' + (draft.color === c ? ' on' : '')}\n style={{ background: c }}\n onClick={() => { set(Object.assign({}, draft, { color: c })) }}\n aria-label={'选择标识色 ' + c}\n />\n ))}\n </div>\n </div>\n <div className=\"dsgc-field\">\n <label>人设 / 角色设定</label>\n <textarea\n className=\"dsgc-textarea\"\n rows={4}\n value={draft.persona}\n onChange={(e) => { set(Object.assign({}, draft, { persona: e.target.value })) }}\n placeholder=\"性格、立场、说话风格、专业背景……\"\n />\n </div>\n <div className=\"dsgc-field\">\n <label>模型提供方</label>\n {providers.length\n ? (\n <select className=\"dsgc-select\" value={draft.provider} onChange={onProvider}>\n <option value=\"\">选择提供方…</option>\n {providers.map((p) => <option key={p.id} value={p.id}>{p.name || p.id}</option>)}\n </select>\n )\n : (\n <div className=\"dsgc-selhint\">\n {(props.modelsError ? '模型目录加载失败:' + props.modelsError : '暂无可用 provider') + ' '}\n <P.Button variant=\"outline\" size=\"sm\" onClick={props.onRetryModels}>重试</P.Button>\n </div>\n )}\n </div>\n <div className=\"dsgc-field\">\n <label>模型</label>\n {modelsOf.length\n ? (\n <select\n className=\"dsgc-select\"\n value={draft.model}\n onChange={(e) => { set(Object.assign({}, draft, { model: e.target.value, reasoningEffort: 'default' })) }}\n >\n {modelsOf.map((m) => <option key={m.id} value={m.id}>{m.name || m.id}</option>)}\n </select>\n )\n : <div className=\"dsgc-selhint\">请先选择有可用模型的提供方</div>}\n </div>\n <div className=\"dsgc-field\">\n <label>温度(可选)</label>\n <input\n className=\"dsgc-input\"\n type=\"number\"\n step=\"0.1\"\n min=\"0\"\n max=\"2\"\n value={draft.temperature == null ? '' : String(draft.temperature)}\n onChange={(e) => { set(Object.assign({}, draft, { temperature: e.target.value === '' ? undefined : Number(e.target.value) })) }}\n />\n </div>\n <div className=\"dsgc-field\">\n <label>深度思考</label>\n <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>\n <P.Switch checked={draft.thinking === true} onChange={(v: boolean) => { set(Object.assign({}, draft, { thinking: v })) }} label=\"深度思考\" />\n <span className=\"dsgc-hint\">开启后角色发言前先思考(支持思考的模型)</span>\n </div>\n </div>\n {draft.thinking === true\n ? (\n <div className=\"dsgc-field\">\n <label>推理级别</label>\n {effortsInfo === null\n ? <div className=\"dsgc-selhint\">查询推理级别…</div>\n : !effortsInfo.ok\n ? <div className=\"dsgc-selhint\">推理级别查询失败:{effortsInfo.error}(若刚更新插件,请重启 dsh web 使 host 半生效)</div>\n : (effortsInfo.efforts || []).length\n ? (\n <select\n className=\"dsgc-select\"\n value={draft.reasoningEffort && draft.reasoningEffort !== 'default' ? draft.reasoningEffort : 'default'}\n onChange={(e) => { set(Object.assign({}, draft, { reasoningEffort: e.target.value })) }}\n title=\"取自当前模型设置中的推理选项;默认 = 使用该模型的默认推理级别\"\n >\n <option value=\"default\">\n 默认{effortsInfo.defaultEffort ? '(当前默认:' + ((effortsInfo.efforts || []).find((x) => x.id === effortsInfo.defaultEffort) || { name: '' }).name + ')' : ''}\n </option>\n {(effortsInfo.efforts || []).map((e) => <option key={e.id} value={e.id} title={e.description || ''}>{e.name || e.id}</option>)}\n </select>\n )\n : <div className=\"dsgc-selhint\">当前模型未提供推理等级,将使用默认</div>}\n </div>\n )\n : null}\n {formError ? <div className=\"dsgc-formerr\">{formError}</div> : null}\n </div>\n </div>\n <div className=\"dsgc-drawerfoot\">\n <P.Button variant=\"outline\" onClick={close}>取消</P.Button>\n <P.Button variant=\"primary\" onClick={() => { void save() }}>{draft.id ? '保存' : '添加'}</P.Button>\n </div>\n </div>\n )\n}\n","/**\n * 对齐宿主 Tooltip 的 hover 气泡:portal 到 document.body,躲开\n * `.dsgc-root` 的 container-type 把 position:fixed 按容器定位。\n * @module dsh-group-chat/client/components\n */\n\nimport { useEffect, useLayoutEffect, useRef, useState, type ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\n\nexport type HoverTipSide = 'top' | 'right'\n\ninterface HoverTipProps {\n label: string\n side?: HoverTipSide\n delayMs?: number\n maxWidth?: number\n className?: string\n children: ReactNode\n}\n\ninterface AnchorBox {\n x: number\n top: number\n bottom: number\n}\n\n/**\n * @param props.label 气泡正文(pre-line)\n * @param props.side 默认 right(对齐侧栏会话行);composer 轮数用 top\n * @param props.delayMs hover 延迟,默认 500;键盘 focus 立即出\n */\nexport function HoverTip(props: HoverTipProps): ReactNode {\n const { label, side = 'right', delayMs = 500, maxWidth, className, children } = props\n const anchorRef = useRef<HTMLDivElement>(null)\n const bubbleRef = useRef<HTMLSpanElement>(null)\n const showTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n const hover = useRef(false)\n const [pos, setPos] = useState<AnchorBox | null>(null)\n const [placement, setPlacement] = useState<'top' | 'bottom' | 'right'>(side)\n\n const cancel = (): void => {\n if (showTimer.current === null) return\n clearTimeout(showTimer.current)\n showTimer.current = null\n }\n const show = (): void => {\n const el = anchorRef.current\n if (!el || !label) return\n const r = el.getBoundingClientRect()\n setPlacement(side)\n setPos({\n x: side === 'right' ? r.right + 10 : r.left + r.width / 2,\n top: r.top,\n bottom: r.bottom,\n })\n }\n const hideIfIdle = (): void => {\n if (!hover.current && !(anchorRef.current && anchorRef.current.contains(document.activeElement))) setPos(null)\n }\n\n useEffect(() => cancel, [])\n useLayoutEffect(() => {\n if (!pos) return\n const fit = (): void => {\n const el = bubbleRef.current\n if (!el) return\n el.style.left = pos.x + 'px'\n const r = el.getBoundingClientRect()\n let dx = 0\n if (r.right > window.innerWidth - 12) dx = window.innerWidth - 12 - r.right\n if (r.left + dx < 12) dx = 12 - r.left\n el.style.left = pos.x + dx + 'px'\n if (side === 'right') return\n const fitsBelow = pos.bottom + 8 + r.height <= window.innerHeight - 12\n const fitsAbove = pos.top - 8 - r.height >= 12\n if (placement === 'bottom' && !fitsBelow && fitsAbove) setPlacement('top')\n if (placement === 'top' && !fitsAbove && fitsBelow) setPlacement('bottom')\n }\n fit()\n window.addEventListener('resize', fit)\n return () => { window.removeEventListener('resize', fit) }\n }, [pos, placement, label, side])\n\n const y = pos === null\n ? 0\n : placement === 'right'\n ? pos.top + (pos.bottom - pos.top) / 2\n : placement === 'top'\n ? pos.top - 8\n : pos.bottom + 8\n\n return (\n <>\n <div\n ref={anchorRef}\n className={className}\n onMouseEnter={() => {\n hover.current = true\n cancel()\n if (delayMs <= 0) { show(); return }\n showTimer.current = setTimeout(() => { showTimer.current = null; show() }, delayMs)\n }}\n onMouseLeave={() => {\n hover.current = false\n cancel()\n hideIfIdle()\n }}\n onFocus={() => { cancel(); show() }}\n onBlur={(e) => {\n const next = e.relatedTarget as Node | null\n if (next && anchorRef.current && anchorRef.current.contains(next)) return\n cancel()\n hideIfIdle()\n }}\n >\n {children}\n </div>\n {pos\n ? createPortal(\n <span\n ref={bubbleRef}\n className=\"dsgc-hovertip\"\n data-side={placement}\n role=\"tooltip\"\n style={{ left: pos.x, top: y, ...(maxWidth ? { maxWidth } : {}) }}\n >\n {label}\n </span>,\n document.body,\n )\n : null}\n </>\n )\n}\n","/**\n * 左侧导航栏组件(群组 → 会话目录树;群组行与会话行共用重命名/删除三件套)。\n * @module dsh-group-chat/client/components\n */\n\nimport type { ReactNode, KeyboardEvent as ReactKeyboardEvent } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport { HoverTip } from './HoverTip.tsx'\nimport { groupById, sessById, sessStatus, SESS_STATUS_LABEL, type ClientSnapshot } from '../lib/model.ts'\n\n/** 目录树节点编辑态形状(群组/会话共用)。 */\ntype NodeEdit = { kind: 'group' | 'session', id: string, value: string }\n\ninterface NavPanelProps {\n snap: ClientSnapshot\n search: string\n setSearch: (val: string) => void\n collapsedGroups: Set<string>\n setCollapsedGroups: (fn: (prev: Set<string>) => Set<string>) => void\n gid: string | null\n sid: string | null\n setGid: (val: string) => void\n setSid: (val: string) => void\n setPartsSel: (val: string[] | null) => void\n renameDraft: NodeEdit | null\n setRenameDraft: (val: NodeEdit | null) => void\n confirmDel: { kind: 'group' | 'session', id: string } | null\n setConfirmDel: (val: { kind: 'group' | 'session', id: string } | null) => void\n mutate: (args: Record<string, unknown>) => Promise<unknown>\n navOpen: boolean\n}\n\n/** 内联重命名输入(群组行/会话行同款)。 */\nfunction RenameField(props: { draft: NodeEdit, set: (d: NodeEdit | null) => void, commit: () => void, keyDown: (e: ReactKeyboardEvent<HTMLInputElement>) => void }): ReactNode {\n const { draft, set, commit, keyDown } = props\n return (\n <input\n className=\"dsgc-rename\"\n value={draft.value}\n autoFocus\n onChange={(e) => { set({ kind: draft.kind, id: draft.id, value: e.target.value }) }}\n onBlur={() => { commit() }}\n onKeyDown={keyDown}\n onClick={(e) => { e.stopPropagation() }}\n />\n )\n}\n\n/** 行尾操作钮:重命名 + 两次点击确认删除(群组行/会话行同款)。 */\nfunction NodeOps(props: { renameLabel: string, deleteLabel: string, deleteTitle: string, danger: boolean, onRename: () => void, onDelete: () => void }): ReactNode {\n const { renameLabel, deleteLabel, deleteTitle, danger, onRename, onDelete } = props\n return (\n <span className=\"dsgc-nodeops\">\n <button\n className=\"dsgc-opbtn\"\n title={renameLabel}\n aria-label={renameLabel}\n onClick={(e) => { e.stopPropagation(); onRename() }}\n >\n {Icon(P.IconEditOutline16, 14)}\n </button>\n <button\n className={'dsgc-opbtn' + (danger ? ' danger' : '')}\n title={deleteTitle}\n aria-label={deleteLabel}\n onClick={(e) => { e.stopPropagation(); onDelete() }}\n >\n {Icon(P.IconTrashOutline16, 14)}\n </button>\n </span>\n )\n}\n\nexport function NavPanel(props: NavPanelProps): ReactNode {\n const { snap, search, setSearch, collapsedGroups, setCollapsedGroups, gid, sid, setGid, setSid, setPartsSel, renameDraft, setRenameDraft, confirmDel, setConfirmDel, mutate, navOpen } = props\n\n const commitRename = async (): Promise<void> => {\n if (!renameDraft) return\n const d = renameDraft\n setRenameDraft(null)\n const value = String(d.value || '').trim()\n if (!value) return\n if (d.kind === 'group') await mutate({ op: 'renameGroup', groupId: d.id, name: value })\n else await mutate({ op: 'renameSession', sessionId: d.id, name: value })\n }\n\n const renameKeyDown = (e: ReactKeyboardEvent<HTMLInputElement>): void => {\n if (e.key === 'Enter') {\n e.preventDefault()\n void commitRename()\n } else if (e.key === 'Escape') {\n e.preventDefault()\n setRenameDraft(null)\n }\n }\n\n const doDelete = async (): Promise<void> => {\n if (!confirmDel) return\n const d = confirmDel\n setConfirmDel(null)\n if (d.kind === 'group') await mutate({ op: 'deleteGroup', groupId: d.id })\n else await mutate({ op: 'deleteSession', sessionId: d.id })\n }\n\n // 选中即清编辑态(四连调用收敛为一处)\n const clearEdits = (): void => {\n setPartsSel(null)\n setConfirmDel(null)\n setRenameDraft(null)\n }\n const pickGroup = (id: string): void => {\n setGid(id)\n clearEdits()\n }\n const pickSession = (gidToSet: string, sidToSet: string): void => {\n setGid(gidToSet)\n setSid(sidToSet)\n clearEdits()\n }\n\n const q = search.trim().toLowerCase()\n const groupMatches = (g: ClientSnapshot['groups'][number]): { show: boolean, filterSessions: boolean } => {\n if (!q) return { show: true, filterSessions: false }\n if (g.name.toLowerCase().includes(q)) return { show: true, filterSessions: false }\n const hitSessions = g.sessionIds.map((id) => sessById(snap, id)).filter((s) => s && s.name.toLowerCase().includes(q))\n return { show: hitSessions.length > 0, filterSessions: true }\n }\n\n const group = gid ? groupById(snap, gid) : null\n const selected = sid ? sessById(snap, sid) : null\n\n const treeNodes: ReactNode[] = []\n for (const g of snap.groups) {\n const match = groupMatches(g)\n if (!match.show) continue\n const expanded = q ? true : !collapsedGroups.has(g.id)\n const isRenameGroup = renameDraft && renameDraft.kind === 'group' && renameDraft.id === g.id\n const isConfirmGroup = confirmDel && confirmDel.kind === 'group' && confirmDel.id === g.id\n const groupChildren: ReactNode[] = []\n\n if (expanded) {\n for (const sessionId of g.sessionIds) {\n const s = sessById(snap, sessionId)\n if (!s) continue\n if (match.filterSessions && !s.name.toLowerCase().includes(q)) continue\n const isActive = selected && s.id === selected.id && g.id === group?.id\n const isRenameSess = renameDraft && renameDraft.kind === 'session' && renameDraft.id === s.id\n const isConfirm = confirmDel && confirmDel.kind === 'session' && confirmDel.id === s.id\n // 会话状态(对齐主 GUI StateDot:idle 不渲染点)\n const st = sessStatus(snap.run, s.id)\n\n groupChildren.push(\n <div\n key={s.id}\n className={'dsgc-sess-row' + (isActive ? ' on' : '')}\n role=\"button\"\n tabIndex={0}\n onClick={() => { pickSession(g.id, s.id) }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n pickSession(g.id, s.id)\n }\n }}\n >\n {/* 固定宽度状态槽(对齐主 GUI:槽恒在、点按状态渲染——行间文案对齐) */}\n <span className=\"dsgc-sess-status\">\n {st !== 'idle'\n ? (\n <span role=\"img\" title={SESS_STATUS_LABEL[st]} aria-label={SESS_STATUS_LABEL[st]}>\n <P.StateDot state={st} size={8} />\n </span>\n )\n : null}\n </span>\n {isRenameSess\n ? <RenameField draft={renameDraft!} set={setRenameDraft} commit={() => { void commitRename() }} keyDown={renameKeyDown} />\n : (\n <HoverTip label={s.name} side=\"right\" delayMs={500} className=\"dsgc-sess-name\">\n {s.name}\n </HoverTip>\n )}\n <NodeOps\n renameLabel=\"重命名会话\"\n deleteLabel=\"删除会话\"\n deleteTitle={isConfirm ? '再次点击确认删除' : '删除会话'}\n danger={!!isConfirm}\n onRename={() => { setRenameDraft({ kind: 'session', id: s.id, value: s.name }) }}\n onDelete={() => {\n if (isConfirm) void doDelete()\n else setConfirmDel({ kind: 'session', id: s.id })\n }}\n />\n </div>,\n )\n }\n\n groupChildren.push(\n <button key=\"__add\" className=\"dsgc-addsess\" onClick={() => { void mutate({ op: 'createSession', groupId: g.id }) }}>\n {Icon(P.IconPlusOutline16, 14)}新会话\n </button>,\n )\n }\n\n treeNodes.push(\n <div key={g.id} className=\"dsgc-gnode\">\n <div\n className={'dsgc-grow-row' + (g.id === group?.id ? ' on' : '')}\n role=\"button\"\n tabIndex={0}\n onClick={() => { pickGroup(g.id) }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n pickGroup(g.id)\n }\n }}\n >\n <button\n className={'dsgc-twist' + (expanded ? '' : ' closed')}\n title={expanded ? '收起' : '展开'}\n aria-label={expanded ? '收起' : '展开'}\n onClick={(e) => {\n e.stopPropagation()\n setCollapsedGroups((prev) => {\n const next = new Set(prev)\n if (next.has(g.id)) next.delete(g.id)\n else next.add(g.id)\n return next\n })\n }}\n >\n {Icon(P.IconChevronDownOutline14, 14)}\n </button>\n {isRenameGroup\n ? <RenameField draft={renameDraft!} set={setRenameDraft} commit={() => { void commitRename() }} keyDown={renameKeyDown} />\n : <span className=\"dsgc-gname\">{g.name}</span>}\n <NodeOps\n renameLabel=\"重命名群组\"\n deleteLabel=\"删除群组\"\n deleteTitle={isConfirmGroup ? '再次点击确认删除' : '删除群组'}\n danger={!!isConfirmGroup}\n onRename={() => { setRenameDraft({ kind: 'group', id: g.id, value: g.name }) }}\n onDelete={() => {\n if (isConfirmGroup) void doDelete()\n else setConfirmDel({ kind: 'group', id: g.id })\n }}\n />\n </div>\n {expanded ? <div className=\"dsgc-sess-list\">{groupChildren}</div> : null}\n </div>,\n )\n }\n\n return (\n <div className={'dsgc-nav' + (navOpen ? '' : ' closed')} aria-hidden={navOpen ? undefined : 'true'}>\n <P.Input\n icon={Icon(P.IconSearchOutline16, 16)}\n className=\"dsgc-search\"\n placeholder=\"搜索群组与会话…\"\n value={search}\n onChange={(e: { target: { value: string } }) => setSearch(e.target.value)}\n />\n {treeNodes.length\n ? <div className=\"dsgc-tree\">{treeNodes}</div>\n : <div className=\"dsgc-hint\">{q ? '没有匹配「' + search.trim() + '」的群组或会话' : '暂无群组'}</div>}\n <P.Button variant=\"outline\" onClick={() => { void mutate({ op: 'createGroup' }) }}>\n {Icon(P.IconPlusOutline16, 16)}新建群组\n </P.Button>\n </div>\n )\n}\n","/**\n * 右侧成员与工作区栏组件。工作区目录编辑态(草稿、文件浏览器)为栏内自有状态。\n * @module dsh-group-chat/client/components\n */\n\nimport { useState, type ReactNode } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport { api } from '../lib/api.ts'\nimport { roleById, type ClientSnapshot, type SnapshotRole } from '../lib/model.ts'\nimport type { BrowseResult } from '../../core/types.ts'\n\ninterface AsidePanelProps {\n snap: ClientSnapshot\n group: ClientSnapshot['groups'][number]\n asideOpen: boolean\n mutate: (args: Record<string, unknown>) => Promise<unknown>\n openRoleEditor: (role: SnapshotRole | null) => void\n}\n\n/** 文件浏览器态(栏内自有)。 */\ninterface FileBrowserState {\n open: boolean\n loading: boolean\n list: BrowseResult | null\n error: string\n}\n\nexport function AsidePanel(props: AsidePanelProps): ReactNode {\n const { snap, group, asideOpen, mutate, openRoleEditor } = props\n const [wsDraft, setWsDraft] = useState<string | null>(null)\n const [fileBrowser, setFileBrowser] = useState<FileBrowserState | null>(null)\n\n const commitWsDir = (): void => {\n if (wsDraft !== null && group && wsDraft !== (group.workspaceDir || '')) {\n void mutate({ op: 'setWorkspaceDir', groupId: group.id, path: wsDraft })\n }\n setWsDraft(null)\n }\n\n const openBrowser = async (path: string | undefined): Promise<void> => {\n setFileBrowser({ open: true, loading: true, list: null, error: '' })\n try {\n const res = await api.action({ kind: 'browse', path: path || '' }) as BrowseResult\n if (res && res.ok) setFileBrowser({ open: true, loading: false, list: res, error: '' })\n else setFileBrowser({ open: true, loading: false, list: null, error: (res && res.error) || '浏览失败' })\n } catch (e) {\n setFileBrowser({ open: true, loading: false, list: null, error: String((e && (e as Error).message) || e) })\n }\n }\n\n const selectCurrentDir = (): void => {\n if (!fileBrowser || !fileBrowser.list || !group) return\n const path = fileBrowser.list.path!\n void mutate({ op: 'setWorkspaceDir', groupId: group.id, path })\n setWsDraft(null)\n setFileBrowser(null)\n }\n\n return (\n <div className={'dsgc-aside' + (asideOpen ? '' : ' closed')} aria-hidden={asideOpen ? undefined : 'true'}>\n <div className=\"dsgc-sec\">\n <div className=\"dsgc-sechead\">\n 群成员\n <span className=\"dsgc-secspacer\" />\n <span className=\"dsgc-seccount\">{group.roleIds.length ? group.roleIds.length + ' 个' : ''}</span>\n <P.Button variant=\"ghost\" size=\"sm\" onClick={() => { openRoleEditor(null) }} aria-label=\"添加角色\">\n {Icon(P.IconPlusOutline16, 14)}添加\n </P.Button>\n </div>\n {group.roleIds.length\n ? (\n <div className=\"dsgc-roles\">\n {group.roleIds.map((rid) => {\n const r = roleById(snap, rid)\n if (!r) return null\n return (\n <div\n key={r.id}\n className={'dsgc-role' + (r.enabled ? '' : ' off')}\n role=\"button\"\n tabIndex={0}\n onClick={() => { openRoleEditor(r) }}\n onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); openRoleEditor(r) } }}\n title=\"点击编辑角色\"\n >\n <div className=\"dsgc-rolehead\">\n <span className=\"dsgc-roledot\" style={{ background: r.color || '#888' }} />\n <span className=\"dsgc-rolename\">{r.name}</span>\n <P.Tooltip label={r.enabled ? '停用该角色' : '启用该角色'} side=\"top\" delayMs={300}>\n <span\n onClick={(e) => { e.stopPropagation() }}\n onKeyDown={(e) => { e.stopPropagation() }}\n style={{ display: 'inline-flex', flex: 'none' }}\n >\n <P.Switch\n checked={r.enabled}\n onChange={() => { void mutate({ op: 'setRoleEnabled', roleId: r.id, enabled: !r.enabled }) }}\n label={r.enabled ? '停用该角色' : '启用该角色'}\n aria-label={(r.enabled ? '停用' : '启用') + '角色 ' + r.name}\n />\n </span>\n </P.Tooltip>\n </div>\n {r.persona ? <div className=\"dsgc-rolepersona\" title={r.persona}>{r.persona}</div> : null}\n <div className=\"dsgc-rolemenu\">\n <span className=\"dsgc-rolemeta\">\n <span\n className=\"dsgc-rolemodel\"\n title={r.provider + ' / ' + r.model + (r.thinking ? ' · 深度思考' + (r.reasoningEffort && r.reasoningEffort !== 'default' ? '(' + r.reasoningEffort + ')' : '') : '')}\n >\n {r.provider} / {r.model}\n </span>\n {r.thinking\n ? <span className=\"dsgc-rolethink\" title=\"深度思考\">{Icon(P.IconThinkOutline14, 14)}</span>\n : null}\n </span>\n <span className=\"dsgc-roleops\">\n <button\n className=\"dsgc-opbtn\"\n title=\"编辑角色\"\n aria-label=\"编辑角色\"\n onClick={(e) => { e.stopPropagation(); openRoleEditor(r) }}\n >\n {Icon(P.IconEditOutline16, 14)}\n </button>\n <button\n className=\"dsgc-opbtn danger\"\n title=\"移除角色\"\n aria-label=\"移除角色\"\n onClick={(e) => { e.stopPropagation(); void mutate({ op: 'deleteRole', roleId: r.id }) }}\n >\n {Icon(P.IconTrashOutline16, 14)}\n </button>\n </span>\n </div>\n </div>\n )\n })}\n </div>\n )\n : <div className=\"dsgc-hint\">还没有角色。每个角色可绑定不同的 provider/model,在群内以独立身份发言。</div>}\n </div>\n <div className=\"dsgc-sec\">\n <div className=\"dsgc-sechead\">工作区目录</div>\n <div className=\"dsgc-field\">\n <div className=\"dsgc-wsrow\">\n <input\n className=\"dsgc-input\"\n value={wsDraft === null ? (group.workspaceDir || '') : wsDraft}\n placeholder=\"~/docs 或 /abs/dir\"\n onChange={(e) => { setWsDraft(e.target.value) }}\n onBlur={commitWsDir}\n onKeyDown={(e) => { if (e.key === 'Enter') (e.target as HTMLInputElement).blur() }}\n />\n <P.Button variant=\"outline\" size=\"sm\" onClick={() => { void openBrowser(wsDraft === null ? group.workspaceDir : wsDraft) }}>\n {Icon(P.IconFolderOpenOutline16, 14)}浏览\n </P.Button>\n </div>\n <div className=\"dsgc-hint\">发送时读取目录内文本文件,注入本群全体角色上下文;角色也可用工具主动查看</div>\n {group.workspaceDir === '~' || group.workspaceDir === '/'\n ? <div className=\"dsgc-err\">工作区指向整个主目录/根目录:角色的只读工具将可读取该范围下的所有文件,请谨慎</div>\n : null}\n </div>\n {fileBrowser && fileBrowser.open\n ? (\n <div className=\"dsgc-fb\">\n <div className=\"dsgc-fbhead\">\n <span className=\"dsgc-fbpath\" title={fileBrowser.list ? fileBrowser.list.path : ''}>\n {fileBrowser.loading ? '读取中…' : (fileBrowser.list ? fileBrowser.list.path : '')}\n </span>\n <span style={{ display: 'flex', gap: 4, alignItems: 'center' }}>\n <P.Button variant=\"primary\" size=\"sm\" disabled={!fileBrowser.list} onClick={selectCurrentDir}>选定此目录</P.Button>\n {fileBrowser.list\n ? <P.Button variant=\"outline\" size=\"sm\" title=\"上一级\" aria-label=\"上一级\" onClick={() => { void openBrowser(fileBrowser.list!.parent) }}>{Icon(P.IconChevronUpOutline14, 14)}</P.Button>\n : null}\n {fileBrowser.list\n ? <P.Button variant=\"outline\" size=\"sm\" title=\"主目录\" aria-label=\"主目录\" onClick={() => { void openBrowser(fileBrowser.list!.home) }}>{Icon(P.IconFolderClose16, 14)}</P.Button>\n : null}\n <P.Button variant=\"ghost\" size=\"sm\" onClick={() => { setFileBrowser(null) }} aria-label=\"关闭浏览器\">{Icon(P.IconCloseOutline16, 14)}</P.Button>\n </span>\n </div>\n {fileBrowser.error ? <div className=\"dsgc-err\">{fileBrowser.error}</div> : null}\n {fileBrowser.list\n ? (\n <div className=\"dsgc-fblist\">\n {(fileBrowser.list.entries || []).length\n ? (fileBrowser.list.entries || []).map((e) => e.type === 'directory'\n ? (\n <button\n key={e.path}\n type=\"button\"\n className={'dsgc-fbrow' + (e.hidden ? ' dim' : '') + ' dir'}\n onClick={() => { void openBrowser(e.path) }}\n >\n {Icon(e.hidden ? P.IconFolderClose16 : P.IconFolderOpenOutline16, 14)}\n <span className=\"dsgc-fbname\">{e.name}/</span>\n </button>\n )\n : (\n <div key={e.path} className=\"dsgc-fbrow dim file\">\n <span className=\"dsgc-fbname\">{e.name}</span>\n {e.size !== undefined ? <span className=\"dsgc-fbsize\">{(P as unknown as { fileSizeText: (n: number) => string }).fileSizeText(e.size)}</span> : null}\n </div>\n ))\n : <div className=\"dsgc-hint\">空目录</div>}\n </div>\n )\n : null}\n </div>\n )\n : null}\n </div>\n </div>\n )\n}\n","/**\n * 记录 → 落盘 JSON 的纯序列化(core 层;可选字段无则省略)。\n * @module dsh-group-chat/core/json\n */\n\nimport type { MessageRecord, RoleRecord } from './types.ts'\n\n/** 消息 → 落盘 JSON(可选字段无则省略;兼容保留 error)。 */\nexport function messageJson(m: Partial<MessageRecord> | undefined): Record<string, unknown> | null {\n if (!m || typeof m.id !== 'string') return null\n const o: Record<string, unknown> = { id: m.id, speaker: m.speaker, text: String(m.text || ''), ts: typeof m.ts === 'number' ? m.ts : Date.now(), seq: typeof m.seq === 'number' ? m.seq : 0 }\n if (m.model !== undefined) o.model = m.model\n if (m.reasoning !== undefined) o.reasoning = m.reasoning\n if (m.reasoningFull !== undefined) o.reasoningFull = m.reasoningFull\n if (m.thinkingSummary !== undefined) o.thinkingSummary = m.thinkingSummary\n if (m.error !== undefined) o.error = m.error\n if (typeof m.failedRoleId === 'string' && m.failedRoleId) o.failedRoleId = m.failedRoleId\n if (Array.isArray(m.toolCalls) && m.toolCalls.length > 0) o.toolCalls = m.toolCalls\n return o\n}\n\n/** 角色 → 落盘 JSON(groupId 由目录归属,不再写入)。 */\nexport function roleJson(r: Partial<RoleRecord>): Record<string, unknown> {\n const o: Record<string, unknown> = { id: r.id, name: String(r.name || '成员'), persona: String(r.persona || ''), provider: String(r.provider || ''), model: String(r.model || ''), enabled: r.enabled !== false, thinking: r.thinking === true }\n if (r.color) o.color = r.color\n if (typeof r.temperature === 'number' && !Number.isNaN(r.temperature)) o.temperature = r.temperature\n if (typeof r.reasoningEffort === 'string' && r.reasoningEffort && r.reasoningEffort !== 'default') o.reasoningEffort = r.reasoningEffort\n return o\n}\n\n/**\n * 宽容 JSON 提取(模型输出/供应商错误原文的统一解析入口):\n * 取首个 { 至末个 } 的片段解析,仅接受普通对象;失败返回 null。\n * 代码围栏剥离由调用方按需先行处理(供应商错误原文不剥)。\n */\nexport function looseJson(raw: string): Record<string, unknown> | null {\n const start = raw.indexOf('{')\n const end = raw.lastIndexOf('}')\n if (start < 0 || end <= start) return null\n try {\n const parsed = JSON.parse(raw.slice(start, end + 1)) as unknown\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed as Record<string, unknown> : null\n } catch {\n return null\n }\n}\n","/**\n * 群聊数据模型(core 层,无 cordis 依赖)。\n * 数据模型:Group 1..N Session,消息挂在会话上;角色与工作区目录挂在群组上。\n * @module dsh-group-chat/core/types\n */\n\n/**\n * 群组权限档位(对齐主会话 /permission 三档):\n * - view_only 仅可查看:只保留 read_file/list_dir,run_command 从 schema 剔除\n * - workspace_write 工作区内修改:run_command 可用,每条命令逐条确认\n * - full_access 完全权限:run_command 免确认直接执行\n */\nexport type PermissionTier = 'view_only' | 'workspace_write' | 'full_access'\n\n/** 全部合法档位(展示顺序)。 */\nexport const PERMISSION_TIERS: readonly PermissionTier[] = ['view_only', 'workspace_write', 'full_access']\n\n/** 档位安全化:合法字符串原样,其余 undefined。 */\nexport function asPermissionTier(value: unknown): PermissionTier | undefined {\n return typeof value === 'string' && (PERMISSION_TIERS as readonly string[]).includes(value) ? value as PermissionTier : undefined\n}\n\n/**\n * ledger 行档位归一(v2→v3 兼容):显式 permissionTier 优先;\n * 缺失时按旧布尔迁移——allowCommands=true → workspace_write(今日语义即\n * 「可执行命令但逐条确认」),false/无字段 → view_only。\n */\nexport function migrateTier(permissionTier: unknown, allowCommands: unknown): PermissionTier {\n const tier = asPermissionTier(permissionTier)\n if (tier !== undefined) return tier\n return allowCommands === true ? 'workspace_write' : 'view_only'\n}\n\n/** 群组:角色与工作区目录的宿主。 */\nexport interface GroupRecord {\n id: string\n name: string\n workspaceDir: string\n permissionTier: PermissionTier\n roleIds: string[]\n sessionIds: string[]\n}\n\n/** 会话约束条目类型(窗口外结论/约束备忘)。 */\nexport type ConstraintKind = 'decided' | 'rejected' | 'open'\n\n/** 全部合法约束类型。 */\nexport const CONSTRAINT_KINDS: readonly ConstraintKind[] = ['decided', 'rejected', 'open']\n\n/** 合法 kind 原样,其余 undefined。 */\nexport function asConstraintKind(value: unknown): ConstraintKind | undefined {\n return typeof value === 'string' && (CONSTRAINT_KINDS as readonly string[]).includes(value) ? value as ConstraintKind : undefined\n}\n\n/** 一条无主结论/约束(已定 / 否决 / 未决)。 */\nexport interface SessionConstraint {\n kind: ConstraintKind\n text: string\n}\n\n/** 会话:消息挂在会话上。 */\nexport interface SessionRecord {\n id: string\n groupId: string\n name: string\n topic: string\n /** 名称已被手动编辑:自动命名永久跳过(隐式固定)。 */\n namePinned?: boolean\n /** 主题已被手动编辑:自动整理永久跳过(隐式固定)。 */\n topicPinned?: boolean\n /** 窗口外结论/约束备忘;空则省略。 */\n constraints?: SessionConstraint[]\n /** 已折入备忘的最大消息 seq;0/缺省 = 尚未折过。 */\n constraintsUpToSeq?: number\n messageIds: string[]\n createdAt: number\n}\n\n/** 角色:绑定 provider/model 的群成员身份。 */\nexport interface RoleRecord {\n id: string\n groupId: string\n name: string\n color?: string\n persona: string\n provider: string\n model: string\n temperature?: number\n reasoningEffort?: string\n enabled: boolean\n thinking: boolean\n}\n\n/** 一次工具调用的落盘/快照形态(TOOLS.md §3.3 回注契约的展示面)。 */\nexport interface ToolCallRecord {\n tool: string\n args: unknown\n status: string\n output: string\n durationMs?: number\n}\n\n/** 消息(user / system / 角色发言共用一条记录)。 */\nexport interface MessageRecord {\n id: string\n sessionId: string\n seq: number\n speaker: string\n text: string\n reasoning?: string\n reasoningFull?: string\n thinkingSummary?: string\n model?: string\n error?: boolean\n /** 发言失败时的角色 id;刷新后仍可对该条点重试。角色消息 speaker 即角色 id,此字段冗余兼容旧系统错误行。 */\n failedRoleId?: string\n toolCalls?: ToolCallRecord[]\n ts: number\n}\n\n/** run_command 确认闸门的待确认载荷。 */\nexport interface PendingConfirm {\n toolCallId: string\n tool: string\n args: { command?: string } & Record<string, unknown>\n}\n\n/** 最近一次创建的群组/会话,供客户端定位选中项。 */\nexport interface LastCreated {\n kind: 'group' | 'session'\n groupId: string\n sessionId: string\n}\n\n/** run 结束后的「输出完毕」标记(内存态不持久化,重启即清;reason 取 ok/error)。 */\nexport interface RunFinished {\n sessionId: string\n reason: 'ok' | 'error'\n}\n\n/** 对话进行时状态(run)。 */\nexport interface RunState {\n running: boolean\n sessionId: string | null\n currentRoleId: string | null\n partial: string\n partialReasoning: string\n stopping: boolean\n queue: string[]\n pendingConfirm: PendingConfirm | null\n confirmSignal: { resolve: (allowed: boolean) => void } | null\n /** 正在执行的 run_command 的中止句柄(stop/dispose 时 abort,执行器 kill 进程)。 */\n commandAbort: AbortController | null\n /** 最近一次 run 的结束标记:会话列表「已完成/已出错」状态的数据源。 */\n finished: RunFinished | null\n /** 原地重试时被覆盖的失败消息 id;普通 send 为 null。 */\n replaceMessageId: string | null\n}\n\n/** 角色发言的引擎产物。 */\nexport interface SpeakResult {\n text: string\n reasoning: string | undefined\n toolCalls: ToolCallRecord[]\n}\n\n/** 工具执行结果(host 内部约定)。 */\nexport interface ToolExecution {\n status: 'ok' | 'error' | 'denied'\n output: string\n args: Record<string, unknown>\n durationMs: number\n}\n\n/** 模型目录(models action 的缓存载荷)。 */\nexport interface ModelCatalog {\n at: number\n providers: { id: string, name: string }[]\n modelsByProvider: Record<string, { id: string, name?: string }[]>\n}\n\n/** 推理级别选项(efforts action 的载荷)。 */\nexport interface EffortOptions {\n efforts: { id: string, name: string, description?: string }[]\n defaultEffort: string | undefined\n error?: string\n}\n\n/** 目录浏览结果(browse action 的载荷)。 */\nexport interface BrowseResult {\n ok: boolean\n path?: string\n home?: string\n parent?: string\n entries?: { name: string, type: string, path: string, size?: number, hidden: boolean }[]\n error?: string\n}\n\n/** 群工作区 @ 文件检索结果(fileSearch action 的载荷)。 */\nexport interface FileSearchResult {\n ok: boolean\n candidates?: { path: string, isDir: boolean }[]\n error?: string\n}\n\n/** 快照内的会话行(wire 形态:不含 hydrate 用的固定标记与折入水位)。 */\nexport type SnapshotSession = Omit<SessionRecord, 'namePinned' | 'topicPinned' | 'constraintsUpToSeq'>\n/** 快照内的消息行(wire 形态:思考全文与摘要不外发)。 */\nexport type SnapshotMessage = Omit<MessageRecord, 'reasoningFull' | 'thinkingSummary'>\n\n/** 发到客户端的全量快照(wire 形态;各表行由领域记录派生,字段增删由编译器同步)。 */\nexport interface Snapshot {\n revision: number\n run: Omit<RunState, 'stopping' | 'queue' | 'confirmSignal' | 'commandAbort'>\n lastCreated: LastCreated | null\n groups: GroupRecord[]\n sessions: SnapshotSession[]\n roles: RoleRecord[]\n messages: SnapshotMessage[]\n error?: string\n}\n\n/** mutate 动作的参数形态(判别联合:按 op 收窄各分支字段;wire 上字段可缺,消费方各自守卫)。 */\nexport type MutateArgs =\n | { op: 'createGroup', name?: string }\n | { op: 'renameGroup', groupId: string, name?: string }\n | { op: 'deleteGroup', groupId: string }\n | { op: 'createSession', groupId: string, name?: string }\n | { op: 'renameSession', sessionId: string, name?: string }\n | { op: 'deleteSession', sessionId: string }\n | { op: 'setTopic', sessionId: string, topic?: string }\n | { op: 'upsertRole', groupId: string, role?: Partial<RoleRecord> }\n | { op: 'deleteRole', roleId: string }\n | { op: 'setRoleEnabled', roleId: string, enabled?: boolean }\n | { op: 'setWorkspaceDir', groupId: string, path?: string }\n | { op: 'setPermissionTier', groupId: string, tier?: string }\n | { op: 'ackFinish' }\n | { op: 'clearMessages', sessionId: string }\n\n/** send 动作的参数形态。 */\nexport interface SendArgs {\n sessionId: string\n text?: string\n participantRoleIds?: string[]\n rounds?: number\n}\n\n/** 可选数值参数安全化:数字则原样,否则 undefined。 */\nexport function asNumber(value: unknown): number | undefined {\n return typeof value === 'number' && !Number.isNaN(value) ? value : undefined\n}\n\n/** 可选字符串参数安全化:非 default 的非空字符串则原样,否则 undefined。 */\nexport function asEffort(value: unknown): string | undefined {\n return typeof value === 'string' && value && value !== 'default' ? value : undefined\n}\n","/**\n * 会话约束备忘纯逻辑:滑动 40 条窗口、挤出集、压行、临时原文、解析与截断。\n * @module dsh-group-chat/core/constraints\n */\n\nimport { looseJson } from './json.ts'\nimport { TRANSCRIPT_TOOL_SUMMARY } from './tools.ts'\nimport { asConstraintKind, type MessageRecord, type SessionConstraint, type SessionRecord } from './types.ts'\n\n/** 当场原文窗口(含系统行)。 */\nexport const WINDOW_SIZE = 40\n/** 折叠失败时临时原文条数上限。 */\nexport const TEMP_MAX_MESSAGES = 20\n/** 折叠失败时临时原文总长上限。 */\nexport const TEMP_MAX_CHARS = 16000\n/** 单轮折叠最多消耗的挤出条数(含系统行;超出留待下一轮)。 */\nexport const FOLD_MAX_MESSAGES = 40\n/** 单轮折叠输入总长上限(格式化后)。 */\nexport const FOLD_MAX_CHARS = 16000\n/** 备忘条数上限。 */\nexport const CONSTRAINT_MAX_ITEMS = 12\n/** 备忘总长上限(条目前缀+正文)。 */\nexport const CONSTRAINT_MAX_CHARS = 1200\n/** 单条备忘正文上限。 */\nexport const CONSTRAINT_ITEM_MAX_CHARS = 160\n\nexport const KIND_LABEL: Record<SessionConstraint['kind'], string> = {\n decided: '已定',\n rejected: '否决',\n open: '未决',\n}\n\n/** 已折入水位(缺省 0)。 */\nexport function constraintsWatermark(sess: SessionRecord): number {\n return typeof sess.constraintsUpToSeq === 'number' && sess.constraintsUpToSeq > 0 ? sess.constraintsUpToSeq : 0\n}\n\n/** 重试:只取失败卡之前的时间线;untilId 不在列表则原样。 */\nexport function prefixIds(ids: string[], untilId?: string): string[] {\n if (!untilId) return ids\n const i = ids.indexOf(untilId)\n return i >= 0 ? ids.slice(0, i) : ids\n}\n\n/**\n * 新挤出:seq > 水位 且不在最近 40 条。只扫窗口外前缀(旧→新)。\n * untilId:重试时把窗口截到该消息之前,不带上后面已经发生的发言。\n */\nexport function squeezedMessages(\n messages: Map<string, MessageRecord>,\n sess: SessionRecord,\n untilId?: string,\n): MessageRecord[] {\n const ids = prefixIds(sess.messageIds, untilId)\n if (ids.length <= WINDOW_SIZE) return []\n const end = ids.length - WINDOW_SIZE\n const upTo = constraintsWatermark(sess)\n const last = messages.get(ids[end - 1])\n if (last && last.seq <= upTo) return []\n const out: MessageRecord[] = []\n for (let i = 0; i < end; i++) {\n const m = messages.get(ids[i])\n if (!m || m.seq <= upTo) continue\n out.push(m)\n }\n return out\n}\n\n/** 说话人展示名(折叠输入 / transcript 共用)。 */\nexport function speakerLabel(speaker: string, roleName?: string): string {\n if (speaker === 'user') return '用户'\n if (speaker === 'system') return '系统'\n return roleName || '成员'\n}\n\n/** 单条消息压成 transcript 行(正文 8k + 工具一行摘要)。 */\nexport function formatTranscriptLine(m: MessageRecord, name: string): string {\n let text = m.text || ''\n if (text.length > 8000) text = text.slice(0, 8000) + '…(已截断)'\n let line = '【' + name + '】' + text\n if (Array.isArray(m.toolCalls)) {\n for (const c of m.toolCalls) {\n if (!c || typeof c.tool !== 'string') continue\n let brief = ''\n try {\n brief = JSON.stringify(c.args) || ''\n } catch {\n brief = ''\n }\n if (brief.length > 60) brief = brief.slice(0, 60) + '…'\n const st = c.status === 'ok' ? '成功' : c.status === 'denied' ? '用户拒绝' : '失败'\n let ob = String(c.output || '')\n if (ob.length > TRANSCRIPT_TOOL_SUMMARY) ob = ob.slice(0, TRANSCRIPT_TOOL_SUMMARY) + '…'\n line += '\\n [工具] ' + c.tool + ' ' + brief + ' → ' + st + (ob ? '(' + ob.replace(/\\s+/g, ' ') + ')' : '')\n }\n }\n return line\n}\n\n/**\n * 单轮折叠消耗前缀:从最旧挤出起,最多 40 条 / 16k;系统行与失败卡计入消耗但不进模型。\n * 水位只能推到 consumed 的 max seq,剩余留待下一轮。\n */\nexport function takeFoldBatch(squeezed: MessageRecord[], nameOf: (m: MessageRecord) => string): {\n consumed: MessageRecord[]\n lines: string[]\n hasUser: boolean\n allSystem: boolean\n} {\n const consumed: MessageRecord[] = []\n const lines: string[] = []\n let hasUser = false\n let chars = 0\n for (const m of squeezed) {\n if (m.speaker === 'system' || m.error) {\n consumed.push(m)\n if (consumed.length >= FOLD_MAX_MESSAGES) break\n continue\n }\n const line = formatTranscriptLine(m, nameOf(m))\n const extra = line.length + (lines.length ? 2 : 0)\n if (lines.length > 0 && chars + extra > FOLD_MAX_CHARS) break\n if (m.speaker === 'user') hasUser = true\n lines.push(line)\n chars += extra\n consumed.push(m)\n if (consumed.length >= FOLD_MAX_MESSAGES) break\n }\n return { consumed, lines, hasUser, allSystem: lines.length === 0 }\n}\n\n/**\n * 未折入的挤出原文(失败缓冲):只格式化最近 20 条,再按 16k 从最旧往下丢。\n */\nexport function tempTranscript(squeezed: MessageRecord[], nameOf: (m: MessageRecord) => string): string {\n if (!squeezed.length) return ''\n const usable = squeezed.filter((m) => m.speaker !== 'system' && !m.error)\n if (!usable.length) return ''\n const batch = usable.length > TEMP_MAX_MESSAGES ? usable.slice(-TEMP_MAX_MESSAGES) : usable\n const lines = batch.map((m) => formatTranscriptLine(m, nameOf(m)))\n let start = 0\n let total = lines[0] ? lines[0].length : 0\n for (let i = 1; i < lines.length; i++) {\n total += 2 + lines[i].length\n }\n while (start < lines.length - 1 && total > TEMP_MAX_CHARS) {\n total -= lines[start].length + 2\n start++\n }\n let block = lines.slice(start).join('\\n\\n')\n if (block.length > TEMP_MAX_CHARS) block = block.slice(0, TEMP_MAX_CHARS) + '…(已截断)'\n return block\n}\n\n/** 水位 = 本批挤出的 max(seq);空批为 0。 */\nexport function squeezedMaxSeq(squeezed: MessageRecord[]): number {\n let max = 0\n for (const m of squeezed) if (m.seq > max) max = m.seq\n return max\n}\n\n/** hydrate / 模型输出:非法 kind 丢条目;空 text 丢;条数与总长截断。 */\nexport function sanitizeConstraints(raw: unknown): SessionConstraint[] {\n if (!Array.isArray(raw)) return []\n const out: SessionConstraint[] = []\n let total = 0\n for (const item of raw) {\n if (out.length >= CONSTRAINT_MAX_ITEMS) break\n if (!item || typeof item !== 'object') continue\n const kind = asConstraintKind((item as { kind?: unknown }).kind)\n const text = typeof (item as { text?: unknown }).text === 'string' ? (item as { text: string }).text.trim() : ''\n if (!kind || !text) continue\n const clipped = text.length > CONSTRAINT_ITEM_MAX_CHARS ? text.slice(0, CONSTRAINT_ITEM_MAX_CHARS) + '…' : text\n const cost = KIND_LABEL[kind].length + clipped.length\n if (total + cost > CONSTRAINT_MAX_CHARS) break\n out.push({ kind, text: clipped })\n total += cost\n }\n return out\n}\n\n/**\n * 解析折叠模型输出。null = 解析失败(水位不推);[] = 无新结论(水位推、备忘不动)。\n */\nexport function parseConstraints(raw: string): SessionConstraint[] | null {\n const o = looseJson(raw.replace(/```(?:json)?/g, ''))\n if (o === null) return null\n if (!Object.prototype.hasOwnProperty.call(o, 'constraints')) return null\n if (!Array.isArray(o.constraints)) return null\n return sanitizeConstraints(o.constraints)\n}\n\n/** 本批无用户消息时,新的已定/否决降为未决。 */\nexport function downgradeWithoutUser(list: SessionConstraint[], hasUser: boolean): SessionConstraint[] {\n if (hasUser) return list\n return list.map((c) => c.kind === 'open' ? c : { kind: 'open', text: c.text })\n}\n\n/** system 提示词「已确认约束」块;空则空串。 */\nexport function constraintBlock(list: SessionConstraint[] | undefined): string {\n if (!list || !list.length) return ''\n const lines = list.map((c) => '- ' + KIND_LABEL[c.kind] + ':' + c.text)\n return '\\n# 已确认约束\\n' + lines.join('\\n')\n}\n","/**\n * 角色发言失败:供应商原文 → 人话标题/原因(core 纯函数,无 React)。\n * 原始 JSON 仍落盘在消息 text 里,UI 默认只展示短因,展开才看原文。\n * @module dsh-group-chat/core/errors\n */\n\nexport interface SpeakFailureView {\n /** 一行标题,例如「额度已用尽」。 */\n title: string\n /** 可选短因:重置时间、HTTP 状态等。 */\n detail?: string\n /** 复制/排障用的供应商原文(已剥「模型输出异常终止: 」前缀)。 */\n raw: string\n}\n\nconst PREFIX = '模型输出异常终止: '\nconst LEGACY_ROLE = /^角色「([^」]+)」发言失败[::]\\s*/\n\n/** 剥旧系统胶囊与引擎包装前缀,保留供应商原文。 */\nexport function unwrapSpeakFailure(raw: string): string {\n const text = String(raw || '').trim()\n const legacy = parseLegacyRoleFailure(text)\n const body = legacy ? legacy.rest : text\n return body.startsWith(PREFIX) ? body.slice(PREFIX.length).trim() : body\n}\n\n/** 旧系统胶囊文案:角色「名」发言失败:原文。对不上则 null。 */\nexport function parseLegacyRoleFailure(text: string): { roleName: string, rest: string } | null {\n const m = LEGACY_ROLE.exec(String(text || ''))\n if (!m) return null\n return { roleName: m[1], rest: String(text).slice(m[0].length) }\n}\n\nexport interface RoleRef {\n id: string\n name: string\n provider?: string\n model?: string\n}\n\nexport interface FailedMessageRef {\n speaker: string\n text: string\n error?: boolean\n failedRoleId?: string\n}\n\n/** 发言失败卡:error 标记,或旧系统胶囊文案。 */\nexport function isSpeakFailure(m: FailedMessageRef): boolean {\n return !!m.error || !!parseLegacyRoleFailure(m.text)\n}\n\n/** 失败回合对应角色:failedRoleId / speaker / 旧文案里的角色名(恰好一名才命中)。 */\nexport function resolveFailedRole<T extends RoleRef>(m: FailedMessageRef, roles: T[]): T | null {\n const byId = (id: string | undefined): T | null => {\n if (!id) return null\n for (const r of roles) if (r.id === id) return r\n return null\n }\n const direct = byId(m.failedRoleId) || (m.speaker !== 'user' && m.speaker !== 'system' ? byId(m.speaker) : null)\n if (direct) return direct\n const parsed = parseLegacyRoleFailure(m.text)\n if (!parsed) return null\n const hits = roles.filter((r) => r.name === parsed.roleName)\n return hits.length === 1 ? hits[0] : null\n}\n\n/**\n * 把旧系统失败行挂到对应角色(恰好一名命中才迁)。\n * 返回是否改写了记录。\n */\nexport function repairFailedMessage(\n m: { speaker: string, text: string, error?: boolean, failedRoleId?: string, model?: string },\n roles: RoleRef[],\n): boolean {\n if (!isSpeakFailure(m)) return false\n let changed = false\n if (!m.error) {\n m.error = true\n changed = true\n }\n if (!m.failedRoleId && m.speaker !== 'user' && m.speaker !== 'system') {\n m.failedRoleId = m.speaker\n changed = true\n }\n if (!m.failedRoleId && m.speaker === 'system') {\n const parsed = parseLegacyRoleFailure(m.text)\n if (parsed) {\n const hits = roles.filter((r) => r.name === parsed.roleName)\n if (hits.length === 1) {\n const role = hits[0]\n m.speaker = role.id\n m.failedRoleId = role.id\n m.text = unwrapSpeakFailure(parsed.rest)\n if (!m.model && (role.provider || role.model)) m.model = (role.provider || '') + ' / ' + (role.model || '')\n changed = true\n }\n }\n } else if (m.failedRoleId && m.speaker === 'system') {\n m.speaker = m.failedRoleId\n changed = true\n }\n // 对不上角色时保留「角色「名」发言失败」原文,客户端才能再解析。\n if (m.failedRoleId || (m.speaker !== 'user' && m.speaker !== 'system')) {\n const unwrapped = unwrapSpeakFailure(m.text)\n if (unwrapped !== m.text) {\n m.text = unwrapped\n changed = true\n }\n }\n return changed\n}\n\nimport { looseJson } from './json.ts'\n\nfunction httpStatus(text: string): number | null {\n const m = text.match(/\\b([1-5]\\d{2})\\b/)\n if (!m) return null\n const n = Number(m[1])\n return n >= 100 && n <= 599 ? n : null\n}\n\nfunction resetHint(message: string): string | undefined {\n const m = message.match(/reset at ([^.]+\\S)/i) || message.match(/将在\\s*([^\\s。]+)\\s*重置/)\n return m ? '将在 ' + m[1] + ' 重置' : undefined\n}\n\n/**\n * 把供应商错误压成可扫描的标题 + 短因。\n * 未知形态回退为「发言失败」,原文仍可展开。\n */\nexport function classifySpeakFailure(raw: string): SpeakFailureView {\n const source = unwrapSpeakFailure(raw)\n const blob = looseJson(source)\n const code = blob && typeof blob.code === 'string' ? blob.code : ''\n const type = blob && typeof blob.type === 'string' ? blob.type : ''\n const message = blob && typeof blob.message === 'string' ? blob.message : source\n const status = httpStatus(source)\n const joined = (code + ' ' + type + ' ' + message + ' ' + source).toLowerCase()\n\n if (/quota|accountquotaexceeded|exceeded the .*quota|额度|配额/.test(joined) || code === 'AccountQuotaExceeded') {\n return { title: '额度已用尽', detail: resetHint(message), raw: source }\n }\n if (status === 429 || /too.?many.?requests|rate.?limit|限流/.test(joined) || type === 'TooManyRequests') {\n return { title: '请求过于频繁', detail: '稍后再试,或降低并发', raw: source }\n }\n if (status === 401 || status === 403 || /unauthorized|forbidden|invalid.?api.?key|鉴权|未授权/.test(joined)) {\n return { title: '模型鉴权失败', detail: '检查该角色绑定的提供方密钥', raw: source }\n }\n if (status === 404 || /model.?not.?found|unknown.?model|模型不存在/.test(joined)) {\n return { title: '模型不可用', detail: '该角色绑定的模型可能已下线', raw: source }\n }\n if (/timeout|timed out|etimedout|超时/.test(joined)) {\n return { title: '模型响应超时', raw: source }\n }\n if (/network|econnreset|econnrefused|enotfound|fetch failed|网络/.test(joined)) {\n return { title: '网络异常', detail: '检查网络后重试', raw: source }\n }\n if (status !== null && status >= 500) {\n return { title: '模型服务暂时不可用', detail: 'HTTP ' + status, raw: source }\n }\n if (status !== null) {\n return { title: '发言失败', detail: 'HTTP ' + status, raw: source }\n }\n return { title: '发言失败', raw: source }\n}\n\n/** 失败卡默认复制内容:标题 + 短因 + 原文。 */\nexport function formatSpeakFailureCopy(view: SpeakFailureView): string {\n const lines = [view.title]\n if (view.detail) lines.push(view.detail)\n if (view.raw && view.raw !== view.title) lines.push(view.raw)\n return lines.join('\\n')\n}\n","/**\n * 会话内折叠:高度 0fr→1fr + 溢出滚动遮罩。思考 / 工具 / 失败原文 / 结论备忘共用。\n * @module dsh-group-chat/client/components\n */\n\nimport { useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from 'react'\n\ninterface FoldProps {\n open: boolean\n children: ReactNode\n className?: string\n}\n\nexport function Fold(props: FoldProps): ReactNode {\n const { open, children, className } = props\n return (\n <div className={'dsgc-fold' + (open ? ' open' : '') + (className ? ' ' + className : '')}>\n <div className=\"dsgc-fold-inner\">{children}</div>\n </div>\n )\n}\n\ninterface ClipWellProps {\n children: ReactNode\n maxHeight: number\n className?: string\n watch?: unknown\n}\n\nexport function ClipWell(props: ClipWellProps): ReactNode {\n const { children, maxHeight, className, watch } = props\n const [clip, setClip] = useState({ up: false, down: false })\n const ref = useRef<HTMLDivElement>(null)\n\n useLayoutEffect(() => {\n const el = ref.current\n if (!el) return\n const measure = (): void => {\n if (el.clientHeight < 2) {\n setClip((cur) => cur.up || cur.down ? { up: false, down: false } : cur)\n return\n }\n const max = el.scrollHeight - el.clientHeight\n const up = el.scrollTop > 1\n const down = max > 1 && el.scrollTop < max - 1\n setClip((cur) => cur.up === up && cur.down === down ? cur : { up, down })\n }\n measure()\n const ro = new ResizeObserver(measure)\n ro.observe(el)\n for (const child of el.children) ro.observe(child)\n el.addEventListener('scroll', measure, { passive: true })\n el.addEventListener('transitionend', measure)\n return () => {\n ro.disconnect()\n el.removeEventListener('scroll', measure)\n el.removeEventListener('transitionend', measure)\n }\n }, [watch])\n\n return (\n <div className={'dsgc-clip' + (clip.up ? ' can-up' : '') + (clip.down ? ' can-down' : '')}>\n <div\n className={'dsgc-clip-scroll' + (className ? ' ' + className : '')}\n ref={ref}\n style={{ maxHeight } as CSSProperties}\n >\n {children}\n </div>\n </div>\n )\n}\n","/**\n * 思考折叠行(对标宿主 ReasoningRow:折叠摘要 / 展开全文)。\n * @module dsh-group-chat/client/ThinkRow\n */\n\nimport { useState, type ReactNode } from 'react'\nimport { P } from '../lib/ui.ts'\nimport { firstLine, latestLine } from '../lib/model.ts'\nimport { ClipWell, Fold } from './Fold.tsx'\n\nexport function ThinkRow(props: { text: string, running?: boolean }): ReactNode {\n const text = props.text || ''\n const running = !!props.running\n const [expanded, setExpanded] = useState(false)\n const plain = (line: string): string => line.replace(/^(\\s*#{1,6}\\s+|\\s*[-*+]\\s+|\\s*>\\s*)+/, '').replace(/[*`_~]/g, '').replace(/\\s+/g, ' ').trim()\n const summary = plain(running ? latestLine(text) : firstLine(text))\n return (\n <div className=\"dsgc-think\">\n <P.DisclosureRow\n rowClassName=\"dsgc-thinkrow\"\n icon={<P.IconThinkOutline14 size={14} />}\n title=\"思考\"\n open={expanded}\n expandable\n expandOnRowClick\n onToggle={() => { setExpanded((v) => !v) }}\n collapsedContent={text ? <span className=\"dsgc-thinksummary\">{summary}</span> : null}\n />\n <Fold open={expanded}>\n <ClipWell maxHeight={320} watch={text}>\n <div className=\"dsgc-thinkbody\">{text}</div>\n </ClipWell>\n </Fold>\n </div>\n )\n}\n","/**\n * 工具调用折叠行(对标思考折叠:摘要行 / 展开输出)。\n * @module dsh-group-chat/client/ToolRow\n */\n\nimport { useState, type ReactNode } from 'react'\nimport { Icon, P, pickPrimitive } from '../lib/ui.ts'\nimport type { ToolCallRecord } from '../../core/types.ts'\nimport { ClipWell, Fold } from './Fold.tsx'\n\nconst TOOL_ICONS: Record<string, string> = { read_file: 'IconBrowseOutline16', list_dir: 'IconFolderOpenOutline16', run_command: 'IconCodeOutline16' }\n\nexport function ToolRow(props: { c: ToolCallRecord }): ReactNode {\n const c = props.c\n const [expanded, setExpanded] = useState(false)\n let brief = ''\n try {\n brief = JSON.stringify(c.args) || ''\n } catch {\n brief = ''\n }\n if (brief.length > 40) brief = brief.slice(0, 40) + '…'\n const IconOf = pickPrimitive(TOOL_ICONS[c.tool] || 'IconCodeOutline16')\n const statusText = c.status === 'ok' ? '成功' : c.status === 'denied' ? '用户拒绝' : '失败'\n const StatusIcon = c.status === 'ok' ? P.IconCheckOutline14 : c.status === 'denied' ? P.IconCloseOutline16 : P.IconWarningOutline16\n const dur = c.durationMs ? (c.durationMs >= 1000 ? (c.durationMs / 1000).toFixed(1) + 's' : c.durationMs + 'ms') : ''\n return (\n <div className=\"dsgc-tool\">\n <P.DisclosureRow\n rowClassName=\"dsgc-toolrow\"\n icon={<IconOf size={14} />}\n title={c.tool + (brief ? ' ' + brief : '')}\n open={expanded}\n expandable\n expandOnRowClick\n onToggle={() => { setExpanded((v) => !v) }}\n collapsedContent={\n <span className=\"dsgc-toolsummary\">\n {Icon(StatusIcon, 12, {\n verticalAlign: '-2px',\n marginRight: 4,\n color: c.status === 'ok' ? 'var(--dsw-alias-label-tertiary,inherit)' : 'var(--dsw-alias-state-error-primary,#e5484d)',\n })}\n {statusText + (dur ? ' · ' + dur : '')}\n </span>\n }\n />\n <Fold open={expanded}>\n <ClipWell maxHeight={260} watch={c.output}>\n <div className=\"dsgc-toolbody\">{c.output || '(无输出)'}</div>\n </ClipWell>\n </Fold>\n </div>\n )\n}\n","/**\n * 角色发言失败卡:人话标题 + 可展开原文。操作条由 Bubble 放在气泡外下方。\n * @module dsh-group-chat/client/FailCard\n */\n\nimport { useState, type ReactNode } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport { classifySpeakFailure } from '../../core/errors.ts'\nimport { ClipWell, Fold } from './Fold.tsx'\n\nexport interface FailCardProps {\n raw: string\n}\n\nexport function FailCard(props: FailCardProps): ReactNode {\n const view = classifySpeakFailure(props.raw)\n const [open, setOpen] = useState(false)\n\n return (\n <div className=\"dsgc-fail\">\n <div className=\"dsgc-failhead\">\n <span className=\"dsgc-failicon\" aria-hidden=\"true\">{Icon(P.IconWarningOutline16, 14)}</span>\n <div className=\"dsgc-failcopy\">\n <div className=\"dsgc-failtitle\">{view.title}</div>\n {view.detail ? <div className=\"dsgc-faildetail\">{view.detail}</div> : null}\n </div>\n </div>\n {view.raw\n ? (\n <>\n <button\n type=\"button\"\n className={'dsgc-failmore' + (open ? ' open' : '')}\n aria-expanded={open}\n onClick={() => { setOpen((v) => !v) }}\n >\n {open ? '收起原始错误' : '查看原始错误'}\n </button>\n <Fold open={open}>\n <ClipWell maxHeight={220} watch={open}>\n <pre className=\"dsgc-failraw\">{view.raw}</pre>\n </ClipWell>\n </Fold>\n </>\n )\n : null}\n </div>\n )\n}\n","/**\n * 消息操作条:贴在气泡外下方。用户/角色消息悬停出「复制」;失败卡常驻「复制 / 重试」。\n * @module dsh-group-chat/client/MsgActions\n */\n\nimport { useEffect, useRef, useState, type ReactNode } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\n\nexport interface MsgActionsProps {\n copyText: string\n onRetry?: () => void\n retryDisabled?: boolean\n retryTitle?: string\n /** 失败卡:不依赖悬停,始终可见。 */\n always?: boolean\n}\n\nasync function writeClipboard(text: string): Promise<boolean> {\n try {\n if (navigator.clipboard && navigator.clipboard.writeText) {\n await navigator.clipboard.writeText(text)\n return true\n }\n } catch { /* fall through */ }\n try {\n const el = document.createElement('textarea')\n el.value = text\n el.setAttribute('readonly', '')\n el.style.position = 'fixed'\n el.style.left = '-9999px'\n document.body.appendChild(el)\n el.select()\n const ok = document.execCommand('copy')\n document.body.removeChild(el)\n return ok\n } catch {\n return false\n }\n}\n\nexport function MsgActions(props: MsgActionsProps): ReactNode {\n const { copyText, onRetry, retryDisabled, retryTitle, always } = props\n const [copied, setCopied] = useState(false)\n const copiedTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n useEffect(() => () => { if (copiedTimer.current) clearTimeout(copiedTimer.current) }, [])\n\n const copy = async (): Promise<void> => {\n if (!copyText) return\n const ok = await writeClipboard(copyText)\n if (!ok) return\n setCopied(true)\n if (copiedTimer.current) clearTimeout(copiedTimer.current)\n copiedTimer.current = setTimeout(() => { setCopied(false) }, 1400)\n }\n\n return (\n <div className={'dsgc-msgops' + (always ? ' always' : '')} role=\"group\" aria-label=\"消息操作\">\n <button\n type=\"button\"\n className={'dsgc-msgop' + (copied ? ' done' : '')}\n title={copied ? '已复制' : '复制'}\n aria-label={copied ? '已复制' : '复制'}\n onClick={(e) => { e.stopPropagation(); void copy() }}\n >\n {Icon(copied ? P.IconCheckOutline14 : P.IconCopyOutline16, 14)}\n <span>{copied ? '已复制' : '复制'}</span>\n </button>\n {onRetry\n ? (\n <button\n type=\"button\"\n className=\"dsgc-msgop retry\"\n title={retryTitle || '重试'}\n aria-label={retryTitle || '重试'}\n disabled={retryDisabled}\n onClick={(e) => { e.stopPropagation(); if (!retryDisabled) onRetry() }}\n >\n {Icon(P.IconRefreshOutline14, 14)}\n <span>重试</span>\n </button>\n )\n : null}\n </div>\n )\n}\n","/**\n * 聊天消息气泡(user / system / 角色发言)。\n *\n * 帧稳定 memo:SSE 全量快照(~65KB × 7fps)每帧重建全部消息对象 identity,\n * 但已完成消息在 host 侧 append 后不可变——按渲染相关字段做值比较,流式\n * 期间跳过已完成消息的重渲(每帧仅 live 行与派生列表变化),避免全量\n * MarkdownText 重新解析打满主线程导致「卡死后一次性蹦出」。\n * @module dsh-group-chat/client/Bubble\n */\n\nimport { memo, type ReactNode } from 'react'\nimport { P } from '../lib/ui.ts'\nimport { classifySpeakFailure, formatSpeakFailureCopy, isSpeakFailure } from '../../core/errors.ts'\nimport { fmtTime, MD_LABELS, type SnapshotRole } from '../lib/model.ts'\nimport type { SnapshotMessage } from '../lib/model.ts'\nimport { ThinkRow } from './ThinkRow.tsx'\nimport { ToolRow } from './ToolRow.tsx'\nimport { FailCard } from './FailCard.tsx'\nimport { MsgActions } from './MsgActions.tsx'\n\nexport interface BubbleProps {\n m: SnapshotMessage\n /** 父级解析好的发言角色(user/system 消息为 null)——避免 Bubble 依赖 snap identity。 */\n role: SnapshotRole | null\n busy?: boolean\n onRetry?: (messageId: string) => void\n}\n\nfunction BubbleInner({ m, role, busy, onRetry }: BubbleProps): ReactNode {\n const isUser = m.speaker === 'user'\n const isFail = isSpeakFailure(m)\n const isSys = m.speaker === 'system' && !isFail && !role\n const name = isUser ? '我' : role ? role.name : isSys ? '系统' : '成员'\n if (isSys) return <div className=\"dsgc-sysmsg\">{m.text}</div>\n\n const retryTitle = !role\n ? '失败角色已不存在,无法重试'\n : !role.enabled\n ? '该角色已停用,无法重试'\n : busy\n ? '已有对话进行中,请先停止'\n : '重试该角色发言'\n const copyText = isFail ? formatSpeakFailureCopy(classifySpeakFailure(m.text)) : (m.text || '')\n\n return (\n <div className={'dsgc-msg' + (isUser ? ' mine' : '') + (isFail ? ' fail' : '')}>\n <div\n className={'dsgc-avatar' + (isUser ? ' mine' : '')}\n style={isUser || !role ? undefined : { border: '2px solid ' + (role.color || '#888') }}\n >\n {name.slice(0, 1)}\n </div>\n <div className=\"dsgc-msgbody\">\n <div className=\"dsgc-msghead\">\n <span className=\"dsgc-msgname\">{name}</span>\n {m.model ? <span className=\"dsgc-msgmodel\" title={m.model}>{m.model}</span> : null}\n {m.ts ? <span className=\"dsgc-msgtime\">{fmtTime(m.ts)}</span> : null}\n </div>\n {isFail\n ? <FailCard raw={m.text} />\n : isUser\n ? <div className=\"dsgc-msgtext\">{m.text}</div>\n : (\n <div className=\"dsgc-msgtext\">\n {m.reasoning ? <ThinkRow text={m.reasoning} /> : null}\n {(Array.isArray(m.toolCalls) ? m.toolCalls : []).map((c, i) => <ToolRow key={'tc' + i} c={c} />)}\n <P.MarkdownText text={m.text || '(无内容)'} labels={MD_LABELS} />\n </div>\n )}\n <MsgActions\n copyText={copyText}\n always={isFail}\n onRetry={isFail && onRetry ? () => { onRetry(m.id) } : undefined}\n retryDisabled={busy || !role || !role.enabled}\n retryTitle={retryTitle}\n />\n </div>\n </div>\n )\n}\n\n/** 渲染相关字段的值比较(消息不可变;角色仅名/色参与渲染)。 */\nfunction bubblePropsEqual(a: BubbleProps, b: BubbleProps): boolean {\n if (a.busy !== b.busy || (a.onRetry == null) !== (b.onRetry == null)) return false\n const x = a.m\n const y = b.m\n if (x !== y) {\n if (x.id !== y.id || x.speaker !== y.speaker || x.text !== y.text || x.reasoning !== y.reasoning || x.model !== y.model || x.error !== y.error || x.failedRoleId !== y.failedRoleId || x.ts !== y.ts) return false\n const ta = Array.isArray(x.toolCalls) ? x.toolCalls : []\n const tb = Array.isArray(y.toolCalls) ? y.toolCalls : []\n if (ta.length !== tb.length) return false\n for (let i = 0; i < ta.length; i++) {\n const ca = ta[i]\n const cb = tb[i]\n if (ca !== cb && (ca.tool !== cb.tool || ca.status !== cb.status || ca.output !== cb.output || ca.durationMs !== cb.durationMs || JSON.stringify(ca.args) !== JSON.stringify(cb.args))) return false\n }\n }\n const ra = a.role\n const rb = b.role\n return (ra ? ra.id + '\\u0000' + ra.name + '\\u0000' + (ra.color || '') + '\\u0000' + (ra.enabled ? '1' : '0') : '') === (rb ? rb.id + '\\u0000' + rb.name + '\\u0000' + (rb.color || '') + '\\u0000' + (rb.enabled ? '1' : '0') : '')\n}\n\nexport const Bubble = memo(BubbleInner, bubblePropsEqual)\n","/**\n * 会话流折点处:只读结论备忘卡(超过 4 条默认露 3 条)。\n * @module dsh-group-chat/client/components\n */\n\nimport { useState, type ReactNode } from 'react'\nimport type { SessionConstraint } from '../../core/types.ts'\nimport { KIND_LABEL } from '../../core/constraints.ts'\nimport { ClipWell, Fold } from './Fold.tsx'\n\ninterface ConstraintListProps {\n items: SessionConstraint[]\n}\n\nfunction ConstraintRow(props: { item: SessionConstraint }): ReactNode {\n const { item } = props\n return (\n <div className=\"dsgc-constraint\">\n <span className={'dsgc-ckind ' + item.kind}>{KIND_LABEL[item.kind]}</span>\n <span className=\"dsgc-ctext\">{item.text}</span>\n </div>\n )\n}\n\nexport function ConstraintList(props: ConstraintListProps): ReactNode {\n const { items } = props\n const [open, setOpen] = useState(false)\n if (!items.length) return null\n const overflow = items.length > 4\n const head = overflow ? items.slice(0, 3) : items\n const extra = overflow ? items.slice(3) : []\n const rest = items.length - 3\n\n return (\n <section className=\"dsgc-constraints\" aria-labelledby=\"dsgc-constraints-title\">\n <div className=\"dsgc-chead\">\n <h2 id=\"dsgc-constraints-title\" className=\"dsgc-ctitle\">结论备忘</h2>\n <p className=\"dsgc-cdesc\">窗口外消息折成的已定 / 否决 / 未决,供后续角色接着用。</p>\n </div>\n <ClipWell maxHeight={160} className=\"dsgc-clist\" watch={open}>\n {head.map((c, i) => <ConstraintRow key={i} item={c} />)}\n {overflow\n ? (\n <Fold open={open}>\n {extra.map((c, i) => <ConstraintRow key={i + 3} item={c} />)}\n </Fold>\n )\n : null}\n </ClipWell>\n {overflow\n ? (\n <button\n type=\"button\"\n className=\"dsgc-cmore\"\n onClick={() => { setOpen(!open) }}\n aria-expanded={open}\n >\n {open ? '收起' : '还有 ' + rest + ' 条约束'}\n </button>\n )\n : null}\n </section>\n )\n}\n","/**\n * 消息流显示组件\n * @module dsh-group-chat/client/components\n */\n\nimport type { ReactNode, CSSProperties } from 'react'\nimport { WINDOW_SIZE } from '../../core/constraints.ts'\nimport { Icon, P } from '../lib/ui.ts'\nimport { Bubble } from './Bubble.tsx'\nimport { ConstraintList } from './ConstraintList.tsx'\nimport { ThinkRow } from './ThinkRow.tsx'\nimport { resolveFailedRole } from '../../core/errors.ts'\nimport { roleById, type ClientSnapshot } from '../lib/model.ts'\nimport { MD_LABELS } from '../lib/model.ts'\n\ninterface MessageFlowProps {\n snap: ClientSnapshot\n sess: ClientSnapshot['sessions'][number] | null\n busyNow: boolean\n msgById: Record<string, ClientSnapshot['messages'][number]>\n action: (payload: Record<string, unknown>) => Promise<unknown>\n onRetrySpeak: (messageId: string) => void\n}\n\nexport function MessageFlow(props: MessageFlowProps): ReactNode {\n const { snap, sess, busyNow, msgById, action, onRetrySpeak } = props\n\n const bubbles: ReactNode[] = []\n const replaceId = busyNow ? snap.run.replaceMessageId : null\n const replaceMsg = replaceId ? msgById[replaceId] : null\n const liveRoleId = snap.run.currentRoleId || (replaceMsg && (replaceMsg.failedRoleId || replaceMsg.speaker)) || null\n const lr = busyNow && liveRoleId ? roleById(snap, liveRoleId) : null\n\n const live = lr\n ? (\n <div key=\"__live\" className=\"dsgc-msg live\">\n <div\n className=\"dsgc-avatar\"\n style={{ border: '2px solid ' + (lr.color || '#888'), '--role-color': lr.color || '#888' } as CSSProperties}\n >\n {lr.name.slice(0, 1)}\n </div>\n <div className=\"dsgc-msgbody\">\n <div className=\"dsgc-msghead\">\n <span className=\"dsgc-msgname\">{lr.name}</span>\n <span className=\"dsgc-msgmodel\">{lr.provider} / {lr.model}</span>\n <span className=\"dsgc-msgtime dsgc-typing\">深度求索...</span>\n </div>\n <div className=\"dsgc-msgtext live\">\n {snap.run.partialReasoning ? <ThinkRow text={snap.run.partialReasoning} running /> : null}\n {snap.run.partial ? <P.MarkdownText text={snap.run.partial} streaming labels={MD_LABELS} /> : null}\n {/* 首 delta 前的「思考中」占位(深度思考模型首字节可能等数秒到数十秒,\n 空白气泡会被感知为卡死);delta 到达后被真实思考行/正文自然替换 */}\n {!snap.run.partial && !snap.run.partialReasoning\n ? (\n <div className=\"dsgc-pending\">\n {Icon(P.IconThinkOutline14, 14)}\n <span>思考中</span>\n <span className=\"dsgc-pendingdots\" aria-hidden=\"true\"><i /><i /><i /></span>\n </div>\n )\n : null}\n </div>\n </div>\n </div>\n )\n : null\n\n const pc = busyNow && snap.run.pendingConfirm && sess && snap.run.sessionId === sess.id ? snap.run.pendingConfirm : null\n const confirm = pc\n ? (\n <div key=\"__confirm\" className=\"dsgc-confirm\">\n <div className=\"dsgc-confirmtitle\">\n {Icon(P.IconWarningOutline16, 14)}\n {(lr ? lr.name : '角色') + ' 请求执行命令(工作区内)'}\n </div>\n <div className=\"dsgc-confirmcmd\">{String((pc.args && pc.args.command) || '')}</div>\n <div className=\"dsgc-hint\">允许后将在工作区目录执行;拒绝后角色将继续纯文本讨论</div>\n <div className=\"dsgc-confirmops\">\n <P.Button variant=\"primary\" size=\"sm\" onClick={() => { void action({ kind: 'confirmCommand', toolCallId: pc.toolCallId, allow: true }) }}>允许</P.Button>\n <P.Button variant=\"outline\" size=\"sm\" onClick={() => { void action({ kind: 'confirmCommand', toolCallId: pc.toolCallId, allow: false }) }}>拒绝</P.Button>\n </div>\n </div>\n )\n : null\n\n let livePlaced = false\n\n if (sess) {\n // 循环不变量:本群角色表只过滤一次(流式期间每帧执行的热路径)\n const groupRoles = snap.roles.filter((r) => r.groupId === sess.groupId)\n const ids = sess.messageIds\n const memo = sess.constraints && sess.constraints.length\n ? <ConstraintList key={sess.id + '-constraints'} items={sess.constraints} />\n : null\n // 折点 = 最近 WINDOW_SIZE 条之前。消息都还在窗口内时卡放流顶。\n const foldAt = memo && ids.length > WINDOW_SIZE ? ids.length - WINDOW_SIZE : 0\n if (memo && foldAt === 0) bubbles.push(memo)\n for (let i = 0; i < ids.length; i++) {\n if (memo && foldAt > 0 && i === foldAt) bubbles.push(memo)\n const m = msgById[ids[i]]\n if (!m) continue\n // 角色在父级解析:Bubble 按值 memo(不依赖 snap identity),流式帧\n // 不再触发已完成消息的全量重渲(每帧仅 live 行与派生列表变化)\n const role = resolveFailedRole(m, groupRoles) || (m.speaker !== 'user' && m.speaker !== 'system' ? roleById(snap, m.speaker) : null)\n // 原地重试:该槽位换成 live(确认卡紧随其后),不要钉在列表末尾\n if (replaceId && m.id === replaceId) {\n if (live) bubbles.push(live)\n if (confirm) bubbles.push(confirm)\n livePlaced = true\n continue\n }\n bubbles.push(<Bubble key={m.id} m={m} role={role} busy={!!snap.run.running} onRetry={onRetrySpeak} />)\n }\n }\n\n if (live && !livePlaced) bubbles.push(live)\n if (confirm && !livePlaced) bubbles.push(confirm)\n\n return <>{bubbles}</>\n}\n","/**\n * 群组权限档位选择器(对齐主会话 composer 左下角的 /permission 选择器):\n * 触发芯片(盾形图标 + 档位名 + chevron)+ Menu 上弹三档 + 完全权限风险\n * 确认弹窗(与主会话同款 RiskConfirmation 原语与文案)。\n * @module dsh-group-chat/client/permission-select\n */\n\nimport { useEffect, useState, type ReactNode } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport type { PermissionTier } from '../../core/types.ts'\nimport { asPermissionTier, PERMISSION_TIERS } from '../../core/types.ts'\n\nexport interface PermissionSelectProps {\n tier: PermissionTier\n onSelect: (tier: PermissionTier) => void\n}\n\n/** 档位展示名(与主会话中文标签一致)。 */\nconst TIER_LABELS: Record<PermissionTier, string> = {\n view_only: '仅可查看',\n workspace_write: '工作区内修改',\n full_access: '完全权限',\n}\n\n/** 档位悬停说明(群聊语境下的真实约束)。 */\nconst TIER_DESCRIPTIONS: Record<PermissionTier, string> = {\n view_only: '角色只能读取工作区文件,不能执行命令',\n workspace_write: '角色可执行命令(cwd 固定在工作区),每条命令需你在会话中确认',\n full_access: '角色可免确认直接执行命令,存在风险',\n}\n\n/** 完全权限风险确认文案(与主会话逐字一致)。 */\nconst CONFIRM_TEXT = {\n title: '确认启用完全权限?',\n description: '启用完全权限后,智能体将减少确认步骤,并且可以直接执行更多操作,包括敏感操作、文件修改或外部命令。仅建议在你信任当前任务时使用。',\n acknowledge: '我已了解风险,并愿意继续',\n cancel: '取消',\n enable: '启用完全权限',\n} as const\n\n// ---- 盾形图标(路径取自主会话 PermissionSelect 的设计稿字形) ----\n\nconst SHIELD_OUTLINE = 'M8.20554 0.899994L14.7901 3.36857V7.01026C14.7901 12 11.0466 14.2103 8.20554 15.3C5.36446 14.2103 1.62012 12 1.62012 7.01026V3.36857L8.20554 0.899994Z'\n\nfunction GlyphViewOnly(): ReactNode {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden>\n <path d={SHIELD_OUTLINE} stroke=\"currentColor\" strokeWidth=\"1.31831\" strokeLinejoin=\"round\" />\n <path d=\"M12.1654 5.7552L8.9447 9.41475C8.73044 9.65816 8.53628 9.8804 8.35774 10.0423C8.1713 10.2114 7.94235 10.3717 7.64016 10.4254C7.48207 10.4535 7.32 10.4552 7.16151 10.4294C6.85843 10.3801 6.62728 10.2223 6.43836 10.0559C6.25752 9.89653 6.06037 9.67732 5.84264 9.43705L4.72925 8.20897L5.63557 7.38707L6.74897 8.61594C6.98603 8.87755 7.12974 9.03533 7.24673 9.13839C7.31033 9.19443 7.34485 9.21476 7.35823 9.22122C7.38068 9.22484 7.40352 9.22515 7.42593 9.22122C7.40522 9.22502 7.42893 9.23294 7.53583 9.136C7.65132 9.03126 7.79316 8.87139 8.02643 8.60638L11.2479 4.94763L12.1654 5.7552Z\" fill=\"currentColor\" />\n </svg>\n )\n}\n\nfunction GlyphWorkspaceWrite(): ReactNode {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden>\n <path d=\"M8.08887 0.251709C8.20479 0.23085 8.32486 0.241168 8.43652 0.282959L15.0215 2.75171C15.2787 2.84819 15.4492 3.09414 15.4492 3.3689V7.0105C15.4492 7.10986 15.4441 7.2081 15.4414 7.30542C15.0285 7.07175 14.5905 6.87695 14.1309 6.73022V3.82495L8.20508 1.60327L2.2793 3.82495V7.0105C2.27936 9.7171 3.4745 11.5379 5.02734 12.7947C5.01025 12.9942 5 13.1962 5 13.4001C5.00001 13.7617 5.02722 14.1169 5.08008 14.4636C2.91555 13.0393 0.961014 10.752 0.960938 7.0105V3.3689C0.960938 3.09417 1.13146 2.84821 1.38867 2.75171L7.97461 0.282959L8.08887 0.251709Z\" fill=\"currentColor\" />\n <path d=\"M11.3525 5.64688V6.85688H5V5.64688H11.3525Z\" fill=\"currentColor\" />\n <path d=\"M9.5824 8.29376V9.50376H5V8.29376H9.5824Z\" fill=\"currentColor\" />\n <path d=\"M14.6647 15.6852H10.0338C10.3878 15.3751 10.7567 15.0517 11.0772 14.7706C11.2531 14.6164 11.4144 14.4746 11.5511 14.3547H14.6647V15.6852Z\" fill=\"currentColor\" />\n <path d=\"M8.14852 14.1308L7.33925 15.4976C7.22458 15.6912 7.42245 15.9194 7.63037 15.8333L9.09785 15.2254L15.0399 10.0719L14.0905 8.97733L8.14852 14.1308Z\" fill=\"currentColor\" />\n </svg>\n )\n}\n\nfunction GlyphFullAccess(): ReactNode {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden>\n <path d={SHIELD_OUTLINE} stroke=\"currentColor\" strokeWidth=\"1.31831\" strokeLinejoin=\"round\" />\n <path d=\"M9.10094 4.5V8.75939H7.59888V4.5H9.10094Z\" fill=\"currentColor\" />\n <path d=\"M9.10094 9.8114V11.5H7.59888V9.8114Z\" fill=\"currentColor\" />\n </svg>\n )\n}\n\nconst TIER_GLYPHS: Record<PermissionTier, () => ReactNode> = {\n view_only: GlyphViewOnly,\n workspace_write: GlyphWorkspaceWrite,\n full_access: GlyphFullAccess,\n}\n\nexport function PermissionSelect(props: PermissionSelectProps): ReactNode {\n const [open, setOpen] = useState(false)\n const [confirming, setConfirming] = useState(false)\n const [acknowledged, setAcknowledged] = useState(false)\n // 版本错位兜底:旧 host 快照无 permissionTier(或值非法)时按最安全的仅可查看呈现,\n // 不让面板整体崩溃\n const tier = asPermissionTier(props.tier) ?? 'view_only'\n\n // 档位被外部改回(如迁移/其他端变更)时收起弹层与确认态\n useEffect(() => {\n setOpen(false)\n setAcknowledged(false)\n setConfirming(false)\n }, [tier])\n\n const choose = (id: string): void => {\n setOpen(false)\n if (id === tier) return\n if (id === 'full_access') {\n setAcknowledged(false)\n setConfirming(true)\n return\n }\n props.onSelect(id as PermissionTier)\n }\n const closeConfirm = (): void => {\n setAcknowledged(false)\n setConfirming(false)\n }\n const confirmFullAccess = (): void => {\n if (!acknowledged) return\n closeConfirm()\n props.onSelect('full_access')\n }\n\n const items = PERMISSION_TIERS.map((t) => ({ id: t, label: TIER_LABELS[t], icon: TIER_GLYPHS[t]() }))\n const Glyph = TIER_GLYPHS[tier] ?? GlyphViewOnly\n\n return (\n <>\n <P.Menu\n open={open}\n items={items}\n selectedId={tier}\n onSelect={choose}\n onClose={() => { setOpen(false) }}\n side=\"top\"\n anchor={(\n <button\n type=\"button\"\n className=\"dsgc-permtrigger\"\n aria-label={'权限模式:' + TIER_LABELS[tier]}\n title={TIER_DESCRIPTIONS[tier]}\n disabled={confirming}\n onClick={() => { setOpen(!open) }}\n >\n <span className=\"dsgc-permicon\" aria-hidden>{Glyph()}</span>\n <span className=\"dsgc-permlabel\">{TIER_LABELS[tier]}</span>\n <span className={'dsgc-permchevron' + (open ? ' open' : '')} aria-hidden>{Icon(P.IconChevronDownOutline14, 14)}</span>\n </button>\n )}\n />\n <P.RiskConfirmation\n open={confirming}\n title={CONFIRM_TEXT.title}\n description={CONFIRM_TEXT.description}\n acknowledgeLabel={CONFIRM_TEXT.acknowledge}\n cancelLabel={CONFIRM_TEXT.cancel}\n closeLabel=\"关闭\"\n confirmLabel={CONFIRM_TEXT.enable}\n acknowledged={acknowledged}\n onAcknowledgedChange={setAcknowledged}\n onCancel={closeConfirm}\n onConfirm={confirmFullAccess}\n />\n </>\n )\n}\n","/**\n * 消息输入编辑器组件\n * @module dsh-group-chat/client/components\n */\n\nimport type { ReactNode, KeyboardEvent as ReactKeyboardEvent, ClipboardEvent as ReactClipboardEvent, DragEvent as ReactDragEvent } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport { PermissionSelect } from './PermissionSelect.tsx'\nimport { HoverTip } from './HoverTip.tsx'\nimport { escapeRegExp, type ClientSnapshot, type SnapshotRole } from '../lib/model.ts'\nimport type { AtToken } from '../../shared/file-mention-grammar.ts'\n\n/** 轮数控件 hover:宿主 Tooltip 三行说明(pre-line)。 */\nconst ROUNDS_HINT = '一轮 = 参与角色各说一次。\\n要他们自己互相反驳、你不插话时再加轮。\\n要边看边插话,就留 1,再点发送。'\n\ninterface ComposerProps {\n snap: ClientSnapshot\n sess: ClientSnapshot['sessions'][number] | null\n group: ClientSnapshot['groups'][number]\n enabledRoles: SnapshotRole[]\n participants: string[]\n mentionedRoles: SnapshotRole[]\n busyNow: boolean\n input: string\n mention: AtToken | null\n mentionCandidates: SnapshotRole[]\n mentionIdxC: number\n fileCandidates: Array<{ path: string, isDir: boolean }>\n fileSearchError: string | null\n fileSearchLoading: boolean\n rounds: number\n err: string\n atBottom: boolean\n bubblesLength: number\n inputRef: React.RefObject<HTMLDivElement>\n scrollRef: React.RefObject<HTMLDivElement>\n setMentionIdx: (val: number) => void\n setRounds: (val: number) => void\n togglePart: (rid: string) => void\n onInputCE: () => void\n onInputKeyDown: (e: ReactKeyboardEvent<HTMLDivElement>) => void\n onPasteCE: (e: ReactClipboardEvent<HTMLDivElement>) => void\n onDropCE: (e: ReactDragEvent<HTMLDivElement>) => void\n onDragOverCE: (e: ReactDragEvent<HTMLDivElement>) => void\n insertChip: (role: SnapshotRole) => void\n insertFileChip: (path: string, kind: 'file' | 'directory') => void\n sendMsg: () => Promise<void>\n stopRun: () => Promise<void>\n mutate: (args: Record<string, unknown>) => Promise<unknown>\n setMention: (val: AtToken | null) => void\n}\n\nexport function Composer(props: ComposerProps): ReactNode {\n const {\n snap,\n sess,\n group,\n enabledRoles,\n participants,\n mentionedRoles,\n busyNow,\n input,\n mention,\n mentionCandidates,\n mentionIdxC,\n fileCandidates,\n fileSearchError,\n fileSearchLoading,\n rounds,\n err,\n atBottom,\n bubblesLength,\n inputRef,\n scrollRef,\n setMentionIdx,\n setRounds,\n togglePart,\n onInputCE,\n onInputKeyDown,\n onPasteCE,\n onDropCE,\n onDragOverCE,\n insertChip,\n insertFileChip,\n sendMsg,\n stopRun,\n mutate,\n setMention,\n } = props\n\n return (\n <div className=\"dsgc-composer\">\n {!atBottom && bubblesLength\n ? (\n <div className=\"dsgc-tobottom\">\n <button\n type=\"button\"\n className=\"dsgc-tobtn\"\n onClick={() => { const el = scrollRef.current; if (el) el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' }) }}\n >\n {Icon(P.IconChevronDownOutline14, 14)}回到底部\n </button>\n </div>\n )\n : null}\n {err ? <div className=\"dsgc-err\">{err}</div> : null}\n <div className=\"dsgc-parts\">\n <span className=\"dsgc-partslabel\">参与角色</span>\n <div className=\"dsgc-partlist\">\n {mentionedRoles.length\n ? <span className=\"dsgc-partslabel\">已 @ {mentionedRoles.map((r) => r.name).join('、')}(本轮仅被点名成员发言)</span>\n : enabledRoles.length\n ? enabledRoles.map((r) => (\n <button\n key={r.id}\n type=\"button\"\n className={'dsgc-partchip' + (participants.includes(r.id) ? ' on' : '')}\n onClick={() => togglePart(r.id)}\n disabled={busyNow}\n title={busyNow ? '对话进行中,暂停调整' : '点击切换本轮是否参与'}\n >\n <span className=\"dsgc-chipdot\" style={{ background: r.color || '#888' }} />\n {r.name}\n </button>\n ))\n : <span className=\"dsgc-hint\">还没有启用的角色,请在右侧添加</span>}\n </div>\n </div>\n <div className=\"dsgc-card\">\n <div className=\"dsgc-mentionwrap\">\n {mention !== null && mention.query === '' && mentionCandidates.length > 0\n ? (\n <div className=\"dsgc-mention\" role=\"listbox\">\n {mentionCandidates.map((r, i) => (\n <button\n key={r.id}\n type=\"button\"\n className={'dsgc-mentionitem' + (i === mentionIdxC ? ' on' : '')}\n role=\"option\"\n aria-selected={i === mentionIdxC ? 'true' : 'false'}\n onMouseDown={(e) => { e.preventDefault() }}\n onClick={() => { insertChip(r) }}\n onMouseEnter={() => setMentionIdx(i)}\n >\n <span className=\"dsgc-chipdot\" style={{ background: r.color || '#888' }} />\n <span className=\"dsgc-mentionname\">{r.name}</span>\n <span className=\"dsgc-mentionmodel\">{r.provider} / {r.model}</span>\n </button>\n ))}\n <span className=\"dsgc-mentionhint\">↑↓ 选择 · Enter/Tab 插入</span>\n </div>\n )\n : mention !== null && mention.query !== ''\n ? (\n <div className=\"dsgc-mention dsgc-mention-file\" role=\"listbox\">\n {fileCandidates.length\n ? fileCandidates.map((item, i) => (\n <button\n key={item.path}\n type=\"button\"\n className={'dsgc-mentionitem' + (i === mentionIdxC ? ' on' : '')}\n role=\"option\"\n aria-selected={i === mentionIdxC ? 'true' : 'false'}\n onMouseDown={(e) => { e.preventDefault() }}\n onClick={() => {\n insertFileChip(item.path, item.isDir ? 'directory' : 'file')\n }}\n onMouseEnter={() => setMentionIdx(i)}\n >\n <span className={'dsgc-fileglyph' + (item.isDir ? ' dir' : ' file')} aria-hidden=\"true\">\n {item.isDir\n ? <P.FileTypeIcon kind=\"folder\" size={16} />\n : <P.FileTypeIcon path={item.path} size={16} />}\n </span>\n <span className=\"dsgc-mentionname\">{item.path}</span>\n {item.isDir ? <span className=\"dsgc-filedrill\">{Icon(P.IconChevronRightOutline14, 12)}</span> : null}\n </button>\n ))\n : fileSearchLoading\n ? <div className=\"dsgc-mentionitem dsgc-hint\">检索中…</div>\n : fileSearchError\n ? <div className=\"dsgc-mentionitem dsgc-hint\">{fileSearchError}</div>\n : <div className=\"dsgc-mentionitem dsgc-hint\">无匹配文件</div>}\n <span className=\"dsgc-mentionhint\">\n {fileSearchLoading && fileCandidates.length\n ? '检索中…'\n : fileCandidates.some((f) => f.isDir)\n ? '↑↓ 选择 · Enter 插入 · Tab 进入目录 · Esc 关闭'\n : '↑↓ 选择 · Enter 插入 · Esc 关闭'}\n </span>\n </div>\n )\n : null}\n {!input.trim()\n ? <div className=\"dsgc-ph\" aria-hidden=\"true\">发消息给全群,@成员 点名让其回应…</div>\n : null}\n <div\n className=\"dsgc-edit\"\n ref={inputRef}\n contentEditable\n suppressContentEditableWarning\n role=\"textbox\"\n aria-multiline=\"true\"\n aria-label=\"群聊消息输入框\"\n onInput={onInputCE}\n onKeyDown={onInputKeyDown}\n onPaste={onPasteCE}\n onDrop={onDropCE}\n onDragOver={onDragOverCE}\n onBlur={() => { setMention(null) }}\n />\n </div>\n <div className=\"dsgc-sendrow\">\n <PermissionSelect\n tier={group.permissionTier}\n onSelect={(tier) => { void mutate({ op: 'setPermissionTier', groupId: group.id, tier }) }}\n />\n <span style={{ flex: 1 }} />\n <HoverTip label={ROUNDS_HINT} side=\"top\" delayMs={500} maxWidth={280} className=\"dsgc-rounds\">\n <button type=\"button\" className=\"dsgc-roundbtn\" aria-label=\"减少轮数\" disabled={rounds <= 1} onClick={() => { setRounds(Math.max(1, rounds - 1)) }}>\n {Icon(P.IconChevronLeftOutline14, 12)}\n </button>\n <span className=\"dsgc-roundnum\">{rounds}</span>\n <button type=\"button\" className=\"dsgc-roundbtn\" aria-label=\"增加轮数\" disabled={rounds >= 10} onClick={() => { setRounds(Math.min(10, rounds + 1)) }}>\n {Icon(P.IconChevronRightOutline14, 12)}\n </button>\n <span style={{ padding: '0 6px 0 2px' }}>轮</span>\n </HoverTip>\n {busyNow\n ? (\n <P.Button variant=\"outline\" className=\"dsgc-stopbtn\" onClick={() => { void stopRun() }}>\n {Icon(P.IconStopFill16, 16)}停止\n </P.Button>\n )\n : (\n <P.Button variant=\"primary\" onClick={() => { void sendMsg() }} disabled={!input.trim() || (!participants.length && !mentionedRoles.length) || !sess}>\n {Icon(P.IconSendOutline16, 16)}发送\n </P.Button>\n )}\n </div>\n </div>\n </div>\n )\n}\n","/**\n * 中央会话面板组件\n * @module dsh-group-chat/client/components\n */\n\nimport type { ReactNode } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport { MessageFlow } from './MessageFlow.tsx'\nimport { Composer } from './Composer.tsx'\nimport type { ClientSnapshot, SnapshotRole } from '../lib/model.ts'\nimport type { AtToken } from '../../shared/file-mention-grammar.ts'\n\ninterface ChatPanelProps {\n snap: ClientSnapshot\n sess: ClientSnapshot['sessions'][number] | null\n group: ClientSnapshot['groups'][number]\n enabledRoles: SnapshotRole[]\n participants: string[]\n mentionedRoles: SnapshotRole[]\n busyNow: boolean\n input: string\n mention: AtToken | null\n mentionCandidates: SnapshotRole[]\n mentionIdxC: number\n fileCandidates: Array<{ path: string, isDir: boolean }>\n fileSearchError: string | null\n fileSearchLoading: boolean\n rounds: number\n err: string\n atBottom: boolean\n topicDraft: string | null\n msgById: Record<string, ClientSnapshot['messages'][number]>\n navOpen: boolean\n asideOpen: boolean\n inputRef: React.RefObject<HTMLDivElement>\n scrollRef: React.RefObject<HTMLDivElement>\n setTopicDraft: (val: string | null) => void\n setConfirmClear: (val: boolean) => void\n setMentionIdx: (val: number) => void\n setRounds: (val: number) => void\n setNavOpen: (val: boolean) => void\n setAsideOpen: (val: boolean) => void\n togglePart: (rid: string) => void\n onMsgsScroll: () => void\n onInputCE: () => void\n onInputKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) => void\n onPasteCE: (e: React.ClipboardEvent<HTMLDivElement>) => void\n onDropCE: (e: React.DragEvent<HTMLDivElement>) => void\n onDragOverCE: (e: React.DragEvent<HTMLDivElement>) => void\n insertChip: (role: SnapshotRole) => void\n insertFileChip: (path: string, kind: 'file' | 'directory') => void\n sendMsg: () => Promise<void>\n stopRun: () => Promise<void>\n action: (payload: Record<string, unknown>) => Promise<unknown>\n mutate: (args: Record<string, unknown>) => Promise<unknown>\n setMention: (val: AtToken | null) => void\n onRetrySpeak: (messageId: string) => void\n}\n\nexport function ChatPanel(props: ChatPanelProps): ReactNode {\n const {\n snap,\n sess,\n group,\n enabledRoles,\n participants,\n mentionedRoles,\n busyNow,\n input,\n mention,\n mentionCandidates,\n mentionIdxC,\n fileCandidates,\n fileSearchError,\n fileSearchLoading,\n rounds,\n err,\n atBottom,\n topicDraft,\n msgById,\n navOpen,\n asideOpen,\n inputRef,\n scrollRef,\n setTopicDraft,\n setConfirmClear,\n setMentionIdx,\n setRounds,\n setNavOpen,\n setAsideOpen,\n togglePart,\n onMsgsScroll,\n onInputCE,\n onInputKeyDown,\n onPasteCE,\n onDropCE,\n onDragOverCE,\n insertChip,\n insertFileChip,\n sendMsg,\n stopRun,\n action,\n mutate,\n setMention,\n onRetrySpeak,\n } = props\n\n const commitTopic = (): void => {\n if (topicDraft !== null && sess && topicDraft !== sess.topic) void mutate({ op: 'setTopic', sessionId: sess.id, topic: topicDraft })\n setTopicDraft(null)\n }\n\n const bubbles = (\n <MessageFlow\n snap={snap}\n sess={sess}\n busyNow={busyNow}\n msgById={msgById}\n action={action}\n onRetrySpeak={onRetrySpeak}\n />\n )\n\n return (\n <section className=\"dsgc-chat\">\n {/* 接缝收合钮 */}\n <button\n type=\"button\"\n className={'dsgc-seambtn left' + (navOpen ? '' : ' closed')}\n aria-label={navOpen ? '收起群组导航栏' : '展开群组导航栏'}\n title={navOpen ? '收起群组导航栏' : '展开群组导航栏'}\n aria-expanded={navOpen}\n onClick={() => { setNavOpen(!navOpen) }}\n >\n {Icon(P.IconChevronLeftOutline14, 16)}\n </button>\n <button\n type=\"button\"\n className={'dsgc-seambtn right' + (asideOpen ? '' : ' closed')}\n aria-label={asideOpen ? '收起成员与工作区栏' : '展开成员与工作区栏'}\n title={asideOpen ? '收起成员与工作区栏' : '展开成员与工作区栏'}\n aria-expanded={asideOpen}\n onClick={() => { setAsideOpen(!asideOpen) }}\n >\n {Icon(P.IconChevronRightOutline14, 16)}\n </button>\n \n <div className=\"dsgc-chathead\">\n <div className=\"dsgc-chathead-row\">\n {sess ? <span className=\"dsgc-sess-title\" title={'当前会话:' + sess.name}>{sess.name}</span> : null}\n <input\n className=\"dsgc-topic\"\n value={topicDraft === null ? (sess ? sess.topic : '') : topicDraft}\n placeholder=\"设置本会话主题(可选)…\"\n onChange={(e) => { setTopicDraft(e.target.value) }}\n onBlur={commitTopic}\n onKeyDown={(e) => { if (e.key === 'Enter') (e.target as HTMLInputElement).blur() }}\n />\n <P.Button variant=\"ghost\" size=\"sm\" className=\"dsgc-clearbtn\" title=\"清空当前会话的消息记录\" onClick={() => { if (sess) setConfirmClear(true) }}>\n 清空\n </P.Button>\n </div>\n </div>\n \n <div className=\"dsgc-msgs\" ref={scrollRef} onScroll={onMsgsScroll}>\n {sess && sess.messageIds.length > 0\n ? bubbles\n : (\n <div className=\"dsgc-empty\">\n {Icon(P.IconSparkle16, 20)}\n <div className=\"dsgc-emptytitle\">{sess && sess.topic ? '「' + sess.topic + '」' : '会话已就绪'}</div>\n <div className=\"dsgc-hint\">\n {enabledRoles.length\n ? '发送消息开始讨论;@成员 点名让其优先回应——每轮全体参与角色按顺序各发言一次,可用右下角轮数控制(1–10 轮)'\n : '先在右侧添加角色(每个角色可绑定不同模型),再回到这里发起讨论。'}\n </div>\n </div>\n )}\n </div>\n \n <Composer\n snap={snap}\n sess={sess}\n group={group}\n enabledRoles={enabledRoles}\n participants={participants}\n mentionedRoles={mentionedRoles}\n busyNow={busyNow}\n input={input}\n mention={mention}\n mentionCandidates={mentionCandidates}\n mentionIdxC={mentionIdxC}\n fileCandidates={fileCandidates}\n fileSearchError={fileSearchError}\n fileSearchLoading={fileSearchLoading}\n rounds={rounds}\n err={err}\n atBottom={atBottom}\n bubblesLength={sess?.messageIds.length || 0}\n inputRef={inputRef}\n scrollRef={scrollRef}\n setMentionIdx={setMentionIdx}\n setRounds={setRounds}\n togglePart={togglePart}\n onInputCE={onInputCE}\n onInputKeyDown={onInputKeyDown}\n onPasteCE={onPasteCE}\n onDropCE={onDropCE}\n onDragOverCE={onDragOverCE}\n insertChip={insertChip}\n insertFileChip={insertFileChip}\n sendMsg={sendMsg}\n stopRun={stopRun}\n mutate={mutate}\n setMention={setMention}\n />\n </section>\n )\n}\n","/**\n * 未发送草稿:按会话 id 分槽,模块级跨挂载存活。\n * 主会话⇄群聊会整页卸载 composer,contentEditable 的 HTML 必须自行记住。\n * @module dsh-group-chat/client/composer-draft\n */\n\nexport interface ComposerDraft {\n html: string\n text: string\n}\n\nconst LIMIT = 32\nconst drafts = new Map<string, ComposerDraft>()\n\nconst empty = (): ComposerDraft => ({ html: '', text: '' })\n\n/** 读指定会话草稿;命中则提到 LRU 最近端。 */\nexport function readComposerDraft(sessionId: string | null | undefined): ComposerDraft {\n if (!sessionId) return empty()\n const hit = drafts.get(sessionId)\n if (!hit) return empty()\n drafts.delete(sessionId)\n drafts.set(sessionId, hit)\n return hit\n}\n\n/** 写入;空草稿删槽。超出上限淘汰最旧槽。 */\nexport function writeComposerDraft(sessionId: string | null | undefined, html: string, text: string): void {\n if (!sessionId) return\n drafts.delete(sessionId)\n if (!html && !text) return\n drafts.set(sessionId, { html, text })\n if (drafts.size > LIMIT) {\n const oldest = drafts.keys().next().value\n if (oldest !== undefined) drafts.delete(oldest)\n }\n}\n\n/** 发送成功或明确丢弃时摘槽。 */\nexport function clearComposerDraft(sessionId: string | null | undefined): void {\n if (sessionId) drafts.delete(sessionId)\n}\n\n/** 测试用:清空全部槽位。 */\nexport function resetComposerDrafts(): void {\n drafts.clear()\n}\n","/**\n * 群聊面板核心状态管理 hook\n * @module dsh-group-chat/client/hooks\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { api } from '../lib/api.ts'\nimport { readComposerDraft } from '../lib/composer-draft.ts'\nimport type { ClientSnapshot, ModelsResponse, RoleDraft } from '../lib/model.ts'\nimport type { AtToken } from '../../shared/file-mention-grammar.ts'\n\nexport interface MutateResponse {\n ok: boolean\n snapshot?: ClientSnapshot\n lastCreated?: ClientSnapshot['lastCreated']\n error?: string\n}\n\nexport interface ActionOk {\n ok: boolean\n error?: string\n}\n\n/**\n * 面板切换缓存(模块级,跨挂载存活):main 为 keyed 槽,主会话⇄群聊切换会\n * 整体卸载重挂面板组件;缓存最近快照、选中项与按会话分槽的未发送草稿,\n * 让重挂载瞬时恢复上次视图。挂载后的 state 拉取 / SSE 首帧再行校正。\n */\nlet cachedSnap: ClientSnapshot | null = null\nlet cachedGid: string | null = null\nlet cachedSid: string | null = null\n\nexport function useGroupChatState() {\n // 核心数据快照(重挂载时从缓存瞬时恢复,消除切换闪现的加载态)\n const [snap, setSnap] = useState<ClientSnapshot | null>(() => cachedSnap)\n\n // 选中状态\n const [gid, setGid] = useState<string | null>(() => cachedGid)\n const [sid, setSid] = useState<string | null>(() => cachedSid)\n\n /** 已应用过的 lastCreated 会话标记:只在标记变化(真正的新建)时跟随选中,\n 而不是每帧都把视图拽回「最近创建的会话」(流式期间每 120ms 一帧)。 */\n const appliedCreatedRef = useRef<string | null>(cachedSnap?.lastCreated?.sessionId ?? null)\n\n /** 快照落地统一口:写状态 + 写切换缓存。 */\n const applySnap = useCallback((s: ClientSnapshot): void => {\n cachedSnap = s\n setSnap(s)\n }, [])\n\n /** 选中项统一口:写状态 + 写切换缓存(重挂载恢复到用户离开时的位置)。 */\n const selectGroup = useCallback((v: string): void => {\n cachedGid = v\n setGid(v)\n }, [])\n const selectSession = useCallback((v: string): void => {\n cachedSid = v\n setSid(v)\n }, [])\n \n // UI 状态\n const [search, setSearch] = useState('')\n const [collapsedGroups, setCollapsedGroups] = useState<Set<string>>(() => new Set())\n const [asideOpen, setAsideOpen] = useState(true)\n const [navOpen, setNavOpen] = useState(true)\n const [atBottom, setAtBottom] = useState(true)\n \n // 编辑态\n const [renameDraft, setRenameDraft] = useState<{ kind: 'group' | 'session', id: string, value: string } | null>(null)\n const [confirmDel, setConfirmDel] = useState<{ kind: 'group' | 'session', id: string } | null>(null)\n const [confirmClear, setConfirmClear] = useState(false)\n const [topicDraft, setTopicDraft] = useState<string | null>(null)\n\n // 角色编辑(models 目录与保存/校验态在 RoleDrawer 内自理)\n const [roleDraft, setRoleDraft] = useState<RoleDraft | null>(null)\n const [models, setModels] = useState<ModelsResponse | null>(null)\n const [modelsError, setModelsError] = useState<string | null>(null)\n \n // 参与角色选择\n const [partsSel, setPartsSel] = useState<string[] | null>(null)\n const [rounds, setRounds] = useState(1)\n \n // 输入与 @提及(文本初值取当前选中会话草稿,HTML 由 useComposerDraft 灌回)\n const [input, setInput] = useState(() => readComposerDraft(cachedSid).text)\n const [mention, setMention] = useState<AtToken | null>(null)\n const [mentionIdx, setMentionIdx] = useState(0)\n \n // 错误提示\n const [err, setErr] = useState('')\n \n // Refs\n const inputRef = useRef<HTMLDivElement | null>(null)\n const sendingRef = useRef(false)\n const scrollRef = useRef<HTMLDivElement | null>(null)\n\n // 初始加载 + SSE 订阅\n useEffect(() => {\n let live = true\n api.state().then((s) => {\n if (live && s && (s as ClientSnapshot).ok) applySnap(s as ClientSnapshot)\n }).catch(() => { /* SSE 会重试 */ })\n const events = new EventSource('/api/group-chat/events')\n events.onmessage = (message) => {\n try {\n const s = JSON.parse(message.data) as ClientSnapshot\n if (!live || !s || !s.ok) return\n // lastCreated 仅在变化时跟随选中(新建群组/会话的定位信号);\n // 帧里重复携带的旧标记不再反复重置视图\n if (s.lastCreated && s.lastCreated.sessionId && s.lastCreated.sessionId !== appliedCreatedRef.current) {\n appliedCreatedRef.current = s.lastCreated.sessionId\n selectGroup(s.lastCreated.groupId)\n selectSession(s.lastCreated.sessionId)\n setPartsSel(null)\n }\n applySnap(s)\n } catch { /* ignore malformed frame */ }\n }\n return () => {\n live = false\n events.close()\n }\n }, [applySnap, selectGroup, selectSession])\n\n // API 操作封装\n const action = useCallback(async (payload: Record<string, unknown>): Promise<unknown> => {\n try {\n return await api.action(payload)\n } catch (e) {\n setErr(String((e && (e as Error).message) || e))\n return null\n }\n }, [])\n\n const mutate = async (args: Record<string, unknown>): Promise<MutateResponse | null> => {\n setErr('')\n const res = await action(Object.assign({ kind: 'mutate' }, args)) as MutateResponse | null\n if (res && res.ok && res.snapshot) {\n // 响应里的 lastCreated 是服务端当前值(未必由本次调用产生)——同样只在\n // 变化时跟随选中,避免改名/改配置等普通 mutate 把视图拽走\n if (res.lastCreated && res.lastCreated.sessionId && res.lastCreated.sessionId !== appliedCreatedRef.current) {\n appliedCreatedRef.current = res.lastCreated.sessionId\n selectGroup(res.lastCreated.groupId)\n selectSession(res.lastCreated.sessionId)\n setPartsSel(null)\n }\n applySnap(res.snapshot)\n if (res.snapshot.error) setErr(res.snapshot.error)\n }\n return res\n }\n\n return {\n // 状态\n snap,\n setSnap: applySnap,\n gid,\n setGid: selectGroup,\n sid,\n setSid: selectSession,\n search,\n setSearch,\n collapsedGroups,\n setCollapsedGroups,\n renameDraft,\n setRenameDraft,\n confirmDel,\n setConfirmDel,\n confirmClear,\n setConfirmClear,\n roleDraft,\n setRoleDraft,\n models,\n setModels,\n modelsError,\n setModelsError,\n partsSel,\n setPartsSel,\n rounds,\n setRounds,\n input,\n setInput,\n err,\n setErr,\n topicDraft,\n setTopicDraft,\n mention,\n setMention,\n mentionIdx,\n setMentionIdx,\n asideOpen,\n setAsideOpen,\n navOpen,\n setNavOpen,\n atBottom,\n setAtBottom,\n // Refs\n inputRef,\n sendingRef,\n scrollRef,\n // 方法\n action,\n mutate,\n }\n}\n","/**\n * Vendored @file token grammar from dsh-file-reference (browser-safe, zero Node API).\n *\n * Sourced from @deepseek-ai/dsh-file-reference/lib/types/grammar.js\n * Cannot import directly due to client bundle purity gate (dsh-client-bundle-purity).\n *\n * 只保留输入侧的 @token 识别(activeAtToken);候选的文本化(formatFileMention)\n * 未被本插件采用——目录钻入走「插入整颗芯片」语义,见 docs/DESIGN.md Composer 契约。\n *\n * @module dsh-group-chat/shared\n */\n\nexport interface AtToken {\n /** Full matched prefix including @ and optional quotes */\n prefix: string\n /** Query fragment after @ (unquoted content) */\n query: string\n /** Whether the token uses quoted form @\"...\" */\n quoted: boolean\n}\n\n/**\n * Extract active @token at cursor position.\n * Matches @ at word boundary (line start or after whitespace).\n *\n * @param line - Current line text\n * @param cursor - Cursor offset in line\n * @returns Token or undefined if no active @token at cursor\n */\nexport function activeAtToken(line: string, cursor: number): AtToken | undefined {\n const before = line.slice(0, cursor)\n\n // Try quoted @\"... first (more specific)\n const quotedMatch = /(?:^|\\s)@\"([^\"]*)$/.exec(before)\n if (quotedMatch) {\n const prefix = quotedMatch[0].trimStart()\n return {\n prefix,\n query: quotedMatch[1],\n quoted: true,\n }\n }\n\n // Then try plain @...\n const plainMatch = /(?:^|\\s)@([^\\s@]*)$/.exec(before)\n if (plainMatch) {\n const prefix = plainMatch[0].trimStart()\n return {\n prefix,\n query: plainMatch[1],\n quoted: false,\n }\n }\n\n return undefined\n}\n","/**\n * 通用工具函数\n * @module dsh-group-chat/client/utils\n */\n\nimport { createElement } from 'react'\nimport { flushSync } from 'react-dom'\nimport { createRoot } from 'react-dom/client'\nimport { FileTypeIcon } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { activeAtToken, type AtToken } from '../../shared/file-mention-grammar.ts'\n\n/** HTML 转义(芯片以 execCommand('insertHTML') 注入,角色名需转义)。 */\nexport function escapeHtml(v: string): string {\n return String(v).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;')\n}\n\n/**\n * execCommand 集中封装。它已被 Web 平台标记 @deprecated(ts 6387 编辑器提示),\n * 但仍是唯一能让 contenteditable 的 DOM 编辑进入浏览器原生 undo 栈的同步 API\n * (自研 undo 栈或引入 Lexical/ProseMirror 类框架代价更大;取舍见 DESIGN.md\n * Composer 契约)。经中间别名擦除废弃标记,全部调用走本封装,不在调用处散布提示。\n */\ntype ExecCommandFn = (commandId: string, showUI?: boolean, value?: string) => boolean\nlet execCommandFn: ExecCommandFn | undefined\nexport function execCommand(commandId: 'delete' | 'insertHTML' | 'insertText' | 'insertLineBreak', value?: string): boolean {\n execCommandFn ??= (document as unknown as { execCommand: ExecCommandFn }).execCommand\n return execCommandFn.call(document, commandId, false, value)\n}\n\n/**\n * contenteditable 输入区 → 纯文本序列化(发送/参与判定的唯一事实源):\n * 文本节点原样;<br> → 换行;角色芯片(.dsgc-chipin[data-role-id])展开回「@名字␠」;\n * 文件芯片(.dsgc-chipin[data-kind=file])展开回「@path」或「@\"path with spaces\"」;\n * DIV/P 块前补换行(防粘贴残留的块级包裹)。\n */\nexport function serializeInput(root: HTMLElement): string {\n const walk = (node: Node): string => {\n if (node.nodeType === Node.TEXT_NODE) return node.nodeValue || ''\n if (node.nodeType !== Node.ELEMENT_NODE) return ''\n const el = node as HTMLElement\n if (el.tagName === 'BR') return '\\n'\n if (el.classList.contains('dsgc-chipin')) {\n // 角色芯片\n if (el.dataset.roleId) {\n return '@' + (el.dataset.name || '') + ' '\n }\n // 文件芯片\n if (el.dataset.kind === 'file') {\n const path = el.dataset.path || ''\n const needsQuote = /\\s/.test(path)\n return needsQuote ? `@\"${path}\"` : `@${path}`\n }\n }\n const sep = /^(DIV|P)$/.test(el.tagName) ? '\\n' : ''\n return sep + Array.from(el.childNodes).map(walk).join('')\n }\n return Array.from(root.childNodes).map(walk).join('')\n}\n\n/** @角色芯片的 HTML(原子元素:contenteditable=false + draggable,退格整删;fresh=插入后需营救选区,加 data-new 标记)。 */\nexport function chipHtml(role: { id: string, name: string, color?: string }, fresh = false): string {\n const c = escapeHtml(role.color || '#888')\n return '<span class=\"dsgc-chipin\"' + (fresh ? ' data-new=\"\"' : '') + ' data-role-id=\"' + escapeHtml(role.id) + '\" data-name=\"' + escapeHtml(role.name) + '\" style=\"--role-color:' + c + '\" contenteditable=\"false\" draggable=\"true\">' +\n '<span class=\"dsgc-chipdot\" style=\"background:' + c + '\"></span>' + escapeHtml(role.name) + '</span>'\n}\n\n/** 把宿主 FileTypeIcon 渲成静态 SVG,再塞进 insertHTML(与检索列表同一套字形)。 */\nfunction fileTypeIconMarkup(path: string, kind: 'file' | 'directory'): string {\n if (typeof document === 'undefined') return ''\n const host = document.createElement('span')\n const root = createRoot(host)\n try {\n flushSync(() => {\n root.render(kind === 'directory'\n ? createElement(FileTypeIcon, { kind: 'folder', size: 14 })\n : createElement(FileTypeIcon, { path, size: 14 }))\n })\n return host.innerHTML\n } finally {\n root.unmount()\n }\n}\n\n/** @文件芯片的 HTML(原子元素:contenteditable=false + draggable,退格整删;fresh 同 chipHtml)。 */\nexport function fileChipHtml(path: string, kind: 'file' | 'directory', fresh = false): string {\n const basename = path.split('/').pop() || path\n const dir = kind === 'directory'\n return '<span class=\"dsgc-chipin dsgc-chipin-file\"' + (fresh ? ' data-new=\"\"' : '') + ' data-kind=\"file\"' + (dir ? ' data-dir=\"1\"' : '') + ' data-path=\"' + escapeHtml(path) + '\" contenteditable=\"false\" draggable=\"true\">' +\n '<span class=\"dsgc-chipglyph\" aria-hidden=\"true\">' + fileTypeIconMarkup(path, kind) + '</span>' + escapeHtml(basename) + '</span>'\n}\n\n/**\n * 光标前的活跃 @token(角色或文件弹层触发判定)。\n * \n * @returns AtToken 对象,包含 prefix/query/quoted;无返回 null\n */\nexport function queryAtCaret(): AtToken | null {\n const sel = window.getSelection()\n if (!sel || !sel.isCollapsed || sel.rangeCount === 0) return null\n const node = sel.anchorNode\n if (!node || node.nodeType !== Node.TEXT_NODE) return null\n const before = (node.nodeValue || '').slice(0, sel.anchorOffset)\n return activeAtToken(before, before.length) || null\n}\n","/**\n * 消息输入相关 hooks\n * @module dsh-group-chat/client/hooks\n */\n\nimport { useCallback, useEffect, useLayoutEffect, useRef, type ClipboardEvent as ReactClipboardEvent, type DragEvent as ReactDragEvent, type KeyboardEvent as ReactKeyboardEvent } from 'react'\nimport { execCommand, queryAtCaret, serializeInput, chipHtml, fileChipHtml } from '../utils/utils.ts'\nimport { readComposerDraft, writeComposerDraft } from '../lib/composer-draft.ts'\nimport type { AtToken } from '../../shared/file-mention-grammar.ts'\nimport type { SnapshotRole } from '../lib/model.ts'\n\nexport function useComposerEffects(\n inputRef: React.RefObject<HTMLDivElement>,\n scrollRef: React.RefObject<HTMLDivElement>,\n input: string,\n atBottom: boolean,\n snap: unknown,\n) {\n // 贴底时新内容自动跟随滚动\n const onMsgsScroll = useCallback(() => {\n const el = scrollRef.current\n if (!el) return\n const isAtBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 60\n return isAtBottom\n }, [scrollRef])\n\n useEffect(() => {\n const el = scrollRef.current\n if (el && atBottom) el.scrollTop = el.scrollHeight\n }, [snap, atBottom, scrollRef])\n\n // composer 输入框随内容自适应高度\n useEffect(() => {\n const el = inputRef.current\n if (!el) return\n el.style.height = 'auto'\n el.style.height = Math.min(180, Math.max(36, el.scrollHeight)) + 'px'\n }, [input, inputRef])\n\n return { onMsgsScroll }\n}\n\nexport function useComposerInput(\n inputRef: React.RefObject<HTMLDivElement>,\n setInput: (val: string) => void,\n setMention: (val: AtToken | null) => void,\n setMentionIdx: (val: number) => void,\n sessionId?: string | null,\n) {\n const sessionIdRef = useRef(sessionId)\n sessionIdRef.current = sessionId\n\n /** 从 DOM 同步 input 状态(序列化),并写入当前会话草稿槽。 */\n const syncFromDOM = useCallback((): void => {\n const el = inputRef.current\n if (!el) return\n const text = serializeInput(el)\n setInput(text)\n writeComposerDraft(sessionIdRef.current, el.innerHTML, text)\n }, [inputRef, setInput])\n\n const onInputCE = useCallback((): void => {\n syncFromDOM()\n setMention(queryAtCaret())\n setMentionIdx(0)\n }, [syncFromDOM, setMention, setMentionIdx])\n\n /** 粘贴/拖放强制纯文本 */\n const onPasteCE = useCallback((e: ReactClipboardEvent<HTMLDivElement>): void => {\n e.preventDefault()\n const text = e.clipboardData.getData('text/plain')\n if (text) execCommand('insertText', text)\n }, [])\n\n const onDragOverCE = useCallback((e: ReactDragEvent<HTMLDivElement>): void => {\n e.preventDefault()\n }, [])\n\n const onDropCE = useCallback((e: ReactDragEvent<HTMLDivElement>): void => {\n e.preventDefault()\n const text = e.dataTransfer.getData('text/plain')\n if (text) execCommand('insertText', text)\n }, [])\n\n return {\n syncFromDOM,\n onInputCE,\n onPasteCE,\n onDragOverCE,\n onDropCE,\n }\n}\n\n/**\n * 按会话恢复草稿:切会话时先把当前 HTML 写入旧槽,再灌入新槽;\n * 面板重挂载(主会话⇄群聊)时 editor 是新节点,从模块缓存灌回。\n */\nexport function useComposerDraft(\n sessionId: string | null | undefined,\n inputRef: React.RefObject<HTMLDivElement>,\n setInput: (val: string) => void,\n setMention: (val: AtToken | null) => void,\n): void {\n const prevIdRef = useRef<string | null>(null)\n useLayoutEffect(() => {\n const el = inputRef.current\n const prev = prevIdRef.current\n const next = sessionId || null\n if (el && prev && prev !== next) writeComposerDraft(prev, el.innerHTML, serializeInput(el))\n prevIdRef.current = next\n if (!next) return\n const draft = readComposerDraft(next)\n if (el) el.innerHTML = draft.html\n setInput(draft.text)\n setMention(null)\n return () => {\n const node = inputRef.current\n const id = prevIdRef.current\n if (node && id) writeComposerDraft(id, node.innerHTML, serializeInput(node))\n }\n }, [sessionId, inputRef, setInput, setMention])\n}\n\nexport function useMentionChip(\n inputRef: React.RefObject<HTMLDivElement>,\n setMention: (val: AtToken | null) => void,\n setMentionIdx: (val: number) => void,\n syncFromDOM: () => void,\n) {\n /** 弹层候选 → 删掉光标前的 @词、插入带 data-new 标记的芯片 + 尾随空格。 */\n const insertChipHtml = useCallback((html: string): void => {\n const el = inputRef.current\n const sel = window.getSelection()\n if (!el || !sel) return\n if (!sel.anchorNode || !el.contains(sel.anchorNode)) return\n el.focus({ preventScroll: true })\n\n // 1. 删除光标前的 @token(包括引号)\n const node = sel.anchorNode\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.nodeValue || ''\n const off = sel.anchorOffset\n const before = text.slice(0, off)\n // 匹配 @词 或 @\"词\n const m = /(?:^|\\s)@(\"?)([^\"\\s@]*)$/.exec(before)\n if (m) {\n const prefixLen = m[1] ? 2 : 1 // @\" 或 @\n const queryLen = m[2].length\n const start = off - prefixLen - queryLen\n if (start >= 0) {\n const range = document.createRange()\n range.setStart(node, start)\n range.setEnd(node, off)\n sel.removeAllRanges()\n sel.addRange(range)\n execCommand('delete')\n }\n }\n }\n\n // 2. 插入芯片(fresh 标记:部分浏览器把选区落进 contenteditable=false 芯片内部,\n // 曾致空格丢失与光标不可见)\n execCommand('insertHTML', html)\n const chip = el.querySelector<HTMLElement>('.dsgc-chipin[data-new]')\n if (!chip) return\n\n // 3. 选区显式钉到芯片之后,再补尾随空格\n const after = document.createRange()\n after.setStartAfter(chip)\n after.collapse(true)\n sel.removeAllRanges()\n sel.addRange(after)\n execCommand('insertText', ' ')\n chip.removeAttribute('data-new')\n setMention(null)\n setMentionIdx(0)\n syncFromDOM()\n }, [inputRef, setMention, setMentionIdx, syncFromDOM])\n\n const insertChip = useCallback((role: SnapshotRole): void => {\n insertChipHtml(chipHtml(role, true))\n }, [insertChipHtml])\n\n const insertFileChip = useCallback((path: string, kind: 'file' | 'directory'): void => {\n insertChipHtml(fileChipHtml(path, kind, true))\n }, [insertChipHtml])\n\n return { insertChip, insertFileChip }\n}\n\nexport function useInputKeyboard(\n mention: AtToken | null,\n mentionCandidates: SnapshotRole[],\n mentionIdxC: number,\n setMentionIdx: (val: number | ((prev: number) => number)) => void,\n insertChip: (role: SnapshotRole) => void,\n insertFileChip: (path: string, kind: 'file' | 'directory') => void,\n fileCandidates: Array<{ path: string; isDir: boolean }>,\n setMention: (val: AtToken | null) => void,\n sendMsg: () => Promise<void>,\n) {\n const onInputKeyDown = useCallback((e: ReactKeyboardEvent<HTMLDivElement>): void => {\n // IME 组合中的按键不参与任何快捷逻辑\n if (e.nativeEvent.isComposing || e.keyCode === 229) return\n \n // 角色模式(裸 @):Enter/Tab 插入角色芯片\n if (mention !== null && mention.query === '' && mentionCandidates.length) {\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setMentionIdx((mentionIdxC + 1) % mentionCandidates.length)\n return\n }\n if (e.key === 'ArrowUp') {\n e.preventDefault()\n setMentionIdx((mentionIdxC - 1 + mentionCandidates.length) % mentionCandidates.length)\n return\n }\n if ((e.key === 'Enter' && !e.shiftKey) || e.key === 'Tab') {\n e.preventDefault()\n insertChip(mentionCandidates[mentionIdxC])\n return\n }\n }\n \n // 文件模式(@ + query):Enter 插入文件/Tab 钻入目录/Esc 关闭\n if (mention !== null && mention.query !== '' && fileCandidates.length) {\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setMentionIdx((mentionIdxC + 1) % fileCandidates.length)\n return\n }\n if (e.key === 'ArrowUp') {\n e.preventDefault()\n setMentionIdx((mentionIdxC - 1 + fileCandidates.length) % fileCandidates.length)\n return\n }\n const selectedItem = fileCandidates[mentionIdxC]\n if (selectedItem) {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n insertFileChip(selectedItem.path, selectedItem.isDir ? 'directory' : 'file')\n return\n }\n if (e.key === 'Tab' && selectedItem.isDir) {\n e.preventDefault()\n insertFileChip(selectedItem.path, 'directory')\n return\n }\n }\n if (e.key === 'Escape') {\n e.preventDefault()\n setMention(null)\n return\n }\n }\n \n if (e.key === 'Enter' && e.shiftKey) {\n e.preventDefault()\n execCommand('insertLineBreak')\n return\n }\n \n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n void sendMsg()\n }\n }, [mention, mentionCandidates, mentionIdxC, fileCandidates, setMentionIdx, insertChip, insertFileChip, setMention, sendMsg])\n\n return { onInputKeyDown }\n}\n","/**\n * 文件搜索 hook:防抖 + 取消过期请求 + 短缓存。\n * @module dsh-group-chat/client/hooks\n */\n\nimport { useEffect, useState } from 'react'\nimport { api } from '../lib/api.ts'\nimport type { AtToken } from '../../shared/file-mention-grammar.ts'\n\nexport interface FileCandidate {\n path: string\n isDir: boolean\n}\n\nexport interface FileSearchResult {\n fileCandidates: FileCandidate[]\n fileSearchError: string | null\n fileSearchLoading: boolean\n}\n\nconst DEBOUNCE_MS = 180\nconst CACHE_LIMIT = 20\nconst cache = new Map<string, FileCandidate[]>()\n\nfunction cacheGet(key: string): FileCandidate[] | undefined {\n const hit = cache.get(key)\n if (!hit) return undefined\n cache.delete(key)\n cache.set(key, hit)\n return hit\n}\n\nfunction cacheSet(key: string, value: FileCandidate[]): void {\n cache.delete(key)\n cache.set(key, value)\n if (cache.size > CACHE_LIMIT) {\n const oldest = cache.keys().next().value\n if (oldest !== undefined) cache.delete(oldest)\n }\n}\n\nfunction isAbort(err: unknown): boolean {\n return !!err && typeof err === 'object' && 'name' in err && (err as { name: string }).name === 'AbortError'\n}\n\n/**\n * 文件搜索:query 变化 180ms 内合并;过期 fetch 真正 abort;\n * 命中短缓存立刻出结果。离开文件模式才清空列表,避免每个按键闪「检索中」。\n */\nexport function useFileSearch(\n mention: AtToken | null,\n groupId: string | undefined,\n): FileSearchResult {\n const [fileCandidates, setFileCandidates] = useState<FileCandidate[]>([])\n const [fileSearchError, setFileSearchError] = useState<string | null>(null)\n const [fileSearchLoading, setFileSearchLoading] = useState(false)\n\n const query = mention && mention.query !== '' ? mention.query : null\n\n useEffect(() => {\n if (query === null || !groupId) {\n setFileCandidates([])\n setFileSearchError(null)\n setFileSearchLoading(false)\n return\n }\n\n const key = groupId + '\\0' + query\n const hit = cacheGet(key)\n if (hit) {\n setFileCandidates(hit)\n setFileSearchError(null)\n setFileSearchLoading(false)\n return\n }\n\n const controller = new AbortController()\n setFileSearchLoading(true)\n const timer = window.setTimeout(() => {\n void (async () => {\n try {\n const res = await api.action({\n kind: 'fileSearch',\n groupId,\n query,\n }, controller.signal) as { ok: true, candidates?: FileCandidate[] } | { ok: false, error?: string }\n\n if (controller.signal.aborted) return\n if (res.ok) {\n const next = res.candidates || []\n cacheSet(key, next)\n setFileCandidates(next)\n setFileSearchError(null)\n } else {\n setFileCandidates([])\n setFileSearchError(res.error || '文件检索失败')\n }\n } catch (err) {\n if (controller.signal.aborted || isAbort(err)) return\n setFileCandidates([])\n setFileSearchError(String(err))\n } finally {\n if (!controller.signal.aborted) setFileSearchLoading(false)\n }\n })()\n }, DEBOUNCE_MS)\n\n return () => {\n window.clearTimeout(timer)\n controller.abort()\n }\n }, [query, groupId])\n\n return { fileCandidates, fileSearchError, fileSearchLoading }\n}\n","/**\n * 提及状态 hook:封装角色/文件提及相关的派生状态计算\n * @module dsh-group-chat/client/hooks\n */\n\nimport { useMemo } from 'react'\nimport { escapeRegExp, type SnapshotRole } from '../lib/model.ts'\nimport type { AtToken } from '../../shared/file-mention-grammar.ts'\n\n/**\n * 计算角色提及候选列表\n * @param mention - 当前 @ token 状态\n * @param enabledRoles - 启用的角色列表\n * @returns 角色候选列表(仅在角色模式且 query 为空时返回)\n */\nexport function useMentionCandidates(\n mention: AtToken | null,\n enabledRoles: SnapshotRole[],\n): SnapshotRole[] {\n return useMemo(() => {\n // 角色模式:仅当 mention 存在且 query 为空时显示全部启用角色\n return mention !== null && mention.query === '' ? enabledRoles : []\n }, [mention, enabledRoles])\n}\n\n/**\n * 检测输入文本中被 @ 的角色\n * @param input - 输入文本\n * @param enabledRoles - 启用的角色列表\n * @returns 被提及的角色列表\n */\nexport function useMentionedRoles(\n input: string,\n enabledRoles: SnapshotRole[],\n): SnapshotRole[] {\n return useMemo(() => {\n return enabledRoles.filter((r) =>\n new RegExp('(^|\\\\s)@' + escapeRegExp(r.name) + '(?=\\\\s|$)').test(input)\n )\n }, [input, enabledRoles])\n}\n\n/**\n * 计算安全的候选索引(确保不越界)\n * @param candidatesLength - 候选列表长度\n * @param currentIndex - 当前索引\n * @returns 安全的索引值\n */\nexport function useSafeMentionIndex(\n candidatesLength: number,\n currentIndex: number,\n): number {\n return useMemo(() => {\n return candidatesLength ? Math.min(currentIndex, candidatesLength - 1) : 0\n }, [candidatesLength, currentIndex])\n}\n","/**\n * 主面板:三区工作台——左导航栏(搜索 + 群组→会话目录树)、中央会话流\n * (@成员 点名 + markdown 渲染 + 思考折叠)、右上下文栏(群成员角色卡 +\n * 工作区目录),右栏可收起,角色编辑走右侧滑出抽屉。\n *\n * 面板数据走 /api/group-chat/*(fetch + SSE),Host 半持有全部状态。\n * @module dsh-group-chat/client/panel\n */\n\nimport { useCallback, useEffect, useState, type ReactNode } from 'react'\nimport { Icon, P } from './lib/ui.ts'\nimport { api } from './lib/api.ts'\nimport { RoleDrawer } from './components/RoleDrawer.tsx'\nimport { NavPanel } from './components/NavPanel.tsx'\nimport { AsidePanel } from './components/AsidePanel.tsx'\nimport { ChatPanel } from './components/ChatPanel.tsx'\nimport { useGroupChatState, type ActionOk } from './hooks/useGroupChatState.ts'\nimport { useComposerEffects, useComposerInput, useComposerDraft, useMentionChip, useInputKeyboard } from './hooks/useComposer.ts'\nimport { useFileSearch } from './hooks/useFileSearch.ts'\nimport { useMentionCandidates, useMentionedRoles, useSafeMentionIndex } from './hooks/useMentionState.ts'\nimport { clearComposerDraft } from './lib/composer-draft.ts'\nimport { draftFromRole, blankDraft, groupById, roleById, sessById, type ClientSnapshot, type ModelsResponse, type SnapshotRole } from './lib/model.ts'\n\nexport function GroupChatPanel(): ReactNode {\n const state = useGroupChatState()\n const {\n snap,\n gid,\n setGid,\n sid,\n setSid,\n search,\n setSearch,\n collapsedGroups,\n setCollapsedGroups,\n renameDraft,\n setRenameDraft,\n confirmDel,\n setConfirmDel,\n confirmClear,\n setConfirmClear,\n roleDraft,\n setRoleDraft,\n models,\n setModels,\n modelsError,\n setModelsError,\n partsSel,\n setPartsSel,\n rounds,\n setRounds,\n input,\n setInput,\n err,\n setErr,\n topicDraft,\n setTopicDraft,\n mention,\n setMention,\n mentionIdx,\n setMentionIdx,\n asideOpen,\n setAsideOpen,\n navOpen,\n setNavOpen,\n atBottom,\n setAtBottom,\n inputRef,\n sendingRef,\n scrollRef,\n action,\n mutate,\n } = state\n\n // 瞬时通知(toast):key 为展示序号,同文案重复触发也会重启动画\n const [toast, setToast] = useState<{ text: string, seq: number } | null>(null)\n\n // ---- 所有 Hooks 必须在条件返回之前调用 ----\n // Composer effects\n const { onMsgsScroll } = useComposerEffects(inputRef, scrollRef, input, atBottom, snap)\n\n // 选中群组/会话解析(用于 hooks 依赖)\n let group = snap && gid ? groupById(snap, gid) : null\n if (!group && snap && snap.groups.length) group = snap.groups[0]\n let sess = snap && sid ? sessById(snap, sid) : null\n // 有效会话统一兜底(与渲染体一致):sid 未建立/未命中/跨群不匹配时取当前群组\n // 最后一个会话——必须在 busyNow 等 run 派生值之前完成,否则流式行/停止按钮\n // 在兜底视图(典型:host 重启后 lastCreated 为空、选中态从未建立)下永远失活\n if ((!sess || sess.groupId !== group?.id) && group && snap) {\n sess = group.sessionIds.length ? sessById(snap, group.sessionIds[group.sessionIds.length - 1]) : null\n }\n\n const { syncFromDOM, onInputCE, onPasteCE, onDragOverCE, onDropCE } = useComposerInput(inputRef, setInput, setMention, setMentionIdx, sess ? sess.id : null)\n useComposerDraft(sess ? sess.id : null, inputRef, setInput, setMention)\n\n const enabledRoles = group ? group.roleIds.map((id) => roleById(snap!, id)).filter((r): r is SnapshotRole => !!r && r.enabled) : []\n const participants = partsSel || enabledRoles.map((r) => r.id)\n const busyNow = !!(sess && snap && snap.run.running && snap.run.sessionId === sess.id)\n\n // 查看即清:当前选中会话即 run.finished 所指会话 → 发 ackFinish 确认已读\n // (host 幂等清除 + 广播;覆盖点击/键盘/重挂恢复/lastCreated 定位全部选中路径)\n const finishedRun = snap ? snap.run.finished : null\n useEffect(() => {\n if (finishedRun && sess && finishedRun.sessionId === sess.id) void mutate({ op: 'ackFinish' })\n }, [finishedRun, sess])\n\n // 提及状态:角色候选、文件搜索、索引安全化\n const mentionCandidates = useMentionCandidates(mention, enabledRoles)\n const { fileCandidates, fileSearchError, fileSearchLoading } = useFileSearch(\n mention,\n group?.id,\n )\n const mentionIdxC = useSafeMentionIndex(\n mentionCandidates.length || fileCandidates.length,\n mentionIdx\n )\n \n const mentionedRoles = useMentionedRoles(input, enabledRoles)\n\n const { insertChip, insertFileChip } = useMentionChip(inputRef, setMention, setMentionIdx, syncFromDOM)\n\n const sendMsg = useCallback(async (): Promise<void> => {\n if (busyNow || !sess || sendingRef.current) return\n // 空内容不可发送(按钮 disabled 之外,Enter 路径在此静默拦截)\n if (!input.trim()) return\n sendingRef.current = true\n try {\n if (!participants.length && !mentionedRoles.length) {\n setErr('请至少选择一个参与角色(或在消息中 @成员)')\n return\n }\n const parts = mentionedRoles.length ? mentionedRoles.map((r) => r.id) : participants\n const res = await action({ kind: 'send', sessionId: sess.id, text: input, participantRoleIds: parts, rounds }) as ActionOk | null\n if (res && !res.ok && res.error) setErr(res.error)\n else if (res && res.ok) {\n const el = inputRef.current\n if (el) el.innerHTML = ''\n setInput('')\n setMention(null)\n setErr('')\n setAtBottom(true)\n clearComposerDraft(sess.id)\n syncFromDOM()\n }\n } finally {\n sendingRef.current = false\n }\n }, [busyNow, sess, sendingRef, mentionedRoles, participants, action, rounds, input, inputRef, setInput, setMention, setErr, setAtBottom, syncFromDOM])\n\n const { onInputKeyDown } = useInputKeyboard(mention, mentionCandidates, mentionIdxC, setMentionIdx, insertChip, insertFileChip, fileCandidates, setMention, sendMsg)\n\n // ---- 条件性早期返回 ----\n if (!snap) {\n return (\n <div className=\"dsgc-root\">\n <div className=\"dsgc-loading\">{Icon(P.IconLoadingOutline16, 16)}加载中…</div>\n </div>\n )\n }\n\n if (!group) {\n return (\n <div className=\"dsgc-root\">\n <div className=\"dsgc-loading\">暂无群组</div>\n </div>\n )\n }\n\n const msgById: Record<string, ClientSnapshot['messages'][number]> = {}\n for (const m of snap.messages) msgById[m.id] = m\n\n const togglePart = (rid: string): void => {\n const has = participants.includes(rid)\n setPartsSel(has ? participants.filter((x) => x !== rid) : participants.concat([rid]))\n }\n\n const retrySpeak = async (messageId: string): Promise<void> => {\n if (!sess) return\n if (busyNow || (snap && snap.run.running)) {\n setToast({ text: '已有对话进行中,请先停止', seq: Date.now() })\n return\n }\n const res = await action({ kind: 'retrySpeak', sessionId: sess.id, messageId }) as ActionOk | null\n if (res && !res.ok && res.error) setToast({ text: res.error, seq: Date.now() })\n }\n\n // 清空确认:不可清空(对话进行中)走 toast 提示,不再落到输入框上方的红字\n const doClear = async (): Promise<void> => {\n if (!sess) return\n if (busyNow) {\n setToast({ text: '对话进行中,需先停止才能清空', seq: Date.now() })\n return\n }\n const res = await mutate({ op: 'clearMessages', sessionId: sess.id })\n if (res && res.ok && res.snapshot && !res.snapshot.error) setConfirmClear(false)\n else if (res && res.snapshot && res.snapshot.error) {\n setErr('')\n setToast({ text: res.snapshot.error, seq: Date.now() })\n }\n }\n\n // ---- 动作 ----\n const fetchModels = async (): Promise<void> => {\n try {\n const m = await api.action({ kind: 'models' }) as ModelsResponse\n if (m && m.ok && Array.isArray(m.providers)) {\n setModels(m)\n setModelsError(null)\n return\n }\n setModelsError(m && m.error ? String(m.error) : '响应异常')\n } catch (e) {\n setModelsError(String((e && (e as Error).message) || e))\n }\n }\n\n const openRoleEditor = async (role: SnapshotRole | null): Promise<void> => {\n setErr('')\n if (!models || modelsError) await fetchModels()\n setRoleDraft(role ? draftFromRole(role) : blankDraft())\n }\n\n const stopRun = async (): Promise<void> => {\n await action({ kind: 'stop', sessionId: sess!.id })\n }\n\n return (\n <div className=\"dsgc-root\">\n <NavPanel\n snap={snap}\n search={search}\n setSearch={setSearch}\n collapsedGroups={collapsedGroups}\n setCollapsedGroups={setCollapsedGroups}\n gid={group.id}\n sid={sess ? sess.id : sid}\n setGid={setGid}\n setSid={setSid}\n setPartsSel={setPartsSel}\n renameDraft={renameDraft}\n setRenameDraft={setRenameDraft}\n confirmDel={confirmDel}\n setConfirmDel={setConfirmDel}\n mutate={mutate}\n navOpen={navOpen}\n />\n <ChatPanel\n snap={snap}\n sess={sess}\n group={group}\n enabledRoles={enabledRoles}\n participants={participants}\n mentionedRoles={mentionedRoles}\n busyNow={busyNow}\n input={input}\n mention={mention}\n mentionCandidates={mentionCandidates}\n mentionIdxC={mentionIdxC}\n fileCandidates={fileCandidates}\n fileSearchError={fileSearchError}\n fileSearchLoading={fileSearchLoading}\n rounds={rounds}\n err={err}\n atBottom={atBottom}\n topicDraft={topicDraft}\n msgById={msgById}\n navOpen={navOpen}\n asideOpen={asideOpen}\n inputRef={inputRef}\n scrollRef={scrollRef}\n setTopicDraft={setTopicDraft}\n setConfirmClear={setConfirmClear}\n setMentionIdx={setMentionIdx}\n setRounds={setRounds}\n setNavOpen={setNavOpen}\n setAsideOpen={setAsideOpen}\n togglePart={togglePart}\n onMsgsScroll={() => {\n const isBottom = onMsgsScroll()\n if (isBottom !== undefined) setAtBottom(isBottom)\n }}\n onInputCE={onInputCE}\n onInputKeyDown={onInputKeyDown}\n onPasteCE={onPasteCE}\n onDropCE={onDropCE}\n onDragOverCE={onDragOverCE}\n insertChip={insertChip}\n insertFileChip={insertFileChip}\n sendMsg={sendMsg}\n stopRun={stopRun}\n action={action}\n mutate={mutate}\n setMention={setMention}\n onRetrySpeak={(messageId) => { void retrySpeak(messageId) }}\n />\n <AsidePanel\n snap={snap}\n group={group}\n asideOpen={asideOpen}\n mutate={mutate}\n openRoleEditor={openRoleEditor}\n />\n {sess && confirmClear\n ? (\n <P.Modal\n open\n onClose={() => { setConfirmClear(false) }}\n title=\"清空本会话的消息记录?\"\n closeLabel=\"关闭\"\n description={'会话「' + sess.name + '」的全部 ' + sess.messageIds.length + ' 条消息将被永久删除'}\n footer={(\n <>\n <P.Button variant=\"outline\" size=\"sm\" onClick={() => { setConfirmClear(false) }}>取消</P.Button>\n <P.Button variant=\"outline\" size=\"sm\" className=\"dsgc-stopbtn\" onClick={() => { void doClear() }}>清空</P.Button>\n </>\n )}\n >\n <ul className=\"dsgc-clearnotes\">\n <li>删除内容:本会话的用户消息与角色发言(含思考、工具调用记录)以及本会话结论/约束备忘,确认后立即落盘</li>\n <li>不可恢复:此操作没有回收站,也没有撤销</li>\n <li>不受影响:会话本身与主题、群成员角色、工作区目录、权限档位</li>\n </ul>\n </P.Modal>\n )\n : null}\n {toast\n ? (\n <P.Toast\n key={toast.seq}\n text={toast.text}\n icon={Icon(P.IconWarningOutline16, 16)}\n anchor={inputRef.current}\n onDone={() => { setToast(null) }}\n />\n )\n : null}\n {roleDraft\n ? (\n <RoleDrawer\n draft={roleDraft}\n set={setRoleDraft}\n groupId={group.id}\n models={models}\n modelsError={modelsError}\n onRetryModels={() => { void fetchModels() }}\n mutate={mutate}\n onCancel={() => { setRoleDraft(null) }}\n />\n )\n : null}\n </div>\n )\n}\n","/**\n * 设置页:启停开关(settings.section 插槽)。写 host 的 group-chat 设置\n * 命名空间(settings.yaml 持久化)。\n * @module dsh-group-chat/client/settings\n */\n\nimport { useEffect, useState, type ReactNode } from 'react'\nimport type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { P } from '../lib/ui.ts'\n\n/** Host 侧注册的设置命名空间 shape。 */\ninterface GroupChatSettings {\n enabled?: boolean\n}\n\nexport function GroupChatSettingsSection(props: { settingsScope: SettingsScope<GroupChatSettings> }): ReactNode {\n const scope = props.settingsScope\n const [snap, setSnap] = useState<ReturnType<SettingsScope<GroupChatSettings>['getSnapshot']> | null>(null)\n const [pending, setPending] = useState(false)\n\n useEffect(() => {\n let live = true\n const read = (): void => {\n if (!live) return\n try {\n setSnap(scope.getSnapshot())\n } catch { /* ignore */ }\n }\n read()\n const off = scope.subscribe(read)\n return () => {\n live = false\n off()\n }\n }, [])\n\n const ready = snap !== null && snap.status === 'ready'\n const writable = ready ? snap.writable !== false : false\n const enabled = ready ? (snap.value && snap.value.enabled) !== false : true\n\n const toggle = async (): Promise<void> => {\n if (!writable || pending) return\n setPending(true)\n try {\n await scope.set('enabled', !enabled)\n } catch (e) {\n console.error('[dsh-group-chat] settings write failed', e)\n } finally {\n setPending(false)\n }\n }\n\n return (\n <div className=\"dgcs-page\">\n <div className=\"dgcs-head\">\n <h3 className=\"dgcs-title\">模型群聊</h3>\n <p className=\"dgcs-desc\">多模型角色群组对话面板:每个角色绑定不同的 provider/model;群组内多会话目录树管理,群内共享对话记录与工作区目录;消息以 markdown 渲染、支持思考折叠;输入框支持 @成员 / @文件。数据持久化于 ~/.dsh/storages/group-chat/,重启 dsh web 后恢复。</p>\n </div>\n <div className=\"dgcs-card\">\n <div className=\"dgcs-cardtext\">\n <div className=\"dgcs-cardtitle\">{enabled ? '已启用' : '已停用'}</div>\n <div className=\"dgcs-cardhint\">{writable ? (enabled ? '关闭后侧边栏将不再显示「群聊」入口,进行中的对话会被中止。' : '开启后侧边栏显示「群聊」入口。') : '当前设置不可写(可能被配置文件覆盖)。'}</div>\n </div>\n <P.Switch\n checked={enabled}\n onChange={() => { void toggle() }}\n disabled={!writable || pending}\n label=\"模型群聊启停\"\n title={pending ? '正在写入…' : enabled ? '点击停用' : '点击启用'}\n />\n </div>\n </div>\n )\n}\n","/**\n * 侧边栏入口图标。\n *\n * 整行命中层携带 “newSession” 类名:任务看板等 DOM 注入式面板用\n * [class*=\"newSession\"] 识别“侧边栏导航点击”并自动收起自己,与点击\n * “新建会话”行为一致——类名不可哈希化。\n * @module dsh-group-chat/client/glyph\n */\n\nimport type { ReactNode } from 'react'\n\nexport function Glyph(props: { size?: number }): ReactNode {\n const size = (props && props.size) || 18\n return (\n <span className=\"dsgc-entryOverlay newSession\">\n <span className=\"dsgc-entryIcon\">\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n strokeWidth={1.8} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\" />\n <circle cx={9} cy={7} r={4} />\n <path d=\"M23 21v-2a4 4 0 0 0-3-3.87\" />\n <path d=\"M16 3.13a4 4 0 0 1 0 7.75\" />\n </svg>\n </span>\n </span>\n )\n}\n","/**\n * dsh-group-chat — 浏览器半(web 客户端模块)。\n *\n * 经 window.__ModuleLoader__.load 注册(由 tsdown 预设的 banner/footer 闭包\n * 工厂外壳生成);factory 返回 Cordis 客户端插件:\n * - 「模型群聊」设置页(settings.section):启停开关,写 host 的 group-chat\n * 设置命名空间(settings.yaml 持久化)\n * - 启用时挂载:侧边栏「群聊」入口(sidebar.panellist)+ 中央主面板(main)\n * - 面板数据走 /api/group-chat/*(fetch + SSE),Host 半持有全部状态\n * - DSW 原语(@deepseek-ai/dsh-client-ui-primitives,shell 静态种子模块)\n * 提供按钮/输入/开关/菜单/图标与 MarkdownText 渲染器\n *\n * 设计契约(impeccable direction contract;seed key 76db9e37,surface roll\n * 第 4/6/1 手中用户锁定 C「三区工作台」,代码先行):\n * THESIS 三区工作台;FIRST VIEWPORT 左 232px 导航 + 中央会话流 + 右 304px\n * 上下文栏(窄容器覆盖式、可收起)。完整契约见 docs/DESIGN.md。\n *\n * @module dsh-group-chat/client\n */\n\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only:拉入浏览器面的 Context 合并(ctx.settingsScope)。\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only:拉入 ctx.slots 合并(renderer 自 0.1.2 起拥有槽位注册表)。\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport { createElement as h } from 'react'\nimport { injectStyles } from './lib/styles.ts'\nimport { GroupChatPanel } from './GroupChatPanel.tsx'\nimport { GroupChatSettingsSection } from './components/GroupChatSettingsSection.tsx'\nimport { Glyph } from './components/Glyph.tsx'\n\n/** Host 侧注册的设置命名空间 shape 与命名名(与宿主半拼写同一值,两边不共享代码)。 */\ninterface GroupChatSettings {\n enabled?: boolean\n}\nconst SETTINGS_NAMESPACE = 'group-chat'\n\n/** Client plugin id. */\nexport const name = 'group-chat-client'\n\n/** Required services. */\nexport const inject = ['slots', 'settingsScope']\n\n/**\n * Shell 布局槽位的类型声明镜像(运行时由外壳的 layout/sidebar 包声明):\n * 中央主面板为 keyed 槽(按 key 挂载),侧边栏面板列表为 list 槽\n * (id + order + label)。参照 dsh-web 家族外部包的自声明模式。\n */\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface SlotMap {\n /** 中央主面板:按 key 挂载一个面板组件。 */\n 'main': { kind: 'keyed', scope: 'root', owner: Record<string, never> }\n /** 侧边栏面板列表行:图标 + 标签入口。 */\n 'sidebar.panellist': { kind: 'list', scope: 'root', owner: { size?: number } }\n }\n}\n\n/**\n * 客户端插件体:设置页常驻注册 + 启用门控挂载侧边栏入口与主面板。\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n injectStyles()\n\n const scope: SettingsScope<GroupChatSettings> = ctx.settingsScope.bind({ namespace: SETTINGS_NAMESPACE })\n\n // 设置页常驻注册(禁用时也保留入口,便于重新启用)\n ctx.slots.inject('settings.section', () =>\n ctx.slots.register(\n {\n name: 'settings.section',\n id: 'dsh-group-chat',\n order: 60,\n label: () => '模型群聊',\n inject: () => ({ settingsScope: scope }),\n },\n (props: { settingsScope: SettingsScope<GroupChatSettings> }) => h(GroupChatSettingsSection, props),\n ),\n )\n\n // 启用门控:enabled 为 false 时卸载侧边栏入口与主面板\n let uiDisposer: (() => void) | undefined\n const mountUi = (): void => {\n if (uiDisposer !== undefined) return\n const disposers: (() => void)[] = []\n try {\n disposers.push(ctx.slots.inject('main', () =>\n ctx.slots.register({ name: 'main', key: 'group-chat' }, () => h(GroupChatPanel, null))))\n disposers.push(ctx.slots.inject('sidebar.panellist', () =>\n ctx.slots.register({ name: 'sidebar.panellist', id: 'group-chat', order: 50, label: '群聊' }, (props: { size?: number }) => h(Glyph, props))))\n } catch (e) {\n console.error('[dsh-group-chat] mount failed:', e)\n }\n uiDisposer = () => {\n uiDisposer = undefined\n for (const dispose of disposers.splice(0)) dispose()\n }\n }\n const syncEnabled = (): void => {\n const snapshot = scope.getSnapshot()\n const on = snapshot.status === 'ready'\n ? (snapshot.value && snapshot.value.enabled) !== false\n : snapshot.status === 'unavailable'\n if (on) mountUi()\n else if (uiDisposer !== undefined) uiDisposer()\n }\n scope.subscribe(syncEnabled)\n syncEnabled()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASA,MAAM,SAAS;EAEf,MAAa,MAAM;GAEjB;GACA;GAGA;GACA;GACA;GAEA;GAKA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GAIA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAIA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAKA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAIA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GAEA;GAIA;GAGA;GACA;GAIA;GAEA;GACA;GAKA;GACA;GAGA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GAGA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;G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"}
1
+ {"version":3,"file":"client.js","names":["h","createElement","P","useState","useRef","P","useRef","useState","createPortal","P","useState","P","useState","useRef","useState","P","useState","P","useState","P","useState","useRef","P","P","memo","useState","useSyncExternalStore","useRef","P","useState","P","P","P","useState","useRef","useCallback","createRoot","createElement","FileTypeIcon","useCallback","useRef","useState","useMemo","useState","useCallback","P","useState","P","h"],"sources":["../src/client/lib/styles.ts","../src/client/lib/ui.ts","../src/core/status.ts","../src/client/lib/model.ts","../src/client/lib/api.ts","../src/client/components/RoleDrawer.tsx","../src/client/components/HoverTip.tsx","../src/client/components/NavPanel.tsx","../src/client/components/AsidePanel.tsx","../src/core/json.ts","../src/core/types.ts","../src/core/constraints.ts","../src/core/errors.ts","../src/client/components/Fold.tsx","../src/client/components/ThinkRow.tsx","../src/client/components/ToolRow.tsx","../src/client/components/FailCard.tsx","../src/client/components/MsgActions.tsx","../src/client/components/Bubble.tsx","../src/client/components/ConstraintList.tsx","../src/client/components/SpeakerOrb.tsx","../src/client/components/MessageFlow.tsx","../src/client/components/PermissionSelect.tsx","../src/client/components/Composer.tsx","../src/client/components/ChatPanel.tsx","../src/client/lib/composer-draft.ts","../src/client/hooks/useGroupChatState.ts","../src/shared/file-mention-grammar.ts","../src/client/utils/utils.ts","../src/client/hooks/useComposer.ts","../src/client/hooks/useFileSearch.ts","../src/client/hooks/useMentionState.ts","../src/client/GroupChatPanel.tsx","../src/client/components/GroupChatSettingsSection.tsx","../src/client/components/Glyph.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * 浏览器半样式:CSS 以内联字符串承载(刻意不迁移 CSS Modules 管线——\n * 类名需保持原样,侧栏入口的 “newSession” 类名是任务看板等 DOM 注入式\n * 面板识别“侧边栏导航点击”的跨插件标记,哈希化会破坏该约定)。\n * 工厂执行时幂等注入 <style>,loader 卸载时按 data-plugin 摘除标签。\n * @module dsh-group-chat/client/styles\n */\n\n/** 注入标签的唯一 id。 */\nconst TAG_ID = 'dsh-group-chat/styles.css'\n\nexport const CSS = [\n /* ===== 布局骨架:三区工作台;卡片只用于内容单元,导航用平铺行 ===== */\n '.dsgc-root{display:flex;height:100%;min-height:0;background:var(--dsw-alias-bg-base,transparent);color:var(--dsw-alias-label-primary,inherit);font-size:var(--dsh-content-font-size,14px);container-type:inline-size;position:relative}',\n '.dsgc-loading{padding:24px;color:var(--dsw-alias-label-tertiary,inherit);display:flex;gap:8px;align-items:center;opacity:0;animation:dsgc-loading-in .18s ease-out .15s forwards}',\n /* 首开加载态延迟 150ms 淡入:本机回路通常数毫秒内数据即达并卸载本元素,\n 快路径完全不可见(无闪现,等同移除);慢路径才出现反馈,空白面板不再是唯一信号 */\n '@keyframes dsgc-loading-in{to{opacity:1}}',\n '.dsgc-loading svg{animation:dsgc-spin 1s linear infinite}',\n '@keyframes dsgc-spin{to{transform:rotate(360deg)}}',\n /* ===== 左导航栏(可收起,收合动画与右栏同款配方) ===== */\n '.dsgc-nav{width:232px;flex:none;display:flex;flex-direction:column;gap:8px;border-right:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.2));padding:12px 10px;min-height:0;min-width:0;transition:width .28s cubic-bezier(.16,1,.3,1),opacity .18s ease,padding .28s cubic-bezier(.16,1,.3,1),border-right-width .28s cubic-bezier(.16,1,.3,1)}',\n /* 子元素经 flex 列默认 stretch 填满内容区(不写死宽度:内容区实宽 232px——\n 宿主无全局 border-box,面板为 content-box,旧版写死 212px 曾致右侧多出\n 20px 死区、左右内距失衡);收合动画期间内容随面板收缩,行内 ellipsis\n 渐进截断 + visibility 0.22s 切断,无溢出涂抹 */\n '.dsgc-nav>*{flex:none}',\n '.dsgc-nav.closed{width:0;opacity:0;padding-left:0;padding-right:0;border-right-width:0;visibility:hidden;transition:width .24s ease-in,opacity .16s ease-in,padding .24s ease-in,border-right-width .24s ease-in,visibility 0s .22s}',\n '.dsgc-search{flex:none}',\n '.dsgc-search input{font-size:13px}',\n '.dsgc-search:focus-within{border-color:var(--dsw-alias-state-business-primary,#4f6ef7)}',\n '.dsgc-tree{display:flex;flex-direction:column;gap:6px;flex:1;overflow-y:auto;min-height:0;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-grow-row{display:flex;align-items:center;gap:2px;min-width:0;border:none;background:none;border-radius:6px;padding:5px 6px;color:var(--dsw-alias-label-secondary,inherit);transition:background-color .12s,color .12s;cursor:pointer;font:inherit;text-align:left}',\n '.dsgc-grow-row:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.12));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-grow-row.on{color:var(--dsw-alias-label-primary,inherit);font-weight:600}',\n '.dsgc-twist{flex:none;width:16px;height:16px;border:none;background:none;color:inherit;cursor:pointer;padding:0;display:inline-flex;align-items:center;justify-content:center}',\n '.dsgc-twist svg{transition:transform .16s ease}',\n '.dsgc-twist.closed svg{transform:rotate(-90deg)}',\n '.dsgc-gname{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',\n '.dsgc-nodeops{display:none;gap:2px;flex:none}',\n '.dsgc-grow-row:hover .dsgc-nodeops,.dsgc-sess-row:hover .dsgc-nodeops{display:inline-flex}',\n '.dsgc-opbtn{border:none;background:none;color:var(--dsw-alias-label-tertiary,inherit);cursor:pointer;padding:2px;border-radius:4px;line-height:0;transition:background-color .12s,color .12s}',\n '.dsgc-opbtn:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-opbtn.danger{color:var(--dsw-alias-state-error-primary,#e5484d)}',\n '.dsgc-sess-list{display:flex;flex-direction:column;gap:2px;margin:4px 0 2px 4px;padding-left:12px;border-left:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.15))}',\n '.dsgc-sess-row{display:flex;align-items:center;gap:6px;min-width:0;border:none;background:none;border-radius:6px;padding:6px 8px;font-size:12.5px;line-height:1.5;color:var(--dsw-alias-label-secondary,inherit);transition:background-color .12s,color .12s;cursor:pointer;text-align:left;font-family:inherit}',\n '.dsgc-sess-row:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.12));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-sess-row.on{background:var(--dsw-alias-interactive-bg-active,rgba(128,128,128,.2));color:var(--dsw-alias-label-primary,inherit);font-weight:600}',\n '.dsgc-sess-status{flex:none;width:8px;height:8px;display:inline-flex;justify-content:center;align-items:center}',\n '.dsgc-sess-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',\n '.dsgc-addsess{border:none;background:none;color:var(--dsw-alias-label-tertiary,inherit);cursor:pointer;text-align:left;font-size:12px;line-height:1.5;padding:5px 8px;border-radius:6px;transition:background-color .12s,color .12s;font-family:inherit;display:flex;align-items:center;gap:5px;white-space:nowrap;overflow:hidden}',\n '.dsgc-addsess:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.12));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-rename{font:inherit;font-size:12.5px;min-width:0;flex:1;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-3,transparent));color:inherit;border-radius:6px;padding:1px 6px;outline:none;transition:border-color .16s}',\n '.dsgc-rename:focus{border-color:var(--dsw-alias-state-business-primary,#4f6ef7)}',\n '.dsgc-hint{font-size:12px;color:var(--dsw-alias-label-tertiary,inherit);line-height:1.5;text-wrap:balance}',\n /* ===== 中央会话区 ===== */\n '.dsgc-chat{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0;position:relative}',\n /* 接缝收合钮:钉在会话区两缘、垂直居中、各控其侧(图标方向相反的 chevron)。\n 宽模式下面板宽度过渡 → 中栏连续变宽,绝对定位的钮贴缘自动随接缝滑行(布局驱动);\n 窄模式右栏为覆盖层,钮用同曲线 right 过渡跟踪其左缘。浮层配方:实底 + border-l2 + 轻方向性软影 */\n '.dsgc-seambtn{position:absolute;top:50%;transform:translateY(-50%);z-index:14;width:24px;height:56px;display:flex;align-items:center;justify-content:center;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-alias-bg-layer-3,#fff);color:var(--dsw-alias-label-secondary,inherit);cursor:pointer;transition:background-color .12s,color .12s,border-color .12s,right .3s cubic-bezier(.16,1,.3,1)}',\n '.dsgc-seambtn:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15));color:var(--dsw-alias-label-primary,inherit);border-color:var(--dsw-alias-border-l3,rgba(128,128,128,.4))}',\n '.dsgc-seambtn.left{left:0;border-left:none;border-radius:0 8px 8px 0;box-shadow:3px 0 10px rgba(0,0,0,.07)}',\n '.dsgc-seambtn.right{right:0;border-right:none;border-radius:8px 0 0 8px;box-shadow:-3px 0 10px rgba(0,0,0,.07)}',\n '.dsgc-chathead{display:flex;flex-direction:column;gap:6px;padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.2))}',\n '.dsgc-chathead-row{display:flex;gap:10px;align-items:center;min-width:0}',\n '.dsgc-constraints{align-self:center;box-sizing:border-box;width:76%;max-width:76%;display:flex;flex-direction:column;gap:8px;min-width:0;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-alias-bg-layer-3,rgba(128,128,128,.06));border-radius:12px;animation:dsgc-fade-in .18s ease-out}',\n '.dsgc-chead{display:flex;flex-direction:column;gap:2px;min-width:0}',\n '.dsgc-ctitle{margin:0;font:inherit;font-size:12px;font-weight:600;line-height:1.5;color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-cdesc{margin:0;font-size:11.5px;line-height:1.5;color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-fold{display:grid;grid-template-rows:0fr;transition:grid-template-rows .16s ease-in}',\n '.dsgc-fold.open{grid-template-rows:1fr;transition:grid-template-rows .22s cubic-bezier(.16,1,.3,1)}',\n '.dsgc-fold-inner{min-height:0;overflow:hidden;display:flex;flex-direction:column;gap:2px;opacity:0;transition:opacity .12s ease-in}',\n '.dsgc-fold.open .dsgc-fold-inner{opacity:1;transition:opacity .18s cubic-bezier(.16,1,.3,1)}',\n '.dsgc-clip{--dsgc-clip-from:var(--dsw-alias-bg-layer-3,rgba(128,128,128,.18));position:relative;min-width:0}',\n '.dsgc-clip::before,.dsgc-clip::after{content:\"\";position:absolute;left:0;right:0;height:14px;pointer-events:none;z-index:1;opacity:0;transition:opacity .12s}',\n '.dsgc-clip::before{top:0;background:linear-gradient(to bottom,var(--dsgc-clip-from),transparent)}',\n '.dsgc-clip::after{bottom:0;background:linear-gradient(to top,var(--dsgc-clip-from),transparent)}',\n '.dsgc-clip.can-up::before,.dsgc-clip.can-down::after{opacity:1}',\n '.dsgc-clip-scroll{min-width:0;overflow-y:auto;overscroll-behavior:contain;overflow-anchor:none;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-clist{display:flex;flex-direction:column;gap:2px;min-width:0}',\n '.dsgc-constraint{display:flex;gap:8px;align-items:flex-start;min-width:0;font-size:11.5px;line-height:1.5}',\n '.dsgc-ckind{flex:none;font-weight:500}',\n '.dsgc-ckind.decided{color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-ckind.rejected{color:var(--dsw-alias-state-error-primary,#e5484d)}',\n '.dsgc-ckind.open{color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-ctext{min-width:0;color:var(--dsw-alias-label-primary,inherit);overflow-wrap:break-word}',\n '.dsgc-cmore{align-self:flex-start;border:none;background:none;padding:0;font:inherit;font-size:11.5px;line-height:1.5;color:var(--dsw-alias-label-tertiary,inherit);cursor:pointer}',\n '.dsgc-cmore:hover{color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-cmore:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,var(--dsw-alias-state-business-primary,#4f6ef7));outline-offset:1px}',\n '.dsgc-sess-title{flex:none;font-weight:600;font-size:14px;color:var(--dsw-alias-label-primary,inherit);max-width:30%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',\n '.dsgc-topic{flex:1;background:transparent;border:none;border-bottom:1px solid transparent;padding:2px;min-height:20px;color:var(--dsw-alias-label-secondary,inherit);font:inherit;outline:none;min-width:0;transition:color .12s,border-color .12s}',\n '.dsgc-topic:hover{border-bottom-color:var(--dsw-alias-border-l2,rgba(128,128,128,.3))}',\n '.dsgc-topic:focus{color:var(--dsw-alias-label-primary,inherit);border-bottom-color:var(--dsw-alias-state-business-primary,#4f6ef7)}',\n '.dsgc-topic::placeholder{color:var(--dsw-alias-label-tertiary,inherit)}',\n /* 清空按钮:破坏性操作的 hover/active 反馈——宿主 ghost hover 是低强度灰底(在本\n 面板底色上近透明、无感知),改为 danger 色文字 + 淡红底,与弹窗内 danger 确认\n 按钮同语言;特异性高于原语 .ghost:hover:not(:disabled) */\n '.dsgc-chathead .dsgc-clearbtn{transition:background-color .12s,color .12s}',\n '.dsgc-chathead .dsgc-clearbtn:hover:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#e5484d) 10%,transparent);color:var(--dsw-alias-state-error-primary,#e5484d)}',\n '.dsgc-chathead .dsgc-clearbtn:active:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#e5484d) 16%,transparent)}',\n '.dsgc-msgs{flex:1;overflow-y:auto;padding:20px 24px 16px;display:flex;flex-direction:column;gap:16px;min-height:0;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-msg{display:flex;gap:10px;align-items:flex-start;max-width:100%;animation:dsgc-msg-in .22s cubic-bezier(.16,1,.3,1)}',\n '.dsgc-msg.mine{flex-direction:row-reverse}',\n '.dsgc-avatar{width:28px;height:28px;box-sizing:border-box;border:2px solid var(--dsw-alias-border-l3,rgba(128,128,128,.4));border-radius:50%;background:var(--dsw-alias-bg-module-platform,rgba(128,128,128,.12));color:var(--dsw-alias-label-primary,inherit);display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;flex:none;margin-top:1px}',\n '.dsgc-avatar.mine{border-color:transparent;background:var(--dsw-alias-button-info-fill,#4f6ef7);color:var(--dsw-alias-label-primary-foreground,#fff)}',\n /* 执行中头像点阵光球(SpeakerOrb):inline canvas 需 block 消除基线空隙,\n 尺寸由组件内联 style 钉死为头像内容盒 24px */\n '.dsgc-avatar .dsgc-orb{display:block}',\n '.dsgc-msgbody{max-width:76%;min-width:0;display:flex;flex-direction:column;gap:5px}',\n '.dsgc-msg.mine .dsgc-msgbody{align-items:flex-end}',\n '.dsgc-msghead{display:flex;gap:6px;align-items:center;min-width:0;font-size:12px;color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-msgname{font-weight:600;color:var(--dsw-alias-label-primary,inherit);white-space:nowrap}',\n '.dsgc-msgmodel{background:var(--dsw-alias-bg-module-platform,rgba(128,128,128,.12));border-radius:999px;padding:0 7px;font-size:10.5px;font-weight:500;line-height:16px;color:var(--dsw-alias-label-secondary,inherit);white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis}',\n '.dsgc-msgtime{font-size:10.5px;color:var(--dsw-alias-label-tertiary,inherit);white-space:nowrap}',\n /* 流式「深度求索...」(对标宿主 TurnStatus「深度求索中...」签名动画):DeepSeek\n 品牌蓝渐变带扫过文字的微光——background-clip:text + background-position\n 1.8s linear 无限扫动;令牌取宿主静态品牌色 --dsw-static-deepseek-*(非主题\n 别名,回退为品牌字面值),贯穿首轮 token 前与流式全程 */\n '.dsgc-typing{background:linear-gradient(90deg,var(--dsw-static-deepseek-500,#4176e6) 0%,var(--dsw-static-deepseek-500,#4176e6) 40%,var(--dsw-static-deepseek-200,#d3e2ff) 50%,var(--dsw-static-deepseek-500,#4176e6) 60%,var(--dsw-static-deepseek-500,#4176e6) 100%);color:#0000;-webkit-text-fill-color:transparent;background-position:100% 0;background-size:250% 100%;-webkit-background-clip:text;background-clip:text;font-weight:600;animation:dsgc-typing-shimmer 1.2s linear infinite}',\n '@keyframes dsgc-typing-shimmer{to{background-position:0 0}}',\n '.dsgc-msgtext{background:var(--dsw-alias-bg-layer-3,rgba(128,128,128,.06));border:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.15));padding:10px 14px;border-radius:12px;line-height:1.6;text-align:left;color:var(--dsw-alias-label-primary,inherit);min-width:0;overflow-wrap:anywhere}',\n '.dsgc-msg.mine .dsgc-msgtext{background:var(--dsw-alias-button-info-fill,#4f6ef7);border-color:transparent;color:var(--dsw-alias-label-primary-foreground,#fff);white-space:pre-wrap;word-break:break-word}',\n '.dsgc-msgtext.live{opacity:.92}',\n '.dsgc-msg.live .dsgc-avatar{--presence-ring:color-mix(in srgb,var(--role-color,#4f6ef7) 22%,transparent);animation:dsgc-presence 1.8s ease-in-out infinite}',\n '.dsgc-think{margin:2px 0}',\n '.dsgc-think .dsgc-thinkrow{font-size:12px;color:var(--dsw-alias-label-secondary,inherit);border-radius:8px;padding:3px 8px;transition:background-color .12s}',\n '.dsgc-think .dsgc-thinkrow:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.1))}',\n '.dsgc-think .dsgc-thinksummary{color:var(--dsw-alias-label-tertiary,inherit);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:44ch;font-size:11.5px;margin-left:6px}',\n '.dsgc-think .dsgc-clip{margin:2px 0 4px;padding-left:10px;border-left:2px solid var(--dsw-alias-border-l2,rgba(128,128,128,.25))}',\n '.dsgc-think .dsgc-thinkbody{font-size:12.5px;line-height:1.7;color:var(--dsw-alias-label-secondary,inherit);white-space:pre-wrap;word-break:break-word}',\n /* 首 delta 前的「思考中」占位行:ThinkRow 同语言(思考图标 + 次要色 12px 小字)\n + 三点交错呼吸动画——深度思考模型首字节可能等数秒到数十秒,空白气泡会被\n 感知为卡死;delta 到达后被真实思考行/正文自然替换 */\n '.dsgc-pending{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-pending svg{flex:none}',\n '.dsgc-pendingdots{display:inline-flex;gap:2px;align-items:center}',\n '.dsgc-pendingdots i{width:3px;height:3px;border-radius:50%;background:currentColor;opacity:.3;animation:dsgc-dot-breathe 1.2s ease-in-out infinite}',\n '.dsgc-pendingdots i:nth-child(2){animation-delay:.2s}',\n '.dsgc-pendingdots i:nth-child(3){animation-delay:.4s}',\n '@keyframes dsgc-dot-breathe{0%,100%{opacity:.25}50%{opacity:1}}',\n '.dsgc-sysmsg{align-self:center;font-size:11.5px;color:var(--dsw-alias-label-secondary,inherit);background:var(--dsw-alias-bg-module-platform,rgba(128,128,128,.1));border-radius:999px;padding:2px 10px;text-align:center;max-width:90%;animation:dsgc-sys-in .24s ease-out}',\n /* 消息操作条:气泡外下方;角色左齐、自己右齐。占位常在,悬停显现;失败卡 always 常驻 */\n '.dsgc-msgops{display:inline-flex;align-items:center;gap:2px;margin-top:2px;min-height:24px;visibility:hidden;opacity:0;transition:opacity .12s,visibility .12s}',\n '.dsgc-msg:hover .dsgc-msgops,.dsgc-msg:focus-within .dsgc-msgops,.dsgc-msgops.always{visibility:visible;opacity:1}',\n '@media (hover:none){.dsgc-msg .dsgc-msgops{visibility:visible;opacity:1}}',\n '.dsgc-msg.mine .dsgc-msgops{justify-content:flex-end}',\n '.dsgc-msgop{border:none;background:none;color:var(--dsw-alias-label-tertiary,inherit);cursor:pointer;padding:3px 6px;border-radius:6px;display:inline-flex;align-items:center;gap:4px;font:inherit;font-size:11.5px;line-height:16px;transition:background-color .12s,color .12s}',\n '.dsgc-msgop svg{flex:none}',\n '.dsgc-msgop:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-msgop:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,var(--dsw-alias-state-business-primary,#4f6ef7));outline-offset:1px}',\n '.dsgc-msgop.done{color:var(--dsw-alias-state-success-primary,#30a46c)}',\n '.dsgc-msgop.retry{color:var(--dsw-alias-state-error-primary,#e5484d)}',\n '.dsgc-msgop.retry:hover:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#e5484d) 10%,transparent);color:var(--dsw-alias-state-error-primary,#e5484d)}',\n '.dsgc-msgop:disabled{opacity:.4;cursor:default}',\n /* 失败卡:角色消息形态,人话标题 + 可展开原文;不用左侧色条,避免 craft-floor 禁令 */\n '.dsgc-fail{background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#e5484d) 8%,var(--dsw-alias-bg-layer-3,rgba(128,128,128,.06)));border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary,#e5484d) 28%,var(--dsw-alias-border-l1,rgba(128,128,128,.15)));border-radius:12px;padding:10px 12px;display:flex;flex-direction:column;gap:6px;min-width:0;animation:dsgc-fade-in .18s ease-out}',\n '.dsgc-failhead{display:flex;align-items:flex-start;gap:8px;min-width:0}',\n '.dsgc-failicon{flex:none;width:22px;height:22px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;color:var(--dsw-alias-state-error-primary,#e5484d);background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#e5484d) 12%,transparent);margin-top:1px}',\n '.dsgc-failcopy{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}',\n '.dsgc-failtitle{font-size:13px;font-weight:600;line-height:1.4;color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-faildetail{font-size:12px;line-height:1.5;color:var(--dsw-alias-label-secondary,inherit);overflow-wrap:anywhere}',\n '.dsgc-failmore{align-self:flex-start;border:none;background:none;padding:0;font:inherit;font-size:11.5px;line-height:1.5;color:var(--dsw-alias-label-tertiary,inherit);cursor:pointer}',\n '.dsgc-failmore:hover{color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-failmore:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,var(--dsw-alias-state-business-primary,#4f6ef7));outline-offset:1px}',\n '.dsgc-fail .dsgc-clip{--dsgc-clip-from:var(--dsw-alias-bg-layer-2,rgba(128,128,128,.12));border-radius:8px}',\n '.dsgc-failraw{margin:0;font-size:11.5px;line-height:1.55;white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,transparent);color:var(--dsw-alias-label-secondary,inherit)}',\n /* ===== 工具调用行 / 确认卡片(对标思考折叠语言) ===== */\n '.dsgc-tool{margin:2px 0}',\n '.dsgc-tool .dsgc-toolrow{font-size:12px;color:var(--dsw-alias-label-secondary,inherit);border-radius:8px;padding:3px 8px;transition:background-color .12s}',\n '.dsgc-tool .dsgc-toolrow:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.1))}',\n '.dsgc-tool .dsgc-toolsummary{color:var(--dsw-alias-label-tertiary,inherit);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:40ch;font-size:11.5px;margin-left:6px}',\n '.dsgc-tool .dsgc-clip{margin:2px 0 4px;padding-left:10px;border-left:2px solid var(--dsw-alias-border-l2,rgba(128,128,128,.25))}',\n '.dsgc-tool .dsgc-toolbody{font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary,inherit);white-space:pre-wrap;word-break:break-word}',\n '.dsgc-confirm{border:1px solid var(--dsw-alias-state-business-primary,#4f6ef7);border-radius:12px;background:var(--dsw-alias-bg-layer-3,rgba(128,128,128,.06));padding:10px 12px;display:flex;flex-direction:column;gap:8px;max-width:76%;animation:dsgc-fade-in .18s ease-out}',\n '.dsgc-confirmtitle{font-size:12px;font-weight:600;color:var(--dsw-alias-label-primary,inherit);display:flex;align-items:center;gap:6px}',\n '.dsgc-confirmcmd{font-size:12px;line-height:1.6;white-space:pre-wrap;word-break:break-word;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));border-radius:8px;padding:8px 10px;background:var(--dsw-alias-bg-layer-2,transparent);color:var(--dsw-alias-label-primary,inherit);max-height:240px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-confirmops{display:flex;gap:8px;justify-content:flex-end}',\n /* 清空确认弹窗内的说明列表 */\n '.dsgc-clearnotes{margin:0;padding-left:18px;font-size:13px;line-height:1.8;color:var(--dsw-alias-label-secondary,inherit);display:flex;flex-direction:column;gap:2px}',\n '.dsgc-err{font-size:12px;color:var(--dsw-alias-state-error-primary,#e5484d);animation:dsgc-fade-in .18s ease-out}',\n '.dsgc-empty{margin:auto;display:flex;flex-direction:column;align-items:center;gap:10px;color:var(--dsw-alias-label-tertiary,inherit);text-align:center;max-width:40ch;padding:24px;animation:dsgc-fade-in .3s ease-out}',\n '.dsgc-empty svg{opacity:.5}',\n '.dsgc-empty .dsgc-emptytitle{font-size:13px;font-weight:600;color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-empty .dsgc-hint{text-wrap:balance}',\n '.dsgc-tobottom{position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);z-index:12;animation:dsgc-rise-in .18s cubic-bezier(.16,1,.3,1)}',\n /* 回到底部:实底浮动胶囊(@弹层同款浮层配方——实底 + border-l2 + shadow-lv3),不与消息内容相互透底 */\n '.dsgc-tobtn{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-alias-bg-layer-3,#fff);color:var(--dsw-alias-label-secondary,inherit);border-radius:999px;padding:5px 12px;font:inherit;font-size:12px;line-height:1.4;cursor:pointer;box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.18));transition:color .12s,border-color .12s}',\n '.dsgc-tobtn:hover{color:var(--dsw-alias-label-primary,inherit);border-color:var(--dsw-alias-border-l3,rgba(128,128,128,.4))}',\n /* ===== composer ===== */\n '.dsgc-composer{padding:12px 16px 14px;display:flex;flex-direction:column;gap:10px;position:relative}',\n /* 输入卡(对标主会话 composer 卡):22px 圆角独立卡、input-major 实底、\n elevation-soft 软影(DESIGN.md 输入面豁免——输入面遵循宿主输入面语言,\n 其余静止表面仍零阴影);chips 等配置行留卡外 */\n '.dsgc-card{background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-3,transparent));--dsw-elevation-stroke-color:var(--dsw-alias-border-l2,rgba(128,128,128,.3));box-shadow:var(--dsw-elevation-soft,0 1px 3px rgba(0,0,0,.08));border-radius:22px;padding:8px 0 0;display:flex;flex-direction:column;gap:8px;position:relative}',\n /* 输入区:非受控 contenteditable(React 不管子节点);白空间与换行规则\n 与序列化契约对齐(pre-wrap + <br>→\\n) */\n '.dsgc-edit{display:block;box-sizing:border-box;width:100%;min-height:36px;max-height:180px;overflow-y:auto;outline:none;white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;font:inherit;font-size:13px;line-height:24px;color:var(--dsw-alias-label-primary,inherit);caret-color:var(--dsw-alias-state-business-primary,#4f6ef7);scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent;position:relative;z-index:1}',\n '.dsgc-card .dsgc-edit{padding:6px 8px 0 14px}',\n /* 占位符 = 独立覆盖层(对齐主会话):不用 ::before——生成内容会把聚焦光标\n 顶到占位文字之后;覆盖层 pointer-events:none 不参与光标布局,\n 与输入区同 padding 基准(左 14 / 上 6) */\n '.dsgc-ph{position:absolute;left:14px;top:6px;max-width:calc(100% - 22px);color:var(--dsw-alias-label-tertiary,inherit);pointer-events:none;user-select:none;font-size:13px;line-height:24px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',\n /* @提及芯片(输入区内原子元素):色点 + 角色色淡底胶囊——弹层候选行同语言 */\n '.dsgc-chipin{display:inline-flex;align-items:center;gap:4px;background:color-mix(in srgb,var(--role-color,#888) 15%,transparent);border-radius:999px;padding:1px 7px 1px 5px;margin:0 1px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary,inherit);white-space:nowrap;user-select:all}',\n '.dsgc-card .dsgc-sendrow{padding:0 12px 10px}',\n /* 停止/清空按钮:实心红(Button primitive outline 变体的 hover 规则\n background:interactive-bg-hover 特异度 (0,3,0) 会盖掉 (0,1,0) 的红底,\n 悬停时按钮变透明;加 button 类型选择器提为 (0,1,1)/(0,3,1),顺序无关\n 地压过变体,hover 补回红底并经 brightness 提亮) */\n 'button.dsgc-stopbtn{background:var(--dsw-alias-state-error-primary,#e5484d);border-color:transparent;color:#fff;font-weight:600}',\n 'button.dsgc-stopbtn:hover:not(:disabled){background:var(--dsw-alias-state-error-primary,#e5484d);filter:brightness(1.08);color:#fff}',\n /* 标签固定在左;芯片在右侧独立换行,后续行与首行芯片左缘对齐(不折到「参与角色」下面)。\n 单行 24px;角色过多时随内容增高,避免固定高度把后续行溢出叠到下方输入卡上 */\n '.dsgc-parts{display:flex;align-items:flex-start;gap:6px;min-height:24px}',\n '.dsgc-partslabel{font-size:12px;line-height:24px;color:var(--dsw-alias-label-tertiary,inherit);flex:none}',\n '.dsgc-partlist{display:flex;flex-wrap:wrap;align-items:center;gap:6px;row-gap:4px;flex:1;min-width:0}',\n '.dsgc-partchip{display:inline-flex;gap:6px;align-items:center;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:transparent;color:var(--dsw-alias-label-secondary,inherit);border-radius:999px;padding:2px 10px;font-size:12px;line-height:1.5;cursor:pointer;transition:background-color .12s,color .12s,border-color .12s;font-family:inherit}',\n '.dsgc-partchip:hover{color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-partchip.on{background:var(--dsw-alias-interactive-bg-active,rgba(128,128,128,.18));color:var(--dsw-alias-label-primary,inherit);border-color:var(--dsw-alias-border-l2,rgba(128,128,128,.3))}',\n '.dsgc-partchip:disabled{opacity:.5;cursor:default}',\n '.dsgc-chipdot{width:8px;height:8px;border-radius:50%;flex:none;display:inline-block}',\n '.dsgc-sendrow{display:flex;gap:8px;align-items:center;justify-content:flex-end}',\n '.dsgc-sendrow button{white-space:nowrap}',\n /* ===== 权限档位选择器(对齐主会话 composer 左下角芯片) ===== */\n '.dsgc-permtrigger{min-width:0;max-width:220px;height:28px;color:var(--dsw-alias-label-secondary,inherit);cursor:pointer;background:transparent;border:none;border-radius:999px;outline:none;align-items:center;gap:4px;padding:0 4px 0 8px;font-size:13px;font-weight:500;line-height:20px;display:inline-flex;font-family:inherit;transition:background-color .12s,color .12s}',\n '.dsgc-permtrigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-permtrigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3,rgba(128,128,128,.4))}',\n '.dsgc-permtrigger:disabled{color:var(--dsw-alias-label-dimmed,inherit);cursor:default}',\n '.dsgc-permicon{flex:none;display:inline-flex}',\n '.dsgc-permicon svg{width:14px;height:14px}',\n '.dsgc-permlabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}',\n '.dsgc-permchevron{color:var(--dsw-alias-label-caption,inherit);flex:none;transition:transform .12s;display:inline-flex}',\n '.dsgc-permchevron.open{transform:rotate(180deg)}',\n '.dsgc-rounds{display:flex;gap:2px;align-items:center;font-size:12px;color:var(--dsw-alias-label-secondary,inherit);flex:none;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));border-radius:8px;padding:2px}',\n '.dsgc-rounds .dsgc-roundbtn{border:none;background:none;color:var(--dsw-alias-label-secondary,inherit);cursor:pointer;padding:3px;border-radius:5px;line-height:0;transition:background-color .12s,color .12s}',\n '.dsgc-rounds .dsgc-roundbtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-rounds .dsgc-roundbtn:disabled{opacity:.4;cursor:default}',\n '.dsgc-rounds .dsgc-roundnum{width:26px;text-align:center;font-variant-numeric:tabular-nums;font-weight:600;color:var(--dsw-alias-label-primary,inherit)}',\n /* hover 气泡:对齐宿主 Tooltip.module.css,portal 到 body 以躲开 container-type */\n '.dsgc-hovertip{position:fixed;z-index:100;width:max-content;max-width:50vw;padding:3px 7px;border-radius:8px;background:var(--dsw-alias-tooltip-bg,#1f1f1f);color:var(--dsw-static-neutral-bluish-00,#fff);font-size:13px;line-height:20px;white-space:pre-line;overflow-wrap:break-word;pointer-events:none;animation:dsgc-hovertip-in 150ms var(--ds-ease-in-out,ease)}',\n '.dsgc-hovertip[data-side=\"right\"]{transform:translateY(-50%)}',\n '.dsgc-hovertip[data-side=\"top\"]{transform:translate(-50%,-100%)}',\n '.dsgc-hovertip[data-side=\"bottom\"]{transform:translateX(-50%)}',\n '@keyframes dsgc-hovertip-in{from{opacity:0}}',\n /* ===== @成员 / @文件弹层 ===== */\n '.dsgc-mentionwrap{position:relative}',\n '.dsgc-mention{animation:dsgc-pop-in .16s cubic-bezier(.16,1,.3,1);position:absolute;left:0;right:0;bottom:calc(100% + 6px);background:var(--dsw-alias-bg-layer-3,#fff);border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));border-radius:10px;box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.18));max-height:220px;overflow-y:auto;padding:4px;z-index:30;display:flex;flex-direction:column;gap:2px;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-mentionitem{display:flex;align-items:center;gap:8px;border:none;background:none;color:var(--dsw-alias-label-secondary,inherit);font:inherit;font-size:12.5px;text-align:left;cursor:pointer;padding:6px 8px;border-radius:6px;transition:background-color .12s,color .12s}',\n '.dsgc-mentionitem.on,.dsgc-mentionitem:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15));color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-mentionname{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}',\n '.dsgc-mentionmodel{font-size:11px;color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-mentionhint{font-size:11px;color:var(--dsw-alias-label-tertiary,inherit);padding:2px 8px 1px}',\n '.dsgc-mention-file .dsgc-mentionitem.dsgc-hint{cursor:default;color:var(--dsw-alias-label-tertiary,inherit);justify-content:center}',\n '.dsgc-mention-file .dsgc-mentionitem.dsgc-hint:hover{background:none}',\n /* 文件检索:宿主 FileTypeIcon 分色字形 + 井位底,文件夹/文件扫一眼可分 */\n '.dsgc-fileglyph{flex:none;width:22px;height:22px;display:inline-flex;align-items:center;justify-content:center;border-radius:5px}',\n '.dsgc-fileglyph.dir{background:color-mix(in srgb,var(--dsw-static-amber-400,#e8912d) 16%,transparent)}',\n '.dsgc-fileglyph.file{background:var(--dsw-alias-bg-module-platform,rgba(128,128,128,.12))}',\n '.dsgc-filedrill{flex:none;display:inline-flex;color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-mentionitem.on .dsgc-filedrill,.dsgc-mentionitem:hover .dsgc-filedrill{color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-chipin-file{background:color-mix(in srgb,var(--dsw-static-neutral-bluish-300,rgba(128,128,128,.55)) 18%,transparent)}',\n '.dsgc-chipin-file[data-dir=\"1\"]{background:color-mix(in srgb,var(--dsw-static-amber-400,#e8912d) 18%,transparent)}',\n '.dsgc-chipglyph{flex:none;width:14px;height:14px;display:inline-flex;align-items:center;justify-content:center;overflow:hidden}',\n '.dsgc-chipglyph svg{display:block}',\n /* ===== 右上下文栏 ===== */\n '.dsgc-aside{width:304px;flex:none;display:flex;flex-direction:column;gap:10px;border-left:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.2));padding:12px;min-height:0;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent;transition:width .28s cubic-bezier(.16,1,.3,1),opacity .18s ease,padding .28s cubic-bezier(.16,1,.3,1),border-left-width .28s cubic-bezier(.16,1,.3,1)}',\n /* 子元素经 flex 列默认 stretch 填满内容区(面板为 content-box、内容区实宽\n 304px;旧版写死 280px 曾致右侧多出 24px 死区) */\n '.dsgc-aside>*{flex:none}',\n '.dsgc-aside.closed{width:0;opacity:0;padding-left:0;padding-right:0;border-left-width:0;visibility:hidden;transition:width .24s ease-in,opacity .16s ease-in,padding .24s ease-in,border-left-width .24s ease-in,visibility 0s .22s}',\n '.dsgc-sec{display:flex;flex-direction:column;gap:8px;flex:none}',\n '.dsgc-sechead{display:flex;align-items:center;gap:6px;font-weight:600;font-size:12px;color:var(--dsw-alias-label-tertiary,inherit);padding-top:2px}',\n '.dsgc-sechead .dsgc-secspacer{flex:1}',\n '.dsgc-seccount{font-weight:500;color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-roles{display:flex;flex-direction:column;gap:8px}',\n '.dsgc-role{border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-alias-bg-layer-3,transparent);border-radius:12px;padding:10px 12px;display:flex;flex-direction:column;gap:7px;transition:border-color .16s,background-color .16s;list-style:none;text-align:left;font:inherit;cursor:pointer;color:inherit}',\n '.dsgc-role:hover{border-color:var(--dsw-alias-label-dimmed,rgba(128,128,128,.5))}',\n '.dsgc-rolehead{display:flex;gap:8px;align-items:center}',\n '.dsgc-roledot{width:10px;height:10px;border-radius:50%;flex:none}',\n '.dsgc-rolename{font-weight:600;font-size:13px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-role.off .dsgc-rolename{color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-rolepersona{font-size:11.5px;color:var(--dsw-alias-label-tertiary,inherit);line-height:1.5;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;min-height:0}',\n '.dsgc-rolemeta{display:flex;align-items:center;gap:6px;min-width:0;flex:1}',\n '.dsgc-rolemodel{min-width:0;flex:0 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-module-platform,rgba(128,128,128,.12));border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-rolethink{display:inline-flex;align-items:center;flex:none;color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-roleops{display:flex;gap:2px;flex:none;margin-left:auto;opacity:0;transition:opacity .12s}',\n '.dsgc-role:hover .dsgc-roleops,.dsgc-role:focus-within .dsgc-roleops{opacity:1}',\n '.dsgc-rolemenu{display:flex;align-items:center;gap:8px}',\n /* ===== 表单与控件(角色抽屉内) ===== */\n '.dsgc-field{display:flex;flex-direction:column;gap:5px}',\n '.dsgc-field>label{font-size:12px;font-weight:500;color:var(--dsw-alias-label-secondary,inherit)}',\n '.dsgc-input,.dsgc-select,.dsgc-textarea{background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-3,transparent));border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));color:var(--dsw-alias-label-primary,inherit);font:inherit;font-size:13px;border-radius:8px;padding:6px 10px;width:100%;box-sizing:border-box;outline:none;transition:border-color .16s,background-color .16s}',\n '.dsgc-input:focus,.dsgc-select:focus,.dsgc-textarea:focus{border-color:var(--dsw-alias-state-business-primary,#4f6ef7)}',\n '.dsgc-input::placeholder,.dsgc-textarea::placeholder{color:var(--dsw-alias-label-tertiary,inherit)}',\n '.dsgc-textarea{resize:vertical;min-height:76px}',\n '.dsgc-palette{display:flex;gap:6px;flex-wrap:wrap}',\n '.dsgc-dot{width:18px;height:18px;border-radius:50%;border:2px solid transparent;cursor:pointer;padding:0;transition:transform .12s}',\n '.dsgc-dot:hover{transform:scale(1.12)}',\n '.dsgc-dot.on{border-color:var(--dsw-alias-label-primary,#fff)}',\n '.dsgc-form{display:flex;flex-direction:column;gap:12px}',\n '.dsgc-formerr{font-size:12px;color:var(--dsw-alias-state-error-primary,#e5484d);line-height:1.5}',\n '.dsgc-selhint{font-size:12px;color:var(--dsw-alias-label-tertiary,inherit);line-height:1.5;display:flex;gap:6px;align-items:center;flex-wrap:wrap}',\n /* ===== 角色编辑抽屉(右侧滑出) ===== */\n '.dsgc-drawer{position:absolute;top:0;right:0;bottom:0;width:380px;max-width:calc(100% - 40px);z-index:20;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#fff));border-left:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));box-shadow:-12px 0 32px rgba(0,0,0,.14);display:flex;flex-direction:column;animation:dsgc-drawer-in .22s cubic-bezier(.16,1,.3,1)}',\n '.dsgc-drawer.closing{animation:dsgc-drawer-out .14s ease-in forwards;pointer-events:none}',\n '@keyframes dsgc-drawer-in{from{transform:translateX(32px);opacity:0}to{transform:none;opacity:1}}',\n '@keyframes dsgc-drawer-out{to{transform:translateX(32px);opacity:0}}',\n '@keyframes dsgc-msg-in{from{opacity:0;transform:translateY(6px)}}',\n '@keyframes dsgc-sys-in{from{opacity:0;transform:scale(.96)}}',\n '@keyframes dsgc-pop-in{from{opacity:0;transform:translateY(4px)}}',\n '@keyframes dsgc-rise-in{from{opacity:0;transform:translate(-50%,6px)}}',\n '@keyframes dsgc-fade-in{from{opacity:0}}',\n '@keyframes dsgc-presence{0%,100%{box-shadow:0 0 0 0 color-mix(in srgb,var(--role-color,#4f6ef7) 0%,transparent)}50%{box-shadow:0 0 0 4px var(--presence-ring)}}',\n '.dsgc-drawerhead{display:flex;align-items:center;gap:8px;padding:14px 16px;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.2));flex:none}',\n '.dsgc-drawertitle{flex:1;font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary,inherit)}',\n '.dsgc-drawerbody{flex:1;overflow-y:auto;padding:16px;min-height:0;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-drawerfoot{display:flex;gap:8px;justify-content:flex-end;padding:12px 16px;border-top:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.2));flex:none}',\n /* ===== 文件浏览器(目录选择) ===== */\n '.dsgc-fb{border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-alias-bg-layer-2,transparent);border-radius:8px;display:flex;flex-direction:column;gap:6px;padding:8px;animation:dsgc-fade-in .2s ease-out}',\n '.dsgc-fbhead{display:flex;align-items:center;justify-content:space-between;gap:8px;min-width:0}',\n '.dsgc-fbhead button{flex:none;white-space:nowrap}',\n '.dsgc-wsrow{display:flex;gap:6px;align-items:center;min-width:0}',\n '.dsgc-wsrow .dsgc-input{width:auto;flex:1;min-width:0}',\n '.dsgc-wsrow>button{flex:none;white-space:nowrap}',\n '.dsgc-nav>button{white-space:nowrap;overflow:hidden}',\n '.dsgc-fbpath{flex:1;min-width:0;font-size:11px;color:var(--dsw-alias-label-secondary,inherit);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',\n '.dsgc-fblist{display:flex;flex-direction:column;gap:1px;max-height:220px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,rgba(128,128,128,.35)) transparent}',\n '.dsgc-fbrow{display:flex;align-items:center;gap:7px;width:100%;border:none;background:none;color:var(--dsw-alias-label-primary,inherit);font:inherit;font-size:12.5px;text-align:left;cursor:pointer;padding:3px 8px;border-radius:6px;transition:background-color .12s}',\n '.dsgc-fbrow:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15))}',\n '.dsgc-fbrow.dim{opacity:.55}',\n '.dsgc-fbrow.file{cursor:default}',\n '.dsgc-fbrow.file:hover{background:none}',\n '.dsgc-fbname{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',\n '.dsgc-fbsize{flex:none;font-size:10.5px;color:var(--dsw-alias-label-tertiary,inherit)}',\n /* ===== 键盘焦点 ===== */\n '.dsgc-partchip:focus-visible,.dsgc-mentionitem:focus-visible,.dsgc-dot:focus-visible,.dsgc-opbtn:focus-visible,.dsgc-twist:focus-visible,.dsgc-addsess:focus-visible,.dsgc-grow-row:focus-visible,.dsgc-sess-row:focus-visible,.dsgc-rename:focus-visible,.dsgc-fbrow:focus-visible,.dsgc-role:focus-visible,.dsgc-roundbtn:focus-visible,.dsgc-tobtn:focus-visible,.dsgc-seambtn:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,var(--dsw-alias-state-business-primary,#4f6ef7));outline-offset:1px}',\n /* ===== 窄容器:右栏覆盖式呈现 ===== */\n '@container (max-width: 880px){.dsgc-aside{position:absolute;top:0;right:0;bottom:0;z-index:15;width:min(304px,88%);box-shadow:-12px 0 32px rgba(0,0,0,.16);border-left:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));transition:transform .3s cubic-bezier(.16,1,.3,1),opacity .2s ease}.dsgc-aside.closed{width:min(304px,88%);padding-left:12px;padding-right:12px;border-left-width:1px;transform:translateX(calc(100% + 14px));opacity:0;transition:transform .26s ease-in,opacity .18s ease-in,visibility 0s .24s}.dsgc-seambtn.right:not(.closed){right:min(304px,88%)}}',\n '@container (max-width: 640px){.dsgc-nav{width:200px}.dsgc-msgbody{max-width:88%}.dsgc-constraints{width:88%;max-width:88%}}',\n /* ===== 侧边栏入口对齐(外壳将插槽内容包在 panelGlyph span 内,必须用后代 :has) ===== */\n '[class*=\"panelList\"]:has(.dsgc-entryOverlay){margin-top:4px}',\n '[class*=\"panelRow\"]:has(.dsgc-entryOverlay){position:relative;box-sizing:border-box;height:36px;min-height:36px;padding:0 10px;font-size:13px;transition:background-color .12s,color .12s}',\n '[class*=\"panelRow\"][class*=\"panelActive\"]:has(.dsgc-entryOverlay){font-weight:600}',\n /* 入口 hover:宿主 panelRow:hover 只给灰底、不变文字色(低强度到近无感);\n 对齐任务看板入口行——hover 灰底 + 文字/图标转 label-primary */\n '[class*=\"panelRow\"]:has(.dsgc-entryOverlay):hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.12));color:var(--dsw-alias-label-primary,inherit)}',\n /* DOM 注入式全幅视图(任务看板 data-dsh-taskboard-active / SSH data-dsh-ssh-active)\n 激活时接管中央列:外壳面板状态机未变(activePanelId 仍指向群聊),但视图已被\n 覆盖——群聊入口随之视觉复位,避免停留“激活”态误导当前所在视图。两行特异性\n 相同(0,4,1),hover 行在后,复位不吞 hover 反馈 */\n 'html[data-dsh-taskboard-active] [class*=\"panelRow\"][class*=\"panelActive\"]:has(.dsgc-entryOverlay),html[data-dsh-ssh-active] [class*=\"panelRow\"][class*=\"panelActive\"]:has(.dsgc-entryOverlay){background:transparent;color:var(--dsw-alias-label-secondary,inherit);font-weight:400}',\n 'html[data-dsh-taskboard-active] [class*=\"panelRow\"]:has(.dsgc-entryOverlay):hover,html[data-dsh-ssh-active] [class*=\"panelRow\"]:has(.dsgc-entryOverlay):hover{background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.12));color:var(--dsw-alias-label-primary,inherit)}',\n /* 收起态例外:外壳把收起栏所有面板图标统一为 primary 色(激活与否不由颜色表达),\n 复位规则不得把群聊图标调暗成 secondary;仅去掉激活底色即可 */\n 'html[data-dsh-taskboard-active] [data-sidebar-collapsed] [class*=\"panelRow\"]:has(.dsgc-entryOverlay),html[data-dsh-ssh-active] [data-sidebar-collapsed] [class*=\"panelRow\"]:has(.dsgc-entryOverlay),html[data-dsh-taskboard-active] [class*=\"collapsed\"] [class*=\"panelRow\"]:has(.dsgc-entryOverlay),html[data-dsh-ssh-active] [class*=\"collapsed\"] [class*=\"panelRow\"]:has(.dsgc-entryOverlay){color:var(--dsw-alias-label-primary,inherit)}',\n '[class*=\"panelRow\"]:has(.dsgc-entryOverlay) > [class*=\"panelTitle\"]{padding-left:24px}',\n '.dsgc-entryOverlay{position:absolute;inset:0;display:flex;align-items:center;padding:0 10px;box-sizing:border-box}',\n '.dsgc-entryIcon{flex:none;width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center}',\n '.dsgc-entryIcon svg{width:18px;height:18px;display:block}',\n '[data-sidebar-collapsed] .dsgc-entryOverlay,[class*=\"collapsed\"] .dsgc-entryOverlay{justify-content:center;padding:0}',\n '[data-sidebar-collapsed] [class*=\"panelRow\"]:has(.dsgc-entryOverlay),[class*=\"collapsed\"] [class*=\"panelRow\"]:has(.dsgc-entryOverlay){margin:0 auto}',\n '@media (prefers-reduced-motion:reduce){.dsgc-dot,.dsgc-partchip,.dsgc-mentionitem,.dsgc-grow-row,.dsgc-sess-row,.dsgc-opbtn,.dsgc-addsess,.dsgc-topic,.dsgc-role,.dsgc-rename,.dsgc-input,.dsgc-select,.dsgc-textarea,.dsgc-fbrow,.dsgc-twist svg,.dsgc-roleops,.dsgc-roundbtn,.dsgc-permtrigger,.dsgc-permchevron,.dsgc-tobtn,.dsgc-seambtn,.dsgc-aside,.dsgc-aside.closed,.dsgc-nav,.dsgc-nav.closed,.dsgc-clearbtn,.dsgc-cmore,.dsgc-msgops,.dsgc-msgop,.dsgc-failmore,.dsgc-clip::before,.dsgc-clip::after,.dsgc-fold,.dsgc-fold-inner,.dsgc-fold.open,.dsgc-fold.open .dsgc-fold-inner,[class*=\"panelRow\"]:has(.dsgc-entryOverlay){transition:none}.dsgc-dot:hover{transform:none}.dsgc-drawer,.dsgc-msg,.dsgc-sysmsg,.dsgc-mention,.dsgc-tobottom,.dsgc-err,.dsgc-empty,.dsgc-fb,.dsgc-msg.live .dsgc-avatar,.dsgc-loading svg,.dsgc-pendingdots i,.dsgc-typing,.dsgc-constraints,.dsgc-hovertip,.dsgc-fail{animation:none}.dsgc-typing{background-position:0 0;background-size:100% 100%}}',\n /* ===== 设置页(同一卡片语言) ===== */\n '.dgcs-page{display:flex;flex-direction:column;gap:14px;padding:4px 0}',\n '.dgcs-head{display:flex;flex-direction:column;gap:6px}',\n '.dgcs-title{margin:0;font-size:15px;font-weight:600;line-height:1.4;color:var(--dsw-alias-label-primary,inherit)}',\n '.dgcs-desc{margin:0;font-size:13px;line-height:1.6;color:var(--dsw-alias-label-secondary,inherit)}',\n '.dgcs-card{display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3));background:var(--dsw-alias-bg-layer-3,transparent);border-radius:12px;padding:14px 16px;transition:border-color .16s}',\n '.dgcs-cardtext{display:flex;flex-direction:column;gap:3px;min-width:0}',\n '.dgcs-cardtitle{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,inherit)}',\n '.dgcs-cardhint{font-size:12px;color:var(--dsw-alias-label-tertiary,inherit)}',\n].join('\\n')\n\n/** 工厂执行时幂等注入样式标签(loader 卸载时按 data-plugin 摘除)。 */\nexport function injectStyles(): void {\n if (typeof document === 'undefined') return\n if (document.querySelector('style[data-plugin-css=' + JSON.stringify(TAG_ID) + ']') === null) {\n const tag = document.createElement('style')\n tag.dataset.plugin = '@roaming-ai/dsh-group-chat'\n tag.dataset.pluginCss = TAG_ID\n tag.textContent = CSS\n document.head.appendChild(tag)\n }\n}\n","/**\n * 浏览器半 UI 基座:DSW 原语(shell 静态种子模块,loader 模块表 external)\n * 与动态图标 / 命令式 createElement 辅助。组件主体已 JSX 化(.tsx);此处\n * 仅保留 slot 注册回调与动态图标表需要的少量命令式辅助。\n * @module dsh-group-chat/client/ui\n */\n\nimport { createElement, type ReactNode } from 'react'\nimport * as P from '@deepseek-ai/dsh-client-ui-primitives'\n\nexport { P }\n\n/** 命令式 createElement(仅 slot 注册回调用)。 */\nexport const h = createElement as unknown as (type: unknown, props?: Record<string, unknown> | null, ...children: unknown[]) => ReactNode\n\n/** 图标组件的调用形态。 */\nexport type IconComponent = (props: Record<string, unknown>) => ReactNode\n\n/** 按名取 DSW 原语(图标表驱动)。 */\nexport function pickPrimitive(name: string): IconComponent {\n return (P as unknown as Record<string, IconComponent>)[name]\n}\n\n/** 以统一 size 包装图标组件调用(放在 JSX 子元素位)。 */\nexport function Icon(comp: unknown, size: number, extra?: Record<string, unknown>): ReactNode {\n return h(comp as never, Object.assign({ size }, extra || {}))\n}\n","/**\n * 会话状态派生(纯函数):从快照 run 派生单个会话的列表状态,\n * 语义对齐 DSH 主会话列表(StateDot 五态取四)。\n *\n * 优先级:等待确认 > 进行中 > 已完成/已出错 > 默认(无点)。\n * - ongoing:run 进行中(含用户已点停止但未停完的 stopping 窗口)\n * - warning:run_command 确认闸门挂起(仅工作区内修改档)\n * - done/error:run 结束后的「输出完毕」标记(正常/停止 → done,发言失败 → error)\n * - idle:无任何活动(不渲染状态点,对齐主 GUI idle 隐藏)\n * @module dsh-group-chat/core/status\n */\n\nimport type { Snapshot } from './types.ts'\n\n/** 会话列表状态(取值即 StateDotState 的渲染态)。 */\nexport type SessStatus = 'idle' | 'ongoing' | 'warning' | 'done' | 'error'\n\n/** 状态点悬停/读屏文案(idle 不渲染点,无文案)。 */\nexport const SESS_STATUS_LABEL: Record<SessStatus, string> = {\n idle: '',\n ongoing: '进行中',\n warning: '等待确认',\n done: '已完成',\n error: '已出错',\n}\n\n/** 派生单个会话的列表状态(run 为快照的 run 视图)。 */\nexport function sessStatus(run: Snapshot['run'], sessionId: string): SessStatus {\n if (run.running && run.sessionId === sessionId) return run.pendingConfirm ? 'warning' : 'ongoing'\n const f = run.finished\n if (f && f.sessionId === sessionId) return f.reason === 'error' ? 'error' : 'done'\n return 'idle'\n}\n","/**\n * 浏览器半共享常量与小工具(纯函数,无 React 依赖)。\n * @module dsh-group-chat/client/model\n */\n\nimport type { Snapshot } from '../../core/types.ts'\n\n/** 会话列表状态派生与文案(core 纯函数,供 NavPanel 渲染)。 */\nexport { sessStatus, SESS_STATUS_LABEL, type SessStatus } from '../../core/status.ts'\n\n/** 角色标识色调色板(与宿主半一致)。 */\nexport const PALETTE = ['#5b8def', '#22a06b', '#e8912d', '#c678dd', '#e05661', '#56b6c2', '#98c379', '#d19a66']\n\n/** Host HTTP API 前缀。 */\nexport const API_PREFIX = '/api/group-chat'\n\n/** MarkdownText 渲染文案。 */\nexport const MD_LABELS = Object.freeze({ code: { copyLabel: '复制', copiedLabel: '已复制' }, footnotes: '脚注' })\n\n/** 快照的 wire 形态(响应里带 ok 标记)。 */\nexport type ClientSnapshot = Snapshot & { ok: boolean }\n\n/** models action 的响应形态。 */\nexport interface ModelsResponse {\n ok: boolean\n providers?: { id: string, name?: string }[]\n modelsByProvider?: Record<string, { id: string, name?: string }[]>\n error?: string\n}\n\n/** efforts action 的响应形态。 */\nexport interface EffortsResponse {\n ok: boolean\n efforts?: { id: string, name: string, description?: string }[]\n defaultEffort?: string\n error?: string\n}\n\n/** 快照内的角色/会话/群组视图行。 */\nexport type SnapshotRole = Snapshot['roles'][number]\nexport type SnapshotSession = Snapshot['sessions'][number]\nexport type SnapshotGroup = Snapshot['groups'][number]\nexport type SnapshotMessage = Snapshot['messages'][number]\n\nexport function roleById(s: ClientSnapshot, id: string | null): SnapshotRole | null {\n for (const r of s.roles) if (r.id === id) return r\n return null\n}\n\nexport function sessById(s: ClientSnapshot, id: string): SnapshotSession | null {\n for (const x of s.sessions) if (x.id === id) return x\n return null\n}\n\nexport function groupById(s: ClientSnapshot, id: string): SnapshotGroup | null {\n for (const g of s.groups) if (g.id === id) return g\n return null\n}\n\nexport function escapeRegExp(v: string): string {\n return String(v).replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nexport function firstLine(text: string): string {\n const i = text.indexOf('\\n')\n return i === -1 ? text : text.slice(0, i)\n}\n\nexport function latestLine(text: string): string {\n const visible = text.trimEnd()\n const i = visible.lastIndexOf('\\n')\n return i === -1 ? visible : visible.slice(i + 1)\n}\n\nexport function fmtTime(ts: number): string {\n const delta = Math.max(0, Date.now() - ts)\n if (delta < 60000) return '刚刚'\n if (delta < 3600000) return Math.floor(delta / 60000) + ' 分钟前'\n if (delta < 86400000) return Math.floor(delta / 3600000) + ' 小时前'\n const d = new Date(ts)\n const sameYear = d.getFullYear() === new Date().getFullYear()\n const pad = (n: number): string => (n < 10 ? '0' + n : '' + n)\n return sameYear ? (d.getMonth() + 1) + '月' + d.getDate() + '日' : d.getFullYear() + '/' + (d.getMonth() + 1) + '/' + d.getDate()\n}\n\n/** 角色编辑抽屉的草稿形态(编辑与新建共用)。 */\nexport interface RoleDraft {\n id?: string\n name: string\n color: string | null\n persona: string\n provider: string\n model: string\n temperature?: number\n reasoningEffort: string\n enabled?: boolean\n thinking: boolean\n}\n\nexport function draftFromRole(role: SnapshotRole): RoleDraft {\n return { id: role.id, name: role.name, color: role.color ?? null, persona: role.persona, provider: role.provider, model: role.model, temperature: role.temperature, reasoningEffort: role.reasoningEffort || 'default', enabled: role.enabled, thinking: role.thinking === true }\n}\n\nexport function blankDraft(): RoleDraft {\n return { name: '', color: null, persona: '', provider: '', model: '', temperature: undefined, reasoningEffort: 'default', enabled: true, thinking: false }\n}\n","/**\n * 浏览器半 transport:/api/group-chat/* 同源 JSON 端点。\n * @module dsh-group-chat/client/api\n */\n\nimport { API_PREFIX } from './model.ts'\n\nasync function readJson<T>(fetchPromise: Promise<Response>): Promise<T> {\n const response = await fetchPromise\n const body = await response.json() as { error?: string }\n if (!response.ok) throw new Error(body && body.error ? body.error : '请求失败(HTTP ' + response.status + '),请稍后重试')\n return body as unknown as T\n}\n\nexport const api = {\n state: (): Promise<unknown> => readJson(fetch(API_PREFIX + '/state', { cache: 'no-store' })),\n action: (payload: Record<string, unknown>, signal?: AbortSignal): Promise<unknown> => readJson(fetch(API_PREFIX + '/action', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n signal,\n })),\n}\n","/**\n * 角色编辑抽屉(右侧滑出,不遮挡会话流阅读)。\n * @module dsh-group-chat/client/drawer\n */\n\nimport { useEffect, useRef, useState, type ReactNode } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport { api } from '../lib/api.ts'\nimport { PALETTE, type EffortsResponse, type ModelsResponse, type RoleDraft } from '../lib/model.ts'\nimport type { MutateResponse } from '../hooks/useGroupChatState.ts'\n\nexport interface RoleDrawerProps {\n draft: RoleDraft\n set: (draft: RoleDraft) => void\n /** 保存目标群组(upsertRole 落库)。 */\n groupId: string\n models: ModelsResponse | null\n modelsError: string | null\n onRetryModels: () => void\n mutate: (args: Record<string, unknown>) => Promise<unknown>\n onCancel: () => void\n}\n\nexport function RoleDrawer(props: RoleDrawerProps): ReactNode {\n const { draft, set, groupId } = props\n const models = props.models\n const providers = (models && models.providers) || []\n const modelsOf = (models && models.modelsByProvider && models.modelsByProvider[draft.provider]) || []\n const [closing, setClosing] = useState(false)\n // Esc 监听挂在空依赖上,闭包看的是首帧 closing(恒 false)——用 ref 挡住\n // 退场动画窗口内的重复触发\n const closingRef = useRef(false)\n const [formError, setFormError] = useState('')\n const [effortsInfo, setEffortsInfo] = useState<EffortsResponse | null>(null)\n const close = (): void => {\n if (closingRef.current) return\n closingRef.current = true\n setClosing(true)\n window.setTimeout(() => props.onCancel(), 140)\n }\n const onProvider = (e: { target: { value: string } }): void => {\n const p = e.target.value\n const list = (models && models.modelsByProvider && models.modelsByProvider[p]) || []\n // 换模型路线后旧推理级别失效,重置为默认\n set(Object.assign({}, draft, { provider: p, model: list.length ? list[0].id : '', reasoningEffort: 'default' }))\n }\n /** 保存(校验在本地,落库经 mutate;失败文案与原实现逐字一致)。 */\n const save = async (): Promise<void> => {\n if (!draft.name.trim()) {\n setFormError('角色名称不能为空')\n return\n }\n if (!draft.provider || !draft.model) {\n setFormError('请选择角色绑定的模型')\n return\n }\n const res = await props.mutate({ op: 'upsertRole', groupId, role: draft }) as MutateResponse | null\n if (res && res.ok && res.snapshot && !res.snapshot.error) {\n props.onCancel()\n }\n }\n useEffect(() => {\n const onKey = (e: KeyboardEvent): void => { if (e.key === 'Escape') close() }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [])\n // 推理级别选项:跟随抽屉内 provider/model 变化重新查询(Host 60s 缓存)\n useEffect(() => {\n let live = true\n setEffortsInfo(null)\n if (!draft.provider || !draft.model) return\n api.action({ kind: 'efforts', provider: draft.provider, model: draft.model }).then((res) => {\n if (!live) return\n const r = res as EffortsResponse\n if (r && r.ok) setEffortsInfo({ ok: true, efforts: r.efforts || [], defaultEffort: r.defaultEffort })\n else setEffortsInfo({ ok: false, efforts: [], defaultEffort: undefined, error: (r && r.error) || '查询失败' })\n }).catch((e: unknown) => { if (live) setEffortsInfo({ ok: false, efforts: [], defaultEffort: undefined, error: String((e && (e as Error).message) || e) }) })\n return () => { live = false }\n }, [draft.provider, draft.model])\n return (\n <div className={'dsgc-drawer' + (closing ? ' closing' : '')} role=\"dialog\" aria-modal=\"false\" aria-label={draft.id ? '编辑角色' : '添加角色'}>\n <div className=\"dsgc-drawerhead\">\n {Icon(P.IconUserOutline16, 16)}\n <span className=\"dsgc-drawertitle\">{draft.id ? '编辑角色' : '添加角色'}</span>\n <P.Button variant=\"ghost\" size=\"sm\" onClick={close} aria-label=\"关闭\">{Icon(P.IconCloseOutline16, 16)}</P.Button>\n </div>\n <div className=\"dsgc-drawerbody\">\n <div className=\"dsgc-form\">\n <div className=\"dsgc-field\">\n <label>名称</label>\n <input\n className=\"dsgc-input\"\n value={draft.name}\n autoFocus={!draft.id}\n onChange={(e) => { set(Object.assign({}, draft, { name: e.target.value })) }}\n placeholder=\"例如:产品经理\"\n />\n </div>\n <div className=\"dsgc-field\">\n <label>标识色</label>\n <div className=\"dsgc-palette\">\n {PALETTE.map((c) => (\n <button\n key={c}\n type=\"button\"\n className={'dsgc-dot' + (draft.color === c ? ' on' : '')}\n style={{ background: c }}\n onClick={() => { set(Object.assign({}, draft, { color: c })) }}\n aria-label={'选择标识色 ' + c}\n />\n ))}\n </div>\n </div>\n <div className=\"dsgc-field\">\n <label>人设 / 角色设定</label>\n <textarea\n className=\"dsgc-textarea\"\n rows={4}\n value={draft.persona}\n onChange={(e) => { set(Object.assign({}, draft, { persona: e.target.value })) }}\n placeholder=\"性格、立场、说话风格、专业背景……\"\n />\n </div>\n <div className=\"dsgc-field\">\n <label>模型提供方</label>\n {providers.length\n ? (\n <select className=\"dsgc-select\" value={draft.provider} onChange={onProvider}>\n <option value=\"\">选择提供方…</option>\n {providers.map((p) => <option key={p.id} value={p.id}>{p.name || p.id}</option>)}\n </select>\n )\n : (\n <div className=\"dsgc-selhint\">\n {(props.modelsError ? '模型目录加载失败:' + props.modelsError : '暂无可用 provider') + ' '}\n <P.Button variant=\"outline\" size=\"sm\" onClick={props.onRetryModels}>重试</P.Button>\n </div>\n )}\n </div>\n <div className=\"dsgc-field\">\n <label>模型</label>\n {modelsOf.length\n ? (\n <select\n className=\"dsgc-select\"\n value={draft.model}\n onChange={(e) => { set(Object.assign({}, draft, { model: e.target.value, reasoningEffort: 'default' })) }}\n >\n {modelsOf.map((m) => <option key={m.id} value={m.id}>{m.name || m.id}</option>)}\n </select>\n )\n : <div className=\"dsgc-selhint\">请先选择有可用模型的提供方</div>}\n </div>\n <div className=\"dsgc-field\">\n <label>温度(可选)</label>\n <input\n className=\"dsgc-input\"\n type=\"number\"\n step=\"0.1\"\n min=\"0\"\n max=\"2\"\n value={draft.temperature == null ? '' : String(draft.temperature)}\n onChange={(e) => { set(Object.assign({}, draft, { temperature: e.target.value === '' ? undefined : Number(e.target.value) })) }}\n />\n </div>\n <div className=\"dsgc-field\">\n <label>深度思考</label>\n <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>\n <P.Switch checked={draft.thinking === true} onChange={(v: boolean) => { set(Object.assign({}, draft, { thinking: v })) }} label=\"深度思考\" />\n <span className=\"dsgc-hint\">开启后角色发言前先思考(支持思考的模型)</span>\n </div>\n </div>\n {draft.thinking === true\n ? (\n <div className=\"dsgc-field\">\n <label>推理级别</label>\n {effortsInfo === null\n ? <div className=\"dsgc-selhint\">查询推理级别…</div>\n : !effortsInfo.ok\n ? <div className=\"dsgc-selhint\">推理级别查询失败:{effortsInfo.error}(若刚更新插件,请重启 dsh web 使 host 半生效)</div>\n : (effortsInfo.efforts || []).length\n ? (\n <select\n className=\"dsgc-select\"\n value={draft.reasoningEffort && draft.reasoningEffort !== 'default' ? draft.reasoningEffort : 'default'}\n onChange={(e) => { set(Object.assign({}, draft, { reasoningEffort: e.target.value })) }}\n title=\"取自当前模型设置中的推理选项;默认 = 使用该模型的默认推理级别\"\n >\n <option value=\"default\">\n 默认{effortsInfo.defaultEffort ? '(当前默认:' + ((effortsInfo.efforts || []).find((x) => x.id === effortsInfo.defaultEffort) || { name: '' }).name + ')' : ''}\n </option>\n {(effortsInfo.efforts || []).map((e) => <option key={e.id} value={e.id} title={e.description || ''}>{e.name || e.id}</option>)}\n </select>\n )\n : <div className=\"dsgc-selhint\">当前模型未提供推理等级,将使用默认</div>}\n </div>\n )\n : null}\n {formError ? <div className=\"dsgc-formerr\">{formError}</div> : null}\n </div>\n </div>\n <div className=\"dsgc-drawerfoot\">\n <P.Button variant=\"outline\" onClick={close}>取消</P.Button>\n <P.Button variant=\"primary\" onClick={() => { void save() }}>{draft.id ? '保存' : '添加'}</P.Button>\n </div>\n </div>\n )\n}\n","/**\n * 对齐宿主 Tooltip 的 hover 气泡:portal 到 document.body,躲开\n * `.dsgc-root` 的 container-type 把 position:fixed 按容器定位。\n * @module dsh-group-chat/client/components\n */\n\nimport { useEffect, useLayoutEffect, useRef, useState, type ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\n\nexport type HoverTipSide = 'top' | 'right'\n\ninterface HoverTipProps {\n label: string\n side?: HoverTipSide\n delayMs?: number\n maxWidth?: number\n className?: string\n children: ReactNode\n}\n\ninterface AnchorBox {\n x: number\n top: number\n bottom: number\n}\n\n/**\n * @param props.label 气泡正文(pre-line)\n * @param props.side 默认 right(对齐侧栏会话行);composer 轮数用 top\n * @param props.delayMs hover 延迟,默认 500;键盘 focus 立即出\n */\nexport function HoverTip(props: HoverTipProps): ReactNode {\n const { label, side = 'right', delayMs = 500, maxWidth, className, children } = props\n const anchorRef = useRef<HTMLDivElement>(null)\n const bubbleRef = useRef<HTMLSpanElement>(null)\n const showTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n const hover = useRef(false)\n const [pos, setPos] = useState<AnchorBox | null>(null)\n const [placement, setPlacement] = useState<'top' | 'bottom' | 'right'>(side)\n\n const cancel = (): void => {\n if (showTimer.current === null) return\n clearTimeout(showTimer.current)\n showTimer.current = null\n }\n const show = (): void => {\n const el = anchorRef.current\n if (!el || !label) return\n const r = el.getBoundingClientRect()\n setPlacement(side)\n setPos({\n x: side === 'right' ? r.right + 10 : r.left + r.width / 2,\n top: r.top,\n bottom: r.bottom,\n })\n }\n const hideIfIdle = (): void => {\n if (!hover.current && !(anchorRef.current && anchorRef.current.contains(document.activeElement))) setPos(null)\n }\n\n useEffect(() => cancel, [])\n useLayoutEffect(() => {\n if (!pos) return\n const fit = (): void => {\n const el = bubbleRef.current\n if (!el) return\n el.style.left = pos.x + 'px'\n const r = el.getBoundingClientRect()\n let dx = 0\n if (r.right > window.innerWidth - 12) dx = window.innerWidth - 12 - r.right\n if (r.left + dx < 12) dx = 12 - r.left\n el.style.left = pos.x + dx + 'px'\n if (side === 'right') return\n const fitsBelow = pos.bottom + 8 + r.height <= window.innerHeight - 12\n const fitsAbove = pos.top - 8 - r.height >= 12\n if (placement === 'bottom' && !fitsBelow && fitsAbove) setPlacement('top')\n if (placement === 'top' && !fitsAbove && fitsBelow) setPlacement('bottom')\n }\n fit()\n window.addEventListener('resize', fit)\n return () => { window.removeEventListener('resize', fit) }\n }, [pos, placement, label, side])\n\n const y = pos === null\n ? 0\n : placement === 'right'\n ? pos.top + (pos.bottom - pos.top) / 2\n : placement === 'top'\n ? pos.top - 8\n : pos.bottom + 8\n\n return (\n <>\n <div\n ref={anchorRef}\n className={className}\n onMouseEnter={() => {\n hover.current = true\n cancel()\n if (delayMs <= 0) { show(); return }\n showTimer.current = setTimeout(() => { showTimer.current = null; show() }, delayMs)\n }}\n onMouseLeave={() => {\n hover.current = false\n cancel()\n hideIfIdle()\n }}\n onFocus={() => { cancel(); show() }}\n onBlur={(e) => {\n const next = e.relatedTarget as Node | null\n if (next && anchorRef.current && anchorRef.current.contains(next)) return\n cancel()\n hideIfIdle()\n }}\n >\n {children}\n </div>\n {pos\n ? createPortal(\n <span\n ref={bubbleRef}\n className=\"dsgc-hovertip\"\n data-side={placement}\n role=\"tooltip\"\n style={{ left: pos.x, top: y, ...(maxWidth ? { maxWidth } : {}) }}\n >\n {label}\n </span>,\n document.body,\n )\n : null}\n </>\n )\n}\n","/**\n * 左侧导航栏组件(群组 → 会话目录树;群组行与会话行共用重命名/删除三件套)。\n * @module dsh-group-chat/client/components\n */\n\nimport type { ReactNode, KeyboardEvent as ReactKeyboardEvent } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport { HoverTip } from './HoverTip.tsx'\nimport { groupById, sessById, sessStatus, SESS_STATUS_LABEL, type ClientSnapshot } from '../lib/model.ts'\n\n/** 目录树节点编辑态形状(群组/会话共用)。 */\ntype NodeEdit = { kind: 'group' | 'session', id: string, value: string }\n\ninterface NavPanelProps {\n snap: ClientSnapshot\n search: string\n setSearch: (val: string) => void\n collapsedGroups: Set<string>\n setCollapsedGroups: (fn: (prev: Set<string>) => Set<string>) => void\n gid: string | null\n sid: string | null\n setGid: (val: string) => void\n setSid: (val: string) => void\n setPartsSel: (val: string[] | null) => void\n renameDraft: NodeEdit | null\n setRenameDraft: (val: NodeEdit | null) => void\n confirmDel: { kind: 'group' | 'session', id: string } | null\n setConfirmDel: (val: { kind: 'group' | 'session', id: string } | null) => void\n mutate: (args: Record<string, unknown>) => Promise<unknown>\n navOpen: boolean\n}\n\n/** 内联重命名输入(群组行/会话行同款)。 */\nfunction RenameField(props: { draft: NodeEdit, set: (d: NodeEdit | null) => void, commit: () => void, keyDown: (e: ReactKeyboardEvent<HTMLInputElement>) => void }): ReactNode {\n const { draft, set, commit, keyDown } = props\n return (\n <input\n className=\"dsgc-rename\"\n value={draft.value}\n autoFocus\n onChange={(e) => { set({ kind: draft.kind, id: draft.id, value: e.target.value }) }}\n onBlur={() => { commit() }}\n onKeyDown={keyDown}\n onClick={(e) => { e.stopPropagation() }}\n />\n )\n}\n\n/** 行尾操作钮:重命名 + 两次点击确认删除(群组行/会话行同款)。 */\nfunction NodeOps(props: { renameLabel: string, deleteLabel: string, deleteTitle: string, danger: boolean, onRename: () => void, onDelete: () => void }): ReactNode {\n const { renameLabel, deleteLabel, deleteTitle, danger, onRename, onDelete } = props\n return (\n <span className=\"dsgc-nodeops\">\n <button\n className=\"dsgc-opbtn\"\n title={renameLabel}\n aria-label={renameLabel}\n onClick={(e) => { e.stopPropagation(); onRename() }}\n >\n {Icon(P.IconEditOutline16, 14)}\n </button>\n <button\n className={'dsgc-opbtn' + (danger ? ' danger' : '')}\n title={deleteTitle}\n aria-label={deleteLabel}\n onClick={(e) => { e.stopPropagation(); onDelete() }}\n >\n {Icon(P.IconTrashOutline16, 14)}\n </button>\n </span>\n )\n}\n\nexport function NavPanel(props: NavPanelProps): ReactNode {\n const { snap, search, setSearch, collapsedGroups, setCollapsedGroups, gid, sid, setGid, setSid, setPartsSel, renameDraft, setRenameDraft, confirmDel, setConfirmDel, mutate, navOpen } = props\n\n const commitRename = async (): Promise<void> => {\n if (!renameDraft) return\n const d = renameDraft\n setRenameDraft(null)\n const value = String(d.value || '').trim()\n if (!value) return\n if (d.kind === 'group') await mutate({ op: 'renameGroup', groupId: d.id, name: value })\n else await mutate({ op: 'renameSession', sessionId: d.id, name: value })\n }\n\n const renameKeyDown = (e: ReactKeyboardEvent<HTMLInputElement>): void => {\n if (e.key === 'Enter') {\n e.preventDefault()\n void commitRename()\n } else if (e.key === 'Escape') {\n e.preventDefault()\n setRenameDraft(null)\n }\n }\n\n const doDelete = async (): Promise<void> => {\n if (!confirmDel) return\n const d = confirmDel\n setConfirmDel(null)\n if (d.kind === 'group') await mutate({ op: 'deleteGroup', groupId: d.id })\n else await mutate({ op: 'deleteSession', sessionId: d.id })\n }\n\n // 选中即清编辑态(四连调用收敛为一处)\n const clearEdits = (): void => {\n setPartsSel(null)\n setConfirmDel(null)\n setRenameDraft(null)\n }\n const pickGroup = (id: string): void => {\n setGid(id)\n clearEdits()\n }\n const pickSession = (gidToSet: string, sidToSet: string): void => {\n setGid(gidToSet)\n setSid(sidToSet)\n clearEdits()\n }\n\n const q = search.trim().toLowerCase()\n const groupMatches = (g: ClientSnapshot['groups'][number]): { show: boolean, filterSessions: boolean } => {\n if (!q) return { show: true, filterSessions: false }\n if (g.name.toLowerCase().includes(q)) return { show: true, filterSessions: false }\n const hitSessions = g.sessionIds.map((id) => sessById(snap, id)).filter((s) => s && s.name.toLowerCase().includes(q))\n return { show: hitSessions.length > 0, filterSessions: true }\n }\n\n const group = gid ? groupById(snap, gid) : null\n const selected = sid ? sessById(snap, sid) : null\n\n const treeNodes: ReactNode[] = []\n for (const g of snap.groups) {\n const match = groupMatches(g)\n if (!match.show) continue\n const expanded = q ? true : !collapsedGroups.has(g.id)\n const isRenameGroup = renameDraft && renameDraft.kind === 'group' && renameDraft.id === g.id\n const isConfirmGroup = confirmDel && confirmDel.kind === 'group' && confirmDel.id === g.id\n const groupChildren: ReactNode[] = []\n\n if (expanded) {\n for (const sessionId of g.sessionIds) {\n const s = sessById(snap, sessionId)\n if (!s) continue\n if (match.filterSessions && !s.name.toLowerCase().includes(q)) continue\n const isActive = selected && s.id === selected.id && g.id === group?.id\n const isRenameSess = renameDraft && renameDraft.kind === 'session' && renameDraft.id === s.id\n const isConfirm = confirmDel && confirmDel.kind === 'session' && confirmDel.id === s.id\n // 会话状态(对齐主 GUI StateDot:idle 不渲染点)\n const st = sessStatus(snap.run, s.id)\n\n groupChildren.push(\n <div\n key={s.id}\n className={'dsgc-sess-row' + (isActive ? ' on' : '')}\n role=\"button\"\n tabIndex={0}\n onClick={() => { pickSession(g.id, s.id) }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n pickSession(g.id, s.id)\n }\n }}\n >\n {/* 固定宽度状态槽(对齐主 GUI:槽恒在、点按状态渲染——行间文案对齐) */}\n <span className=\"dsgc-sess-status\">\n {st !== 'idle'\n ? (\n <span role=\"img\" title={SESS_STATUS_LABEL[st]} aria-label={SESS_STATUS_LABEL[st]}>\n <P.StateDot state={st} size={8} />\n </span>\n )\n : null}\n </span>\n {isRenameSess\n ? <RenameField draft={renameDraft!} set={setRenameDraft} commit={() => { void commitRename() }} keyDown={renameKeyDown} />\n : (\n <HoverTip label={s.name} side=\"right\" delayMs={500} className=\"dsgc-sess-name\">\n {s.name}\n </HoverTip>\n )}\n <NodeOps\n renameLabel=\"重命名会话\"\n deleteLabel=\"删除会话\"\n deleteTitle={isConfirm ? '再次点击确认删除' : '删除会话'}\n danger={!!isConfirm}\n onRename={() => { setRenameDraft({ kind: 'session', id: s.id, value: s.name }) }}\n onDelete={() => {\n if (isConfirm) void doDelete()\n else setConfirmDel({ kind: 'session', id: s.id })\n }}\n />\n </div>,\n )\n }\n\n groupChildren.push(\n <button key=\"__add\" className=\"dsgc-addsess\" onClick={() => { void mutate({ op: 'createSession', groupId: g.id }) }}>\n {Icon(P.IconPlusOutline16, 14)}新会话\n </button>,\n )\n }\n\n treeNodes.push(\n <div key={g.id} className=\"dsgc-gnode\">\n <div\n className={'dsgc-grow-row' + (g.id === group?.id ? ' on' : '')}\n role=\"button\"\n tabIndex={0}\n onClick={() => { pickGroup(g.id) }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n pickGroup(g.id)\n }\n }}\n >\n <button\n className={'dsgc-twist' + (expanded ? '' : ' closed')}\n title={expanded ? '收起' : '展开'}\n aria-label={expanded ? '收起' : '展开'}\n onClick={(e) => {\n e.stopPropagation()\n setCollapsedGroups((prev) => {\n const next = new Set(prev)\n if (next.has(g.id)) next.delete(g.id)\n else next.add(g.id)\n return next\n })\n }}\n >\n {Icon(P.IconChevronDownOutline14, 14)}\n </button>\n {isRenameGroup\n ? <RenameField draft={renameDraft!} set={setRenameDraft} commit={() => { void commitRename() }} keyDown={renameKeyDown} />\n : <span className=\"dsgc-gname\">{g.name}</span>}\n <NodeOps\n renameLabel=\"重命名群组\"\n deleteLabel=\"删除群组\"\n deleteTitle={isConfirmGroup ? '再次点击确认删除' : '删除群组'}\n danger={!!isConfirmGroup}\n onRename={() => { setRenameDraft({ kind: 'group', id: g.id, value: g.name }) }}\n onDelete={() => {\n if (isConfirmGroup) void doDelete()\n else setConfirmDel({ kind: 'group', id: g.id })\n }}\n />\n </div>\n {expanded ? <div className=\"dsgc-sess-list\">{groupChildren}</div> : null}\n </div>,\n )\n }\n\n return (\n <div className={'dsgc-nav' + (navOpen ? '' : ' closed')} aria-hidden={navOpen ? undefined : 'true'}>\n <P.Input\n icon={Icon(P.IconSearchOutline16, 16)}\n className=\"dsgc-search\"\n placeholder=\"搜索群组与会话…\"\n value={search}\n onChange={(e: { target: { value: string } }) => setSearch(e.target.value)}\n />\n {treeNodes.length\n ? <div className=\"dsgc-tree\">{treeNodes}</div>\n : <div className=\"dsgc-hint\">{q ? '没有匹配「' + search.trim() + '」的群组或会话' : '暂无群组'}</div>}\n <P.Button variant=\"outline\" onClick={() => { void mutate({ op: 'createGroup' }) }}>\n {Icon(P.IconPlusOutline16, 16)}新建群组\n </P.Button>\n </div>\n )\n}\n","/**\n * 右侧成员与工作区栏组件。工作区目录编辑态(草稿、文件浏览器)为栏内自有状态。\n * @module dsh-group-chat/client/components\n */\n\nimport { useState, type ReactNode } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport { api } from '../lib/api.ts'\nimport { roleById, type ClientSnapshot, type SnapshotRole } from '../lib/model.ts'\nimport type { BrowseResult } from '../../core/types.ts'\n\ninterface AsidePanelProps {\n snap: ClientSnapshot\n group: ClientSnapshot['groups'][number]\n asideOpen: boolean\n mutate: (args: Record<string, unknown>) => Promise<unknown>\n openRoleEditor: (role: SnapshotRole | null) => void\n}\n\n/** 文件浏览器态(栏内自有)。 */\ninterface FileBrowserState {\n open: boolean\n loading: boolean\n list: BrowseResult | null\n error: string\n}\n\nexport function AsidePanel(props: AsidePanelProps): ReactNode {\n const { snap, group, asideOpen, mutate, openRoleEditor } = props\n const [wsDraft, setWsDraft] = useState<string | null>(null)\n const [fileBrowser, setFileBrowser] = useState<FileBrowserState | null>(null)\n\n const commitWsDir = (): void => {\n if (wsDraft !== null && group && wsDraft !== (group.workspaceDir || '')) {\n void mutate({ op: 'setWorkspaceDir', groupId: group.id, path: wsDraft })\n }\n setWsDraft(null)\n }\n\n const openBrowser = async (path: string | undefined): Promise<void> => {\n setFileBrowser({ open: true, loading: true, list: null, error: '' })\n try {\n const res = await api.action({ kind: 'browse', path: path || '' }) as BrowseResult\n if (res && res.ok) setFileBrowser({ open: true, loading: false, list: res, error: '' })\n else setFileBrowser({ open: true, loading: false, list: null, error: (res && res.error) || '浏览失败' })\n } catch (e) {\n setFileBrowser({ open: true, loading: false, list: null, error: String((e && (e as Error).message) || e) })\n }\n }\n\n const selectCurrentDir = (): void => {\n if (!fileBrowser || !fileBrowser.list || !group) return\n const path = fileBrowser.list.path!\n void mutate({ op: 'setWorkspaceDir', groupId: group.id, path })\n setWsDraft(null)\n setFileBrowser(null)\n }\n\n return (\n <div className={'dsgc-aside' + (asideOpen ? '' : ' closed')} aria-hidden={asideOpen ? undefined : 'true'}>\n <div className=\"dsgc-sec\">\n <div className=\"dsgc-sechead\">\n 群成员\n <span className=\"dsgc-secspacer\" />\n <span className=\"dsgc-seccount\">{group.roleIds.length ? group.roleIds.length + ' 个' : ''}</span>\n <P.Button variant=\"ghost\" size=\"sm\" onClick={() => { openRoleEditor(null) }} aria-label=\"添加角色\">\n {Icon(P.IconPlusOutline16, 14)}添加\n </P.Button>\n </div>\n {group.roleIds.length\n ? (\n <div className=\"dsgc-roles\">\n {group.roleIds.map((rid) => {\n const r = roleById(snap, rid)\n if (!r) return null\n return (\n <div\n key={r.id}\n className={'dsgc-role' + (r.enabled ? '' : ' off')}\n role=\"button\"\n tabIndex={0}\n onClick={() => { openRoleEditor(r) }}\n onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); openRoleEditor(r) } }}\n title=\"点击编辑角色\"\n >\n <div className=\"dsgc-rolehead\">\n <span className=\"dsgc-roledot\" style={{ background: r.color || '#888' }} />\n <span className=\"dsgc-rolename\">{r.name}</span>\n <P.Tooltip label={r.enabled ? '停用该角色' : '启用该角色'} side=\"top\" delayMs={300}>\n <span\n onClick={(e) => { e.stopPropagation() }}\n onKeyDown={(e) => { e.stopPropagation() }}\n style={{ display: 'inline-flex', flex: 'none' }}\n >\n <P.Switch\n checked={r.enabled}\n onChange={() => { void mutate({ op: 'setRoleEnabled', roleId: r.id, enabled: !r.enabled }) }}\n label={r.enabled ? '停用该角色' : '启用该角色'}\n aria-label={(r.enabled ? '停用' : '启用') + '角色 ' + r.name}\n />\n </span>\n </P.Tooltip>\n </div>\n {r.persona ? <div className=\"dsgc-rolepersona\" title={r.persona}>{r.persona}</div> : null}\n <div className=\"dsgc-rolemenu\">\n <span className=\"dsgc-rolemeta\">\n <span\n className=\"dsgc-rolemodel\"\n title={r.provider + ' / ' + r.model + (r.thinking ? ' · 深度思考' + (r.reasoningEffort && r.reasoningEffort !== 'default' ? '(' + r.reasoningEffort + ')' : '') : '')}\n >\n {r.provider} / {r.model}\n </span>\n {r.thinking\n ? <span className=\"dsgc-rolethink\" title=\"深度思考\">{Icon(P.IconThinkOutline14, 14)}</span>\n : null}\n </span>\n <span className=\"dsgc-roleops\">\n <button\n className=\"dsgc-opbtn\"\n title=\"编辑角色\"\n aria-label=\"编辑角色\"\n onClick={(e) => { e.stopPropagation(); openRoleEditor(r) }}\n >\n {Icon(P.IconEditOutline16, 14)}\n </button>\n <button\n className=\"dsgc-opbtn danger\"\n title=\"移除角色\"\n aria-label=\"移除角色\"\n onClick={(e) => { e.stopPropagation(); void mutate({ op: 'deleteRole', roleId: r.id }) }}\n >\n {Icon(P.IconTrashOutline16, 14)}\n </button>\n </span>\n </div>\n </div>\n )\n })}\n </div>\n )\n : <div className=\"dsgc-hint\">还没有角色。每个角色可绑定不同的 provider/model,在群内以独立身份发言。</div>}\n </div>\n <div className=\"dsgc-sec\">\n <div className=\"dsgc-sechead\">工作区目录</div>\n <div className=\"dsgc-field\">\n <div className=\"dsgc-wsrow\">\n <input\n className=\"dsgc-input\"\n value={wsDraft === null ? (group.workspaceDir || '') : wsDraft}\n placeholder=\"~/docs 或 /abs/dir\"\n onChange={(e) => { setWsDraft(e.target.value) }}\n onBlur={commitWsDir}\n onKeyDown={(e) => { if (e.key === 'Enter') (e.target as HTMLInputElement).blur() }}\n />\n <P.Button variant=\"outline\" size=\"sm\" onClick={() => { void openBrowser(wsDraft === null ? group.workspaceDir : wsDraft) }}>\n {Icon(P.IconFolderOpenOutline16, 14)}浏览\n </P.Button>\n </div>\n <div className=\"dsgc-hint\">发送时读取目录内文本文件,注入本群全体角色上下文;角色也可用工具主动查看</div>\n {group.workspaceDir === '~' || group.workspaceDir === '/'\n ? <div className=\"dsgc-err\">工作区指向整个主目录/根目录:角色的只读工具将可读取该范围下的所有文件,请谨慎</div>\n : null}\n </div>\n {fileBrowser && fileBrowser.open\n ? (\n <div className=\"dsgc-fb\">\n <div className=\"dsgc-fbhead\">\n <span className=\"dsgc-fbpath\" title={fileBrowser.list ? fileBrowser.list.path : ''}>\n {fileBrowser.loading ? '读取中…' : (fileBrowser.list ? fileBrowser.list.path : '')}\n </span>\n <span style={{ display: 'flex', gap: 4, alignItems: 'center' }}>\n <P.Button variant=\"primary\" size=\"sm\" disabled={!fileBrowser.list} onClick={selectCurrentDir}>选定此目录</P.Button>\n {fileBrowser.list\n ? <P.Button variant=\"outline\" size=\"sm\" title=\"上一级\" aria-label=\"上一级\" onClick={() => { void openBrowser(fileBrowser.list!.parent) }}>{Icon(P.IconChevronUpOutline14, 14)}</P.Button>\n : null}\n {fileBrowser.list\n ? <P.Button variant=\"outline\" size=\"sm\" title=\"主目录\" aria-label=\"主目录\" onClick={() => { void openBrowser(fileBrowser.list!.home) }}>{Icon(P.IconFolderClose16, 14)}</P.Button>\n : null}\n <P.Button variant=\"ghost\" size=\"sm\" onClick={() => { setFileBrowser(null) }} aria-label=\"关闭浏览器\">{Icon(P.IconCloseOutline16, 14)}</P.Button>\n </span>\n </div>\n {fileBrowser.error ? <div className=\"dsgc-err\">{fileBrowser.error}</div> : null}\n {fileBrowser.list\n ? (\n <div className=\"dsgc-fblist\">\n {(fileBrowser.list.entries || []).length\n ? (fileBrowser.list.entries || []).map((e) => e.type === 'directory'\n ? (\n <button\n key={e.path}\n type=\"button\"\n className={'dsgc-fbrow' + (e.hidden ? ' dim' : '') + ' dir'}\n onClick={() => { void openBrowser(e.path) }}\n >\n {Icon(e.hidden ? P.IconFolderClose16 : P.IconFolderOpenOutline16, 14)}\n <span className=\"dsgc-fbname\">{e.name}/</span>\n </button>\n )\n : (\n <div key={e.path} className=\"dsgc-fbrow dim file\">\n <span className=\"dsgc-fbname\">{e.name}</span>\n {e.size !== undefined ? <span className=\"dsgc-fbsize\">{(P as unknown as { fileSizeText: (n: number) => string }).fileSizeText(e.size)}</span> : null}\n </div>\n ))\n : <div className=\"dsgc-hint\">空目录</div>}\n </div>\n )\n : null}\n </div>\n )\n : null}\n </div>\n </div>\n )\n}\n","/**\n * 记录 → 落盘 JSON 的纯序列化(core 层;可选字段无则省略)。\n * @module dsh-group-chat/core/json\n */\n\nimport type { MessageRecord, RoleRecord } from './types.ts'\n\n/** 消息 → 落盘 JSON(可选字段无则省略;兼容保留 error)。 */\nexport function messageJson(m: Partial<MessageRecord> | undefined): Record<string, unknown> | null {\n if (!m || typeof m.id !== 'string') return null\n const o: Record<string, unknown> = { id: m.id, speaker: m.speaker, text: String(m.text || ''), ts: typeof m.ts === 'number' ? m.ts : Date.now(), seq: typeof m.seq === 'number' ? m.seq : 0 }\n if (m.model !== undefined) o.model = m.model\n if (m.reasoning !== undefined) o.reasoning = m.reasoning\n if (m.reasoningFull !== undefined) o.reasoningFull = m.reasoningFull\n if (m.thinkingSummary !== undefined) o.thinkingSummary = m.thinkingSummary\n if (m.error !== undefined) o.error = m.error\n if (typeof m.failedRoleId === 'string' && m.failedRoleId) o.failedRoleId = m.failedRoleId\n if (Array.isArray(m.toolCalls) && m.toolCalls.length > 0) o.toolCalls = m.toolCalls\n return o\n}\n\n/** 角色 → 落盘 JSON(groupId 由目录归属,不再写入)。 */\nexport function roleJson(r: Partial<RoleRecord>): Record<string, unknown> {\n const o: Record<string, unknown> = { id: r.id, name: String(r.name || '成员'), persona: String(r.persona || ''), provider: String(r.provider || ''), model: String(r.model || ''), enabled: r.enabled !== false, thinking: r.thinking === true }\n if (r.color) o.color = r.color\n if (typeof r.temperature === 'number' && !Number.isNaN(r.temperature)) o.temperature = r.temperature\n if (typeof r.reasoningEffort === 'string' && r.reasoningEffort && r.reasoningEffort !== 'default') o.reasoningEffort = r.reasoningEffort\n return o\n}\n\n/**\n * 宽容 JSON 提取(模型输出/供应商错误原文的统一解析入口):\n * 取首个 { 至末个 } 的片段解析,仅接受普通对象;失败返回 null。\n * 代码围栏剥离由调用方按需先行处理(供应商错误原文不剥)。\n */\nexport function looseJson(raw: string): Record<string, unknown> | null {\n const start = raw.indexOf('{')\n const end = raw.lastIndexOf('}')\n if (start < 0 || end <= start) return null\n try {\n const parsed = JSON.parse(raw.slice(start, end + 1)) as unknown\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed as Record<string, unknown> : null\n } catch {\n return null\n }\n}\n","/**\n * 群聊数据模型(core 层,无 cordis 依赖)。\n * 数据模型:Group 1..N Session,消息挂在会话上;角色与工作区目录挂在群组上。\n * @module dsh-group-chat/core/types\n */\n\n/**\n * 群组权限档位(对齐主会话 /permission 三档):\n * - view_only 仅可查看:只保留 read_file/list_dir,run_command 从 schema 剔除\n * - workspace_write 工作区内修改:run_command 可用,每条命令逐条确认\n * - full_access 完全权限:run_command 免确认直接执行\n */\nexport type PermissionTier = 'view_only' | 'workspace_write' | 'full_access'\n\n/** 全部合法档位(展示顺序)。 */\nexport const PERMISSION_TIERS: readonly PermissionTier[] = ['view_only', 'workspace_write', 'full_access']\n\n/** 档位安全化:合法字符串原样,其余 undefined。 */\nexport function asPermissionTier(value: unknown): PermissionTier | undefined {\n return typeof value === 'string' && (PERMISSION_TIERS as readonly string[]).includes(value) ? value as PermissionTier : undefined\n}\n\n/**\n * ledger 行档位归一(v2→v3 兼容):显式 permissionTier 优先;\n * 缺失时按旧布尔迁移——allowCommands=true → workspace_write(今日语义即\n * 「可执行命令但逐条确认」),false/无字段 → view_only。\n */\nexport function migrateTier(permissionTier: unknown, allowCommands: unknown): PermissionTier {\n const tier = asPermissionTier(permissionTier)\n if (tier !== undefined) return tier\n return allowCommands === true ? 'workspace_write' : 'view_only'\n}\n\n/** 群组:角色与工作区目录的宿主。 */\nexport interface GroupRecord {\n id: string\n name: string\n workspaceDir: string\n permissionTier: PermissionTier\n roleIds: string[]\n sessionIds: string[]\n}\n\n/** 会话约束条目类型(窗口外结论/约束备忘)。 */\nexport type ConstraintKind = 'decided' | 'rejected' | 'open'\n\n/** 全部合法约束类型。 */\nexport const CONSTRAINT_KINDS: readonly ConstraintKind[] = ['decided', 'rejected', 'open']\n\n/** 合法 kind 原样,其余 undefined。 */\nexport function asConstraintKind(value: unknown): ConstraintKind | undefined {\n return typeof value === 'string' && (CONSTRAINT_KINDS as readonly string[]).includes(value) ? value as ConstraintKind : undefined\n}\n\n/** 一条无主结论/约束(已定 / 否决 / 未决)。 */\nexport interface SessionConstraint {\n kind: ConstraintKind\n text: string\n}\n\n/** 会话:消息挂在会话上。 */\nexport interface SessionRecord {\n id: string\n groupId: string\n name: string\n topic: string\n /** 名称已被手动编辑:自动命名永久跳过(隐式固定)。 */\n namePinned?: boolean\n /** 主题已被手动编辑:自动整理永久跳过(隐式固定)。 */\n topicPinned?: boolean\n /** 窗口外结论/约束备忘;空则省略。 */\n constraints?: SessionConstraint[]\n /** 已折入备忘的最大消息 seq;0/缺省 = 尚未折过。 */\n constraintsUpToSeq?: number\n messageIds: string[]\n createdAt: number\n}\n\n/** 角色:绑定 provider/model 的群成员身份。 */\nexport interface RoleRecord {\n id: string\n groupId: string\n name: string\n color?: string\n persona: string\n provider: string\n model: string\n temperature?: number\n reasoningEffort?: string\n enabled: boolean\n thinking: boolean\n}\n\n/** 一次工具调用的落盘/快照形态(TOOLS.md §3.3 回注契约的展示面)。 */\nexport interface ToolCallRecord {\n tool: string\n args: unknown\n status: string\n output: string\n durationMs?: number\n}\n\n/** 消息(user / system / 角色发言共用一条记录)。 */\nexport interface MessageRecord {\n id: string\n sessionId: string\n seq: number\n speaker: string\n text: string\n reasoning?: string\n reasoningFull?: string\n thinkingSummary?: string\n model?: string\n error?: boolean\n /** 发言失败时的角色 id;刷新后仍可对该条点重试。角色消息 speaker 即角色 id,此字段冗余兼容旧系统错误行。 */\n failedRoleId?: string\n toolCalls?: ToolCallRecord[]\n ts: number\n}\n\n/** run_command 确认闸门的待确认载荷。 */\nexport interface PendingConfirm {\n toolCallId: string\n tool: string\n args: { command?: string } & Record<string, unknown>\n}\n\n/** 最近一次创建的群组/会话,供客户端定位选中项。 */\nexport interface LastCreated {\n kind: 'group' | 'session'\n groupId: string\n sessionId: string\n}\n\n/** run 结束后的「输出完毕」标记(内存态不持久化,重启即清;reason 取 ok/error)。 */\nexport interface RunFinished {\n sessionId: string\n reason: 'ok' | 'error'\n}\n\n/** 对话进行时状态(run)。 */\nexport interface RunState {\n running: boolean\n sessionId: string | null\n currentRoleId: string | null\n partial: string\n partialReasoning: string\n stopping: boolean\n queue: string[]\n pendingConfirm: PendingConfirm | null\n confirmSignal: { resolve: (allowed: boolean) => void } | null\n /** 正在执行的 run_command 的中止句柄(stop/dispose 时 abort,执行器 kill 进程)。 */\n commandAbort: AbortController | null\n /** 最近一次 run 的结束标记:会话列表「已完成/已出错」状态的数据源。 */\n finished: RunFinished | null\n /** 原地重试时被覆盖的失败消息 id;普通 send 为 null。 */\n replaceMessageId: string | null\n}\n\n/** 角色发言的引擎产物。 */\nexport interface SpeakResult {\n text: string\n reasoning: string | undefined\n toolCalls: ToolCallRecord[]\n}\n\n/** 工具执行结果(host 内部约定)。 */\nexport interface ToolExecution {\n status: 'ok' | 'error' | 'denied'\n output: string\n args: Record<string, unknown>\n durationMs: number\n}\n\n/** 模型目录(models action 的缓存载荷)。 */\nexport interface ModelCatalog {\n at: number\n providers: { id: string, name: string }[]\n modelsByProvider: Record<string, { id: string, name?: string }[]>\n}\n\n/** 推理级别选项(efforts action 的载荷)。 */\nexport interface EffortOptions {\n efforts: { id: string, name: string, description?: string }[]\n defaultEffort: string | undefined\n error?: string\n}\n\n/** 目录浏览结果(browse action 的载荷)。 */\nexport interface BrowseResult {\n ok: boolean\n path?: string\n home?: string\n parent?: string\n entries?: { name: string, type: string, path: string, size?: number, hidden: boolean }[]\n error?: string\n}\n\n/** 群工作区 @ 文件检索结果(fileSearch action 的载荷)。 */\nexport interface FileSearchResult {\n ok: boolean\n candidates?: { path: string, isDir: boolean }[]\n error?: string\n}\n\n/** 快照内的会话行(wire 形态:不含 hydrate 用的固定标记与折入水位)。 */\nexport type SnapshotSession = Omit<SessionRecord, 'namePinned' | 'topicPinned' | 'constraintsUpToSeq'>\n/** 快照内的消息行(wire 形态:思考全文与摘要不外发)。 */\nexport type SnapshotMessage = Omit<MessageRecord, 'reasoningFull' | 'thinkingSummary'>\n\n/** 发到客户端的全量快照(wire 形态;各表行由领域记录派生,字段增删由编译器同步)。 */\nexport interface Snapshot {\n revision: number\n run: Omit<RunState, 'stopping' | 'queue' | 'confirmSignal' | 'commandAbort'>\n lastCreated: LastCreated | null\n groups: GroupRecord[]\n sessions: SnapshotSession[]\n roles: RoleRecord[]\n messages: SnapshotMessage[]\n error?: string\n}\n\n/** mutate 动作的参数形态(判别联合:按 op 收窄各分支字段;wire 上字段可缺,消费方各自守卫)。 */\nexport type MutateArgs =\n | { op: 'createGroup', name?: string }\n | { op: 'renameGroup', groupId: string, name?: string }\n | { op: 'deleteGroup', groupId: string }\n | { op: 'createSession', groupId: string, name?: string }\n | { op: 'renameSession', sessionId: string, name?: string }\n | { op: 'deleteSession', sessionId: string }\n | { op: 'setTopic', sessionId: string, topic?: string }\n | { op: 'upsertRole', groupId: string, role?: Partial<RoleRecord> }\n | { op: 'deleteRole', roleId: string }\n | { op: 'setRoleEnabled', roleId: string, enabled?: boolean }\n | { op: 'setWorkspaceDir', groupId: string, path?: string }\n | { op: 'setPermissionTier', groupId: string, tier?: string }\n | { op: 'ackFinish' }\n | { op: 'clearMessages', sessionId: string }\n\n/** send 动作的参数形态。 */\nexport interface SendArgs {\n sessionId: string\n text?: string\n participantRoleIds?: string[]\n rounds?: number\n}\n\n/** 可选数值参数安全化:数字则原样,否则 undefined。 */\nexport function asNumber(value: unknown): number | undefined {\n return typeof value === 'number' && !Number.isNaN(value) ? value : undefined\n}\n\n/** 可选字符串参数安全化:非 default 的非空字符串则原样,否则 undefined。 */\nexport function asEffort(value: unknown): string | undefined {\n return typeof value === 'string' && value && value !== 'default' ? value : undefined\n}\n","/**\n * 会话约束备忘纯逻辑:滑动 40 条窗口、挤出集、压行、临时原文、解析与截断。\n * @module dsh-group-chat/core/constraints\n */\n\nimport { looseJson } from './json.ts'\nimport { TRANSCRIPT_TOOL_SUMMARY } from './tools.ts'\nimport { asConstraintKind, type MessageRecord, type SessionConstraint, type SessionRecord } from './types.ts'\n\n/** 当场原文窗口(含系统行)。 */\nexport const WINDOW_SIZE = 40\n/** 折叠失败时临时原文条数上限。 */\nexport const TEMP_MAX_MESSAGES = 20\n/** 折叠失败时临时原文总长上限。 */\nexport const TEMP_MAX_CHARS = 16000\n/** 单轮折叠最多消耗的挤出条数(含系统行;超出留待下一轮)。 */\nexport const FOLD_MAX_MESSAGES = 40\n/** 单轮折叠输入总长上限(格式化后)。 */\nexport const FOLD_MAX_CHARS = 16000\n/** 备忘条数上限。 */\nexport const CONSTRAINT_MAX_ITEMS = 12\n/** 备忘总长上限(条目前缀+正文)。 */\nexport const CONSTRAINT_MAX_CHARS = 1200\n/** 单条备忘正文上限。 */\nexport const CONSTRAINT_ITEM_MAX_CHARS = 160\n\nexport const KIND_LABEL: Record<SessionConstraint['kind'], string> = {\n decided: '已定',\n rejected: '否决',\n open: '未决',\n}\n\n/** 已折入水位(缺省 0)。 */\nexport function constraintsWatermark(sess: SessionRecord): number {\n return typeof sess.constraintsUpToSeq === 'number' && sess.constraintsUpToSeq > 0 ? sess.constraintsUpToSeq : 0\n}\n\n/** 重试:只取失败卡之前的时间线;untilId 不在列表则原样。 */\nexport function prefixIds(ids: string[], untilId?: string): string[] {\n if (!untilId) return ids\n const i = ids.indexOf(untilId)\n return i >= 0 ? ids.slice(0, i) : ids\n}\n\n/**\n * 新挤出:seq > 水位 且不在最近 40 条。只扫窗口外前缀(旧→新)。\n * untilId:重试时把窗口截到该消息之前,不带上后面已经发生的发言。\n */\nexport function squeezedMessages(\n messages: Map<string, MessageRecord>,\n sess: SessionRecord,\n untilId?: string,\n): MessageRecord[] {\n const ids = prefixIds(sess.messageIds, untilId)\n if (ids.length <= WINDOW_SIZE) return []\n const end = ids.length - WINDOW_SIZE\n const upTo = constraintsWatermark(sess)\n const last = messages.get(ids[end - 1])\n if (last && last.seq <= upTo) return []\n const out: MessageRecord[] = []\n for (let i = 0; i < end; i++) {\n const m = messages.get(ids[i])\n if (!m || m.seq <= upTo) continue\n out.push(m)\n }\n return out\n}\n\n/** 说话人展示名(折叠输入 / transcript 共用)。 */\nexport function speakerLabel(speaker: string, roleName?: string): string {\n if (speaker === 'user') return '用户'\n if (speaker === 'system') return '系统'\n return roleName || '成员'\n}\n\n/** 单条消息压成 transcript 行(正文 8k + 工具一行摘要)。 */\nexport function formatTranscriptLine(m: MessageRecord, name: string): string {\n let text = m.text || ''\n if (text.length > 8000) text = text.slice(0, 8000) + '…(已截断)'\n let line = '【' + name + '】' + text\n if (Array.isArray(m.toolCalls)) {\n for (const c of m.toolCalls) {\n if (!c || typeof c.tool !== 'string') continue\n let brief = ''\n try {\n brief = JSON.stringify(c.args) || ''\n } catch {\n brief = ''\n }\n if (brief.length > 60) brief = brief.slice(0, 60) + '…'\n const st = c.status === 'ok' ? '成功' : c.status === 'denied' ? '用户拒绝' : '失败'\n let ob = String(c.output || '')\n if (ob.length > TRANSCRIPT_TOOL_SUMMARY) ob = ob.slice(0, TRANSCRIPT_TOOL_SUMMARY) + '…'\n line += '\\n [工具] ' + c.tool + ' ' + brief + ' → ' + st + (ob ? '(' + ob.replace(/\\s+/g, ' ') + ')' : '')\n }\n }\n return line\n}\n\n/**\n * 单轮折叠消耗前缀:从最旧挤出起,最多 40 条 / 16k;系统行与失败卡计入消耗但不进模型。\n * 水位只能推到 consumed 的 max seq,剩余留待下一轮。\n */\nexport function takeFoldBatch(squeezed: MessageRecord[], nameOf: (m: MessageRecord) => string): {\n consumed: MessageRecord[]\n lines: string[]\n hasUser: boolean\n allSystem: boolean\n} {\n const consumed: MessageRecord[] = []\n const lines: string[] = []\n let hasUser = false\n let chars = 0\n for (const m of squeezed) {\n if (m.speaker === 'system' || m.error) {\n consumed.push(m)\n if (consumed.length >= FOLD_MAX_MESSAGES) break\n continue\n }\n const line = formatTranscriptLine(m, nameOf(m))\n const extra = line.length + (lines.length ? 2 : 0)\n if (lines.length > 0 && chars + extra > FOLD_MAX_CHARS) break\n if (m.speaker === 'user') hasUser = true\n lines.push(line)\n chars += extra\n consumed.push(m)\n if (consumed.length >= FOLD_MAX_MESSAGES) break\n }\n return { consumed, lines, hasUser, allSystem: lines.length === 0 }\n}\n\n/**\n * 未折入的挤出原文(失败缓冲):只格式化最近 20 条,再按 16k 从最旧往下丢。\n */\nexport function tempTranscript(squeezed: MessageRecord[], nameOf: (m: MessageRecord) => string): string {\n if (!squeezed.length) return ''\n const usable = squeezed.filter((m) => m.speaker !== 'system' && !m.error)\n if (!usable.length) return ''\n const batch = usable.length > TEMP_MAX_MESSAGES ? usable.slice(-TEMP_MAX_MESSAGES) : usable\n const lines = batch.map((m) => formatTranscriptLine(m, nameOf(m)))\n let start = 0\n let total = lines[0] ? lines[0].length : 0\n for (let i = 1; i < lines.length; i++) {\n total += 2 + lines[i].length\n }\n while (start < lines.length - 1 && total > TEMP_MAX_CHARS) {\n total -= lines[start].length + 2\n start++\n }\n let block = lines.slice(start).join('\\n\\n')\n if (block.length > TEMP_MAX_CHARS) block = block.slice(0, TEMP_MAX_CHARS) + '…(已截断)'\n return block\n}\n\n/** 水位 = 本批挤出的 max(seq);空批为 0。 */\nexport function squeezedMaxSeq(squeezed: MessageRecord[]): number {\n let max = 0\n for (const m of squeezed) if (m.seq > max) max = m.seq\n return max\n}\n\n/** hydrate / 模型输出:非法 kind 丢条目;空 text 丢;条数与总长截断。 */\nexport function sanitizeConstraints(raw: unknown): SessionConstraint[] {\n if (!Array.isArray(raw)) return []\n const out: SessionConstraint[] = []\n let total = 0\n for (const item of raw) {\n if (out.length >= CONSTRAINT_MAX_ITEMS) break\n if (!item || typeof item !== 'object') continue\n const kind = asConstraintKind((item as { kind?: unknown }).kind)\n const text = typeof (item as { text?: unknown }).text === 'string' ? (item as { text: string }).text.trim() : ''\n if (!kind || !text) continue\n const clipped = text.length > CONSTRAINT_ITEM_MAX_CHARS ? text.slice(0, CONSTRAINT_ITEM_MAX_CHARS) + '…' : text\n const cost = KIND_LABEL[kind].length + clipped.length\n if (total + cost > CONSTRAINT_MAX_CHARS) break\n out.push({ kind, text: clipped })\n total += cost\n }\n return out\n}\n\n/**\n * 解析折叠模型输出。null = 解析失败(水位不推);[] = 无新结论(水位推、备忘不动)。\n */\nexport function parseConstraints(raw: string): SessionConstraint[] | null {\n const o = looseJson(raw.replace(/```(?:json)?/g, ''))\n if (o === null) return null\n if (!Object.prototype.hasOwnProperty.call(o, 'constraints')) return null\n if (!Array.isArray(o.constraints)) return null\n return sanitizeConstraints(o.constraints)\n}\n\n/** 本批无用户消息时,新的已定/否决降为未决。 */\nexport function downgradeWithoutUser(list: SessionConstraint[], hasUser: boolean): SessionConstraint[] {\n if (hasUser) return list\n return list.map((c) => c.kind === 'open' ? c : { kind: 'open', text: c.text })\n}\n\n/** system 提示词「已确认约束」块;空则空串。 */\nexport function constraintBlock(list: SessionConstraint[] | undefined): string {\n if (!list || !list.length) return ''\n const lines = list.map((c) => '- ' + KIND_LABEL[c.kind] + ':' + c.text)\n return '\\n# 已确认约束\\n' + lines.join('\\n')\n}\n","/**\n * 角色发言失败:供应商原文 → 人话标题/原因(core 纯函数,无 React)。\n * 原始 JSON 仍落盘在消息 text 里,UI 默认只展示短因,展开才看原文。\n * @module dsh-group-chat/core/errors\n */\n\nexport interface SpeakFailureView {\n /** 一行标题,例如「额度已用尽」。 */\n title: string\n /** 可选短因:重置时间、HTTP 状态等。 */\n detail?: string\n /** 复制/排障用的供应商原文(已剥「模型输出异常终止: 」前缀)。 */\n raw: string\n}\n\nconst PREFIX = '模型输出异常终止: '\nconst LEGACY_ROLE = /^角色「([^」]+)」发言失败[::]\\s*/\n\n/** 剥旧系统胶囊与引擎包装前缀,保留供应商原文。 */\nexport function unwrapSpeakFailure(raw: string): string {\n const text = String(raw || '').trim()\n const legacy = parseLegacyRoleFailure(text)\n const body = legacy ? legacy.rest : text\n return body.startsWith(PREFIX) ? body.slice(PREFIX.length).trim() : body\n}\n\n/** 旧系统胶囊文案:角色「名」发言失败:原文。对不上则 null。 */\nexport function parseLegacyRoleFailure(text: string): { roleName: string, rest: string } | null {\n const m = LEGACY_ROLE.exec(String(text || ''))\n if (!m) return null\n return { roleName: m[1], rest: String(text).slice(m[0].length) }\n}\n\nexport interface RoleRef {\n id: string\n name: string\n provider?: string\n model?: string\n}\n\nexport interface FailedMessageRef {\n speaker: string\n text: string\n error?: boolean\n failedRoleId?: string\n}\n\n/** 发言失败卡:error 标记,或旧系统胶囊文案。 */\nexport function isSpeakFailure(m: FailedMessageRef): boolean {\n return !!m.error || !!parseLegacyRoleFailure(m.text)\n}\n\n/** 失败回合对应角色:failedRoleId / speaker / 旧文案里的角色名(恰好一名才命中)。 */\nexport function resolveFailedRole<T extends RoleRef>(m: FailedMessageRef, roles: T[]): T | null {\n const byId = (id: string | undefined): T | null => {\n if (!id) return null\n for (const r of roles) if (r.id === id) return r\n return null\n }\n const direct = byId(m.failedRoleId) || (m.speaker !== 'user' && m.speaker !== 'system' ? byId(m.speaker) : null)\n if (direct) return direct\n const parsed = parseLegacyRoleFailure(m.text)\n if (!parsed) return null\n const hits = roles.filter((r) => r.name === parsed.roleName)\n return hits.length === 1 ? hits[0] : null\n}\n\n/**\n * 把旧系统失败行挂到对应角色(恰好一名命中才迁)。\n * 返回是否改写了记录。\n */\nexport function repairFailedMessage(\n m: { speaker: string, text: string, error?: boolean, failedRoleId?: string, model?: string },\n roles: RoleRef[],\n): boolean {\n if (!isSpeakFailure(m)) return false\n let changed = false\n if (!m.error) {\n m.error = true\n changed = true\n }\n if (!m.failedRoleId && m.speaker !== 'user' && m.speaker !== 'system') {\n m.failedRoleId = m.speaker\n changed = true\n }\n if (!m.failedRoleId && m.speaker === 'system') {\n const parsed = parseLegacyRoleFailure(m.text)\n if (parsed) {\n const hits = roles.filter((r) => r.name === parsed.roleName)\n if (hits.length === 1) {\n const role = hits[0]\n m.speaker = role.id\n m.failedRoleId = role.id\n m.text = unwrapSpeakFailure(parsed.rest)\n if (!m.model && (role.provider || role.model)) m.model = (role.provider || '') + ' / ' + (role.model || '')\n changed = true\n }\n }\n } else if (m.failedRoleId && m.speaker === 'system') {\n m.speaker = m.failedRoleId\n changed = true\n }\n // 对不上角色时保留「角色「名」发言失败」原文,客户端才能再解析。\n if (m.failedRoleId || (m.speaker !== 'user' && m.speaker !== 'system')) {\n const unwrapped = unwrapSpeakFailure(m.text)\n if (unwrapped !== m.text) {\n m.text = unwrapped\n changed = true\n }\n }\n return changed\n}\n\nimport { looseJson } from './json.ts'\n\nfunction httpStatus(text: string): number | null {\n const m = text.match(/\\b([1-5]\\d{2})\\b/)\n if (!m) return null\n const n = Number(m[1])\n return n >= 100 && n <= 599 ? n : null\n}\n\nfunction resetHint(message: string): string | undefined {\n const m = message.match(/reset at ([^.]+\\S)/i) || message.match(/将在\\s*([^\\s。]+)\\s*重置/)\n return m ? '将在 ' + m[1] + ' 重置' : undefined\n}\n\n/**\n * 把供应商错误压成可扫描的标题 + 短因。\n * 未知形态回退为「发言失败」,原文仍可展开。\n */\nexport function classifySpeakFailure(raw: string): SpeakFailureView {\n const source = unwrapSpeakFailure(raw)\n const blob = looseJson(source)\n const code = blob && typeof blob.code === 'string' ? blob.code : ''\n const type = blob && typeof blob.type === 'string' ? blob.type : ''\n const message = blob && typeof blob.message === 'string' ? blob.message : source\n const status = httpStatus(source)\n const joined = (code + ' ' + type + ' ' + message + ' ' + source).toLowerCase()\n\n if (/quota|accountquotaexceeded|exceeded the .*quota|额度|配额/.test(joined) || code === 'AccountQuotaExceeded') {\n return { title: '额度已用尽', detail: resetHint(message), raw: source }\n }\n if (status === 429 || /too.?many.?requests|rate.?limit|限流/.test(joined) || type === 'TooManyRequests') {\n return { title: '请求过于频繁', detail: '稍后再试,或降低并发', raw: source }\n }\n if (status === 401 || status === 403 || /unauthorized|forbidden|invalid.?api.?key|鉴权|未授权/.test(joined)) {\n return { title: '模型鉴权失败', detail: '检查该角色绑定的提供方密钥', raw: source }\n }\n if (status === 404 || /model.?not.?found|unknown.?model|模型不存在/.test(joined)) {\n return { title: '模型不可用', detail: '该角色绑定的模型可能已下线', raw: source }\n }\n if (/timeout|timed out|etimedout|超时/.test(joined)) {\n return { title: '模型响应超时', raw: source }\n }\n if (/network|econnreset|econnrefused|enotfound|fetch failed|网络/.test(joined)) {\n return { title: '网络异常', detail: '检查网络后重试', raw: source }\n }\n if (status !== null && status >= 500) {\n return { title: '模型服务暂时不可用', detail: 'HTTP ' + status, raw: source }\n }\n if (status !== null) {\n return { title: '发言失败', detail: 'HTTP ' + status, raw: source }\n }\n return { title: '发言失败', raw: source }\n}\n\n/** 失败卡默认复制内容:标题 + 短因 + 原文。 */\nexport function formatSpeakFailureCopy(view: SpeakFailureView): string {\n const lines = [view.title]\n if (view.detail) lines.push(view.detail)\n if (view.raw && view.raw !== view.title) lines.push(view.raw)\n return lines.join('\\n')\n}\n","/**\n * 会话内折叠:高度 0fr→1fr + 溢出滚动遮罩。思考 / 工具 / 失败原文 / 结论备忘共用。\n * @module dsh-group-chat/client/components\n */\n\nimport { useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from 'react'\n\ninterface FoldProps {\n open: boolean\n children: ReactNode\n className?: string\n}\n\nexport function Fold(props: FoldProps): ReactNode {\n const { open, children, className } = props\n return (\n <div className={'dsgc-fold' + (open ? ' open' : '') + (className ? ' ' + className : '')}>\n <div className=\"dsgc-fold-inner\">{children}</div>\n </div>\n )\n}\n\ninterface ClipWellProps {\n children: ReactNode\n maxHeight: number\n className?: string\n watch?: unknown\n}\n\nexport function ClipWell(props: ClipWellProps): ReactNode {\n const { children, maxHeight, className, watch } = props\n const [clip, setClip] = useState({ up: false, down: false })\n const ref = useRef<HTMLDivElement>(null)\n\n useLayoutEffect(() => {\n const el = ref.current\n if (!el) return\n const measure = (): void => {\n if (el.clientHeight < 2) {\n setClip((cur) => cur.up || cur.down ? { up: false, down: false } : cur)\n return\n }\n const max = el.scrollHeight - el.clientHeight\n const up = el.scrollTop > 1\n const down = max > 1 && el.scrollTop < max - 1\n setClip((cur) => cur.up === up && cur.down === down ? cur : { up, down })\n }\n measure()\n const ro = new ResizeObserver(measure)\n ro.observe(el)\n for (const child of el.children) ro.observe(child)\n el.addEventListener('scroll', measure, { passive: true })\n el.addEventListener('transitionend', measure)\n return () => {\n ro.disconnect()\n el.removeEventListener('scroll', measure)\n el.removeEventListener('transitionend', measure)\n }\n }, [watch])\n\n return (\n <div className={'dsgc-clip' + (clip.up ? ' can-up' : '') + (clip.down ? ' can-down' : '')}>\n <div\n className={'dsgc-clip-scroll' + (className ? ' ' + className : '')}\n ref={ref}\n style={{ maxHeight } as CSSProperties}\n >\n {children}\n </div>\n </div>\n )\n}\n","/**\n * 思考折叠行(对标宿主 ReasoningRow:折叠摘要 / 展开全文)。\n * @module dsh-group-chat/client/ThinkRow\n */\n\nimport { useState, type ReactNode } from 'react'\nimport { P } from '../lib/ui.ts'\nimport { firstLine, latestLine } from '../lib/model.ts'\nimport { ClipWell, Fold } from './Fold.tsx'\n\nexport function ThinkRow(props: { text: string, running?: boolean }): ReactNode {\n const text = props.text || ''\n const running = !!props.running\n const [expanded, setExpanded] = useState(false)\n const plain = (line: string): string => line.replace(/^(\\s*#{1,6}\\s+|\\s*[-*+]\\s+|\\s*>\\s*)+/, '').replace(/[*`_~]/g, '').replace(/\\s+/g, ' ').trim()\n const summary = plain(running ? latestLine(text) : firstLine(text))\n return (\n <div className=\"dsgc-think\">\n <P.DisclosureRow\n rowClassName=\"dsgc-thinkrow\"\n icon={<P.IconThinkOutline14 size={14} />}\n title=\"思考\"\n open={expanded}\n expandable\n expandOnRowClick\n onToggle={() => { setExpanded((v) => !v) }}\n collapsedContent={text ? <span className=\"dsgc-thinksummary\">{summary}</span> : null}\n />\n <Fold open={expanded}>\n <ClipWell maxHeight={320} watch={text}>\n <div className=\"dsgc-thinkbody\">{text}</div>\n </ClipWell>\n </Fold>\n </div>\n )\n}\n","/**\n * 工具调用折叠行(对标思考折叠:摘要行 / 展开输出)。\n * @module dsh-group-chat/client/ToolRow\n */\n\nimport { useState, type ReactNode } from 'react'\nimport { Icon, P, pickPrimitive } from '../lib/ui.ts'\nimport type { ToolCallRecord } from '../../core/types.ts'\nimport { ClipWell, Fold } from './Fold.tsx'\n\nconst TOOL_ICONS: Record<string, string> = { read_file: 'IconBrowseOutline16', list_dir: 'IconFolderOpenOutline16', run_command: 'IconCodeOutline16' }\n\nexport function ToolRow(props: { c: ToolCallRecord }): ReactNode {\n const c = props.c\n const [expanded, setExpanded] = useState(false)\n let brief = ''\n try {\n brief = JSON.stringify(c.args) || ''\n } catch {\n brief = ''\n }\n if (brief.length > 40) brief = brief.slice(0, 40) + '…'\n const IconOf = pickPrimitive(TOOL_ICONS[c.tool] || 'IconCodeOutline16')\n const statusText = c.status === 'ok' ? '成功' : c.status === 'denied' ? '用户拒绝' : '失败'\n const StatusIcon = c.status === 'ok' ? P.IconCheckOutline14 : c.status === 'denied' ? P.IconCloseOutline16 : P.IconWarningOutline16\n const dur = c.durationMs ? (c.durationMs >= 1000 ? (c.durationMs / 1000).toFixed(1) + 's' : c.durationMs + 'ms') : ''\n return (\n <div className=\"dsgc-tool\">\n <P.DisclosureRow\n rowClassName=\"dsgc-toolrow\"\n icon={<IconOf size={14} />}\n title={c.tool + (brief ? ' ' + brief : '')}\n open={expanded}\n expandable\n expandOnRowClick\n onToggle={() => { setExpanded((v) => !v) }}\n collapsedContent={\n <span className=\"dsgc-toolsummary\">\n {Icon(StatusIcon, 12, {\n verticalAlign: '-2px',\n marginRight: 4,\n color: c.status === 'ok' ? 'var(--dsw-alias-label-tertiary,inherit)' : 'var(--dsw-alias-state-error-primary,#e5484d)',\n })}\n {statusText + (dur ? ' · ' + dur : '')}\n </span>\n }\n />\n <Fold open={expanded}>\n <ClipWell maxHeight={260} watch={c.output}>\n <div className=\"dsgc-toolbody\">{c.output || '(无输出)'}</div>\n </ClipWell>\n </Fold>\n </div>\n )\n}\n","/**\n * 角色发言失败卡:人话标题 + 可展开原文。操作条由 Bubble 放在气泡外下方。\n * @module dsh-group-chat/client/FailCard\n */\n\nimport { useState, type ReactNode } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport { classifySpeakFailure } from '../../core/errors.ts'\nimport { ClipWell, Fold } from './Fold.tsx'\n\nexport interface FailCardProps {\n raw: string\n}\n\nexport function FailCard(props: FailCardProps): ReactNode {\n const view = classifySpeakFailure(props.raw)\n const [open, setOpen] = useState(false)\n\n return (\n <div className=\"dsgc-fail\">\n <div className=\"dsgc-failhead\">\n <span className=\"dsgc-failicon\" aria-hidden=\"true\">{Icon(P.IconWarningOutline16, 14)}</span>\n <div className=\"dsgc-failcopy\">\n <div className=\"dsgc-failtitle\">{view.title}</div>\n {view.detail ? <div className=\"dsgc-faildetail\">{view.detail}</div> : null}\n </div>\n </div>\n {view.raw\n ? (\n <>\n <button\n type=\"button\"\n className={'dsgc-failmore' + (open ? ' open' : '')}\n aria-expanded={open}\n onClick={() => { setOpen((v) => !v) }}\n >\n {open ? '收起原始错误' : '查看原始错误'}\n </button>\n <Fold open={open}>\n <ClipWell maxHeight={220} watch={open}>\n <pre className=\"dsgc-failraw\">{view.raw}</pre>\n </ClipWell>\n </Fold>\n </>\n )\n : null}\n </div>\n )\n}\n","/**\n * 消息操作条:贴在气泡外下方。用户/角色消息悬停出「复制」;失败卡常驻「复制 / 重试」。\n * @module dsh-group-chat/client/MsgActions\n */\n\nimport { useEffect, useRef, useState, type ReactNode } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\n\nexport interface MsgActionsProps {\n copyText: string\n onRetry?: () => void\n retryDisabled?: boolean\n retryTitle?: string\n /** 失败卡:不依赖悬停,始终可见。 */\n always?: boolean\n}\n\nasync function writeClipboard(text: string): Promise<boolean> {\n try {\n if (navigator.clipboard && navigator.clipboard.writeText) {\n await navigator.clipboard.writeText(text)\n return true\n }\n } catch { /* fall through */ }\n try {\n const el = document.createElement('textarea')\n el.value = text\n el.setAttribute('readonly', '')\n el.style.position = 'fixed'\n el.style.left = '-9999px'\n document.body.appendChild(el)\n el.select()\n const ok = document.execCommand('copy')\n document.body.removeChild(el)\n return ok\n } catch {\n return false\n }\n}\n\nexport function MsgActions(props: MsgActionsProps): ReactNode {\n const { copyText, onRetry, retryDisabled, retryTitle, always } = props\n const [copied, setCopied] = useState(false)\n const copiedTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n useEffect(() => () => { if (copiedTimer.current) clearTimeout(copiedTimer.current) }, [])\n\n const copy = async (): Promise<void> => {\n if (!copyText) return\n const ok = await writeClipboard(copyText)\n if (!ok) return\n setCopied(true)\n if (copiedTimer.current) clearTimeout(copiedTimer.current)\n copiedTimer.current = setTimeout(() => { setCopied(false) }, 1400)\n }\n\n return (\n <div className={'dsgc-msgops' + (always ? ' always' : '')} role=\"group\" aria-label=\"消息操作\">\n <button\n type=\"button\"\n className={'dsgc-msgop' + (copied ? ' done' : '')}\n title={copied ? '已复制' : '复制'}\n aria-label={copied ? '已复制' : '复制'}\n onClick={(e) => { e.stopPropagation(); void copy() }}\n >\n {Icon(copied ? P.IconCheckOutline14 : P.IconCopyOutline16, 14)}\n <span>{copied ? '已复制' : '复制'}</span>\n </button>\n {onRetry\n ? (\n <button\n type=\"button\"\n className=\"dsgc-msgop retry\"\n title={retryTitle || '重试'}\n aria-label={retryTitle || '重试'}\n disabled={retryDisabled}\n onClick={(e) => { e.stopPropagation(); if (!retryDisabled) onRetry() }}\n >\n {Icon(P.IconRefreshOutline14, 14)}\n <span>重试</span>\n </button>\n )\n : null}\n </div>\n )\n}\n","/**\n * 聊天消息气泡(user / system / 角色发言)。\n *\n * 帧稳定 memo:SSE 全量快照(~65KB × 7fps)每帧重建全部消息对象 identity,\n * 但已完成消息在 host 侧 append 后不可变——按渲染相关字段做值比较,流式\n * 期间跳过已完成消息的重渲(每帧仅 live 行与派生列表变化),避免全量\n * MarkdownText 重新解析打满主线程导致「卡死后一次性蹦出」。\n * @module dsh-group-chat/client/Bubble\n */\n\nimport { memo, type ReactNode } from 'react'\nimport { P } from '../lib/ui.ts'\nimport { classifySpeakFailure, formatSpeakFailureCopy, isSpeakFailure } from '../../core/errors.ts'\nimport { fmtTime, MD_LABELS, type SnapshotRole } from '../lib/model.ts'\nimport type { SnapshotMessage } from '../lib/model.ts'\nimport { ThinkRow } from './ThinkRow.tsx'\nimport { ToolRow } from './ToolRow.tsx'\nimport { FailCard } from './FailCard.tsx'\nimport { MsgActions } from './MsgActions.tsx'\n\nexport interface BubbleProps {\n m: SnapshotMessage\n /** 父级解析好的发言角色(user/system 消息为 null)——避免 Bubble 依赖 snap identity。 */\n role: SnapshotRole | null\n busy?: boolean\n onRetry?: (messageId: string) => void\n}\n\nfunction BubbleInner({ m, role, busy, onRetry }: BubbleProps): ReactNode {\n const isUser = m.speaker === 'user'\n const isFail = isSpeakFailure(m)\n const isSys = m.speaker === 'system' && !isFail && !role\n const name = isUser ? '我' : role ? role.name : isSys ? '系统' : '成员'\n if (isSys) return <div className=\"dsgc-sysmsg\">{m.text}</div>\n\n const retryTitle = !role\n ? '失败角色已不存在,无法重试'\n : !role.enabled\n ? '该角色已停用,无法重试'\n : busy\n ? '已有对话进行中,请先停止'\n : '重试该角色发言'\n const copyText = isFail ? formatSpeakFailureCopy(classifySpeakFailure(m.text)) : (m.text || '')\n\n return (\n <div className={'dsgc-msg' + (isUser ? ' mine' : '') + (isFail ? ' fail' : '')}>\n <div\n className={'dsgc-avatar' + (isUser ? ' mine' : '')}\n style={isUser || !role ? undefined : { border: '2px solid ' + (role.color || '#888') }}\n >\n {name.slice(0, 1)}\n </div>\n <div className=\"dsgc-msgbody\">\n <div className=\"dsgc-msghead\">\n <span className=\"dsgc-msgname\">{name}</span>\n {m.model ? <span className=\"dsgc-msgmodel\" title={m.model}>{m.model}</span> : null}\n {m.ts ? <span className=\"dsgc-msgtime\">{fmtTime(m.ts)}</span> : null}\n </div>\n {isFail\n ? <FailCard raw={m.text} />\n : isUser\n ? <div className=\"dsgc-msgtext\">{m.text}</div>\n : (\n <div className=\"dsgc-msgtext\">\n {m.reasoning ? <ThinkRow text={m.reasoning} /> : null}\n {(Array.isArray(m.toolCalls) ? m.toolCalls : []).map((c, i) => <ToolRow key={'tc' + i} c={c} />)}\n <P.MarkdownText text={m.text || '(无内容)'} labels={MD_LABELS} />\n </div>\n )}\n <MsgActions\n copyText={copyText}\n always={isFail}\n onRetry={isFail && onRetry ? () => { onRetry(m.id) } : undefined}\n retryDisabled={busy || !role || !role.enabled}\n retryTitle={retryTitle}\n />\n </div>\n </div>\n )\n}\n\n/** 渲染相关字段的值比较(消息不可变;角色仅名/色参与渲染)。 */\nfunction bubblePropsEqual(a: BubbleProps, b: BubbleProps): boolean {\n if (a.busy !== b.busy || (a.onRetry == null) !== (b.onRetry == null)) return false\n const x = a.m\n const y = b.m\n if (x !== y) {\n if (x.id !== y.id || x.speaker !== y.speaker || x.text !== y.text || x.reasoning !== y.reasoning || x.model !== y.model || x.error !== y.error || x.failedRoleId !== y.failedRoleId || x.ts !== y.ts) return false\n const ta = Array.isArray(x.toolCalls) ? x.toolCalls : []\n const tb = Array.isArray(y.toolCalls) ? y.toolCalls : []\n if (ta.length !== tb.length) return false\n for (let i = 0; i < ta.length; i++) {\n const ca = ta[i]\n const cb = tb[i]\n if (ca !== cb && (ca.tool !== cb.tool || ca.status !== cb.status || ca.output !== cb.output || ca.durationMs !== cb.durationMs || JSON.stringify(ca.args) !== JSON.stringify(cb.args))) return false\n }\n }\n const ra = a.role\n const rb = b.role\n return (ra ? ra.id + '\\u0000' + ra.name + '\\u0000' + (ra.color || '') + '\\u0000' + (ra.enabled ? '1' : '0') : '') === (rb ? rb.id + '\\u0000' + rb.name + '\\u0000' + (rb.color || '') + '\\u0000' + (rb.enabled ? '1' : '0') : '')\n}\n\nexport const Bubble = memo(BubbleInner, bubblePropsEqual)\n","/**\n * 会话流折点处:只读结论备忘卡(超过 4 条默认露 3 条)。\n * @module dsh-group-chat/client/components\n */\n\nimport { useState, type ReactNode } from 'react'\nimport type { SessionConstraint } from '../../core/types.ts'\nimport { KIND_LABEL } from '../../core/constraints.ts'\nimport { ClipWell, Fold } from './Fold.tsx'\n\ninterface ConstraintListProps {\n items: SessionConstraint[]\n}\n\nfunction ConstraintRow(props: { item: SessionConstraint }): ReactNode {\n const { item } = props\n return (\n <div className=\"dsgc-constraint\">\n <span className={'dsgc-ckind ' + item.kind}>{KIND_LABEL[item.kind]}</span>\n <span className=\"dsgc-ctext\">{item.text}</span>\n </div>\n )\n}\n\nexport function ConstraintList(props: ConstraintListProps): ReactNode {\n const { items } = props\n const [open, setOpen] = useState(false)\n if (!items.length) return null\n const overflow = items.length > 4\n const head = overflow ? items.slice(0, 3) : items\n const extra = overflow ? items.slice(3) : []\n const rest = items.length - 3\n\n return (\n <section className=\"dsgc-constraints\" aria-labelledby=\"dsgc-constraints-title\">\n <div className=\"dsgc-chead\">\n <h2 id=\"dsgc-constraints-title\" className=\"dsgc-ctitle\">结论备忘</h2>\n <p className=\"dsgc-cdesc\">窗口外消息折成的已定 / 否决 / 未决,供后续角色接着用。</p>\n </div>\n <ClipWell maxHeight={160} className=\"dsgc-clist\" watch={open}>\n {head.map((c, i) => <ConstraintRow key={i} item={c} />)}\n {overflow\n ? (\n <Fold open={open}>\n {extra.map((c, i) => <ConstraintRow key={i + 3} item={c} />)}\n </Fold>\n )\n : null}\n </ClipWell>\n {overflow\n ? (\n <button\n type=\"button\"\n className=\"dsgc-cmore\"\n onClick={() => { setOpen(!open) }}\n aria-expanded={open}\n >\n {open ? '收起' : '还有 ' + rest + ' 条约束'}\n </button>\n )\n : null}\n </section>\n )\n}\n","/**\n * 发言人执行态点阵光球(live 行头像内容):角色色单色点阵 Canvas 2D 动画。\n * thinking(轨道热斑游走=等待首字节/推理中)与 listening(向外涟漪=正文\n * 流出)两态间弹簧缩放 + 权重交叉淡入;裁掉参考实现 MatrixOrb 的 label、\n * level 与 idle 态(本场景只有执行中一种挂载时机),尺寸钉死为头像内容盒。\n * @module dsh-group-chat/client/SpeakerOrb\n */\n\nimport { useEffect, useRef, useSyncExternalStore, type ReactNode } from 'react'\n\nexport type SpeakerOrbState = 'thinking' | 'listening'\n\nconst TAU = Math.PI * 2\nconst STATES: SpeakerOrbState[] = ['thinking', 'listening']\n\n/** 头像内容盒:28px 外框减 2px 描边 ×2;圆形轮廓由 d 截断近似。 */\nconst SIZE = 24\nconst GRID = 7\n/** 点阵铺开比例:外圈点贴近描边又不被 border-radius 裁切。 */\nconst SPREAD = 0.86\n\nconst SCALE: Record<SpeakerOrbState, number> = { thinking: 0.94, listening: 1 }\nconst STIFFNESS = 180\nconst DAMPING = 26\nconst ATTACK = 0.22\nconst RELEASE = 0.08\nconst BLEND = 0.16\n\n/** thinking 态热斑轨道(点阵归一化坐标)。 */\nconst ORBITERS = [\n { radius: 0.62, speed: 2.2, phase: 0, spread: 0.42 },\n { radius: 0.4, speed: -1.7, phase: 2.1, spread: 0.36 },\n { radius: 0.8, speed: 1.15, phase: 4, spread: 0.34 },\n]\n\n// no Math.abs here, its corners read as a snap at every trough\nfunction envelope(t: number) {\n const slow = 0.5 + 0.5 * Math.sin(t * 0.62 + 0.4)\n const fast = 0.5 + 0.5 * Math.sin(t * 1.9 + 1.1)\n return 0.22 + 0.78 * (0.45 + 0.55 * slow) * fast\n}\n\nfunction intensityOf(\n state: SpeakerOrbState,\n d: number,\n nx: number,\n ny: number,\n t: number,\n amplitude: number,\n) {\n if (state === 'listening') {\n const ripple = 0.5 + 0.5 * Math.sin(d * 4.2 - t * 3)\n return 0.32 + amplitude * (0.34 + 0.38 * ripple)\n }\n\n let heat = 0\n for (const o of ORBITERS) {\n const a = t * o.speed + o.phase\n const dx = nx - Math.cos(a) * o.radius\n const dy = ny - Math.sin(a) * o.radius\n heat += Math.exp(-(dx * dx + dy * dy) / (o.spread * o.spread))\n }\n return 0.26 + 0.8 * Math.min(1, heat)\n}\n\n// zoom changes devicePixelRatio, and a buffer built for the old one gets upscaled\nfunction subscribeToZoom(onChange: () => void) {\n window.addEventListener('resize', onChange)\n return () => window.removeEventListener('resize', onChange)\n}\n\nfunction useDevicePixelRatio() {\n return useSyncExternalStore(\n subscribeToZoom,\n () => Math.min(window.devicePixelRatio || 1, 4),\n () => 1,\n )\n}\n\nexport function SpeakerOrb(props: { state: SpeakerOrbState, color: string }): ReactNode {\n const { state, color } = props\n const canvasRef = useRef<HTMLCanvasElement>(null)\n const stateRef = useRef(state)\n const redrawRef = useRef<(() => void) | null>(null)\n const dpr = useDevicePixelRatio()\n\n useEffect(() => {\n stateRef.current = state\n }, [state])\n\n useEffect(() => {\n const canvas = canvasRef.current\n const ctx = canvas?.getContext('2d')\n if (!canvas || !ctx) return\n\n // scaling by buffer/size, not dpr, keeps the transform exact when it rounds\n const buffer = Math.round(SIZE * dpr)\n canvas.width = canvas.height = buffer\n ctx.scale(buffer / SIZE, buffer / SIZE)\n ctx.fillStyle = color\n\n const half = (GRID - 1) / 2\n const spacing = (SIZE * SPREAD) / (GRID - 1)\n const maxRadius = spacing * 0.6\n const center = SIZE / 2\n\n const weights: Record<SpeakerOrbState, number> = { thinking: 0, listening: 0 }\n weights[stateRef.current] = 1\n\n const draw = (t: number, amplitude: number, scale: number) => {\n ctx.clearRect(0, 0, SIZE, SIZE)\n\n for (let iy = 0; iy < GRID; iy++) {\n for (let ix = 0; ix < GRID; ix++) {\n const nx = (ix - half) / half\n const ny = (iy - half) / half\n const d = Math.hypot(nx, ny)\n // 1.12, not the square's 1.41 corner, is what makes the outline round\n if (d > 1.12) continue\n\n let blended = 0\n for (const s of STATES) {\n if (weights[s] < 0.001) continue\n blended += weights[s] * intensityOf(s, d, nx, ny, t, amplitude)\n }\n\n const intensity = Math.min(1, Math.max(0, blended))\n const radius = maxRadius * Math.exp(-d * d * 1.7) * intensity * scale\n // anything under half a device pixel renders as haze, not a dot\n if (radius * dpr < 0.5) continue\n\n ctx.beginPath()\n ctx.arc(\n center + (ix - half) * spacing * scale,\n center + (iy - half) * spacing * scale,\n radius,\n 0,\n TAU,\n )\n ctx.fill()\n }\n }\n }\n\n const reduce =\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches\n\n if (reduce) {\n redrawRef.current = () => {\n const current = stateRef.current\n for (const s of STATES) weights[s] = s === current ? 1 : 0\n draw(0, envelope(0), SCALE[current])\n }\n redrawRef.current()\n return () => {\n redrawRef.current = null\n }\n }\n\n let t = 0\n let amplitude = 0\n let scale = SCALE[stateRef.current]\n let velocity = 0\n let last = performance.now()\n let raf = 0\n\n const frame = (now: number) => {\n const dt = Math.min((now - last) / 1000, 0.05)\n last = now\n t += dt\n\n const current = stateRef.current\n const target = envelope(t)\n const rate = target > amplitude ? ATTACK : RELEASE\n amplitude += (target - amplitude) * (1 - Math.pow(1 - rate, dt * 60))\n\n // per-state weights, so interrupting a change blends from what is on screen\n const step = 1 - Math.pow(1 - BLEND, dt * 60)\n for (const s of STATES) {\n weights[s] += ((s === current ? 1 : 0) - weights[s]) * step\n }\n\n velocity += (-STIFFNESS * (scale - SCALE[current]) - DAMPING * velocity) * dt\n scale += velocity * dt\n\n draw(t, amplitude, scale)\n raf = requestAnimationFrame(frame)\n }\n raf = requestAnimationFrame(frame)\n\n return () => cancelAnimationFrame(raf)\n // state stays out of the deps on purpose: the loop retargets, it never restarts\n }, [color, dpr])\n\n useEffect(() => {\n redrawRef.current?.()\n }, [state])\n\n return <canvas ref={canvasRef} aria-hidden className=\"dsgc-orb\" style={{ width: SIZE, height: SIZE }} />\n}\n","/**\n * 消息流显示组件\n * @module dsh-group-chat/client/components\n */\n\nimport type { ReactNode, CSSProperties } from 'react'\nimport { WINDOW_SIZE } from '../../core/constraints.ts'\nimport { Icon, P } from '../lib/ui.ts'\nimport { Bubble } from './Bubble.tsx'\nimport { ConstraintList } from './ConstraintList.tsx'\nimport { SpeakerOrb, type SpeakerOrbState } from './SpeakerOrb.tsx'\nimport { ThinkRow } from './ThinkRow.tsx'\nimport { resolveFailedRole } from '../../core/errors.ts'\nimport { roleById, type ClientSnapshot } from '../lib/model.ts'\nimport { MD_LABELS } from '../lib/model.ts'\n\ninterface MessageFlowProps {\n snap: ClientSnapshot\n sess: ClientSnapshot['sessions'][number] | null\n busyNow: boolean\n msgById: Record<string, ClientSnapshot['messages'][number]>\n action: (payload: Record<string, unknown>) => Promise<unknown>\n onRetrySpeak: (messageId: string) => void\n}\n\nexport function MessageFlow(props: MessageFlowProps): ReactNode {\n const { snap, sess, busyNow, msgById, action, onRetrySpeak } = props\n\n const bubbles: ReactNode[] = []\n const replaceId = busyNow ? snap.run.replaceMessageId : null\n const replaceMsg = replaceId ? msgById[replaceId] : null\n const liveRoleId = snap.run.currentRoleId || (replaceMsg && (replaceMsg.failedRoleId || replaceMsg.speaker)) || null\n const lr = busyNow && liveRoleId ? roleById(snap, liveRoleId) : null\n const liveColor = lr ? (lr.color || '#888') : '#888'\n // 执行阶段映射:正文流出 → listening 涟漪;等待首字节/推理中 → thinking 热斑游走\n const orbState: SpeakerOrbState = snap.run.partial ? 'listening' : 'thinking'\n\n const live = lr\n ? (\n <div key=\"__live\" className=\"dsgc-msg live\">\n <div\n className=\"dsgc-avatar\"\n style={{ border: '2px solid ' + liveColor, '--role-color': liveColor } as CSSProperties}\n >\n <SpeakerOrb state={orbState} color={liveColor} />\n </div>\n <div className=\"dsgc-msgbody\">\n <div className=\"dsgc-msghead\">\n <span className=\"dsgc-msgname\">{lr.name}</span>\n <span className=\"dsgc-msgmodel\">{lr.provider} / {lr.model}</span>\n <span className=\"dsgc-msgtime dsgc-typing\">深度求索...</span>\n </div>\n <div className=\"dsgc-msgtext live\">\n {snap.run.partialReasoning ? <ThinkRow text={snap.run.partialReasoning} running /> : null}\n {snap.run.partial ? <P.MarkdownText text={snap.run.partial} streaming labels={MD_LABELS} /> : null}\n {/* 首 delta 前的「思考中」占位(深度思考模型首字节可能等数秒到数十秒,\n 空白气泡会被感知为卡死);delta 到达后被真实思考行/正文自然替换 */}\n {!snap.run.partial && !snap.run.partialReasoning\n ? (\n <div className=\"dsgc-pending\">\n {Icon(P.IconThinkOutline14, 14)}\n <span>思考中</span>\n <span className=\"dsgc-pendingdots\" aria-hidden=\"true\"><i /><i /><i /></span>\n </div>\n )\n : null}\n </div>\n </div>\n </div>\n )\n : null\n\n const pc = busyNow && snap.run.pendingConfirm && sess && snap.run.sessionId === sess.id ? snap.run.pendingConfirm : null\n const confirm = pc\n ? (\n <div key=\"__confirm\" className=\"dsgc-confirm\">\n <div className=\"dsgc-confirmtitle\">\n {Icon(P.IconWarningOutline16, 14)}\n {(lr ? lr.name : '角色') + ' 请求执行命令(工作区内)'}\n </div>\n <div className=\"dsgc-confirmcmd\">{String((pc.args && pc.args.command) || '')}</div>\n <div className=\"dsgc-hint\">允许后将在工作区目录执行;拒绝后角色将继续纯文本讨论</div>\n <div className=\"dsgc-confirmops\">\n <P.Button variant=\"primary\" size=\"sm\" onClick={() => { void action({ kind: 'confirmCommand', toolCallId: pc.toolCallId, allow: true }) }}>允许</P.Button>\n <P.Button variant=\"outline\" size=\"sm\" onClick={() => { void action({ kind: 'confirmCommand', toolCallId: pc.toolCallId, allow: false }) }}>拒绝</P.Button>\n </div>\n </div>\n )\n : null\n\n let livePlaced = false\n\n if (sess) {\n // 循环不变量:本群角色表只过滤一次(流式期间每帧执行的热路径)\n const groupRoles = snap.roles.filter((r) => r.groupId === sess.groupId)\n const ids = sess.messageIds\n const memo = sess.constraints && sess.constraints.length\n ? <ConstraintList key={sess.id + '-constraints'} items={sess.constraints} />\n : null\n // 折点 = 最近 WINDOW_SIZE 条之前。消息都还在窗口内时卡放流顶。\n const foldAt = memo && ids.length > WINDOW_SIZE ? ids.length - WINDOW_SIZE : 0\n if (memo && foldAt === 0) bubbles.push(memo)\n for (let i = 0; i < ids.length; i++) {\n if (memo && foldAt > 0 && i === foldAt) bubbles.push(memo)\n const m = msgById[ids[i]]\n if (!m) continue\n // 角色在父级解析:Bubble 按值 memo(不依赖 snap identity),流式帧\n // 不再触发已完成消息的全量重渲(每帧仅 live 行与派生列表变化)\n const role = resolveFailedRole(m, groupRoles) || (m.speaker !== 'user' && m.speaker !== 'system' ? roleById(snap, m.speaker) : null)\n // 原地重试:该槽位换成 live(确认卡紧随其后),不要钉在列表末尾\n if (replaceId && m.id === replaceId) {\n if (live) bubbles.push(live)\n if (confirm) bubbles.push(confirm)\n livePlaced = true\n continue\n }\n bubbles.push(<Bubble key={m.id} m={m} role={role} busy={!!snap.run.running} onRetry={onRetrySpeak} />)\n }\n }\n\n if (live && !livePlaced) bubbles.push(live)\n if (confirm && !livePlaced) bubbles.push(confirm)\n\n return <>{bubbles}</>\n}\n","/**\n * 群组权限档位选择器(对齐主会话 composer 左下角的 /permission 选择器):\n * 触发芯片(盾形图标 + 档位名 + chevron)+ Menu 上弹三档 + 完全权限风险\n * 确认弹窗(与主会话同款 RiskConfirmation 原语与文案)。\n * @module dsh-group-chat/client/permission-select\n */\n\nimport { useEffect, useState, type ReactNode } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport type { PermissionTier } from '../../core/types.ts'\nimport { asPermissionTier, PERMISSION_TIERS } from '../../core/types.ts'\n\nexport interface PermissionSelectProps {\n tier: PermissionTier\n onSelect: (tier: PermissionTier) => void\n}\n\n/** 档位展示名(与主会话中文标签一致)。 */\nconst TIER_LABELS: Record<PermissionTier, string> = {\n view_only: '仅可查看',\n workspace_write: '工作区内修改',\n full_access: '完全权限',\n}\n\n/** 档位悬停说明(群聊语境下的真实约束)。 */\nconst TIER_DESCRIPTIONS: Record<PermissionTier, string> = {\n view_only: '角色只能读取工作区文件,不能执行命令',\n workspace_write: '角色可执行命令(cwd 固定在工作区),每条命令需你在会话中确认',\n full_access: '角色可免确认直接执行命令,存在风险',\n}\n\n/** 完全权限风险确认文案(与主会话逐字一致)。 */\nconst CONFIRM_TEXT = {\n title: '确认启用完全权限?',\n description: '启用完全权限后,智能体将减少确认步骤,并且可以直接执行更多操作,包括敏感操作、文件修改或外部命令。仅建议在你信任当前任务时使用。',\n acknowledge: '我已了解风险,并愿意继续',\n cancel: '取消',\n enable: '启用完全权限',\n} as const\n\n// ---- 盾形图标(路径取自主会话 PermissionSelect 的设计稿字形) ----\n\nconst SHIELD_OUTLINE = 'M8.20554 0.899994L14.7901 3.36857V7.01026C14.7901 12 11.0466 14.2103 8.20554 15.3C5.36446 14.2103 1.62012 12 1.62012 7.01026V3.36857L8.20554 0.899994Z'\n\nfunction GlyphViewOnly(): ReactNode {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden>\n <path d={SHIELD_OUTLINE} stroke=\"currentColor\" strokeWidth=\"1.31831\" strokeLinejoin=\"round\" />\n <path d=\"M12.1654 5.7552L8.9447 9.41475C8.73044 9.65816 8.53628 9.8804 8.35774 10.0423C8.1713 10.2114 7.94235 10.3717 7.64016 10.4254C7.48207 10.4535 7.32 10.4552 7.16151 10.4294C6.85843 10.3801 6.62728 10.2223 6.43836 10.0559C6.25752 9.89653 6.06037 9.67732 5.84264 9.43705L4.72925 8.20897L5.63557 7.38707L6.74897 8.61594C6.98603 8.87755 7.12974 9.03533 7.24673 9.13839C7.31033 9.19443 7.34485 9.21476 7.35823 9.22122C7.38068 9.22484 7.40352 9.22515 7.42593 9.22122C7.40522 9.22502 7.42893 9.23294 7.53583 9.136C7.65132 9.03126 7.79316 8.87139 8.02643 8.60638L11.2479 4.94763L12.1654 5.7552Z\" fill=\"currentColor\" />\n </svg>\n )\n}\n\nfunction GlyphWorkspaceWrite(): ReactNode {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden>\n <path d=\"M8.08887 0.251709C8.20479 0.23085 8.32486 0.241168 8.43652 0.282959L15.0215 2.75171C15.2787 2.84819 15.4492 3.09414 15.4492 3.3689V7.0105C15.4492 7.10986 15.4441 7.2081 15.4414 7.30542C15.0285 7.07175 14.5905 6.87695 14.1309 6.73022V3.82495L8.20508 1.60327L2.2793 3.82495V7.0105C2.27936 9.7171 3.4745 11.5379 5.02734 12.7947C5.01025 12.9942 5 13.1962 5 13.4001C5.00001 13.7617 5.02722 14.1169 5.08008 14.4636C2.91555 13.0393 0.961014 10.752 0.960938 7.0105V3.3689C0.960938 3.09417 1.13146 2.84821 1.38867 2.75171L7.97461 0.282959L8.08887 0.251709Z\" fill=\"currentColor\" />\n <path d=\"M11.3525 5.64688V6.85688H5V5.64688H11.3525Z\" fill=\"currentColor\" />\n <path d=\"M9.5824 8.29376V9.50376H5V8.29376H9.5824Z\" fill=\"currentColor\" />\n <path d=\"M14.6647 15.6852H10.0338C10.3878 15.3751 10.7567 15.0517 11.0772 14.7706C11.2531 14.6164 11.4144 14.4746 11.5511 14.3547H14.6647V15.6852Z\" fill=\"currentColor\" />\n <path d=\"M8.14852 14.1308L7.33925 15.4976C7.22458 15.6912 7.42245 15.9194 7.63037 15.8333L9.09785 15.2254L15.0399 10.0719L14.0905 8.97733L8.14852 14.1308Z\" fill=\"currentColor\" />\n </svg>\n )\n}\n\nfunction GlyphFullAccess(): ReactNode {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden>\n <path d={SHIELD_OUTLINE} stroke=\"currentColor\" strokeWidth=\"1.31831\" strokeLinejoin=\"round\" />\n <path d=\"M9.10094 4.5V8.75939H7.59888V4.5H9.10094Z\" fill=\"currentColor\" />\n <path d=\"M9.10094 9.8114V11.5H7.59888V9.8114Z\" fill=\"currentColor\" />\n </svg>\n )\n}\n\nconst TIER_GLYPHS: Record<PermissionTier, () => ReactNode> = {\n view_only: GlyphViewOnly,\n workspace_write: GlyphWorkspaceWrite,\n full_access: GlyphFullAccess,\n}\n\nexport function PermissionSelect(props: PermissionSelectProps): ReactNode {\n const [open, setOpen] = useState(false)\n const [confirming, setConfirming] = useState(false)\n const [acknowledged, setAcknowledged] = useState(false)\n // 版本错位兜底:旧 host 快照无 permissionTier(或值非法)时按最安全的仅可查看呈现,\n // 不让面板整体崩溃\n const tier = asPermissionTier(props.tier) ?? 'view_only'\n\n // 档位被外部改回(如迁移/其他端变更)时收起弹层与确认态\n useEffect(() => {\n setOpen(false)\n setAcknowledged(false)\n setConfirming(false)\n }, [tier])\n\n const choose = (id: string): void => {\n setOpen(false)\n if (id === tier) return\n if (id === 'full_access') {\n setAcknowledged(false)\n setConfirming(true)\n return\n }\n props.onSelect(id as PermissionTier)\n }\n const closeConfirm = (): void => {\n setAcknowledged(false)\n setConfirming(false)\n }\n const confirmFullAccess = (): void => {\n if (!acknowledged) return\n closeConfirm()\n props.onSelect('full_access')\n }\n\n const items = PERMISSION_TIERS.map((t) => ({ id: t, label: TIER_LABELS[t], icon: TIER_GLYPHS[t]() }))\n const Glyph = TIER_GLYPHS[tier] ?? GlyphViewOnly\n\n return (\n <>\n <P.Menu\n open={open}\n items={items}\n selectedId={tier}\n onSelect={choose}\n onClose={() => { setOpen(false) }}\n side=\"top\"\n anchor={(\n <button\n type=\"button\"\n className=\"dsgc-permtrigger\"\n aria-label={'权限模式:' + TIER_LABELS[tier]}\n title={TIER_DESCRIPTIONS[tier]}\n disabled={confirming}\n onClick={() => { setOpen(!open) }}\n >\n <span className=\"dsgc-permicon\" aria-hidden>{Glyph()}</span>\n <span className=\"dsgc-permlabel\">{TIER_LABELS[tier]}</span>\n <span className={'dsgc-permchevron' + (open ? ' open' : '')} aria-hidden>{Icon(P.IconChevronDownOutline14, 14)}</span>\n </button>\n )}\n />\n <P.RiskConfirmation\n open={confirming}\n title={CONFIRM_TEXT.title}\n description={CONFIRM_TEXT.description}\n acknowledgeLabel={CONFIRM_TEXT.acknowledge}\n cancelLabel={CONFIRM_TEXT.cancel}\n closeLabel=\"关闭\"\n confirmLabel={CONFIRM_TEXT.enable}\n acknowledged={acknowledged}\n onAcknowledgedChange={setAcknowledged}\n onCancel={closeConfirm}\n onConfirm={confirmFullAccess}\n />\n </>\n )\n}\n","/**\n * 消息输入编辑器组件\n * @module dsh-group-chat/client/components\n */\n\nimport type { ReactNode, KeyboardEvent as ReactKeyboardEvent, ClipboardEvent as ReactClipboardEvent, DragEvent as ReactDragEvent } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport { PermissionSelect } from './PermissionSelect.tsx'\nimport { HoverTip } from './HoverTip.tsx'\nimport { escapeRegExp, type ClientSnapshot, type SnapshotRole } from '../lib/model.ts'\nimport type { AtToken } from '../../shared/file-mention-grammar.ts'\n\n/** 轮数控件 hover:宿主 Tooltip 三行说明(pre-line)。 */\nconst ROUNDS_HINT = '一轮 = 参与角色各说一次。\\n要他们自己互相反驳、你不插话时再加轮。\\n要边看边插话,就留 1,再点发送。'\n\ninterface ComposerProps {\n snap: ClientSnapshot\n sess: ClientSnapshot['sessions'][number] | null\n group: ClientSnapshot['groups'][number]\n enabledRoles: SnapshotRole[]\n participants: string[]\n mentionedRoles: SnapshotRole[]\n busyNow: boolean\n input: string\n mention: AtToken | null\n mentionCandidates: SnapshotRole[]\n mentionIdxC: number\n fileCandidates: Array<{ path: string, isDir: boolean }>\n fileSearchError: string | null\n fileSearchLoading: boolean\n rounds: number\n err: string\n atBottom: boolean\n bubblesLength: number\n inputRef: React.RefObject<HTMLDivElement>\n scrollRef: React.RefObject<HTMLDivElement>\n setMentionIdx: (val: number) => void\n setRounds: (val: number) => void\n togglePart: (rid: string) => void\n onInputCE: () => void\n onInputKeyDown: (e: ReactKeyboardEvent<HTMLDivElement>) => void\n onPasteCE: (e: ReactClipboardEvent<HTMLDivElement>) => void\n onDropCE: (e: ReactDragEvent<HTMLDivElement>) => void\n onDragOverCE: (e: ReactDragEvent<HTMLDivElement>) => void\n insertChip: (role: SnapshotRole) => void\n insertFileChip: (path: string, kind: 'file' | 'directory') => void\n sendMsg: () => Promise<void>\n stopRun: () => Promise<void>\n mutate: (args: Record<string, unknown>) => Promise<unknown>\n setMention: (val: AtToken | null) => void\n}\n\nexport function Composer(props: ComposerProps): ReactNode {\n const {\n snap,\n sess,\n group,\n enabledRoles,\n participants,\n mentionedRoles,\n busyNow,\n input,\n mention,\n mentionCandidates,\n mentionIdxC,\n fileCandidates,\n fileSearchError,\n fileSearchLoading,\n rounds,\n err,\n atBottom,\n bubblesLength,\n inputRef,\n scrollRef,\n setMentionIdx,\n setRounds,\n togglePart,\n onInputCE,\n onInputKeyDown,\n onPasteCE,\n onDropCE,\n onDragOverCE,\n insertChip,\n insertFileChip,\n sendMsg,\n stopRun,\n mutate,\n setMention,\n } = props\n\n return (\n <div className=\"dsgc-composer\">\n {!atBottom && bubblesLength\n ? (\n <div className=\"dsgc-tobottom\">\n <button\n type=\"button\"\n className=\"dsgc-tobtn\"\n onClick={() => { const el = scrollRef.current; if (el) el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' }) }}\n >\n {Icon(P.IconChevronDownOutline14, 14)}回到底部\n </button>\n </div>\n )\n : null}\n {err ? <div className=\"dsgc-err\">{err}</div> : null}\n <div className=\"dsgc-parts\">\n <span className=\"dsgc-partslabel\">参与角色</span>\n <div className=\"dsgc-partlist\">\n {mentionedRoles.length\n ? <span className=\"dsgc-partslabel\">已 @ {mentionedRoles.map((r) => r.name).join('、')}(本轮仅被点名成员发言)</span>\n : enabledRoles.length\n ? enabledRoles.map((r) => (\n <button\n key={r.id}\n type=\"button\"\n className={'dsgc-partchip' + (participants.includes(r.id) ? ' on' : '')}\n onClick={() => togglePart(r.id)}\n disabled={busyNow}\n title={busyNow ? '对话进行中,暂停调整' : '点击切换本轮是否参与'}\n >\n <span className=\"dsgc-chipdot\" style={{ background: r.color || '#888' }} />\n {r.name}\n </button>\n ))\n : <span className=\"dsgc-hint\">还没有启用的角色,请在右侧添加</span>}\n </div>\n </div>\n <div className=\"dsgc-card\">\n <div className=\"dsgc-mentionwrap\">\n {mention !== null && mention.query === '' && mentionCandidates.length > 0\n ? (\n <div className=\"dsgc-mention\" role=\"listbox\">\n {mentionCandidates.map((r, i) => (\n <button\n key={r.id}\n type=\"button\"\n className={'dsgc-mentionitem' + (i === mentionIdxC ? ' on' : '')}\n role=\"option\"\n aria-selected={i === mentionIdxC ? 'true' : 'false'}\n onMouseDown={(e) => { e.preventDefault() }}\n onClick={() => { insertChip(r) }}\n onMouseEnter={() => setMentionIdx(i)}\n >\n <span className=\"dsgc-chipdot\" style={{ background: r.color || '#888' }} />\n <span className=\"dsgc-mentionname\">{r.name}</span>\n <span className=\"dsgc-mentionmodel\">{r.provider} / {r.model}</span>\n </button>\n ))}\n <span className=\"dsgc-mentionhint\">↑↓ 选择 · Enter/Tab 插入</span>\n </div>\n )\n : mention !== null && mention.query !== ''\n ? (\n <div className=\"dsgc-mention dsgc-mention-file\" role=\"listbox\">\n {fileCandidates.length\n ? fileCandidates.map((item, i) => (\n <button\n key={item.path}\n type=\"button\"\n className={'dsgc-mentionitem' + (i === mentionIdxC ? ' on' : '')}\n role=\"option\"\n aria-selected={i === mentionIdxC ? 'true' : 'false'}\n onMouseDown={(e) => { e.preventDefault() }}\n onClick={() => {\n insertFileChip(item.path, item.isDir ? 'directory' : 'file')\n }}\n onMouseEnter={() => setMentionIdx(i)}\n >\n <span className={'dsgc-fileglyph' + (item.isDir ? ' dir' : ' file')} aria-hidden=\"true\">\n {item.isDir\n ? <P.FileTypeIcon kind=\"folder\" size={16} />\n : <P.FileTypeIcon path={item.path} size={16} />}\n </span>\n <span className=\"dsgc-mentionname\">{item.path}</span>\n {item.isDir ? <span className=\"dsgc-filedrill\">{Icon(P.IconChevronRightOutline14, 12)}</span> : null}\n </button>\n ))\n : fileSearchLoading\n ? <div className=\"dsgc-mentionitem dsgc-hint\">检索中…</div>\n : fileSearchError\n ? <div className=\"dsgc-mentionitem dsgc-hint\">{fileSearchError}</div>\n : <div className=\"dsgc-mentionitem dsgc-hint\">无匹配文件</div>}\n <span className=\"dsgc-mentionhint\">\n {fileSearchLoading && fileCandidates.length\n ? '检索中…'\n : fileCandidates.some((f) => f.isDir)\n ? '↑↓ 选择 · Enter 插入 · Tab 进入目录 · Esc 关闭'\n : '↑↓ 选择 · Enter 插入 · Esc 关闭'}\n </span>\n </div>\n )\n : null}\n {!input.trim()\n ? <div className=\"dsgc-ph\" aria-hidden=\"true\">发消息给全群,@成员 点名让其回应…</div>\n : null}\n <div\n className=\"dsgc-edit\"\n ref={inputRef}\n contentEditable\n suppressContentEditableWarning\n role=\"textbox\"\n aria-multiline=\"true\"\n aria-label=\"群聊消息输入框\"\n onInput={onInputCE}\n onKeyDown={onInputKeyDown}\n onPaste={onPasteCE}\n onDrop={onDropCE}\n onDragOver={onDragOverCE}\n onBlur={() => { setMention(null) }}\n />\n </div>\n <div className=\"dsgc-sendrow\">\n <PermissionSelect\n tier={group.permissionTier}\n onSelect={(tier) => { void mutate({ op: 'setPermissionTier', groupId: group.id, tier }) }}\n />\n <span style={{ flex: 1 }} />\n <HoverTip label={ROUNDS_HINT} side=\"top\" delayMs={500} maxWidth={280} className=\"dsgc-rounds\">\n <button type=\"button\" className=\"dsgc-roundbtn\" aria-label=\"减少轮数\" disabled={rounds <= 1} onClick={() => { setRounds(Math.max(1, rounds - 1)) }}>\n {Icon(P.IconChevronLeftOutline14, 12)}\n </button>\n <span className=\"dsgc-roundnum\">{rounds}</span>\n <button type=\"button\" className=\"dsgc-roundbtn\" aria-label=\"增加轮数\" disabled={rounds >= 10} onClick={() => { setRounds(Math.min(10, rounds + 1)) }}>\n {Icon(P.IconChevronRightOutline14, 12)}\n </button>\n <span style={{ padding: '0 6px 0 2px' }}>轮</span>\n </HoverTip>\n {busyNow\n ? (\n <P.Button variant=\"outline\" className=\"dsgc-stopbtn\" onClick={() => { void stopRun() }}>\n {Icon(P.IconStopFill16, 16)}停止\n </P.Button>\n )\n : (\n <P.Button variant=\"primary\" onClick={() => { void sendMsg() }} disabled={!input.trim() || (!participants.length && !mentionedRoles.length) || !sess}>\n {Icon(P.IconSendOutline16, 16)}发送\n </P.Button>\n )}\n </div>\n </div>\n </div>\n )\n}\n","/**\n * 中央会话面板组件\n * @module dsh-group-chat/client/components\n */\n\nimport type { ReactNode } from 'react'\nimport { Icon, P } from '../lib/ui.ts'\nimport { MessageFlow } from './MessageFlow.tsx'\nimport { Composer } from './Composer.tsx'\nimport type { ClientSnapshot, SnapshotRole } from '../lib/model.ts'\nimport type { AtToken } from '../../shared/file-mention-grammar.ts'\n\ninterface ChatPanelProps {\n snap: ClientSnapshot\n sess: ClientSnapshot['sessions'][number] | null\n group: ClientSnapshot['groups'][number]\n enabledRoles: SnapshotRole[]\n participants: string[]\n mentionedRoles: SnapshotRole[]\n busyNow: boolean\n input: string\n mention: AtToken | null\n mentionCandidates: SnapshotRole[]\n mentionIdxC: number\n fileCandidates: Array<{ path: string, isDir: boolean }>\n fileSearchError: string | null\n fileSearchLoading: boolean\n rounds: number\n err: string\n atBottom: boolean\n topicDraft: string | null\n msgById: Record<string, ClientSnapshot['messages'][number]>\n navOpen: boolean\n asideOpen: boolean\n inputRef: React.RefObject<HTMLDivElement>\n scrollRef: React.RefObject<HTMLDivElement>\n setTopicDraft: (val: string | null) => void\n setConfirmClear: (val: boolean) => void\n setMentionIdx: (val: number) => void\n setRounds: (val: number) => void\n setNavOpen: (val: boolean) => void\n setAsideOpen: (val: boolean) => void\n togglePart: (rid: string) => void\n onMsgsScroll: () => void\n onInputCE: () => void\n onInputKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) => void\n onPasteCE: (e: React.ClipboardEvent<HTMLDivElement>) => void\n onDropCE: (e: React.DragEvent<HTMLDivElement>) => void\n onDragOverCE: (e: React.DragEvent<HTMLDivElement>) => void\n insertChip: (role: SnapshotRole) => void\n insertFileChip: (path: string, kind: 'file' | 'directory') => void\n sendMsg: () => Promise<void>\n stopRun: () => Promise<void>\n action: (payload: Record<string, unknown>) => Promise<unknown>\n mutate: (args: Record<string, unknown>) => Promise<unknown>\n setMention: (val: AtToken | null) => void\n onRetrySpeak: (messageId: string) => void\n}\n\nexport function ChatPanel(props: ChatPanelProps): ReactNode {\n const {\n snap,\n sess,\n group,\n enabledRoles,\n participants,\n mentionedRoles,\n busyNow,\n input,\n mention,\n mentionCandidates,\n mentionIdxC,\n fileCandidates,\n fileSearchError,\n fileSearchLoading,\n rounds,\n err,\n atBottom,\n topicDraft,\n msgById,\n navOpen,\n asideOpen,\n inputRef,\n scrollRef,\n setTopicDraft,\n setConfirmClear,\n setMentionIdx,\n setRounds,\n setNavOpen,\n setAsideOpen,\n togglePart,\n onMsgsScroll,\n onInputCE,\n onInputKeyDown,\n onPasteCE,\n onDropCE,\n onDragOverCE,\n insertChip,\n insertFileChip,\n sendMsg,\n stopRun,\n action,\n mutate,\n setMention,\n onRetrySpeak,\n } = props\n\n const commitTopic = (): void => {\n if (topicDraft !== null && sess && topicDraft !== sess.topic) void mutate({ op: 'setTopic', sessionId: sess.id, topic: topicDraft })\n setTopicDraft(null)\n }\n\n const bubbles = (\n <MessageFlow\n snap={snap}\n sess={sess}\n busyNow={busyNow}\n msgById={msgById}\n action={action}\n onRetrySpeak={onRetrySpeak}\n />\n )\n\n return (\n <section className=\"dsgc-chat\">\n {/* 接缝收合钮 */}\n <button\n type=\"button\"\n className={'dsgc-seambtn left' + (navOpen ? '' : ' closed')}\n aria-label={navOpen ? '收起群组导航栏' : '展开群组导航栏'}\n title={navOpen ? '收起群组导航栏' : '展开群组导航栏'}\n aria-expanded={navOpen}\n onClick={() => { setNavOpen(!navOpen) }}\n >\n {Icon(P.IconChevronLeftOutline14, 16)}\n </button>\n <button\n type=\"button\"\n className={'dsgc-seambtn right' + (asideOpen ? '' : ' closed')}\n aria-label={asideOpen ? '收起成员与工作区栏' : '展开成员与工作区栏'}\n title={asideOpen ? '收起成员与工作区栏' : '展开成员与工作区栏'}\n aria-expanded={asideOpen}\n onClick={() => { setAsideOpen(!asideOpen) }}\n >\n {Icon(P.IconChevronRightOutline14, 16)}\n </button>\n \n <div className=\"dsgc-chathead\">\n <div className=\"dsgc-chathead-row\">\n {sess ? <span className=\"dsgc-sess-title\" title={'当前会话:' + sess.name}>{sess.name}</span> : null}\n <input\n className=\"dsgc-topic\"\n value={topicDraft === null ? (sess ? sess.topic : '') : topicDraft}\n placeholder=\"设置本会话主题(可选)…\"\n onChange={(e) => { setTopicDraft(e.target.value) }}\n onBlur={commitTopic}\n onKeyDown={(e) => { if (e.key === 'Enter') (e.target as HTMLInputElement).blur() }}\n />\n <P.Button variant=\"ghost\" size=\"sm\" className=\"dsgc-clearbtn\" title=\"清空当前会话的消息记录\" onClick={() => { if (sess) setConfirmClear(true) }}>\n 清空\n </P.Button>\n </div>\n </div>\n \n <div className=\"dsgc-msgs\" ref={scrollRef} onScroll={onMsgsScroll}>\n {sess && sess.messageIds.length > 0\n ? bubbles\n : (\n <div className=\"dsgc-empty\">\n {Icon(P.IconSparkle16, 20)}\n <div className=\"dsgc-emptytitle\">{sess && sess.topic ? '「' + sess.topic + '」' : '会话已就绪'}</div>\n <div className=\"dsgc-hint\">\n {enabledRoles.length\n ? '发送消息开始讨论;@成员 点名让其优先回应——每轮全体参与角色按顺序各发言一次,可用右下角轮数控制(1–10 轮)'\n : '先在右侧添加角色(每个角色可绑定不同模型),再回到这里发起讨论。'}\n </div>\n </div>\n )}\n </div>\n \n <Composer\n snap={snap}\n sess={sess}\n group={group}\n enabledRoles={enabledRoles}\n participants={participants}\n mentionedRoles={mentionedRoles}\n busyNow={busyNow}\n input={input}\n mention={mention}\n mentionCandidates={mentionCandidates}\n mentionIdxC={mentionIdxC}\n fileCandidates={fileCandidates}\n fileSearchError={fileSearchError}\n fileSearchLoading={fileSearchLoading}\n rounds={rounds}\n err={err}\n atBottom={atBottom}\n bubblesLength={sess?.messageIds.length || 0}\n inputRef={inputRef}\n scrollRef={scrollRef}\n setMentionIdx={setMentionIdx}\n setRounds={setRounds}\n togglePart={togglePart}\n onInputCE={onInputCE}\n onInputKeyDown={onInputKeyDown}\n onPasteCE={onPasteCE}\n onDropCE={onDropCE}\n onDragOverCE={onDragOverCE}\n insertChip={insertChip}\n insertFileChip={insertFileChip}\n sendMsg={sendMsg}\n stopRun={stopRun}\n mutate={mutate}\n setMention={setMention}\n />\n </section>\n )\n}\n","/**\n * 未发送草稿:按会话 id 分槽,模块级跨挂载存活。\n * 主会话⇄群聊会整页卸载 composer,contentEditable 的 HTML 必须自行记住。\n * @module dsh-group-chat/client/composer-draft\n */\n\nexport interface ComposerDraft {\n html: string\n text: string\n}\n\nconst LIMIT = 32\nconst drafts = new Map<string, ComposerDraft>()\n\nconst empty = (): ComposerDraft => ({ html: '', text: '' })\n\n/** 读指定会话草稿;命中则提到 LRU 最近端。 */\nexport function readComposerDraft(sessionId: string | null | undefined): ComposerDraft {\n if (!sessionId) return empty()\n const hit = drafts.get(sessionId)\n if (!hit) return empty()\n drafts.delete(sessionId)\n drafts.set(sessionId, hit)\n return hit\n}\n\n/** 写入;空草稿删槽。超出上限淘汰最旧槽。 */\nexport function writeComposerDraft(sessionId: string | null | undefined, html: string, text: string): void {\n if (!sessionId) return\n drafts.delete(sessionId)\n if (!html && !text) return\n drafts.set(sessionId, { html, text })\n if (drafts.size > LIMIT) {\n const oldest = drafts.keys().next().value\n if (oldest !== undefined) drafts.delete(oldest)\n }\n}\n\n/** 发送成功或明确丢弃时摘槽。 */\nexport function clearComposerDraft(sessionId: string | null | undefined): void {\n if (sessionId) drafts.delete(sessionId)\n}\n\n/** 测试用:清空全部槽位。 */\nexport function resetComposerDrafts(): void {\n drafts.clear()\n}\n","/**\n * 群聊面板核心状态管理 hook\n * @module dsh-group-chat/client/hooks\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { api } from '../lib/api.ts'\nimport { readComposerDraft } from '../lib/composer-draft.ts'\nimport type { ClientSnapshot, ModelsResponse, RoleDraft } from '../lib/model.ts'\nimport type { AtToken } from '../../shared/file-mention-grammar.ts'\n\nexport interface MutateResponse {\n ok: boolean\n snapshot?: ClientSnapshot\n lastCreated?: ClientSnapshot['lastCreated']\n error?: string\n}\n\nexport interface ActionOk {\n ok: boolean\n error?: string\n}\n\n/**\n * 面板切换缓存(模块级,跨挂载存活):main 为 keyed 槽,主会话⇄群聊切换会\n * 整体卸载重挂面板组件;缓存最近快照、选中项与按会话分槽的未发送草稿,\n * 让重挂载瞬时恢复上次视图。挂载后的 state 拉取 / SSE 首帧再行校正。\n */\nlet cachedSnap: ClientSnapshot | null = null\nlet cachedGid: string | null = null\nlet cachedSid: string | null = null\n\nexport function useGroupChatState() {\n // 核心数据快照(重挂载时从缓存瞬时恢复,消除切换闪现的加载态)\n const [snap, setSnap] = useState<ClientSnapshot | null>(() => cachedSnap)\n\n // 选中状态\n const [gid, setGid] = useState<string | null>(() => cachedGid)\n const [sid, setSid] = useState<string | null>(() => cachedSid)\n\n /** 已应用过的 lastCreated 会话标记:只在标记变化(真正的新建)时跟随选中,\n 而不是每帧都把视图拽回「最近创建的会话」(流式期间每 120ms 一帧)。 */\n const appliedCreatedRef = useRef<string | null>(cachedSnap?.lastCreated?.sessionId ?? null)\n\n /** 快照落地统一口:写状态 + 写切换缓存。 */\n const applySnap = useCallback((s: ClientSnapshot): void => {\n cachedSnap = s\n setSnap(s)\n }, [])\n\n /** 选中项统一口:写状态 + 写切换缓存(重挂载恢复到用户离开时的位置)。 */\n const selectGroup = useCallback((v: string): void => {\n cachedGid = v\n setGid(v)\n }, [])\n const selectSession = useCallback((v: string): void => {\n cachedSid = v\n setSid(v)\n }, [])\n \n // UI 状态\n const [search, setSearch] = useState('')\n const [collapsedGroups, setCollapsedGroups] = useState<Set<string>>(() => new Set())\n const [asideOpen, setAsideOpen] = useState(true)\n const [navOpen, setNavOpen] = useState(true)\n const [atBottom, setAtBottom] = useState(true)\n \n // 编辑态\n const [renameDraft, setRenameDraft] = useState<{ kind: 'group' | 'session', id: string, value: string } | null>(null)\n const [confirmDel, setConfirmDel] = useState<{ kind: 'group' | 'session', id: string } | null>(null)\n const [confirmClear, setConfirmClear] = useState(false)\n const [topicDraft, setTopicDraft] = useState<string | null>(null)\n\n // 角色编辑(models 目录与保存/校验态在 RoleDrawer 内自理)\n const [roleDraft, setRoleDraft] = useState<RoleDraft | null>(null)\n const [models, setModels] = useState<ModelsResponse | null>(null)\n const [modelsError, setModelsError] = useState<string | null>(null)\n \n // 参与角色选择\n const [partsSel, setPartsSel] = useState<string[] | null>(null)\n const [rounds, setRounds] = useState(1)\n \n // 输入与 @提及(文本初值取当前选中会话草稿,HTML 由 useComposerDraft 灌回)\n const [input, setInput] = useState(() => readComposerDraft(cachedSid).text)\n const [mention, setMention] = useState<AtToken | null>(null)\n const [mentionIdx, setMentionIdx] = useState(0)\n \n // 错误提示\n const [err, setErr] = useState('')\n \n // Refs\n const inputRef = useRef<HTMLDivElement | null>(null)\n const sendingRef = useRef(false)\n const scrollRef = useRef<HTMLDivElement | null>(null)\n\n // 初始加载 + SSE 订阅\n useEffect(() => {\n let live = true\n api.state().then((s) => {\n if (live && s && (s as ClientSnapshot).ok) applySnap(s as ClientSnapshot)\n }).catch(() => { /* SSE 会重试 */ })\n const events = new EventSource('/api/group-chat/events')\n events.onmessage = (message) => {\n try {\n const s = JSON.parse(message.data) as ClientSnapshot\n if (!live || !s || !s.ok) return\n // lastCreated 仅在变化时跟随选中(新建群组/会话的定位信号);\n // 帧里重复携带的旧标记不再反复重置视图\n if (s.lastCreated && s.lastCreated.sessionId && s.lastCreated.sessionId !== appliedCreatedRef.current) {\n appliedCreatedRef.current = s.lastCreated.sessionId\n selectGroup(s.lastCreated.groupId)\n selectSession(s.lastCreated.sessionId)\n setPartsSel(null)\n }\n applySnap(s)\n } catch { /* ignore malformed frame */ }\n }\n return () => {\n live = false\n events.close()\n }\n }, [applySnap, selectGroup, selectSession])\n\n // API 操作封装\n const action = useCallback(async (payload: Record<string, unknown>): Promise<unknown> => {\n try {\n return await api.action(payload)\n } catch (e) {\n setErr(String((e && (e as Error).message) || e))\n return null\n }\n }, [])\n\n const mutate = async (args: Record<string, unknown>): Promise<MutateResponse | null> => {\n setErr('')\n const res = await action(Object.assign({ kind: 'mutate' }, args)) as MutateResponse | null\n if (res && res.ok && res.snapshot) {\n // 响应里的 lastCreated 是服务端当前值(未必由本次调用产生)——同样只在\n // 变化时跟随选中,避免改名/改配置等普通 mutate 把视图拽走\n if (res.lastCreated && res.lastCreated.sessionId && res.lastCreated.sessionId !== appliedCreatedRef.current) {\n appliedCreatedRef.current = res.lastCreated.sessionId\n selectGroup(res.lastCreated.groupId)\n selectSession(res.lastCreated.sessionId)\n setPartsSel(null)\n }\n applySnap(res.snapshot)\n if (res.snapshot.error) setErr(res.snapshot.error)\n }\n return res\n }\n\n return {\n // 状态\n snap,\n setSnap: applySnap,\n gid,\n setGid: selectGroup,\n sid,\n setSid: selectSession,\n search,\n setSearch,\n collapsedGroups,\n setCollapsedGroups,\n renameDraft,\n setRenameDraft,\n confirmDel,\n setConfirmDel,\n confirmClear,\n setConfirmClear,\n roleDraft,\n setRoleDraft,\n models,\n setModels,\n modelsError,\n setModelsError,\n partsSel,\n setPartsSel,\n rounds,\n setRounds,\n input,\n setInput,\n err,\n setErr,\n topicDraft,\n setTopicDraft,\n mention,\n setMention,\n mentionIdx,\n setMentionIdx,\n asideOpen,\n setAsideOpen,\n navOpen,\n setNavOpen,\n atBottom,\n setAtBottom,\n // Refs\n inputRef,\n sendingRef,\n scrollRef,\n // 方法\n action,\n mutate,\n }\n}\n","/**\n * Vendored @file token grammar from dsh-file-reference (browser-safe, zero Node API).\n *\n * Sourced from @deepseek-ai/dsh-file-reference/lib/types/grammar.js\n * Cannot import directly due to client bundle purity gate (dsh-client-bundle-purity).\n *\n * 只保留输入侧的 @token 识别(activeAtToken);候选的文本化(formatFileMention)\n * 未被本插件采用——目录钻入走「插入整颗芯片」语义,见 docs/DESIGN.md Composer 契约。\n *\n * @module dsh-group-chat/shared\n */\n\nexport interface AtToken {\n /** Full matched prefix including @ and optional quotes */\n prefix: string\n /** Query fragment after @ (unquoted content) */\n query: string\n /** Whether the token uses quoted form @\"...\" */\n quoted: boolean\n}\n\n/**\n * Extract active @token at cursor position.\n * Matches @ at word boundary (line start or after whitespace).\n *\n * @param line - Current line text\n * @param cursor - Cursor offset in line\n * @returns Token or undefined if no active @token at cursor\n */\nexport function activeAtToken(line: string, cursor: number): AtToken | undefined {\n const before = line.slice(0, cursor)\n\n // Try quoted @\"... first (more specific)\n const quotedMatch = /(?:^|\\s)@\"([^\"]*)$/.exec(before)\n if (quotedMatch) {\n const prefix = quotedMatch[0].trimStart()\n return {\n prefix,\n query: quotedMatch[1],\n quoted: true,\n }\n }\n\n // Then try plain @...\n const plainMatch = /(?:^|\\s)@([^\\s@]*)$/.exec(before)\n if (plainMatch) {\n const prefix = plainMatch[0].trimStart()\n return {\n prefix,\n query: plainMatch[1],\n quoted: false,\n }\n }\n\n return undefined\n}\n","/**\n * 通用工具函数\n * @module dsh-group-chat/client/utils\n */\n\nimport { createElement } from 'react'\nimport { flushSync } from 'react-dom'\nimport { createRoot } from 'react-dom/client'\nimport { FileTypeIcon } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { activeAtToken, type AtToken } from '../../shared/file-mention-grammar.ts'\n\n/** HTML 转义(芯片以 execCommand('insertHTML') 注入,角色名需转义)。 */\nexport function escapeHtml(v: string): string {\n return String(v).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;')\n}\n\n/**\n * execCommand 集中封装。它已被 Web 平台标记 @deprecated(ts 6387 编辑器提示),\n * 但仍是唯一能让 contenteditable 的 DOM 编辑进入浏览器原生 undo 栈的同步 API\n * (自研 undo 栈或引入 Lexical/ProseMirror 类框架代价更大;取舍见 DESIGN.md\n * Composer 契约)。经中间别名擦除废弃标记,全部调用走本封装,不在调用处散布提示。\n */\ntype ExecCommandFn = (commandId: string, showUI?: boolean, value?: string) => boolean\nlet execCommandFn: ExecCommandFn | undefined\nexport function execCommand(commandId: 'delete' | 'insertHTML' | 'insertText' | 'insertLineBreak', value?: string): boolean {\n execCommandFn ??= (document as unknown as { execCommand: ExecCommandFn }).execCommand\n return execCommandFn.call(document, commandId, false, value)\n}\n\n/**\n * contenteditable 输入区 → 纯文本序列化(发送/参与判定的唯一事实源):\n * 文本节点原样;<br> → 换行;角色芯片(.dsgc-chipin[data-role-id])展开回「@名字␠」;\n * 文件芯片(.dsgc-chipin[data-kind=file])展开回「@path」或「@\"path with spaces\"」;\n * DIV/P 块前补换行(防粘贴残留的块级包裹)。\n */\nexport function serializeInput(root: HTMLElement): string {\n const walk = (node: Node): string => {\n if (node.nodeType === Node.TEXT_NODE) return node.nodeValue || ''\n if (node.nodeType !== Node.ELEMENT_NODE) return ''\n const el = node as HTMLElement\n if (el.tagName === 'BR') return '\\n'\n if (el.classList.contains('dsgc-chipin')) {\n // 角色芯片\n if (el.dataset.roleId) {\n return '@' + (el.dataset.name || '') + ' '\n }\n // 文件芯片\n if (el.dataset.kind === 'file') {\n const path = el.dataset.path || ''\n const needsQuote = /\\s/.test(path)\n return needsQuote ? `@\"${path}\"` : `@${path}`\n }\n }\n const sep = /^(DIV|P)$/.test(el.tagName) ? '\\n' : ''\n return sep + Array.from(el.childNodes).map(walk).join('')\n }\n return Array.from(root.childNodes).map(walk).join('')\n}\n\n/** @角色芯片的 HTML(原子元素:contenteditable=false + draggable,退格整删;fresh=插入后需营救选区,加 data-new 标记)。 */\nexport function chipHtml(role: { id: string, name: string, color?: string }, fresh = false): string {\n const c = escapeHtml(role.color || '#888')\n return '<span class=\"dsgc-chipin\"' + (fresh ? ' data-new=\"\"' : '') + ' data-role-id=\"' + escapeHtml(role.id) + '\" data-name=\"' + escapeHtml(role.name) + '\" style=\"--role-color:' + c + '\" contenteditable=\"false\" draggable=\"true\">' +\n '<span class=\"dsgc-chipdot\" style=\"background:' + c + '\"></span>' + escapeHtml(role.name) + '</span>'\n}\n\n/** 把宿主 FileTypeIcon 渲成静态 SVG,再塞进 insertHTML(与检索列表同一套字形)。 */\nfunction fileTypeIconMarkup(path: string, kind: 'file' | 'directory'): string {\n if (typeof document === 'undefined') return ''\n const host = document.createElement('span')\n const root = createRoot(host)\n try {\n flushSync(() => {\n root.render(kind === 'directory'\n ? createElement(FileTypeIcon, { kind: 'folder', size: 14 })\n : createElement(FileTypeIcon, { path, size: 14 }))\n })\n return host.innerHTML\n } finally {\n root.unmount()\n }\n}\n\n/** @文件芯片的 HTML(原子元素:contenteditable=false + draggable,退格整删;fresh 同 chipHtml)。 */\nexport function fileChipHtml(path: string, kind: 'file' | 'directory', fresh = false): string {\n const basename = path.split('/').pop() || path\n const dir = kind === 'directory'\n return '<span class=\"dsgc-chipin dsgc-chipin-file\"' + (fresh ? ' data-new=\"\"' : '') + ' data-kind=\"file\"' + (dir ? ' data-dir=\"1\"' : '') + ' data-path=\"' + escapeHtml(path) + '\" contenteditable=\"false\" draggable=\"true\">' +\n '<span class=\"dsgc-chipglyph\" aria-hidden=\"true\">' + fileTypeIconMarkup(path, kind) + '</span>' + escapeHtml(basename) + '</span>'\n}\n\n/**\n * 光标前的活跃 @token(角色或文件弹层触发判定)。\n * \n * @returns AtToken 对象,包含 prefix/query/quoted;无返回 null\n */\nexport function queryAtCaret(): AtToken | null {\n const sel = window.getSelection()\n if (!sel || !sel.isCollapsed || sel.rangeCount === 0) return null\n const node = sel.anchorNode\n if (!node || node.nodeType !== Node.TEXT_NODE) return null\n const before = (node.nodeValue || '').slice(0, sel.anchorOffset)\n return activeAtToken(before, before.length) || null\n}\n","/**\n * 消息输入相关 hooks\n * @module dsh-group-chat/client/hooks\n */\n\nimport { useCallback, useEffect, useLayoutEffect, useRef, type ClipboardEvent as ReactClipboardEvent, type DragEvent as ReactDragEvent, type KeyboardEvent as ReactKeyboardEvent } from 'react'\nimport { execCommand, queryAtCaret, serializeInput, chipHtml, fileChipHtml } from '../utils/utils.ts'\nimport { readComposerDraft, writeComposerDraft } from '../lib/composer-draft.ts'\nimport type { AtToken } from '../../shared/file-mention-grammar.ts'\nimport type { SnapshotRole } from '../lib/model.ts'\n\nexport function useComposerEffects(\n inputRef: React.RefObject<HTMLDivElement>,\n scrollRef: React.RefObject<HTMLDivElement>,\n input: string,\n atBottom: boolean,\n snap: unknown,\n) {\n // 贴底时新内容自动跟随滚动\n const onMsgsScroll = useCallback(() => {\n const el = scrollRef.current\n if (!el) return\n const isAtBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 60\n return isAtBottom\n }, [scrollRef])\n\n useEffect(() => {\n const el = scrollRef.current\n if (el && atBottom) el.scrollTop = el.scrollHeight\n }, [snap, atBottom, scrollRef])\n\n // composer 输入框随内容自适应高度\n useEffect(() => {\n const el = inputRef.current\n if (!el) return\n el.style.height = 'auto'\n el.style.height = Math.min(180, Math.max(36, el.scrollHeight)) + 'px'\n }, [input, inputRef])\n\n return { onMsgsScroll }\n}\n\nexport function useComposerInput(\n inputRef: React.RefObject<HTMLDivElement>,\n setInput: (val: string) => void,\n setMention: (val: AtToken | null) => void,\n setMentionIdx: (val: number) => void,\n sessionId?: string | null,\n) {\n const sessionIdRef = useRef(sessionId)\n sessionIdRef.current = sessionId\n\n /** 从 DOM 同步 input 状态(序列化),并写入当前会话草稿槽。 */\n const syncFromDOM = useCallback((): void => {\n const el = inputRef.current\n if (!el) return\n const text = serializeInput(el)\n setInput(text)\n writeComposerDraft(sessionIdRef.current, el.innerHTML, text)\n }, [inputRef, setInput])\n\n const onInputCE = useCallback((): void => {\n syncFromDOM()\n setMention(queryAtCaret())\n setMentionIdx(0)\n }, [syncFromDOM, setMention, setMentionIdx])\n\n /** 粘贴/拖放强制纯文本 */\n const onPasteCE = useCallback((e: ReactClipboardEvent<HTMLDivElement>): void => {\n e.preventDefault()\n const text = e.clipboardData.getData('text/plain')\n if (text) execCommand('insertText', text)\n }, [])\n\n const onDragOverCE = useCallback((e: ReactDragEvent<HTMLDivElement>): void => {\n e.preventDefault()\n }, [])\n\n const onDropCE = useCallback((e: ReactDragEvent<HTMLDivElement>): void => {\n e.preventDefault()\n const text = e.dataTransfer.getData('text/plain')\n if (text) execCommand('insertText', text)\n }, [])\n\n return {\n syncFromDOM,\n onInputCE,\n onPasteCE,\n onDragOverCE,\n onDropCE,\n }\n}\n\n/**\n * 按会话恢复草稿:切会话时先把当前 HTML 写入旧槽,再灌入新槽;\n * 面板重挂载(主会话⇄群聊)时 editor 是新节点,从模块缓存灌回。\n */\nexport function useComposerDraft(\n sessionId: string | null | undefined,\n inputRef: React.RefObject<HTMLDivElement>,\n setInput: (val: string) => void,\n setMention: (val: AtToken | null) => void,\n): void {\n const prevIdRef = useRef<string | null>(null)\n useLayoutEffect(() => {\n const el = inputRef.current\n const prev = prevIdRef.current\n const next = sessionId || null\n if (el && prev && prev !== next) writeComposerDraft(prev, el.innerHTML, serializeInput(el))\n prevIdRef.current = next\n if (!next) return\n const draft = readComposerDraft(next)\n if (el) el.innerHTML = draft.html\n setInput(draft.text)\n setMention(null)\n return () => {\n const node = inputRef.current\n const id = prevIdRef.current\n if (node && id) writeComposerDraft(id, node.innerHTML, serializeInput(node))\n }\n }, [sessionId, inputRef, setInput, setMention])\n}\n\nexport function useMentionChip(\n inputRef: React.RefObject<HTMLDivElement>,\n setMention: (val: AtToken | null) => void,\n setMentionIdx: (val: number) => void,\n syncFromDOM: () => void,\n) {\n /** 弹层候选 → 删掉光标前的 @词、插入带 data-new 标记的芯片 + 尾随空格。 */\n const insertChipHtml = useCallback((html: string): void => {\n const el = inputRef.current\n const sel = window.getSelection()\n if (!el || !sel) return\n if (!sel.anchorNode || !el.contains(sel.anchorNode)) return\n el.focus({ preventScroll: true })\n\n // 1. 删除光标前的 @token(包括引号)\n const node = sel.anchorNode\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.nodeValue || ''\n const off = sel.anchorOffset\n const before = text.slice(0, off)\n // 匹配 @词 或 @\"词\n const m = /(?:^|\\s)@(\"?)([^\"\\s@]*)$/.exec(before)\n if (m) {\n const prefixLen = m[1] ? 2 : 1 // @\" 或 @\n const queryLen = m[2].length\n const start = off - prefixLen - queryLen\n if (start >= 0) {\n const range = document.createRange()\n range.setStart(node, start)\n range.setEnd(node, off)\n sel.removeAllRanges()\n sel.addRange(range)\n execCommand('delete')\n }\n }\n }\n\n // 2. 插入芯片(fresh 标记:部分浏览器把选区落进 contenteditable=false 芯片内部,\n // 曾致空格丢失与光标不可见)\n execCommand('insertHTML', html)\n const chip = el.querySelector<HTMLElement>('.dsgc-chipin[data-new]')\n if (!chip) return\n\n // 3. 选区显式钉到芯片之后,再补尾随空格\n const after = document.createRange()\n after.setStartAfter(chip)\n after.collapse(true)\n sel.removeAllRanges()\n sel.addRange(after)\n execCommand('insertText', ' ')\n chip.removeAttribute('data-new')\n setMention(null)\n setMentionIdx(0)\n syncFromDOM()\n }, [inputRef, setMention, setMentionIdx, syncFromDOM])\n\n const insertChip = useCallback((role: SnapshotRole): void => {\n insertChipHtml(chipHtml(role, true))\n }, [insertChipHtml])\n\n const insertFileChip = useCallback((path: string, kind: 'file' | 'directory'): void => {\n insertChipHtml(fileChipHtml(path, kind, true))\n }, [insertChipHtml])\n\n return { insertChip, insertFileChip }\n}\n\nexport function useInputKeyboard(\n mention: AtToken | null,\n mentionCandidates: SnapshotRole[],\n mentionIdxC: number,\n setMentionIdx: (val: number | ((prev: number) => number)) => void,\n insertChip: (role: SnapshotRole) => void,\n insertFileChip: (path: string, kind: 'file' | 'directory') => void,\n fileCandidates: Array<{ path: string; isDir: boolean }>,\n setMention: (val: AtToken | null) => void,\n sendMsg: () => Promise<void>,\n) {\n const onInputKeyDown = useCallback((e: ReactKeyboardEvent<HTMLDivElement>): void => {\n // IME 组合中的按键不参与任何快捷逻辑\n if (e.nativeEvent.isComposing || e.keyCode === 229) return\n \n // 角色模式(裸 @):Enter/Tab 插入角色芯片\n if (mention !== null && mention.query === '' && mentionCandidates.length) {\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setMentionIdx((mentionIdxC + 1) % mentionCandidates.length)\n return\n }\n if (e.key === 'ArrowUp') {\n e.preventDefault()\n setMentionIdx((mentionIdxC - 1 + mentionCandidates.length) % mentionCandidates.length)\n return\n }\n if ((e.key === 'Enter' && !e.shiftKey) || e.key === 'Tab') {\n e.preventDefault()\n insertChip(mentionCandidates[mentionIdxC])\n return\n }\n }\n \n // 文件模式(@ + query):Enter 插入文件/Tab 钻入目录/Esc 关闭\n if (mention !== null && mention.query !== '' && fileCandidates.length) {\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setMentionIdx((mentionIdxC + 1) % fileCandidates.length)\n return\n }\n if (e.key === 'ArrowUp') {\n e.preventDefault()\n setMentionIdx((mentionIdxC - 1 + fileCandidates.length) % fileCandidates.length)\n return\n }\n const selectedItem = fileCandidates[mentionIdxC]\n if (selectedItem) {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n insertFileChip(selectedItem.path, selectedItem.isDir ? 'directory' : 'file')\n return\n }\n if (e.key === 'Tab' && selectedItem.isDir) {\n e.preventDefault()\n insertFileChip(selectedItem.path, 'directory')\n return\n }\n }\n if (e.key === 'Escape') {\n e.preventDefault()\n setMention(null)\n return\n }\n }\n \n if (e.key === 'Enter' && e.shiftKey) {\n e.preventDefault()\n execCommand('insertLineBreak')\n return\n }\n \n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n void sendMsg()\n }\n }, [mention, mentionCandidates, mentionIdxC, fileCandidates, setMentionIdx, insertChip, insertFileChip, setMention, sendMsg])\n\n return { onInputKeyDown }\n}\n","/**\n * 文件搜索 hook:防抖 + 取消过期请求 + 短缓存。\n * @module dsh-group-chat/client/hooks\n */\n\nimport { useEffect, useState } from 'react'\nimport { api } from '../lib/api.ts'\nimport type { AtToken } from '../../shared/file-mention-grammar.ts'\n\nexport interface FileCandidate {\n path: string\n isDir: boolean\n}\n\nexport interface FileSearchResult {\n fileCandidates: FileCandidate[]\n fileSearchError: string | null\n fileSearchLoading: boolean\n}\n\nconst DEBOUNCE_MS = 180\nconst CACHE_LIMIT = 20\nconst cache = new Map<string, FileCandidate[]>()\n\nfunction cacheGet(key: string): FileCandidate[] | undefined {\n const hit = cache.get(key)\n if (!hit) return undefined\n cache.delete(key)\n cache.set(key, hit)\n return hit\n}\n\nfunction cacheSet(key: string, value: FileCandidate[]): void {\n cache.delete(key)\n cache.set(key, value)\n if (cache.size > CACHE_LIMIT) {\n const oldest = cache.keys().next().value\n if (oldest !== undefined) cache.delete(oldest)\n }\n}\n\nfunction isAbort(err: unknown): boolean {\n return !!err && typeof err === 'object' && 'name' in err && (err as { name: string }).name === 'AbortError'\n}\n\n/**\n * 文件搜索:query 变化 180ms 内合并;过期 fetch 真正 abort;\n * 命中短缓存立刻出结果。离开文件模式才清空列表,避免每个按键闪「检索中」。\n */\nexport function useFileSearch(\n mention: AtToken | null,\n groupId: string | undefined,\n): FileSearchResult {\n const [fileCandidates, setFileCandidates] = useState<FileCandidate[]>([])\n const [fileSearchError, setFileSearchError] = useState<string | null>(null)\n const [fileSearchLoading, setFileSearchLoading] = useState(false)\n\n const query = mention && mention.query !== '' ? mention.query : null\n\n useEffect(() => {\n if (query === null || !groupId) {\n setFileCandidates([])\n setFileSearchError(null)\n setFileSearchLoading(false)\n return\n }\n\n const key = groupId + '\\0' + query\n const hit = cacheGet(key)\n if (hit) {\n setFileCandidates(hit)\n setFileSearchError(null)\n setFileSearchLoading(false)\n return\n }\n\n const controller = new AbortController()\n setFileSearchLoading(true)\n const timer = window.setTimeout(() => {\n void (async () => {\n try {\n const res = await api.action({\n kind: 'fileSearch',\n groupId,\n query,\n }, controller.signal) as { ok: true, candidates?: FileCandidate[] } | { ok: false, error?: string }\n\n if (controller.signal.aborted) return\n if (res.ok) {\n const next = res.candidates || []\n cacheSet(key, next)\n setFileCandidates(next)\n setFileSearchError(null)\n } else {\n setFileCandidates([])\n setFileSearchError(res.error || '文件检索失败')\n }\n } catch (err) {\n if (controller.signal.aborted || isAbort(err)) return\n setFileCandidates([])\n setFileSearchError(String(err))\n } finally {\n if (!controller.signal.aborted) setFileSearchLoading(false)\n }\n })()\n }, DEBOUNCE_MS)\n\n return () => {\n window.clearTimeout(timer)\n controller.abort()\n }\n }, [query, groupId])\n\n return { fileCandidates, fileSearchError, fileSearchLoading }\n}\n","/**\n * 提及状态 hook:封装角色/文件提及相关的派生状态计算\n * @module dsh-group-chat/client/hooks\n */\n\nimport { useMemo } from 'react'\nimport { escapeRegExp, type SnapshotRole } from '../lib/model.ts'\nimport type { AtToken } from '../../shared/file-mention-grammar.ts'\n\n/**\n * 计算角色提及候选列表\n * @param mention - 当前 @ token 状态\n * @param enabledRoles - 启用的角色列表\n * @returns 角色候选列表(仅在角色模式且 query 为空时返回)\n */\nexport function useMentionCandidates(\n mention: AtToken | null,\n enabledRoles: SnapshotRole[],\n): SnapshotRole[] {\n return useMemo(() => {\n // 角色模式:仅当 mention 存在且 query 为空时显示全部启用角色\n return mention !== null && mention.query === '' ? enabledRoles : []\n }, [mention, enabledRoles])\n}\n\n/**\n * 检测输入文本中被 @ 的角色\n * @param input - 输入文本\n * @param enabledRoles - 启用的角色列表\n * @returns 被提及的角色列表\n */\nexport function useMentionedRoles(\n input: string,\n enabledRoles: SnapshotRole[],\n): SnapshotRole[] {\n return useMemo(() => {\n return enabledRoles.filter((r) =>\n new RegExp('(^|\\\\s)@' + escapeRegExp(r.name) + '(?=\\\\s|$)').test(input)\n )\n }, [input, enabledRoles])\n}\n\n/**\n * 计算安全的候选索引(确保不越界)\n * @param candidatesLength - 候选列表长度\n * @param currentIndex - 当前索引\n * @returns 安全的索引值\n */\nexport function useSafeMentionIndex(\n candidatesLength: number,\n currentIndex: number,\n): number {\n return useMemo(() => {\n return candidatesLength ? Math.min(currentIndex, candidatesLength - 1) : 0\n }, [candidatesLength, currentIndex])\n}\n","/**\n * 主面板:三区工作台——左导航栏(搜索 + 群组→会话目录树)、中央会话流\n * (@成员 点名 + markdown 渲染 + 思考折叠)、右上下文栏(群成员角色卡 +\n * 工作区目录),右栏可收起,角色编辑走右侧滑出抽屉。\n *\n * 面板数据走 /api/group-chat/*(fetch + SSE),Host 半持有全部状态。\n * @module dsh-group-chat/client/panel\n */\n\nimport { useCallback, useEffect, useState, type ReactNode } from 'react'\nimport { Icon, P } from './lib/ui.ts'\nimport { api } from './lib/api.ts'\nimport { RoleDrawer } from './components/RoleDrawer.tsx'\nimport { NavPanel } from './components/NavPanel.tsx'\nimport { AsidePanel } from './components/AsidePanel.tsx'\nimport { ChatPanel } from './components/ChatPanel.tsx'\nimport { useGroupChatState, type ActionOk } from './hooks/useGroupChatState.ts'\nimport { useComposerEffects, useComposerInput, useComposerDraft, useMentionChip, useInputKeyboard } from './hooks/useComposer.ts'\nimport { useFileSearch } from './hooks/useFileSearch.ts'\nimport { useMentionCandidates, useMentionedRoles, useSafeMentionIndex } from './hooks/useMentionState.ts'\nimport { clearComposerDraft } from './lib/composer-draft.ts'\nimport { draftFromRole, blankDraft, groupById, roleById, sessById, type ClientSnapshot, type ModelsResponse, type SnapshotRole } from './lib/model.ts'\n\nexport function GroupChatPanel(): ReactNode {\n const state = useGroupChatState()\n const {\n snap,\n gid,\n setGid,\n sid,\n setSid,\n search,\n setSearch,\n collapsedGroups,\n setCollapsedGroups,\n renameDraft,\n setRenameDraft,\n confirmDel,\n setConfirmDel,\n confirmClear,\n setConfirmClear,\n roleDraft,\n setRoleDraft,\n models,\n setModels,\n modelsError,\n setModelsError,\n partsSel,\n setPartsSel,\n rounds,\n setRounds,\n input,\n setInput,\n err,\n setErr,\n topicDraft,\n setTopicDraft,\n mention,\n setMention,\n mentionIdx,\n setMentionIdx,\n asideOpen,\n setAsideOpen,\n navOpen,\n setNavOpen,\n atBottom,\n setAtBottom,\n inputRef,\n sendingRef,\n scrollRef,\n action,\n mutate,\n } = state\n\n // 瞬时通知(toast):key 为展示序号,同文案重复触发也会重启动画\n const [toast, setToast] = useState<{ text: string, seq: number } | null>(null)\n\n // ---- 所有 Hooks 必须在条件返回之前调用 ----\n // Composer effects\n const { onMsgsScroll } = useComposerEffects(inputRef, scrollRef, input, atBottom, snap)\n\n // 选中群组/会话解析(用于 hooks 依赖)\n let group = snap && gid ? groupById(snap, gid) : null\n if (!group && snap && snap.groups.length) group = snap.groups[0]\n let sess = snap && sid ? sessById(snap, sid) : null\n // 有效会话统一兜底(与渲染体一致):sid 未建立/未命中/跨群不匹配时取当前群组\n // 最后一个会话——必须在 busyNow 等 run 派生值之前完成,否则流式行/停止按钮\n // 在兜底视图(典型:host 重启后 lastCreated 为空、选中态从未建立)下永远失活\n if ((!sess || sess.groupId !== group?.id) && group && snap) {\n sess = group.sessionIds.length ? sessById(snap, group.sessionIds[group.sessionIds.length - 1]) : null\n }\n\n const { syncFromDOM, onInputCE, onPasteCE, onDragOverCE, onDropCE } = useComposerInput(inputRef, setInput, setMention, setMentionIdx, sess ? sess.id : null)\n useComposerDraft(sess ? sess.id : null, inputRef, setInput, setMention)\n\n const enabledRoles = group ? group.roleIds.map((id) => roleById(snap!, id)).filter((r): r is SnapshotRole => !!r && r.enabled) : []\n const participants = partsSel || enabledRoles.map((r) => r.id)\n const busyNow = !!(sess && snap && snap.run.running && snap.run.sessionId === sess.id)\n\n // 查看即清:当前选中会话即 run.finished 所指会话 → 发 ackFinish 确认已读\n // (host 幂等清除 + 广播;覆盖点击/键盘/重挂恢复/lastCreated 定位全部选中路径)\n const finishedRun = snap ? snap.run.finished : null\n useEffect(() => {\n if (finishedRun && sess && finishedRun.sessionId === sess.id) void mutate({ op: 'ackFinish' })\n }, [finishedRun, sess])\n\n // 提及状态:角色候选、文件搜索、索引安全化\n const mentionCandidates = useMentionCandidates(mention, enabledRoles)\n const { fileCandidates, fileSearchError, fileSearchLoading } = useFileSearch(\n mention,\n group?.id,\n )\n const mentionIdxC = useSafeMentionIndex(\n mentionCandidates.length || fileCandidates.length,\n mentionIdx\n )\n \n const mentionedRoles = useMentionedRoles(input, enabledRoles)\n\n const { insertChip, insertFileChip } = useMentionChip(inputRef, setMention, setMentionIdx, syncFromDOM)\n\n const sendMsg = useCallback(async (): Promise<void> => {\n if (busyNow || !sess || sendingRef.current) return\n // 空内容不可发送(按钮 disabled 之外,Enter 路径在此静默拦截)\n if (!input.trim()) return\n sendingRef.current = true\n try {\n if (!participants.length && !mentionedRoles.length) {\n setErr('请至少选择一个参与角色(或在消息中 @成员)')\n return\n }\n const parts = mentionedRoles.length ? mentionedRoles.map((r) => r.id) : participants\n const res = await action({ kind: 'send', sessionId: sess.id, text: input, participantRoleIds: parts, rounds }) as ActionOk | null\n if (res && !res.ok && res.error) setErr(res.error)\n else if (res && res.ok) {\n const el = inputRef.current\n if (el) el.innerHTML = ''\n setInput('')\n setMention(null)\n setErr('')\n setAtBottom(true)\n clearComposerDraft(sess.id)\n syncFromDOM()\n }\n } finally {\n sendingRef.current = false\n }\n }, [busyNow, sess, sendingRef, mentionedRoles, participants, action, rounds, input, inputRef, setInput, setMention, setErr, setAtBottom, syncFromDOM])\n\n const { onInputKeyDown } = useInputKeyboard(mention, mentionCandidates, mentionIdxC, setMentionIdx, insertChip, insertFileChip, fileCandidates, setMention, sendMsg)\n\n // ---- 条件性早期返回 ----\n if (!snap) {\n return (\n <div className=\"dsgc-root\">\n <div className=\"dsgc-loading\">{Icon(P.IconLoadingOutline16, 16)}加载中…</div>\n </div>\n )\n }\n\n if (!group) {\n return (\n <div className=\"dsgc-root\">\n <div className=\"dsgc-loading\">暂无群组</div>\n </div>\n )\n }\n\n const msgById: Record<string, ClientSnapshot['messages'][number]> = {}\n for (const m of snap.messages) msgById[m.id] = m\n\n const togglePart = (rid: string): void => {\n const has = participants.includes(rid)\n setPartsSel(has ? participants.filter((x) => x !== rid) : participants.concat([rid]))\n }\n\n const retrySpeak = async (messageId: string): Promise<void> => {\n if (!sess) return\n if (busyNow || (snap && snap.run.running)) {\n setToast({ text: '已有对话进行中,请先停止', seq: Date.now() })\n return\n }\n const res = await action({ kind: 'retrySpeak', sessionId: sess.id, messageId }) as ActionOk | null\n if (res && !res.ok && res.error) setToast({ text: res.error, seq: Date.now() })\n }\n\n // 清空确认:不可清空(对话进行中)走 toast 提示,不再落到输入框上方的红字\n const doClear = async (): Promise<void> => {\n if (!sess) return\n if (busyNow) {\n setToast({ text: '对话进行中,需先停止才能清空', seq: Date.now() })\n return\n }\n const res = await mutate({ op: 'clearMessages', sessionId: sess.id })\n if (res && res.ok && res.snapshot && !res.snapshot.error) setConfirmClear(false)\n else if (res && res.snapshot && res.snapshot.error) {\n setErr('')\n setToast({ text: res.snapshot.error, seq: Date.now() })\n }\n }\n\n // ---- 动作 ----\n const fetchModels = async (): Promise<void> => {\n try {\n const m = await api.action({ kind: 'models' }) as ModelsResponse\n if (m && m.ok && Array.isArray(m.providers)) {\n setModels(m)\n setModelsError(null)\n return\n }\n setModelsError(m && m.error ? String(m.error) : '响应异常')\n } catch (e) {\n setModelsError(String((e && (e as Error).message) || e))\n }\n }\n\n const openRoleEditor = async (role: SnapshotRole | null): Promise<void> => {\n setErr('')\n if (!models || modelsError) await fetchModels()\n setRoleDraft(role ? draftFromRole(role) : blankDraft())\n }\n\n const stopRun = async (): Promise<void> => {\n await action({ kind: 'stop', sessionId: sess!.id })\n }\n\n return (\n <div className=\"dsgc-root\">\n <NavPanel\n snap={snap}\n search={search}\n setSearch={setSearch}\n collapsedGroups={collapsedGroups}\n setCollapsedGroups={setCollapsedGroups}\n gid={group.id}\n sid={sess ? sess.id : sid}\n setGid={setGid}\n setSid={setSid}\n setPartsSel={setPartsSel}\n renameDraft={renameDraft}\n setRenameDraft={setRenameDraft}\n confirmDel={confirmDel}\n setConfirmDel={setConfirmDel}\n mutate={mutate}\n navOpen={navOpen}\n />\n <ChatPanel\n snap={snap}\n sess={sess}\n group={group}\n enabledRoles={enabledRoles}\n participants={participants}\n mentionedRoles={mentionedRoles}\n busyNow={busyNow}\n input={input}\n mention={mention}\n mentionCandidates={mentionCandidates}\n mentionIdxC={mentionIdxC}\n fileCandidates={fileCandidates}\n fileSearchError={fileSearchError}\n fileSearchLoading={fileSearchLoading}\n rounds={rounds}\n err={err}\n atBottom={atBottom}\n topicDraft={topicDraft}\n msgById={msgById}\n navOpen={navOpen}\n asideOpen={asideOpen}\n inputRef={inputRef}\n scrollRef={scrollRef}\n setTopicDraft={setTopicDraft}\n setConfirmClear={setConfirmClear}\n setMentionIdx={setMentionIdx}\n setRounds={setRounds}\n setNavOpen={setNavOpen}\n setAsideOpen={setAsideOpen}\n togglePart={togglePart}\n onMsgsScroll={() => {\n const isBottom = onMsgsScroll()\n if (isBottom !== undefined) setAtBottom(isBottom)\n }}\n onInputCE={onInputCE}\n onInputKeyDown={onInputKeyDown}\n onPasteCE={onPasteCE}\n onDropCE={onDropCE}\n onDragOverCE={onDragOverCE}\n insertChip={insertChip}\n insertFileChip={insertFileChip}\n sendMsg={sendMsg}\n stopRun={stopRun}\n action={action}\n mutate={mutate}\n setMention={setMention}\n onRetrySpeak={(messageId) => { void retrySpeak(messageId) }}\n />\n <AsidePanel\n snap={snap}\n group={group}\n asideOpen={asideOpen}\n mutate={mutate}\n openRoleEditor={openRoleEditor}\n />\n {sess && confirmClear\n ? (\n <P.Modal\n open\n onClose={() => { setConfirmClear(false) }}\n title=\"清空本会话的消息记录?\"\n closeLabel=\"关闭\"\n description={'会话「' + sess.name + '」的全部 ' + sess.messageIds.length + ' 条消息将被永久删除'}\n footer={(\n <>\n <P.Button variant=\"outline\" size=\"sm\" onClick={() => { setConfirmClear(false) }}>取消</P.Button>\n <P.Button variant=\"outline\" size=\"sm\" className=\"dsgc-stopbtn\" onClick={() => { void doClear() }}>清空</P.Button>\n </>\n )}\n >\n <ul className=\"dsgc-clearnotes\">\n <li>删除内容:本会话的用户消息与角色发言(含思考、工具调用记录)以及本会话结论/约束备忘,确认后立即落盘</li>\n <li>不可恢复:此操作没有回收站,也没有撤销</li>\n <li>不受影响:会话本身与主题、群成员角色、工作区目录、权限档位</li>\n </ul>\n </P.Modal>\n )\n : null}\n {toast\n ? (\n <P.Toast\n key={toast.seq}\n text={toast.text}\n icon={Icon(P.IconWarningOutline16, 16)}\n anchor={inputRef.current}\n onDone={() => { setToast(null) }}\n />\n )\n : null}\n {roleDraft\n ? (\n <RoleDrawer\n draft={roleDraft}\n set={setRoleDraft}\n groupId={group.id}\n models={models}\n modelsError={modelsError}\n onRetryModels={() => { void fetchModels() }}\n mutate={mutate}\n onCancel={() => { setRoleDraft(null) }}\n />\n )\n : null}\n </div>\n )\n}\n","/**\n * 设置页:启停开关(settings.section 插槽)。写 host 的 group-chat 设置\n * 命名空间(settings.yaml 持久化)。\n * @module dsh-group-chat/client/settings\n */\n\nimport { useEffect, useState, type ReactNode } from 'react'\nimport type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { P } from '../lib/ui.ts'\n\n/** Host 侧注册的设置命名空间 shape。 */\ninterface GroupChatSettings {\n enabled?: boolean\n}\n\nexport function GroupChatSettingsSection(props: { settingsScope: SettingsScope<GroupChatSettings> }): ReactNode {\n const scope = props.settingsScope\n const [snap, setSnap] = useState<ReturnType<SettingsScope<GroupChatSettings>['getSnapshot']> | null>(null)\n const [pending, setPending] = useState(false)\n\n useEffect(() => {\n let live = true\n const read = (): void => {\n if (!live) return\n try {\n setSnap(scope.getSnapshot())\n } catch { /* ignore */ }\n }\n read()\n const off = scope.subscribe(read)\n return () => {\n live = false\n off()\n }\n }, [])\n\n const ready = snap !== null && snap.status === 'ready'\n const writable = ready ? snap.writable !== false : false\n const enabled = ready ? (snap.value && snap.value.enabled) !== false : true\n\n const toggle = async (): Promise<void> => {\n if (!writable || pending) return\n setPending(true)\n try {\n await scope.set('enabled', !enabled)\n } catch (e) {\n console.error('[dsh-group-chat] settings write failed', e)\n } finally {\n setPending(false)\n }\n }\n\n return (\n <div className=\"dgcs-page\">\n <div className=\"dgcs-head\">\n <h3 className=\"dgcs-title\">模型群聊</h3>\n <p className=\"dgcs-desc\">多模型角色群组对话面板:每个角色绑定不同的 provider/model;群组内多会话目录树管理,群内共享对话记录与工作区目录;消息以 markdown 渲染、支持思考折叠;输入框支持 @成员 / @文件。数据持久化于 ~/.dsh/storages/group-chat/,重启 dsh web 后恢复。</p>\n </div>\n <div className=\"dgcs-card\">\n <div className=\"dgcs-cardtext\">\n <div className=\"dgcs-cardtitle\">{enabled ? '已启用' : '已停用'}</div>\n <div className=\"dgcs-cardhint\">{writable ? (enabled ? '关闭后侧边栏将不再显示「群聊」入口,进行中的对话会被中止。' : '开启后侧边栏显示「群聊」入口。') : '当前设置不可写(可能被配置文件覆盖)。'}</div>\n </div>\n <P.Switch\n checked={enabled}\n onChange={() => { void toggle() }}\n disabled={!writable || pending}\n label=\"模型群聊启停\"\n title={pending ? '正在写入…' : enabled ? '点击停用' : '点击启用'}\n />\n </div>\n </div>\n )\n}\n","/**\n * 侧边栏入口图标。\n *\n * 整行命中层携带 “newSession” 类名:任务看板等 DOM 注入式面板用\n * [class*=\"newSession\"] 识别“侧边栏导航点击”并自动收起自己,与点击\n * “新建会话”行为一致——类名不可哈希化。\n * @module dsh-group-chat/client/glyph\n */\n\nimport type { ReactNode } from 'react'\n\nexport function Glyph(props: { size?: number }): ReactNode {\n const size = (props && props.size) || 18\n return (\n <span className=\"dsgc-entryOverlay newSession\">\n <span className=\"dsgc-entryIcon\">\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n strokeWidth={1.8} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\" />\n <circle cx={9} cy={7} r={4} />\n <path d=\"M23 21v-2a4 4 0 0 0-3-3.87\" />\n <path d=\"M16 3.13a4 4 0 0 1 0 7.75\" />\n </svg>\n </span>\n </span>\n )\n}\n","/**\n * dsh-group-chat — 浏览器半(web 客户端模块)。\n *\n * 经 window.__ModuleLoader__.load 注册(由 tsdown 预设的 banner/footer 闭包\n * 工厂外壳生成);factory 返回 Cordis 客户端插件:\n * - 「模型群聊」设置页(settings.section):启停开关,写 host 的 group-chat\n * 设置命名空间(settings.yaml 持久化)\n * - 启用时挂载:侧边栏「群聊」入口(sidebar.panellist)+ 中央主面板(main)\n * - 面板数据走 /api/group-chat/*(fetch + SSE),Host 半持有全部状态\n * - DSW 原语(@deepseek-ai/dsh-client-ui-primitives,shell 静态种子模块)\n * 提供按钮/输入/开关/菜单/图标与 MarkdownText 渲染器\n *\n * 设计契约(impeccable direction contract;seed key 76db9e37,surface roll\n * 第 4/6/1 手中用户锁定 C「三区工作台」,代码先行):\n * THESIS 三区工作台;FIRST VIEWPORT 左 232px 导航 + 中央会话流 + 右 304px\n * 上下文栏(窄容器覆盖式、可收起)。完整契约见 docs/DESIGN.md。\n *\n * @module dsh-group-chat/client\n */\n\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only:拉入浏览器面的 Context 合并(ctx.settingsScope)。\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only:拉入 ctx.slots 合并(renderer 自 0.1.2 起拥有槽位注册表)。\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport { createElement as h } from 'react'\nimport { injectStyles } from './lib/styles.ts'\nimport { GroupChatPanel } from './GroupChatPanel.tsx'\nimport { GroupChatSettingsSection } from './components/GroupChatSettingsSection.tsx'\nimport { Glyph } from './components/Glyph.tsx'\n\n/** Host 侧注册的设置命名空间 shape 与命名名(与宿主半拼写同一值,两边不共享代码)。 */\ninterface GroupChatSettings {\n enabled?: boolean\n}\nconst SETTINGS_NAMESPACE = 'group-chat'\n\n/** Client plugin id. */\nexport const name = 'group-chat-client'\n\n/** Required services. */\nexport const inject = ['slots', 'settingsScope']\n\n/**\n * Shell 布局槽位的类型声明镜像(运行时由外壳的 layout/sidebar 包声明):\n * 中央主面板为 keyed 槽(按 key 挂载),侧边栏面板列表为 list 槽\n * (id + order + label)。参照 dsh-web 家族外部包的自声明模式。\n */\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface SlotMap {\n /** 中央主面板:按 key 挂载一个面板组件。 */\n 'main': { kind: 'keyed', scope: 'root', owner: Record<string, never> }\n /** 侧边栏面板列表行:图标 + 标签入口。 */\n 'sidebar.panellist': { kind: 'list', scope: 'root', owner: { size?: number } }\n }\n}\n\n/**\n * 客户端插件体:设置页常驻注册 + 启用门控挂载侧边栏入口与主面板。\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n injectStyles()\n\n const scope: SettingsScope<GroupChatSettings> = ctx.settingsScope.bind({ namespace: SETTINGS_NAMESPACE })\n\n // 设置页常驻注册(禁用时也保留入口,便于重新启用)\n ctx.slots.inject('settings.section', () =>\n ctx.slots.register(\n {\n name: 'settings.section',\n id: 'dsh-group-chat',\n order: 60,\n label: () => '模型群聊',\n inject: () => ({ settingsScope: scope }),\n },\n (props: { settingsScope: SettingsScope<GroupChatSettings> }) => h(GroupChatSettingsSection, props),\n ),\n )\n\n // 启用门控:enabled 为 false 时卸载侧边栏入口与主面板\n let uiDisposer: (() => void) | undefined\n const mountUi = (): void => {\n if (uiDisposer !== undefined) return\n const disposers: (() => void)[] = []\n try {\n disposers.push(ctx.slots.inject('main', () =>\n ctx.slots.register({ name: 'main', key: 'group-chat' }, () => h(GroupChatPanel, null))))\n disposers.push(ctx.slots.inject('sidebar.panellist', () =>\n ctx.slots.register({ name: 'sidebar.panellist', id: 'group-chat', order: 50, label: '群聊' }, (props: { size?: number }) => h(Glyph, props))))\n } catch (e) {\n console.error('[dsh-group-chat] mount failed:', e)\n }\n uiDisposer = () => {\n uiDisposer = undefined\n for (const dispose of disposers.splice(0)) dispose()\n }\n }\n const syncEnabled = (): void => {\n const snapshot = scope.getSnapshot()\n const on = snapshot.status === 'ready'\n ? (snapshot.value && snapshot.value.enabled) !== false\n : snapshot.status === 'unavailable'\n if (on) mountUi()\n else if (uiDisposer !== undefined) uiDisposer()\n }\n scope.subscribe(syncEnabled)\n syncEnabled()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASA,MAAM,SAAS;EAEf,MAAa,MAAM;GAEjB;GACA;GAGA;GACA;GACA;GAEA;GAKA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GAIA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAIA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAGA;GACA;GACA;GACA;GACA;GACA;GACA;GAKA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAIA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GAEA;GAIA;GAGA;GACA;GAIA;GAEA;GACA;GAKA;GACA;GAGA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAEA;GAGA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;G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"}