dsh-session-guard 3.2.4 → 3.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["POLL_MS","useState","useState","useState","useSyncExternalStore","useSyncExternalStore"],"sources":["../src/client/badge-text.ts","../src/client/styles.ts","../src/client/status-badge.tsx","../src/client/pause-button-text.ts","../src/client/pause-button.tsx","../src/client/settings-card.tsx","../src/client/family-section.tsx","../src/client/index.ts"],"sourcesContent":["/**\r\n * dsh-session-guard — 状态徽标文案(纯函数,零依赖,可单测)。\r\n *\r\n * 分离出来的原因:徽标语义(高峰期「只拦官方」vs「全部暂停」)需要单测,\r\n * 而组件文件是 TSX(含 React 运行时)。这里只有字符串逻辑。\r\n */\r\n\r\n/** /session-guard/status 返回的全局阶段(组件与测试共用)。 */\r\nexport interface Status {\r\n phase: 'peak' | 'off-peak' | 'weekend'\r\n enabled: boolean\r\n weekendMode: boolean\r\n /** 官方源二维判定是否开启(开启时高峰期只拦官方源)。 */\r\n providerGuard?: boolean\r\n /** 当前被挂起的请求数(hold 模式)。 */\r\n held?: number\r\n /** error 模式记下的延后会话数。 */\r\n deferred?: number\r\n /** 当前被 step 门挂起的会话数(v0.2.0)。 */\r\n stepHeld?: number\r\n timezone: string\r\n}\r\n\r\n/** 阶段文案。 */\r\nexport const PHASE_LABELS = {\r\n peak: '高峰',\r\n 'off-peak': '谷时',\r\n weekend: '周末',\r\n} as const\r\n\r\n/** 高峰期的徽标文案:二维判定开启时区分「只拦官方」与「全部暂停」。 */\r\nexport function peakLabel(status: Pick<Status, 'phase' | 'providerGuard'>): string {\r\n if (status.phase !== 'peak') return PHASE_LABELS[status.phase]\r\n return status.providerGuard === true ? '高峰·拦官方' : '高峰·全部暂停'\r\n}\r\n\r\n/** 悬浮说明:把判定口径与当前挂起/延后数量写清楚。 */\r\nexport function badgeTitle(status: Status): string {\r\n const base = `${PHASE_LABELS[status.phase]} · ${status.timezone}${status.weekendMode ? ' · 周末模式' : ''}`\r\n if (status.phase !== 'peak') return base\r\n const mode = status.providerGuard === true ? '仅拦截 DeepSeek 官方源' : '全部会话暂停(未启用二维判定)'\r\n const held = status.held ?? 0\r\n const deferred = status.deferred ?? 0\r\n const stepHeld = status.stepHeld ?? 0\r\n const extra = held > 0 || deferred > 0 || stepHeld > 0\r\n ? ` · 挂起 ${held} · 延后 ${deferred} · step 挂起 ${stepHeld}`\r\n : ''\r\n return `${base} · ${mode}${extra}`\r\n}\r\n","/**\n * dsh-session-guard — 客户端样式(与 composer 右侧 input-traffic 冻结按钮同一视觉语言)。\n *\n * 为什么注入 `<style>` 而不是 CSS Modules:本插件的 tsdown 配置没有 CSS Modules 管线\n * (input-traffic 有),而 settings-card 已经用 `<style data-plugin-css>` 的既有约定。\n * 这里只做一件事:把「暂停会话 / 继续会话」按钮与状态徽标对齐到同一行的其它控件\n * (高度 24px、圆角 6px、12px 字号、同样的 border / hover / pressed 令牌)。\n */\n\n/** 与 `dsh-input-traffic/src/client/freeze-button.module.css` 对齐的控件外观。 */\nexport const CLIENT_CSS = `\n.sg-pause{display:inline-flex;align-items:center;gap:4px;height:24px;padding:0 8px;border:1px solid var(--dsw-alias-border-l3,rgba(0,0,0,.12));border-radius:6px;background:transparent;color:var(--dsw-alias-label-secondary,#6b7280);font-size:12px;line-height:1;cursor:pointer;white-space:nowrap;flex:none}\n.sg-pause:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}\n.sg-pause:disabled{opacity:.55;cursor:default}\n.sg-pause[aria-pressed='true']{border-color:var(--dsw-alias-state-warning-primary,#d97706);color:var(--dsw-alias-state-warning-primary,#d97706);background:color-mix(in srgb,var(--dsw-alias-state-warning-primary,#d97706) 8%,transparent)}\n.sg-status{display:inline-flex;align-items:center;height:24px;padding:0 8px;border:1px solid var(--dsw-alias-border-l3,rgba(0,0,0,.12));border-radius:6px;font-size:12px;line-height:1;color:var(--dsw-alias-label-secondary,#6b7280);white-space:nowrap;flex:none}\n.sg-status.sg-peak{border-color:var(--dsw-alias-state-warning-primary,#d97706);color:var(--dsw-alias-state-warning-primary,#d97706)}\n.sg-status.sg-weekend{border-color:var(--dsw-alias-state-success-primary,#30a46c);color:var(--dsw-alias-state-success-primary,#30a46c)}\n`\n\n/** 注入一次(幂等;无 document 时静默跳过)。 */\nexport function injectClientCss(): void {\n if (typeof document === 'undefined') return\n if (document.querySelector('style[data-plugin-css=\"session-guard-client\"]') !== null) return\n const tag = document.createElement('style')\n tag.dataset.plugin = 'dsh-session-guard'\n tag.dataset.pluginCss = 'session-guard-client'\n tag.textContent = CLIENT_CSS\n document.head.appendChild(tag)\n}\n","/**\r\n * dsh-session-guard — 状态徽标(纯展示,fail-open)。\r\n *\r\n * 轮询 host 的 /session-guard/status(全局当前阶段),显示 高峰/谷时/周末;\r\n * 高峰期按二维判定区分「只拦官方」与「全部暂停」(文案见 badge-text.ts)。\r\n * 仅展示,不做任何队列/会话动作;冻结按钮由 input-traffic 经桥接管(D6/D8)。\r\n */\r\nimport { useEffect, useState } from 'react'\r\nimport { badgeTitle, peakLabel, type Status } from './badge-text'\r\nimport { injectClientCss } from './styles'\r\n\r\n/** slot 运行时注入的会话级 props(sessionId 由 dsh 的 SessionStandardProps 提供)。 */\r\nexport interface StatusBadgeProps {\r\n sessionId?: string\r\n}\r\n\r\nconst POLL_MS = 15_000\r\n\r\n/** 状态徽标:轮询全局阶段,显示 高峰/谷时/周末(enabled 关闭或请求失败时静默隐藏)。 */\r\nexport function StatusBadge({ sessionId }: StatusBadgeProps) {\r\n const [status, setStatus] = useState<Status | null>(null)\r\n\r\n injectClientCss()\r\n\r\n useEffect(() => {\r\n if (!sessionId) return\r\n let cancelled = false\r\n const poll = async () => {\r\n try {\r\n const res = await fetch('/session-guard/status')\r\n const body = await res.json().catch(() => null)\r\n if (!cancelled && body?.ok && body.status) setStatus(body.status)\r\n } catch {\r\n // fail-open:路由/网络不可达 → 静默,徽标隐藏。\r\n }\r\n }\r\n void poll()\r\n const timer = setInterval(poll, POLL_MS)\r\n return () => {\r\n cancelled = true\r\n clearInterval(timer)\r\n }\r\n }, [sessionId])\r\n\r\n if (!status || !status.enabled) return null\r\n\r\n const cls = status.phase === 'peak' ? 'sg-peak' : status.phase === 'weekend' ? 'sg-weekend' : 'sg-off'\r\n return (\r\n <span\r\n className={`sg-status ${cls}`}\r\n title={badgeTitle(status)}\r\n data-sg-phase={status.phase}\r\n data-sg-provider-guard={status.providerGuard === true ? 'on' : 'off'}\r\n data-sg-step-held={String(status.stepHeld ?? 0)}\r\n >\r\n {peakLabel(status)}\r\n </span>\r\n )\r\n}\r\n","/**\n * dsh-session-guard — 暂停/继续按钮文案与状态投影(纯函数,零依赖,可单测)。\n *\n * 交互(v0.2.0 修订):\n * - 未暂停 → 「暂停会话」(**可点**:点击 = 在下一次 step 边界手动暂停该会话);\n * - 已暂停(step 门已拉 / 已请求但未到边界)→ 「继续会话」(点击 = 放行并本峰不再拦)。\n * 按钮不置灰:step 暂停虽然会自动发生,但按钮同时是**手动暂停**入口。\n */\n\n/** 按钮状态。 */\nexport interface PauseButtonState {\n /** 是否处于暂停态(step 门已挂起,或已请求暂停但还没到边界) */\n paused: boolean\n /** 挂起起始时间戳(毫秒);未知为 null */\n heldSince?: number | null\n /** 暂停是否来自用户手动请求(而非高峰自动拉门) */\n manual?: boolean\n}\n\n/** 按钮文案。 */\nexport function pauseButtonLabel(state: PauseButtonState): string {\n return state.paused === true ? '继续会话' : '暂停会话'\n}\n\n/** 悬浮说明:写清当前状态与点击后的语义。 */\nexport function pauseButtonTitle(state: PauseButtonState): string {\n if (state.paused !== true) {\n return '暂停会话:在下一次 step 的模型请求前暂停(高峰 + 官方源时会自动暂停)'\n }\n const since = typeof state.heldSince === 'number' && Number.isFinite(state.heldSince) ? new Date(state.heldSince) : null\n const at = since === null ? null : `${String(since.getHours()).padStart(2, '0')}:${String(since.getMinutes()).padStart(2, '0')}`\n const why = state.manual === true ? '手动暂停' : '高峰自动暂停'\n const base = at === null ? `已暂停(${why})` : `已暂停(${why},自 ${at})`\n return `${base} · 点击继续:放行当前 step,且本高峰内不再拦该会话`\n}\n\n/** 把 `/session-guard/state` 的响应体投影为按钮状态(形状异常 → 未暂停,fail-open)。 */\nexport function readPauseState(body: unknown): PauseButtonState {\n const b = (body ?? {}) as {\n ok?: unknown\n paused?: { step?: unknown; manual?: unknown }\n stepGate?: { since?: unknown; manual?: unknown }\n state?: { pausedStep?: unknown; stepHeldSince?: unknown; stepManual?: unknown }\n }\n if (b.ok !== true) return { paused: false, heldSince: null, manual: false }\n const manual = b.paused?.manual === true || b.stepGate?.manual === true || b.state?.stepManual === true\n const paused = b.paused?.step === true || b.state?.pausedStep === true || manual\n const raw = b.stepGate?.since ?? b.state?.stepHeldSince ?? null\n const heldSince = typeof raw === 'number' && Number.isFinite(raw) ? raw : null\n return { paused, heldSince, manual }\n}\n\n/** 把 SSE `/session-guard/events` 的 `state` 快照投影为按钮状态。 */\nexport function readStepSnapshot(snapshot: unknown): PauseButtonState {\n const s = (snapshot ?? {}) as { held?: unknown; since?: unknown; manual?: unknown }\n const manual = s.manual === true\n const paused = s.held === true || manual\n const heldSince = typeof s.since === 'number' && Number.isFinite(s.since) ? s.since : null\n return { paused, heldSince, manual }\n}\n","/**\n * dsh-session-guard — 「暂停会话 / 继续会话」按钮(`conversation.input.right`,order 20)。\n *\n * 交互(v0.2.0 修订):\n * - 未暂停 → 「暂停会话」,**可点**:点击 POST `{action:'stepPause'}`,在**下一次 step 边界**暂停\n * (不打断当前 step;step 1 也拦,不受峰谷 / provider 限制);\n * - 已暂停(高峰自动拉门 **或** 手动请求已登记)→ 「继续会话」,点击 POST `{action:'stepResume'}`;\n * - 状态更新双通道:① SSE `/session-guard/events?session=<id>` 即时推送;② 10s 轮询兜底\n * (SSE 不可用 / 断线时仍能收敛)。全部 fail-open,绝不抛错。\n *\n * 与 input-traffic 的「❄ 冻结追加 / 恢复追加」并列(order 30 在其右侧),互不取代:\n * 本按钮控 step 门,冻结按钮控回合级冻结 + 队列摘除。\n */\nimport { useEffect, useState } from 'react'\nimport {\n pauseButtonLabel,\n pauseButtonTitle,\n readPauseState,\n readStepSnapshot,\n type PauseButtonState,\n} from './pause-button-text'\nimport { injectClientCss } from './styles'\n\n/** slot 运行时注入的会话级 props。 */\nexport interface PauseButtonProps {\n sessionId?: string\n}\n\n/** SSE 不可用时的兜底轮询间隔(正常路径由事件驱动,几乎不触发)。 */\nconst POLL_MS = 10_000\n\nconst IDLE: PauseButtonState = { paused: false, heldSince: null, manual: false }\n\n/** 暂停 / 继续会话按钮。 */\nexport function PauseButton({ sessionId }: PauseButtonProps) {\n const [state, setState] = useState<PauseButtonState>(IDLE)\n const [busy, setBusy] = useState(false)\n\n injectClientCss()\n\n useEffect(() => {\n if (sessionId === undefined || sessionId === '') return\n let cancelled = false\n\n const poll = async (): Promise<void> => {\n try {\n const res = await fetch(`/session-guard/state?session=${encodeURIComponent(sessionId)}`)\n const body = await res.json().catch(() => null)\n if (cancelled) return\n setState(readPauseState(body))\n } catch {\n // fail-open:路由不存在 / 网络失败 → 保持上一次状态。\n }\n }\n void poll()\n const timer = setInterval(() => {\n void poll()\n }, POLL_MS)\n\n let source: EventSource | undefined\n try {\n source = new EventSource(`/session-guard/events?session=${encodeURIComponent(sessionId)}`)\n source.onmessage = (ev: MessageEvent<string>) => {\n try {\n const msg = JSON.parse(ev.data) as { type?: string; state?: unknown }\n if (cancelled || msg?.type !== 'step') return\n setState(readStepSnapshot(msg.state))\n } catch {\n /* 非法负载:忽略,等下一次推送或轮询 */\n }\n }\n // onerror:EventSource 会自行重连;轮询同时兜底。\n source.onerror = () => undefined\n } catch {\n // 浏览器不支持 EventSource → 只靠轮询。\n }\n\n return () => {\n cancelled = true\n clearInterval(timer)\n try {\n source?.close()\n } catch {\n /* ignore */\n }\n }\n }, [sessionId])\n\n if (sessionId === undefined || sessionId === '') return null\n\n const paused = state.paused === true\n const onClick = async (): Promise<void> => {\n if (busy) return\n setBusy(true)\n try {\n const action = paused ? 'stepResume' : 'stepPause'\n const res = await fetch('/session-guard/rpc', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ sessionId, action }),\n })\n const body = await res.json().catch(() => null)\n if (body?.ok === true) {\n // 立即乐观更新;SSE / 轮询随后校正。\n setState(paused ? IDLE : { paused: true, heldSince: null, manual: true })\n }\n } catch {\n // fail-open:下一轮轮询会纠正显示。\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <button\n type=\"button\"\n className=\"sg-pause\"\n disabled={busy}\n aria-pressed={paused || undefined}\n title={pauseButtonTitle(state)}\n data-sg-step-paused={paused ? 'on' : 'off'}\n onClick={() => {\n void onClick()\n }}\n >\n {pauseButtonLabel(state)}\n </button>\n )\n}\n","/**\n * dsh-session-guard — 插件配置卡片(dsh-family.tab 共用设置节,抽屉默认展开)。\n *\n * 对齐 dsh-thinking-levels / dsh-tidychat 的卡片语法:一个可展开的 `<li>`,\n * header 按钮(插件名 + 描述 + chevron)切换字段体;开关为 pill switch\n * (track + thumb),不是复选框对勾。\n *\n * 经 `configForms.get('session-guard')` 绑定本插件 entry 的配置\n * (0.1.7 configForms 缝);每次变更立即经 scope 提交(无 staged form)。\n * 仅依赖 react;CSS 经 `<style data-plugin-css>` 注入一次,控件为原生 HTML,\n * 客户端 bundle 无 value-import @deepseek-ai/* 平台包(类型导入被构建擦除)。\n */\nimport { useEffect, useState, useSyncExternalStore } from 'react'\nimport type { JSX } from 'react'\nimport type { SettingsScope } from './scope-face.ts'\n\n/** 命名空间值形状(与 host 的 DEFAULT_SETTINGS 对应)。 */\nexport interface SessionGuardConfig {\n enabled: boolean\n offPeakAutoResume: boolean\n weekendMode: boolean\n queueFallback: boolean\n retryEnabled: boolean\n timezone: string\n pauseMode: 'safe' | 'force'\n pauseReason: 'wait' | 'stop'\n // ── step 级门控(v0.2.0)──\n stepLevelPause: boolean\n stepGateTimeoutMs: number\n // ── 官方 provider 二维判定(高峰 × 目标源)──\n providerGuard: boolean\n officialProviders: string[]\n officialBaseURLs: string[]\n deferredResume: boolean\n deferredResumeText: string\n deferredMode: 'hold' | 'error'\n deferredMaxHoldMs: number\n guardSubagents: boolean\n}\n\n/** 注入给卡片的面:绑定到 session-guard 命名空间的 settings scope。 */\nexport interface SettingsCardInjected {\n scope: SettingsScope<SessionGuardConfig>\n}\n\nexport type SettingsCardProps = SettingsCardInjected\n\n/** 卡片样式,注入一次(保持 bundle CSS-free)。 */\nconst CARD_CSS = `\n.sgCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}\n.sgCard:hover{border-color:var(--dsw-alias-label-dimmed)}\n.sgCard-open{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}\n.sgCardHeader{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:transparent;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}\n.sgCardHeadtext{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}\n.sgCardName{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}\n.sgCardDesc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}\n.sgCardChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}\n.sgCardChevron-open{transform:rotate(180deg)}\n.sgCardBody{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 12px}\n.sgRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}\n.sgRow:last-child{border-bottom:0}\n.sgRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}\n.sgRowText-wide{padding-right:0}\n.sgTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}\n.sgDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}\n.sgSwitch{position:relative;width:40px;height:22px;flex:none}\n.sgSwitch>input{position:absolute;inset:0;width:100%;height:100%;opacity:0;margin:0;cursor:pointer}\n.sgSwitch>input:disabled{cursor:not-allowed}\n.sgSwitchTrack{position:absolute;inset:0;border-radius:22px;background:var(--dsw-alias-interactive-bg-hover);transition:background .16s}\n.sgSwitch>input:checked+.sgSwitchTrack{background:var(--dsw-alias-button-primary-fill)}\n.sgSwitchThumb{position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:transform .16s}\n.sgSwitch>input:checked~.sgSwitchThumb{transform:translateX(18px)}\n.sgInput{appearance:none;min-width:0;width:100%;font:inherit;font-size:13px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:7px 10px;margin-top:8px}\n.sgInput:disabled{opacity:.6;cursor:not-allowed}\n.sgSelect{appearance:none;font:inherit;font-size:13px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:7px 10px;min-width:160px;flex:none}\n.sgSelect:disabled{opacity:.6;cursor:not-allowed}\n.sgHint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:6px 0 0}\n.sgReadonly{color:var(--dsw-alias-label-tertiary);font-size:12px;margin:8px 0 0}\n`\n\n/** 注入一次卡片样式。 */\nfunction injectCss(): void {\n if (typeof document !== 'undefined' && document.querySelector('style[data-plugin-css=\"session-guard-card\"]') === null) {\n const tag = document.createElement('style')\n tag.dataset.plugin = 'dsh-session-guard'\n tag.dataset.pluginCss = 'session-guard-card'\n tag.textContent = CARD_CSS\n document.head.appendChild(tag)\n }\n}\n\n/** 一行 pill switch(滑块开关,绑定 scope)。 */\nfunction SwitchRow(props: {\n label: string\n description?: string\n checked: boolean\n disabled: boolean\n onChange: (_next: boolean) => void\n}): JSX.Element {\n const { label, description, checked, disabled, onChange } = props\n return (\n <div className=\"sgRow\">\n <div className=\"sgRowText\">\n <div className=\"sgTitle\">{label}</div>\n {description !== undefined && <div className=\"sgDesc\">{description}</div>}\n </div>\n <label className=\"sgSwitch\">\n <input\n type=\"checkbox\"\n checked={checked}\n disabled={disabled}\n onChange={(e) => onChange(e.currentTarget.checked)}\n />\n <span className=\"sgSwitchTrack\" />\n <span className=\"sgSwitchThumb\" />\n </label>\n </div>\n )\n}\n\n/** 一行文本输入(失焦提交;外部值变化时同步草稿)。 */\nfunction TextRow(props: {\n label: string\n description?: string\n value: string\n placeholder?: string\n disabled: boolean\n onCommit: (_next: string) => void\n}): JSX.Element {\n const { label, description, value, placeholder, disabled, onCommit } = props\n const [draft, setDraft] = useState(value)\n useEffect(() => {\n setDraft(value)\n }, [value])\n return (\n <div className=\"sgRow\">\n <div className=\"sgRowText sgRowText-wide\">\n <div className=\"sgTitle\">{label}</div>\n {description !== undefined && <div className=\"sgDesc\">{description}</div>}\n <input\n className=\"sgInput\"\n type=\"text\"\n value={draft}\n placeholder={placeholder}\n disabled={disabled}\n onChange={(e) => setDraft(e.currentTarget.value)}\n onBlur={() => onCommit(draft)}\n />\n </div>\n </div>\n )\n}\n\n/** 一行「逗号/换行分隔」的字符串列表(失焦提交为数组)。 */\nfunction ListRow(props: {\n label: string\n description?: string\n values: string[]\n placeholder?: string\n disabled: boolean\n onCommit: (_next: string[]) => void\n}): JSX.Element {\n const { label, description, values, placeholder, disabled, onCommit } = props\n const joined = values.join(', ')\n const [draft, setDraft] = useState(joined)\n useEffect(() => {\n setDraft(joined)\n }, [joined])\n return (\n <div className=\"sgRow\">\n <div className=\"sgRowText sgRowText-wide\">\n <div className=\"sgTitle\">{label}</div>\n {description !== undefined && <div className=\"sgDesc\">{description}</div>}\n <input\n className=\"sgInput\"\n type=\"text\"\n value={draft}\n placeholder={placeholder}\n disabled={disabled}\n onChange={(e) => setDraft(e.currentTarget.value)}\n onBlur={() => {\n const next = draft\n .split(/[,\\n]/)\n .map((s) => s.trim())\n .filter((s) => s !== '')\n onCommit(next)\n }}\n />\n </div>\n </div>\n )\n}\n\n/** 一行下拉选择。 */\nfunction SelectRow<T extends string>(props: {\n label: string\n description?: string\n value: T\n options: readonly { value: T; label: string }[]\n disabled: boolean\n onChange: (_next: T) => void\n}): JSX.Element {\n const { label, description, value, options, disabled, onChange } = props\n return (\n <div className=\"sgRow\">\n <div className=\"sgRowText\">\n <div className=\"sgTitle\">{label}</div>\n {description !== undefined && <div className=\"sgDesc\">{description}</div>}\n </div>\n <select\n className=\"sgSelect\"\n value={value}\n disabled={disabled}\n onChange={(e) => onChange(e.currentTarget.value as T)}\n >\n {options.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n </div>\n )\n}\n\n/** 插件配置卡片主体:可展开的 <li> + header 按钮 + pill switch 字段体。 */\nexport function SessionGuardCard({ scope }: SettingsCardProps): JSX.Element {\n const snapshot = useSyncExternalStore(\n (listener) => scope.subscribe(listener),\n () => scope.getSnapshot(),\n )\n const unavailable = snapshot.status === 'unavailable'\n const readonly = unavailable || !snapshot.writable\n const value = (snapshot.value ?? {}) as Partial<SessionGuardConfig>\n const [open, setOpen] = useState(true)\n\n injectCss()\n\n const toggle = (field: keyof SessionGuardConfig, next: boolean) => { void scope.set(field, next) }\n return (\n <li className={'sgCard' + (open ? ' sgCard-open' : '')}>\n <button\n type=\"button\"\n className=\"sgCardHeader\"\n aria-expanded={open}\n onClick={() => setOpen(!open)}\n >\n <span className=\"sgCardHeadtext\">\n <span className=\"sgCardName\">会话守护门禁</span>\n <span className=\"sgCardDesc\">高峰自动暂停运行会话,周末模式无视峰谷畅快跑</span>\n </span>\n <svg\n className={'sgCardChevron' + (open ? ' sgCardChevron-open' : '')}\n viewBox=\"0 0 14 14\"\n width={14}\n height={14}\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path d=\"M3.5 5.5L7 9l3.5-3.5\" stroke=\"currentColor\" strokeWidth={1.5} strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n {open && (\n <div className=\"sgCardBody\">\n {unavailable ? (\n <p style={{ margin: '0', padding: '12px 0', fontSize: '13px', color: 'var(--dsw-alias-label-tertiary)' }}>\n 设置命名空间不可用:请确认 dsh-session-guard 已装配进此 profile。\n </p>\n ) : (\n <>\n <SwitchRow\n label=\"高峰自动暂停冻结会话\"\n description=\"高峰时段自动暂停运行会话\"\n checked={value.enabled ?? true}\n disabled={readonly}\n onChange={(next) => toggle('enabled', next)}\n />\n <SwitchRow\n label=\"step 级门控\"\n description=\"高峰在下一个 step 的模型请求前拉门(省 token 更彻底);关闭则回退为回合级暂停\"\n checked={value.stepLevelPause ?? true}\n disabled={readonly}\n onChange={(next) => toggle('stepLevelPause', next)}\n />\n <TextRow\n label=\"step 门控超时(毫秒)\"\n description=\"到期释放 step 门并升级为回合级暂停(防死锁);0 或非法值用默认 300000\"\n value={String(value.stepGateTimeoutMs ?? 300000)}\n placeholder=\"300000\"\n disabled={readonly}\n onCommit={(next) => {\n const n = Number(String(next).trim())\n void scope.set('stepGateTimeoutMs', Number.isFinite(n) && n > 0 ? n : 300000)\n }}\n />\n <SwitchRow\n label=\"官方源二维判定\"\n description=\"高峰期只拦 DeepSeek 官方源;本地/第三方 provider 照常跑\"\n checked={value.providerGuard ?? true}\n disabled={readonly}\n onChange={(next) => toggle('providerGuard', next)}\n />\n <ListRow\n label=\"追加官方 provider id\"\n description=\"精确匹配,优先级最高(逗号分隔)\"\n values={value.officialProviders ?? []}\n placeholder=\"deepseek-official\"\n disabled={readonly}\n onCommit={(next) => { void scope.set('officialProviders', next) }}\n />\n <ListRow\n label=\"官方端点名单\"\n description=\"baseURL 归一化后的 host(逗号分隔)\"\n values={value.officialBaseURLs ?? []}\n placeholder=\"api.deepseek.com\"\n disabled={readonly}\n onCommit={(next) => { void scope.set('officialBaseURLs', next) }}\n />\n <SelectRow<'hold' | 'error'>\n label=\"拦截方式\"\n description=\"挂起等待不报错;或报错并记入延后队列\"\n value={value.deferredMode ?? 'hold'}\n options={[\n { value: 'hold', label: '挂起等待(退峰自动放行)' },\n { value: 'error', label: '报错并延后(退峰续跑)' },\n ]}\n disabled={readonly}\n onChange={(next) => { void scope.set('deferredMode', next) }}\n />\n <SwitchRow\n label=\"退峰自动继续\"\n description=\"关闭后延后的请求/会话不自动续跑,需手动 /resume\"\n checked={value.deferredResume ?? true}\n disabled={readonly}\n onChange={(next) => toggle('deferredResume', next)}\n />\n <TextRow\n label=\"退峰续跑文案\"\n description=\"error 模式退峰时发送的消息内容\"\n value={value.deferredResumeText ?? ''}\n placeholder=\"继续(高峰已过,自动继续)\"\n disabled={readonly}\n onCommit={(next) => { void scope.set('deferredResumeText', next) }}\n />\n <SwitchRow\n label=\"纳入子代理请求\"\n description=\"子代理请求同样计费,默认一并拦截\"\n checked={value.guardSubagents ?? true}\n disabled={readonly}\n onChange={(next) => toggle('guardSubagents', next)}\n />\n <SwitchRow\n label=\"低谷自动恢复\"\n description=\"低峰时段自动恢复被暂停的会话\"\n checked={value.offPeakAutoResume ?? true}\n disabled={readonly}\n onChange={(next) => toggle('offPeakAutoResume', next)}\n />\n <SwitchRow\n label=\"周末模式\"\n description=\"识别周末,无视峰谷畅快跑\"\n checked={value.weekendMode ?? true}\n disabled={readonly}\n onChange={(next) => toggle('weekendMode', next)}\n />\n <SwitchRow\n label=\"回退锁队列\"\n description=\"无会话门时锁等待队列\"\n checked={value.queueFallback ?? true}\n disabled={readonly}\n onChange={(next) => toggle('queueFallback', next)}\n />\n <SwitchRow\n label=\"自动重试\"\n description=\"后端重试,默认关(保守)\"\n checked={value.retryEnabled ?? false}\n disabled={readonly}\n onChange={(next) => toggle('retryEnabled', next)}\n />\n <p className=\"sgHint\">\n 判定口径:显式 id 名单 → baseURL 端点 → catalog 默认端点 → 内置 id。\n 排查误判访问 /session-guard/provider?provider=&lt;id&gt; 看 matchedBy。\n </p>\n {!snapshot.writable && <p className=\"sgReadonly\">当前只读,无法修改。</p>}\n </>\n )}\n </div>\n )}\n </li>\n )\n}\n","/**\n * dsh-session-guard — 家族节接管组件(fallback host section)。\n *\n * 仅当宿主 dsh-thinking-levels 缺席、且本插件在接管选举中胜出时,由\n * index.ts 注册为顶级 `settings.section`(id 固定 `dsh-family`,节名仍为\n * 「起子插件设置」)。组件是纯通用渲染:把 `dsh-family.tab` 账本里的每张\n * 贡献卡(含本插件自己的,因为接管时本插件也声明了该子席位)按 order\n * 依次 renderSlot —— 卡片本身是默认展开的抽屉,整节即一页抽屉。\n *\n * 与 thinking-levels 的 FamilySettingsSection 的差别仅在不需要 thinking-\n * levels 自己的卡(宿主不在了,它的卡也不在):渲染循环没有 own-tab 特例。\n */\nimport { useSyncExternalStore } from 'react'\nimport type { JSX } from 'react'\n\n/** 与 FamilySectionInjected.hooks.tabs 同形的账本投影(结构化镜像)。 */\ntype HostObservable<T> = {\n getSnapshot(): T\n subscribe(listener: () => void): () => void\n}\n\n/** 账本条目(id/order/label,label 已解析为字符串)。 */\nexport interface FamilyTabEntry {\n id: string\n order: number\n label: string\n}\n\n/** 组件 props:框架注入的子席位 dispatcher + 注册侧 inject 返回的 hooks。 */\nexport interface GuardFamilySectionProps {\n renderSlot: (key: 'dsh-family.tab', owner?: object, opts?: { only?: string; fallback?: JSX.Element | null }) => JSX.Element | null\n hooks: { tabs: HostObservable<readonly FamilyTabEntry[]> }\n}\n\nexport function GuardFamilySection(props: GuardFamilySectionProps): JSX.Element {\n const tabs = useSyncExternalStore(props.hooks.tabs.subscribe, props.hooks.tabs.getSnapshot)\n return (\n <div style={{ display: 'grid', gap: '12px' }}>\n {tabs.map(row => (\n <div key={row.id}>\n {props.renderSlot('dsh-family.tab', {}, { only: row.id, fallback: null })}\n </div>\n ))}\n </div>\n )\n}\n","/**\n * dsh-session-guard — 浏览器 half。\n *\n * 职责(全部 fail-open,D8):\n * - 在 composer 输入区右侧注册一个**纯展示**状态徽标(高峰/谷时/周末),轮询\n * /session-guard/status;\n * - **不做**冻结/会话动作——冻结按钮由 input-traffic 接管并经 /session-guard/rpc\n * 桥接 host 会话门;本插件客户端不注册任何按钮,避免与 input-traffic 冲突。\n * - 0.1.7:旧的插件设置卡已随席位删除 —— 设置表单由 host\n * 侧 Config 的 `.volatile()` 字段自动生成。\n *\n * 构建:tsdown → lib/client.js(__ModuleLoader__.load 注册,与 input-traffic 同构)。\n */\nimport { StatusBadge } from './status-badge'\nimport { PauseButton } from './pause-button'\nimport { SessionGuardCard } from './settings-card'\nimport { GuardFamilySection, type FamilyTabEntry } from './family-section'\n\n// 起子插件族共用设置节:宿主 dsh-thinking-levels 注册顶级 `settings.section`\n// (id `dsh-family`)并声明 `dsh-family.tab` 子席位,本插件贡献卡片。宿主缺席\n// 时本插件按下载量排名接管该节(见 apply 内的选举逻辑),节名仍为\n// 「起子插件设置」;宿主在场时本插件只贡献卡片。\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface SlotMap {\n 'dsh-family.tab': { kind: 'list'; scope: 'root' }\n }\n}\n\n/** 家族节固定 id(与 thinking-levels 的注册严格一致)。 */\nconst FAMILY_SECTION_ID = 'dsh-family'\n/** 家族子席位 key(与 thinking-levels 的声明严格一致)。 */\nconst FAMILY_CHILD_KEY = 'dsh-family.tab'\n/**\n * 接管宽限期:等宿主(以及排名更前的贡献方)先落座。下载量排名 guard(1522)\n * 高于 session-steward(1090) → guard 宽限期更短、先尝试接管;并发冲突由\n * ui-slots 的「同 id 同 priority 重复注册抛错」仲裁,后到者放弃即可。\n */\nconst FAMILY_HOST_GRACE_MS = 2000\n\n/** 客户端所需服务:slots(状态徽标)+ locale + configForms(共用 tab 设置卡)。 */\nexport const inject = ['slots', 'locale', 'configForms']\n\n/** 轻量 ctx 类型(仅本客户端用到的方法;构建时类型被剥离)。 */\ninterface SlotsFace {\n inject: (_name: string, _fn: () => unknown) => () => void\n register: (_options: Record<string, unknown>, _component: unknown) => () => void\n entries: (_name: string) => Array<{ options: { id?: string; order?: number; label?: unknown } }>\n getVersion: (_name: string) => number\n subscribe: (_name: string, _listener: () => void) => () => void\n}\ninterface ConfigFormsFace {\n get: <T>(_entryId: string) => import('./scope-face').SettingsScope<T>\n}\ninterface ClientCtx {\n slots: SlotsFace\n configForms: ConfigFormsFace\n}\n\nexport function apply(ctx: ClientCtx) {\n // 暂停会话按钮(v0.2.0):step 级门控的状态显示 + 手动解除。\n // order 20 < input-traffic 冻结按钮的 30 → 排在左侧,两者并列互不取代(ADR-001/002)。\n ctx.slots.inject('conversation.input.right', () => ctx.slots.register({\n name: 'conversation.input.right',\n id: 'session-guard-pause',\n order: 20,\n locale: 'session-guard',\n }, PauseButton))\n\n // 状态徽标:输入区右侧,纯展示。\n ctx.slots.inject('conversation.input.right', () => ctx.slots.register({\n name: 'conversation.input.right',\n id: 'session-guard-status',\n order: 40,\n locale: 'session-guard',\n }, StatusBadge))\n\n // 插件族共用 tab 贡献卡:读写本插件 entry(`session-guard`)的 volatile 配置。\n ctx.slots.inject('dsh-family.tab', () => ctx.slots.register({\n name: 'dsh-family.tab',\n id: 'session-guard',\n order: 20,\n label: '会话守护门禁',\n locale: 'session-guard',\n inject: () => ({ scope: ctx.configForms.get<Record<string, unknown>>('session-guard') }),\n }, SessionGuardCard))\n\n // 家族节宿主选举:宿主 dsh-thinking-levels 缺席时顶上「起子插件设置」节。\n // 宽限期后若 `settings.section` 里没有 id `dsh-family` 的条目,则按同一 id\n // 接管(声明同一个 dsh-family.tab 子席位,节内通用渲染全部贡献卡)。与\n // session-steward 的并发竞争由 ui-slots 同 id 重复注册抛错仲裁,先到者胜。\n // 节内各卡(含本插件自己的贡献卡)经子席位 renderSlot 渲染,抽屉默认展开。\n setTimeout(() => {\n if (ctx.slots.entries('settings.section').some(e => e.options.id === FAMILY_SECTION_ID)) return\n try {\n ctx.slots.register({\n name: 'settings.section',\n id: FAMILY_SECTION_ID,\n order: 40,\n label: () => '起子插件设置',\n inject: () => makeGuardFamilyTabsHooks(ctx.slots),\n children: { [FAMILY_CHILD_KEY]: { kind: 'list', scope: 'root' } },\n }, GuardFamilySection)\n } catch {\n // 并发接管竞争落败(或设置壳未声明席位):胜出方的节服务整个家族。\n }\n }, FAMILY_HOST_GRACE_MS)\n}\n\n/** 接管节的账本投影 hooks(与 thinking-levels 的 FamilySectionInjected 同形)。 */\nfunction makeGuardFamilyTabsHooks(slots: SlotsFace): {\n getSnapshot: () => readonly FamilyTabEntry[]\n subscribe: (listener: () => void) => () => void\n} {\n let version = -1\n let tabs: readonly FamilyTabEntry[] = []\n return {\n getSnapshot: () => {\n const next = slots.getVersion(FAMILY_CHILD_KEY)\n if (next !== version) {\n version = next\n tabs = slots.entries(FAMILY_CHILD_KEY)\n .map(entry => ({\n id: entry.options.id ?? '',\n order: entry.options.order ?? 0,\n label: typeof entry.options.label === 'function'\n ? (() => { try { return String((entry.options.label as () => unknown)() ?? entry.options.id ?? '') } catch { return String(entry.options.id ?? '') } })()\n : String(entry.options.label ?? entry.options.id ?? ''),\n }))\n .sort((a, b) => a.order - b.order)\n }\n return tabs\n },\n subscribe: (listener: () => void) => slots.subscribe(FAMILY_CHILD_KEY, listener),\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["POLL_MS","useState","useState","useState","useSyncExternalStore","useSyncExternalStore"],"sources":["../src/client/locales.ts","../src/client/badge-text.ts","../src/client/styles.ts","../src/client/status-badge.tsx","../src/client/pause-button-text.ts","../src/client/pause-button.tsx","../src/client/settings-card.tsx","../src/client/family-section.tsx","../src/client/index.ts"],"sourcesContent":["/** `session-guard` client dictionaries (zh / en / ja / ko / fr / de / it / ru / es). */\r\n\r\n/** Dictionary namespace owned by this plugin. */\r\nexport const NS = 'session-guard'\r\n\r\n/** Simplified Chinese dictionary (the key-set source of truth). */\r\nexport const zh = {\r\n 'badge.normal': '正常',\r\n 'badge.paused': '已暂停(峰值)',\r\n 'badge_paused_peak': '峰值暂停中',\r\n 'settings.enabled': '高峰自动暂停',\r\n 'settings.enabled.desc': '高峰时段自动暂停运行中的会话',\r\n 'settings.offPeakAutoResume': '低谷自动恢复',\r\n 'settings.offPeakAutoResume.desc': '低峰时段自动恢复被暂停的会话',\r\n 'settings.weekendMode': '周末模式',\r\n 'settings.weekendMode.desc': '识别周末 → 周末不自动暂停',\r\n 'settings.queueFallback': '回退锁等待队列',\r\n 'settings.queueFallback.desc': '自研会话门不可用时回退锁等待队列(fail-open)',\r\n 'settings.retryEnabled': '自动重试',\r\n 'settings.retryEnabled.desc': '瞬时失败自动续跑(默认关,保守)',\r\n 'settings.timezone': '时区',\r\n 'settings.peakWindows': '高峰时间窗口',\r\n 'settings.providerGuard': '官方源二维判定',\r\n 'settings.providerGuard.desc': '高峰期只拦 DeepSeek 官方源;本地/第三方 provider 照常跑',\r\n 'settings.officialProviders': '追加官方 provider id',\r\n 'settings.officialProviders.desc': '精确匹配,优先级最高(逗号分隔)',\r\n 'settings.officialBaseURLs': '官方端点名单',\r\n 'settings.officialBaseURLs.desc': 'baseURL 归一化后的 host(逗号分隔)',\r\n 'settings.deferredMode': '拦截方式',\r\n 'settings.deferredMode.desc': '挂起等待不报错;或报错并记入延后队列',\r\n 'settings.deferredResume': '退峰自动继续',\r\n 'settings.deferredResume.desc': '关闭后延后的请求/会话不自动续跑,需手动 /resume',\r\n 'settings.deferredResumeText': '退峰续跑文案',\r\n 'settings.deferredResumeText.desc': 'error 模式退峰时发送的消息内容',\r\n 'settings.guardSubagents': '纳入子代理请求',\r\n 'settings.guardSubagents.desc': '子代理请求同样计费,默认一并拦截',\r\n 'settings.officialHint': '判定口径:显式 id 名单 → baseURL 端点 → catalog 默认端点 → 内置 id。排查误判访问 /session-guard/provider?provider=<id> 看 matchedBy。',\r\n 'settings.unavailable': '设置不可用:请确认 dsh-session-guard 已装配进 profile。',\r\n 'status.normal': '正常运行',\r\n 'status.paused_peak': '峰值暂停中',\r\n 'status.peak_official': '高峰·拦官方',\r\n 'status.peak_all': '高峰·全部暂停',\r\n} satisfies Record<string, string>\r\n\r\n/** English dictionary (keys mirror zh). */\r\nexport const en: Record<keyof typeof zh, string> = {\r\n 'badge.normal': 'Normal',\r\n 'badge.paused': 'Paused (peak)',\r\n 'badge_paused_peak': 'Peak paused',\r\n 'settings.enabled': 'Peak auto-pause',\r\n 'settings.enabled.desc': 'Auto-pause running sessions during peak hours',\r\n 'settings.offPeakAutoResume': 'Off-peak auto-resume',\r\n 'settings.offPeakAutoResume.desc': 'Auto-resume paused sessions during off-peak hours',\r\n 'settings.weekendMode': 'Weekend mode',\r\n 'settings.weekendMode.desc': 'Detect weekends → no auto-pause on weekends',\r\n 'settings.queueFallback': 'Fallback lock-wait queue',\r\n 'settings.queueFallback.desc': 'Fallback to lock-wait queue when custom session gate is unavailable (fail-open)',\r\n 'settings.retryEnabled': 'Auto-retry',\r\n 'settings.retryEnabled.desc': 'Transient failure auto-resume (off by default, conservative)',\r\n 'settings.timezone': 'Timezone',\r\n 'settings.peakWindows': 'Peak time windows',\r\n 'settings.providerGuard': 'Official-source guard',\r\n 'settings.providerGuard.desc': 'During peak hours only DeepSeek official sources are blocked; local/third-party providers keep running',\r\n 'settings.officialProviders': 'Extra official provider ids',\r\n 'settings.officialProviders.desc': 'Exact match, highest priority (comma separated)',\r\n 'settings.officialBaseURLs': 'Official endpoint hosts',\r\n 'settings.officialBaseURLs.desc': 'Hosts after baseURL normalization (comma separated)',\r\n 'settings.deferredMode': 'Interception mode',\r\n 'settings.deferredMode.desc': 'Hold without error, or fail and queue as deferred',\r\n 'settings.deferredResume': 'Auto-resume after peak',\r\n 'settings.deferredResume.desc': 'When off, deferred requests/sessions stay parked until a manual /resume',\r\n 'settings.deferredResumeText': 'Resume message',\r\n 'settings.deferredResumeText.desc': 'Text sent when an error-mode session resumes off-peak',\r\n 'settings.guardSubagents': 'Guard subagent requests',\r\n 'settings.guardSubagents.desc': 'Subagent requests are billed too; guarded by default',\r\n 'settings.officialHint': 'Decision order: explicit id list → baseURL endpoint → catalog default endpoint → builtin id. For a wrong verdict open /session-guard/provider?provider=<id> and read matchedBy.',\r\n 'settings.unavailable': 'Settings unavailable: make sure dsh-session-guard is assembled into this profile.',\r\n 'status.normal': 'Running normally',\r\n 'status.paused_peak': 'Peak paused',\r\n 'status.peak_official': 'Peak · official only',\r\n 'status.peak_all': 'Peak · all paused',\r\n}\r\n\r\n/** Japanese dictionary (keys mirror zh). */\r\nexport const ja: Record<keyof typeof zh, string> = {\r\n 'badge.normal': '通常',\r\n 'badge.paused': '一時停止(ピーク)',\r\n 'badge_paused_peak': 'ピーク一時停止中',\r\n 'settings.enabled': 'ピーク自動一時停止',\r\n 'settings.enabled.desc': 'ピーク時間帯に実行中セッションを自動一時停止',\r\n 'settings.offPeakAutoResume': 'オフピーク自動再開',\r\n 'settings.offPeakAutoResume.desc': 'オフピーク時に一時停止セッションを自動再開',\r\n 'settings.weekendMode': '週末モード',\r\n 'settings.weekendMode.desc': '週末を認識→週末は自動一時停止しない',\r\n 'settings.queueFallback': 'フォールバックロック待機キュー',\r\n 'settings.queueFallback.desc': 'カスタムセッションゲート利用不可時にロック待機キューにフォールバック(fail-open)',\r\n 'settings.retryEnabled': '自動リトライ',\r\n 'settings.retryEnabled.desc': '瞬時失敗自動再試行(デフォルトオフ、保守的)',\r\n 'settings.timezone': 'タイムゾーン',\r\n 'settings.peakWindows': 'ピーク時間ウィンドウ',\r\n 'settings.providerGuard': '公式ソース二次判定',\r\n 'settings.providerGuard.desc': 'ピーク時は DeepSeek 公式ソースのみ停止。ローカル/第三者 provider は通常どおり実行',\r\n 'settings.officialProviders': '公式 provider id を追加',\r\n 'settings.officialProviders.desc': '完全一致、最優先(カンマ区切り)',\r\n 'settings.officialBaseURLs': '公式エンドポイント host',\r\n 'settings.officialBaseURLs.desc': 'baseURL 正規化後の host(カンマ区切り)',\r\n 'settings.deferredMode': '遮断方式',\r\n 'settings.deferredMode.desc': 'エラーなしで保留、またはエラーにして延後キューへ',\r\n 'settings.deferredResume': 'ピーク後の自動再開',\r\n 'settings.deferredResume.desc': 'オフにすると延後したリクエスト/セッションは手動 /resume まで停止',\r\n 'settings.deferredResumeText': '再開メッセージ',\r\n 'settings.deferredResumeText.desc': 'error モードでピーク後に送るテキスト',\r\n 'settings.guardSubagents': 'サブエージェントも対象',\r\n 'settings.guardSubagents.desc': 'サブエージェントのリクエストも課金対象。既定で遮断',\r\n 'settings.officialHint': '判定順:明示 id リスト → baseURL エンドポイント → catalog 既定エンドポイント → 内蔵 id。誤判定は /session-guard/provider?provider=<id> の matchedBy を確認。',\r\n 'settings.unavailable': '設定利用不可:dsh-session-guard が profile に組み込まれているか確認してください。',\r\n 'status.normal': '通常実行中',\r\n 'status.paused_peak': 'ピーク一時停止中',\r\n 'status.peak_official': 'ピーク・公式のみ',\r\n 'status.peak_all': 'ピーク・全停止',\r\n}\r\n\r\n/** Korean dictionary (keys mirror zh). */\r\nexport const ko: Record<keyof typeof zh, string> = {\r\n 'badge.normal': '정상',\r\n 'badge.paused': '일시정지(피크)',\r\n 'badge_paused_peak': '피크 일시정지 중',\r\n 'settings.enabled': '피크 자동 일시정지',\r\n 'settings.enabled.desc': '피크 시간대에 실행 중인 세션을 자동 일시정지',\r\n 'settings.offPeakAutoResume': '오피크 자동 재개',\r\n 'settings.offPeakAutoResume.desc': '오피크 시간대에 일시정지된 세션을 자동 재개',\r\n 'settings.weekendMode': '주말 모드',\r\n 'settings.weekendMode.desc': '주말 감지 → 주말에는 자동 일시정지 안 함',\r\n 'settings.queueFallback': '폴백 잠금 대기 큐',\r\n 'settings.queueFallback.desc': '커스텀 세션 게이트 사용 불가 시 잠금 대기 큐로 폴백(fail-open)',\r\n 'settings.retryEnabled': '자동 재시도',\r\n 'settings.retryEnabled.desc': '일시적 실패 자동 재개(기본값 꺼짐, 보수적)',\r\n 'settings.timezone': '타임존',\r\n 'settings.peakWindows': '피크 시간대',\r\n 'settings.providerGuard': '공식 소스 2차 판정',\r\n 'settings.providerGuard.desc': '피크 시간에는 DeepSeek 공식 소스만 차단, 로컬/서드파티 provider는 정상 실행',\r\n 'settings.officialProviders': '공식 provider id 추가',\r\n 'settings.officialProviders.desc': '정확히 일치, 최우선(쉼표 구분)',\r\n 'settings.officialBaseURLs': '공식 엔드포인트 host',\r\n 'settings.officialBaseURLs.desc': 'baseURL 정규화 후 host(쉼표 구분)',\r\n 'settings.deferredMode': '차단 방식',\r\n 'settings.deferredMode.desc': '오류 없이 보류, 또는 오류로 연기 후 큐에 기록',\r\n 'settings.deferredResume': '피크 후 자동 재개',\r\n 'settings.deferredResume.desc': '끄면 보류된 요청/세션은 수동 /resume 전까지 멈춤',\r\n 'settings.deferredResumeText': '재개 메시지',\r\n 'settings.deferredResumeText.desc': 'error 모드에서 피크 후 보내는 텍스트',\r\n 'settings.guardSubagents': '서브에이전트 포함',\r\n 'settings.guardSubagents.desc': '서브에이전트 요청도 과금 대상, 기본 포함',\r\n 'settings.officialHint': '판정 순서: 명시 id 목록 → baseURL 엔드포인트 → catalog 기본 엔드포인트 → 내장 id. 오판정은 /session-guard/provider?provider=<id> 의 matchedBy 확인.',\r\n 'settings.unavailable': '설정 사용 불가: dsh-session-guard가 이 profile에 조립되었는지 확인하세요.',\r\n 'status.normal': '정상 실행 중',\r\n 'status.paused_peak': '피크 일시정지 중',\r\n 'status.peak_official': '피크·공식만',\r\n 'status.peak_all': '피크·전체 정지',\r\n}\r\n\r\n/** French dictionary (keys mirror zh). */\r\nexport const fr: Record<keyof typeof zh, string> = {\r\n 'badge.normal': 'Normal',\r\n 'badge.paused': 'En pause (pic)',\r\n 'badge_paused_peak': 'Pause pic en cours',\r\n 'settings.enabled': 'Pause auto en période de pic',\r\n 'settings.enabled.desc': 'Mettre automatiquement en pause les sessions actives pendant les heures de pic',\r\n 'settings.offPeakAutoResume': 'Reprise auto hors pic',\r\n 'settings.offPeakAutoResume.desc': 'Reprendre automatiquement les sessions en pause pendant les heures creuses',\r\n 'settings.weekendMode': 'Mode week-end',\r\n 'settings.weekendMode.desc': 'Détecter les week-ends → pas de pause auto le week-end',\r\n 'settings.queueFallback': 'File d\\u2019attente de secours',\r\n 'settings.queueFallback.desc': 'Repli sur la file d\\u2019attente verrouillée quand la passerelle personnalisée est indisponible (fail-open)',\r\n 'settings.retryEnabled': 'Nouvelle tentative auto',\r\n 'settings.retryEnabled.desc': 'Reprise auto après échec transitoire (désactivé par défaut, conservateur)',\r\n 'settings.timezone': 'Fuseau horaire',\r\n 'settings.peakWindows': 'Plages horaires de pic',\r\n 'settings.providerGuard': 'Garde source officielle',\r\n 'settings.providerGuard.desc': 'En période de pic, seules les sources officielles DeepSeek sont bloquées ; les fournisseurs locaux/tiers continuent',\r\n 'settings.officialProviders': 'IDs de fournisseur officiels supplémentaires',\r\n 'settings.officialProviders.desc': 'Correspondance exacte, priorité maximale (séparés par des virgules)',\r\n 'settings.officialBaseURLs': 'Hôtes des points de terminaison officiels',\r\n 'settings.officialBaseURLs.desc': 'Hôtes après normalisation de la baseURL (séparés par des virgules)',\r\n 'settings.deferredMode': 'Mode d\\u2019interception',\r\n 'settings.deferredMode.desc': 'Suspendre sans erreur, ou générer une erreur et mettre en file différée',\r\n 'settings.deferredResume': 'Reprise auto après le pic',\r\n 'settings.deferredResume.desc': 'Si désactivé, les requêtes/sessions différées restent en attente jusqu\\u2019à un /resume manuel',\r\n 'settings.deferredResumeText': 'Message de reprise',\r\n 'settings.deferredResumeText.desc': 'Texte envoyé lorsqu\\u2019une session en mode erreur reprend hors pic',\r\n 'settings.guardSubagents': 'Inclure les sous-agents',\r\n 'settings.guardSubagents.desc': 'Les requêtes des sous-agents sont aussi facturées ; gardées par défaut',\r\n 'settings.officialHint': 'Ordre de décision : liste d\\u2019ids explicites → point de terminaison baseURL → point de terminaison par défaut du catalogue → id intégré. Pour un verdict erroné, ouvrez /session-guard/provider?provider=<id> et consultez matchedBy.',\r\n 'settings.unavailable': 'Paramètres indisponibles : assurez-vous que dsh-session-guard est assemblé dans ce profil.',\r\n 'status.normal': 'Fonctionnement normal',\r\n 'status.paused_peak': 'Pause pic en cours',\r\n 'status.peak_official': 'Pic · officiel uniquement',\r\n 'status.peak_all': 'Pic · tout en pause',\r\n}\r\n\r\n/** German dictionary (keys mirror zh). */\r\nexport const de: Record<keyof typeof zh, string> = {\r\n 'badge.normal': 'Normal',\r\n 'badge.paused': 'Pausiert (Spitzenzeit)',\r\n 'badge_paused_peak': 'Spitzenzeit-Pause aktiv',\r\n 'settings.enabled': 'Auto-Pause zur Spitzenzeit',\r\n 'settings.enabled.desc': 'Laufende Sitzungen während der Spitzenzeiten automatisch pausieren',\r\n 'settings.offPeakAutoResume': 'Auto-Fortsetzung außerhalb der Spitzenzeit',\r\n 'settings.offPeakAutoResume.desc': 'Pausierte Sitzungen außerhalb der Spitzenzeiten automatisch fortsetzen',\r\n 'settings.weekendMode': 'Wochenendmodus',\r\n 'settings.weekendMode.desc': 'Wochenenden erkennen → keine Auto-Pause am Wochenende',\r\n 'settings.queueFallback': 'Fallback-Warteschlange',\r\n 'settings.queueFallback.desc': 'Auf Sperr-Warteschlange zurückgreifen, wenn eigenes Sitzungs-Gate nicht verfügbar ist (fail-open)',\r\n 'settings.retryEnabled': 'Automatischer Wiederholungsversuch',\r\n 'settings.retryEnabled.desc': 'Automatische Fortsetzung nach kurzzeitigem Fehler (standardmäßig aus, konservativ)',\r\n 'settings.timezone': 'Zeitzone',\r\n 'settings.peakWindows': 'Spitzenzeitfenster',\r\n 'settings.providerGuard': 'Offizielle-Quellen-Prüfung',\r\n 'settings.providerGuard.desc': 'Zur Spitzenzeit nur DeepSeek-offizielle Quellen blockieren; lokale/Dritt-Anbieter laufen weiter',\r\n 'settings.officialProviders': 'Zusätzliche offizielle Provider-IDs',\r\n 'settings.officialProviders.desc': 'Exakte Übereinstimmung, höchste Priorität (kommagetrennt)',\r\n 'settings.officialBaseURLs': 'Offizielle Endpunkt-Hosts',\r\n 'settings.officialBaseURLs.desc': 'Hosts nach baseURL-Normalisierung (kommagetrennt)',\r\n 'settings.deferredMode': 'Abfangmodus',\r\n 'settings.deferredMode.desc': 'Ohne Fehler anhalten oder Fehler erzeugen und in Warteschlange stellen',\r\n 'settings.deferredResume': 'Auto-Fortsetzung nach Spitzenzeit',\r\n 'settings.deferredResume.desc': 'Wenn aus, bleiben zurückgestellte Anfragen/Sitzungen bis zum manuellen /resume geparkt',\r\n 'settings.deferredResumeText': 'Fortsetzungsnachricht',\r\n 'settings.deferredResumeText.desc': 'Text, der gesendet wird, wenn eine Sitzung im Fehlermodus nach der Spitzenzeit fortgesetzt wird',\r\n 'settings.guardSubagents': 'Unteragenten einbeziehen',\r\n 'settings.guardSubagents.desc': 'Anfragen von Unteragenten werden ebenfalls abgerechnet; standardmäßig überwacht',\r\n 'settings.officialHint': 'Entscheidungsreihenfolge: explizite ID-Liste → baseURL-Endpunkt → Katalog-Standardendpunkt → eingebaute ID. Bei Fehlentscheidung /session-guard/provider?provider=<id> öffnen und matchedBy prüfen.',\r\n 'settings.unavailable': 'Einstellungen nicht verfügbar: Stellen Sie sicher, dass dsh-session-guard in diesem Profil eingebunden ist.',\r\n 'status.normal': 'Normaler Betrieb',\r\n 'status.paused_peak': 'Spitzenzeit-Pause aktiv',\r\n 'status.peak_official': 'Spitzenzeit · nur offizielle',\r\n 'status.peak_all': 'Spitzenzeit · alle pausiert',\r\n}\r\n\r\n/** Italian dictionary (keys mirror zh). */\r\nexport const it: Record<keyof typeof zh, string> = {\r\n 'badge.normal': 'Normale',\r\n 'badge.paused': 'In pausa (picco)',\r\n 'badge_paused_peak': 'Pausa di picco attiva',\r\n 'settings.enabled': 'Pausa automatica durante il picco',\r\n 'settings.enabled.desc': 'Metti automaticamente in pausa le sessioni attive durante le ore di picco',\r\n 'settings.offPeakAutoResume': 'Ripresa automatica fuori picco',\r\n 'settings.offPeakAutoResume.desc': 'Riprendi automaticamente le sessioni in pausa durante le ore fuori picco',\r\n 'settings.weekendMode': 'Modalità fine settimana',\r\n 'settings.weekendMode.desc': 'Rileva i fine settimana → nessuna pausa automatica nel weekend',\r\n 'settings.queueFallback': 'Coda di riserva con blocco',\r\n 'settings.queueFallback.desc': 'Ripiega sulla coda di attesa bloccata quando il gate di sessione personalizzato non è disponibile (fail-open)',\r\n 'settings.retryEnabled': 'Nuovo tentativo automatico',\r\n 'settings.retryEnabled.desc': 'Ripresa automatica dopo errore transitorio (disattivato per impostazione predefinita, conservativo)',\r\n 'settings.timezone': 'Fuso orario',\r\n 'settings.peakWindows': 'Finestre temporali di picco',\r\n 'settings.providerGuard': 'Guardia sorgente ufficiale',\r\n 'settings.providerGuard.desc': 'Durante il picco blocca solo le sorgenti ufficiali DeepSeek; i provider locali/terzi continuano a funzionare',\r\n 'settings.officialProviders': 'ID provider ufficiali aggiuntivi',\r\n 'settings.officialProviders.desc': 'Corrispondenza esatta, priorità massima (separati da virgola)',\r\n 'settings.officialBaseURLs': 'Host degli endpoint ufficiali',\r\n 'settings.officialBaseURLs.desc': 'Host dopo la normalizzazione della baseURL (separati da virgola)',\r\n 'settings.deferredMode': 'Modalità di intercettazione',\r\n 'settings.deferredMode.desc': 'Sospendi senza errore, oppure genera errore e accoda come differito',\r\n 'settings.deferredResume': 'Ripresa automatica dopo il picco',\r\n 'settings.deferredResume.desc': 'Se disattivato, le richieste/sessioni differite restano in attesa fino a un /resume manuale',\r\n 'settings.deferredResumeText': 'Messaggio di ripresa',\r\n 'settings.deferredResumeText.desc': 'Testo inviato quando una sessione in modalità errore riprende fuori picco',\r\n 'settings.guardSubagents': 'Includi sottoagenti',\r\n 'settings.guardSubagents.desc': 'Anche le richieste dei sottoagenti sono fatturate; protette per impostazione predefinita',\r\n 'settings.officialHint': 'Ordine di decisione: elenco id espliciti → endpoint baseURL → endpoint predefinito del catalogo → id integrato. Per un verdetto errato apri /session-guard/provider?provider=<id> e controlla matchedBy.',\r\n 'settings.unavailable': 'Impostazioni non disponibili: assicurati che dsh-session-guard sia integrato in questo profilo.',\r\n 'status.normal': 'Funzionamento normale',\r\n 'status.paused_peak': 'Pausa di picco attiva',\r\n 'status.peak_official': 'Picco · solo ufficiale',\r\n 'status.peak_all': 'Picco · tutto in pausa',\r\n}\r\n\r\n/** Russian dictionary (keys mirror zh). */\r\nexport const ru: Record<keyof typeof zh, string> = {\r\n 'badge.normal': 'Норма',\r\n 'badge.paused': 'Приостановлено (пик)',\r\n 'badge_paused_peak': 'Пиковая пауза активна',\r\n 'settings.enabled': 'Автопауза в час пик',\r\n 'settings.enabled.desc': 'Автоматически приостанавливать активные сессии в часы пиковой нагрузки',\r\n 'settings.offPeakAutoResume': 'Автопродолжение вне пика',\r\n 'settings.offPeakAutoResume.desc': 'Автоматически возобновлять приостановленные сессии в непиковые часы',\r\n 'settings.weekendMode': 'Режим выходных',\r\n 'settings.weekendMode.desc': 'Определять выходные → не приостанавливать автоматически в выходные',\r\n 'settings.queueFallback': 'Резервная очередь блокировки',\r\n 'settings.queueFallback.desc': 'Откат к очереди блокировки, когда собственный гейт сессий недоступен (fail-open)',\r\n 'settings.retryEnabled': 'Автоповтор',\r\n 'settings.retryEnabled.desc': 'Автоматическое продолжение после временного сбоя (по умолчанию выключено, консервативно)',\r\n 'settings.timezone': 'Часовой пояс',\r\n 'settings.peakWindows': 'Пиковые временные окна',\r\n 'settings.providerGuard': 'Проверка официального источника',\r\n 'settings.providerGuard.desc': 'В час пик блокируются только официальные источники DeepSeek; локальные/сторонние провайдеры работают',\r\n 'settings.officialProviders': 'Дополнительные ID официальных провайдеров',\r\n 'settings.officialProviders.desc': 'Точное совпадение, наивысший приоритет (через запятую)',\r\n 'settings.officialBaseURLs': 'Хосты официальных эндпоинтов',\r\n 'settings.officialBaseURLs.desc': 'Хосты после нормализации baseURL (через запятую)',\r\n 'settings.deferredMode': 'Режим перехвата',\r\n 'settings.deferredMode.desc': 'Приостановить без ошибки, или выдать ошибку и поставить в отложенную очередь',\r\n 'settings.deferredResume': 'Автопродолжение после пика',\r\n 'settings.deferredResume.desc': 'Если выключено, отложенные запросы/сессии ожидают ручного /resume',\r\n 'settings.deferredResumeText': 'Сообщение возобновления',\r\n 'settings.deferredResumeText.desc': 'Текст, отправляемый при возобновлении сессии в режиме ошибки после пика',\r\n 'settings.guardSubagents': 'Включить субагентов',\r\n 'settings.guardSubagents.desc': 'Запросы субагентов также тарифицируются; по умолчанию защищаются',\r\n 'settings.officialHint': 'Порядок принятия решения: явный список id → эндпоинт baseURL → эндпоинт по умолчанию из каталога → встроенный id. При ошибочном вердикте откройте /session-guard/provider?provider=<id> и проверьте matchedBy.',\r\n 'settings.unavailable': 'Настройки недоступны: убедитесь, что dsh-session-guard подключён к этому профилю.',\r\n 'status.normal': 'Штатная работа',\r\n 'status.paused_peak': 'Пиковая пауза активна',\r\n 'status.peak_official': 'Пик · только официальные',\r\n 'status.peak_all': 'Пик · все приостановлены',\r\n}\r\n\r\n/** Spanish dictionary (keys mirror zh). */\r\nexport const es: Record<keyof typeof zh, string> = {\r\n 'badge.normal': 'Normal',\r\n 'badge.paused': 'Pausado (pico)',\r\n 'badge_paused_peak': 'Pausa por pico activa',\r\n 'settings.enabled': 'Pausa automática en hora pico',\r\n 'settings.enabled.desc': 'Pausar automáticamente las sesiones activas durante las horas pico',\r\n 'settings.offPeakAutoResume': 'Reanudación automática fuera de pico',\r\n 'settings.offPeakAutoResume.desc': 'Reanudar automáticamente las sesiones pausadas durante las horas valle',\r\n 'settings.weekendMode': 'Modo fin de semana',\r\n 'settings.weekendMode.desc': 'Detectar fines de semana → sin pausa automática el fin de semana',\r\n 'settings.queueFallback': 'Cola de bloqueo de reserva',\r\n 'settings.queueFallback.desc': 'Alternativa a la cola de bloqueo cuando la puerta de sesión personalizada no está disponible (fail-open)',\r\n 'settings.retryEnabled': 'Reintento automático',\r\n 'settings.retryEnabled.desc': 'Reanudación automática tras fallo transitorio (desactivado por defecto, conservador)',\r\n 'settings.timezone': 'Zona horaria',\r\n 'settings.peakWindows': 'Ventanas horarias de pico',\r\n 'settings.providerGuard': 'Protección de fuente oficial',\r\n 'settings.providerGuard.desc': 'En hora pico solo se bloquean las fuentes oficiales de DeepSeek; los proveedores locales/terceros siguen funcionando',\r\n 'settings.officialProviders': 'IDs de proveedor oficiales adicionales',\r\n 'settings.officialProviders.desc': 'Coincidencia exacta, prioridad máxima (separados por comas)',\r\n 'settings.officialBaseURLs': 'Hosts de endpoints oficiales',\r\n 'settings.officialBaseURLs.desc': 'Hosts tras normalización de la baseURL (separados por comas)',\r\n 'settings.deferredMode': 'Modo de intercepción',\r\n 'settings.deferredMode.desc': 'Suspender sin error, o generar error y encolar como diferido',\r\n 'settings.deferredResume': 'Reanudación automática tras el pico',\r\n 'settings.deferredResume.desc': 'Si se desactiva, las solicitudes/sesiones diferidas quedan en espera hasta un /resume manual',\r\n 'settings.deferredResumeText': 'Mensaje de reanudación',\r\n 'settings.deferredResumeText.desc': 'Texto enviado cuando una sesión en modo error se reanuda fuera de pico',\r\n 'settings.guardSubagents': 'Incluir subagentes',\r\n 'settings.guardSubagents.desc': 'Las solicitudes de subagentes también se facturan; protegidas por defecto',\r\n 'settings.officialHint': 'Orden de decisión: lista explícita de ids → endpoint de baseURL → endpoint predeterminado del catálogo → id integrado. Para un veredicto erróneo abra /session-guard/provider?provider=<id> y consulte matchedBy.',\r\n 'settings.unavailable': 'Configuración no disponible: asegúrese de que dsh-session-guard esté integrado en este perfil.',\r\n 'status.normal': 'Funcionamiento normal',\r\n 'status.paused_peak': 'Pausa por pico activa',\r\n 'status.peak_official': 'Pico · solo oficial',\r\n 'status.peak_all': 'Pico · todo pausado',\r\n}\r\n\r\n/** Dictionary key union. */\r\nexport type SessionGuardKey = keyof typeof zh\r\n\r\n/** Combined dictionary map — all 9 languages, for one-call registration. */\r\nexport const dictionaries: Record<string, Record<string, string>> = { zh, en, ja, ko, fr, de, it, ru, es }\r\n","/**\r\n * dsh-session-guard — 状态徽标文案(纯函数,零依赖,可单测)。\r\n *\r\n * 分离出来的原因:徽标语义(高峰期「只拦官方」vs「全部暂停」)需要单测,\r\n * 而组件文件是 TSX(含 React 运行时)。这里只有字符串逻辑。\r\n */\r\n\r\n/** /session-guard/status 返回的全局阶段(组件与测试共用)。 */\r\nexport interface Status {\r\n phase: 'peak' | 'off-peak' | 'weekend'\r\n enabled: boolean\r\n weekendMode: boolean\r\n /** 官方源二维判定是否开启(开启时高峰期只拦官方源)。 */\r\n providerGuard?: boolean\r\n /** 当前被挂起的请求数(hold 模式)。 */\r\n held?: number\r\n /** error 模式记下的延后会话数。 */\r\n deferred?: number\r\n /** 当前被 step 门挂起的会话数(v0.2.0)。 */\r\n stepHeld?: number\r\n timezone: string\r\n}\r\n\r\n/** 阶段文案。 */\r\nexport const PHASE_LABELS = {\r\n peak: '高峰',\r\n 'off-peak': '谷时',\r\n weekend: '周末',\r\n} as const\r\n\r\n/** 高峰期的徽标文案:二维判定开启时区分「只拦官方」与「全部暂停」。 */\r\nexport function peakLabel(status: Pick<Status, 'phase' | 'providerGuard'>): string {\r\n if (status.phase !== 'peak') return PHASE_LABELS[status.phase]\r\n return status.providerGuard === true ? '高峰·拦官方' : '高峰·全部暂停'\r\n}\r\n\r\n/** 悬浮说明:把判定口径与当前挂起/延后数量写清楚。 */\r\nexport function badgeTitle(status: Status): string {\r\n const base = `${PHASE_LABELS[status.phase]} · ${status.timezone}${status.weekendMode ? ' · 周末模式' : ''}`\r\n if (status.phase !== 'peak') return base\r\n const mode = status.providerGuard === true ? '仅拦截 DeepSeek 官方源' : '全部会话暂停(未启用二维判定)'\r\n const held = status.held ?? 0\r\n const deferred = status.deferred ?? 0\r\n const stepHeld = status.stepHeld ?? 0\r\n const extra = held > 0 || deferred > 0 || stepHeld > 0\r\n ? ` · 挂起 ${held} · 延后 ${deferred} · step 挂起 ${stepHeld}`\r\n : ''\r\n return `${base} · ${mode}${extra}`\r\n}\r\n","/**\n * dsh-session-guard — 客户端样式(与 composer 右侧 input-traffic 冻结按钮同一视觉语言)。\n *\n * 为什么注入 `<style>` 而不是 CSS Modules:本插件的 tsdown 配置没有 CSS Modules 管线\n * (input-traffic 有),而 settings-card 已经用 `<style data-plugin-css>` 的既有约定。\n * 这里只做一件事:把「暂停会话 / 继续会话」按钮与状态徽标对齐到同一行的其它控件\n * (高度 24px、圆角 6px、12px 字号、同样的 border / hover / pressed 令牌)。\n */\n\n/** 与 `dsh-input-traffic/src/client/freeze-button.module.css` 对齐的控件外观。 */\nexport const CLIENT_CSS = `\n.sg-pause{display:inline-flex;align-items:center;gap:4px;height:24px;padding:0 8px;border:1px solid var(--dsw-alias-border-l3,rgba(0,0,0,.12));border-radius:6px;background:transparent;color:var(--dsw-alias-label-secondary,#6b7280);font-size:12px;line-height:1;cursor:pointer;white-space:nowrap;flex:none}\n.sg-pause:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}\n.sg-pause:disabled{opacity:.55;cursor:default}\n.sg-pause[aria-pressed='true']{border-color:var(--dsw-alias-state-warning-primary,#d97706);color:var(--dsw-alias-state-warning-primary,#d97706);background:color-mix(in srgb,var(--dsw-alias-state-warning-primary,#d97706) 8%,transparent)}\n.sg-status{display:inline-flex;align-items:center;height:24px;padding:0 8px;border:1px solid var(--dsw-alias-border-l3,rgba(0,0,0,.12));border-radius:6px;font-size:12px;line-height:1;color:var(--dsw-alias-label-secondary,#6b7280);white-space:nowrap;flex:none}\n.sg-status.sg-peak{border-color:var(--dsw-alias-state-warning-primary,#d97706);color:var(--dsw-alias-state-warning-primary,#d97706)}\n.sg-status.sg-weekend{border-color:var(--dsw-alias-state-success-primary,#30a46c);color:var(--dsw-alias-state-success-primary,#30a46c)}\n`\n\n/** 注入一次(幂等;无 document 时静默跳过)。 */\nexport function injectClientCss(): void {\n if (typeof document === 'undefined') return\n if (document.querySelector('style[data-plugin-css=\"session-guard-client\"]') !== null) return\n const tag = document.createElement('style')\n tag.dataset.plugin = 'dsh-session-guard'\n tag.dataset.pluginCss = 'session-guard-client'\n tag.textContent = CLIENT_CSS\n document.head.appendChild(tag)\n}\n","/**\r\n * dsh-session-guard — 状态徽标(纯展示,fail-open)。\r\n *\r\n * 轮询 host 的 /session-guard/status(全局当前阶段),显示 高峰/谷时/周末;\r\n * 高峰期按二维判定区分「只拦官方」与「全部暂停」(文案见 badge-text.ts)。\r\n * 仅展示,不做任何队列/会话动作;冻结按钮由 input-traffic 经桥接管(D6/D8)。\r\n */\r\nimport { useEffect, useState } from 'react'\r\nimport { badgeTitle, peakLabel, type Status } from './badge-text'\r\nimport { injectClientCss } from './styles'\r\n\r\n/** slot 运行时注入的会话级 props(sessionId 由 dsh 的 SessionStandardProps 提供)。 */\r\nexport interface StatusBadgeProps {\r\n sessionId?: string\r\n}\r\n\r\nconst POLL_MS = 15_000\r\n\r\n/** 状态徽标:轮询全局阶段,显示 高峰/谷时/周末(enabled 关闭或请求失败时静默隐藏)。 */\r\nexport function StatusBadge({ sessionId }: StatusBadgeProps) {\r\n const [status, setStatus] = useState<Status | null>(null)\r\n\r\n injectClientCss()\r\n\r\n useEffect(() => {\r\n if (!sessionId) return\r\n let cancelled = false\r\n const poll = async () => {\r\n try {\r\n const res = await fetch('/session-guard/status')\r\n const body = await res.json().catch(() => null)\r\n if (!cancelled && body?.ok && body.status) setStatus(body.status)\r\n } catch {\r\n // fail-open:路由/网络不可达 → 静默,徽标隐藏。\r\n }\r\n }\r\n void poll()\r\n const timer = setInterval(poll, POLL_MS)\r\n return () => {\r\n cancelled = true\r\n clearInterval(timer)\r\n }\r\n }, [sessionId])\r\n\r\n if (!status || !status.enabled) return null\r\n\r\n const cls = status.phase === 'peak' ? 'sg-peak' : status.phase === 'weekend' ? 'sg-weekend' : 'sg-off'\r\n return (\r\n <span\r\n className={`sg-status ${cls}`}\r\n title={badgeTitle(status)}\r\n data-sg-phase={status.phase}\r\n data-sg-provider-guard={status.providerGuard === true ? 'on' : 'off'}\r\n data-sg-step-held={String(status.stepHeld ?? 0)}\r\n >\r\n {peakLabel(status)}\r\n </span>\r\n )\r\n}\r\n","/**\n * dsh-session-guard — 暂停/继续按钮文案与状态投影(纯函数,零依赖,可单测)。\n *\n * 交互(v0.2.0 修订):\n * - 未暂停 → 「暂停会话」(**可点**:点击 = 在下一次 step 边界手动暂停该会话);\n * - 已暂停(step 门已拉 / 已请求但未到边界)→ 「继续会话」(点击 = 放行并本峰不再拦)。\n * 按钮不置灰:step 暂停虽然会自动发生,但按钮同时是**手动暂停**入口。\n */\n\n/** 按钮状态。 */\nexport interface PauseButtonState {\n /** 是否处于暂停态(step 门已挂起,或已请求暂停但还没到边界) */\n paused: boolean\n /** 挂起起始时间戳(毫秒);未知为 null */\n heldSince?: number | null\n /** 暂停是否来自用户手动请求(而非高峰自动拉门) */\n manual?: boolean\n}\n\n/** 按钮文案。 */\nexport function pauseButtonLabel(state: PauseButtonState): string {\n return state.paused === true ? '继续会话' : '暂停会话'\n}\n\n/** 悬浮说明:写清当前状态与点击后的语义。 */\nexport function pauseButtonTitle(state: PauseButtonState): string {\n if (state.paused !== true) {\n return '暂停会话:在下一次 step 的模型请求前暂停(高峰 + 官方源时会自动暂停)'\n }\n const since = typeof state.heldSince === 'number' && Number.isFinite(state.heldSince) ? new Date(state.heldSince) : null\n const at = since === null ? null : `${String(since.getHours()).padStart(2, '0')}:${String(since.getMinutes()).padStart(2, '0')}`\n const why = state.manual === true ? '手动暂停' : '高峰自动暂停'\n const base = at === null ? `已暂停(${why})` : `已暂停(${why},自 ${at})`\n return `${base} · 点击继续:放行当前 step,且本高峰内不再拦该会话`\n}\n\n/** 把 `/session-guard/state` 的响应体投影为按钮状态(形状异常 → 未暂停,fail-open)。 */\nexport function readPauseState(body: unknown): PauseButtonState {\n const b = (body ?? {}) as {\n ok?: unknown\n paused?: { step?: unknown; manual?: unknown }\n stepGate?: { since?: unknown; manual?: unknown }\n state?: { pausedStep?: unknown; stepHeldSince?: unknown; stepManual?: unknown }\n }\n if (b.ok !== true) return { paused: false, heldSince: null, manual: false }\n const manual = b.paused?.manual === true || b.stepGate?.manual === true || b.state?.stepManual === true\n const paused = b.paused?.step === true || b.state?.pausedStep === true || manual\n const raw = b.stepGate?.since ?? b.state?.stepHeldSince ?? null\n const heldSince = typeof raw === 'number' && Number.isFinite(raw) ? raw : null\n return { paused, heldSince, manual }\n}\n\n/** 把 SSE `/session-guard/events` 的 `state` 快照投影为按钮状态。 */\nexport function readStepSnapshot(snapshot: unknown): PauseButtonState {\n const s = (snapshot ?? {}) as { held?: unknown; since?: unknown; manual?: unknown }\n const manual = s.manual === true\n const paused = s.held === true || manual\n const heldSince = typeof s.since === 'number' && Number.isFinite(s.since) ? s.since : null\n return { paused, heldSince, manual }\n}\n","/**\n * dsh-session-guard — 「暂停会话 / 继续会话」按钮(`conversation.input.right`,order 20)。\n *\n * 交互(v0.2.0 修订):\n * - 未暂停 → 「暂停会话」,**可点**:点击 POST `{action:'stepPause'}`,在**下一次 step 边界**暂停\n * (不打断当前 step;step 1 也拦,不受峰谷 / provider 限制);\n * - 已暂停(高峰自动拉门 **或** 手动请求已登记)→ 「继续会话」,点击 POST `{action:'stepResume'}`;\n * - 状态更新双通道:① SSE `/session-guard/events?session=<id>` 即时推送;② 10s 轮询兜底\n * (SSE 不可用 / 断线时仍能收敛)。全部 fail-open,绝不抛错。\n *\n * 与 input-traffic 的「❄ 冻结追加 / 恢复追加」并列(order 30 在其右侧),互不取代:\n * 本按钮控 step 门,冻结按钮控回合级冻结 + 队列摘除。\n */\nimport { useEffect, useState } from 'react'\nimport {\n pauseButtonLabel,\n pauseButtonTitle,\n readPauseState,\n readStepSnapshot,\n type PauseButtonState,\n} from './pause-button-text'\nimport { injectClientCss } from './styles'\n\n/** slot 运行时注入的会话级 props。 */\nexport interface PauseButtonProps {\n sessionId?: string\n}\n\n/** SSE 不可用时的兜底轮询间隔(正常路径由事件驱动,几乎不触发)。 */\nconst POLL_MS = 10_000\n\nconst IDLE: PauseButtonState = { paused: false, heldSince: null, manual: false }\n\n/** 暂停 / 继续会话按钮。 */\nexport function PauseButton({ sessionId }: PauseButtonProps) {\n const [state, setState] = useState<PauseButtonState>(IDLE)\n const [busy, setBusy] = useState(false)\n\n injectClientCss()\n\n useEffect(() => {\n if (sessionId === undefined || sessionId === '') return\n let cancelled = false\n\n const poll = async (): Promise<void> => {\n try {\n const res = await fetch(`/session-guard/state?session=${encodeURIComponent(sessionId)}`)\n const body = await res.json().catch(() => null)\n if (cancelled) return\n setState(readPauseState(body))\n } catch {\n // fail-open:路由不存在 / 网络失败 → 保持上一次状态。\n }\n }\n void poll()\n const timer = setInterval(() => {\n void poll()\n }, POLL_MS)\n\n let source: EventSource | undefined\n try {\n source = new EventSource(`/session-guard/events?session=${encodeURIComponent(sessionId)}`)\n source.onmessage = (ev: MessageEvent<string>) => {\n try {\n const msg = JSON.parse(ev.data) as { type?: string; state?: unknown }\n if (cancelled || msg?.type !== 'step') return\n setState(readStepSnapshot(msg.state))\n } catch {\n /* 非法负载:忽略,等下一次推送或轮询 */\n }\n }\n // onerror:EventSource 会自行重连;轮询同时兜底。\n source.onerror = () => undefined\n } catch {\n // 浏览器不支持 EventSource → 只靠轮询。\n }\n\n return () => {\n cancelled = true\n clearInterval(timer)\n try {\n source?.close()\n } catch {\n /* ignore */\n }\n }\n }, [sessionId])\n\n if (sessionId === undefined || sessionId === '') return null\n\n const paused = state.paused === true\n const onClick = async (): Promise<void> => {\n if (busy) return\n setBusy(true)\n try {\n const action = paused ? 'stepResume' : 'stepPause'\n const res = await fetch('/session-guard/rpc', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ sessionId, action }),\n })\n const body = await res.json().catch(() => null)\n if (body?.ok === true) {\n // 立即乐观更新;SSE / 轮询随后校正。\n setState(paused ? IDLE : { paused: true, heldSince: null, manual: true })\n }\n } catch {\n // fail-open:下一轮轮询会纠正显示。\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <button\n type=\"button\"\n className=\"sg-pause\"\n disabled={busy}\n aria-pressed={paused || undefined}\n title={pauseButtonTitle(state)}\n data-sg-step-paused={paused ? 'on' : 'off'}\n onClick={() => {\n void onClick()\n }}\n >\n {pauseButtonLabel(state)}\n </button>\n )\n}\n","/**\n * dsh-session-guard — 插件配置卡片(dsh-family.tab 共用设置节,抽屉默认展开)。\n *\n * 对齐 dsh-thinking-levels / dsh-tidychat 的卡片语法:一个可展开的 `<li>`,\n * header 按钮(插件名 + 描述 + chevron)切换字段体;开关为 pill switch\n * (track + thumb),不是复选框对勾。\n *\n * 经 `configForms.get('session-guard')` 绑定本插件 entry 的配置\n * (0.1.7 configForms 缝);每次变更立即经 scope 提交(无 staged form)。\n * 仅依赖 react;CSS 经 `<style data-plugin-css>` 注入一次,控件为原生 HTML,\n * 客户端 bundle 无 value-import @deepseek-ai/* 平台包(类型导入被构建擦除)。\n */\nimport { useEffect, useState, useSyncExternalStore } from 'react'\nimport type { JSX } from 'react'\nimport type { SettingsScope } from './scope-face.ts'\n\n/** 命名空间值形状(与 host 的 DEFAULT_SETTINGS 对应)。 */\nexport interface SessionGuardConfig {\n enabled: boolean\n offPeakAutoResume: boolean\n weekendMode: boolean\n queueFallback: boolean\n retryEnabled: boolean\n timezone: string\n pauseMode: 'safe' | 'force'\n pauseReason: 'wait' | 'stop'\n // ── step 级门控(v0.2.0)──\n stepLevelPause: boolean\n stepGateTimeoutMs: number\n // ── 官方 provider 二维判定(高峰 × 目标源)──\n providerGuard: boolean\n officialProviders: string[]\n officialBaseURLs: string[]\n deferredResume: boolean\n deferredResumeText: string\n deferredMode: 'hold' | 'error'\n deferredMaxHoldMs: number\n guardSubagents: boolean\n}\n\n/** 注入给卡片的面:绑定到 session-guard 命名空间的 settings scope。 */\nexport interface SettingsCardInjected {\n scope: SettingsScope<SessionGuardConfig>\n}\n\nexport type SettingsCardProps = SettingsCardInjected\n\n/** 卡片样式,注入一次(保持 bundle CSS-free)。 */\nconst CARD_CSS = `\n.sgCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}\n.sgCard:hover{border-color:var(--dsw-alias-label-dimmed)}\n.sgCard-open{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}\n.sgCardHeader{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:transparent;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}\n.sgCardHeadtext{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}\n.sgCardName{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}\n.sgCardDesc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}\n.sgCardChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}\n.sgCardChevron-open{transform:rotate(180deg)}\n.sgCardBody{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 12px}\n.sgRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}\n.sgRow:last-child{border-bottom:0}\n.sgRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}\n.sgRowText-wide{padding-right:0}\n.sgTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}\n.sgDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}\n.sgSwitch{position:relative;width:40px;height:22px;flex:none}\n.sgSwitch>input{position:absolute;inset:0;width:100%;height:100%;opacity:0;margin:0;cursor:pointer}\n.sgSwitch>input:disabled{cursor:not-allowed}\n.sgSwitchTrack{position:absolute;inset:0;border-radius:22px;background:var(--dsw-alias-interactive-bg-hover);transition:background .16s}\n.sgSwitch>input:checked+.sgSwitchTrack{background:var(--dsw-alias-button-primary-fill)}\n.sgSwitchThumb{position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:transform .16s}\n.sgSwitch>input:checked~.sgSwitchThumb{transform:translateX(18px)}\n.sgInput{appearance:none;min-width:0;width:100%;font:inherit;font-size:13px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:7px 10px;margin-top:8px}\n.sgInput:disabled{opacity:.6;cursor:not-allowed}\n.sgSelect{appearance:none;font:inherit;font-size:13px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:7px 10px;min-width:160px;flex:none}\n.sgSelect:disabled{opacity:.6;cursor:not-allowed}\n.sgHint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:6px 0 0}\n.sgReadonly{color:var(--dsw-alias-label-tertiary);font-size:12px;margin:8px 0 0}\n`\n\n/** 注入一次卡片样式。 */\nfunction injectCss(): void {\n if (typeof document !== 'undefined' && document.querySelector('style[data-plugin-css=\"session-guard-card\"]') === null) {\n const tag = document.createElement('style')\n tag.dataset.plugin = 'dsh-session-guard'\n tag.dataset.pluginCss = 'session-guard-card'\n tag.textContent = CARD_CSS\n document.head.appendChild(tag)\n }\n}\n\n/** 一行 pill switch(滑块开关,绑定 scope)。 */\nfunction SwitchRow(props: {\n label: string\n description?: string\n checked: boolean\n disabled: boolean\n onChange: (_next: boolean) => void\n}): JSX.Element {\n const { label, description, checked, disabled, onChange } = props\n return (\n <div className=\"sgRow\">\n <div className=\"sgRowText\">\n <div className=\"sgTitle\">{label}</div>\n {description !== undefined && <div className=\"sgDesc\">{description}</div>}\n </div>\n <label className=\"sgSwitch\">\n <input\n type=\"checkbox\"\n checked={checked}\n disabled={disabled}\n onChange={(e) => onChange(e.currentTarget.checked)}\n />\n <span className=\"sgSwitchTrack\" />\n <span className=\"sgSwitchThumb\" />\n </label>\n </div>\n )\n}\n\n/** 一行文本输入(失焦提交;外部值变化时同步草稿)。 */\nfunction TextRow(props: {\n label: string\n description?: string\n value: string\n placeholder?: string\n disabled: boolean\n onCommit: (_next: string) => void\n}): JSX.Element {\n const { label, description, value, placeholder, disabled, onCommit } = props\n const [draft, setDraft] = useState(value)\n useEffect(() => {\n setDraft(value)\n }, [value])\n return (\n <div className=\"sgRow\">\n <div className=\"sgRowText sgRowText-wide\">\n <div className=\"sgTitle\">{label}</div>\n {description !== undefined && <div className=\"sgDesc\">{description}</div>}\n <input\n className=\"sgInput\"\n type=\"text\"\n value={draft}\n placeholder={placeholder}\n disabled={disabled}\n onChange={(e) => setDraft(e.currentTarget.value)}\n onBlur={() => onCommit(draft)}\n />\n </div>\n </div>\n )\n}\n\n/** 一行「逗号/换行分隔」的字符串列表(失焦提交为数组)。 */\nfunction ListRow(props: {\n label: string\n description?: string\n values: string[]\n placeholder?: string\n disabled: boolean\n onCommit: (_next: string[]) => void\n}): JSX.Element {\n const { label, description, values, placeholder, disabled, onCommit } = props\n const joined = values.join(', ')\n const [draft, setDraft] = useState(joined)\n useEffect(() => {\n setDraft(joined)\n }, [joined])\n return (\n <div className=\"sgRow\">\n <div className=\"sgRowText sgRowText-wide\">\n <div className=\"sgTitle\">{label}</div>\n {description !== undefined && <div className=\"sgDesc\">{description}</div>}\n <input\n className=\"sgInput\"\n type=\"text\"\n value={draft}\n placeholder={placeholder}\n disabled={disabled}\n onChange={(e) => setDraft(e.currentTarget.value)}\n onBlur={() => {\n const next = draft\n .split(/[,\\n]/)\n .map((s) => s.trim())\n .filter((s) => s !== '')\n onCommit(next)\n }}\n />\n </div>\n </div>\n )\n}\n\n/** 一行下拉选择。 */\nfunction SelectRow<T extends string>(props: {\n label: string\n description?: string\n value: T\n options: readonly { value: T; label: string }[]\n disabled: boolean\n onChange: (_next: T) => void\n}): JSX.Element {\n const { label, description, value, options, disabled, onChange } = props\n return (\n <div className=\"sgRow\">\n <div className=\"sgRowText\">\n <div className=\"sgTitle\">{label}</div>\n {description !== undefined && <div className=\"sgDesc\">{description}</div>}\n </div>\n <select\n className=\"sgSelect\"\n value={value}\n disabled={disabled}\n onChange={(e) => onChange(e.currentTarget.value as T)}\n >\n {options.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n </div>\n )\n}\n\n/** 插件配置卡片主体:可展开的 <li> + header 按钮 + pill switch 字段体。 */\nexport function SessionGuardCard({ scope }: SettingsCardProps): JSX.Element {\n const snapshot = useSyncExternalStore(\n (listener) => scope.subscribe(listener),\n () => scope.getSnapshot(),\n )\n const unavailable = snapshot.status === 'unavailable'\n const readonly = unavailable || !snapshot.writable\n const value = (snapshot.value ?? {}) as Partial<SessionGuardConfig>\n const [open, setOpen] = useState(true)\n\n injectCss()\n\n const toggle = (field: keyof SessionGuardConfig, next: boolean) => { void scope.set(field, next) }\n return (\n <li className={'sgCard' + (open ? ' sgCard-open' : '')}>\n <button\n type=\"button\"\n className=\"sgCardHeader\"\n aria-expanded={open}\n onClick={() => setOpen(!open)}\n >\n <span className=\"sgCardHeadtext\">\n <span className=\"sgCardName\">会话守护门禁</span>\n <span className=\"sgCardDesc\">高峰自动暂停运行会话,周末模式无视峰谷畅快跑</span>\n </span>\n <svg\n className={'sgCardChevron' + (open ? ' sgCardChevron-open' : '')}\n viewBox=\"0 0 14 14\"\n width={14}\n height={14}\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path d=\"M3.5 5.5L7 9l3.5-3.5\" stroke=\"currentColor\" strokeWidth={1.5} strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n {open && (\n <div className=\"sgCardBody\">\n {unavailable ? (\n <p style={{ margin: '0', padding: '12px 0', fontSize: '13px', color: 'var(--dsw-alias-label-tertiary)' }}>\n 设置命名空间不可用:请确认 dsh-session-guard 已装配进此 profile。\n </p>\n ) : (\n <>\n <SwitchRow\n label=\"高峰自动暂停冻结会话\"\n description=\"高峰时段自动暂停运行会话\"\n checked={value.enabled ?? true}\n disabled={readonly}\n onChange={(next) => toggle('enabled', next)}\n />\n <SwitchRow\n label=\"step 级门控\"\n description=\"高峰在下一个 step 的模型请求前拉门(省 token 更彻底);关闭则回退为回合级暂停\"\n checked={value.stepLevelPause ?? true}\n disabled={readonly}\n onChange={(next) => toggle('stepLevelPause', next)}\n />\n <TextRow\n label=\"step 门控超时(毫秒)\"\n description=\"到期释放 step 门并升级为回合级暂停(防死锁);0 或非法值用默认 300000\"\n value={String(value.stepGateTimeoutMs ?? 300000)}\n placeholder=\"300000\"\n disabled={readonly}\n onCommit={(next) => {\n const n = Number(String(next).trim())\n void scope.set('stepGateTimeoutMs', Number.isFinite(n) && n > 0 ? n : 300000)\n }}\n />\n <SwitchRow\n label=\"官方源二维判定\"\n description=\"高峰期只拦 DeepSeek 官方源;本地/第三方 provider 照常跑\"\n checked={value.providerGuard ?? true}\n disabled={readonly}\n onChange={(next) => toggle('providerGuard', next)}\n />\n <ListRow\n label=\"追加官方 provider id\"\n description=\"精确匹配,优先级最高(逗号分隔)\"\n values={value.officialProviders ?? []}\n placeholder=\"deepseek-official\"\n disabled={readonly}\n onCommit={(next) => { void scope.set('officialProviders', next) }}\n />\n <ListRow\n label=\"官方端点名单\"\n description=\"baseURL 归一化后的 host(逗号分隔)\"\n values={value.officialBaseURLs ?? []}\n placeholder=\"api.deepseek.com\"\n disabled={readonly}\n onCommit={(next) => { void scope.set('officialBaseURLs', next) }}\n />\n <SelectRow<'hold' | 'error'>\n label=\"拦截方式\"\n description=\"挂起等待不报错;或报错并记入延后队列\"\n value={value.deferredMode ?? 'hold'}\n options={[\n { value: 'hold', label: '挂起等待(退峰自动放行)' },\n { value: 'error', label: '报错并延后(退峰续跑)' },\n ]}\n disabled={readonly}\n onChange={(next) => { void scope.set('deferredMode', next) }}\n />\n <SwitchRow\n label=\"退峰自动继续\"\n description=\"关闭后延后的请求/会话不自动续跑,需手动 /resume\"\n checked={value.deferredResume ?? true}\n disabled={readonly}\n onChange={(next) => toggle('deferredResume', next)}\n />\n <TextRow\n label=\"退峰续跑文案\"\n description=\"error 模式退峰时发送的消息内容\"\n value={value.deferredResumeText ?? ''}\n placeholder=\"继续(高峰已过,自动继续)\"\n disabled={readonly}\n onCommit={(next) => { void scope.set('deferredResumeText', next) }}\n />\n <SwitchRow\n label=\"纳入子代理请求\"\n description=\"子代理请求同样计费,默认一并拦截\"\n checked={value.guardSubagents ?? true}\n disabled={readonly}\n onChange={(next) => toggle('guardSubagents', next)}\n />\n <SwitchRow\n label=\"低谷自动恢复\"\n description=\"低峰时段自动恢复被暂停的会话\"\n checked={value.offPeakAutoResume ?? true}\n disabled={readonly}\n onChange={(next) => toggle('offPeakAutoResume', next)}\n />\n <SwitchRow\n label=\"周末模式\"\n description=\"识别周末,无视峰谷畅快跑\"\n checked={value.weekendMode ?? true}\n disabled={readonly}\n onChange={(next) => toggle('weekendMode', next)}\n />\n <SwitchRow\n label=\"回退锁队列\"\n description=\"无会话门时锁等待队列\"\n checked={value.queueFallback ?? true}\n disabled={readonly}\n onChange={(next) => toggle('queueFallback', next)}\n />\n <SwitchRow\n label=\"自动重试\"\n description=\"后端重试,默认关(保守)\"\n checked={value.retryEnabled ?? false}\n disabled={readonly}\n onChange={(next) => toggle('retryEnabled', next)}\n />\n <p className=\"sgHint\">\n 判定口径:显式 id 名单 → baseURL 端点 → catalog 默认端点 → 内置 id。\n 排查误判访问 /session-guard/provider?provider=&lt;id&gt; 看 matchedBy。\n </p>\n {!snapshot.writable && <p className=\"sgReadonly\">当前只读,无法修改。</p>}\n </>\n )}\n </div>\n )}\n </li>\n )\n}\n","/**\r\n * dsh-session-guard — 家族节接管组件(fallback host section)。\r\n *\r\n * 仅当宿主 dsh-thinking-levels 缺席、且本插件在接管选举中胜出时,由\r\n * index.ts 注册为顶级 `settings.section`(id 固定 `dsh-family`,节名仍为\r\n * 「起子插件设置」)。组件是纯通用渲染:把 `dsh-family.tab` 账本里的每张\r\n * 贡献卡(含本插件自己的,因为接管时本插件也声明了该子席位)按 order\r\n * 依次 renderSlot —— 卡片本身是默认展开的抽屉,整节即一页抽屉。\r\n *\r\n * 与 thinking-levels 的 FamilySettingsSection 的差别仅在不需要 thinking-\r\n * levels 自己的卡(宿主不在了,它的卡也不在):渲染循环没有 own-tab 特例。\r\n */\r\nimport { useSyncExternalStore } from 'react'\r\nimport type { JSX } from 'react'\r\n\r\n/** 与 FamilySectionInjected.hooks.tabs 同形的账本投影(结构化镜像)。 */\r\ntype HostObservable<T> = {\r\n getSnapshot(): T\r\n subscribe(listener: () => void): () => void\r\n}\r\n\r\n/** 账本条目(id/order/label,label 已解析为字符串)。 */\r\nexport interface FamilyTabEntry {\r\n id: string\r\n order: number\r\n label: string\r\n}\r\n\r\n/** 组件 props:框架注入的子席位 dispatcher + 注册侧 inject 返回的 hooks。 */\r\nexport interface GuardFamilySectionProps {\r\n renderSlot: (key: 'dsh-family.tab', owner?: object, opts?: { only?: string; fallback?: JSX.Element | null }) => JSX.Element | null\r\n hooks: { tabs: HostObservable<readonly FamilyTabEntry[]> }\r\n}\r\n\r\nexport function GuardFamilySection(props: GuardFamilySectionProps): JSX.Element {\r\n const tabs = useSyncExternalStore(props.hooks.tabs.subscribe, props.hooks.tabs.getSnapshot)\r\n return (\r\n <div style={{ display: 'grid', gap: '12px' }}>\r\n {tabs.map(row => (\r\n <div key={row.id}>\r\n {props.renderSlot('dsh-family.tab', {}, { only: row.id, fallback: null })}\r\n </div>\r\n ))}\r\n </div>\r\n )\r\n}\r\n","/**\n * dsh-session-guard — 浏览器 half。\n *\n * 职责(全部 fail-open,D8):\n * - 在 composer 输入区右侧注册一个**纯展示**状态徽标(高峰/谷时/周末),轮询\n * /session-guard/status;\n * - **不做**冻结/会话动作——冻结按钮由 input-traffic 接管并经 /session-guard/rpc\n * 桥接 host 会话门;本插件客户端不注册任何按钮,避免与 input-traffic 冲突。\n * - 0.1.7:旧的插件设置卡已随席位删除 —— 设置表单由 host\n * 侧 Config 的 `.volatile()` 字段自动生成。\n *\n * 构建:tsdown → lib/client.js(__ModuleLoader__.load 注册,与 input-traffic 同构)。\n */\nimport { NS, dictionaries } from './locales'\nimport { StatusBadge } from './status-badge'\nimport { PauseButton } from './pause-button'\nimport { SessionGuardCard } from './settings-card'\nimport { GuardFamilySection, type FamilyTabEntry } from './family-section'\n\n// 起子插件族共用设置节:宿主 dsh-thinking-levels 注册顶级 `settings.section`\n// (id `dsh-family`)并声明 `dsh-family.tab` 子席位,本插件贡献卡片。宿主缺席\n// 时本插件按下载量排名接管该节(见 apply 内的选举逻辑),节名仍为\n// 「起子插件设置」;宿主在场时本插件只贡献卡片。\n// 类型导入(构建时擦除,bundle 无 value-import 平台包):让下方 `declare\n// module` 增补能解析到 @deepseek-ai/dsh-client-ui-slots 的 SlotMap。\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface SlotMap {\n 'dsh-family.tab': { kind: 'list'; scope: 'root' }\n /**\n * 插件页配置卡(官方 ui-plugin-manager 契约,key = 包名):Plugins 页\n * 不自动渲染 volatile 配置表单,bundle 详情页只渲染注册在本 keyed 席位\n * 下的卡片;owner props 由页面给(`{ view: 'page', form }`),本卡片改经\n * inject 工厂拿自己的 scope(与 dsh-family.tab 注册同源)。\n */\n 'plugins.bundle.config': { kind: 'keyed'; scope: 'root'; owner: Record<string, unknown> }\n }\n}\n\n/** 家族节固定 id(与 thinking-levels 的注册严格一致)。 */\nconst FAMILY_SECTION_ID = 'dsh-family'\n/** 家族子席位 key(与 thinking-levels 的声明严格一致)。 */\nconst FAMILY_CHILD_KEY = 'dsh-family.tab'\n/**\n * 接管宽限期:等宿主(以及排名更前的贡献方)先落座。下载量排名 guard(1522)\n * 高于 session-steward(1090) → guard 宽限期更短、先尝试接管;并发冲突由\n * ui-slots 的「同 id 同 priority 重复注册抛错」仲裁,后到者放弃即可。\n */\nconst FAMILY_HOST_GRACE_MS = 2000\n\n/** 客户端所需服务:slots(状态徽标)+ locale + configForms(共用 tab 设置卡)。 */\nexport const inject = ['slots', 'locale', 'configForms']\n\n/** 轻量 ctx 类型(仅本客户端用到的方法;构建时类型被剥离)。 */\ninterface SlotsFace {\n inject: (_name: string, _fn: () => unknown) => () => void\n register: (_options: Record<string, unknown>, _component: unknown) => () => void\n entries: (_name: string) => Array<{ options: { id?: string; order?: number; label?: unknown } }>\n getVersion: (_name: string) => number\n subscribe: (_name: string, _listener: () => void) => () => void\n}\ninterface ConfigFormsFace {\n get: <T>(_entryId: string) => import('./scope-face').SettingsScope<T>\n}\ninterface LocaleFace {\n register(ns: string, dicts: Record<string, Record<string, string>>): () => void\n}\ninterface ClientCtx {\n slots: SlotsFace\n configForms: ConfigFormsFace\n locale?: LocaleFace\n effect: (fn: () => (() => void) | void, label: string) => void\n}\n\nexport function apply(ctx: ClientCtx) {\n // 注册全部 9 种语言字典(guarded:throw 不会逃逸)。\n if (ctx.locale) {\n const locale = ctx.locale\n ctx.effect(() => locale.register(NS, dictionaries), 'dsh-session-guard: dictionaries')\n }\n\n // 暂停会话按钮(v0.2.0):step 级门控的状态显示 + 手动解除。\n // order 20 < input-traffic 冻结按钮的 30 → 排在左侧,两者并列互不取代(ADR-001/002)。\n ctx.slots.inject('conversation.input.right', () => ctx.slots.register({\n name: 'conversation.input.right',\n id: 'session-guard-pause',\n order: 20,\n locale: 'session-guard',\n }, PauseButton))\n\n // 状态徽标:输入区右侧,纯展示。\n ctx.slots.inject('conversation.input.right', () => ctx.slots.register({\n name: 'conversation.input.right',\n id: 'session-guard-status',\n order: 40,\n locale: 'session-guard',\n }, StatusBadge))\n\n // 插件族共用 tab 贡献卡:读写本插件 entry(`session-guard`)的 volatile 配置。\n ctx.slots.inject('dsh-family.tab', () => ctx.slots.register({\n name: 'dsh-family.tab',\n id: 'session-guard',\n order: 20,\n label: '会话守护门禁',\n locale: 'session-guard',\n inject: () => ({ scope: ctx.configForms.get<Record<string, unknown>>('session-guard') }),\n }, SessionGuardCard))\n\n // 插件页配置卡:Plugins 页不自动渲染 volatile 配置表单,须注册\n // `plugins.bundle.config` 席位(key = 包名),配置卡才渲染在 bundle 详情页。\n // 卡片组件与 props(scope)与上方 dsh-family.tab 注册完全同源:同一张\n // SessionGuardCard、同一 inject 工厂,配置仍写入 entry `session-guard` 的\n // volatile config;页面注入的 owner props(form 等)本卡不消费。\n ctx.slots.inject('plugins.bundle.config', () => ctx.slots.register({\n name: 'plugins.bundle.config',\n key: 'dsh-session-guard',\n inject: () => ({ scope: ctx.configForms.get<Record<string, unknown>>('session-guard') }),\n }, SessionGuardCard))\n\n // 家族节宿主选举:宿主 dsh-thinking-levels 缺席时顶上「起子插件设置」节。\n // 宽限期后若 `settings.section` 里没有 id `dsh-family` 的条目,则按同一 id\n // 接管(声明同一个 dsh-family.tab 子席位,节内通用渲染全部贡献卡)。与\n // session-steward 的并发竞争由 ui-slots 同 id 重复注册抛错仲裁,先到者胜。\n // 节内各卡(含本插件自己的贡献卡)经子席位 renderSlot 渲染,抽屉默认展开。\n setTimeout(() => {\n if (ctx.slots.entries('settings.section').some(e => e.options.id === FAMILY_SECTION_ID)) return\n try {\n ctx.slots.register({\n name: 'settings.section',\n id: FAMILY_SECTION_ID,\n order: 40,\n label: () => '起子插件设置',\n inject: () => makeGuardFamilyTabsHooks(ctx.slots),\n children: { [FAMILY_CHILD_KEY]: { kind: 'list', scope: 'root' } },\n }, GuardFamilySection)\n } catch {\n // 并发接管竞争落败(或设置壳未声明席位):胜出方的节服务整个家族。\n }\n }, FAMILY_HOST_GRACE_MS)\n}\n\n/** 接管节的账本投影 hooks(与 thinking-levels 的 FamilySectionInjected 同形)。 */\nfunction makeGuardFamilyTabsHooks(slots: SlotsFace): {\n getSnapshot: () => readonly FamilyTabEntry[]\n subscribe: (listener: () => void) => () => void\n} {\n let version = -1\n let tabs: readonly FamilyTabEntry[] = []\n return {\n getSnapshot: () => {\n const next = slots.getVersion(FAMILY_CHILD_KEY)\n if (next !== version) {\n version = next\n tabs = slots.entries(FAMILY_CHILD_KEY)\n .map(entry => ({\n id: entry.options.id ?? '',\n order: entry.options.order ?? 0,\n label: typeof entry.options.label === 'function'\n ? (() => { try { return String((entry.options.label as () => unknown)() ?? entry.options.id ?? '') } catch { return String(entry.options.id ?? '') } })()\n : String(entry.options.label ?? entry.options.id ?? ''),\n }))\n .sort((a, b) => a.order - b.order)\n }\n return tabs\n },\n subscribe: (listener: () => void) => slots.subscribe(FAMILY_CHILD_KEY, listener),\n }\n}\n"],"mappings":"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"}
package/locale/de.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Sitzungswache",
4
+ "description": "Sitzungs-Gate zur Spitzenzeit: Wochenendmodus, Auto-Pause, Prüfung offizieller Quellen, Sitzungs-Einfrieren und automatischer Wiederholungsversuch."
5
+ }
6
+ }
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Session Guard",
4
+ "description": "Peak-hour session gate: weekend mode, auto-pause, official-source guard, session freeze, and auto-retry."
5
+ }
6
+ }
package/locale/es.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Guardia de sesión",
4
+ "description": "Puerta de sesión en hora pico: modo fin de semana, pausa automática, verificación de fuente oficial, congelación de sesión y reintento automático."
5
+ }
6
+ }
package/locale/fr.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Garde de session",
4
+ "description": "Portail de session en période de pic : mode week-end, pause automatique, vérification source officielle, gel de session et nouvelle tentative automatique."
5
+ }
6
+ }
package/locale/it.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Guardia di sessione",
4
+ "description": "Portale di sessione nelle ore di picco: modalità fine settimana, pausa automatica, verifica fonte ufficiale, blocco sessione e nuovo tentativo automatico."
5
+ }
6
+ }
package/locale/ja.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "セッションガード",
4
+ "description": "ピーク時間セッションゲート:週末モード、自動一時停止、公式ソース判定、セッション凍結、自動リトライ。"
5
+ }
6
+ }
package/locale/ko.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "세션 가드",
4
+ "description": "피크 시간 세션 게이트: 주말 모드, 자동 일시정지, 공식 소스 판정, 세션 동결, 자동 재시도."
5
+ }
6
+ }
package/locale/ru.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Страж сессий",
4
+ "description": "Гейт сессий в час пик: режим выходных, автопауза, проверка официального источника, заморозка сессии и автоповтор."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "会话守护门禁",
4
+ "description": "高峰自动会话门:周末模式 + 高峰自动暂停 + 官方源二维判定 + 会话级冻结 + 后端自动重试。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-session-guard",
3
- "version": "3.2.4",
3
+ "version": "3.2.5",
4
4
  "publishConfig": {
5
5
  "tag": "dsh-0.1.7"
6
6
  },
