diff --git a/panel.js b/panel.js index 4afff13..5452848 100644 --- a/panel.js +++ b/panel.js @@ -3877,40 +3877,123 @@ function _formatRegexReuseSourceState(source = {}) { return states.join(" · "); } -function _renderRegexReuseRuleList(rules = [], emptyText = "无") { +function _formatRegexReuseSourceLabel(sourceType = "") { + if (sourceType === "global") return "全局"; + if (sourceType === "preset") return "预设"; + if (sourceType === "character") return "角色卡"; + if (sourceType === "local") return "任务本地"; + return sourceType ? String(sourceType) : "未知"; +} + +function _formatRegexReuseReplaceText(rule = {}) { + if (rule.promptStageMode === "clear") { + return "(美化/展示正则,ST-BME 请求阶段清空)"; + } + if (typeof rule.effectivePromptReplaceString === "string" && rule.effectivePromptReplaceString.length > 0) { + return rule.effectivePromptReplaceString; + } + if (typeof rule.replaceString === "string" && rule.replaceString.length > 0) { + return rule.replaceString; + } + return "(空 - 删除匹配内容)"; +} + +function _renderRegexReuseBadges(rule = {}) { + const badges = []; + if (rule.promptStageMode === "clear") { + badges.push({ + className: "is-clear", + text: "美化 -> 清空", + }); + } else if (rule.promptStageMode === "replace") { + badges.push({ + className: "is-transform", + text: "转义", + }); + } else { + badges.push({ + className: "is-skip", + text: "当前阶段跳过", + }); + } + if (rule.markdownOnly) { + badges.push({ + className: "is-skip", + text: "跳过(MD)", + }); + } + if (rule.promptOnly) { + badges.push({ + className: "is-prompt", + text: "仅 Prompt", + }); + } + return badges + .map( + (badge) => `${_escHtml(badge.text)}`, + ) + .join(""); +} + +function _renderRegexReuseRuleList(rules = [], emptyText = "无", options = {}) { if (!Array.isArray(rules) || rules.length === 0) { return `
${_escHtml(emptyText)}
`; } + const { + showSource = false, + showReason = false, + startIndex = 0, + muted = false, + } = options || {}; + return rules - .map((rule) => { + .map((rule, index) => { const placementText = Array.isArray(rule.placementLabels) && rule.placementLabels.length - ? rule.placementLabels.join(" / ") - : "未声明 placement"; - const flags = [ - rule.promptOnly ? "promptOnly" : "", - rule.markdownOnly ? "markdownOnly" : "", - rule.promptStageMode === "clear" - ? "请求阶段: 美化/展示 -> 清空" - : rule.promptStageMode === "replace" - ? "请求阶段: 正常替换" - : "请求阶段: 不参与", - rule.reason ? `原因: ${rule.reason}` : "", - ].filter(Boolean); - const replaceText = rule.promptReplaceAsEmpty - ? `${rule.replaceString ? `${_escHtml(rule.replaceString)} -> ` : ""}(prompt 时为空)` - : rule.replaceString - ? `${_escHtml(rule.replaceString)}` - : ""; + ? rule.placementLabels.join(",") + : "未声明作用域"; + const sourceLabel = _formatRegexReuseSourceLabel(rule.sourceType || ""); + const metaBits = []; + if (showSource) { + metaBits.push(`来源:${sourceLabel}`); + } + if (showReason && rule.reason) { + metaBits.push(rule.reason); + } return ` -
- ${_escHtml(rule.name || rule.id || "未命名规则")} - ${_escHtml(placementText)} -
-
- ${_escHtml(rule.findRegex || "(空 findRegex)")} - ${replaceText ? ` -> ${replaceText}` : ""} - ${flags.length ? `
${_escHtml(flags.join(" · "))}` : ""} +
+
+
+ #${startIndex + index + 1} + ${_escHtml(rule.name || rule.id || "未命名规则")} +
+
+ ${_renderRegexReuseBadges(rule)} +
+
+
+
+ 查找 + ${_escHtml(rule.findRegex || "(空 findRegex)")} +
+
+ 替换 + ${_escHtml(_formatRegexReuseReplaceText(rule))} +
+
+ 作用域 + ${_escHtml(placementText)} +
+ ${showSource ? ` +
+ 来源 + ${_escHtml(sourceLabel)} +
+ ` : ""} +
+ ${metaBits.length ? ` +
${_escHtml(metaBits.join(" · "))}
+ ` : ""}
`; }) @@ -3927,83 +4010,101 @@ function _buildRegexReusePopupContent(snapshot = {}) { const sourceConfig = snapshot.sourceConfig && typeof snapshot.sourceConfig === "object" ? snapshot.sourceConfig : {}; + const sourceSummaryText = [ + `global=${sourceConfig.global === false ? "关" : "开"}`, + `preset=${sourceConfig.preset === false ? "关" : "开"}`, + `character=${sourceConfig.character === false ? "关" : "开"}`, + ].join(" / "); + const stageSummaryText = + Object.entries(stageConfig) + .map(([key, value]) => `${key}=${value ? "on" : "off"}`) + .join(" | ") || "无"; container.innerHTML = ` -
-
-
酒馆正则复用快照
-
- 这里展示的是当前任务预设下,ST-BME 实际会尝试复用的 Tavern 正则来源和规则,不是静态说明文案。 +
+
+
当前正则脚本一览
+
+ 这里展示的是当前任务预设下,ST-BME 实际会复用到请求链里的 Tavern 正则。展示/美化类规则在请求阶段会按空字符串替换。
-
-
- 任务 - ${_escHtml(snapshot.taskType || "—")} +
+
+ 任务 + ${_escHtml(snapshot.taskType || "—")}
-
- 预设 - ${_escHtml(snapshot.profileName || snapshot.profileId || "—")} +
+ 预设 + ${_escHtml(snapshot.profileName || snapshot.profileId || "—")}
-
- 任务正则 - ${snapshot.regexEnabled ? "已启用" : "已关闭"} +
+ 任务正则 + ${snapshot.regexEnabled ? "已启用" : "已关闭"}
-
- 复用酒馆正则 - ${snapshot.inheritStRegex ? "已启用" : "已关闭"} +
+ 复用 Tavern + ${snapshot.inheritStRegex ? "已启用" : "已关闭"}
-
- 本地规则数 - ${Number(snapshot.localRuleCount || 0)} +
+ 已收集规则 + ${Number(snapshot.activeRuleCount || activeRules.length || 0)}
-
- 桥接模式 - ${_escHtml(snapshot.host?.sourceLabel || "unknown")} · ${_escHtml(snapshot.host?.capabilityStatus?.mode || snapshot.host?.mode || "unknown")}${snapshot.host?.fallback ? " · fallback" : ""} +
+ 桥接模式 + ${_escHtml(snapshot.host?.sourceLabel || "unknown")} · ${_escHtml(snapshot.host?.capabilityStatus?.mode || snapshot.host?.mode || "unknown")}${snapshot.host?.fallback ? " · fallback" : ""}
-
-
当前启用开关
-
- 来源:global=${sourceConfig.global === false ? "关" : "开"} / preset=${sourceConfig.preset === false ? "关" : "开"} / character=${sourceConfig.character === false ? "关" : "开"} +
+
+
+
当前启用规则
+
EW 风格平铺展示,优先看你这次请求里真正会进入链路的规则。
+
- 阶段:${_escHtml(Object.entries(stageConfig).map(([key, value]) => `${key}=${value ? "on" : "off"}`).join(" | ") || "无")} + 来源开关:${_escHtml(sourceSummaryText)}
+ 阶段开关:${_escHtml(stageSummaryText)} +
+
+ ${_renderRegexReuseRuleList(activeRules, "当前没有复用到任何酒馆正则", { + showSource: true, + })}
-
-
来源明细
+
+ 来源与排除明细 +
${ sources.length ? sources.map((source) => ` -
- - ${_escHtml(source.label || source.type || "未知来源")} - · ${_escHtml(_formatRegexReuseSourceState(source))} - +
+
+
${_escHtml(source.label || source.type || "未知来源")}
+
${_escHtml(_formatRegexReuseSourceState(source))}
+
raw=${Number(source.rawRuleCount || 0)} / active=${Number(source.activeRuleCount || 0)} ${source.reason ? `
${_escHtml(source.reason)}` : ""}
- ${_renderRegexReuseRuleList(source.previewRules || source.rules, "该来源当前没有可展示的规则")} +
+ ${_renderRegexReuseRuleList(source.previewRules || source.rules, "该来源当前没有可展示的规则")} +
- ${_renderRegexReuseRuleList(source.ignoredRules, "没有额外被排除的规则")} -
+
+ ${_renderRegexReuseRuleList(source.ignoredRules, "没有额外被排除的规则", { + showReason: true, + muted: true, + })} +
+
`).join("") : `
当前没有可展示的酒馆正则来源。
` } -
- -
-
汇总后的复用规则
-
- 这是经过来源开关、allowlist 和去重后,进入 ST-BME 任务链的 Tavern 规则集合。展示/美化类规则在请求阶段会按空字符串替换。
- ${_renderRegexReuseRuleList(activeRules, "当前没有复用到任何酒馆正则")} -
+
`; diff --git a/style.css b/style.css index 28ffa9d..9cd1492 100644 --- a/style.css +++ b/style.css @@ -1954,6 +1954,211 @@ line-height: 1.55; } +.bme-regex-preview-screen { + gap: 14px; +} + +.bme-regex-preview-hero, +.bme-regex-preview-panel, +.bme-regex-preview-source { + background: linear-gradient(180deg, rgba(255, 255, 255, 0.035), rgba(255, 255, 255, 0.02)); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 16px; + padding: 16px; +} + +.bme-regex-preview-hero__title, +.bme-regex-preview-panel__title { + font-size: 16px; + font-weight: 700; + color: var(--bme-on-surface); +} + +.bme-regex-preview-hero__subtitle, +.bme-regex-preview-panel__subtitle, +.bme-regex-preview-source__meta, +.bme-regex-preview-item__meta { + margin-top: 6px; + font-size: 12px; + line-height: 1.55; + color: var(--bme-on-surface-dim); +} + +.bme-regex-preview-summary { + margin-top: 14px; + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; +} + +.bme-regex-preview-summary__item { + padding: 10px 12px; + border-radius: 12px; + background: rgba(255, 255, 255, 0.025); + border: 1px solid rgba(255, 255, 255, 0.06); +} + +.bme-regex-preview-summary__label { + display: block; + font-size: 11px; + letter-spacing: 0.05em; + text-transform: uppercase; + color: var(--bme-on-surface-dim); +} + +.bme-regex-preview-summary__value { + display: block; + margin-top: 4px; + font-size: 13px; + line-height: 1.45; + color: var(--bme-on-surface); + word-break: break-word; +} + +.bme-regex-preview-panel__head, +.bme-regex-preview-source__head { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 12px; + margin-bottom: 10px; +} + +.bme-regex-preview-source__title { + font-size: 14px; + font-weight: 700; + color: var(--bme-on-surface); +} + +.bme-regex-preview-list { + display: flex; + flex-direction: column; + gap: 10px; +} + +.bme-regex-preview-list .bme-task-empty { + margin: 0; +} + +.bme-regex-preview-item { + padding: 14px; + border-radius: 14px; + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(255, 255, 255, 0.08); +} + +.bme-regex-preview-item.is-muted { + opacity: 0.82; +} + +.bme-regex-preview-item__head { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 10px; +} + +.bme-regex-preview-item__title-group, +.bme-regex-preview-item__badges { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; +} + +.bme-regex-preview-item__index { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 34px; + height: 24px; + padding: 0 8px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.08); + color: var(--bme-on-surface-dim); + font-size: 11px; + font-weight: 700; +} + +.bme-regex-preview-item__name { + font-size: 13px; + font-weight: 700; + color: var(--bme-on-surface); + line-height: 1.4; +} + +.bme-regex-preview-item__badge { + display: inline-flex; + align-items: center; + min-height: 24px; + padding: 0 8px; + border-radius: 999px; + font-size: 11px; + font-weight: 700; + border: 1px solid transparent; +} + +.bme-regex-preview-item__badge.is-transform { + background: rgba(76, 175, 80, 0.12); + color: #9fe6a1; + border-color: rgba(76, 175, 80, 0.25); +} + +.bme-regex-preview-item__badge.is-clear { + background: rgba(255, 193, 7, 0.13); + color: #ffd777; + border-color: rgba(255, 193, 7, 0.26); +} + +.bme-regex-preview-item__badge.is-skip { + background: rgba(255, 255, 255, 0.08); + color: var(--bme-on-surface-dim); + border-color: rgba(255, 255, 255, 0.1); +} + +.bme-regex-preview-item__badge.is-prompt { + background: rgba(33, 150, 243, 0.13); + color: #88d0ff; + border-color: rgba(33, 150, 243, 0.26); +} + +.bme-regex-preview-item__details { + margin-top: 12px; + display: grid; + gap: 8px; +} + +.bme-regex-preview-item__row { + display: grid; + grid-template-columns: 52px minmax(0, 1fr); + gap: 10px; + align-items: start; + font-size: 12px; + line-height: 1.55; + color: var(--bme-on-surface); +} + +.bme-regex-preview-item__label { + color: var(--bme-on-surface-dim); + font-weight: 700; +} + +.bme-regex-preview-item__row code { + white-space: pre-wrap; + word-break: break-word; +} + +.bme-regex-preview-details > summary { + padding: 12px 14px; +} + +.bme-regex-preview-details__body { + padding: 0 14px 14px; + display: flex; + flex-direction: column; + gap: 12px; +} + .bme-task-editor-toggle { margin-bottom: 12px; } @@ -2491,6 +2696,28 @@ display: none; } + .bme-regex-preview-hero, + .bme-regex-preview-panel, + .bme-regex-preview-source { + padding: 14px; + border-radius: 14px; + } + + .bme-regex-preview-summary { + grid-template-columns: 1fr; + } + + .bme-regex-preview-item__head, + .bme-regex-preview-source__head { + flex-direction: column; + align-items: stretch; + } + + .bme-regex-preview-item__row { + grid-template-columns: 1fr; + gap: 4px; + } + /* ⑥ 图谱 tab 移动端全屏覆盖 */ .bme-panel-main.mobile-visible { display: flex;