@shgroup/dsh-serenity-hooks 1.39.0 → 1.39.1
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/dsh.plugin.json +1 -1
- package/lib/client.js +46 -1
- package/package.json +1 -1
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.39.
|
|
3
|
+
"version": "1.39.1",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——11 个工具(container_fs/container_trajectory/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/im-bridge/acc-diag;后两个按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 轨迹日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.5-rc.2(deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
package/lib/client.js
CHANGED
|
@@ -8,7 +8,7 @@ window.__ModuleLoader__.load({
|
|
|
8
8
|
let react = require("react");
|
|
9
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
10
|
//#region \0sp-css:/home/yh/home/home-serenity/AI_LAB/dsh-serenity-plugin/hooks/dsh-serenity-hooks/src/client/SafeModePanel
|
|
11
|
-
const css$3 = "/* SafeModePanel — 会话头部 Serenity 状态胶囊(v1.24.10 胶囊改版,对齐 OcgoDockEntry pill)\n * 胶囊 999px 全圆 → 点击 → 自绘 popover(340px 右上角卡片,外点/Escape 关闭)\n * popover 内:分组(groupTitle 标题 + rowCard 行卡)——看齐官方 settings 设计语言\n * 遵循 web-styling.md:颜色只用 --dsw-alias-* 语义 token(明暗自适应)+ --sp-safe-green 统一绿家族;\n * 前缀 sp- 防冲突。 */\n\n/* ── 统一绿色变量家族(一处改全改;emerald 500~600 区间保证深色对比度) ── */\n\n.sp-root {\n --sp-safe-green: #0ba875; /* emerald-550:SAFE ON 主色 */\n --sp-safe-green-deep: #059669; /* emerald-600:渐变深端 */\n}\n\n/* ── 头部状态胶囊(可点击) ── */\n\n.sp-card {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 9px; /* 无固定 height:由内容撑高(胶囊) */\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n color: inherit;\n font-size: 12px;\n line-height: 1;\n cursor: pointer;\n transition: background var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease),\n border-color var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease);\n}\n\n.sp-card:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n border-color: var(--dsw-alias-border-l2);\n}\n\n.sp-card:focus-visible {\n outline: 2px solid var(--dsw-alias-button-ghost-active-border);\n outline-offset: 1px;\n}\n\n.sp-card:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n/* 绿点 = Serenity 在线(恒亮绿,不随 SAFE 变);离线/未激活 → 灰 */\n.sp-dot {\n flex: none;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--dsw-alias-state-success-primary);\n}\n\n.sp-dotOff {\n background: var(--dsw-alias-label-dimmed);\n}\n\n.sp-cardInactive {\n opacity: 0.85;\n}\n\n.sp-cardInactive .sp-brand {\n color: var(--dsw-alias-label-secondary);\n font-weight: 500;\n}\n\n.sp-brand {\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n\n/* 版本号:monospace + translateY(1px) 下沉对齐(与文字基线齐平) */\n.sp-ver {\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n font-family: var(--ds-font-family-code, monospace);\n transform: translateY(1px);\n}\n\n/* 1px 深灰分隔线(两侧紧凑) */\n.sp-sep {\n flex: none;\n width: 1px;\n height: 12px;\n margin: 0 2px;\n background: var(--dsw-alias-label-tertiary);\n}\n\n.sp-shield {\n display: inline-flex;\n width: 14px;\n height: 14px;\n flex: none;\n}\n\n.sp-shield svg {\n width: 14px;\n height: 14px;\n}\n\n.sp-statusWord {\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0;\n white-space: nowrap;\n}\n\n/* SAFE OFF(未保护):灰——低姿态提醒,非错误(用户自己的开关选择) */\n.sp-cardUnprotected .sp-shield {\n color: var(--dsw-alias-label-secondary);\n}\n\n.sp-cardUnprotected .sp-statusWord {\n color: var(--dsw-alias-label-secondary);\n}\n\n/* SAFE ON(保护中):emerald 绿——安心(盾牌实色 + SAFE 文字渐变质感) */\n.sp-cardProtected .sp-shield {\n color: var(--sp-safe-green);\n}\n\n.sp-cardProtected .sp-statusWord {\n color: var(--sp-safe-green);\n background: linear-gradient(135deg, var(--sp-safe-green) 0%, var(--sp-safe-green-deep) 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n}\n\n/* ── Mac 风格滑块(v1.24.10:轨道 24×13 / thumb 11px 灰白 #f2f4f6 无图标 / cubic-bezier 平滑) ── */\n\n.sp-switch {\n display: inline-block;\n width: 24px;\n height: 13px;\n border-radius: 999px;\n position: relative;\n flex: none;\n cursor: pointer;\n transition: background 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.sp-switchOff {\n background: var(--dsw-alias-border-l2);\n}\n\n.sp-switchOn {\n background: var(--sp-safe-green);\n}\n\n.sp-switchThumb {\n position: absolute;\n top: 1px;\n width: 11px;\n height: 11px;\n border-radius: 50%;\n background: #f2f4f6; /* Mac 灰白 thumb(明暗通用) */\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);\n transition: left 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.sp-switchOff .sp-switchThumb {\n left: 1px;\n}\n\n.sp-switchOn .sp-switchThumb {\n left: 12px; /* 24 - 11 - 1 */\n}\n\n/* CSS 特异性坑(S013 指南):.sp-switch:hover (0,2,0) 会覆盖 .sp-switchOn (0,1,0)\n * → ON 态 hover 绿底消失。必须同特异性且后定义补回。 */\n.sp-switch:hover {\n filter: brightness(1.08);\n}\n\n.sp-switchOn:hover {\n background: var(--sp-safe-green);\n}\n\n.sp-switchBusy {\n opacity: 0.6;\n cursor: default;\n pointer-events: none;\n}\n\n.sp-chev {\n color: var(--dsw-alias-label-dimmed);\n flex: none;\n}\n\n/* ── 自绘 popover(340px 右上角小卡片,替代官方 Modal) ── */\n\n.sp-root {\n position: relative;\n display: inline-flex;\n}\n\n/* ── 自绘 popover(卡片,替代官方 Modal)\n v1.36.1(所有者:「卡片做成双倍宽,左侧是信息,右侧是动画」):340 → **680px**(双倍)。\n 胶囊在头部右端,卡片 `right:0` 对齐 ⇒ 加宽只会**向左**长;再叠 `min(…, 100vw-24px)` 兜住窄视口。 */\n.sp-pop {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n width: min(680px, calc(100vw - 24px));\n z-index: 2000;\n box-sizing: border-box;\n padding: 14px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 14px;\n background: var(--dsw-alias-bg-overlay);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);\n}\n\n/* ── 航行动画栏:宁静号心智模型(ACC 层资产 /serenity/voyage,S142 §12.44 → v1.36.1 改右栏)\n v1.36.1 改版(所有者:「卡片做成双倍宽,左侧是信息,右侧是动画」):\n 动画从**背景层**改为**右栏**。这一改动解开了 v1.36.0 的取舍死结——\n 旧布局里动画垫在正文底下,必须靠 0.75 的卡片底色把它压住才读得清字;\n 分段之后两者不再争同一片像素 ⇒ 动画可以亮、正文可以干净,不必再互相妥协。\n ⚠️ 动画本身仍是「卡片模式」(词元压到 22%、铭牌层关闭),本栏只负责**给位置**,不改作品。 */\n.sp-popVoyage {\n overflow: hidden; /* 裁掉 iframe 在 14px 圆角外的溢出 */\n /* 分段后不再需要 0.75 的重压暗:压到 0.9 只压整体观感,不与正文争对比度。\n 若所有者觉得动画太亮/太暗,这仍是主旋钮(次旋钮 = iframe 的 blur)。 */\n background: rgba(6, 11, 14, 0.9);\n display: flex;\n flex-direction: row;\n /* 两栏都从**同一行高**分配(row 轴 cross = 高度):左栏按内容、右栏吃满行高。\n 行高 = 左栏内容高度,且被 max-height 封顶 ⇒ 信息长时内部滚动,动画不把行撑破。 */\n align-items: stretch;\n gap: 12px;\n padding: 12px;\n max-height: calc(100vh - 120px);\n}\n/* 左栏:信息(正文)——固定 340px,与旧卡片同宽,保证原有排印不变 */\n.sp-popVoyage > .sp-popBody {\n position: relative;\n z-index: 1;\n order: 1;\n flex: none;\n width: 340px;\n min-width: 0;\n}\n/* 右栏:动画——吃掉剩余宽度,并吃满左栏高度 */\n.sp-voyage {\n order: 2;\n flex: 1 1 auto;\n min-width: 0;\n position: relative;\n pointer-events: none; /* 纯展示:不挡点击、不抢焦点 */\n overflow: hidden;\n border-radius: 10px;\n min-height: 260px; /* 动画的下限:信息很少时也不塌成一条 */\n}\n.sp-voyage iframe {\n display: block;\n width: 100%;\n height: 100%;\n border: 0;\n /* ⚠️ 用 iframe 自身的 filter 而**不是** backdrop-filter:iframe 内容不参与本文档的\n backdrop(跨文档不采样)⇒ backdrop-filter 对它无效,只有 filter 才是可靠的杠杆。\n v1.36.1:动画移入独立右栏后不再压在文字后面 ⇒ 磨砂可以收得很轻(1.2 → 0.6px),\n 既保留柔化,又让飞船细节(舷窗/引擎环)比旧版清楚。 */\n filter: blur(0.6px);\n}\n\n/* 窄屏(放不下两栏)⇒ 退回单栏:信息在上、动画在下(DOM 顺序即如此,无需改结构) */\n@media (max-width: 860px) {\n .sp-pop {\n /* 两栏放不下时,卡片回到\"不超过视口\"的旧行为 */\n width: min(420px, calc(100vw - 24px));\n }\n .sp-popVoyage {\n flex-direction: column;\n align-items: stretch;\n }\n .sp-popVoyage > .sp-popBody {\n width: auto; /* 单栏下不再固定 340px,跟随卡片宽度 */\n flex: none; /* 按内容高(仍受自身 max-height 约束) */\n }\n .sp-voyage {\n flex: none;\n height: 200px; /* 单栏时给动画明确高度,避免被 flex 压扁 */\n min-height: 0;\n }\n}\n\n.sp-popBody {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-height: calc(100vh - 140px);\n overflow-y: auto;\n}\n\n/* ── 分组(官方 settings 语言:groupTitle + rows) ── */\n\n.sp-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.sp-groupHead {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.sp-groupTitle {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sp-rows {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n/* 行卡(rowCard:border + radius + padding;值与 label 分离、长内容可换行) */\n.sp-row {\n display: flex;\n align-items: baseline;\n gap: 12px;\n min-width: 0;\n padding: 8px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.sp-label {\n flex: none;\n width: 76px;\n font-size: 12px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n}\n\n.sp-value {\n flex: 1;\n min-width: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-primary);\n font-family: var(--ds-font-family-code, monospace);\n word-break: break-all;\n overflow-wrap: anywhere;\n}\n\n/* 安全模式动作区 */\n.sp-actions {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.sp-toggle {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 24px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n font-size: 12px;\n cursor: pointer;\n transition: background var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease);\n}\n\n.sp-toggleLg {\n height: 30px;\n padding: 0 16px;\n font-size: 13px;\n}\n\n.sp-toggleOn {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);\n color: var(--dsw-alias-state-error-primary);\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent);\n}\n\n.sp-toggleOff {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n\n.sp-toggleIcon {\n flex: none;\n}\n\n.sp-toggleDesc {\n flex: 1;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* handyman 运行状态区块 */\n\n.sp-handymenToggle {\n flex: none;\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n cursor: pointer;\n}\n\n.sp-handymenToggle:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.sp-handymenList {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin-top: 2px;\n}\n\n.sp-handymanItem {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n min-width: 0;\n}\n\n.sp-handymanHead {\n display: flex;\n align-items: baseline;\n gap: 8px;\n min-width: 0;\n}\n\n.sp-handymanLabel {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n.sp-handymanRound {\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-dimmed);\n}\n\n.sp-handymanTime {\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-dimmed);\n}\n\n.sp-handymanResp {\n font-size: 11px;\n line-height: 16px;\n color: var(--dsw-alias-label-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.sp-handymenMore {\n font-size: 11px;\n color: var(--dsw-alias-label-dimmed);\n padding: 4px 12px;\n}\n\n/* 底部提示(配置入口引导) */\n.sp-hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n padding: 8px 12px;\n border: 1px dashed var(--dsw-alias-border-l2);\n border-radius: 10px;\n}\n";
|
|
11
|
+
const css$3 = "/* SafeModePanel — 会话头部 Serenity 状态胶囊(v1.24.10 胶囊改版,对齐 OcgoDockEntry pill)\n * 胶囊 999px 全圆 → 点击 → 自绘 popover(340px 右上角卡片,外点/Escape 关闭)\n * popover 内:分组(groupTitle 标题 + rowCard 行卡)——看齐官方 settings 设计语言\n * 遵循 web-styling.md:颜色只用 --dsw-alias-* 语义 token(明暗自适应)+ --sp-safe-green 统一绿家族;\n * 前缀 sp- 防冲突。 */\n\n/* ── 统一绿色变量家族(一处改全改;emerald 500~600 区间保证深色对比度) ── */\n\n.sp-root {\n --sp-safe-green: #0ba875; /* emerald-550:SAFE ON 主色 */\n --sp-safe-green-deep: #059669; /* emerald-600:渐变深端 */\n}\n\n/* ── 头部状态胶囊(可点击) ── */\n\n.sp-card {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 9px; /* 无固定 height:由内容撑高(胶囊) */\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n color: inherit;\n font-size: 12px;\n line-height: 1;\n cursor: pointer;\n transition: background var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease),\n border-color var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease);\n}\n\n.sp-card:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n border-color: var(--dsw-alias-border-l2);\n}\n\n.sp-card:focus-visible {\n outline: 2px solid var(--dsw-alias-button-ghost-active-border);\n outline-offset: 1px;\n}\n\n.sp-card:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n/* 绿点 = Serenity 在线(恒亮绿,不随 SAFE 变);离线/未激活 → 灰 */\n.sp-dot {\n flex: none;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--dsw-alias-state-success-primary);\n}\n\n.sp-dotOff {\n background: var(--dsw-alias-label-dimmed);\n}\n\n.sp-cardInactive {\n opacity: 0.85;\n}\n\n.sp-cardInactive .sp-brand {\n color: var(--dsw-alias-label-secondary);\n font-weight: 500;\n}\n\n.sp-brand {\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n\n/* 版本号:monospace + translateY(1px) 下沉对齐(与文字基线齐平) */\n.sp-ver {\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n font-family: var(--ds-font-family-code, monospace);\n transform: translateY(1px);\n}\n\n/* 1px 深灰分隔线(两侧紧凑) */\n.sp-sep {\n flex: none;\n width: 1px;\n height: 12px;\n margin: 0 2px;\n background: var(--dsw-alias-label-tertiary);\n}\n\n.sp-shield {\n display: inline-flex;\n width: 14px;\n height: 14px;\n flex: none;\n}\n\n.sp-shield svg {\n width: 14px;\n height: 14px;\n}\n\n.sp-statusWord {\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0;\n white-space: nowrap;\n}\n\n/* SAFE OFF(未保护):灰——低姿态提醒,非错误(用户自己的开关选择) */\n.sp-cardUnprotected .sp-shield {\n color: var(--dsw-alias-label-secondary);\n}\n\n.sp-cardUnprotected .sp-statusWord {\n color: var(--dsw-alias-label-secondary);\n}\n\n/* SAFE ON(保护中):emerald 绿——安心(盾牌实色 + SAFE 文字渐变质感) */\n.sp-cardProtected .sp-shield {\n color: var(--sp-safe-green);\n}\n\n.sp-cardProtected .sp-statusWord {\n color: var(--sp-safe-green);\n background: linear-gradient(135deg, var(--sp-safe-green) 0%, var(--sp-safe-green-deep) 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n}\n\n/* ── Mac 风格滑块(v1.24.10:轨道 24×13 / thumb 11px 灰白 #f2f4f6 无图标 / cubic-bezier 平滑) ── */\n\n.sp-switch {\n display: inline-block;\n width: 24px;\n height: 13px;\n border-radius: 999px;\n position: relative;\n flex: none;\n cursor: pointer;\n transition: background 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.sp-switchOff {\n background: var(--dsw-alias-border-l2);\n}\n\n.sp-switchOn {\n background: var(--sp-safe-green);\n}\n\n.sp-switchThumb {\n position: absolute;\n top: 1px;\n width: 11px;\n height: 11px;\n border-radius: 50%;\n background: #f2f4f6; /* Mac 灰白 thumb(明暗通用) */\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);\n transition: left 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.sp-switchOff .sp-switchThumb {\n left: 1px;\n}\n\n.sp-switchOn .sp-switchThumb {\n left: 12px; /* 24 - 11 - 1 */\n}\n\n/* CSS 特异性坑(S013 指南):.sp-switch:hover (0,2,0) 会覆盖 .sp-switchOn (0,1,0)\n * → ON 态 hover 绿底消失。必须同特异性且后定义补回。 */\n.sp-switch:hover {\n filter: brightness(1.08);\n}\n\n.sp-switchOn:hover {\n background: var(--sp-safe-green);\n}\n\n.sp-switchBusy {\n opacity: 0.6;\n cursor: default;\n pointer-events: none;\n}\n\n.sp-chev {\n color: var(--dsw-alias-label-dimmed);\n flex: none;\n}\n\n/* ── 自绘 popover(340px 右上角小卡片,替代官方 Modal) ── */\n\n.sp-root {\n position: relative;\n display: inline-flex;\n}\n\n/* ── 自绘 popover(卡片,替代官方 Modal)\n v1.36.1(所有者:「卡片做成双倍宽,左侧是信息,右侧是动画」):340 → **680px**(双倍)。\n v1.39.1(所有者:「下拉 dialog / 弹窗内容过宽后,会被左侧元素遮挡」):\n 🔴 根因 = **祖先 `overflow:hidden` 裁切**,不是 z-index 也不是宽度不够。\n 真机取证(CDP hit-test,1280/1600/1920 三档一致):\n · 胶囊右端 x=954.2、卡片 680 宽 ⇒ 左边界 274.2\n · 而会话中列 `pI_x6G_centerCol` / `wSkVaW_root` 都 `overflow:hidden` 且左边界 = **280**\n ⇒ 左边缘 **5.8px** 被裁掉(左边框线与圆角消失)。\n 加宽前(340px)左边界 614.2 远在 280 右侧 ⇒ **这正是 v1.36.1 加宽引入的回归**。\n 修法:**改为 `position: fixed`** —— fixed 子元素**不受祖先 overflow 裁切**;\n 坐标由 SafeModePanel 用 `getBoundingClientRect()` 算出并夹取进视口(见 .tsx 的 useLayoutEffect)。\n (本仓 client 侧**无 `react-dom` 依赖** ⇒ `createPortal` 不可用;fixed 是等效且更轻的出路。\n 已在真机验证祖先链**无** transform/filter/contain/will-change ⇒ fixed 不会被降级为相对某祖先。)\n 宽度仍走 `min(680px, 100vw-24px)`(窄视口兜底),窄屏退回单栏见文末 @media。 */\n.sp-pop {\n position: fixed; /* 不受祖先 overflow:hidden 裁切;left/top 由 JS 计算 */\n top: 0; /* ← 声明默认值,JS 会覆写(未落位时组件给 -9999 屏外值,不会闪到右下角) */\n left: 0;\n width: min(680px, calc(100vw - 24px));\n z-index: 2000;\n box-sizing: border-box;\n padding: 14px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 14px;\n background: var(--dsw-alias-bg-overlay);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);\n}\n\n/* ── 航行动画栏:宁静号心智模型(ACC 层资产 /serenity/voyage,S142 §12.44 → v1.36.1 改右栏)\n v1.36.1 改版(所有者:「卡片做成双倍宽,左侧是信息,右侧是动画」):\n 动画从**背景层**改为**右栏**。这一改动解开了 v1.36.0 的取舍死结——\n 旧布局里动画垫在正文底下,必须靠 0.75 的卡片底色把它压住才读得清字;\n 分段之后两者不再争同一片像素 ⇒ 动画可以亮、正文可以干净,不必再互相妥协。\n ⚠️ 动画本身仍是「卡片模式」(词元压到 22%、铭牌层关闭),本栏只负责**给位置**,不改作品。 */\n.sp-popVoyage {\n overflow: hidden; /* 裁掉 iframe 在 14px 圆角外的溢出 */\n /* 分段后不再需要 0.75 的重压暗:压到 0.9 只压整体观感,不与正文争对比度。\n 若所有者觉得动画太亮/太暗,这仍是主旋钮(次旋钮 = iframe 的 blur)。 */\n background: rgba(6, 11, 14, 0.9);\n display: flex;\n flex-direction: row;\n /* 两栏都从**同一行高**分配(row 轴 cross = 高度):左栏按内容、右栏吃满行高。\n 行高 = 左栏内容高度,且被 max-height 封顶 ⇒ 信息长时内部滚动,动画不把行撑破。 */\n align-items: stretch;\n gap: 12px;\n padding: 12px;\n max-height: calc(100vh - 120px);\n}\n/* 左栏:信息(正文)——固定 340px,与旧卡片同宽,保证原有排印不变 */\n.sp-popVoyage > .sp-popBody {\n position: relative;\n z-index: 1;\n order: 1;\n flex: none;\n width: 340px;\n min-width: 0;\n}\n/* 右栏:动画——吃掉剩余宽度,并吃满左栏高度 */\n.sp-voyage {\n order: 2;\n flex: 1 1 auto;\n min-width: 0;\n position: relative;\n pointer-events: none; /* 纯展示:不挡点击、不抢焦点 */\n overflow: hidden;\n border-radius: 10px;\n min-height: 260px; /* 动画的下限:信息很少时也不塌成一条 */\n}\n.sp-voyage iframe {\n display: block;\n width: 100%;\n height: 100%;\n border: 0;\n /* ⚠️ 用 iframe 自身的 filter 而**不是** backdrop-filter:iframe 内容不参与本文档的\n backdrop(跨文档不采样)⇒ backdrop-filter 对它无效,只有 filter 才是可靠的杠杆。\n v1.36.1:动画移入独立右栏后不再压在文字后面 ⇒ 磨砂可以收得很轻(1.2 → 0.6px),\n 既保留柔化,又让飞船细节(舷窗/引擎环)比旧版清楚。 */\n filter: blur(0.6px);\n}\n\n/* 窄屏(放不下两栏)⇒ 退回单栏:信息在上、动画在下(DOM 顺序即如此,无需改结构) */\n@media (max-width: 860px) {\n .sp-pop {\n /* 两栏放不下时,卡片回到\"不超过视口\"的旧行为 */\n width: min(420px, calc(100vw - 24px));\n }\n .sp-popVoyage {\n flex-direction: column;\n align-items: stretch;\n }\n .sp-popVoyage > .sp-popBody {\n width: auto; /* 单栏下不再固定 340px,跟随卡片宽度 */\n flex: none; /* 按内容高(仍受自身 max-height 约束) */\n }\n .sp-voyage {\n flex: none;\n height: 200px; /* 单栏时给动画明确高度,避免被 flex 压扁 */\n min-height: 0;\n }\n}\n\n.sp-popBody {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-height: calc(100vh - 140px);\n overflow-y: auto;\n}\n\n/* ── 分组(官方 settings 语言:groupTitle + rows) ── */\n\n.sp-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.sp-groupHead {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.sp-groupTitle {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sp-rows {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n/* 行卡(rowCard:border + radius + padding;值与 label 分离、长内容可换行) */\n.sp-row {\n display: flex;\n align-items: baseline;\n gap: 12px;\n min-width: 0;\n padding: 8px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.sp-label {\n flex: none;\n width: 76px;\n font-size: 12px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n}\n\n.sp-value {\n flex: 1;\n min-width: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-primary);\n font-family: var(--ds-font-family-code, monospace);\n word-break: break-all;\n overflow-wrap: anywhere;\n}\n\n/* 安全模式动作区 */\n.sp-actions {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.sp-toggle {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 24px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n font-size: 12px;\n cursor: pointer;\n transition: background var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease);\n}\n\n.sp-toggleLg {\n height: 30px;\n padding: 0 16px;\n font-size: 13px;\n}\n\n.sp-toggleOn {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);\n color: var(--dsw-alias-state-error-primary);\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent);\n}\n\n.sp-toggleOff {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n\n.sp-toggleIcon {\n flex: none;\n}\n\n.sp-toggleDesc {\n flex: 1;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* handyman 运行状态区块 */\n\n.sp-handymenToggle {\n flex: none;\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n cursor: pointer;\n}\n\n.sp-handymenToggle:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.sp-handymenList {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin-top: 2px;\n}\n\n.sp-handymanItem {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n min-width: 0;\n}\n\n.sp-handymanHead {\n display: flex;\n align-items: baseline;\n gap: 8px;\n min-width: 0;\n}\n\n.sp-handymanLabel {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n.sp-handymanRound {\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-dimmed);\n}\n\n.sp-handymanTime {\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-dimmed);\n}\n\n.sp-handymanResp {\n font-size: 11px;\n line-height: 16px;\n color: var(--dsw-alias-label-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.sp-handymenMore {\n font-size: 11px;\n color: var(--dsw-alias-label-dimmed);\n padding: 4px 12px;\n}\n\n/* 底部提示(配置入口引导) */\n.sp-hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n padding: 8px 12px;\n border: 1px dashed var(--dsw-alias-border-l2);\n border-radius: 10px;\n}\n";
|
|
12
12
|
if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"SafeModePanel\"]") === null) {
|
|
13
13
|
const tag = document.createElement("style");
|
|
14
14
|
tag.setAttribute("data-sp-css", "SafeModePanel");
|
|
@@ -17,6 +17,12 @@ window.__ModuleLoader__.load({
|
|
|
17
17
|
}
|
|
18
18
|
//#endregion
|
|
19
19
|
//#region src/client/SafeModePanel.tsx
|
|
20
|
+
/** popover 与锚点胶囊之间的间距(= 旧 CSS `top: calc(100% + 8px)` 的 8) */
|
|
21
|
+
const POP_GAP_PX = 8;
|
|
22
|
+
/** popover 与视口边缘的最小留白(夹取用,防卡片贴边或被视口切掉) */
|
|
23
|
+
const POP_VIEW_PAD_PX = 8;
|
|
24
|
+
/** 尚未落位时的屏外坐标(`useLayoutEffect` 在绘制前就会覆写,肉眼看不到) */
|
|
25
|
+
const POP_OFFSCREEN = -9999;
|
|
20
26
|
const API = "/serenity/status";
|
|
21
27
|
const HANDYMEN_API = "/serenity/handymen";
|
|
22
28
|
/** 盾牌 SVG(v1.24.5 校准:fill=none 纯描边;ON=绿 emerald / OFF=灰 label-secondary 由状态类控制) */
|
|
@@ -51,6 +57,8 @@ window.__ModuleLoader__.load({
|
|
|
51
57
|
const [handymen, setHandymen] = (0, react.useState)([]);
|
|
52
58
|
const [handymenOpen, setHandymenOpen] = (0, react.useState)(false);
|
|
53
59
|
const rootRef = (0, react.useRef)(null);
|
|
60
|
+
const popRef = (0, react.useRef)(null);
|
|
61
|
+
const [popPos, setPopPos] = (0, react.useState)(null);
|
|
54
62
|
const sessionId = props.sessionId;
|
|
55
63
|
const refresh = (0, react.useCallback)(async () => {
|
|
56
64
|
const qs = sessionId ? `?sessionId=${encodeURIComponent(sessionId)}` : "";
|
|
@@ -98,6 +106,35 @@ window.__ModuleLoader__.load({
|
|
|
98
106
|
document.removeEventListener("keydown", onKey);
|
|
99
107
|
};
|
|
100
108
|
}, [open]);
|
|
109
|
+
(0, react.useLayoutEffect)(() => {
|
|
110
|
+
if (!open) {
|
|
111
|
+
setPopPos(null);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const place = () => {
|
|
115
|
+
const anchor = rootRef.current;
|
|
116
|
+
const pop = popRef.current;
|
|
117
|
+
if (!anchor || !pop) return;
|
|
118
|
+
const a = anchor.getBoundingClientRect();
|
|
119
|
+
const vw = window.innerWidth;
|
|
120
|
+
const vh = window.innerHeight;
|
|
121
|
+
const w = pop.offsetWidth;
|
|
122
|
+
const h = pop.offsetHeight;
|
|
123
|
+
const left = Math.max(POP_VIEW_PAD_PX, Math.min(a.right - w, vw - w - POP_VIEW_PAD_PX));
|
|
124
|
+
const top = Math.max(POP_VIEW_PAD_PX, Math.min(a.bottom + POP_GAP_PX, vh - h - POP_VIEW_PAD_PX));
|
|
125
|
+
setPopPos({
|
|
126
|
+
left,
|
|
127
|
+
top
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
place();
|
|
131
|
+
window.addEventListener("resize", place);
|
|
132
|
+
window.addEventListener("scroll", place, true);
|
|
133
|
+
return () => {
|
|
134
|
+
window.removeEventListener("resize", place);
|
|
135
|
+
window.removeEventListener("scroll", place, true);
|
|
136
|
+
};
|
|
137
|
+
}, [open]);
|
|
101
138
|
const toggle = async (on) => {
|
|
102
139
|
setBusy(true);
|
|
103
140
|
try {
|
|
@@ -177,9 +214,17 @@ window.__ModuleLoader__.load({
|
|
|
177
214
|
})
|
|
178
215
|
]
|
|
179
216
|
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
217
|
+
ref: popRef,
|
|
180
218
|
className: cx("sp-pop", "sp-popVoyage"),
|
|
181
219
|
role: "dialog",
|
|
182
220
|
"aria-label": "CCC 状态栏",
|
|
221
|
+
style: popPos ? {
|
|
222
|
+
left: popPos.left,
|
|
223
|
+
top: popPos.top
|
|
224
|
+
} : {
|
|
225
|
+
left: POP_OFFSCREEN,
|
|
226
|
+
top: POP_OFFSCREEN
|
|
227
|
+
},
|
|
183
228
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
184
229
|
className: cx("sp-popBody"),
|
|
185
230
|
children: inCcc ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.39.
|
|
3
|
+
"version": "1.39.1",
|
|
4
4
|
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:11 个工具(container_fs/container_trajectory/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/im-bridge/acc-diag)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 工作日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.5-rc.2。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|