@@ -28,11 +28,13 @@
28
28
  "exports": {
29
29
  ".": "./src/index.js",
30
30
  "./client": "./lib/client.js",
31
+ "./locale/*.json": "./locale/*.json",
31
32
  "./package.json": "./package.json"
32
33
  },
33
34
  "files": [
34
35
  "src/",
35
36
  "lib/",
37
+ "locale",
36
38
  "cordis.patch.yml",
37
39
  "dsh.plugin.json",
38
40
  "README.md",
@@ -1,46 +1,46 @@
1
- /**
2
- * dsh-session-guard — 家族节接管组件(fallback host section)。
3
- *
4
- * 仅当宿主 dsh-thinking-levels 缺席、且本插件在接管选举中胜出时,由
5
- * index.ts 注册为顶级 `settings.section`(id 固定 `dsh-family`,节名仍为
6
- * 「起子插件设置」)。组件是纯通用渲染:把 `dsh-family.tab` 账本里的每张
7
- * 贡献卡(含本插件自己的,因为接管时本插件也声明了该子席位)按 order
8
- * 依次 renderSlot —— 卡片本身是默认展开的抽屉,整节即一页抽屉。
9
- *
10
- * 与 thinking-levels 的 FamilySettingsSection 的差别仅在不需要 thinking-
11
- * levels 自己的卡(宿主不在了,它的卡也不在):渲染循环没有 own-tab 特例。
12
- */
13
- import { useSyncExternalStore } from 'react'
14
- import type { JSX } from 'react'
15
-
16
- /** 与 FamilySectionInjected.hooks.tabs 同形的账本投影(结构化镜像)。 */
17
- type HostObservable<T> = {
18
- getSnapshot(): T
19
- subscribe(listener: () => void): () => void
20
- }
21
-
22
- /** 账本条目(id/order/label,label 已解析为字符串)。 */
23
- export interface FamilyTabEntry {
24
- id: string
25
- order: number
26
- label: string
27
- }
28
-
29
- /** 组件 props:框架注入的子席位 dispatcher + 注册侧 inject 返回的 hooks。 */
30
- export interface GuardFamilySectionProps {
31
- renderSlot: (key: 'dsh-family.tab', owner?: object, opts?: { only?: string; fallback?: JSX.Element | null }) => JSX.Element | null
32
- hooks: { tabs: HostObservable<readonly FamilyTabEntry[]> }
33
- }
34
-
35
- export function GuardFamilySection(props: GuardFamilySectionProps): JSX.Element {
36
- const tabs = useSyncExternalStore(props.hooks.tabs.subscribe, props.hooks.tabs.getSnapshot)
37
- return (
38
- <div style={{ display: 'grid', gap: '12px' }}>
39
- {tabs.map(row => (
40
- <div key={row.id}>
41
- {props.renderSlot('dsh-family.tab', {}, { only: row.id, fallback: null })}
42
- </div>
43
- ))}
44
- </div>
45
- )
46
- }
1
+ /**
2
+ * dsh-session-guard — 家族节接管组件(fallback host section)。
3
+ *
4
+ * 仅当宿主 dsh-thinking-levels 缺席、且本插件在接管选举中胜出时,由
5
+ * index.ts 注册为顶级 `settings.section`(id 固定 `dsh-family`,节名仍为
6
+ * 「起子插件设置」)。组件是纯通用渲染:把 `dsh-family.tab` 账本里的每张
7
+ * 贡献卡(含本插件自己的,因为接管时本插件也声明了该子席位)按 order
8
+ * 依次 renderSlot —— 卡片本身是默认展开的抽屉,整节即一页抽屉。
9
+ *
10
+ * 与 thinking-levels 的 FamilySettingsSection 的差别仅在不需要 thinking-
11
+ * levels 自己的卡(宿主不在了,它的卡也不在):渲染循环没有 own-tab 特例。
12
+ */
13
+ import { useSyncExternalStore } from 'react'
14
+ import type { JSX } from 'react'
15
+
16
+ /** 与 FamilySectionInjected.hooks.tabs 同形的账本投影(结构化镜像)。 */
17
+ type HostObservable<T> = {
18
+ getSnapshot(): T
19
+ subscribe(listener: () => void): () => void
20
+ }
21
+
22
+ /** 账本条目(id/order/label,label 已解析为字符串)。 */
23
+ export interface FamilyTabEntry {
24
+ id: string
25
+ order: number
26
+ label: string
27
+ }
28
+
29
+ /** 组件 props:框架注入的子席位 dispatcher + 注册侧 inject 返回的 hooks。 */
30
+ export interface GuardFamilySectionProps {
31
+ renderSlot: (key: 'dsh-family.tab', owner?: object, opts?: { only?: string; fallback?: JSX.Element | null }) => JSX.Element | null
32
+ hooks: { tabs: HostObservable<readonly FamilyTabEntry[]> }
33
+ }
34
+
35
+ export function GuardFamilySection(props: GuardFamilySectionProps): JSX.Element {
36
+ const tabs = useSyncExternalStore(props.hooks.tabs.subscribe, props.hooks.tabs.getSnapshot)
37
+ return (
38
+ <div style={{ display: 'grid', gap: '12px' }}>
39
+ {tabs.map(row => (
40
+ <div key={row.id}>
41
+ {props.renderSlot('dsh-family.tab', {}, { only: row.id, fallback: null })}
42
+ </div>
43
+ ))}
44
+ </div>
45
+ )
46
+ }