@y9931666/dsh-plugin-roundtable 1.0.0-rc.3 → 1.0.0-rc.6
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/README.md +9 -0
- package/lib/client.js +89 -19
- package/lib/index.js +38 -20
- package/lib/types/client/icons.d.ts +15 -0
- package/lib/types/version.d.ts +3 -3
- package/package.json +40 -40
- package/release-notes/v1.0.0-rc.4.md +26 -0
package/README.md
CHANGED
|
@@ -89,6 +89,15 @@
|
|
|
89
89
|
| **崩溃不再无声无息** | DSH 会静默摘掉渲染抛错的 slot 条目(隔离正确,但用户只看到"页签不见了")。两个界面入口现在都包在错误边界里:崩溃渲染成可读报错面板 + 控制台完整堆栈,可直接贴 issue。**客户端改动刷新页面即生效。** |
|
|
90
90
|
| **防回归闸门** | `test/inject.test.mjs` 直接对**构建产物**断言上述两条不变量(含"没有 connection 服务时仍必须注册两个入口"),旧产物必然失败。 |
|
|
91
91
|
|
|
92
|
+
### 视觉与布局(v1.0.0-rc.4)
|
|
93
|
+
| 改动 | 说明 |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| **设置页轻分组** | 刻意**不套卡片**:用「细线 + 组标题」分组,避免与针锋的卡片语言冲突。控件统一 32px 高 / 8px 圆角 / 320 宽,面板开关改为等宽网格。 |
|
|
96
|
+
| **拓扑节点名可读** | 显示时去掉专家共有的 `expert-` 前缀并允许两行(`expert-lifecycle` → `lifecycle`),完整 key 仍由悬停 `title` 提供。 |
|
|
97
|
+
| **连线可读性** | 专家间连线从最低对比边框色改为次级文字色,线宽 1.6、圆端点。 |
|
|
98
|
+
| **右栏面板** | 面板标题升为正文色 + 字距,内容内边距加大,面板间距 12px。 |
|
|
99
|
+
| **区块图标** | 设置页各分组标题前加 16×16 内联 SVG 图标(零依赖、随主题变色)。 |
|
|
100
|
+
|
|
92
101
|
### 界面操作
|
|
93
102
|
| 能力 | 说明 |
|
|
94
103
|
| --- | --- |
|
package/lib/client.js
CHANGED
|
@@ -100,7 +100,7 @@ const BRAND_LOGOS = {
|
|
|
100
100
|
|
|
101
101
|
//#endregion
|
|
102
102
|
//#region \0dsh-css:F:\AI\DSH\1changyong\dsh-plugin-roundtable\src\client\RoundTableView.module.css.mjs
|
|
103
|
-
const css$1 = ".dd3px29_root {\n display: flex;\n height: 100%;\n min-height: 0;\n gap: 12px;\n padding: 12px;\n overflow: hidden;\n}\n\n/* ---------- main column ---------- */\n\n.dd3px29_main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.dd3px29_header {\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex: none;\n}\n\n.dd3px29_titleRow {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.dd3px29_meetingName {\n font-size: 15px;\n font-weight: 600;\n}\n\n.dd3px29_meetingSelect {\n font-size: 12px;\n padding: 2px 6px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n max-width: 220px;\n}\n\n.dd3px29_badge {\n font-size: 11px;\n padding: 1px 8px;\n border-radius: 999px;\n border: 1px solid var(--dsw-alias-border-l2);\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_round {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 标题区「针锋相对」入口:可点击打开评审窗口 */\n.dd3px29_reviewBadge {\n font-size: 11px;\n padding: 2px 10px;\n border-radius: 999px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 6%, transparent);\n color: var(--dsw-alias-state-error-primary);\n cursor: pointer;\n font-weight: 600;\n transition: background 120ms ease;\n}\n\n.dd3px29_reviewBadge:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);\n}\n\n/* 右栏「分针记录」摘要卡片:可点击打开评审窗口 */\n.dd3px29_reviewCard {\n display: flex;\n flex-direction: column;\n gap: 4px;\n text-align: left;\n width: 100%;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 25%, transparent);\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 5%, transparent);\n padding: 8px 10px;\n cursor: pointer;\n transition: background 120ms ease;\n}\n\n.dd3px29_reviewCard:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.dd3px29_reviewCardTitle {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n line-height: 1.45;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.dd3px29_reviewCardMeta {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 会议删除按钮:固定在右栏顶部操作条(不再挤在标题行最右,窄屏也能看到)。 */\n.dd3px29_meetingDelete {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n padding: 4px 10px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n opacity: 0.75;\n transition: opacity 120ms ease, border-color 120ms ease, color 120ms ease;\n}\n\n.dd3px29_meetingDelete:hover {\n opacity: 1;\n border-color: var(--dsw-alias-state-error-primary);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dd3px29_budgetRow {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.dd3px29_budgetLabel {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_budgetBar {\n width: 90px;\n height: 5px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-label-secondary) 18%, transparent);\n overflow: hidden;\n}\n\n.dd3px29_budgetFill {\n height: 100%;\n border-radius: 999px;\n /* 蓝色强调用宿主的真实强调色令牌(浅色 #4176e6 / 深色 deepseek-450),\n 不用 --dsw-alias-brand-primary —— 后者是随主题翻转的近黑/近白单色。 */\n background: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n}\n\n.dd3px29_budgetFillTokens {\n height: 100%;\n border-radius: 999px;\n background: var(--dsw-alias-state-success-primary);\n}\n\n.dd3px29_budgetValue {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n}\n\n.dd3px29_decisionBanner {\n display: flex;\n align-items: baseline;\n gap: 8px;\n flex-wrap: wrap;\n padding: 6px 10px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n}\n\n.dd3px29_decisionTag {\n font-size: 11px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n flex: none;\n}\n\n.dd3px29_decisionQuestion {\n font-size: 12px;\n color: var(--dsw-alias-label-primary);\n}\n\n/* ---------- topology canvas ---------- */\n\n.dd3px29_canvas {\n position: relative;\n flex: 1;\n min-width: 320px;\n min-height: 420px;\n border-radius: 12px;\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n overflow: hidden;\n}\n\n/* A1 图例:把「这张图在当前模式下该怎么读」直接写在画布上。\n 起因是红队评审的两条认定缺陷(gpt-1 / claude-2):同一张通道图在\n 主持人统筹 / 多模型平等 / 针锋相对三种模式下含义完全不同,不写清楚,\n 用户会把它读成一张\"控制流程的路径图\"。\n pointer-events:none —— 它只是说明文字,绝不能挡住节点的拖拽拉线。\n 位置放左上角:主持人节点锚在左侧垂直居中(x≈10% w, y=50% h),\n 右上是连线最稀疏的区域。 */\n.dd3px29_canvasLegend {\n position: absolute;\n top: 10px;\n left: 12px;\n z-index: 3;\n max-width: 300px;\n /* 右侧留出叉号的位置,避免文字压到关闭按钮下面。 */\n padding: 7px 24px 7px 10px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-1);\n border: 1px solid var(--dsw-alias-border-l2);\n box-shadow: 0 1px 4px color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n pointer-events: none;\n line-height: 1.5;\n}\n\n/* 关闭按钮:父级是 pointer-events:none(图例绝不能挡住拖拽拉线),\n 所以这里必须单独把事件收回来。 */\n.dd3px29_canvasLegendClose {\n position: absolute;\n top: 4px;\n right: 4px;\n width: 16px;\n height: 16px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n line-height: 1;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n pointer-events: auto;\n}\n\n.dd3px29_canvasLegendClose:hover {\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_canvasLegendTitle {\n font-size: 11px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary);\n margin-bottom: 2px;\n}\n\n.dd3px29_canvasLegendRow {\n font-size: 11px;\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_canvasLegendHint {\n font-size: 10.5px;\n color: var(--dsw-alias-label-secondary);\n margin-top: 2px;\n}\n\n.dd3px29_edgeLayer {\n position: absolute;\n inset: 0;\n pointer-events: none;\n}\n\n.dd3px29_edgeGroup {\n pointer-events: auto;\n cursor: pointer;\n}\n\n.dd3px29_edgeGroup path {\n pointer-events: stroke;\n}\n\n/* Hover delete affordance: a red circle with an X floating ABOVE the canvas\n at the edge's midpoint. It lives in a top layer (not the SVG, which sits\n under the nodes) so a midpoint that lands inside a node is never hidden.\n Revealed while the edge (or the button itself) is hovered. */\n.dd3px29_edgeRemove {\n position: absolute;\n transform: translate(-50%, -50%);\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--dsw-alias-state-error-primary);\n border: 1.5px solid var(--dsw-alias-brand-primary);\n color: #ffffff;\n font-size: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n padding: 0;\n cursor: pointer;\n z-index: 6;\n opacity: 0;\n pointer-events: none;\n transition: opacity 120ms ease;\n box-shadow: 0 1px 5px color-mix(in srgb, var(--dsw-alias-label-primary) 28%, transparent);\n}\n\n.dd3px29_edgeRemoveActive {\n opacity: 1;\n pointer-events: auto;\n}\n\n.dd3px29_edgeRemove:hover {\n opacity: 1;\n pointer-events: auto;\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 85%, transparent);\n}\n\n.dd3px29_edgeForward {\n stroke: var(--dsw-alias-border-l1);\n stroke-width: 1.5;\n}\n\n.dd3px29_edgeBidirectional {\n stroke: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 70%, transparent);\n stroke-width: 1.6;\n}\n\n.dd3px29_edgeArrow {\n fill: var(--dsw-alias-border-l1);\n}\n\n.dd3px29_edgeSynthetic {\n stroke: var(--dsw-alias-border-l2);\n stroke-width: 1.3;\n stroke-dasharray: 4 4;\n}\n\n.dd3px29_edgeArrowSynthetic {\n fill: var(--dsw-alias-border-l2);\n}\n\n/* Role-based accents so the topology reads at a glance: captain is the single\n \"everything radiates from here\" hub (warm gold), aggregator is the sink\n (cool teal), and expert↔expert wires stay neutral grey. */\n.dd3px29_edgeCaptain {\n stroke: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 85%, transparent);\n stroke-width: 1.8;\n}\n\n.dd3px29_edgeAggregator {\n stroke: color-mix(in srgb, var(--dsw-alias-state-success-primary) 80%, transparent);\n stroke-width: 1.6;\n}\n\n.dd3px29_edgeSyntheticCaptain {\n stroke: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 45%, transparent);\n stroke-width: 1.4;\n stroke-dasharray: 4 4;\n}\n\n.dd3px29_edgeSyntheticAggregator {\n stroke: color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent);\n stroke-width: 1.4;\n stroke-dasharray: 4 4;\n}\n\n.dd3px29_edgeArrowCaptain {\n fill: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 90%, transparent);\n}\n\n.dd3px29_edgeArrowAggregator {\n fill: color-mix(in srgb, var(--dsw-alias-state-success-primary) 85%, transparent);\n}\n\n.dd3px29_edgeArrowSyntheticCaptain {\n fill: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 50%, transparent);\n}\n\n.dd3px29_edgeArrowSyntheticAggregator {\n fill: color-mix(in srgb, var(--dsw-alias-state-success-primary) 45%, transparent);\n}\n\n.dd3px29_dragLine {\n stroke: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n stroke-width: 1.6;\n stroke-dasharray: 5 4;\n pointer-events: none;\n}\n\n/* One-shot message pulse traveling from sender to receiver. */\n.dd3px29_msgPulse {\n position: absolute;\n left: 0;\n top: 0;\n width: 9px;\n height: 9px;\n border-radius: 50%;\n /* 与下方辉光同一强调蓝:此前填 brand-primary(随主题翻成近白),\n 深色下会变成\"蓝辉光围着近白圆点\"——不一致,且圆点在浅底上不可见。 */\n background: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n box-shadow: 0 0 10px 2px color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 70%, transparent);\n pointer-events: none;\n z-index: 4;\n animation: rt-msg-flow 1.1s ease-out forwards;\n}\n\n@keyframes rt-msg-flow {\n 0% {\n transform: translate(var(--rt-fx), var(--rt-fy)) translate(-50%, -50%);\n opacity: 1;\n }\n 100% {\n transform: translate(var(--rt-tx), var(--rt-ty)) translate(-50%, -50%);\n opacity: 0;\n }\n}\n\n.dd3px29_node {\n position: absolute;\n transform: translate(-50%, -50%);\n width: 68px;\n height: 68px;\n border-radius: 50%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n background: var(--dsw-alias-bg-layer-1);\n border: 1px solid var(--dsw-alias-border-l2);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n user-select: none;\n z-index: 2;\n}\n\n.dd3px29_captainNode {\n width: 96px;\n height: 88px;\n border-radius: 12px;\n background: #202124;\n border: none;\n box-shadow: 0 4px 14px color-mix(in srgb, var(--dsw-alias-label-primary) 25%, transparent);\n}\n\n.dd3px29_captainNode .dd3px29_nodeLabel {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n font-weight: 600;\n text-align: center;\n line-height: 1.4;\n}\n\n.dd3px29_aggregatorNode {\n width: 74px;\n height: 74px;\n border-radius: 14px;\n background: var(--dsw-alias-bg-layer-2);\n border: 1.5px dashed var(--dsw-alias-border-l2);\n}\n\n.dd3px29_nodeLabel {\n font-size: 11px;\n color: var(--dsw-alias-label-primary);\n text-align: center;\n line-height: 1.3;\n max-width: 62px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Captain/aggregator labels are longer (\"DeepSeek · 主持\", \"汇聚网关\") and are\n clipped into \"DeepSee…\" by the 62px default. Give them room to wrap to two\n lines so the full name shows — the truncation was hiding the final \"K\" and\n broke the reading of the host's name. */\n.dd3px29_captainNode .dd3px29_nodeLabel,\n.dd3px29_aggregatorNode .dd3px29_nodeLabel {\n max-width: 86px;\n white-space: normal;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.dd3px29_avatar {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex: none;\n box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--dsw-alias-label-primary) 22%, transparent);\n}\n\n/* 厂商 logo 图:圆形裁切 + contain 防切边,品牌色底垫在透明图后面。 */\n.dd3px29_avatarImg {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: contain;\n padding: 2px;\n box-sizing: border-box;\n}\n\n.dd3px29_avatarAbbr {\n color: #ffffff;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.3px;\n line-height: 1;\n}\n\n/* A2:节点状态如实显示持久子代理的生命周期。默认中性灰(空闲/就绪/未唤醒\n 都不代表节点坏了),只有真的在跑才用绿色高亮。\n 节点只有 68px 宽,所以这里强制单行 + 省略号:状态标签永远不能换行,\n 否则文字会溢出圆形卡片、和连线叠在一起(\"就绪(可唤醒)\"就是这么翻车的)。\n 完整语义交给 title(activityLifecycleHint)与右栏列表的悬停提示。 */\n.dd3px29_nodeMeta {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n min-height: 12px;\n max-width: calc(100% - 4px);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.dd3px29_nodeMetaWorking {\n color: var(--dsw-alias-state-success-primary);\n}\n\n/* A node that was added then removed: keep it visible so the topology still\n shows which models participated, but degrade it (greyed, no pulse, muted). */\n.dd3px29_nodeRemoved {\n background: var(--dsw-alias-bg-layer-2);\n border-color: var(--dsw-alias-border-l2);\n box-shadow: none;\n opacity: 0.72;\n}\n\n.dd3px29_nodeRemoved .dd3px29_nodeLabel {\n color: var(--dsw-alias-label-secondary);\n text-decoration: line-through;\n}\n\n.dd3px29_nodeRemoved .dd3px29_avatar {\n filter: grayscale(0.8);\n opacity: 0.85;\n}\n\n/* Breathing light: low-opacity pulse, pure CSS — zero tokens. */\n.dd3px29_breathing {\n animation: roundtable-pulse 1.6s ease-in-out infinite;\n}\n\n@keyframes roundtable-pulse {\n 0%, 100% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 28%, transparent), 0 2px 8px color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 75%, transparent);\n }\n 50% {\n box-shadow: 0 0 0 9px color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 0%, transparent), 0 2px 8px color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 45%, transparent);\n }\n}\n\n/* Connector ports: small hit-dots on the node rim that a connector grows out\n of (a Dify-style workflow port). Four per node; each is a 10px circle that\n brightens on hover to signal \"drag from here to wire an edge\". The dots sit\n outside the node circle so the wire visibly starts at the expert's edge. */\n.dd3px29_port {\n position: absolute;\n width: 11px;\n height: 11px;\n border-radius: 50%;\n background: var(--dsw-alias-bg-layer-1);\n border: 2px solid var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 15%, transparent);\n cursor: crosshair;\n opacity: 0;\n transition: opacity 120ms ease, transform 120ms ease, box-shadow 120ms ease;\n z-index: 4;\n}\n\n.dd3px29_node:hover .dd3px29_port,\n.dd3px29_port:focus-visible {\n opacity: 1;\n}\n\n.dd3px29_port:hover {\n transform: scale(1.25);\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 28%, transparent);\n /* 与描边同一强调蓝:此前填 brand-primary,深色下会与蓝色描边自相矛盾。 */\n background: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n}\n\n/* Placement: centered on each rim, slightly outside the 68px circle. */\n.dd3px29_portN { top: -7px; left: calc(50% - 5.5px); }\n.dd3px29_portE { right: -7px; top: calc(50% - 5.5px); }\n.dd3px29_portS { bottom: -7px; left: calc(50% - 5.5px); }\n.dd3px29_portW { left: -7px; top: calc(50% - 5.5px); }\n\n/* Larger captain/aggregator rims need the ports pushed a touch further out. */\n.dd3px29_captainNode .dd3px29_portN { top: -9px; }\n.dd3px29_captainNode .dd3px29_portS { bottom: -9px; }\n.dd3px29_captainNode .dd3px29_portE { right: -9px; }\n.dd3px29_captainNode .dd3px29_portW { left: -9px; }\n.dd3px29_aggregatorNode .dd3px29_portN { top: -8px; }\n.dd3px29_aggregatorNode .dd3px29_portS { bottom: -8px; }\n.dd3px29_aggregatorNode .dd3px29_portE { right: -8px; }\n.dd3px29_aggregatorNode .dd3px29_portW { left: -8px; }\n\n/* While a connector is being dragged, keep every port visible so the user can\n see exactly where they may drop — ports otherwise only appear on hover. */\n.dd3px29_canvasDragging .dd3px29_port {\n opacity: 0.6;\n}\n\n/* ---------- gateway digest ---------- */\n\n.dd3px29_digest {\n flex: none;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2);\n font-size: 12px;\n}\n\n.dd3px29_digest summary {\n cursor: pointer;\n padding: 6px 10px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_digestBody {\n margin: 0;\n padding: 0 10px 10px;\n max-height: 180px;\n overflow: auto;\n font-family: inherit;\n white-space: pre-wrap;\n word-break: break-word;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* ---------- sidebar ---------- */\n\n.dd3px29_sidebar {\n width: 264px;\n flex: none;\n display: flex;\n flex-direction: column;\n gap: 10px;\n overflow-y: auto;\n padding-right: 2px;\n}\n\n/* 右栏顶部操作条:删除会议 + 待办徽标(固定位置,窄屏可见)。 */\n.dd3px29_sidebarActions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n flex: none;\n}\n\n.dd3px29_pendingBadge {\n font-size: 11px;\n color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 50%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n\n/* 专家行\"待移除\"标记(用户已删除、主持人下一轮执行)。 */\n.dd3px29_agentQueuedRemove {\n font-size: 10px;\n color: var(--dsw-alias-state-warn-primary);\n flex: none;\n font-weight: 600;\n}\n\n.dd3px29_panel {\n flex: none;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2);\n overflow: hidden;\n}\n\n.dd3px29_panelTitleRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 10px;\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.dd3px29_panelTitle {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_panelAdd {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n line-height: 16px;\n text-align: center;\n padding: 0;\n cursor: pointer;\n flex: none;\n}\n\n.dd3px29_panelAdd:hover {\n border-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n}\n\n.dd3px29_panelBody {\n padding: 8px 10px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n max-height: 220px;\n overflow-y: auto;\n}\n\n.dd3px29_agentRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dd3px29_agentAvatar {\n width: 26px;\n height: 26px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex: none;\n}\n\n.dd3px29_agentAbbr {\n color: #ffffff;\n font-size: 9px;\n font-weight: 700;\n}\n\n.dd3px29_agentInfo {\n flex: 1;\n min-width: 0;\n}\n\n.dd3px29_agentName {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_agentRole {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.dd3px29_agentStatus {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n flex: none;\n}\n\n.dd3px29_agentStatusWorking {\n font-size: 10px;\n color: var(--dsw-alias-state-success-primary);\n flex: none;\n font-weight: 600;\n}\n\n.dd3px29_agentRowRemoved {\n opacity: 0.6;\n}\n\n.dd3px29_agentRowRemoved .dd3px29_avatar,\n.dd3px29_agentRowRemoved .dd3px29_agentAvatar {\n filter: grayscale(0.8);\n}\n\n.dd3px29_agentRowRemoved .dd3px29_agentName {\n color: var(--dsw-alias-label-secondary);\n text-decoration: line-through;\n}\n\n.dd3px29_agentStatusRemoved {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n font-style: italic;\n flex: none;\n}\n\n.dd3px29_taskRow {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.dd3px29_taskToggle {\n display: flex;\n align-items: center;\n gap: 6px;\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n text-align: left;\n border-radius: 4px;\n}\n\n.dd3px29_taskToggle:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 8%, transparent);\n}\n\n.dd3px29_taskChevron {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n width: 12px;\n flex: none;\n}\n\n.dd3px29_taskKey {\n font-size: 11px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n/* Collapsed: always a single line with an ellipsis, regardless of length. */\n.dd3px29_taskRole {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.35;\n}\n\n/* Expanded: full role, wrapped. */\n.dd3px29_taskRoleExpanded {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n line-height: 1.45;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.dd3px29_panelEmpty {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n line-height: 1.5;\n}\n\n.dd3px29_logRow {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding-bottom: 6px;\n border-bottom: 1px dashed var(--dsw-alias-border-l2);\n}\n\n.dd3px29_logRow:last-child {\n border-bottom: none;\n padding-bottom: 0;\n}\n\n.dd3px29_logHead {\n display: flex;\n justify-content: space-between;\n gap: 6px;\n}\n\n.dd3px29_logFrom {\n font-size: 10px;\n font-weight: 600;\n color: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 90%, transparent);\n}\n\n.dd3px29_logTime {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n}\n\n.dd3px29_logText {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n line-height: 1.45;\n}\n\n/* ---------- context menu ---------- */\n\n.dd3px29_contextMenu {\n position: fixed;\n z-index: 1000;\n min-width: 170px;\n background: var(--dsw-alias-bg-layer-1);\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n box-shadow: 0 6px 20px color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent);\n padding: 4px;\n display: flex;\n flex-direction: column;\n}\n\n.dd3px29_contextMenuTitle {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n padding: 4px 10px;\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n margin-bottom: 4px;\n}\n\n.dd3px29_contextMenuItem,\n.dd3px29_contextMenuItemDanger {\n border: none;\n background: none;\n text-align: left;\n font-size: 13px;\n padding: 7px 10px;\n border-radius: 6px;\n cursor: pointer;\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_contextMenuItem:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 10%, transparent);\n}\n\n.dd3px29_contextMenuItemDanger {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dd3px29_contextMenuItemDanger:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);\n}\n\n/* ---------- empty / error ---------- */\n\n.dd3px29_emptyState {\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n padding: 24px;\n text-align: center;\n}\n\n.dd3px29_emptyTitle {\n font-size: 15px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_emptyHint {\n font-size: 13px;\n color: var(--dsw-alias-label-secondary);\n max-width: 420px;\n line-height: 1.6;\n}\n\n.dd3px29_fetchFailed {\n font-size: 11px;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* Connect-result toast: a short-lived banner at the top of the topology\n canvas telling the user whether a dragged wire landed. Without it a failed\n edge.dd3px29_add (e.dd3px29_g. wiring a removed node) was silently swallowed — the user saw\n nothing and assumed the drag did nothing. White card, black text, no tilt:\n the label sits on a single centered baseline. */\n.dd3px29_toast {\n position: absolute;\n top: 12px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 6;\n max-width: 90%;\n background: var(--dsw-alias-bg-layer-1);\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 8px 16px;\n box-shadow: 0 4px 14px color-mix(in srgb, var(--dsw-alias-label-primary) 18%, transparent);\n pointer-events: none;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1.4;\n text-align: center;\n font-variant-numeric: tabular-nums;\n}\n\n.dd3px29_toastOk {\n font-size: 12.5px;\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n\n.dd3px29_toastErr {\n font-size: 12.5px;\n color: var(--dsw-alias-state-error-primary);\n font-weight: 500;\n}\n\n/* ---------- expert management modal (panel \"+\" buttons) ---------- */\n\n.dd3px29_manageOverlay {\n position: fixed;\n inset: 0;\n z-index: 1200;\n background: var(--dsw-alias-bg-overlay);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.dd3px29_manageModal {\n width: 480px;\n max-width: calc(100vw - 32px);\n max-height: calc(100vh - 48px);\n overflow-y: auto;\n background: var(--dsw-alias-bg-layer-1);\n border-radius: 12px;\n box-shadow: 0 12px 40px color-mix(in srgb, var(--dsw-alias-label-primary) 22%, transparent);\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.dd3px29_manageTitle {\n font-size: 14px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_managePendingNote {\n font-size: 11px;\n color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 45%, transparent);\n border-radius: 8px;\n padding: 6px 10px;\n line-height: 1.5;\n}\n\n.dd3px29_manageSectionTitle {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary);\n margin-top: 2px;\n}\n\n.dd3px29_manageList {\n display: flex;\n flex-direction: column;\n gap: 6px;\n max-height: 220px;\n overflow-y: auto;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 8px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.dd3px29_manageRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dd3px29_managePendingAvatar {\n width: 26px;\n height: 26px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex: none;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 25%, transparent);\n color: var(--dsw-alias-state-warn-primary);\n font-size: 14px;\n font-weight: 700;\n}\n\n.dd3px29_manageStatusTag {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n flex: none;\n}\n\n.dd3px29_managePendingTag {\n font-size: 10px;\n color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 15%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n flex: none;\n font-weight: 600;\n}\n\n.dd3px29_manageRemoveBtn {\n font-size: 11px;\n padding: 2px 10px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-state-error-primary);\n cursor: pointer;\n flex: none;\n}\n\n.dd3px29_manageRemoveBtn:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);\n}\n\n.dd3px29_manageForm {\n display: flex;\n flex-direction: column;\n gap: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 10px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.dd3px29_manageFormRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dd3px29_manageLabel {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n width: 40px;\n flex: none;\n}\n\n.dd3px29_manageInput {\n flex: 1;\n min-width: 0;\n font-size: 12px;\n padding: 4px 8px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_manageSelect {\n flex: 1;\n min-width: 0;\n font-size: 12px;\n padding: 3px 6px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_manageAddBtn {\n align-self: flex-end;\n font-size: 12px;\n padding: 4px 14px;\n border-radius: 6px;\n border: none;\n background: var(--dsw-alias-brand-primary);\n /* 填充的反色,而不是写死的白字:brand-primary 随主题翻转(浅色近黑 / 深色近白),\n 写死 #ffffff 会在深色下变成\"白字压近白底\"。该令牌是宿主 primitives 标准的\n \"填充上的文字色\"(浅色 #fff / 深色 #0f1115),语义正确。 */\n color: var(--dsw-alias-label-primary-foreground);\n cursor: pointer;\n}\n\n.dd3px29_manageAddBtn:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 85%, transparent);\n}\n\n.dd3px29_manageFooter {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n border-top: 1px solid var(--dsw-alias-border-l2);\n padding-top: 10px;\n}\n\n.dd3px29_manageHint {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n line-height: 1.5;\n}\n\n.dd3px29_manageCloseBtn {\n font-size: 12px;\n padding: 4px 14px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n flex: none;\n}\n\n.dd3px29_manageCloseBtn:hover {\n border-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n}\n\n/* ---------- 右栏面板可见性(R3:设置页点圆圈决定显示) ---------- */\n\n/* 被用户关掉的面板不渲染(右栏因此变短,拓扑区自然变大)。 */\n.dd3px29_panelHidden {\n display: none !important;\n}\n\n/* ---------- knowledge base (阅览版) ---------- */\n\n/* skill 传递方式的简短标注(与面板标题同一行,保持界面工整)。 */\n.dd3px29_skillDeliveryLabel {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n font-weight: 400;\n}\n\n.dd3px29_kbPathRow {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 7%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 25%, transparent);\n border-radius: 6px;\n padding: 5px 8px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n word-break: break-all;\n}\n\n.dd3px29_kbPathForm {\n display: flex;\n flex-direction: column;\n gap: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 10px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.dd3px29_kbChangedRow {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n user-select: none;\n}\n\n.dd3px29_switchInput {\n accent-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n cursor: pointer;\n}\n\n.dd3px29_kbList {\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: 240px;\n overflow-y: auto;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 8px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.dd3px29_kbRow {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n}\n\n.dd3px29_kbKindDir,\n.dd3px29_kbKindFile {\n font-size: 13px;\n flex: none;\n opacity: 0.85;\n}\n\n.dd3px29_kbName {\n flex: 1;\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.dd3px29_kbMeta {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n flex: none;\n}\n\n.dd3px29_kbError {\n font-size: 12px;\n color: var(--dsw-alias-state-error-primary);\n line-height: 1.5;\n}\n\n/* ---------- 针锋相对评审弹窗(三区布局) ---------- */\n\n.dd3px29_reviewModal {\n width: 860px;\n max-width: calc(100vw - 32px);\n max-height: calc(100vh - 48px);\n overflow-y: auto;\n background: var(--dsw-alias-bg-layer-1);\n border-radius: 12px;\n box-shadow: 0 12px 40px color-mix(in srgb, var(--dsw-alias-label-primary) 22%, transparent);\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.dd3px29_reviewBody {\n display: flex;\n gap: 12px;\n min-height: 0;\n}\n\n.dd3px29_reviewLeft {\n flex: 0 0 300px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n border-right: 1px solid var(--dsw-alias-border-l2);\n padding-right: 12px;\n max-height: 60vh;\n overflow-y: auto;\n}\n\n.dd3px29_reviewRight {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.dd3px29_reviewSectionTitle {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_reviewQuestion {\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 7%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 25%, transparent);\n border-radius: 8px;\n padding: 8px 10px;\n white-space: pre-wrap;\n word-break: break-word;\n line-height: 1.5;\n}\n\n.dd3px29_reviewPlan {\n font-size: 12px;\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 8px 10px;\n white-space: pre-wrap;\n word-break: break-word;\n line-height: 1.6;\n}\n\n.dd3px29_reviewList {\n display: flex;\n flex-direction: column;\n gap: 10px;\n max-height: 60vh;\n overflow-y: auto;\n padding-right: 4px;\n}\n\n.dd3px29_reviewItem {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n padding: 10px 12px;\n background: var(--dsw-alias-bg-layer-2);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.dd3px29_reviewItemHead {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dd3px29_reviewNode {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n flex: 1;\n}\n\n.dd3px29_reviewSeq {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n font-weight: 600;\n white-space: nowrap;\n}\n\n.dd3px29_reviewEndorsed {\n font-size: 10px;\n color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n font-weight: 600;\n}\n\n.dd3px29_reviewContent {\n font-size: 12px;\n color: var(--dsw-alias-label-primary);\n line-height: 1.6;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.dd3px29_reviewActions {\n display: flex;\n justify-content: flex-end;\n}\n\n/* 表态三态的语义配色:认定(endorsed / support)= 绿系,驳回(rejected / reject)= 红系。\n 与针锋 Crossfire 插件的约定保持一致(认定=绿、驳回=红),\n 避免同一用户在两个插件之间切换时反向读数。不要改回去。 */\n.dd3px29_reviewSupport {\n font-size: 11px;\n padding: 4px 12px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 45%, transparent);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-state-success-primary);\n cursor: pointer;\n}\n\n.dd3px29_reviewSupport:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent);\n}\n\n.dd3px29_reviewSupportDone {\n font-size: 11px;\n padding: 4px 12px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 30%, transparent);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent);\n color: var(--dsw-alias-state-success-primary);\n cursor: default;\n}\n\n.dd3px29_reviewDimension {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 5%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n white-space: nowrap;\n}\n\n.dd3px29_reviewQuote {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 4%, transparent);\n border-left: 3px solid var(--dsw-alias-border-l2);\n padding: 4px 8px;\n border-radius: 0 6px 6px 0;\n line-height: 1.5;\n}\n\n.dd3px29_reviewPending {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n font-weight: 500;\n}\n\n.dd3px29_reviewRejected {\n font-size: 10px;\n color: var(--dsw-alias-state-error-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n font-weight: 600;\n}\n\n.dd3px29_reviewReject {\n font-size: 11px;\n padding: 4px 12px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-state-error-primary);\n cursor: pointer;\n margin-left: 8px;\n}\n\n.dd3px29_reviewReject:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);\n}\n\n.dd3px29_reviewRejectDone {\n font-size: 11px;\n padding: 4px 12px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 30%, transparent);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);\n color: var(--dsw-alias-state-error-primary);\n cursor: default;\n margin-left: 8px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dd3px29_breathing {\n animation: none;\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 60%, transparent);\n }\n}\n\n.dd3px29_reviewPassBadge {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 5%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n font-weight: 600;\n margin-right: 6px;\n}\n\n.dd3px29_reviewEvidence {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 6%, transparent);\n border-left: 3px solid color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 35%, transparent);\n padding: 4px 8px;\n border-radius: 0 6px 6px 0;\n line-height: 1.5;\n margin-top: 4px;\n white-space: pre-wrap;\n}\n\n.dd3px29_reviewEvidenceLabel {\n font-weight: 600;\n}\n\n.dd3px29_reviewRejectReason {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 3%, transparent);\n border-left: 3px solid var(--dsw-alias-border-l1);\n padding: 4px 8px;\n border-radius: 0 6px 6px 0;\n line-height: 1.5;\n margin-top: 4px;\n}\n\n.dd3px29_reviewRejectBox {\n margin-top: 6px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.dd3px29_reviewRejectLabel {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_reviewRejectInput {\n width: 100%;\n box-sizing: border-box;\n font-size: 12px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n color: inherit;\n resize: vertical;\n min-height: 34px;\n font-family: inherit;\n}\n\n.dd3px29_reviewRejectActions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n}\n\n.dd3px29_reviewImpactBar {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n margin-top: 6px;\n padding: 6px 8px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 4%, transparent);\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_reviewImpactWarn {\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 10%, transparent);\n color: var(--dsw-alias-state-warn-primary);\n font-weight: 500;\n}\n\n.dd3px29_feedbackBar {\n position: fixed;\n right: 16px;\n bottom: 16px;\n z-index: 60;\n width: 300px;\n max-width: calc(100vw - 32px);\n background: var(--dsw-alias-bg-layer-1);\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 12px;\n box-shadow: 0 8px 28px color-mix(in srgb, var(--dsw-alias-label-primary) 18%, transparent);\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.dd3px29_feedbackBarTitle {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n line-height: 1.5;\n}\n\n.dd3px29_feedbackBarActions {\n display: flex;\n gap: 6px;\n}\n\n.dd3px29_feedbackRating {\n font-size: 12px;\n padding: 5px 10px;\n border-radius: 999px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 40%, transparent);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 6%, transparent);\n color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n cursor: pointer;\n}\n\n.dd3px29_feedbackRating:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 14%, transparent);\n}\n\n.dd3px29_feedbackBarNote {\n width: 100%;\n box-sizing: border-box;\n font-size: 12px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n color: inherit;\n font-family: inherit;\n}\n\n.dd3px29_feedbackBarFooter {\n display: flex;\n justify-content: flex-end;\n}\n\n.dd3px29_feedbackSkip {\n font-size: 11px;\n padding: 3px 10px;\n border-radius: 6px;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n.dd3px29_feedbackSkip:hover {\n color: var(--dsw-alias-label-primary);\n}\n";
|
|
103
|
+
const css$1 = ".dd3px29_root {\n display: flex;\n height: 100%;\n min-height: 0;\n gap: 12px;\n padding: 12px;\n overflow: hidden;\n}\n\n/* ---------- main column ---------- */\n\n.dd3px29_main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.dd3px29_header {\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex: none;\n}\n\n.dd3px29_titleRow {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.dd3px29_meetingName {\n font-size: 15px;\n font-weight: 600;\n}\n\n.dd3px29_meetingSelect {\n font-size: 12px;\n padding: 2px 6px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n max-width: 220px;\n}\n\n.dd3px29_badge {\n font-size: 11px;\n padding: 1px 8px;\n border-radius: 999px;\n border: 1px solid var(--dsw-alias-border-l2);\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_round {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 标题区「针锋相对」入口:可点击打开评审窗口 */\n.dd3px29_reviewBadge {\n font-size: 11px;\n padding: 2px 10px;\n border-radius: 999px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 6%, transparent);\n color: var(--dsw-alias-state-error-primary);\n cursor: pointer;\n font-weight: 600;\n transition: background 120ms ease;\n}\n\n.dd3px29_reviewBadge:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);\n}\n\n/* 右栏「分针记录」摘要卡片:可点击打开评审窗口 */\n.dd3px29_reviewCard {\n display: flex;\n flex-direction: column;\n gap: 4px;\n text-align: left;\n width: 100%;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 25%, transparent);\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 5%, transparent);\n padding: 8px 10px;\n cursor: pointer;\n transition: background 120ms ease;\n}\n\n.dd3px29_reviewCard:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.dd3px29_reviewCardTitle {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n line-height: 1.45;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.dd3px29_reviewCardMeta {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 会议删除按钮:固定在右栏顶部操作条(不再挤在标题行最右,窄屏也能看到)。 */\n.dd3px29_meetingDelete {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n padding: 4px 10px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n opacity: 0.75;\n transition: opacity 120ms ease, border-color 120ms ease, color 120ms ease;\n}\n\n.dd3px29_meetingDelete:hover {\n opacity: 1;\n border-color: var(--dsw-alias-state-error-primary);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dd3px29_budgetRow {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.dd3px29_budgetLabel {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_budgetBar {\n width: 100px;\n height: 6px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-label-secondary) 18%, transparent);\n overflow: hidden;\n}\n\n.dd3px29_budgetFill {\n height: 100%;\n border-radius: 999px;\n /* 蓝色强调用宿主的真实强调色令牌(浅色 #4176e6 / 深色 deepseek-450),\n 不用 --dsw-alias-brand-primary —— 后者是随主题翻转的近黑/近白单色。 */\n background: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n}\n\n.dd3px29_budgetFillTokens {\n height: 100%;\n border-radius: 999px;\n background: var(--dsw-alias-state-success-primary);\n}\n\n.dd3px29_budgetValue {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n}\n\n.dd3px29_decisionBanner {\n display: flex;\n align-items: baseline;\n gap: 8px;\n flex-wrap: wrap;\n padding: 6px 10px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n}\n\n.dd3px29_decisionTag {\n font-size: 11px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n flex: none;\n}\n\n.dd3px29_decisionQuestion {\n font-size: 12px;\n color: var(--dsw-alias-label-primary);\n}\n\n/* ---------- topology canvas ---------- */\n\n.dd3px29_canvas {\n position: relative;\n flex: 1;\n min-width: 320px;\n min-height: 420px;\n border-radius: 12px;\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n overflow: hidden;\n}\n\n/* A1 图例:把「这张图在当前模式下该怎么读」直接写在画布上。\n 起因是红队评审的两条认定缺陷(gpt-1 / claude-2):同一张通道图在\n 主持人统筹 / 多模型平等 / 针锋相对三种模式下含义完全不同,不写清楚,\n 用户会把它读成一张\"控制流程的路径图\"。\n pointer-events:none —— 它只是说明文字,绝不能挡住节点的拖拽拉线。\n 位置放左上角:主持人节点锚在左侧垂直居中(x≈10% w, y=50% h),\n 右上是连线最稀疏的区域。 */\n.dd3px29_canvasLegend {\n position: absolute;\n top: 10px;\n left: 12px;\n z-index: 3;\n max-width: 300px;\n /* 右侧留出叉号的位置,避免文字压到关闭按钮下面。 */\n padding: 7px 24px 7px 10px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-1);\n border: 1px solid var(--dsw-alias-border-l2);\n box-shadow: 0 1px 4px color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n pointer-events: none;\n line-height: 1.5;\n}\n\n/* 关闭按钮:父级是 pointer-events:none(图例绝不能挡住拖拽拉线),\n 所以这里必须单独把事件收回来。 */\n.dd3px29_canvasLegendClose {\n position: absolute;\n top: 4px;\n right: 4px;\n width: 16px;\n height: 16px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n line-height: 1;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n pointer-events: auto;\n}\n\n.dd3px29_canvasLegendClose:hover {\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_canvasLegendTitle {\n font-size: 11px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary);\n margin-bottom: 2px;\n}\n\n.dd3px29_canvasLegendRow {\n font-size: 11px;\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_canvasLegendHint {\n font-size: 10.5px;\n color: var(--dsw-alias-label-secondary);\n margin-top: 2px;\n}\n\n.dd3px29_edgeLayer {\n position: absolute;\n inset: 0;\n pointer-events: none;\n}\n\n.dd3px29_edgeGroup {\n pointer-events: auto;\n cursor: pointer;\n}\n\n.dd3px29_edgeGroup path {\n pointer-events: stroke;\n}\n\n/* Hover delete affordance: a red circle with an X floating ABOVE the canvas\n at the edge's midpoint. It lives in a top layer (not the SVG, which sits\n under the nodes) so a midpoint that lands inside a node is never hidden.\n Revealed while the edge (or the button itself) is hovered. */\n.dd3px29_edgeRemove {\n position: absolute;\n transform: translate(-50%, -50%);\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--dsw-alias-state-error-primary);\n border: 1.5px solid var(--dsw-alias-brand-primary);\n color: #ffffff;\n font-size: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n padding: 0;\n cursor: pointer;\n z-index: 6;\n opacity: 0;\n pointer-events: none;\n transition: opacity 120ms ease;\n box-shadow: 0 1px 5px color-mix(in srgb, var(--dsw-alias-label-primary) 28%, transparent);\n}\n\n.dd3px29_edgeRemoveActive {\n opacity: 1;\n pointer-events: auto;\n}\n\n.dd3px29_edgeRemove:hover {\n opacity: 1;\n pointer-events: auto;\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 85%, transparent);\n}\n\n/* 专家↔专家的普通边:此前用 border-l1,在浅色底上几乎看不见。\n * 换成 label-secondary 并统一 round 端点,曲线交汇处不再有硬角。 */\n.dd3px29_edgeForward {\n stroke: var(--dsw-alias-label-secondary);\n stroke-width: 1.6;\n stroke-linecap: round;\n}\n\n.dd3px29_edgeBidirectional {\n stroke: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 70%, transparent);\n stroke-width: 1.6;\n}\n\n.dd3px29_edgeArrow {\n fill: var(--dsw-alias-border-l1);\n}\n\n.dd3px29_edgeSynthetic {\n stroke: var(--dsw-alias-border-l2);\n stroke-width: 1.3;\n stroke-dasharray: 4 4;\n}\n\n.dd3px29_edgeArrowSynthetic {\n fill: var(--dsw-alias-border-l2);\n}\n\n/* Role-based accents so the topology reads at a glance: captain is the single\n \"everything radiates from here\" hub (warm gold), aggregator is the sink\n (cool teal), and expert↔expert wires stay neutral grey. */\n.dd3px29_edgeCaptain {\n stroke: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 85%, transparent);\n stroke-width: 1.8;\n}\n\n.dd3px29_edgeAggregator {\n stroke: color-mix(in srgb, var(--dsw-alias-state-success-primary) 80%, transparent);\n stroke-width: 1.6;\n}\n\n.dd3px29_edgeSyntheticCaptain {\n stroke: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 45%, transparent);\n stroke-width: 1.4;\n stroke-dasharray: 4 4;\n}\n\n.dd3px29_edgeSyntheticAggregator {\n stroke: color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent);\n stroke-width: 1.4;\n stroke-dasharray: 4 4;\n}\n\n.dd3px29_edgeArrowCaptain {\n fill: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 90%, transparent);\n}\n\n.dd3px29_edgeArrowAggregator {\n fill: color-mix(in srgb, var(--dsw-alias-state-success-primary) 85%, transparent);\n}\n\n.dd3px29_edgeArrowSyntheticCaptain {\n fill: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 50%, transparent);\n}\n\n.dd3px29_edgeArrowSyntheticAggregator {\n fill: color-mix(in srgb, var(--dsw-alias-state-success-primary) 45%, transparent);\n}\n\n.dd3px29_dragLine {\n stroke: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n stroke-width: 1.6;\n stroke-dasharray: 5 4;\n pointer-events: none;\n}\n\n/* One-shot message pulse traveling from sender to receiver. */\n.dd3px29_msgPulse {\n position: absolute;\n left: 0;\n top: 0;\n width: 9px;\n height: 9px;\n border-radius: 50%;\n /* 与下方辉光同一强调蓝:此前填 brand-primary(随主题翻成近白),\n 深色下会变成\"蓝辉光围着近白圆点\"——不一致,且圆点在浅底上不可见。 */\n background: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n box-shadow: 0 0 10px 2px color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 70%, transparent);\n pointer-events: none;\n z-index: 4;\n animation: rt-msg-flow 1.1s ease-out forwards;\n}\n\n@keyframes rt-msg-flow {\n 0% {\n transform: translate(var(--rt-fx), var(--rt-fy)) translate(-50%, -50%);\n opacity: 1;\n }\n 100% {\n transform: translate(var(--rt-tx), var(--rt-ty)) translate(-50%, -50%);\n opacity: 0;\n }\n}\n\n.dd3px29_node {\n position: absolute;\n transform: translate(-50%, -50%);\n width: 84px;\n height: 84px;\n border-radius: 50%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n background: var(--dsw-alias-bg-layer-1);\n border: 1px solid var(--dsw-alias-border-l2);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n user-select: none;\n z-index: 2;\n}\n\n.dd3px29_captainNode {\n width: 108px;\n height: 96px;\n border-radius: 12px;\n background: #202124;\n border: none;\n box-shadow: 0 4px 14px color-mix(in srgb, var(--dsw-alias-label-primary) 25%, transparent);\n}\n\n/* 黑块上的文字必须用固定白色:`label-secondary` 是\"浅底上的次要文字\",\n * 在 #202124 上会变成低对比的灰,读不出来。 */\n.dd3px29_captainNode .dd3px29_nodeLabel {\n color: #ffffff;\n font-size: 12px;\n font-weight: 600;\n text-align: center;\n line-height: 1.4;\n}\n\n.dd3px29_aggregatorNode {\n width: 84px;\n height: 84px;\n border-radius: 14px;\n background: var(--dsw-alias-bg-layer-2);\n border: 1.5px dashed var(--dsw-alias-border-l2);\n}\n\n/* 节点标签:允许两行。\n *\n * 68px 的圆形节点里,单行 + 62px 会把任何超过 5 个字符的名字吃掉\n * (`expert-lifecycle` → `expert-life…`)。两行 + 10px 能放下 `lifecycle`\n * 这类 9–13 字符的名字;超过两行才截断(`-webkit-line-clamp`)。\n * 完整 key 仍由节点的 title 提供。 */\n.dd3px29_nodeLabel {\n font-size: 11px;\n color: var(--dsw-alias-label-primary);\n text-align: center;\n line-height: 1.25;\n max-width: 78px;\n overflow: hidden;\n overflow-wrap: anywhere;\n white-space: normal;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n/* Captain/aggregator labels are longer (\"DeepSeek · 主持\", \"汇聚网关\") and are\n clipped into \"DeepSee…\" by the 62px default. Give them room to wrap to two\n lines so the full name shows — the truncation was hiding the final \"K\" and\n broke the reading of the host's name. */\n.dd3px29_captainNode .dd3px29_nodeLabel,\n.dd3px29_aggregatorNode .dd3px29_nodeLabel {\n max-width: 100px;\n white-space: normal;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n/* 头像:纯圆图,不再套一圈 inset 灰边 —— 那圈边与节点自身的边框叠在一起,\n * 看起来像\"框里还有一个框\"。 */\n.dd3px29_avatar {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex: none;\n overflow: hidden;\n}\n\n/* 厂商 logo 图:圆形裁切 + contain 防切边,品牌色底垫在透明图后面。 */\n.dd3px29_avatarImg {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: contain;\n padding: 2px;\n box-sizing: border-box;\n}\n\n.dd3px29_avatarAbbr {\n color: #ffffff;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.3px;\n line-height: 1;\n}\n\n/* A2:节点状态如实显示持久子代理的生命周期。默认中性灰(空闲/就绪/未唤醒\n 都不代表节点坏了),只有真的在跑才用绿色高亮。\n 节点只有 68px 宽,所以这里强制单行 + 省略号:状态标签永远不能换行,\n 否则文字会溢出圆形卡片、和连线叠在一起(\"就绪(可唤醒)\"就是这么翻车的)。\n 完整语义交给 title(activityLifecycleHint)与右栏列表的悬停提示。 */\n.dd3px29_nodeMeta {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n min-height: 12px;\n max-width: calc(100% - 4px);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.dd3px29_nodeMetaWorking {\n color: var(--dsw-alias-state-success-primary);\n}\n\n/* A node that was added then removed: keep it visible so the topology still\n shows which models participated, but degrade it (greyed, no pulse, muted). */\n.dd3px29_nodeRemoved {\n background: var(--dsw-alias-bg-layer-2);\n border-color: var(--dsw-alias-border-l2);\n box-shadow: none;\n opacity: 0.72;\n}\n\n.dd3px29_nodeRemoved .dd3px29_nodeLabel {\n color: var(--dsw-alias-label-secondary);\n text-decoration: line-through;\n}\n\n.dd3px29_nodeRemoved .dd3px29_avatar {\n filter: grayscale(0.8);\n opacity: 0.85;\n}\n\n/* Breathing light: low-opacity pulse, pure CSS — zero tokens. */\n.dd3px29_breathing {\n animation: roundtable-pulse 1.6s ease-in-out infinite;\n}\n\n@keyframes roundtable-pulse {\n 0%, 100% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 28%, transparent), 0 2px 8px color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 75%, transparent);\n }\n 50% {\n box-shadow: 0 0 0 9px color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 0%, transparent), 0 2px 8px color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 45%, transparent);\n }\n}\n\n/* Connector ports: small hit-dots on the node rim that a connector grows out\n of (a Dify-style workflow port). Four per node; each is a 10px circle that\n brightens on hover to signal \"drag from here to wire an edge\". The dots sit\n outside the node circle so the wire visibly starts at the expert's edge. */\n.dd3px29_port {\n position: absolute;\n width: 11px;\n height: 11px;\n border-radius: 50%;\n background: var(--dsw-alias-bg-layer-1);\n border: 2px solid var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 15%, transparent);\n cursor: crosshair;\n opacity: 0;\n transition: opacity 120ms ease, transform 120ms ease, box-shadow 120ms ease;\n z-index: 4;\n}\n\n.dd3px29_node:hover .dd3px29_port,\n.dd3px29_port:focus-visible {\n opacity: 1;\n}\n\n.dd3px29_port:hover {\n transform: scale(1.25);\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 28%, transparent);\n /* 与描边同一强调蓝:此前填 brand-primary,深色下会与蓝色描边自相矛盾。 */\n background: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n}\n\n/* Placement: centered on each rim, slightly outside the 68px circle. */\n.dd3px29_portN { top: -7px; left: calc(50% - 5.5px); }\n.dd3px29_portE { right: -7px; top: calc(50% - 5.5px); }\n.dd3px29_portS { bottom: -7px; left: calc(50% - 5.5px); }\n.dd3px29_portW { left: -7px; top: calc(50% - 5.5px); }\n\n/* Larger captain/aggregator rims need the ports pushed a touch further out. */\n.dd3px29_captainNode .dd3px29_portN { top: -9px; }\n.dd3px29_captainNode .dd3px29_portS { bottom: -9px; }\n.dd3px29_captainNode .dd3px29_portE { right: -9px; }\n.dd3px29_captainNode .dd3px29_portW { left: -9px; }\n.dd3px29_aggregatorNode .dd3px29_portN { top: -8px; }\n.dd3px29_aggregatorNode .dd3px29_portS { bottom: -8px; }\n.dd3px29_aggregatorNode .dd3px29_portE { right: -8px; }\n.dd3px29_aggregatorNode .dd3px29_portW { left: -8px; }\n\n/* While a connector is being dragged, keep every port visible so the user can\n see exactly where they may drop — ports otherwise only appear on hover. */\n.dd3px29_canvasDragging .dd3px29_port {\n opacity: 0.6;\n}\n\n/* ---------- gateway digest ---------- */\n\n.dd3px29_digest {\n flex: none;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2);\n font-size: 12px;\n}\n\n.dd3px29_digest summary {\n cursor: pointer;\n padding: 6px 10px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_digestBody {\n margin: 0;\n padding: 0 10px 10px;\n max-height: 180px;\n overflow: auto;\n font-family: inherit;\n white-space: pre-wrap;\n word-break: break-word;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* ---------- sidebar ---------- */\n\n.dd3px29_sidebar {\n width: 272px;\n flex: none;\n display: flex;\n flex-direction: column;\n gap: 12px;\n overflow-y: auto;\n padding-right: 2px;\n}\n\n/* 右栏顶部操作条:删除会议 + 待办徽标(固定位置,窄屏可见)。 */\n.dd3px29_sidebarActions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n flex: none;\n}\n\n.dd3px29_pendingBadge {\n font-size: 11px;\n color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 50%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n\n/* 专家行\"待移除\"标记(用户已删除、主持人下一轮执行)。 */\n.dd3px29_agentQueuedRemove {\n font-size: 10px;\n color: var(--dsw-alias-state-warn-primary);\n flex: none;\n font-weight: 600;\n}\n\n.dd3px29_panel {\n flex: none;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2);\n overflow: hidden;\n}\n\n.dd3px29_panelTitleRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 10px;\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n/* 面板标题是右栏的\"目录\":用正文色 + 字距,而不是与说明文字同级的灰色。 */\n.dd3px29_panelTitle {\n font-size: 12px;\n font-weight: 650;\n letter-spacing: 0.01em;\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_panelAdd {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n line-height: 16px;\n text-align: center;\n padding: 0;\n cursor: pointer;\n flex: none;\n}\n\n.dd3px29_panelAdd:hover {\n border-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n}\n\n.dd3px29_panelBody {\n padding: 10px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n max-height: 220px;\n overflow-y: auto;\n}\n\n.dd3px29_agentRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dd3px29_agentAvatar {\n width: 26px;\n height: 26px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex: none;\n}\n\n.dd3px29_agentAbbr {\n color: #ffffff;\n font-size: 9px;\n font-weight: 700;\n}\n\n.dd3px29_agentInfo {\n flex: 1;\n min-width: 0;\n}\n\n.dd3px29_agentName {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_agentRole {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.dd3px29_agentStatus {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n flex: none;\n}\n\n.dd3px29_agentStatusWorking {\n font-size: 10px;\n color: var(--dsw-alias-state-success-primary);\n flex: none;\n font-weight: 600;\n}\n\n.dd3px29_agentRowRemoved {\n opacity: 0.6;\n}\n\n.dd3px29_agentRowRemoved .dd3px29_avatar,\n.dd3px29_agentRowRemoved .dd3px29_agentAvatar {\n filter: grayscale(0.8);\n}\n\n.dd3px29_agentRowRemoved .dd3px29_agentName {\n color: var(--dsw-alias-label-secondary);\n text-decoration: line-through;\n}\n\n.dd3px29_agentStatusRemoved {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n font-style: italic;\n flex: none;\n}\n\n.dd3px29_taskRow {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.dd3px29_taskToggle {\n display: flex;\n align-items: center;\n gap: 6px;\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n text-align: left;\n border-radius: 4px;\n}\n\n.dd3px29_taskToggle:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 8%, transparent);\n}\n\n.dd3px29_taskChevron {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n width: 12px;\n flex: none;\n}\n\n.dd3px29_taskKey {\n font-size: 11px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n/* Collapsed: always a single line with an ellipsis, regardless of length. */\n.dd3px29_taskRole {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.35;\n}\n\n/* Expanded: full role, wrapped. */\n.dd3px29_taskRoleExpanded {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n line-height: 1.45;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.dd3px29_panelEmpty {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n line-height: 1.5;\n}\n\n.dd3px29_logRow {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding-bottom: 6px;\n border-bottom: 1px dashed var(--dsw-alias-border-l2);\n}\n\n.dd3px29_logRow:last-child {\n border-bottom: none;\n padding-bottom: 0;\n}\n\n.dd3px29_logHead {\n display: flex;\n justify-content: space-between;\n gap: 6px;\n}\n\n.dd3px29_logFrom {\n font-size: 10px;\n font-weight: 600;\n color: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 90%, transparent);\n}\n\n.dd3px29_logTime {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n}\n\n.dd3px29_logText {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n line-height: 1.45;\n}\n\n/* ---------- context menu ---------- */\n\n.dd3px29_contextMenu {\n position: fixed;\n z-index: 1000;\n min-width: 170px;\n background: var(--dsw-alias-bg-layer-1);\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n box-shadow: 0 6px 20px color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent);\n padding: 4px;\n display: flex;\n flex-direction: column;\n}\n\n.dd3px29_contextMenuTitle {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n padding: 4px 10px;\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n margin-bottom: 4px;\n}\n\n.dd3px29_contextMenuItem,\n.dd3px29_contextMenuItemDanger {\n border: none;\n background: none;\n text-align: left;\n font-size: 13px;\n padding: 7px 10px;\n border-radius: 6px;\n cursor: pointer;\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_contextMenuItem:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 10%, transparent);\n}\n\n.dd3px29_contextMenuItemDanger {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dd3px29_contextMenuItemDanger:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);\n}\n\n/* ---------- empty / error ---------- */\n\n.dd3px29_emptyState {\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n padding: 24px;\n text-align: center;\n}\n\n.dd3px29_emptyTitle {\n font-size: 15px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_emptyHint {\n font-size: 13px;\n color: var(--dsw-alias-label-secondary);\n max-width: 420px;\n line-height: 1.6;\n}\n\n.dd3px29_fetchFailed {\n font-size: 11px;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* Connect-result toast: a short-lived banner at the top of the topology\n canvas telling the user whether a dragged wire landed. Without it a failed\n edge.dd3px29_add (e.dd3px29_g. wiring a removed node) was silently swallowed — the user saw\n nothing and assumed the drag did nothing. White card, black text, no tilt:\n the label sits on a single centered baseline. */\n.dd3px29_toast {\n position: absolute;\n top: 12px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 6;\n max-width: 90%;\n background: var(--dsw-alias-bg-layer-1);\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 8px 16px;\n box-shadow: 0 4px 14px color-mix(in srgb, var(--dsw-alias-label-primary) 18%, transparent);\n pointer-events: none;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1.4;\n text-align: center;\n font-variant-numeric: tabular-nums;\n}\n\n.dd3px29_toastOk {\n font-size: 12.5px;\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n\n.dd3px29_toastErr {\n font-size: 12.5px;\n color: var(--dsw-alias-state-error-primary);\n font-weight: 500;\n}\n\n/* ---------- expert management modal (panel \"+\" buttons) ---------- */\n\n.dd3px29_manageOverlay {\n position: fixed;\n inset: 0;\n z-index: 1200;\n background: var(--dsw-alias-bg-overlay);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.dd3px29_manageModal {\n width: 480px;\n max-width: calc(100vw - 32px);\n max-height: calc(100vh - 48px);\n overflow-y: auto;\n background: var(--dsw-alias-bg-layer-1);\n border-radius: 12px;\n box-shadow: 0 12px 40px color-mix(in srgb, var(--dsw-alias-label-primary) 22%, transparent);\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.dd3px29_manageTitle {\n font-size: 14px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_managePendingNote {\n font-size: 11px;\n color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 45%, transparent);\n border-radius: 8px;\n padding: 6px 10px;\n line-height: 1.5;\n}\n\n.dd3px29_manageSectionTitle {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary);\n margin-top: 2px;\n}\n\n.dd3px29_manageList {\n display: flex;\n flex-direction: column;\n gap: 6px;\n max-height: 220px;\n overflow-y: auto;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 8px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.dd3px29_manageRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dd3px29_managePendingAvatar {\n width: 26px;\n height: 26px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex: none;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 25%, transparent);\n color: var(--dsw-alias-state-warn-primary);\n font-size: 14px;\n font-weight: 700;\n}\n\n.dd3px29_manageStatusTag {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n flex: none;\n}\n\n.dd3px29_managePendingTag {\n font-size: 10px;\n color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 15%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n flex: none;\n font-weight: 600;\n}\n\n.dd3px29_manageRemoveBtn {\n font-size: 11px;\n padding: 2px 10px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-state-error-primary);\n cursor: pointer;\n flex: none;\n}\n\n.dd3px29_manageRemoveBtn:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);\n}\n\n.dd3px29_manageForm {\n display: flex;\n flex-direction: column;\n gap: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 10px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.dd3px29_manageFormRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dd3px29_manageLabel {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n width: 40px;\n flex: none;\n}\n\n.dd3px29_manageInput {\n flex: 1;\n min-width: 0;\n font-size: 12px;\n padding: 4px 8px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_manageSelect {\n flex: 1;\n min-width: 0;\n font-size: 12px;\n padding: 3px 6px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n}\n\n.dd3px29_manageAddBtn {\n align-self: flex-end;\n font-size: 12px;\n padding: 4px 14px;\n border-radius: 6px;\n border: none;\n background: var(--dsw-alias-brand-primary);\n /* 填充的反色,而不是写死的白字:brand-primary 随主题翻转(浅色近黑 / 深色近白),\n 写死 #ffffff 会在深色下变成\"白字压近白底\"。该令牌是宿主 primitives 标准的\n \"填充上的文字色\"(浅色 #fff / 深色 #0f1115),语义正确。 */\n color: var(--dsw-alias-label-primary-foreground);\n cursor: pointer;\n}\n\n.dd3px29_manageAddBtn:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 85%, transparent);\n}\n\n.dd3px29_manageFooter {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n border-top: 1px solid var(--dsw-alias-border-l2);\n padding-top: 10px;\n}\n\n.dd3px29_manageHint {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n line-height: 1.5;\n}\n\n.dd3px29_manageCloseBtn {\n font-size: 12px;\n padding: 4px 14px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n flex: none;\n}\n\n.dd3px29_manageCloseBtn:hover {\n border-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n}\n\n/* ---------- 右栏面板可见性(R3:设置页点圆圈决定显示) ---------- */\n\n/* 被用户关掉的面板不渲染(右栏因此变短,拓扑区自然变大)。 */\n.dd3px29_panelHidden {\n display: none !important;\n}\n\n/* ---------- knowledge base (阅览版) ---------- */\n\n/* skill 传递方式的简短标注(与面板标题同一行,保持界面工整)。 */\n.dd3px29_skillDeliveryLabel {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n font-weight: 400;\n}\n\n.dd3px29_kbPathRow {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 7%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 25%, transparent);\n border-radius: 6px;\n padding: 5px 8px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n word-break: break-all;\n}\n\n.dd3px29_kbPathForm {\n display: flex;\n flex-direction: column;\n gap: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 10px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.dd3px29_kbChangedRow {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n user-select: none;\n}\n\n.dd3px29_switchInput {\n accent-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n cursor: pointer;\n}\n\n.dd3px29_kbList {\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: 240px;\n overflow-y: auto;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 8px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.dd3px29_kbRow {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n}\n\n.dd3px29_kbKindDir,\n.dd3px29_kbKindFile {\n font-size: 13px;\n flex: none;\n opacity: 0.85;\n}\n\n.dd3px29_kbName {\n flex: 1;\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.dd3px29_kbMeta {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n flex: none;\n}\n\n.dd3px29_kbError {\n font-size: 12px;\n color: var(--dsw-alias-state-error-primary);\n line-height: 1.5;\n}\n\n/* ---------- 针锋相对评审弹窗(三区布局) ---------- */\n\n.dd3px29_reviewModal {\n width: 860px;\n max-width: calc(100vw - 32px);\n max-height: calc(100vh - 48px);\n overflow-y: auto;\n background: var(--dsw-alias-bg-layer-1);\n border-radius: 12px;\n box-shadow: 0 12px 40px color-mix(in srgb, var(--dsw-alias-label-primary) 22%, transparent);\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.dd3px29_reviewBody {\n display: flex;\n gap: 12px;\n min-height: 0;\n}\n\n.dd3px29_reviewLeft {\n flex: 0 0 300px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n border-right: 1px solid var(--dsw-alias-border-l2);\n padding-right: 12px;\n max-height: 60vh;\n overflow-y: auto;\n}\n\n.dd3px29_reviewRight {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.dd3px29_reviewSectionTitle {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_reviewQuestion {\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 7%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 25%, transparent);\n border-radius: 8px;\n padding: 8px 10px;\n white-space: pre-wrap;\n word-break: break-word;\n line-height: 1.5;\n}\n\n.dd3px29_reviewPlan {\n font-size: 12px;\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 8px 10px;\n white-space: pre-wrap;\n word-break: break-word;\n line-height: 1.6;\n}\n\n.dd3px29_reviewList {\n display: flex;\n flex-direction: column;\n gap: 10px;\n max-height: 60vh;\n overflow-y: auto;\n padding-right: 4px;\n}\n\n.dd3px29_reviewItem {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n padding: 10px 12px;\n background: var(--dsw-alias-bg-layer-2);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.dd3px29_reviewItemHead {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dd3px29_reviewNode {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n flex: 1;\n}\n\n.dd3px29_reviewSeq {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n font-weight: 600;\n white-space: nowrap;\n}\n\n.dd3px29_reviewEndorsed {\n font-size: 10px;\n color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n font-weight: 600;\n}\n\n.dd3px29_reviewContent {\n font-size: 12px;\n color: var(--dsw-alias-label-primary);\n line-height: 1.6;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.dd3px29_reviewActions {\n display: flex;\n justify-content: flex-end;\n}\n\n/* 表态三态的语义配色:认定(endorsed / support)= 绿系,驳回(rejected / reject)= 红系。\n 与针锋 Crossfire 插件的约定保持一致(认定=绿、驳回=红),\n 避免同一用户在两个插件之间切换时反向读数。不要改回去。 */\n.dd3px29_reviewSupport {\n font-size: 11px;\n padding: 4px 12px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 45%, transparent);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-state-success-primary);\n cursor: pointer;\n}\n\n.dd3px29_reviewSupport:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent);\n}\n\n.dd3px29_reviewSupportDone {\n font-size: 11px;\n padding: 4px 12px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 30%, transparent);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent);\n color: var(--dsw-alias-state-success-primary);\n cursor: default;\n}\n\n.dd3px29_reviewDimension {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 5%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n white-space: nowrap;\n}\n\n.dd3px29_reviewQuote {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 4%, transparent);\n border-left: 3px solid var(--dsw-alias-border-l2);\n padding: 4px 8px;\n border-radius: 0 6px 6px 0;\n line-height: 1.5;\n}\n\n.dd3px29_reviewPending {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n font-weight: 500;\n}\n\n.dd3px29_reviewRejected {\n font-size: 10px;\n color: var(--dsw-alias-state-error-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n font-weight: 600;\n}\n\n.dd3px29_reviewReject {\n font-size: 11px;\n padding: 4px 12px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-state-error-primary);\n cursor: pointer;\n margin-left: 8px;\n}\n\n.dd3px29_reviewReject:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);\n}\n\n.dd3px29_reviewRejectDone {\n font-size: 11px;\n padding: 4px 12px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 30%, transparent);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);\n color: var(--dsw-alias-state-error-primary);\n cursor: default;\n margin-left: 8px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dd3px29_breathing {\n animation: none;\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 60%, transparent);\n }\n}\n\n.dd3px29_reviewPassBadge {\n font-size: 10px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 5%, transparent);\n border-radius: 999px;\n padding: 2px 8px;\n font-weight: 600;\n margin-right: 6px;\n}\n\n.dd3px29_reviewEvidence {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 6%, transparent);\n border-left: 3px solid color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 35%, transparent);\n padding: 4px 8px;\n border-radius: 0 6px 6px 0;\n line-height: 1.5;\n margin-top: 4px;\n white-space: pre-wrap;\n}\n\n.dd3px29_reviewEvidenceLabel {\n font-weight: 600;\n}\n\n.dd3px29_reviewRejectReason {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 3%, transparent);\n border-left: 3px solid var(--dsw-alias-border-l1);\n padding: 4px 8px;\n border-radius: 0 6px 6px 0;\n line-height: 1.5;\n margin-top: 4px;\n}\n\n.dd3px29_reviewRejectBox {\n margin-top: 6px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.dd3px29_reviewRejectLabel {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_reviewRejectInput {\n width: 100%;\n box-sizing: border-box;\n font-size: 12px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n color: inherit;\n resize: vertical;\n min-height: 34px;\n font-family: inherit;\n}\n\n.dd3px29_reviewRejectActions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n}\n\n.dd3px29_reviewImpactBar {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n margin-top: 6px;\n padding: 6px 8px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 4%, transparent);\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dd3px29_reviewImpactWarn {\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 10%, transparent);\n color: var(--dsw-alias-state-warn-primary);\n font-weight: 500;\n}\n\n.dd3px29_feedbackBar {\n position: fixed;\n right: 16px;\n bottom: 16px;\n z-index: 60;\n width: 300px;\n max-width: calc(100vw - 32px);\n background: var(--dsw-alias-bg-layer-1);\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 12px;\n box-shadow: 0 8px 28px color-mix(in srgb, var(--dsw-alias-label-primary) 18%, transparent);\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.dd3px29_feedbackBarTitle {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n line-height: 1.5;\n}\n\n.dd3px29_feedbackBarActions {\n display: flex;\n gap: 6px;\n}\n\n.dd3px29_feedbackRating {\n font-size: 12px;\n padding: 5px 10px;\n border-radius: 999px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 40%, transparent);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 6%, transparent);\n color: var(--dsw-alias-brand-primary-new-colorprimary-new-color);\n cursor: pointer;\n}\n\n.dd3px29_feedbackRating:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 14%, transparent);\n}\n\n.dd3px29_feedbackBarNote {\n width: 100%;\n box-sizing: border-box;\n font-size: 12px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n color: inherit;\n font-family: inherit;\n}\n\n.dd3px29_feedbackBarFooter {\n display: flex;\n justify-content: flex-end;\n}\n\n.dd3px29_feedbackSkip {\n font-size: 11px;\n padding: 3px 10px;\n border-radius: 6px;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n.dd3px29_feedbackSkip:hover {\n color: var(--dsw-alias-label-primary);\n}\n";
|
|
104
104
|
const classMap$1 = {
|
|
105
105
|
"root": "dd3px29_root",
|
|
106
106
|
"main": "dd3px29_main",
|
|
@@ -298,7 +298,9 @@ var RoundTableView_module_css_default = classMap$1;
|
|
|
298
298
|
|
|
299
299
|
//#endregion
|
|
300
300
|
//#region src/client/RoundTableView.tsx
|
|
301
|
-
|
|
301
|
+
/** 节点半径(px):与 `.node` 的 84px 直径一致。连线端点、环形最小半径都靠它,
|
|
302
|
+
* 改节点尺寸时必须同步改这里,否则线会插进节点内部。 */
|
|
303
|
+
const NODE_RADIUS = 42;
|
|
302
304
|
/** Provider → brand avatar (logo image if bundled, else abbreviation + brand color). */
|
|
303
305
|
const PROVIDER_BRAND = [
|
|
304
306
|
{
|
|
@@ -1342,7 +1344,7 @@ function RoundTableView(props) {
|
|
|
1342
1344
|
left: point.x,
|
|
1343
1345
|
top: point.y
|
|
1344
1346
|
},
|
|
1345
|
-
title: node === void 0 ? label : `${
|
|
1347
|
+
title: node === void 0 ? label : `${node.key}${node.role !== "" ? ` · ${node.role}` : ""}`,
|
|
1346
1348
|
children: [
|
|
1347
1349
|
brand !== null ? brandAvatar(brand, "node") : null,
|
|
1348
1350
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -1547,7 +1549,7 @@ function RoundTableView(props) {
|
|
|
1547
1549
|
}),
|
|
1548
1550
|
renderNode("captain", "DeepSeek · 主持", "captain"),
|
|
1549
1551
|
renderNode("aggregator", "汇聚网关", "aggregator"),
|
|
1550
|
-
meeting.nodes.filter((node) => node.status !== "removed").map((node) => renderNode(node.key, node.key, "node")),
|
|
1552
|
+
meeting.nodes.filter((node) => node.status !== "removed").map((node) => renderNode(node.key, node.key.startsWith("expert-") ? node.key.slice(7) : node.key, "node")),
|
|
1551
1553
|
edgeRemoveDots.map((dot) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1552
1554
|
type: "button",
|
|
1553
1555
|
className: [RoundTableView_module_css_default.edgeRemove, hoverEdgeId === dot.id ? RoundTableView_module_css_default.edgeRemoveActive : ""].filter(Boolean).join(" "),
|
|
@@ -2551,9 +2553,77 @@ function RoundTableView(props) {
|
|
|
2551
2553
|
});
|
|
2552
2554
|
}
|
|
2553
2555
|
|
|
2556
|
+
//#endregion
|
|
2557
|
+
//#region src/client/icons.tsx
|
|
2558
|
+
const SHAPES = {
|
|
2559
|
+
panel: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
2560
|
+
x: "2.2",
|
|
2561
|
+
y: "3.2",
|
|
2562
|
+
width: "11.6",
|
|
2563
|
+
height: "9.6",
|
|
2564
|
+
rx: "2"
|
|
2565
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M6.2 3.2v9.6" })] }),
|
|
2566
|
+
skill: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M9.2 2 4.6 8.8h3L6.8 14l4.6-6.8h-3L9.2 2Z" }),
|
|
2567
|
+
role: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2568
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
2569
|
+
x: "2.2",
|
|
2570
|
+
y: "3.2",
|
|
2571
|
+
width: "11.6",
|
|
2572
|
+
height: "9.6",
|
|
2573
|
+
rx: "2"
|
|
2574
|
+
}),
|
|
2575
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
2576
|
+
cx: "6",
|
|
2577
|
+
cy: "7.2",
|
|
2578
|
+
r: "1.4"
|
|
2579
|
+
}),
|
|
2580
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8.6 6.4h3.2M8.6 8.4h2.4" })
|
|
2581
|
+
] }),
|
|
2582
|
+
squad: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2583
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
2584
|
+
cx: "6",
|
|
2585
|
+
cy: "6",
|
|
2586
|
+
r: "2"
|
|
2587
|
+
}),
|
|
2588
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.6 13c.3-2.1 1.7-3.2 3.4-3.2s3.1 1.1 3.4 3.2" }),
|
|
2589
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
2590
|
+
cx: "11.4",
|
|
2591
|
+
cy: "6.6",
|
|
2592
|
+
r: "1.5"
|
|
2593
|
+
}),
|
|
2594
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M11.4 9.4c1.5 0 2.5 1 2.8 2.6" })
|
|
2595
|
+
] }),
|
|
2596
|
+
gauge: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2597
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.2 11.5a5.8 5.8 0 1 1 11.6 0" }),
|
|
2598
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 11.5 10.8 6.5" }),
|
|
2599
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
2600
|
+
cx: "8",
|
|
2601
|
+
cy: "11.5",
|
|
2602
|
+
r: "0.9"
|
|
2603
|
+
})
|
|
2604
|
+
] }),
|
|
2605
|
+
message: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3 3.4h10a1.6 1.6 0 0 1 1.6 1.6v5.2A1.6 1.6 0 0 1 13 11.8H8.4L5 14v-2.2H3A1.6 1.6 0 0 1 1.4 10.2V5A1.6 1.6 0 0 1 3 3.4Z" })
|
|
2606
|
+
};
|
|
2607
|
+
/** 渲染一个 16×16 线性图标,颜色跟随 `currentColor`。 */
|
|
2608
|
+
function InlineIcon({ name, size = 14 }) {
|
|
2609
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
2610
|
+
width: size,
|
|
2611
|
+
height: size,
|
|
2612
|
+
viewBox: "0 0 16 16",
|
|
2613
|
+
fill: "none",
|
|
2614
|
+
stroke: "currentColor",
|
|
2615
|
+
strokeWidth: "1.4",
|
|
2616
|
+
strokeLinecap: "round",
|
|
2617
|
+
strokeLinejoin: "round",
|
|
2618
|
+
"aria-hidden": "true",
|
|
2619
|
+
focusable: "false",
|
|
2620
|
+
children: SHAPES[name]
|
|
2621
|
+
});
|
|
2622
|
+
}
|
|
2623
|
+
|
|
2554
2624
|
//#endregion
|
|
2555
2625
|
//#region \0dsh-css:F:\AI\DSH\1changyong\dsh-plugin-roundtable\src\client\RoundTableSettings.module.css.mjs
|
|
2556
|
-
const css = ".dx5ni8t_root {\n display: flex;\n flex-direction: column;\n gap: 16px;\n max-width: 560px;\n padding: 8px 0;\n}\n\n.dx5ni8t_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.dx5ni8t_label {\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n.dx5ni8t_select,\n.dx5ni8t_input {\n font-size: 13px;\n padding: 6px 10px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n max-width: 260px;\n}\n\n.dx5ni8t_hint {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n line-height: 1.6;\n}\n\n/* Minimal toggle switch. */\n.dx5ni8t_switchRow {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n width: fit-content;\n}\n\n.dx5ni8t_switchInput {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n}\n\n.dx5ni8t_switchTrack {\n position: relative;\n width: 36px;\n height: 20px;\n border-radius: 999px;\n background: var(--dsw-alias-border-l2);\n transition: background 140ms ease;\n flex: none;\n}\n\n.dx5ni8t_switchTrack::after {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n /* 保留 #ffffff:滑块是「实底上的前景」(品牌蓝轨道 / 弱灰轨道),13 个令牌里没有\n on-brand 前景色;深色主题下白滑块在两种轨道上对比都是对的。\n 保留 rgba(0,0,0,0.25):投影没有对应令牌,换成任何语义色都会渲染错。 */\n background: #ffffff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);\n transition: transform 140ms ease;\n}\n\n.dx5ni8t_switchInput:checked + .dx5ni8t_switchTrack {\n background: var(--dsw-alias-brand-primary);\n}\n\n.dx5ni8t_switchInput:checked + .dx5ni8t_switchTrack::after {\n transform: translateX(16px);\n}\n\n.dx5ni8t_switchLabel {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dx5ni8t_warning {\n font-size: 12px;\n color: var(--dsw-alias-state-warn-primary);\n padding: 8px 10px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n line-height: 1.6;\n}\n\n.dx5ni8t_actions {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.dx5ni8t_saveButton {\n font-size: 13px;\n padding: 7px 18px;\n border-radius: 8px;\n border: none;\n background: var(--dsw-alias-brand-primary);\n /* 保留 #ffffff:品牌实底上的按钮文字,13 个令牌里没有 on-brand 前景色。 */\n color: #ffffff;\n cursor: pointer;\n}\n\n.dx5ni8t_saveButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.dx5ni8t_saved {\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.dx5ni8t_failed {\n font-size: 12px;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dx5ni8t_note {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dx5ni8t_sectionDivider {\n height: 1px;\n background: var(--dsw-alias-border-l2);\n margin: 2px 0;\n}\n\n.dx5ni8t_sectionTitle {\n font-size: 13px;\n font-weight: 700;\n color: var(--dsw-alias-label-primary);\n}\n\n/* ---------- R3:右栏面板显示(点圆圈决定显示/隐藏) ---------- */\n\n.dx5ni8t_panelToggles {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n max-width: 100%;\n}\n\n.dx5ni8t_panelToggleOn,\n.dx5ni8t_panelToggleOff {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n padding: 5px 10px 5px 8px;\n border-radius: 999px;\n cursor: pointer;\n transition: background 140ms ease, border-color 140ms ease, color 140ms ease;\n}\n\n/* 点亮 = 显示;暗掉 = 隐藏。 */\n.dx5ni8t_panelToggleOn {\n border: 1px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, transparent);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent);\n color: var(--dsw-alias-label-primary);\n}\n\n.dx5ni8t_panelToggleOff {\n border: 1px solid var(--dsw-alias-border-l2);\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dx5ni8t_panelDot {\n width: 9px;\n height: 9px;\n border-radius: 50%;\n flex: none;\n border: 1px solid transparent;\n}\n\n.dx5ni8t_panelToggleOn .dx5ni8t_panelDot {\n background: var(--dsw-alias-brand-primary);\n}\n\n.dx5ni8t_panelToggleOff .dx5ni8t_panelDot {\n background: transparent;\n border-color: var(--dsw-alias-border-l1);\n}\n\n.dx5ni8t_panelToggleLabel {\n line-height: 1;\n}\n\n.dx5ni8t_feedbackNote {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 6%, transparent);\n border-left: 3px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 30%, transparent);\n padding: 6px 10px;\n border-radius: 0 8px 8px 0;\n line-height: 1.6;\n}\n\n.dx5ni8t_feedbackList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n max-height: 260px;\n overflow-y: auto;\n}\n\n.dx5ni8t_feedbackItem {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 8px 10px;\n line-height: 1.5;\n}\n\n.dx5ni8t_feedbackMeta {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dx5ni8t_feedbackNoteText {\n margin-top: 4px;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.dx5ni8t_feedbackClearBtn {\n font-size: 12px;\n padding: 4px 12px;\n border-radius: 8px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);\n background: transparent;\n color: var(--dsw-alias-state-error-primary);\n cursor: pointer;\n align-self: flex-start;\n}\n\n.dx5ni8t_feedbackClearBtn:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 6%, transparent);\n}\n\n/* ---------- B3:用户自建角色预设(扁平、克制,与 panelToggles 同观感) ---------- */\n\n.dx5ni8t_presetList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n max-height: 260px;\n overflow-y: auto;\n}\n\n.dx5ni8t_presetItem {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 8px 10px;\n}\n\n.dx5ni8t_presetInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n flex: 1;\n}\n\n.dx5ni8t_presetName {\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n.dx5ni8t_presetMeta {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n line-height: 1.5;\n word-break: break-word;\n}\n\n.dx5ni8t_presetRoute {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dx5ni8t_presetActions {\n display: flex;\n gap: 6px;\n flex: none;\n}\n\n.dx5ni8t_presetBtn {\n font-size: 12px;\n padding: 4px 10px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n.dx5ni8t_presetBtn:hover {\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.dx5ni8t_presetDeleteBtn {\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 35%, transparent);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dx5ni8t_presetDeleteBtn:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 6%, transparent);\n}\n\n.dx5ni8t_presetForm {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n border-radius: 8px;\n border: 1px dashed var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.dx5ni8t_presetFormRow {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.dx5ni8t_presetModelRow {\n display: flex;\n gap: 8px;\n}\n\n.dx5ni8t_presetSelect {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n padding: 6px 10px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n}\n\n.dx5ni8t_presetFormActions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dx5ni8t_presetAddBtn {\n font-size: 13px;\n padding: 7px 18px;\n border-radius: 8px;\n border: none;\n background: var(--dsw-alias-brand-primary);\n /* 保留 #ffffff:品牌实底上的按钮文字,13 个令牌里没有 on-brand 前景色。 */\n color: #ffffff;\n cursor: pointer;\n align-self: flex-start;\n}\n\n.dx5ni8t_presetCancelBtn {\n font-size: 12px;\n padding: 4px 10px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n.dx5ni8t_presetCancelBtn:hover {\n background: var(--dsw-alias-bg-layer-2);\n}\n\n/* ---------- B3+:阵容预设的成员行 ----------\n 一行 = 专家 key + 角色 + provider + model + 移除。窄屏折行,避免把\n 设置页撑出横向滚动条。 */\n\n.dx5ni8t_squadMemberRow {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n align-items: center;\n}\n\n.dx5ni8t_squadMemberRow .dx5ni8t_presetSelect {\n flex: 1 1 120px;\n min-width: 0;\n}\n";
|
|
2626
|
+
const css = "/* ---- 本地设计令牌(与针锋设置页同值,视觉重量刻意更低) ----\n *\n * 圆桌的设置页**不套卡片**:它的主界面是拓扑画布 + 右侧多面板,本来信息密度就高,\n * 设置页再加一层带边框的卡片,两个插件并排时会有明显割裂感。这里只共享\n * 字号 / 圆角 / 间距 / 控件规格,分组靠「细线 + 标题」表达。\n */\n.dx5ni8t_root {\n --rt-fs-11: 11px;\n --rt-fs-12: 12px;\n --rt-fs-13: 13px;\n --rt-fs-14: 14px;\n --rt-radius-s: 6px;\n --rt-radius-m: 8px;\n --rt-radius-l: 12px;\n --rt-space-1: 4px;\n --rt-space-2: 8px;\n --rt-space-3: 12px;\n --rt-space-4: 16px;\n --rt-control-h: 32px;\n --rt-border: var(--dsw-alias-border-l1);\n --rt-border-strong: var(--dsw-alias-border-l2);\n --rt-bg-soft: var(--dsw-alias-bg-layer-2);\n --rt-fg: var(--dsw-alias-label-primary);\n --rt-fg-2: var(--dsw-alias-label-secondary);\n --rt-brand: var(--dsw-alias-brand-primary);\n --rt-on-brand: var(--dsw-alias-bg-base);\n\n display: flex;\n flex-direction: column;\n gap: var(--rt-space-3);\n max-width: 620px;\n padding: 8px 0;\n color: var(--rt-fg);\n font-size: var(--rt-fs-13);\n line-height: 1.6;\n}\n\n.dx5ni8t_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.dx5ni8t_label {\n font-size: var(--rt-fs-13);\n font-weight: 600;\n color: var(--rt-fg);\n}\n\n.dx5ni8t_select,\n.dx5ni8t_input {\n box-sizing: border-box;\n min-height: var(--rt-control-h);\n width: 100%;\n max-width: 320px;\n font-size: var(--rt-fs-13);\n padding: 6px 10px;\n border-radius: var(--rt-radius-m);\n border: 1px solid var(--rt-border-strong);\n background: var(--rt-bg-soft);\n color: var(--rt-fg);\n}\n\n.dx5ni8t_hint {\n font-size: var(--rt-fs-12);\n color: var(--rt-fg-2);\n line-height: 1.7;\n}\n\n/* Minimal toggle switch. */\n.dx5ni8t_switchRow {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n width: fit-content;\n}\n\n.dx5ni8t_switchInput {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n}\n\n.dx5ni8t_switchTrack {\n position: relative;\n width: 36px;\n height: 20px;\n border-radius: 999px;\n background: var(--dsw-alias-border-l2);\n transition: background 140ms ease;\n flex: none;\n}\n\n.dx5ni8t_switchTrack::after {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n /* 保留 #ffffff:滑块是「实底上的前景」(品牌蓝轨道 / 弱灰轨道),13 个令牌里没有\n on-brand 前景色;深色主题下白滑块在两种轨道上对比都是对的。\n 保留 rgba(0,0,0,0.25):投影没有对应令牌,换成任何语义色都会渲染错。 */\n background: #ffffff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);\n transition: transform 140ms ease;\n}\n\n.dx5ni8t_switchInput:checked + .dx5ni8t_switchTrack {\n background: var(--dsw-alias-brand-primary);\n}\n\n.dx5ni8t_switchInput:checked + .dx5ni8t_switchTrack::after {\n transform: translateX(16px);\n}\n\n.dx5ni8t_switchLabel {\n font-size: var(--rt-fs-12);\n color: var(--rt-fg-2);\n}\n\n.dx5ni8t_warning {\n font-size: 12px;\n color: var(--dsw-alias-state-warn-primary);\n padding: 8px 10px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n line-height: 1.6;\n}\n\n.dx5ni8t_actions {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.dx5ni8t_saveButton {\n box-sizing: border-box;\n min-height: var(--rt-control-h);\n font-size: var(--rt-fs-13);\n font-weight: 600;\n padding: 6px 16px;\n border-radius: var(--rt-radius-m);\n border: none;\n background: var(--rt-brand);\n color: var(--rt-on-brand);\n cursor: pointer;\n}\n\n.dx5ni8t_saveButton:hover:not(:disabled) {\n filter: brightness(1.06);\n}\n\n.dx5ni8t_saveButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.dx5ni8t_saved {\n font-size: var(--rt-fs-12);\n color: var(--dsw-alias-state-success-primary);\n}\n\n.dx5ni8t_failed {\n font-size: var(--rt-fs-12);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dx5ni8t_note {\n font-size: var(--rt-fs-12);\n color: var(--rt-fg-2);\n}\n\n/* 分组:一条极淡的细线 + 一个紧贴其下的组标题。\n *\n * 之前是「1px 线 + 同样的 16px 空隙」,线和标题之间没有关系,读起来像随机分隔;\n * 现在让线成为标题的\"上边界\",标题到内容收紧到 8px,分组因此可辨。 */\n.dx5ni8t_sectionDivider {\n height: 1px;\n background: var(--rt-border);\n margin: var(--rt-space-3) 0 0;\n}\n\n.dx5ni8t_sectionTitle {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: var(--rt-fs-13);\n font-weight: 650;\n letter-spacing: 0.02em;\n color: var(--rt-fg);\n}\n\n/* 图标降一档:它是\"目录\"记号,不和文字抢。 */\n.dx5ni8t_sectionTitle svg {\n flex: none;\n color: var(--rt-fg-2);\n}\n\n/* 组标题与它下面的第一个控件贴紧,避免标题\"漂\"在两段空隙中间。 */\n.dx5ni8t_sectionTitle + .dx5ni8t_field,\n.dx5ni8t_sectionTitle + .dx5ni8t_panelToggles,\n.dx5ni8t_sectionTitle + .dx5ni8t_switchRow,\n.dx5ni8t_sectionTitle + .dx5ni8t_feedbackList,\n.dx5ni8t_sectionTitle + .dx5ni8t_presetList {\n margin-top: calc(var(--rt-space-1) * -1);\n}\n\n/* ---------- R3:右栏面板显示(点圆圈决定显示/隐藏) ---------- */\n\n/* 面板开关排成等宽网格:七项用 flex+wrap 时最后一行只剩一个,看起来像漏排。\n * 网格让每一行的起点对齐,行数随宽度自然变化。 */\n.dx5ni8t_panelToggles {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(136px, 1fr));\n gap: var(--rt-space-2);\n max-width: 100%;\n}\n\n.dx5ni8t_panelToggleOn,\n.dx5ni8t_panelToggleOff {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-height: 30px;\n font-size: var(--rt-fs-12);\n padding: 4px 10px 4px 8px;\n border-radius: 999px;\n cursor: pointer;\n transition: background 140ms ease, border-color 140ms ease, color 140ms ease;\n}\n\n/* 点亮 = 显示;暗掉 = 隐藏。 */\n.dx5ni8t_panelToggleOn {\n border: 1px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, transparent);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent);\n color: var(--dsw-alias-label-primary);\n}\n\n.dx5ni8t_panelToggleOff {\n border: 1px solid var(--dsw-alias-border-l2);\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dx5ni8t_panelDot {\n width: 9px;\n height: 9px;\n border-radius: 50%;\n flex: none;\n border: 1px solid transparent;\n}\n\n.dx5ni8t_panelToggleOn .dx5ni8t_panelDot {\n background: var(--dsw-alias-brand-primary);\n}\n\n.dx5ni8t_panelToggleOff .dx5ni8t_panelDot {\n background: transparent;\n border-color: var(--dsw-alias-border-l1);\n}\n\n.dx5ni8t_panelToggleLabel {\n line-height: 1;\n}\n\n.dx5ni8t_feedbackNote {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 6%, transparent);\n border-left: 3px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 30%, transparent);\n padding: 6px 10px;\n border-radius: 0 8px 8px 0;\n line-height: 1.6;\n}\n\n.dx5ni8t_feedbackList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n max-height: 260px;\n overflow-y: auto;\n}\n\n.dx5ni8t_feedbackItem {\n font-size: var(--rt-fs-12);\n color: var(--rt-fg-2);\n background: var(--rt-bg-soft);\n border: 1px solid transparent;\n border-radius: var(--rt-radius-m);\n padding: 8px 10px;\n line-height: 1.5;\n}\n\n.dx5ni8t_feedbackMeta {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.dx5ni8t_feedbackNoteText {\n margin-top: 4px;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.dx5ni8t_feedbackClearBtn {\n box-sizing: border-box;\n min-height: 28px;\n font-size: var(--rt-fs-12);\n padding: 3px 12px;\n border-radius: var(--rt-radius-s);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);\n background: transparent;\n color: var(--dsw-alias-state-error-primary);\n cursor: pointer;\n align-self: flex-start;\n}\n\n.dx5ni8t_feedbackClearBtn:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 6%, transparent);\n}\n\n/* ---------- B3:用户自建角色预设(扁平、克制,与 panelToggles 同观感) ---------- */\n\n.dx5ni8t_presetList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n max-height: 260px;\n overflow-y: auto;\n}\n\n.dx5ni8t_presetItem {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: var(--rt-fs-12);\n color: var(--rt-fg-2);\n background: var(--rt-bg-soft);\n border: 1px solid transparent;\n border-radius: var(--rt-radius-m);\n padding: 8px 10px;\n}\n\n.dx5ni8t_presetInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n flex: 1;\n}\n\n.dx5ni8t_presetName {\n font-size: var(--rt-fs-13);\n font-weight: 600;\n color: var(--rt-fg);\n}\n\n.dx5ni8t_presetMeta {\n font-size: var(--rt-fs-11);\n color: var(--rt-fg-2);\n line-height: 1.5;\n word-break: break-word;\n}\n\n.dx5ni8t_presetRoute {\n font-size: var(--rt-fs-11);\n color: var(--rt-fg-2);\n}\n\n.dx5ni8t_presetActions {\n display: flex;\n gap: 6px;\n flex: none;\n}\n\n.dx5ni8t_presetBtn {\n box-sizing: border-box;\n min-height: 28px;\n font-size: var(--rt-fs-12);\n padding: 3px 10px;\n border-radius: var(--rt-radius-s);\n border: 1px solid var(--rt-border-strong);\n background: transparent;\n color: var(--rt-fg-2);\n cursor: pointer;\n}\n\n.dx5ni8t_presetBtn:hover {\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.dx5ni8t_presetDeleteBtn {\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 35%, transparent);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dx5ni8t_presetDeleteBtn:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 6%, transparent);\n}\n\n.dx5ni8t_presetForm {\n display: flex;\n flex-direction: column;\n gap: var(--rt-space-2);\n padding: 12px;\n border-radius: var(--rt-radius-l);\n border: 1px solid var(--rt-border);\n background: var(--rt-bg-soft);\n}\n\n.dx5ni8t_presetFormRow {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.dx5ni8t_presetModelRow {\n display: flex;\n gap: 8px;\n}\n\n.dx5ni8t_presetSelect {\n box-sizing: border-box;\n flex: 1;\n min-width: 0;\n min-height: var(--rt-control-h);\n font-size: var(--rt-fs-13);\n padding: 6px 10px;\n border-radius: var(--rt-radius-m);\n border: 1px solid var(--rt-border-strong);\n background: var(--rt-bg-soft);\n color: var(--rt-fg);\n}\n\n.dx5ni8t_presetFormActions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dx5ni8t_presetAddBtn {\n box-sizing: border-box;\n min-height: var(--rt-control-h);\n font-size: var(--rt-fs-13);\n font-weight: 600;\n padding: 6px 16px;\n border-radius: var(--rt-radius-m);\n border: none;\n background: var(--rt-brand);\n color: var(--rt-on-brand);\n cursor: pointer;\n align-self: flex-start;\n}\n\n.dx5ni8t_presetCancelBtn {\n box-sizing: border-box;\n min-height: 28px;\n font-size: var(--rt-fs-12);\n padding: 3px 12px;\n border-radius: var(--rt-radius-s);\n border: 1px solid var(--rt-border-strong);\n background: transparent;\n color: var(--rt-fg-2);\n cursor: pointer;\n}\n\n.dx5ni8t_presetCancelBtn:hover {\n background: var(--dsw-alias-bg-layer-2);\n}\n\n/* ---------- B3+:阵容预设的成员行 ----------\n 一行 = 专家 key + 角色 + provider + model + 移除。窄屏折行,避免把\n 设置页撑出横向滚动条。 */\n\n.dx5ni8t_squadMemberRow {\n display: flex;\n flex-wrap: wrap;\n gap: var(--rt-space-2);\n align-items: center;\n}\n\n.dx5ni8t_squadMemberRow .dx5ni8t_presetSelect {\n flex: 1 1 140px;\n min-width: 0;\n}\n";
|
|
2557
2627
|
const classMap = {
|
|
2558
2628
|
"root": "dx5ni8t_root",
|
|
2559
2629
|
"field": "dx5ni8t_field",
|
|
@@ -2574,17 +2644,17 @@ const classMap = {
|
|
|
2574
2644
|
"sectionDivider": "dx5ni8t_sectionDivider",
|
|
2575
2645
|
"sectionTitle": "dx5ni8t_sectionTitle",
|
|
2576
2646
|
"panelToggles": "dx5ni8t_panelToggles",
|
|
2647
|
+
"feedbackList": "dx5ni8t_feedbackList",
|
|
2648
|
+
"presetList": "dx5ni8t_presetList",
|
|
2577
2649
|
"panelToggleOn": "dx5ni8t_panelToggleOn",
|
|
2578
2650
|
"panelToggleOff": "dx5ni8t_panelToggleOff",
|
|
2579
2651
|
"panelDot": "dx5ni8t_panelDot",
|
|
2580
2652
|
"panelToggleLabel": "dx5ni8t_panelToggleLabel",
|
|
2581
2653
|
"feedbackNote": "dx5ni8t_feedbackNote",
|
|
2582
|
-
"feedbackList": "dx5ni8t_feedbackList",
|
|
2583
2654
|
"feedbackItem": "dx5ni8t_feedbackItem",
|
|
2584
2655
|
"feedbackMeta": "dx5ni8t_feedbackMeta",
|
|
2585
2656
|
"feedbackNoteText": "dx5ni8t_feedbackNoteText",
|
|
2586
2657
|
"feedbackClearBtn": "dx5ni8t_feedbackClearBtn",
|
|
2587
|
-
"presetList": "dx5ni8t_presetList",
|
|
2588
2658
|
"presetItem": "dx5ni8t_presetItem",
|
|
2589
2659
|
"presetInfo": "dx5ni8t_presetInfo",
|
|
2590
2660
|
"presetName": "dx5ni8t_presetName",
|
|
@@ -3083,9 +3153,9 @@ function RoundTableSettings(props) {
|
|
|
3083
3153
|
]
|
|
3084
3154
|
}),
|
|
3085
3155
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: RoundTableSettings_module_css_default.sectionDivider }),
|
|
3086
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3156
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3087
3157
|
className: RoundTableSettings_module_css_default.sectionTitle,
|
|
3088
|
-
children: t("settingsPanelsTitle")
|
|
3158
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineIcon, { name: "panel" }), t("settingsPanelsTitle")]
|
|
3089
3159
|
}),
|
|
3090
3160
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3091
3161
|
className: RoundTableSettings_module_css_default.field,
|
|
@@ -3147,9 +3217,9 @@ function RoundTableSettings(props) {
|
|
|
3147
3217
|
]
|
|
3148
3218
|
}),
|
|
3149
3219
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: RoundTableSettings_module_css_default.sectionDivider }),
|
|
3150
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3220
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3151
3221
|
className: RoundTableSettings_module_css_default.sectionTitle,
|
|
3152
|
-
children: t("settingsSkillTitle")
|
|
3222
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineIcon, { name: "skill" }), t("settingsSkillTitle")]
|
|
3153
3223
|
}),
|
|
3154
3224
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3155
3225
|
className: RoundTableSettings_module_css_default.field,
|
|
@@ -3177,9 +3247,9 @@ function RoundTableSettings(props) {
|
|
|
3177
3247
|
]
|
|
3178
3248
|
}),
|
|
3179
3249
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: RoundTableSettings_module_css_default.sectionDivider }),
|
|
3180
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3250
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3181
3251
|
className: RoundTableSettings_module_css_default.sectionTitle,
|
|
3182
|
-
children: t("settingsPresetsTitle")
|
|
3252
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineIcon, { name: "role" }), t("settingsPresetsTitle")]
|
|
3183
3253
|
}),
|
|
3184
3254
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3185
3255
|
className: RoundTableSettings_module_css_default.field,
|
|
@@ -3340,9 +3410,9 @@ function RoundTableSettings(props) {
|
|
|
3340
3410
|
]
|
|
3341
3411
|
}),
|
|
3342
3412
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: RoundTableSettings_module_css_default.sectionDivider }),
|
|
3343
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3413
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3344
3414
|
className: RoundTableSettings_module_css_default.sectionTitle,
|
|
3345
|
-
children: t("settingsSquadTitle")
|
|
3415
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineIcon, { name: "squad" }), t("settingsSquadTitle")]
|
|
3346
3416
|
}),
|
|
3347
3417
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3348
3418
|
className: RoundTableSettings_module_css_default.field,
|
|
@@ -3517,9 +3587,9 @@ function RoundTableSettings(props) {
|
|
|
3517
3587
|
]
|
|
3518
3588
|
}),
|
|
3519
3589
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: RoundTableSettings_module_css_default.sectionDivider }),
|
|
3520
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3590
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3521
3591
|
className: RoundTableSettings_module_css_default.sectionTitle,
|
|
3522
|
-
children: t("settingsLimitsTitle")
|
|
3592
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineIcon, { name: "gauge" }), t("settingsLimitsTitle")]
|
|
3523
3593
|
}),
|
|
3524
3594
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3525
3595
|
className: RoundTableSettings_module_css_default.field,
|
|
@@ -3567,9 +3637,9 @@ function RoundTableSettings(props) {
|
|
|
3567
3637
|
]
|
|
3568
3638
|
}),
|
|
3569
3639
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: RoundTableSettings_module_css_default.sectionDivider }),
|
|
3570
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3640
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3571
3641
|
className: RoundTableSettings_module_css_default.sectionTitle,
|
|
3572
|
-
children: t("feedbackTitle")
|
|
3642
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineIcon, { name: "message" }), t("feedbackTitle")]
|
|
3573
3643
|
}),
|
|
3574
3644
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3575
3645
|
className: RoundTableSettings_module_css_default.field,
|
package/lib/index.js
CHANGED
|
@@ -89,7 +89,7 @@ async function evaluateKbDigests(entries) {
|
|
|
89
89
|
* @module dsh-plugin-roundtable/version
|
|
90
90
|
*/
|
|
91
91
|
/** 当前插件版本(必须与 package.json 的 version 逐字一致)。 */
|
|
92
|
-
const PLUGIN_VERSION = "1.0.0-rc.
|
|
92
|
+
const PLUGIN_VERSION = "1.0.0-rc.6";
|
|
93
93
|
/** 导出物头部使用的插件标识行。 */
|
|
94
94
|
const PLUGIN_ID = `@y9931666/dsh-plugin-roundtable v${PLUGIN_VERSION}`;
|
|
95
95
|
/** DeepSeek Harness 版本区间(导出头部展示用)。
|
|
@@ -98,7 +98,7 @@ const PLUGIN_ID = `@y9931666/dsh-plugin-roundtable v${PLUGIN_VERSION}`;
|
|
|
98
98
|
* `test/compatibility.test.mjs` 强制,`scripts/compatibility.mjs` 参与发布门禁。
|
|
99
99
|
* 此前这里是硬编码字符串,与 devDependencies 一起漂到了 rc.2 而无人发现;
|
|
100
100
|
* 0.2.0-rc.2 这次跨大版本升级同样由这两道闸门兜住。 */
|
|
101
|
-
const HARNESS_RANGE = "DeepSeek Harness 0.2.
|
|
101
|
+
const HARNESS_RANGE = "DeepSeek Harness 0.2.1-rc.5+";
|
|
102
102
|
|
|
103
103
|
//#endregion
|
|
104
104
|
//#region src/charter.ts
|
|
@@ -863,8 +863,6 @@ async function spawnNode(ctx, config, meeting, node, captain, stateDir, signal,
|
|
|
863
863
|
const provider = ctx.subagents.getProvider(config.provider);
|
|
864
864
|
if (provider === void 0) throw new Error(`roundtable: no subagent provider "${config.provider}" is registered (available: ${ctx.subagents.list().join(", ") || "none"}) — check that the subagent provider row (e.g. subagent-spawn) is mounted in the composition`);
|
|
865
865
|
if (provider.prepareContinuable === void 0) throw new Error(`roundtable: provider "${config.provider}" does not support continuable nodes`);
|
|
866
|
-
if (!provider.capabilities.persona) throw new Error(`roundtable: provider "${config.provider}" cannot apply a node persona`);
|
|
867
|
-
if (!provider.capabilities.toolFilter) throw new Error(`roundtable: provider "${config.provider}" cannot restrict captain-only tools for nodes`);
|
|
868
866
|
const label = `${NODE_LABEL_PREFIX}${meeting.id}:${node.key}`;
|
|
869
867
|
const agentOptions = {};
|
|
870
868
|
if (node.provider !== void 0 && node.model !== void 0) {
|
|
@@ -876,27 +874,47 @@ async function spawnNode(ctx, config, meeting, node, captain, stateDir, signal,
|
|
|
876
874
|
if (limits.maxTokens !== void 0 && limits.maxTokens > 0) agentOptions.maxTokens = limits.maxTokens;
|
|
877
875
|
const delivery = skill.delivery ?? meeting.skillDelivery ?? "relay";
|
|
878
876
|
const skillToolAvailable = ctx.tools.get("skill", captain) !== void 0;
|
|
879
|
-
const
|
|
877
|
+
const persona = nodePersona(meeting, node, stateDir, limits, {
|
|
878
|
+
...skill,
|
|
879
|
+
delivery,
|
|
880
|
+
skillToolAvailable
|
|
881
|
+
});
|
|
882
|
+
const prompt = [{
|
|
883
|
+
type: "text",
|
|
884
|
+
text: nodeWelcome(meeting, node)
|
|
885
|
+
}];
|
|
886
|
+
const request = {
|
|
887
|
+
prompt,
|
|
888
|
+
parent: captain,
|
|
889
|
+
...Object.keys(agentOptions).length > 0 ? { agentOptions } : {},
|
|
890
|
+
...config.maxDepth !== void 0 ? { maxDepth: config.maxDepth } : {}
|
|
891
|
+
};
|
|
892
|
+
const subagents = ctx.subagents;
|
|
893
|
+
let childId;
|
|
894
|
+
if (typeof subagents.startActivation === "function") {
|
|
895
|
+
request.prompt = [...prompt, {
|
|
896
|
+
type: "text",
|
|
897
|
+
text: persona
|
|
898
|
+
}];
|
|
899
|
+
childId = (await subagents.startActivation({
|
|
900
|
+
provider: config.provider,
|
|
901
|
+
label,
|
|
902
|
+
request,
|
|
903
|
+
signal,
|
|
904
|
+
delivery: "parent"
|
|
905
|
+
})).childId;
|
|
906
|
+
} else if (typeof subagents.startContinuable === "function") childId = (await subagents.startContinuable({
|
|
880
907
|
provider: config.provider,
|
|
881
908
|
label,
|
|
882
909
|
request: {
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
}],
|
|
887
|
-
parent: captain,
|
|
888
|
-
persona: nodePersona(meeting, node, stateDir, limits, {
|
|
889
|
-
...skill,
|
|
890
|
-
delivery,
|
|
891
|
-
skillToolAvailable
|
|
892
|
-
}),
|
|
893
|
-
toolFilter: nodeToolRestriction(delivery),
|
|
894
|
-
...Object.keys(agentOptions).length > 0 ? { agentOptions } : {},
|
|
895
|
-
...config.maxDepth !== void 0 ? { maxDepth: config.maxDepth } : {}
|
|
910
|
+
...request,
|
|
911
|
+
persona,
|
|
912
|
+
toolFilter: nodeToolRestriction(delivery)
|
|
896
913
|
},
|
|
897
914
|
signal
|
|
898
|
-
});
|
|
899
|
-
|
|
915
|
+
})).childId;
|
|
916
|
+
else throw new Error("roundtable: the host exposes neither startActivation (0.2.1+) nor startContinuable (older) — cannot spawn a node");
|
|
917
|
+
node.id = String(childId);
|
|
900
918
|
}
|
|
901
919
|
/**
|
|
902
920
|
* Deliver one message to a node as its next FIFO turn. Best effort: a failure
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 内联 SVG 图标(零依赖、零资源、随主题变色)。
|
|
3
|
+
*
|
|
4
|
+
* 与针锋 `icons.tsx` 同一套几何规格(16×16、1.4px 描边、currentColor),但按圆桌
|
|
5
|
+
* 自己的设置页需要收窄到六个图标 —— 两个插件各自独立打包,不跨包共享源码。
|
|
6
|
+
*
|
|
7
|
+
* @module dsh-plugin-roundtable/client/icons
|
|
8
|
+
*/
|
|
9
|
+
/** 圆桌设置页用到的图标名。新增图标必须同时加进 {@link SHAPES}。 */
|
|
10
|
+
export type IconName = 'panel' | 'skill' | 'role' | 'squad' | 'gauge' | 'message';
|
|
11
|
+
/** 渲染一个 16×16 线性图标,颜色跟随 `currentColor`。 */
|
|
12
|
+
export declare function InlineIcon({ name, size }: {
|
|
13
|
+
name: IconName;
|
|
14
|
+
size?: number;
|
|
15
|
+
}): JSX.Element;
|
package/lib/types/version.d.ts
CHANGED
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
* @module dsh-plugin-roundtable/version
|
|
10
10
|
*/
|
|
11
11
|
/** 当前插件版本(必须与 package.json 的 version 逐字一致)。 */
|
|
12
|
-
export declare const PLUGIN_VERSION = "1.0.0-rc.
|
|
12
|
+
export declare const PLUGIN_VERSION = "1.0.0-rc.6";
|
|
13
13
|
/** 导出物头部使用的插件标识行。 */
|
|
14
|
-
export declare const PLUGIN_ID = "@y9931666/dsh-plugin-roundtable v1.0.0-rc.
|
|
14
|
+
export declare const PLUGIN_ID = "@y9931666/dsh-plugin-roundtable v1.0.0-rc.6";
|
|
15
15
|
/** DeepSeek Harness 版本区间(导出头部展示用)。
|
|
16
16
|
*
|
|
17
17
|
* 必须与 `compatibility.json` 的 `recommendedHost` 一致 —— 由
|
|
18
18
|
* `test/compatibility.test.mjs` 强制,`scripts/compatibility.mjs` 参与发布门禁。
|
|
19
19
|
* 此前这里是硬编码字符串,与 devDependencies 一起漂到了 rc.2 而无人发现;
|
|
20
20
|
* 0.2.0-rc.2 这次跨大版本升级同样由这两道闸门兜住。 */
|
|
21
|
-
export declare const HARNESS_RANGE = "DeepSeek Harness 0.2.
|
|
21
|
+
export declare const HARNESS_RANGE = "DeepSeek Harness 0.2.1-rc.5+";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@y9931666/dsh-plugin-roundtable",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.6",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public",
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
70
|
"roundtable": {
|
|
71
|
-
"hostBaseline": "0.2.
|
|
71
|
+
"hostBaseline": "0.2.1-rc.5"
|
|
72
72
|
},
|
|
73
73
|
"scripts": {
|
|
74
74
|
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
|
|
@@ -84,25 +84,25 @@
|
|
|
84
84
|
"publish:guard": "node scripts/compatibility.mjs && node scripts/verify-package.mjs --strict && node scripts/release.mjs"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
88
|
-
"@deepseek-ai/schemastery": "^3.18.
|
|
89
|
-
"@deepseek-ai/dsh-agent": "^0.2.
|
|
90
|
-
"@deepseek-ai/dsh-atomic-write": "^0.2.
|
|
91
|
-
"@deepseek-ai/dsh-client-connection": "^0.2.
|
|
92
|
-
"@deepseek-ai/dsh-client-locale": "^0.2.
|
|
93
|
-
"@deepseek-ai/dsh-client-ui-conversation": "^0.2.
|
|
94
|
-
"@deepseek-ai/dsh-client-ui-renderer": "^0.2.
|
|
95
|
-
"@deepseek-ai/dsh-client-ui-settings": "^0.2.
|
|
96
|
-
"@deepseek-ai/dsh-client-ui-tool": "^0.2.
|
|
97
|
-
"@deepseek-ai/dsh-host-webserver": "^0.2.
|
|
98
|
-
"@deepseek-ai/dsh-llm": "^0.2.
|
|
99
|
-
"@deepseek-ai/dsh-session": "^0.2.
|
|
100
|
-
"@deepseek-ai/dsh-skill": "^0.2.
|
|
101
|
-
"@deepseek-ai/dsh-subagent": "^0.2.
|
|
102
|
-
"@deepseek-ai/dsh-system-prompt": "^0.2.
|
|
103
|
-
"@deepseek-ai/dsh-tools": "^0.2.
|
|
104
|
-
"@deepseek-ai/dsh-user-questions": "^0.2.
|
|
105
|
-
"@deepseek-ai/dsh-workspace": "^0.2.
|
|
87
|
+
"@deepseek-ai/cordis": "^4.0.5",
|
|
88
|
+
"@deepseek-ai/schemastery": "^3.18.5",
|
|
89
|
+
"@deepseek-ai/dsh-agent": "^0.2.1-rc.5",
|
|
90
|
+
"@deepseek-ai/dsh-atomic-write": "^0.2.1-rc.5",
|
|
91
|
+
"@deepseek-ai/dsh-client-connection": "^0.2.1-rc.5",
|
|
92
|
+
"@deepseek-ai/dsh-client-locale": "^0.2.1-rc.5",
|
|
93
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.2.1-rc.5",
|
|
94
|
+
"@deepseek-ai/dsh-client-ui-renderer": "^0.2.1-rc.5",
|
|
95
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.2.1-rc.5",
|
|
96
|
+
"@deepseek-ai/dsh-client-ui-tool": "^0.2.1-rc.5",
|
|
97
|
+
"@deepseek-ai/dsh-host-webserver": "^0.2.1-rc.5",
|
|
98
|
+
"@deepseek-ai/dsh-llm": "^0.2.1-rc.5",
|
|
99
|
+
"@deepseek-ai/dsh-session": "^0.2.1-rc.5",
|
|
100
|
+
"@deepseek-ai/dsh-skill": "^0.2.1-rc.5",
|
|
101
|
+
"@deepseek-ai/dsh-subagent": "^0.2.1-rc.5",
|
|
102
|
+
"@deepseek-ai/dsh-system-prompt": "^0.2.1-rc.5",
|
|
103
|
+
"@deepseek-ai/dsh-tools": "^0.2.1-rc.5",
|
|
104
|
+
"@deepseek-ai/dsh-user-questions": "^0.2.1-rc.5",
|
|
105
|
+
"@deepseek-ai/dsh-workspace": "^0.2.1-rc.5",
|
|
106
106
|
"react": "^18.2.0"
|
|
107
107
|
},
|
|
108
108
|
"peerDependenciesMeta": {
|
|
@@ -128,25 +128,25 @@
|
|
|
128
128
|
"react": { "optional": true }
|
|
129
129
|
},
|
|
130
130
|
"devDependencies": {
|
|
131
|
-
"@deepseek-ai/cordis": "4.0.
|
|
132
|
-
"@deepseek-ai/schemastery": "3.18.
|
|
133
|
-
"@deepseek-ai/dsh-agent": "0.2.
|
|
134
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.
|
|
135
|
-
"@deepseek-ai/dsh-client-connection": "0.2.
|
|
136
|
-
"@deepseek-ai/dsh-client-locale": "0.2.
|
|
137
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.2.
|
|
138
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.2.
|
|
139
|
-
"@deepseek-ai/dsh-client-ui-settings": "0.2.
|
|
140
|
-
"@deepseek-ai/dsh-client-ui-tool": "0.2.
|
|
141
|
-
"@deepseek-ai/dsh-host-webserver": "0.2.
|
|
142
|
-
"@deepseek-ai/dsh-llm": "0.2.
|
|
143
|
-
"@deepseek-ai/dsh-session": "0.2.
|
|
144
|
-
"@deepseek-ai/dsh-skill": "0.2.
|
|
145
|
-
"@deepseek-ai/dsh-subagent": "0.2.
|
|
146
|
-
"@deepseek-ai/dsh-system-prompt": "0.2.
|
|
147
|
-
"@deepseek-ai/dsh-tools": "0.2.
|
|
148
|
-
"@deepseek-ai/dsh-user-questions": "0.2.
|
|
149
|
-
"@deepseek-ai/dsh-workspace": "0.2.
|
|
131
|
+
"@deepseek-ai/cordis": "4.0.5",
|
|
132
|
+
"@deepseek-ai/schemastery": "3.18.5",
|
|
133
|
+
"@deepseek-ai/dsh-agent": "0.2.1-rc.5",
|
|
134
|
+
"@deepseek-ai/dsh-atomic-write": "0.2.1-rc.5",
|
|
135
|
+
"@deepseek-ai/dsh-client-connection": "0.2.1-rc.5",
|
|
136
|
+
"@deepseek-ai/dsh-client-locale": "0.2.1-rc.5",
|
|
137
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.2.1-rc.5",
|
|
138
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.1-rc.5",
|
|
139
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.2.1-rc.5",
|
|
140
|
+
"@deepseek-ai/dsh-client-ui-tool": "0.2.1-rc.5",
|
|
141
|
+
"@deepseek-ai/dsh-host-webserver": "0.2.1-rc.5",
|
|
142
|
+
"@deepseek-ai/dsh-llm": "0.2.1-rc.5",
|
|
143
|
+
"@deepseek-ai/dsh-session": "0.2.1-rc.5",
|
|
144
|
+
"@deepseek-ai/dsh-skill": "0.2.1-rc.5",
|
|
145
|
+
"@deepseek-ai/dsh-subagent": "0.2.1-rc.5",
|
|
146
|
+
"@deepseek-ai/dsh-system-prompt": "0.2.1-rc.5",
|
|
147
|
+
"@deepseek-ai/dsh-tools": "0.2.1-rc.5",
|
|
148
|
+
"@deepseek-ai/dsh-user-questions": "0.2.1-rc.5",
|
|
149
|
+
"@deepseek-ai/dsh-workspace": "0.2.1-rc.5",
|
|
150
150
|
"@types/node": "^22.0.0",
|
|
151
151
|
"@types/react": "~18.3.1",
|
|
152
152
|
"@types/react-dom": "^18.3.7",
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# v1.0.0-rc.4 — 界面视觉优化(轻量)
|
|
2
|
+
|
|
3
|
+
本版只改界面,不改会议协议、工具语义与数据格式。视觉重量刻意低于针锋的卡片化:
|
|
4
|
+
圆桌的主界面是拓扑画布 + 多面板,设置页再加一层带边框的卡片会与针锋产生割裂感。
|
|
5
|
+
|
|
6
|
+
## 设置页
|
|
7
|
+
|
|
8
|
+
- **轻分组**:保留「细线 + 组标题」结构,不套卡片;组标题成为细线的下边界,标题到内容收紧 4px。
|
|
9
|
+
- **控件统一**:输入 / 下拉 32px 高、8px 圆角、320 宽、次级背景;主按钮 32px、次按钮 28px。
|
|
10
|
+
- **面板开关**:从 flex 换行改为等宽网格,七项不再出现"最后一行只剩一个"。
|
|
11
|
+
- **列表项**:预设 / 反馈条目去边框,只留浅底(边框曾是视觉重量最大的来源)。
|
|
12
|
+
- **图标**:分组标题前加 16×16 内联 SVG 图标(`src/client/icons.tsx`),零依赖、随主题变色。
|
|
13
|
+
|
|
14
|
+
## 拓扑视图
|
|
15
|
+
|
|
16
|
+
- **节点放大**:专家节点 68 → 84px(`NODE_RADIUS` 34 → 42,连线端点与环形最小半径同步);头像 30 → 36px。此前节点在 1900px 宽的画布里显得过小。
|
|
17
|
+
- **头像去灰边**:头像不再套一圈 `inset` 灰色圆环 —— 它与节点自身的边框叠成"框里还有框"。
|
|
18
|
+
- **主持块对比度**:DeepSeek 主持的黑块上,文字从 `label-secondary`(浅底次要文字色,黑底上读不出来)改为固定白色;块尺寸 96×88 → 108×96。
|
|
19
|
+
- **节点名**:显示时去掉专家共有的 `expert-` 前缀并允许两行(`expert-lifecycle` → `lifecycle`);完整 key 仍由悬停 `title` 提供。
|
|
20
|
+
- **连线**:专家间连线从最低对比的边框色改为次级文字色,线宽 1.6、圆端点,浅色底上不再"几乎看不见"。
|
|
21
|
+
- **右栏面板**:标题升为正文色 + 字距(此前与说明文字同级),内容内边距 8→10,面板间距 10→12。
|
|
22
|
+
- **预算进度条**:90×5px → 100×6px。
|
|
23
|
+
|
|
24
|
+
## 构建说明
|
|
25
|
+
|
|
26
|
+
`tsdown` 的 clean 会清空 `lib/types`;声明文件需在正常环境用 `npm run build`(含 `tsc --emitDeclarationOnly`)生成。
|