dsh-perm-gate 5.1.0 → 5.1.2-compat.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dsh.plugin.json +1 -1
- package/lib/bridge.d.ts +34 -0
- package/lib/bridge.js +125 -0
- package/lib/cli.js +0 -0
- package/lib/client.js +246 -7
- package/lib/client.js.map +1 -1
- package/lib/debug-generation.d.ts +21 -0
- package/lib/debug-generation.js +44 -0
- package/lib/index.js +104 -7
- package/package.json +31 -20
- package/scripts/patch-permission-glyph.mjs +0 -0
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useState","useRef","useState","useSyncExternalStore","useState","useRef","useState"],"sources":["../src/client/locales.ts","../src/deny-defaults.ts","../src/llm-presets.ts","../src/preset.ts","../src/client/sediment.tsx","../src/client/card.tsx","../src/client/feed.ts","../src/client/notice.tsx","../src/client/history.tsx","../src/client/compat.ts","../src/client/index.ts"],"sourcesContent":["/** `dsh-perm-gate` client dictionaries (zh / en / ja / ko / fr / de / it / ru / es). */\n\n/** Dictionary namespace owned by this plugin. */\nexport const NS = 'dsh-perm-gate'\n\n/** The key union of this plugin's dictionary (source of truth: `zh`). */\nexport type PermissiveKey = keyof typeof zh\n\n/** Simplified Chinese dictionary (the key-set source of truth). */\nexport const zh = {\n 'card.title': '自动审查',\n 'section.title': '自动审查门',\n 'card.description': '独立审批档位:与只读 / 完全权限 / 白名单平行,在会话权限下拉中显示为「自动审查」。前端只暴露一个开关;后台四个审批策略可组合、由此处设置决定,仍对 P0 硬拒绝保持 fail-closed。',\n 'card.permissive': '启用自动审查档位',\n 'card.permissiveHint': '关闭时门禁行为与此前完全一致。',\n 'card.scopeNote': '档位作用域:本门禁仅在会话权限档位为 %scope 时生效。其他档位下整个门禁停用(含 P0 硬拒绝),由所选档位自身的策略接管;停用时会写入一条 stand-down 事件,并在输入框上方常驻一条提示条。',\n 'card.strategies': '后台审批策略(至少一个生效;可组合)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — 作用域内安全操作自动放行,危险/未知转 ask(中间档基线)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — 一律逐次 ask;审批面板「允许控件」含两个扩展按钮:「本会话重复允许该类」(会话语限次 grant)与「允许所有类型」(命令词持久迁入 rulesFile 白名单)',\n 'card.strategy.llmAssist': 'llmAssist — 自定义 LLM 按风险分级裁决:safe 自动放行;deletion/credential/remote/system/bulk 硬风险维持人工确认(分类器永不拒绝,只负责升级判断);neutral 进入确认学习;失败/超时回退人工',\n 'card.strategy.trustEscalation': 'trustEscalation — 沙箱升级免确认:本门禁已放行的调用,其工具内部发起的沙箱提权(shell / pwsh / edit 的 sandbox_permissions)由门禁直接批准,不再弹窗',\n 'card.strategy.trustEscalationHint': '沙箱提权审批发生在 tools/pre-execute 之后、工具体内部,门禁原本看不到它,因此「LLM 判安全已自动放行」的调用仍会弹窗要求你批准提权。开启后,仅对门禁确实放行过的那一次调用(按 callId 精确匹配)免确认,其余一律照旧走人工;目标模式非 workspace-write / danger-full-access 或理由无法识别时同样回退人工。关闭后提权保持人工把关。',\n 'card.readonly': '只读',\n 'card.unavailable': '设置命名空间不可用:请确认 dsh-perm-gate 已装配进 profile。',\n 'card.llmReceiver': 'llmAssist 接收 LLM(OpenAI 兼容,可用自定义 API)',\n 'card.llmEndpoint': 'Endpoint(BaseURL,如 https://api.openai.com/v1)',\n 'card.llmModel': 'Model(模型 id,如 deepseek-chat)',\n 'card.llmKey': 'API Key(保密)',\n 'card.llmKeyHidden': '未设置 · 首次输入后以 * 显示',\n 'card.llmKeyMasked': '已设置 · 输入新值覆盖',\n 'card.llmKeyOverwrite': '已设置保密值,输入新值并失焦即可覆盖。',\n 'card.llmKeyClear': '清除',\n 'card.allowlist': '白名单(allow,rulesFile 同步)',\n 'card.allowlistHint': '命中 allow 段的命令模式直接放行;逐条添加或删除,实时写入 rulesFile 并重载。',\n 'card.allowlistPresetNote': '预置白名单的等价物是 trustAutoAllow 策略(工作区内安全操作自动放行),在上方策略区开启;本列表镜像你的 rulesFile allow 段,初始为空属正常。',\n 'card.allowlistEmpty': '无白名单规则',\n 'card.allowlistPlaceholder': '新命令模式,如 npm test*',\n 'card.allowlistAdd': '添加',\n 'card.allowlistRemove': '删除该模式',\n 'card.allowlistBulk': '批量编辑',\n 'card.allowlistBulkHide': '收起批量编辑',\n 'card.allowlistSave': '保存白名单',\n 'card.riskLearning': 'riskLearning — 裁决学习:neutral 风险操作经人工确认并执行后计数,满阈值且操作指纹一致时自动放行',\n 'card.riskLearningHint': '学习状态为插件自有数据($DSH_HOME/perm-gate/learning.json),不写入你的 YAML 规则文件;不同目标永不复用放行。默认关闭。',\n 'card.riskThreshold': '自动放行所需人工确认次数(1–10)',\n 'notice.label': '权限门禁动态',\n 'history.label': '审批记录',\n 'history.title': '权限审批记录',\n 'history.subtitle': '本会话中门禁的每次判定轨迹(最新在上)',\n 'history.loading': '加载中…',\n 'history.empty': '本会话暂无审批记录',\n 'history.error': '加载失败:',\n 'history.tag.auto': '自动放行',\n 'history.tag.ask': '转人工',\n 'history.tag.deny': '拒绝',\n 'card.denylistRestore': '恢复预置黑名单',\n 'card.denylist': '黑名单(deny 关键词,插件预置)',\n 'card.denylistHint': '命中关键词(大小写不敏感子串)的调用直接拒绝,先于白名单/授权/LLM。预置列表继承自 dsh-approval-gate,安装即生效;可增删,清空或删除后可用「恢复预置黑名单」一键还原(空列表等同预置,黑名单常开)。',\n 'card.denylistEmpty': '黑名单为空(所有调用都不会被关键词层拒绝)',\n 'card.denylistPlaceholder': '新关键词,如 drop database',\n 'card.denylistAdd': '添加',\n 'card.denylistRemove': '删除该关键词',\n 'card.denylistTagPreset': '预置',\n 'card.denylistTagCustom': '自定义',\n 'card.riskSediment': 'riskSediment — 学习沉淀:满阈值的确认样本成为确定性放行规则',\n 'card.riskSedimentHint': '开启后,同一「工具|类别」确认满阈值,其样本指纹即沉淀为放行规则——同工具同目标精确命中时直接放行,不再过 LLM(关闭 llmAssist 也继续生效)。',\n 'card.sediment': '学习沉淀(确定性放行规则)',\n 'card.sedimentHint': '来自人工确认的沉淀规则:样本指纹命中才放行,不同目标永不复用。可终止单个学习或删除单条样本。',\n 'card.sedimentEmpty': '暂无沉淀规则(确认满阈值的样本会出现在这里)',\n 'card.sedimentCount': '已确认 %n/%t',\n 'card.sedimentStop': '终止',\n 'card.sedimentStopTitle': '终止该学习(删除计数与样本)',\n 'card.sedimentStopConfirm': '终止「%k」的学习?将删除其确认计数与全部样本。',\n 'card.sedimentSampleRemove': '删除该沉淀样本',\n 'card.llmSource': '接收 LLM 来源',\n 'card.llmSourceCustom': '自定义 API(OpenAI 兼容)',\n 'card.llmSourceHost': '使用会话当前默认模型(DSH llm 服务)',\n 'card.llmSourceHostHint': '默认使用 DSH 会话当前选中的模型组执行审批判定(下方显示当前生效值);Provider / Model 留空即跟随会话,也可从下拉选择或手动输入固定下来——你在 DSH 里配置的自定义组(如 local-35b)会自动出现在下拉中。',\n 'card.llmProvider': 'Provider(留空 = 跟随会话当前选择)',\n 'card.llmProviderPlaceholder': '跟随会话当前选择',\n 'card.llmModelHostPlaceholder': '留空 = 跟随会话当前选择',\n 'card.llmResolved': '当前生效:%p / %m',\n 'card.llmPreset': '预置端点(选择后自动填充,可再编辑)',\n 'card.llmPresetChoose': '选择预置…',\n 'card.llmPresetPublic': '公共 API 预置',\n 'card.llmPresetHost': 'DSH 模型组(选择后自动切换为会话模式)',\n 'card.networkEnabled': '网络拦截(networkEnabled)',\n 'card.networkEnabledHint': '开启后启动本地代理拦截子进程出站连接,按规则放行/阻断。关闭则零行为变更。',\n 'card.watch': '规则热重载(watch)',\n 'card.watchHint': '开启后自动监听规则文件变更并即时生效,无需手动 reload。',\n 'card.networkRebindNote': '切换后立即生效(自动重绑,无需重载插件)。',\n 'card.networkInjectEnv': '注入代理环境变量(networkInjectEnv)',\n 'card.networkInjectEnvHint': '开启后为子进程写入 HTTP(S)_PROXY / ALL_PROXY(并清空 NO_PROXY)。关闭则只启动监听、不改变任何进程环境。',\n 'card.healthStale': '宿主路由不可用(404)——node 半区仍是旧版本,请完全重启 dsh(而非仅刷新页面)后重试。',\n 'card.healthTest': '健康测试',\n 'card.healthRunning': '测试中…',\n 'card.healthOk': '正常(%ms ms)',\n 'card.healthFail': '失败:',\n 'history.tag.learned': '学习沉淀',\n 'history.tag.manualApproved': '人工通过',\n 'history.tag.manualRejected': '人工拒绝',\n 'history.tag.manualCancelled': '人工取消',\n 'history.tag.standDown': '门禁停用',\n 'history.learnedProgress': '学习 %n/%t',\n 'history.snapshots': 'diff 快照',\n 'history.clearSession': '仅清本会话',\n 'history.clearAll': '清空全部',\n 'history.clearSessionTitle': '仅清除本会话的 diff 快照(不影响其他会话)',\n 'history.clearAllTitle': '清空全部会话(含其他会话未查看过的)diff 快照,需二次确认',\n 'history.clearSessionConfirm': '确定清除【本会话】的 diff 快照?仅删除本会话审批产生的改动对比数据,不影响审批记录本身。',\n 'history.clearAllConfirm': '确定清除【全部会话】的 diff 快照?这可能删除其他会话还没看过的改动对比记录,且不可恢复。',\n 'history.diffTitle': '文件改动对比',\n 'history.diffClose': '关闭',\n 'history.diffLoading': '加载中…',\n 'history.diffEmpty': '该文件无内容变化(或文件不可读)',\n 'history.diffLoadFail': '加载 diff 失败:',\n 'history.diffRevert': '撤销此改动',\n 'history.diffReverting': '发送中…',\n 'history.diffRevertDone': '已发送撤销指令',\n 'history.diffRevertSent': '撤销指令已发送到对话框,AI 将按指令恢复文件',\n 'history.diffRevertFail': '发送失败:',\n 'history.diffNoSnapshot': '该事件没有此文件的快照',\n 'history.diffChipTitle': '查看该文件改动对比',\n 'history.diffStats': '+%a / -%r 行变更 · %c 行未变',\n 'history.diffGone': '(文件当前已不存在)',\n 'history.diffHidden': '%n 行未修改',\n // Rule test (dry-run) panel. `%d` is the defaultAction, `%s` is unused here.\n 'card.dryRun': '规则测试',\n 'card.dryRunHint': '用当前生效的规则判定一次调用,不执行任何工具、不写入任何规则。改规则前先在这里验一遍。',\n 'card.dryRunTool': '工具名',\n 'card.dryRunCommand': '命令 / 参数',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': '测试',\n 'card.dryRunRunning': '判定中…',\n 'card.dryRunEmpty': '尚未测试。填入工具名与命令,点「测试」查看会怎么裁决。',\n 'card.dryRunVerdict': '裁决',\n 'card.dryRunAllow': '放行',\n 'card.dryRunAsk': '人工确认',\n 'card.dryRunDeny': '拒绝',\n 'card.dryRunRule': '命中规则',\n 'card.dryRunRuleNone': '无规则命中,走 defaultAction:%d',\n 'card.dryRunDimensions': '约束维度',\n 'card.dryRunReason': '原因',\n 'card.dryRunNote': '「命中规则」来自规则层。若裁决由更早的硬拒绝或关键词黑名单产生,则不会有规则序号——那种情况下列出的维度仅供参考。',\n 'card.dryRunNoRules': '(当前加载了 0 条规则:检查 rulesFile 路径)',\n 'card.dryRunFail': '测试失败:',\n 'card.dryRunStale': '路由不存在(插件未重启?)',\n 'card.rules': 'Settings 内置规则',\n 'card.rulesHint': '门禁此刻实际加载的规则(来自本插件入口的 rules 配置字段;未配置时回退到规则文件)。只读——这里改不了任何东西。要改规则,用下面的白名单,或在设置页中编辑。',\n 'card.rulesRefresh': '刷新',\n 'card.rulesLoading': '读取中…',\n 'card.rulesPath': '来源',\n 'card.rulesNone': '未配置规则',\n 'card.rulesCounts': '规则',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b 字节 · %l 行',\n 'card.rulesMissing': '规则不存在。门禁会退到内置默认。',\n 'card.rulesTruncated': '规则过大,仅显示前 512 KB。',\n 'card.rulesError': '加载失败:',\n 'card.rulesStale': '路由不存在(插件未重启?)',\n 'card.rulesNote': '此处只读:面板无法修改规则;白名单段与“始终允许”会写回本插件的入口配置。',\n} satisfies Record<string, string>\n\n/** English dictionary (keys mirror zh). */\nexport const en: Record<keyof typeof zh, string> = {\n 'card.title': '自动审查 (Auto review)',\n 'section.title': 'Auto-Review Gate',\n 'card.description': 'Independent approval tier, parallel to read-only / full-access / whitelist, shown as 自动审查 in the session permission picker. The front-end exposes a single switch; the four backend approval strategies are combinable via this panel and still fail-closed against P0 hard-deny.',\n 'card.permissive': 'Enable the 自动审查 tier',\n 'card.permissiveHint': 'When off, the gate behaves exactly as before.',\n 'card.scopeNote': 'Preset scope: this gate only acts while the session permission preset is %scope. Under any other preset the whole gate stands down — P0 hard-deny included — and the selected preset\\'s own policy takes over. A stand-down records one event and leaves a sticky strip above the input.',\n 'card.strategies': 'Backend approval strategies (at least one effective; combinable)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — safe in-scope ops auto-allow; dangerous/unknown ask (baseline middle tier)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — every crossing asks; the approval \"allow controls\" get two extended buttons: \"repeat-allow this type this session\" (bounded session grant) and \"allow every occurrence\" (persist the command word into the rulesFile whitelist)',\n 'card.strategy.llmAssist': 'llmAssist — a custom LLM grades risk: safe auto-allows; deletion/credential/remote/system/bulk hard risks keep the human ask (the classifier never denies — it only escalates); neutral enters confirm-learning; failure/timeout falls back to the human',\n 'card.strategy.trustEscalation': 'trustEscalation — sandbox escalation without a prompt: for a call this gate already allowed, the sandbox widening a shell / pwsh / edit tool raises from inside itself is approved here instead of asking you',\n 'card.strategy.trustEscalationHint': 'A sandbox escalation is asked from inside the tool body, after tools/pre-execute, so the gate never saw it — a call the LLM graded safe and the gate auto-allowed still prompted you to approve the widening. With this on, only the exact call the gate allowed (matched by callId) skips the prompt; everything else goes to the human as before, as does any unrecognized reason or a target other than workspace-write / danger-full-access. Turn it off to keep widening human-gated.',\n 'card.readonly': 'Read-only',\n 'card.unavailable': 'Settings namespace unavailable: make sure dsh-perm-gate is assembled into this profile.',\n 'card.llmReceiver': 'llmAssist receiving LLM (OpenAI-compatible; any custom API)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, e.g. https://api.openai.com/v1)',\n 'card.llmModel': 'Model (model id, e.g. deepseek-chat)',\n 'card.llmKey': 'API Key (secret)',\n 'card.llmKeyHidden': 'Unset · shown as * after first entry',\n 'card.llmKeyMasked': 'Set · type a new value to overwrite',\n 'card.llmKeyOverwrite': 'A secret is stored; type a new value and blur to overwrite it.',\n 'card.llmKeyClear': 'Clear',\n 'card.allowlist': 'Whitelist (allow, synced to rulesFile)',\n 'card.allowlistHint': 'Patterns in the allow section allow directly; add or remove entries one by one, written to the rulesFile and reloaded live.',\n 'card.allowlistPresetNote': 'The preset-whitelist equivalent is the trustAutoAllow strategy (safe in-scope ops auto-allow), enabled in the strategies section above; this list mirrors your rulesFile allow section and legitimately starts empty.',\n 'card.allowlistEmpty': 'No whitelist rules',\n 'card.allowlistPlaceholder': 'New command pattern, e.g. npm test*',\n 'card.allowlistAdd': 'Add',\n 'card.allowlistRemove': 'Remove this pattern',\n 'card.allowlistBulk': 'Bulk edit',\n 'card.allowlistBulkHide': 'Hide bulk edit',\n 'card.allowlistSave': 'Save whitelist',\n 'card.riskLearning': 'riskLearning — verdict learning: neutral-risk asks that the human approves and that execute count up; the same operation auto-allows at threshold with a matching fingerprint',\n 'card.riskLearningHint': 'Learning state is plugin-owned ($DSH_HOME/perm-gate/learning.json) and never written into your YAML rules; a different target never reuses authority. Off by default.',\n 'card.riskThreshold': 'Human confirmations required before auto-allow (1–10)',\n 'notice.label': 'Permission gate activity',\n 'history.label': 'Approvals',\n 'history.title': 'Permission approval records',\n 'history.subtitle': 'Every gate decision in this conversation, newest first',\n 'history.loading': 'Loading…',\n 'history.empty': 'No approval records in this session yet',\n 'history.error': 'Failed to load: ',\n 'history.tag.auto': 'Auto-allowed',\n 'history.tag.ask': 'Asked',\n 'history.tag.deny': 'Denied',\n 'card.denylistRestore': 'Restore preset blacklist',\n 'card.denylist': 'Blacklist (deny keywords, plugin preset)',\n 'card.denylistHint': 'A call whose text contains a keyword (case-insensitive substring) is denied outright, before whitelist / grants / LLM. The preset list is inherited from dsh-approval-gate and active from install; edit freely — empty or cleared falls back to the preset (one-click restore available), so the blacklist never silently turns off.',\n 'card.denylistEmpty': 'Blacklist empty (no call is vetoed by the keyword layer)',\n 'card.denylistPlaceholder': 'New keyword, e.g. drop database',\n 'card.denylistAdd': 'Add',\n 'card.denylistRemove': 'Remove this keyword',\n 'card.denylistTagPreset': 'Preset',\n 'card.denylistTagCustom': 'Custom',\n 'card.riskSediment': 'riskSediment — learning sedimentation: threshold-reached samples become deterministic auto-allows',\n 'card.riskSedimentHint': 'When on, once a tool|category key reaches the threshold its sample fingerprints are sedimented into allow rules — an exact same-tool same-target hit allows outright without another LLM call (keeps working with llmAssist off).',\n 'card.sediment': 'Learning sediment (deterministic allow rules)',\n 'card.sedimentHint': 'Rules sedimented from human confirmations: only an exact fingerprint hit allows, never a different target. Terminate one learning or remove one sample.',\n 'card.sedimentEmpty': 'No sedimented rules yet (samples reaching the threshold appear here)',\n 'card.sedimentCount': 'confirmed %n/%t',\n 'card.sedimentStop': 'Terminate',\n 'card.sedimentStopTitle': \"Terminate this learning (drops the count and samples)\",\n 'card.sedimentStopConfirm': \"Terminate learning for '%k'? Its count and samples are dropped.\",\n 'card.sedimentSampleRemove': 'Remove this sedimented sample',\n 'card.llmSource': 'Receiver source',\n 'card.llmSourceCustom': 'Custom API (OpenAI-compatible)',\n 'card.llmSourceHost': \"Use the session's current default model (DSH llm service)\",\n 'card.llmSourceHostHint': 'By default approval grading runs on the model group the DSH session currently uses (the effective value is shown below); leave Provider / Model empty to follow the session, or pick from the dropdown or type to pin one — custom groups you configured in DSH (e.g. local-35b) appear automatically.',\n 'card.llmProvider': 'Provider (empty = follow the session selection)',\n 'card.llmProviderPlaceholder': 'Follow the session selection',\n 'card.llmModelHostPlaceholder': 'Empty = follow the session selection',\n 'card.llmResolved': 'Effective now: %p / %m',\n 'card.llmPreset': 'Endpoint presets (fills the fields; still editable)',\n 'card.llmPresetChoose': 'Pick a preset…',\n 'card.llmPresetPublic': 'Public API presets',\n 'card.llmPresetHost': 'DSH model groups (selecting one switches to the session receiver)',\n 'card.networkEnabled': 'Network interception (networkEnabled)',\n 'card.networkEnabledHint': 'When on, starts a local proxy that intercepts outbound subprocess connections and applies allow/deny rules. Off = zero behavior change.',\n 'card.watch': 'Rule hot-reload (watch)',\n 'card.watchHint': 'When on, automatically watches rule files for changes and applies them instantly without manual reload.',\n 'card.networkRebindNote': 'Takes effect immediately — the proxy rebinds automatically, no plugin reload needed.',\n 'card.networkInjectEnv': 'Inject proxy environment (networkInjectEnv)',\n 'card.networkInjectEnvHint': 'Writes HTTP(S)_PROXY / ALL_PROXY for subprocesses (and clears NO_PROXY). Off = the listener runs but no process environment is changed.',\n 'card.healthStale': \"Host route unavailable (404) — the node half is still an old build; fully restart dsh (not just the browser page) and retry.\",\n 'card.healthTest': 'Health test',\n 'card.healthRunning': 'Testing…',\n 'card.healthOk': 'OK (%ms ms)',\n 'card.healthFail': 'Failed: ',\n 'history.tag.learned': 'Learned',\n 'history.tag.manualApproved': 'Approved',\n 'history.tag.manualRejected': 'Rejected',\n 'history.tag.manualCancelled': 'Cancelled',\n 'history.tag.standDown': 'Gate off',\n 'history.learnedProgress': 'learned %n/%t',\n 'history.snapshots': 'diff snapshots',\n 'history.clearSession': 'Clear this session',\n 'history.clearAll': 'Clear all',\n 'history.clearSessionTitle': 'Clear only this session\\u2019s diff snapshots (other sessions untouched)',\n 'history.clearAllTitle': 'Clear diff snapshots for every session, including ones never reviewed — asks again',\n 'history.clearSessionConfirm': 'Clear this session\\u2019s diff snapshots? Only the change-comparison data produced by this session\\u2019s approvals is removed; the approval records stay.',\n 'history.clearAllConfirm': 'Clear diff snapshots for ALL sessions? This may delete change comparisons other sessions have not reviewed yet, and cannot be undone.',\n 'history.diffTitle': 'File change comparison',\n 'history.diffClose': 'Close',\n 'history.diffLoading': 'Loading…',\n 'history.diffEmpty': 'No content change (or the file is unreadable)',\n 'history.diffLoadFail': 'Failed to load diff: ',\n 'history.diffRevert': 'Revert this change',\n 'history.diffReverting': 'Sending…',\n 'history.diffRevertDone': 'Revert instruction sent',\n 'history.diffRevertSent': 'Revert instruction sent to the conversation; the AI will restore the file accordingly',\n 'history.diffRevertFail': 'Send failed: ',\n 'history.diffNoSnapshot': 'This event has no snapshot for that file',\n 'history.diffChipTitle': 'View this file\\u2019s change comparison',\n 'history.diffStats': '+%a / -%r lines changed · %c unchanged',\n 'history.diffGone': ' (file no longer exists)',\n 'history.diffHidden': '%n unmodified lines',\n 'card.dryRun': 'Rule test',\n 'card.dryRunHint': 'Judge one call against the rules in force. Runs no tool and writes no rule — check a rule here before you change it.',\n 'card.dryRunTool': 'Tool',\n 'card.dryRunCommand': 'Command / arguments',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'Test',\n 'card.dryRunRunning': 'Judging…',\n 'card.dryRunEmpty': 'Nothing tested yet. Fill in a tool and command, then press Test to see how it would be judged.',\n 'card.dryRunVerdict': 'Verdict',\n 'card.dryRunAllow': 'allow',\n 'card.dryRunAsk': 'ask',\n 'card.dryRunDeny': 'deny',\n 'card.dryRunRule': 'Matched rule',\n 'card.dryRunRuleNone': 'no rule matched; defaultAction: %d',\n 'card.dryRunDimensions': 'Dimensions',\n 'card.dryRunReason': 'Reason',\n 'card.dryRunNote': '\"Matched rule\" comes from the rule layer. When the verdict was produced by an earlier hard-deny or by the keyword blacklist there is no rule index — the dimensions listed are then informational only.',\n 'card.dryRunNoRules': '(0 rules loaded — check the rulesFile path)',\n 'card.dryRunFail': 'Test failed: ',\n 'card.dryRunStale': 'route missing (plugin not restarted?)',\n 'card.rules': 'Settings Built-in Rules',\n 'card.rulesHint': 'The rules the gate is loading right now (from this plugin entry\\'s `rules` config field; falls back to the rules file when unset). Read-only — nothing here can change them. To change rules, use the allowlist below or edit them on the settings page.',\n 'card.rulesRefresh': 'Refresh',\n 'card.rulesLoading': 'Reading…',\n 'card.rulesPath': 'Source',\n 'card.rulesNone': 'no rules configured',\n 'card.rulesCounts': 'Rules',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b bytes · %l lines',\n 'card.rulesMissing': 'Rules not found. The gate falls back to its built-in defaults.',\n 'card.rulesTruncated': 'Rules are large; showing the first 512 KB only.',\n 'card.rulesError': 'Load failed: ',\n 'card.rulesStale': 'route missing (plugin not restarted?)',\n 'card.rulesNote': 'Read-only: this panel cannot modify the rules. The allowlist section and \"allow always\" write back to this plugin\\'s entry config.',\n}\n\n/** Japanese dictionary (keys mirror zh). */\nexport const ja: Record<keyof typeof zh, string> = {\n 'card.title': '自动审查(自動審査)ティア',\n 'section.title': '自動審査ゲート',\n 'card.description': 'read-only / full-access / whitelist と並ぶ独立の承認モード。セッション権限ピッカーでは「自动审查」と表示されます。フロントは単一スイッチのみ。バックエンドの 4 つの承認戦略はこのパネルで組み合わせ可能で、P0 ハード拒否に対して依然 fail-closed。',\n 'card.permissive': '自动审查ティアを有効化',\n 'card.permissiveHint': 'オフのときは以前と完全に同じ動作です。',\n 'card.scopeNote': 'プリセットスコープ: このゲートはセッションの権限プリセットが %scope のときだけ動作します。それ以外のプリセットでは P0 ハード拒否を含むゲート全体が停止し、選択されたプリセット自身のポリシーが引き継ぎます。停止時は stand-down イベントを 1 件記録し、入力欄の上に常駐表示します。',\n 'card.strategies': 'バックエンド承認戦略(少なくとも 1 つ有効、組み合わせ可)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — スコープ内の安全操作は自動許可、危険/不明は ask(中間ティアのベースライン)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — すべて ask。承認パネルの「許可コントロール」に2つの拡張ボタン:「このセッションで当該種別を繰り返し許可」(セッション限次 grant)と「すべての発生を許可」(コマンド語を rulesFile の許可リストへ永続化)',\n 'card.strategy.llmAssist': 'llmAssist — カスタム LLM がリスクを判定:safe は自動許可、deletion/credential/remote/system/bulk のハードリスクは人手確認を維持(分類器は決して拒否せず、判断をエスカレートするだけ)、neutral は確認学習へ、失敗/タイムアウトは人手にフォールバック',\n 'card.strategy.trustEscalation': 'trustEscalation — サンドボックス昇格を確認なしで許可:本ゲートが既に許可した呼び出しについて、shell / pwsh / edit がツール内部から要求するサンドボックス拡張をゲートが承認し、プロンプトを出しません',\n 'card.strategy.trustEscalationHint': 'サンドボックス昇格の承認要求は tools/pre-execute の後、ツール本体の内部で発行されるためゲートには見えず、LLM が safe と判定して自動許可した呼び出しでも拡張の承認を求められていました。オンにすると、ゲートが実際に許可した同一呼び出し(callId で厳密一致)だけがプロンプトを省略し、それ以外は従来どおり人手に回ります。理由を認識できない場合や対象が workspace-write / danger-full-access 以外の場合も同様です。オフにすると拡張は常に人手の判断となります。',\n 'card.readonly': '読み取り専用',\n 'card.unavailable': '設定名前空間が利用できません:dsh-perm-gate がこの profile に組み込まれているか確認してください。',\n 'card.llmReceiver': 'llmAssist 受信 LLM(OpenAI 互換、カスタム API 可)',\n 'card.llmEndpoint': 'Endpoint(BaseURL、例:https://api.openai.com/v1)',\n 'card.llmModel': 'Model(モデル id、例:deepseek-chat)',\n 'card.llmKey': 'API Key(機密)',\n 'card.llmKeyHidden': '未設定・初回入力後は * 表示',\n 'card.llmKeyMasked': '設定済み・新しい値を入力すると上書き',\n 'card.llmKeyOverwrite': '機密値が保存されています。新しい値を入力してフォーカスを外すと上書きします。',\n 'card.llmKeyClear': 'クリア',\n 'card.allowlist': '許可リスト(allow、rulesFile と同期)',\n 'card.allowlistHint': 'allow セクションに一致したパターンは直接許可。1 件ずつ追加・削除でき、rulesFile に即時書き込み&再読込します。',\n 'card.allowlistPresetNote': 'プリセット許可リストの等価物は trustAutoAllow 戦略(スコープ内の安全操作を自動許可)で、上の戦略セクションで有効化します。このリストは rulesFile の allow を反映するため、初期は空で正常です。',\n 'card.allowlistEmpty': '許可ルールはありません',\n 'card.allowlistPlaceholder': '新しいコマンドパターン、例:npm test*',\n 'card.allowlistAdd': '追加',\n 'card.allowlistRemove': 'このパターンを削除',\n 'card.allowlistBulk': '一括編集',\n 'card.allowlistBulkHide': '一括編集を閉じる',\n 'card.allowlistSave': '許可リストを保存',\n 'card.riskLearning': 'riskLearning — 裁決学習:neutral リスク操作が人手で承認され実行されるとカウントし、しきい値到達後は同一操作(指紋一致)のみ自動許可',\n 'card.riskLearningHint': '学習状態はプラグイン所有($DSH_HOME/perm-gate/learning.json)で、YAML ルールには書き込みません。別の対象は決して権限を再利用しません。既定はオフ。',\n 'card.riskThreshold': '自動許可に必要な人手確認回数(1–10)',\n 'notice.label': '権限ゲートの活動',\n 'history.label': '承認記録',\n 'history.title': '権限承認記録',\n 'history.subtitle': 'このセッションでのゲート判定のすべて(新しい順)',\n 'history.loading': '読み込み中…',\n 'history.empty': 'このセッションにはまだ承認記録がありません',\n 'history.error': '読み込み失敗:',\n 'history.tag.auto': '自動許可',\n 'history.tag.ask': '人手へ',\n 'history.tag.deny': '拒否',\n 'card.denylistRestore': 'プリセットの拒否キーワードに戻す',\n 'card.denylist': '拒否キーワード(deny、プリセット)',\n 'card.denylistHint': 'キーワード(大小文字を区別しない部分一致)を含む呼び出しは、許可リスト / 許可 / LLM より先に拒否されます。プリセットは dsh-approval-gate から継承し、導入直後から有効。空または未設定ならプリセットを適用(ワンクリック復元対応)し、黑名単が静かに無効化されることはありません。',\n 'card.denylistEmpty': '拒否キーワードは空です(キーワード層で拒否される呼び出しはありません)',\n 'card.denylistPlaceholder': '新しいキーワード、例:drop database',\n 'card.denylistAdd': '追加',\n 'card.denylistRemove': 'このキーワードを削除',\n 'card.denylistTagPreset': 'プリセット',\n 'card.denylistTagCustom': 'カスタム',\n 'card.riskSediment': 'riskSediment — 学習沈殿:しきい値に達したサンプルが決定論的な自動許可ルールに',\n 'card.riskSedimentHint': 'オンにすると、tool|category キーの確認がしきい値に達した時点でサンプル指紋が許可ルールとして沈殿します。同一ツール・同一ターゲットの正確一致は LLM を経由せず自動許可(llmAssist オフでも継続)。',\n 'card.sediment': '学習沈殿(決定論的許可ルール)',\n 'card.sedimentHint': '人手確認から沈殿したルール:指紋が正確に一致したときのみ許可。別の対象は決して再利用しません。学習の終止やサンプル削除ができます。',\n 'card.sedimentEmpty': '沈殿ルールはまだありません(しきい値に達したサンプルがここに表示されます)',\n 'card.sedimentCount': '確認済み %n/%t',\n 'card.sedimentStop': '終止',\n 'card.sedimentStopTitle': 'この学習を終止する(カウントとサンプルを削除)',\n 'card.sedimentStopConfirm': '「%k」の学習を終止しますか?カウントと全サンプルを削除します。',\n 'card.sedimentSampleRemove': 'この沈殿サンプルを削除',\n 'card.llmSource': '受信 LLM のソース',\n 'card.llmSourceCustom': 'カスタム API(OpenAI 互換)',\n 'card.llmSourceHost': 'セッションの現在の既定モデルを使用(DSH llm サービス)',\n 'card.llmSourceHostHint': '既定では DSH セッションで現在选择中のモデルグループで審査判定を実行します(下に現在の実効値を表示)。Provider / Model を空のままにするとセッションに追従し、ドロップダウンから選ぶか手入力で固定できます——DSH で設定したカスタムグループ(例:local-35b)は自動的にリストに現れます。',\n 'card.llmProvider': 'Provider(空 = セッションの現在の選択に追従)',\n 'card.llmProviderPlaceholder': 'セッションの現在の選択に追従',\n 'card.llmModelHostPlaceholder': '空 = セッションの現在の選択に追従',\n 'card.llmResolved': '現在の実効値:%p / %m',\n 'card.llmPreset': 'プリセットエンドポイント(選択で自動入力、後から編集可)',\n 'card.llmPresetChoose': 'プリセットを選択…',\n 'card.llmPresetPublic': '公開 API プリセット',\n 'card.llmPresetHost': 'DSH モデルグループ(選択するとセッション受信へ切替)',\n 'card.networkEnabled': 'ネットワーク傍受(networkEnabled)',\n 'card.networkEnabledHint': 'オンにするとローカルプロキシが起動し、サブプロセスの送信接続を傍受して許可/拒否ルールを適用します。オフにすると動作変更なし。',\n 'card.watch': 'ルールホットリロード(watch)',\n 'card.watchHint': 'オンにするとルールファイルの変更を自動監視し、手動リロードなしで即座に反映されます。',\n 'card.networkRebindNote': '切り替えは即時反映されます(自動で再バインド、プラグイン再読み込み不要)。',\n 'card.networkInjectEnv': 'プロキシ環境変数の注入(networkInjectEnv)',\n 'card.networkInjectEnvHint': 'サブプロセスに HTTP(S)_PROXY / ALL_PROXY を書き込みます(NO_PROXY はクリア)。オフの場合はリスナーのみ起動し、プロセス環境は変更しません。',\n 'card.healthStale': 'ホストルートが利用できません(404)——node 側が旧ビルドです。ページ再読み込みだけでなく dsh を完全に再起動してから再試行してください。',\n 'card.healthTest': '健全性テスト',\n 'card.healthRunning': 'テスト中…',\n 'card.healthOk': '正常(%ms ms)',\n 'card.healthFail': '失敗:',\n 'history.tag.learned': '学習済み',\n 'history.tag.manualApproved': '人手承認',\n 'history.tag.manualRejected': '人手拒否',\n 'history.tag.manualCancelled': '人手キャンセル',\n 'history.tag.standDown': 'ゲート停止',\n 'history.learnedProgress': '学習 %n/%t',\n 'history.snapshots': 'diff スナップショット',\n 'history.clearSession': 'このセッションのみ削除',\n 'history.clearAll': 'すべて削除',\n 'history.clearSessionTitle': 'このセッションの diff スナップショットのみ削除(他のセッションは対象外)',\n 'history.clearAllTitle': '全セッション(未確認のものも含む)の diff スナップショットを削除。再確認あり',\n 'history.clearSessionConfirm': 'このセッションの diff スナップショットを削除しますか?本セッションの承認で生成された変更比較データのみを削除し、承認記録自体には影響しません。',\n 'history.clearAllConfirm': '【全セッション】の diff スナップショットを削除しますか?他のセッションがまだ確認していない変更比較も削除され、復元できません。',\n 'history.diffTitle': 'ファイル変更の比較',\n 'history.diffClose': '閉じる',\n 'history.diffLoading': '読み込み中…',\n 'history.diffEmpty': '内容の変更なし(またはファイルを読み取れません)',\n 'history.diffLoadFail': 'diff の読み込みに失敗:',\n 'history.diffRevert': 'この変更を元に戻す',\n 'history.diffReverting': '送信中…',\n 'history.diffRevertDone': '取り消し指示を送信しました',\n 'history.diffRevertSent': '取り消し指示を会話に送信しました。AI が指示に従ってファイルを復元します',\n 'history.diffRevertFail': '送信に失敗:',\n 'history.diffNoSnapshot': 'このイベントには該当ファイルのスナップショットがありません',\n 'history.diffChipTitle': 'このファイルの変更比較を表示',\n 'history.diffStats': '+%a / -%r 行変更 · %c 行は未変更',\n 'history.diffGone': '(ファイルは現在存在しません)',\n 'history.diffHidden': '%n 行は未変更',\n 'card.dryRun': 'ルールテスト',\n 'card.dryRunHint': '現在有効なルールで 1 回の呼び出しを判定します。ツールは実行せず、ルールも書き換えません。ルールを変更する前にここで確認してください。',\n 'card.dryRunTool': 'ツール名',\n 'card.dryRunCommand': 'コマンド / 引数',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'テスト',\n 'card.dryRunRunning': '判定中…',\n 'card.dryRunEmpty': 'まだテストしていません。ツール名とコマンドを入力し「テスト」を押すと、どう判定されるか確認できます。',\n 'card.dryRunVerdict': '判定',\n 'card.dryRunAllow': '許可',\n 'card.dryRunAsk': '要確認',\n 'card.dryRunDeny': '拒否',\n 'card.dryRunRule': '一致したルール',\n 'card.dryRunRuleNone': '一致するルールなし。defaultAction:%d',\n 'card.dryRunDimensions': '制約次元',\n 'card.dryRunReason': '理由',\n 'card.dryRunNote': '「一致したルール」はルール層の結果です。判定がより前段のハード拒否やキーワードブラックリストによる場合、ルール番号はありません——その場合の次元表示は参考情報です。',\n 'card.dryRunNoRules': '(読み込まれたルールは 0 件:rulesFile のパスを確認してください)',\n 'card.dryRunFail': 'テスト失敗:',\n 'card.dryRunStale': 'ルートが存在しません(プラグイン未再起動?)',\n 'card.rules': 'Settings 組み込みルール',\n 'card.rulesHint': 'ゲートが今読み込んでいるルール(本プラグインエントリの rules 設定フィールドから。未設定時はルールファイルにフォールバック)。読み取り専用 — 変更するには下の許可リストか設定ページを使ってください。',\n 'card.rulesRefresh': '再読み込み',\n 'card.rulesLoading': '読み込み中…',\n 'card.rulesPath': 'ソース',\n 'card.rulesNone': 'ルールが設定されていません',\n 'card.rulesCounts': 'ルール',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b バイト · %l 行',\n 'card.rulesMissing': 'ルールが存在しません。ゲートは組み込みの既定値にフォールバックします。',\n 'card.rulesTruncated': 'ルールが大きいため、先頭 512 KB のみ表示します。',\n 'card.rulesError': '読み込みに失敗しました:',\n 'card.rulesStale': 'ルートが存在しません(プラグイン未再起動?)',\n 'card.rulesNote': '読み取り専用:このパネルからルールは変更できません。許可リストと「常に許可」は本プラグインのエントリ設定に書き戻されます。',\n}\n\n/** Korean dictionary (keys mirror zh). */\nexport const ko: Record<keyof typeof zh, string> = {\n 'card.title': '自动审查(자동 검토) 티어',\n 'section.title': '자동 검토 게이트',\n 'card.description': 'read-only / full-access / whitelist와 나란한 독립 승인 모드. 세션 권한 선택기에서는 「自动审查」로 표시됩니다. 프론트는 단일 스위치만 노출. 백엔드의 네 가지 승인 전략은 이 패널에서 조합 가능하며 P0 하드 거부에 대해 여전히 fail-closed.',\n 'card.permissive': '自动审查 티어 활성화',\n 'card.permissiveHint': '꺼져 있으면 이전과 완전히 동일하게 동작합니다.',\n 'card.scopeNote': '프리셋 범위: 이 게이트는 세션 권한 프리셋이 %scope일 때만 동작합니다. 다른 프리셋에서는 P0 하드 거부를 포함한 게이트 전체가 정지하고, 선택된 프리셋 자체의 정책이 대신합니다. 정지 시 stand-down 이벤트가 1건 기록되고 입력창 위에 상시 표시됩니다.',\n 'card.strategies': '백엔드 승인 전략(하나 이상 유효, 조합 가능)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — 범위 내 안전 작업은 자동 허용, 위험/미확인은 ask(중간 티어 기준)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — 모든 경계를 ask. 승인 패널의「허용 컨트롤」에 두 개의 확장 버튼:「이 세션에서 해당 유형 반복 허용」(세션 제한 grant) 과「모든 발생 허용」(명령어를 rulesFile 허용 목록에 영구 추가)',\n 'card.strategy.llmAssist': 'llmAssist — 사용자 지정 LLM이 위험을 판정: safe는 자동 허용, deletion/credential/remote/system/bulk 하드 위험은 사람 확인 유지(분류기는 결코 거부하지 않고 판단을 에스컬레이션만 합니다), neutral은 확인 학습으로, 실패/시간 초과는 사람에게 폴백',\n 'card.strategy.trustEscalation': 'trustEscalation — 샌드박스 승격 무확인: 이 게이트가 이미 허용한 호출에 대해 shell / pwsh / edit 이 도구 내부에서 요청하는 샌드박스 확장을 게이트가 승인하고 프롬프트를 띄우지 않습니다',\n 'card.strategy.trustEscalationHint': '샌드박스 승격 승인 요청은 tools/pre-execute 이후 도구 본체 내부에서 발생하므로 게이트가 보지 못했고, LLM이 safe로 판정해 자동 허용한 호출에도 확장 승인을 물었습니다. 켜면 게이트가 실제로 허용한 동일 호출(callId 정확 일치)만 프롬프트를 건너뛰고, 나머지는 이전과 같이 사람에게 전달됩니다. 이유를 인식할 수 없거나 대상이 workspace-write / danger-full-access 가 아닌 경우도 마찬가지입니다. 끄면 확장은 항상 사람이 판단합니다.',\n 'card.readonly': '읽기 전용',\n 'card.unavailable': '설정 네임스페이스를 사용할 수 없습니다: dsh-perm-gate가 이 profile에 조립되었는지 확인하세요.',\n 'card.llmReceiver': 'llmAssist 수신 LLM (OpenAI 호환, 사용자 지정 API 가능)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, 예: https://api.openai.com/v1)',\n 'card.llmModel': 'Model (모델 id, 예: deepseek-chat)',\n 'card.llmKey': 'API Key (비밀)',\n 'card.llmKeyHidden': '미설정 · 최초 입력 후 * 표시',\n 'card.llmKeyMasked': '설정됨 · 새 값을 입력하면 덮어씀',\n 'card.llmKeyOverwrite': '비밀 값이 저장되어 있습니다. 새 값을 입력하고 포커스를 벗어나면 덮어씁니다.',\n 'card.llmKeyClear': '지우기',\n 'card.allowlist': '허용 목록(allow, rulesFile과 동기화)',\n 'card.allowlistHint': 'allow 섹션과 일치하는 패턴은 바로 허용됩니다. 항목을 하나씩 추가·삭제하면 rulesFile에 즉시 기록 후 다시 적재됩니다.',\n 'card.allowlistPresetNote': '프리셋 허용 목록의 등가물은 trustAutoAllow 전략(범위 내 안전 작업 자동 허용)으로, 위 전략 섹션에서 활성화합니다. 이 목록은 rulesFile의 allow를 반영하므로 초기에 비어 있는 것이 정상입니다.',\n 'card.allowlistEmpty': '허용 규칙이 없습니다',\n 'card.allowlistPlaceholder': '새 명령 패턴, 예: npm test*',\n 'card.allowlistAdd': '추가',\n 'card.allowlistRemove': '이 패턴 삭제',\n 'card.allowlistBulk': '일괄 편집',\n 'card.allowlistBulkHide': '일괄 편집 접기',\n 'card.allowlistSave': '허용 목록 저장',\n 'card.riskLearning': 'riskLearning — 판정 학습: neutral 위험 요청이 사람의 승인과 실행까지 완료되면 카운트되며, 임계값 도달 후 동일 작업(지문 일치)만 자동 허용',\n 'card.riskLearningHint': '학습 상태는 플러그인 소유($DSH_HOME/perm-gate/learning.json)이며 YAML 규칙에는 기록하지 않습니다. 다른 대상은 권한을 재사용하지 않습니다. 기본값은 꺼짐.',\n 'card.riskThreshold': '자동 허용 전 필요한 사람 확인 횟수(1–10)',\n 'notice.label': '권한 게이트 활동',\n 'history.label': '승인 기록',\n 'history.title': '권한 승인 기록',\n 'history.subtitle': '이 세션에서 게이트가 판정한 모든 기록(최신 순)',\n 'history.loading': '불러오는 중…',\n 'history.empty': '이 세션에는 아직 승인 기록이 없습니다',\n 'history.error': '불러오기 실패: ',\n 'history.tag.auto': '자동 허용',\n 'history.tag.ask': '사람에게',\n 'history.tag.deny': '거부',\n 'card.denylistRestore': '프리셋 블랙리스트로 복원',\n 'card.denylist': '블랙리스트(deny 키워드, 플러그인 프리셋)',\n 'card.denylistHint': '키워드(대소문자 구분 없는 부분 일치)를 포함한 호출은 허용 목록/권한/LLM보다 먼저 거부됩니다. 프리셋은 dsh-approval-gate에서 계승되어 설치 즉시 활성화되며, 비어 있거나 미설정이면 프리셋이 적용됩니다(원클릭 복원 지원). 블랙리스트가 조용히 꺼지는 일은 없습니다.',\n 'card.denylistEmpty': '블랙리스트가 비어 있음(키워드 계층에서 거부되는 호출 없음)',\n 'card.denylistPlaceholder': '새 키워드, 예: drop database',\n 'card.denylistAdd': '추가',\n 'card.denylistRemove': '이 키워드 삭제',\n 'card.denylistTagPreset': '프리셋',\n 'card.denylistTagCustom': '사용자 지정',\n 'card.riskSediment': 'riskSediment — 학습 침전: 임계값에 도달한 샘플이 결정론적 자동 허용 규칙으로',\n 'card.riskSedimentHint': '켜면 tool|category 키의 확인이 임계값에 도달한 시점에 샘플 지문이 허용 규칙으로 침전됩니다. 동일 도구·동일 대상의 정확 일치는 LLM 없이 바로 허용(llmAssist가 꺼져도 유지).',\n 'card.sediment': '학습 침전(결정론적 허용 규칙)',\n 'card.sedimentHint': '사람의 확인에서 침전된 규칙: 지문이 정확히 일치할 때만 허용되며 다른 대상은 절대 재사용하지 않습니다. 학습 종료 또는 샘플 삭제가 가능합니다.',\n 'card.sedimentEmpty': '아직 침전 규칙이 없습니다(임계값에 도달한 샘플이 여기에 표시됩니다)',\n 'card.sedimentCount': '확인 %n/%t',\n 'card.sedimentStop': '종료',\n 'card.sedimentStopTitle': '이 학습 종료(카운트와 샘플 삭제)',\n 'card.sedimentStopConfirm': \"'%k' 학습을 종료합니까? 카운트와 모든 샘플이 삭제됩니다.\",\n 'card.sedimentSampleRemove': '이 침전 샘플 삭제',\n 'card.llmSource': '수신 LLM 소스',\n 'card.llmSourceCustom': '사용자 지정 API(OpenAI 호환)',\n 'card.llmSourceHost': '세션의 현재 기본 모델 사용(DSH llm 서비스)',\n 'card.llmSourceHostHint': '기본적으로 DSH 세션에서 현재 선택한 모델 그룹으로 승인 판정을 수행합니다(아래에 실제 적용값 표시). Provider / Model을 비우면 세션 선택을 따르며, 드롭다운에서 선택하거나 직접 입력해 고정할 수 있습니다——DSH에 설정한 사용자 지정 그룹(예: local-35b)은 목록에 자동으로 나타납니다.',\n 'card.llmProvider': 'Provider(비움 = 세션 현재 선택 따름)',\n 'card.llmProviderPlaceholder': '세션 현재 선택 따름',\n 'card.llmModelHostPlaceholder': '비움 = 세션 현재 선택 따름',\n 'card.llmResolved': '현재 적용: %p / %m',\n 'card.llmPreset': '프리셋 엔드포인트(선택 시 자동 채움, 이후 편집 가능)',\n 'card.llmPresetChoose': '프리셋 선택…',\n 'card.llmPresetPublic': '공개 API 프리셋',\n 'card.llmPresetHost': 'DSH 모델 그룹(선택 시 세션 수신으로 전환)',\n 'card.networkEnabled': '네트워크 가로채기 (networkEnabled)',\n 'card.networkEnabledHint': '켜면 로컬 프록시가 시작되어 서브프로세스의 아웃바운드 연결을 가로채고 허용/거부 규칙을 적용합니다. 끄면 동작 변경 없음.',\n 'card.watch': '규칙 핫 리로드 (watch)',\n 'card.watchHint': '켜면 규칙 파일 변경을 자동 감시하여 수동 리로드 없이 즉시 적용됩니다.',\n 'card.networkRebindNote': '전환 즉시 적용됩니다(자동 재바인딩, 플러그인 리로드 불필요).',\n 'card.networkInjectEnv': '프록시 환경 변수 주입 (networkInjectEnv)',\n 'card.networkInjectEnvHint': '서브프로세스에 HTTP(S)_PROXY / ALL_PROXY를 기록합니다(NO_PROXY는 비움). 끄면 리스너만 실행되고 프로세스 환경은 변경되지 않습니다.',\n 'card.healthStale': '호스트 라우트를 사용할 수 없음(404)——node 측이 이전 빌드입니다. 페이지 새로고침이 아니라 dsh를 완전히 재시작한 후 다시 시도하세요.',\n 'card.healthTest': '상태 테스트',\n 'card.healthRunning': '테스트 중…',\n 'card.healthOk': '정상(%ms ms)',\n 'card.healthFail': '실패: ',\n 'history.tag.learned': '학습됨',\n 'history.tag.manualApproved': '사람 승인',\n 'history.tag.manualRejected': '사람 거부',\n 'history.tag.manualCancelled': '사람 취소',\n 'history.tag.standDown': '게이트 정지',\n 'history.learnedProgress': '학습 %n/%t',\n 'history.snapshots': 'diff 스냅샷',\n 'history.clearSession': '이 세션만 삭제',\n 'history.clearAll': '전체 삭제',\n 'history.clearSessionTitle': '이 세션의 diff 스냅샷만 삭제(다른 세션은 그대로)',\n 'history.clearAllTitle': '모든 세션(아직 확인하지 않은 것 포함)의 diff 스냅샷을 삭제. 재확인 필요',\n 'history.clearSessionConfirm': '이 세션의 diff 스냅샷을 삭제합니까? 이 세션의 승인으로 생성된 변경 비교 데이터만 삭제하며 승인 기록 자체는 유지됩니다.',\n 'history.clearAllConfirm': '【모든 세션】의 diff 스냅샷을 삭제합니까? 다른 세션이 아직 확인하지 않은 변경 비교도 삭제되며 복구할 수 없습니다.',\n 'history.diffTitle': '파일 변경 비교',\n 'history.diffClose': '닫기',\n 'history.diffLoading': '불러오는 중…',\n 'history.diffEmpty': '내용 변경 없음(또는 파일을 읽을 수 없음)',\n 'history.diffLoadFail': 'diff 불러오기 실패: ',\n 'history.diffRevert': '이 변경 되돌리기',\n 'history.diffReverting': '전송 중…',\n 'history.diffRevertDone': '되돌리기 지시를 보냈습니다',\n 'history.diffRevertSent': '되돌리기 지시를 대화로 보냈습니다. AI가 지시에 따라 파일을 복원합니다',\n 'history.diffRevertFail': '전송 실패: ',\n 'history.diffNoSnapshot': '이 이벤트에는 해당 파일의 스냅샷이 없습니다',\n 'history.diffChipTitle': '이 파일의 변경 비교 보기',\n 'history.diffStats': '+%a / -%r 행 변경 · %c 행 미변경',\n 'history.diffGone': ' (파일이 더 이상 존재하지 않음)',\n 'history.diffHidden': '%n 행 미변경',\n 'card.dryRun': '규칙 테스트',\n 'card.dryRunHint': '현재 적용 중인 규칙으로 호출 한 건을 판정합니다. 도구를 실행하지 않고 규칙도 쓰지 않습니다. 규칙을 바꾸기 전에 여기서 먼저 확인하세요.',\n 'card.dryRunTool': '도구 이름',\n 'card.dryRunCommand': '명령 / 인수',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': '테스트',\n 'card.dryRunRunning': '판정 중…',\n 'card.dryRunEmpty': '아직 테스트하지 않았습니다. 도구 이름과 명령을 입력하고 「테스트」를 누르면 어떻게 판정되는지 볼 수 있습니다.',\n 'card.dryRunVerdict': '판정',\n 'card.dryRunAllow': '허용',\n 'card.dryRunAsk': '확인 필요',\n 'card.dryRunDeny': '거부',\n 'card.dryRunRule': '일치한 규칙',\n 'card.dryRunRuleNone': '일치하는 규칙 없음, defaultAction: %d',\n 'card.dryRunDimensions': '제약 차원',\n 'card.dryRunReason': '이유',\n 'card.dryRunNote': '「일치한 규칙」은 규칙 계층의 결과입니다. 판정이 더 앞선 하드 거부나 키워드 블랙리스트에서 나온 경우 규칙 번호가 없습니다——그때의 차원 표시는 참고용입니다.',\n 'card.dryRunNoRules': '(로드된 규칙 0건: rulesFile 경로를 확인하세요)',\n 'card.dryRunFail': '테스트 실패: ',\n 'card.dryRunStale': '라우트가 없습니다(플러그인 미재시작?)',\n 'card.rules': 'Settings 내장 규칙',\n 'card.rulesHint': '게이트가 지금 불러오는 규칙(이 플러그인 엔트리의 rules 설정 필드에서. 미설정 시 규칙 파일로 폴백). 읽기 전용 — 아래 허용 목록이나 설정 페이지에서 수정하세요.',\n 'card.rulesRefresh': '새로 고침',\n 'card.rulesLoading': '읽는 중…',\n 'card.rulesPath': '소스',\n 'card.rulesNone': '규칙이 설정되지 않았습니다',\n 'card.rulesCounts': '규칙',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b 바이트 · %l 줄',\n 'card.rulesMissing': '규칙이 없습니다. 게이트는 내장 기본값으로 대체합니다.',\n 'card.rulesTruncated': '규칙이 커서 앞 512 KB만 표시합니다.',\n 'card.rulesError': '불러오기 실패: ',\n 'card.rulesStale': '라우트가 없습니다(플러그인 미재시작?)',\n 'card.rulesNote': '읽기 전용: 이 패널은 규칙을 수정할 수 없습니다. 허용 목록과 \"항상 허용\"은 이 플러그인의 엔트리 설정에 기록됩니다.',\n}\n/** French dictionary (keys mirror zh). */\nexport const fr: Record<PermissiveKey, string> = {\n 'card.title': 'Examen automatique',\n 'section.title': 'Porte d\\'examen automatique',\n 'card.description': 'Niveau d\\'approbation indépendant : parallèle à lecture seule / accès complet / liste blanche, affiché comme « Examen automatique » dans le sélecteur de permissions de session. Le front-end n\\'expose qu\\'un seul interrupteur ; les quatre stratégies d\\'approbation backend sont combinables via ce panneau et restent fail-closed contre le refus dur P0.',\n 'card.permissive': 'Activer le niveau d\\'examen automatique',\n 'card.permissiveHint': 'Lorsqu\\'il est désactivé, la porte se comporte exactement comme avant.',\n 'card.scopeNote': 'Portée du préréglage : cette porte n\\'agit que lorsque le préréglage de permission de session est %scope. Sous tout autre préréglage, la porte entière se met en veille — y compris le refus dur P0 — et la politique du préréglage sélectionné prend le relais. La mise en veille enregistre un événement et affiche une bande persistante au-dessus de la saisie.',\n 'card.strategies': 'Stratégies d\\'approbation backend (au moins une active ; combinables)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — les opérations sûres dans le périmètre sont auto-autorisées ; dangereuses/inconnues → demande (niveau intermédiaire de base)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — chaque passage demande ; les « contrôles d\\'autorisation » du panneau d\\'approbation ajoutent deux boutons étendus : « répéter l\\'autorisation pour ce type cette session » (grant borné de session) et « autoriser toutes les occurrences » (persistance du mot de commande dans la liste blanche rulesFile)',\n 'card.strategy.llmAssist': 'llmAssist — un LLM personnalisé évalue le risque : safe → auto-autorisation ; deletion/credential/remote/system/bulk → risques durs maintiennent la demande humaine (le classifieur ne refuse jamais — il ne fait qu\\'escalader) ; neutral → apprentissage par confirmation ; échec/timeout → retour à l\\'humain',\n 'card.strategy.trustEscalation': 'trustEscalation — escalade sandbox sans invite : pour un appel déjà autorisé par cette porte, l\\'élargissement sandbox initié par shell / pwsh / edit depuis l\\'intérieur de l\\'outil est approuvé ici au lieu de vous le demander',\n 'card.strategy.trustEscalationHint': 'L\\'approbation d\\'escalade sandbox est demandée depuis l\\'intérieur du corps de l\\'outil, après tools/pre-execute, donc la porte ne la voit jamais — un appel que le LLM a jugé sûr et que la porte a auto-autorisé vous demandait quand même d\\'approuver l\\'élargissement. Activé, seul l\\'appel exact que la porte a autorisé (correspondance par callId) ignore l\\'invite ; tout le reste passe à l\\'humain comme avant, ainsi que toute raison non reconnue ou cible autre que workspace-write / danger-full-access. Désactivez pour garder l\\'élargissement sous contrôle humain.',\n 'card.readonly': 'Lecture seule',\n 'card.unavailable': 'Espace de noms des paramètres indisponible : assurez-vous que dsh-perm-gate est assemblé dans ce profil.',\n 'card.llmReceiver': 'LLM récepteur llmAssist (compatible OpenAI ; API personnalisée possible)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, ex. https://api.openai.com/v1)',\n 'card.llmModel': 'Model (identifiant du modèle, ex. deepseek-chat)',\n 'card.llmKey': 'API Key (secret)',\n 'card.llmKeyHidden': 'Non défini · affiché comme * après la première saisie',\n 'card.llmKeyMasked': 'Défini · saisir une nouvelle valeur pour écraser',\n 'card.llmKeyOverwrite': 'Une valeur secrète est stockée ; saisissez une nouvelle valeur et quittez le champ pour l\\'écraser.',\n 'card.llmKeyClear': 'Effacer',\n 'card.allowlist': 'Liste blanche (allow, synchronisée avec rulesFile)',\n 'card.allowlistHint': 'Les motifs correspondant à la section allow sont directement autorisés ; ajoutez ou supprimez des entrées une par une, écrites dans rulesFile et rechargées en direct.',\n 'card.allowlistPresetNote': 'L\\'équivalent de la liste blanche prédéfinie est la stratégie trustAutoAllow (opérations sûres dans le périmètre auto-autorisées), activée dans la section stratégies ci-dessus ; cette liste reflète votre section allow de rulesFile et démarre légitimement vide.',\n 'card.allowlistEmpty': 'Aucune règle de liste blanche',\n 'card.allowlistPlaceholder': 'Nouveau motif de commande, ex. npm test*',\n 'card.allowlistAdd': 'Ajouter',\n 'card.allowlistRemove': 'Supprimer ce motif',\n 'card.allowlistBulk': 'Édition groupée',\n 'card.allowlistBulkHide': 'Masquer l\\'édition groupée',\n 'card.allowlistSave': 'Enregistrer la liste blanche',\n 'card.riskLearning': 'riskLearning — apprentissage de verdict : les opérations à risque neutral approuvées et exécutées sont comptées ; la même opération est auto-autorisée au seuil avec une empreinte correspondante',\n 'card.riskLearningHint': 'L\\'état d\\'apprentissage appartient au plugin ($DSH_HOME/perm-gate/learning.json) et n\\'est jamais écrit dans vos règles YAML ; une cible différente ne réutilise jamais l\\'autorité. Désactivé par défaut.',\n 'card.riskThreshold': 'Confirmations humaines requises avant auto-autorisation (1–10)',\n 'notice.label': 'Activité de la porte de permission',\n 'history.label': 'Approbations',\n 'history.title': 'Historique des approbations de permission',\n 'history.subtitle': 'Chaque décision de la porte dans cette session, les plus récentes d\\'abord',\n 'history.loading': 'Chargement…',\n 'history.empty': 'Aucun enregistrement d\\'approbation dans cette session',\n 'history.error': 'Échec du chargement : ',\n 'history.tag.auto': 'Auto-autorisé',\n 'history.tag.ask': 'Demandé',\n 'history.tag.deny': 'Refusé',\n 'card.denylistRestore': 'Restaurer la liste noire prédéfinie',\n 'card.denylist': 'Liste noire (mots-clés deny, prédéfinis par le plugin)',\n 'card.denylistHint': 'Un appel dont le texte contient un mot-clé (sous-chaîne insensible à la casse) est refusé immédiatement, avant liste blanche / grants / LLM. La liste prédéfinie hérite de dsh-approval-gate et est active dès l\\'installation ; modifiez librement — vide ou effacée, retour au préréglage (restauration en un clic), donc la liste noire ne se désactive jamais silencieusement.',\n 'card.denylistEmpty': 'Liste noire vide (aucun appel n\\'est rejeté par la couche de mots-clés)',\n 'card.denylistPlaceholder': 'Nouveau mot-clé, ex. drop database',\n 'card.denylistAdd': 'Ajouter',\n 'card.denylistRemove': 'Supprimer ce mot-clé',\n 'card.denylistTagPreset': 'Prédéfini',\n 'card.denylistTagCustom': 'Personnalisé',\n 'card.riskSediment': 'riskSediment — sédimentation d\\'apprentissage : les échantillons ayant atteint le seuil deviennent des règles d\\'auto-autorisation déterministes',\n 'card.riskSedimentHint': 'Activé, lorsqu\\'une clé tool|category atteint le seuil, ses empreintes d\\'échantillons se sédimentent en règles d\\'autorisation — une correspondance exacte même outil/même cible autorise directement sans autre appel LLM (continue de fonctionner avec llmAssist désactivé).',\n 'card.sediment': 'Sédiment d\\'apprentissage (règles d\\'autorisation déterministes)',\n 'card.sedimentHint': 'Règles sédimentées à partir des confirmations humaines : seule une correspondance exacte d\\'empreinte autorise, jamais une cible différente. Terminez un apprentissage ou supprimez un échantillon.',\n 'card.sedimentEmpty': 'Aucune règle sédimentée pour l\\'instant (les échantillons atteignant le seuil apparaissent ici)',\n 'card.sedimentCount': 'confirmé %n/%t',\n 'card.sedimentStop': 'Terminer',\n 'card.sedimentStopTitle': 'Terminer cet apprentissage (supprime le compteur et les échantillons)',\n 'card.sedimentStopConfirm': 'Terminer l\\'apprentissage pour « %k » ? Son compteur et tous ses échantillons seront supprimés.',\n 'card.sedimentSampleRemove': 'Supprimer cet échantillon sédimenté',\n 'card.llmSource': 'Source du LLM récepteur',\n 'card.llmSourceCustom': 'API personnalisée (compatible OpenAI)',\n 'card.llmSourceHost': 'Utiliser le modèle par défaut actuel de la session (service DSH llm)',\n 'card.llmSourceHostHint': 'Par défaut, l\\'évaluation d\\'approbation utilise le groupe de modèles actuellement sélectionné dans la session DSH (la valeur effective est affichée ci-dessous) ; laissez Provider / Model vide pour suivre la session, ou choisissez dans la liste déroulante ou saisissez pour épingler — vos groupes personnalisés configurés dans DSH (ex. local-35b) apparaissent automatiquement.',\n 'card.llmProvider': 'Provider (vide = suit la sélection de session)',\n 'card.llmProviderPlaceholder': 'Suit la sélection de session',\n 'card.llmModelHostPlaceholder': 'Vide = suit la sélection de session',\n 'card.llmResolved': 'Effectif actuellement : %p / %m',\n 'card.llmPreset': 'Préréglages d\\'endpoint (remplit les champs ; modifiable ensuite)',\n 'card.llmPresetChoose': 'Choisir un préréglage…',\n 'card.llmPresetPublic': 'Préréglages d\\'API publiques',\n 'card.llmPresetHost': 'Groupes de modèles DSH (la sélection bascule vers le récepteur de session)',\n 'card.networkEnabled': 'Interception réseau (networkEnabled)',\n 'card.networkEnabledHint': 'Activé, démarre un proxy local qui intercepte les connexions sortantes des sous-processus et applique les règles d\\'autorisation/refus. Désactivé = aucun changement de comportement.',\n 'card.watch': 'Rechargement à chaud des règles (watch)',\n 'card.watchHint': 'Activé, surveille automatiquement les modifications des fichiers de règles et les applique instantanément sans rechargement manuel.',\n 'card.networkRebindNote': 'Prend effet immédiatement — le proxy se relie automatiquement, pas besoin de recharger le plugin.',\n 'card.networkInjectEnv': 'Injecter les variables d\\'environnement proxy (networkInjectEnv)',\n 'card.networkInjectEnvHint': 'Écrit HTTP(S)_PROXY / ALL_PROXY pour les sous-processus (et vide NO_PROXY). Désactivé = l\\'écouteur fonctionne mais aucun environnement de processus n\\'est modifié.',\n 'card.healthStale': 'Route hôte indisponible (404) — la moitié node est encore une ancienne version ; redémarrez complètement dsh (pas seulement la page du navigateur) et réessayez.',\n 'card.healthTest': 'Test de santé',\n 'card.healthRunning': 'Test en cours…',\n 'card.healthOk': 'OK (%ms ms)',\n 'card.healthFail': 'Échec : ',\n 'history.tag.learned': 'Appris',\n 'history.tag.manualApproved': 'Approuvé',\n 'history.tag.manualRejected': 'Rejeté',\n 'history.tag.manualCancelled': 'Annulé',\n 'history.tag.standDown': 'Porte inactive',\n 'history.learnedProgress': 'appris %n/%t',\n 'history.snapshots': 'instantanés diff',\n 'history.clearSession': 'Effacer cette session',\n 'history.clearAll': 'Tout effacer',\n 'history.clearSessionTitle': 'Effacer uniquement les instantanés diff de cette session (les autres sessions ne sont pas affectées)',\n 'history.clearAllTitle': 'Effacer les instantanés diff de toutes les sessions, y compris celles jamais consultées — demande une reconfirmation',\n 'history.clearSessionConfirm': 'Effacer les instantanés diff de cette session ? Seules les données de comparaison produites par les approbations de cette session sont supprimées ; les enregistrements d\\'approbation restent.',\n 'history.clearAllConfirm': 'Effacer les instantanés diff de TOUTES les sessions ? Cela peut supprimer des comparaisons que d\\'autres sessions n\\'ont pas encore consultées, et c\\'est irréversible.',\n 'history.diffTitle': 'Comparaison des modifications de fichier',\n 'history.diffClose': 'Fermer',\n 'history.diffLoading': 'Chargement…',\n 'history.diffEmpty': 'Aucun changement de contenu (ou fichier illisible)',\n 'history.diffLoadFail': 'Échec du chargement du diff : ',\n 'history.diffRevert': 'Annuler cette modification',\n 'history.diffReverting': 'Envoi…',\n 'history.diffRevertDone': 'Instruction d\\'annulation envoyée',\n 'history.diffRevertSent': 'Instruction d\\'annulation envoyée à la conversation ; l\\'IA restaurera le fichier en conséquence',\n 'history.diffRevertFail': 'Échec de l\\'envoi : ',\n 'history.diffNoSnapshot': 'Cet événement n\\'a pas d\\'instantané pour ce fichier',\n 'history.diffChipTitle': 'Voir la comparaison des modifications de ce fichier',\n 'history.diffStats': '+%a / -%r lignes modifiées · %c inchangées',\n 'history.diffGone': ' (le fichier n\\'existe plus)',\n 'history.diffHidden': '%n lignes non modifiées',\n 'card.dryRun': 'Test de règles',\n 'card.dryRunHint': 'Juge un appel contre les règles en vigueur. N\\'exécute aucun outil et n\\'écrit aucune règle — vérifiez ici avant de modifier.',\n 'card.dryRunTool': 'Outil',\n 'card.dryRunCommand': 'Commande / arguments',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'Tester',\n 'card.dryRunRunning': 'Évaluation…',\n 'card.dryRunEmpty': 'Rien de testé pour l\\'instant. Renseignez un outil et une commande, puis appuyez sur Tester pour voir le verdict.',\n 'card.dryRunVerdict': 'Verdict',\n 'card.dryRunAllow': 'autoriser',\n 'card.dryRunAsk': 'demander',\n 'card.dryRunDeny': 'refuser',\n 'card.dryRunRule': 'Règle correspondante',\n 'card.dryRunRuleNone': 'aucune règle correspondante ; defaultAction : %d',\n 'card.dryRunDimensions': 'Dimensions',\n 'card.dryRunReason': 'Raison',\n 'card.dryRunNote': '« Règle correspondante » provient de la couche de règles. Quand le verdict est produit par un refus dur antérieur ou par la liste noire de mots-clés, il n\\'y a pas d\\'index de règle — les dimensions listées sont alors informatives.',\n 'card.dryRunNoRules': '(0 règles chargées — vérifiez le chemin rulesFile)',\n 'card.dryRunFail': 'Échec du test : ',\n 'card.dryRunStale': 'route manquante (plugin non redémarré ?)',\n 'card.rules': 'Règles intégrées des paramètres',\n 'card.rulesHint': 'Les règles que la porte charge actuellement (depuis le champ de configuration rules de cette entrée de plugin ; retour au fichier de règles si non configuré). Lecture seule — rien ici ne peut les modifier. Pour changer les règles, utilisez la liste blanche ci-dessous ou modifiez-les dans la page des paramètres.',\n 'card.rulesRefresh': 'Actualiser',\n 'card.rulesLoading': 'Lecture…',\n 'card.rulesPath': 'Source',\n 'card.rulesNone': 'aucune règle configurée',\n 'card.rulesCounts': 'Règles',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b octets · %l lignes',\n 'card.rulesMissing': 'Règles introuvables. La porte retombe sur ses valeurs par défaut intégrées.',\n 'card.rulesTruncated': 'Règles volumineuses ; affichage des 512 Ko premiers uniquement.',\n 'card.rulesError': 'Échec du chargement : ',\n 'card.rulesStale': 'route manquante (plugin non redémarré ?)',\n 'card.rulesNote': 'Lecture seule : ce panneau ne peut pas modifier les règles. La section liste blanche et « toujours autoriser » écrivent dans la configuration d\\'entrée de ce plugin.',\n}\n\n/** German dictionary (keys mirror zh). */\nexport const de: Record<PermissiveKey, string> = {\n 'card.title': 'Automatische Überprüfung',\n 'section.title': 'Automatische Prüfschleuse',\n 'card.description': 'Unabhängige Genehmigungsstufe: parallel zu Nur-Lesen / Vollzugriff / Whitelist, angezeigt als „Automatische Überprüfung\" im Sitzungs-Berechtigungswähler. Das Frontend bietet einen einzigen Schalter; die vier Backend-Genehmigungsstrategien sind über dieses Panel kombinierbar und bleiben fail-closed gegen P0-Hartablehnung.',\n 'card.permissive': 'Stufe „Automatische Überprüfung\" aktivieren',\n 'card.permissiveHint': 'Wenn deaktiviert, verhält sich das Gate genau wie zuvor.',\n 'card.scopeNote': 'Voreinstellungsbereich: Dieses Gate wirkt nur, während die Sitzungsberechtigungsvoreinstellung %scope ist. Unter jeder anderen Voreinstellung tritt das gesamte Gate zurück — einschließlich P0-Hartablehnung — und die Richtlinie der gewählten Voreinstellung übernimmt. Der Rücktritt protokolliert ein Ereignis und zeigt einen dauerhaften Hinweis über der Eingabe.',\n 'card.strategies': 'Backend-Genehmigungsstrategien (mindestens eine aktiv; kombinierbar)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — sichere Operationen im Bereich werden automatisch erlaubt; gefährliche/unbekannte → Nachfrage (mittlere Baseline-Stufe)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — jeder Übergang fragt; die „Erlaubnis-Steuerelemente\" des Genehmigungspanels erhalten zwei erweiterte Buttons: „Diesen Typ in dieser Sitzung wiederholt erlauben\" (begrenztes Sitzungs-Grant) und „Alle Vorkommen erlauben\" (Befehlswort dauerhaft in die rulesFile-Whitelist aufnehmen)',\n 'card.strategy.llmAssist': 'llmAssist — ein benutzerdefiniertes LLM bewertet das Risiko: safe → automatische Erlaubnis; deletion/credential/remote/system/bulk → Hartrisiken behalten die menschliche Nachfrage (der Klassifizierer lehnt nie ab — er eskaliert nur); neutral → Bestätigungslernen; Fehler/Timeout → Rückfall auf den Menschen',\n 'card.strategy.trustEscalation': 'trustEscalation — Sandbox-Eskalation ohne Eingabeaufforderung: Für einen bereits von diesem Gate erlaubten Aufruf wird die Sandbox-Erweiterung, die shell / pwsh / edit intern anfordert, hier genehmigt statt Sie zu fragen',\n 'card.strategy.trustEscalationHint': 'Die Sandbox-Eskalationsgenehmigung wird nach tools/pre-execute im Tool-Körper angefordert, sodass das Gate sie nie sieht — ein vom LLM als sicher eingestufter und automatisch erlaubter Aufruf fragte Sie dennoch nach der Erweiterung. Aktiviert überspringt nur der exakte vom Gate erlaubte Aufruf (übereinstimmend per callId) die Eingabeaufforderung; alles andere geht wie zuvor zum Menschen, ebenso jeder unerkannte Grund oder ein anderes Ziel als workspace-write / danger-full-access. Deaktivieren, um die Erweiterung unter menschlicher Kontrolle zu halten.',\n 'card.readonly': 'Nur-Lesen',\n 'card.unavailable': 'Einstellungs-Namensraum nicht verfügbar: Stellen Sie sicher, dass dsh-perm-gate in diesem Profil zusammengebaut ist.',\n 'card.llmReceiver': 'llmAssist empfangendes LLM (OpenAI-kompatibel; jede benutzerdefinierte API)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, z. B. https://api.openai.com/v1)',\n 'card.llmModel': 'Model (Modell-ID, z. B. deepseek-chat)',\n 'card.llmKey': 'API Key (geheim)',\n 'card.llmKeyHidden': 'Nicht gesetzt · nach erster Eingabe als * angezeigt',\n 'card.llmKeyMasked': 'Gesetzt · neuen Wert eingeben zum Überschreiben',\n 'card.llmKeyOverwrite': 'Ein geheimer Wert ist gespeichert; geben Sie einen neuen Wert ein und verlassen Sie das Feld zum Überschreiben.',\n 'card.llmKeyClear': 'Löschen',\n 'card.allowlist': 'Whitelist (allow, mit rulesFile synchronisiert)',\n 'card.allowlistHint': 'Muster im allow-Abschnitt werden direkt erlaubt; Einträge einzeln hinzufügen oder entfernen, live in rulesFile geschrieben und neu geladen.',\n 'card.allowlistPresetNote': 'Das Äquivalent der Voreinstellungs-Whitelist ist die trustAutoAllow-Strategie (sichere Operationen im Bereich automatisch erlaubt), aktiviert im Strategiebereich oben; diese Liste spiegelt Ihren rulesFile-allow-Abschnitt und startet berechtigterweise leer.',\n 'card.allowlistEmpty': 'Keine Whitelist-Regeln',\n 'card.allowlistPlaceholder': 'Neues Befehlsmuster, z. B. npm test*',\n 'card.allowlistAdd': 'Hinzufügen',\n 'card.allowlistRemove': 'Dieses Muster entfernen',\n 'card.allowlistBulk': 'Massenbearbeitung',\n 'card.allowlistBulkHide': 'Massenbearbeitung ausblenden',\n 'card.allowlistSave': 'Whitelist speichern',\n 'card.riskLearning': 'riskLearning — Verdiktlernen: neutrale Risikoanfragen, die der Mensch genehmigt und die ausgeführt werden, zählen hoch; dieselbe Operation wird am Schwellenwert mit passendem Fingerabdruck automatisch erlaubt',\n 'card.riskLearningHint': 'Der Lernzustand gehört dem Plugin ($DSH_HOME/perm-gate/learning.json) und wird nie in Ihre YAML-Regeln geschrieben; ein anderes Ziel nutzt nie die Autorität wieder. Standardmäßig deaktiviert.',\n 'card.riskThreshold': 'Menschliche Bestätigungen vor automatischer Erlaubnis erforderlich (1–10)',\n 'notice.label': 'Berechtigungs-Gate-Aktivität',\n 'history.label': 'Genehmigungen',\n 'history.title': 'Berechtigungsgenehmigungsprotokolle',\n 'history.subtitle': 'Jede Gate-Entscheidung in dieser Sitzung, neueste zuerst',\n 'history.loading': 'Wird geladen…',\n 'history.empty': 'Noch keine Genehmigungsprotokolle in dieser Sitzung',\n 'history.error': 'Laden fehlgeschlagen: ',\n 'history.tag.auto': 'Automatisch erlaubt',\n 'history.tag.ask': 'Angefragt',\n 'history.tag.deny': 'Abgelehnt',\n 'card.denylistRestore': 'Standard-Blacklist wiederherstellen',\n 'card.denylist': 'Blacklist (deny-Schlüsselwörter, Plugin-Standard)',\n 'card.denylistHint': 'Ein Aufruf, dessen Text ein Schlüsselwort enthält (Groß-/Kleinschreibung-unempfindliche Teilzeichenkette), wird sofort abgelehnt, vor Whitelist / Grants / LLM. Die Standardliste erbt von dsh-approval-gate und ist ab Installation aktiv; frei bearbeitbar — leer oder geleert fällt auf den Standard zurück (Ein-Klick-Wiederherstellung verfügbar), sodass die Blacklist sich nie stillschweigend abschaltet.',\n 'card.denylistEmpty': 'Blacklist leer (kein Aufruf wird von der Schlüsselwortschicht abgelehnt)',\n 'card.denylistPlaceholder': 'Neues Schlüsselwort, z. B. drop database',\n 'card.denylistAdd': 'Hinzufügen',\n 'card.denylistRemove': 'Dieses Schlüsselwort entfernen',\n 'card.denylistTagPreset': 'Standard',\n 'card.denylistTagCustom': 'Benutzerdefiniert',\n 'card.riskSediment': 'riskSediment — Lernsedimentation: Proben am Schwellenwert werden zu deterministischen Auto-Erlaubnisregeln',\n 'card.riskSedimentHint': 'Wenn aktiv, werden bei Erreichen des Schwellenwerts für einen tool|category-Schlüssel dessen Proben-Fingerabdrücke als Erlaubnisregeln sedimentiert — eine exakte Übereinstimmung bei gleichem Tool und gleichem Ziel erlaubt direkt ohne weiteren LLM-Aufruf (funktioniert weiter mit deaktiviertem llmAssist).',\n 'card.sediment': 'Lernsediment (deterministische Erlaubnisregeln)',\n 'card.sedimentHint': 'Aus menschlichen Bestätigungen sedimentierte Regeln: Nur eine exakte Fingerabdruckübereinstimmung erlaubt, nie ein anderes Ziel. Beenden Sie ein Lernen oder entfernen Sie eine Probe.',\n 'card.sedimentEmpty': 'Noch keine sedimentierten Regeln (Proben am Schwellenwert erscheinen hier)',\n 'card.sedimentCount': 'bestätigt %n/%t',\n 'card.sedimentStop': 'Beenden',\n 'card.sedimentStopTitle': 'Dieses Lernen beenden (Zähler und Proben löschen)',\n 'card.sedimentStopConfirm': 'Lernen für „%k\" beenden? Zähler und alle Proben werden gelöscht.',\n 'card.sedimentSampleRemove': 'Diese sedimentierte Probe entfernen',\n 'card.llmSource': 'Empfängerquelle',\n 'card.llmSourceCustom': 'Benutzerdefinierte API (OpenAI-kompatibel)',\n 'card.llmSourceHost': 'Das aktuelle Standardmodell der Sitzung verwenden (DSH-llm-Dienst)',\n 'card.llmSourceHostHint': 'Standardmäßig läuft die Genehmigungsbewertung auf der Modellgruppe, die die DSH-Sitzung aktuell verwendet (der effektive Wert wird unten angezeigt); Provider / Model leer lassen, um der Sitzung zu folgen, oder aus dem Dropdown wählen bzw. eingeben zum Festlegen — Ihre in DSH konfigurierten benutzerdefinierten Gruppen (z. B. local-35b) erscheinen automatisch.',\n 'card.llmProvider': 'Provider (leer = folgt der Sitzungsauswahl)',\n 'card.llmProviderPlaceholder': 'Folgt der Sitzungsauswahl',\n 'card.llmModelHostPlaceholder': 'Leer = folgt der Sitzungsauswahl',\n 'card.llmResolved': 'Aktuell wirksam: %p / %m',\n 'card.llmPreset': 'Endpoint-Voreinstellungen (füllt die Felder; weiter bearbeitbar)',\n 'card.llmPresetChoose': 'Voreinstellung wählen…',\n 'card.llmPresetPublic': 'Öffentliche API-Voreinstellungen',\n 'card.llmPresetHost': 'DSH-Modellgruppen (Auswahl wechselt zum Sitzungsempfänger)',\n 'card.networkEnabled': 'Netzwerk-Interception (networkEnabled)',\n 'card.networkEnabledHint': 'Wenn aktiv, startet ein lokaler Proxy, der ausgehende Verbindungen von Unterprozessen abfängt und Erlaubnis-/Ablehnungsregeln anwendet. Deaktiviert = keine Verhaltensänderung.',\n 'card.watch': 'Regel-Hot-Reload (watch)',\n 'card.watchHint': 'Wenn aktiv, werden Regeldateien automatisch auf Änderungen überwacht und sofort ohne manuelles Neuladen angewendet.',\n 'card.networkRebindNote': 'Wirkt sofort — der Proxy bindet sich automatisch neu, kein Plugin-Reload nötig.',\n 'card.networkInjectEnv': 'Proxy-Umgebungsvariablen injizieren (networkInjectEnv)',\n 'card.networkInjectEnvHint': 'Schreibt HTTP(S)_PROXY / ALL_PROXY für Unterprozesse (und leert NO_PROXY). Deaktiviert = der Listener läuft, aber keine Prozessumgebung wird geändert.',\n 'card.healthStale': 'Host-Route nicht verfügbar (404) — die Node-Hälfte ist noch ein alter Build; starten Sie dsh vollständig neu (nicht nur die Browserseite) und versuchen Sie es erneut.',\n 'card.healthTest': 'Zustandstest',\n 'card.healthRunning': 'Wird getestet…',\n 'card.healthOk': 'OK (%ms ms)',\n 'card.healthFail': 'Fehlgeschlagen: ',\n 'history.tag.learned': 'Gelernt',\n 'history.tag.manualApproved': 'Genehmigt',\n 'history.tag.manualRejected': 'Abgelehnt',\n 'history.tag.manualCancelled': 'Abgebrochen',\n 'history.tag.standDown': 'Gate aus',\n 'history.learnedProgress': 'gelernt %n/%t',\n 'history.snapshots': 'Diff-Snapshots',\n 'history.clearSession': 'Diese Sitzung löschen',\n 'history.clearAll': 'Alle löschen',\n 'history.clearSessionTitle': 'Nur die Diff-Snapshots dieser Sitzung löschen (andere Sitzungen unberührt)',\n 'history.clearAllTitle': 'Diff-Snapshots aller Sitzungen löschen, einschließlich nie überprüfter — fragt erneut',\n 'history.clearSessionConfirm': 'Diff-Snapshots dieser Sitzung löschen? Nur die von dieser Sitzung erzeugten Änderungsvergleichsdaten werden entfernt; die Genehmigungsprotokolle bleiben.',\n 'history.clearAllConfirm': 'Diff-Snapshots ALLER Sitzungen löschen? Dies kann Änderungsvergleiche löschen, die andere Sitzungen noch nicht überprüft haben, und ist unwiderruflich.',\n 'history.diffTitle': 'Dateiänderungsvergleich',\n 'history.diffClose': 'Schließen',\n 'history.diffLoading': 'Wird geladen…',\n 'history.diffEmpty': 'Keine Inhaltsänderung (oder Datei unlesbar)',\n 'history.diffLoadFail': 'Diff-Laden fehlgeschlagen: ',\n 'history.diffRevert': 'Diese Änderung zurücksetzen',\n 'history.diffReverting': 'Wird gesendet…',\n 'history.diffRevertDone': 'Zurücksetzungsanweisung gesendet',\n 'history.diffRevertSent': 'Zurücksetzungsanweisung an die Konversation gesendet; die KI stellt die Datei entsprechend wieder her',\n 'history.diffRevertFail': 'Senden fehlgeschlagen: ',\n 'history.diffNoSnapshot': 'Dieses Ereignis hat keinen Snapshot für diese Datei',\n 'history.diffChipTitle': 'Änderungsvergleich dieser Datei anzeigen',\n 'history.diffStats': '+%a / -%r Zeilen geändert · %c unverändert',\n 'history.diffGone': ' (Datei existiert nicht mehr)',\n 'history.diffHidden': '%n unveränderte Zeilen',\n 'card.dryRun': 'Regeltest',\n 'card.dryRunHint': 'Beurteilt einen Aufruf gegen die aktuellen Regeln. Führt kein Tool aus und schreibt keine Regel — prüfen Sie hier, bevor Sie ändern.',\n 'card.dryRunTool': 'Werkzeug',\n 'card.dryRunCommand': 'Befehl / Argumente',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'Testen',\n 'card.dryRunRunning': 'Wird bewertet…',\n 'card.dryRunEmpty': 'Noch nichts getestet. Geben Sie ein Werkzeug und einen Befehl ein und drücken Sie Testen, um das Verdikt zu sehen.',\n 'card.dryRunVerdict': 'Verdikt',\n 'card.dryRunAllow': 'erlauben',\n 'card.dryRunAsk': 'anfragen',\n 'card.dryRunDeny': 'ablehnen',\n 'card.dryRunRule': 'Übereinstimmende Regel',\n 'card.dryRunRuleNone': 'keine Regel gefunden; defaultAction: %d',\n 'card.dryRunDimensions': 'Dimensionen',\n 'card.dryRunReason': 'Begründung',\n 'card.dryRunNote': '„Übereinstimmende Regel\" stammt aus der Regelebene. Wenn das Verdikt von einer früheren Hartablehnung oder der Schlüsselwort-Blacklist erzeugt wurde, gibt es keinen Regelindex — die aufgelisteten Dimensionen sind dann nur informativ.',\n 'card.dryRunNoRules': '(0 Regeln geladen — prüfen Sie den rulesFile-Pfad)',\n 'card.dryRunFail': 'Test fehlgeschlagen: ',\n 'card.dryRunStale': 'Route fehlt (Plugin nicht neu gestartet?)',\n 'card.rules': 'Einstellungen: Integrierte Regeln',\n 'card.rulesHint': 'Die Regeln, die das Gate gerade lädt (aus dem rules-Konfigurationsfeld dieses Plugin-Eintrags; Fallback auf die Regeldatei, wenn nicht konfiguriert). Nur-Lesen — nichts hier kann sie ändern. Um Regeln zu ändern, verwenden Sie die Whitelist unten oder bearbeiten Sie sie auf der Einstellungsseite.',\n 'card.rulesRefresh': 'Aktualisieren',\n 'card.rulesLoading': 'Wird gelesen…',\n 'card.rulesPath': 'Quelle',\n 'card.rulesNone': 'keine Regeln konfiguriert',\n 'card.rulesCounts': 'Regeln',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b Bytes · %l Zeilen',\n 'card.rulesMissing': 'Regeln nicht gefunden. Das Gate fällt auf seine integrierten Standardwerte zurück.',\n 'card.rulesTruncated': 'Regeln sind groß; nur die ersten 512 KB werden angezeigt.',\n 'card.rulesError': 'Laden fehlgeschlagen: ',\n 'card.rulesStale': 'Route fehlt (Plugin nicht neu gestartet?)',\n 'card.rulesNote': 'Nur-Lesen: Dieses Panel kann die Regeln nicht ändern. Der Whitelist-Abschnitt und „Immer erlauben\" schreiben in die Konfiguration dieses Plugin-Eintrags zurück.',\n}\n\n/** Italian dictionary (keys mirror zh). */\nexport const it: Record<PermissiveKey, string> = {\n 'card.title': 'Revisione automatica',\n 'section.title': 'Portale di revisione automatica',\n 'card.description': 'Livello di approvazione indipendente: parallelo a sola lettura / accesso completo / whitelist, mostrato come «Revisione automatica» nel selettore delle autorizzazioni della sessione. Il front-end espone un unico interruttore; le quattro strategie di approvazione backend sono combinabili tramite questo pannello e restano fail-closed contro il rifiuto rigido P0.',\n 'card.permissive': 'Abilita il livello di revisione automatica',\n 'card.permissiveHint': 'Quando disattivato, il portale si comporta esattamente come prima.',\n 'card.scopeNote': 'Ambito del preset: questo portale agisce solo quando il preset di autorizzazione della sessione è %scope. Con qualsiasi altro preset l\\'intero portale si mette in pausa — incluso il rifiuto rigido P0 — e la politica del preset selezionato prende il controllo. La pausa registra un evento e lascia una striscia persistente sopra l\\'input.',\n 'card.strategies': 'Strategie di approvazione backend (almeno una attiva; combinabili)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — le operazioni sicure nell\\'ambito sono auto-consentite; pericolose/sconosciute → richiesta (livello intermedio di base)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — ogni attraversamento chiede; i «controlli di consenso» del pannello di approvazione aggiungono due pulsanti estesi: «ripeti consenso per questo tipo in questa sessione» (grant limitato alla sessione) e «consenti tutte le occorrenze» (persistenza della parola comando nella whitelist rulesFile)',\n 'card.strategy.llmAssist': 'llmAssist — un LLM personalizzato valuta il rischio: safe → auto-consenso; deletion/credential/remote/system/bulk → rischi rigidi mantengono la richiesta umana (il classificatore non rifiuta mai — scala solo); neutral → apprendimento per conferma; fallimento/timeout → ritorno all\\'umano',\n 'card.strategy.trustEscalation': 'trustEscalation — escalation sandbox senza prompt: per una chiamata già consentita da questo portale, l\\'ampliamento sandbox avviato internamente da shell / pwsh / edit è approvato qui invece di chiedere a te',\n 'card.strategy.trustEscalationHint': 'L\\'approvazione dell\\'escalation sandbox è richiesta dall\\'interno del corpo dello strumento, dopo tools/pre-execute, quindi il portale non la vede mai — una chiamata che il LLM ha giudicato sicura e che il portale ha auto-consentito ti chiedeva comunque di approvare l\\'ampliamento. Attivato, solo la chiamata esatta consentita dal portale (corrispondenza per callId) salta il prompt; tutto il resto va all\\'umano come prima, così come ogni motivo non riconosciuto o un target diverso da workspace-write / danger-full-access. Disattiva per mantenere l\\'ampliamento sotto controllo umano.',\n 'card.readonly': 'Sola lettura',\n 'card.unavailable': 'Namespace delle impostazioni non disponibile: assicurati che dsh-perm-gate sia assemblato in questo profilo.',\n 'card.llmReceiver': 'LLM ricevente llmAssist (compatibile OpenAI; qualsiasi API personalizzata)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, es. https://api.openai.com/v1)',\n 'card.llmModel': 'Model (ID modello, es. deepseek-chat)',\n 'card.llmKey': 'API Key (segreta)',\n 'card.llmKeyHidden': 'Non impostata · mostrata come * dopo il primo inserimento',\n 'card.llmKeyMasked': 'Impostata · inserisci un nuovo valore per sovrascrivere',\n 'card.llmKeyOverwrite': 'Un valore segreto è memorizzato; inserisci un nuovo valore e lascia il campo per sovrascriverlo.',\n 'card.llmKeyClear': 'Cancella',\n 'card.allowlist': 'Whitelist (allow, sincronizzata con rulesFile)',\n 'card.allowlistHint': 'I pattern nella sezione allow consentono direttamente; aggiungi o rimuovi voci una alla volta, scritte in rulesFile e ricaricate in tempo reale.',\n 'card.allowlistPresetNote': 'L\\'equivalente della whitelist predefinita è la strategia trustAutoAllow (operazioni sicure nell\\'ambito auto-consentite), attivata nella sezione strategie sopra; questa lista rispecchia la tua sezione allow di rulesFile e inizia legittimamente vuota.',\n 'card.allowlistEmpty': 'Nessuna regola whitelist',\n 'card.allowlistPlaceholder': 'Nuovo pattern di comando, es. npm test*',\n 'card.allowlistAdd': 'Aggiungi',\n 'card.allowlistRemove': 'Rimuovi questo pattern',\n 'card.allowlistBulk': 'Modifica in blocco',\n 'card.allowlistBulkHide': 'Nascondi modifica in blocco',\n 'card.allowlistSave': 'Salva whitelist',\n 'card.riskLearning': 'riskLearning — apprendimento del verdetto: le operazioni a rischio neutral approvate ed eseguite vengono conteggiate; la stessa operazione è auto-consentita alla soglia con impronta corrispondente',\n 'card.riskLearningHint': 'Lo stato di apprendimento appartiene al plugin ($DSH_HOME/perm-gate/learning.json) e non viene mai scritto nelle tue regole YAML; un target diverso non riutilizza mai l\\'autorità. Disattivato per impostazione predefinita.',\n 'card.riskThreshold': 'Conferme umane richieste prima dell\\'auto-consenso (1–10)',\n 'notice.label': 'Attività del portale autorizzazioni',\n 'history.label': 'Approvazioni',\n 'history.title': 'Registro approvazioni autorizzazioni',\n 'history.subtitle': 'Ogni decisione del portale in questa sessione, più recenti prima',\n 'history.loading': 'Caricamento…',\n 'history.empty': 'Nessun record di approvazione in questa sessione',\n 'history.error': 'Caricamento non riuscito: ',\n 'history.tag.auto': 'Auto-consentito',\n 'history.tag.ask': 'Richiesto',\n 'history.tag.deny': 'Rifiutato',\n 'card.denylistRestore': 'Ripristina blacklist predefinita',\n 'card.denylist': 'Blacklist (parole chiave deny, preset plugin)',\n 'card.denylistHint': 'Una chiamata il cui testo contiene una parola chiave (sottostringa senza distinzione maiuscole/minuscole) è rifiutata immediatamente, prima di whitelist / grant / LLM. La lista predefinita eredita da dsh-approval-gate ed è attiva dall\\'installazione; modifica liberamente — vuota o cancellata torna al predefinito (ripristino con un clic), quindi la blacklist non si disattiva mai silenziosamente.',\n 'card.denylistEmpty': 'Blacklist vuota (nessuna chiamata è respinta dal livello parole chiave)',\n 'card.denylistPlaceholder': 'Nuova parola chiave, es. drop database',\n 'card.denylistAdd': 'Aggiungi',\n 'card.denylistRemove': 'Rimuovi questa parola chiave',\n 'card.denylistTagPreset': 'Preset',\n 'card.denylistTagCustom': 'Personalizzato',\n 'card.riskSediment': 'riskSediment — sedimentazione dell\\'apprendimento: i campioni alla soglia diventano regole deterministiche di auto-consenso',\n 'card.riskSedimentHint': 'Attivato, quando una chiave tool|category raggiunge la soglia le sue impronte campione si sedimentano in regole di consenso — una corrispondenza esatta stesso strumento/stesso target consente direttamente senza altra chiamata LLM (continua a funzionare con llmAssist disattivato).',\n 'card.sediment': 'Sedimento di apprendimento (regole deterministiche di consenso)',\n 'card.sedimentHint': 'Regole sedimentate dalle conferme umane: solo una corrispondenza esatta dell\\'impronta consente, mai un target diverso. Termina un apprendimento o rimuovi un campione.',\n 'card.sedimentEmpty': 'Nessuna regola sedimentata per ora (i campioni che raggiungono la soglia appaiono qui)',\n 'card.sedimentCount': 'confermato %n/%t',\n 'card.sedimentStop': 'Termina',\n 'card.sedimentStopTitle': 'Termina questo apprendimento (elimina conteggio e campioni)',\n 'card.sedimentStopConfirm': 'Terminare l\\'apprendimento per «%k»? Il conteggio e tutti i campioni saranno eliminati.',\n 'card.sedimentSampleRemove': 'Rimuovi questo campione sedimentato',\n 'card.llmSource': 'Sorgente LLM ricevente',\n 'card.llmSourceCustom': 'API personalizzata (compatibile OpenAI)',\n 'card.llmSourceHost': 'Usa il modello predefinito attuale della sessione (servizio DSH llm)',\n 'card.llmSourceHostHint': 'Per impostazione predefinita la valutazione dell\\'approvazione usa il gruppo di modelli attualmente selezionato nella sessione DSH (il valore effettivo è mostrato sotto); lascia Provider / Model vuoto per seguire la sessione, oppure scegli dal menu a tendina o digita per fissare — i gruppi personalizzati configurati in DSH (es. local-35b) appaiono automaticamente.',\n 'card.llmProvider': 'Provider (vuoto = segue la selezione della sessione)',\n 'card.llmProviderPlaceholder': 'Segue la selezione della sessione',\n 'card.llmModelHostPlaceholder': 'Vuoto = segue la selezione della sessione',\n 'card.llmResolved': 'Attualmente effettivo: %p / %m',\n 'card.llmPreset': 'Preset endpoint (compila i campi; ancora modificabile)',\n 'card.llmPresetChoose': 'Scegli un preset…',\n 'card.llmPresetPublic': 'Preset API pubbliche',\n 'card.llmPresetHost': 'Gruppi modelli DSH (la selezione passa al ricevitore di sessione)',\n 'card.networkEnabled': 'Intercettazione rete (networkEnabled)',\n 'card.networkEnabledHint': 'Attivato, avvia un proxy locale che intercetta le connessioni in uscita dei sottoprocessi e applica regole di consenso/rifiuto. Disattivato = nessun cambiamento di comportamento.',\n 'card.watch': 'Ricaricamento a caldo regole (watch)',\n 'card.watchHint': 'Attivato, monitora automaticamente le modifiche ai file di regole e le applica istantaneamente senza ricaricamento manuale.',\n 'card.networkRebindNote': 'Ha effetto immediato — il proxy si ricollega automaticamente, nessun ricaricamento del plugin necessario.',\n 'card.networkInjectEnv': 'Inietta variabili d\\'ambiente proxy (networkInjectEnv)',\n 'card.networkInjectEnvHint': 'Scrive HTTP(S)_PROXY / ALL_PROXY per i sottoprocessi (e svuota NO_PROXY). Disattivato = il listener è in esecuzione ma nessun ambiente di processo viene modificato.',\n 'card.healthStale': 'Route host non disponibile (404) — la metà node è ancora una build vecchia; riavvia completamente dsh (non solo la pagina del browser) e riprova.',\n 'card.healthTest': 'Test di salute',\n 'card.healthRunning': 'Test in corso…',\n 'card.healthOk': 'OK (%ms ms)',\n 'card.healthFail': 'Fallito: ',\n 'history.tag.learned': 'Appreso',\n 'history.tag.manualApproved': 'Approvato',\n 'history.tag.manualRejected': 'Rifiutato',\n 'history.tag.manualCancelled': 'Annullato',\n 'history.tag.standDown': 'Portale inattivo',\n 'history.learnedProgress': 'appreso %n/%t',\n 'history.snapshots': 'snapshot diff',\n 'history.clearSession': 'Cancella questa sessione',\n 'history.clearAll': 'Cancella tutto',\n 'history.clearSessionTitle': 'Cancella solo gli snapshot diff di questa sessione (altre sessioni intatte)',\n 'history.clearAllTitle': 'Cancella gli snapshot diff di tutte le sessioni, incluse quelle mai revisionate — chiede di nuovo',\n 'history.clearSessionConfirm': 'Cancellare gli snapshot diff di questa sessione? Solo i dati di confronto prodotti dalle approvazioni di questa sessione sono rimossi; i record di approvazione restano.',\n 'history.clearAllConfirm': 'Cancellare gli snapshot diff di TUTTE le sessioni? Potrebbe eliminare confronti che altre sessioni non hanno ancora revisionato, ed è irreversibile.',\n 'history.diffTitle': 'Confronto modifiche file',\n 'history.diffClose': 'Chiudi',\n 'history.diffLoading': 'Caricamento…',\n 'history.diffEmpty': 'Nessuna modifica al contenuto (o file illeggibile)',\n 'history.diffLoadFail': 'Caricamento diff non riuscito: ',\n 'history.diffRevert': 'Annulla questa modifica',\n 'history.diffReverting': 'Invio…',\n 'history.diffRevertDone': 'Istruzione di ripristino inviata',\n 'history.diffRevertSent': 'Istruzione di ripristino inviata alla conversazione; l\\'IA ripristinerà il file di conseguenza',\n 'history.diffRevertFail': 'Invio non riuscito: ',\n 'history.diffNoSnapshot': 'Questo evento non ha uno snapshot per quel file',\n 'history.diffChipTitle': 'Visualizza il confronto modifiche di questo file',\n 'history.diffStats': '+%a / -%r righe modificate · %c invariate',\n 'history.diffGone': ' (il file non esiste più)',\n 'history.diffHidden': '%n righe non modificate',\n 'card.dryRun': 'Test regole',\n 'card.dryRunHint': 'Giudica una chiamata contro le regole in vigore. Non esegue alcun strumento e non scrive alcuna regola — verifica qui prima di modificare.',\n 'card.dryRunTool': 'Strumento',\n 'card.dryRunCommand': 'Comando / argomenti',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'Testa',\n 'card.dryRunRunning': 'Valutazione…',\n 'card.dryRunEmpty': 'Nulla di testato finora. Inserisci uno strumento e un comando, poi premi Testa per vedere il verdetto.',\n 'card.dryRunVerdict': 'Verdetto',\n 'card.dryRunAllow': 'consenti',\n 'card.dryRunAsk': 'richiedi',\n 'card.dryRunDeny': 'rifiuta',\n 'card.dryRunRule': 'Regola corrispondente',\n 'card.dryRunRuleNone': 'nessuna regola corrispondente; defaultAction: %d',\n 'card.dryRunDimensions': 'Dimensioni',\n 'card.dryRunReason': 'Motivo',\n 'card.dryRunNote': '«Regola corrispondente» proviene dal livello regole. Quando il verdetto è prodotto da un rifiuto rigido precedente o dalla blacklist di parole chiave non c\\'è indice di regola — le dimensioni elencate sono solo informative.',\n 'card.dryRunNoRules': '(0 regole caricate — controlla il percorso rulesFile)',\n 'card.dryRunFail': 'Test non riuscito: ',\n 'card.dryRunStale': 'route mancante (plugin non riavviato?)',\n 'card.rules': 'Regole integrate delle impostazioni',\n 'card.rulesHint': 'Le regole che il portale sta caricando ora (dal campo di configurazione rules di questa voce plugin; fallback al file regole se non configurato). Sola lettura — nulla qui può modificarle. Per cambiare le regole, usa la whitelist sotto o modificale nella pagina impostazioni.',\n 'card.rulesRefresh': 'Aggiorna',\n 'card.rulesLoading': 'Lettura…',\n 'card.rulesPath': 'Sorgente',\n 'card.rulesNone': 'nessuna regola configurata',\n 'card.rulesCounts': 'Regole',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b byte · %l righe',\n 'card.rulesMissing': 'Regole non trovate. Il portale ripiega sui suoi valori predefiniti integrati.',\n 'card.rulesTruncated': 'Regole grandi; mostrati solo i primi 512 KB.',\n 'card.rulesError': 'Caricamento non riuscito: ',\n 'card.rulesStale': 'route mancante (plugin non riavviato?)',\n 'card.rulesNote': 'Sola lettura: questo pannello non può modificare le regole. La sezione whitelist e «consenti sempre» scrivono nella configurazione di questa voce plugin.',\n}\n\n/** Russian dictionary (keys mirror zh). */\nexport const ru: Record<PermissiveKey, string> = {\n 'card.title': 'Автоматическая проверка',\n 'section.title': 'Шлюз автоматической проверки',\n 'card.description': 'Независимый уровень одобрения: параллельно с «только чтение» / «полный доступ» / «белый список», отображается как «Автоматическая проверка» в выборе разрешений сессии. Фронтенд предоставляет один переключатель; четыре серверные стратегии одобрения комбинируемы через эту панель и остаются fail-closed против жёсткого отказа P0.',\n 'card.permissive': 'Включить уровень автоматической проверки',\n 'card.permissiveHint': 'Когда выключено, шлюз ведёт себя точно так же, как раньше.',\n 'card.scopeNote': 'Область пресета: этот шлюз действует только когда пресет разрешений сессии — %scope. При любом другом пресете весь шлюз отключается — включая жёсткий отказ P0 — и политика выбранного пресета берёт управление на себя. Отключение записывает событие и оставляет постоянную полоску над полем ввода.',\n 'card.strategies': 'Серверные стратегии одобрения (хотя бы одна активна; комбинируемы)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — безопасные операции в области автоматически разрешаются; опасные/неизвестные → запрос (базовый средний уровень)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — каждый переход спрашивает; «элементы управления разрешением» панели одобрения получают две расширенные кнопки: «повторно разрешить этот тип в этой сессии» (ограниченный grant сессии) и «разрешить все вхождения» (постоянное добавление слова команды в белый список rulesFile)',\n 'card.strategy.llmAssist': 'llmAssist — пользовательская LLM оценивает риск: safe → авто-разрешение; deletion/credential/remote/system/bulk → жёсткие риски сохраняют запрос к человеку (классификатор никогда не отказывает — только эскалирует); neutral → обучение подтверждением; сбой/таймаут → возврат к человеку',\n 'card.strategy.trustEscalation': 'trustEscalation — эскалация песочницы без запроса: для вызова, уже разрешённого этим шлюзом, расширение песочницы, инициированное shell / pwsh / edit изнутри инструмента, одобряется здесь вместо запроса к вам',\n 'card.strategy.trustEscalationHint': 'Запрос на одобрение эскалации песочницы происходит изнутри тела инструмента после tools/pre-execute, поэтому шлюз его не видит — вызов, который LLM оценила как безопасный и шлюз авто-разрешил, всё равно спрашивал вас об одобрении расширения. При включении только точный вызов, разрешённый шлюзом (совпадение по callId), пропускает запрос; всё остальное идёт к человеку как раньше, равно как и любая нераспознанная причина или цель, отличная от workspace-write / danger-full-access. Выключите, чтобы расширение оставалось под контролем человека.',\n 'card.readonly': 'Только чтение',\n 'card.unavailable': 'Пространство имён настроек недоступно: убедитесь, что dsh-perm-gate собран в этом профиле.',\n 'card.llmReceiver': 'Принимающая LLM для llmAssist (совместимая с OpenAI; любой пользовательский API)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, напр. https://api.openai.com/v1)',\n 'card.llmModel': 'Model (идентификатор модели, напр. deepseek-chat)',\n 'card.llmKey': 'API Key (секрет)',\n 'card.llmKeyHidden': 'Не задан · после первого ввода отображается как *',\n 'card.llmKeyMasked': 'Задан · введите новое значение для перезаписи',\n 'card.llmKeyOverwrite': 'Секретное значение сохранено; введите новое значение и покиньте поле для перезаписи.',\n 'card.llmKeyClear': 'Очистить',\n 'card.allowlist': 'Белый список (allow, синхронизирован с rulesFile)',\n 'card.allowlistHint': 'Паттерны в секции allow разрешаются напрямую; добавляйте или удаляйте записи по одной, они записываются в rulesFile и перезагружаются в реальном времени.',\n 'card.allowlistPresetNote': 'Эквивалент пресетного белого списка — стратегия trustAutoAllow (безопасные операции в области автоматически разрешаются), активируется в секции стратегий выше; этот список отражает вашу секцию allow в rulesFile и закономерно начинается пустым.',\n 'card.allowlistEmpty': 'Нет правил белого списка',\n 'card.allowlistPlaceholder': 'Новый паттерн команды, напр. npm test*',\n 'card.allowlistAdd': 'Добавить',\n 'card.allowlistRemove': 'Удалить этот паттерн',\n 'card.allowlistBulk': 'Массовое редактирование',\n 'card.allowlistBulkHide': 'Скрыть массовое редактирование',\n 'card.allowlistSave': 'Сохранить белый список',\n 'card.riskLearning': 'riskLearning — обучение вердиктам: операции с нейтральным риском, одобренные человеком и выполненные, подсчитываются; та же операция автоматически разрешается при достижении порога с совпадающим отпечатком',\n 'card.riskLearningHint': 'Состояние обучения принадлежит плагину ($DSH_HOME/perm-gate/learning.json) и никогда не записывается в ваши YAML-правила; другая цель никогда не переиспользует полномочие. По умолчанию выключено.',\n 'card.riskThreshold': 'Подтверждений человеком перед авто-разрешением (1–10)',\n 'notice.label': 'Активность шлюза разрешений',\n 'history.label': 'Одобрения',\n 'history.title': 'Журнал одобрений разрешений',\n 'history.subtitle': 'Каждое решение шлюза в этой сессии, последние сверху',\n 'history.loading': 'Загрузка…',\n 'history.empty': 'В этой сессии пока нет записей одобрения',\n 'history.error': 'Ошибка загрузки: ',\n 'history.tag.auto': 'Авто-разрешено',\n 'history.tag.ask': 'Запрошено',\n 'history.tag.deny': 'Отклонено',\n 'card.denylistRestore': 'Восстановить пресетный чёрный список',\n 'card.denylist': 'Чёрный список (ключевые слова deny, пресет плагина)',\n 'card.denylistHint': 'Вызов, текст которого содержит ключевое слово (подстрока без учёта регистра), немедленно отклоняется — до белого списка / grants / LLM. Пресетный список наследуется от dsh-approval-gate и активен с момента установки; редактируйте свободно — пустой или очищенный возвращается к пресету (восстановление в один клик), поэтому чёрный список никогда не отключается молча.',\n 'card.denylistEmpty': 'Чёрный список пуст (ни один вызов не отклоняется на уровне ключевых слов)',\n 'card.denylistPlaceholder': 'Новое ключевое слово, напр. drop database',\n 'card.denylistAdd': 'Добавить',\n 'card.denylistRemove': 'Удалить это ключевое слово',\n 'card.denylistTagPreset': 'Пресет',\n 'card.denylistTagCustom': 'Пользовательское',\n 'card.riskSediment': 'riskSediment — седиментация обучения: образцы, достигшие порога, становятся детерминированными правилами авто-разрешения',\n 'card.riskSedimentHint': 'При включении, когда ключ tool|category достигает порога, отпечатки его образцов оседают в правила разрешения — точное совпадение тот же инструмент/та же цель разрешает напрямую без нового вызова LLM (продолжает работать с выключенным llmAssist).',\n 'card.sediment': 'Осадок обучения (детерминированные правила разрешения)',\n 'card.sedimentHint': 'Правила, осевшие из подтверждений человека: только точное совпадение отпечатка разрешает, никогда другая цель. Завершите одно обучение или удалите один образец.',\n 'card.sedimentEmpty': 'Пока нет осаждённых правил (образцы, достигшие порога, появятся здесь)',\n 'card.sedimentCount': 'подтверждено %n/%t',\n 'card.sedimentStop': 'Завершить',\n 'card.sedimentStopTitle': 'Завершить это обучение (удаляет счётчик и образцы)',\n 'card.sedimentStopConfirm': 'Завершить обучение для «%k»? Его счётчик и все образцы будут удалены.',\n 'card.sedimentSampleRemove': 'Удалить этот осаждённый образец',\n 'card.llmSource': 'Источник принимающей LLM',\n 'card.llmSourceCustom': 'Пользовательский API (совместимый с OpenAI)',\n 'card.llmSourceHost': 'Использовать текущую модель по умолчанию сессии (сервис DSH llm)',\n 'card.llmSourceHostHint': 'По умолчанию оценка одобрения выполняется на группе моделей, выбранной в текущей сессии DSH (эффективное значение показано ниже); оставьте Provider / Model пустым, чтобы следовать за сессией, или выберите из выпадающего списка / введите для фиксации — ваши пользовательские группы, настроенные в DSH (напр. local-35b), появляются автоматически.',\n 'card.llmProvider': 'Provider (пусто = следует выбору сессии)',\n 'card.llmProviderPlaceholder': 'Следует выбору сессии',\n 'card.llmModelHostPlaceholder': 'Пусто = следует выбору сессии',\n 'card.llmResolved': 'Текущий эффективный: %p / %m',\n 'card.llmPreset': 'Пресеты эндпоинтов (заполняет поля; далее редактируемо)',\n 'card.llmPresetChoose': 'Выбрать пресет…',\n 'card.llmPresetPublic': 'Пресеты публичных API',\n 'card.llmPresetHost': 'Группы моделей DSH (выбор переключает на приёмник сессии)',\n 'card.networkEnabled': 'Перехват сети (networkEnabled)',\n 'card.networkEnabledHint': 'При включении запускается локальный прокси, перехватывающий исходящие соединения подпроцессов и применяющий правила разрешения/отказа. Выключено = никаких изменений поведения.',\n 'card.watch': 'Горячая перезагрузка правил (watch)',\n 'card.watchHint': 'При включении автоматически отслеживает изменения файлов правил и применяет их мгновенно без ручной перезагрузки.',\n 'card.networkRebindNote': 'Вступает в силу немедленно — прокси автоматически перепривязывается, перезагрузка плагина не нужна.',\n 'card.networkInjectEnv': 'Инъекция переменных окружения прокси (networkInjectEnv)',\n 'card.networkInjectEnvHint': 'Записывает HTTP(S)_PROXY / ALL_PROXY для подпроцессов (и очищает NO_PROXY). Выключено = слушатель работает, но окружение процессов не изменяется.',\n 'card.healthStale': 'Маршрут хоста недоступен (404) — половина node всё ещё старой сборки; полностью перезапустите dsh (не только страницу браузера) и повторите.',\n 'card.healthTest': 'Тест состояния',\n 'card.healthRunning': 'Тестирование…',\n 'card.healthOk': 'OK (%ms мс)',\n 'card.healthFail': 'Ошибка: ',\n 'history.tag.learned': 'Изучено',\n 'history.tag.manualApproved': 'Одобрено',\n 'history.tag.manualRejected': 'Отклонено',\n 'history.tag.manualCancelled': 'Отменено',\n 'history.tag.standDown': 'Шлюз выключен',\n 'history.learnedProgress': 'изучено %n/%t',\n 'history.snapshots': 'снимки diff',\n 'history.clearSession': 'Очистить эту сессию',\n 'history.clearAll': 'Очистить всё',\n 'history.clearSessionTitle': 'Очистить только снимки diff этой сессии (другие сессии не затрагиваются)',\n 'history.clearAllTitle': 'Очистить снимки diff всех сессий, включая непросмотренные — запрашивает подтверждение',\n 'history.clearSessionConfirm': 'Очистить снимки diff этой сессии? Удаляются только данные сравнения, созданные одобрениями этой сессии; записи одобрений остаются.',\n 'history.clearAllConfirm': 'Очистить снимки diff ВСЕХ сессий? Это может удалить сравнения, которые другие сессии ещё не просмотрели, и необратимо.',\n 'history.diffTitle': 'Сравнение изменений файла',\n 'history.diffClose': 'Закрыть',\n 'history.diffLoading': 'Загрузка…',\n 'history.diffEmpty': 'Нет изменений содержимого (или файл нечитаем)',\n 'history.diffLoadFail': 'Ошибка загрузки diff: ',\n 'history.diffRevert': 'Отменить это изменение',\n 'history.diffReverting': 'Отправка…',\n 'history.diffRevertDone': 'Инструкция отмены отправлена',\n 'history.diffRevertSent': 'Инструкция отмены отправлена в диалог; ИИ восстановит файл соответственно',\n 'history.diffRevertFail': 'Ошибка отправки: ',\n 'history.diffNoSnapshot': 'У этого события нет снимка для данного файла',\n 'history.diffChipTitle': 'Просмотреть сравнение изменений этого файла',\n 'history.diffStats': '+%a / -%r строк изменено · %c без изменений',\n 'history.diffGone': ' (файл больше не существует)',\n 'history.diffHidden': '%n неизменённых строк',\n 'card.dryRun': 'Тест правил',\n 'card.dryRunHint': 'Оценивает один вызов по действующим правилам. Не выполняет инструмент и не записывает правило — проверьте здесь перед изменением.',\n 'card.dryRunTool': 'Инструмент',\n 'card.dryRunCommand': 'Команда / аргументы',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'Тестировать',\n 'card.dryRunRunning': 'Оценка…',\n 'card.dryRunEmpty': 'Пока ничего не протестировано. Укажите инструмент и команду, затем нажмите «Тестировать», чтобы увидеть вердикт.',\n 'card.dryRunVerdict': 'Вердикт',\n 'card.dryRunAllow': 'разрешить',\n 'card.dryRunAsk': 'запросить',\n 'card.dryRunDeny': 'отклонить',\n 'card.dryRunRule': 'Совпавшее правило',\n 'card.dryRunRuleNone': 'ни одно правило не совпало; defaultAction: %d',\n 'card.dryRunDimensions': 'Измерения',\n 'card.dryRunReason': 'Причина',\n 'card.dryRunNote': '«Совпавшее правило» происходит из уровня правил. Когда вердикт выработан более ранним жёстким отказом или чёрным списком ключевых слов, индекса правила нет — перечисленные измерения носят справочный характер.',\n 'card.dryRunNoRules': '(загружено 0 правил — проверьте путь rulesFile)',\n 'card.dryRunFail': 'Ошибка теста: ',\n 'card.dryRunStale': 'маршрут отсутствует (плагин не перезапущен?)',\n 'card.rules': 'Встроенные правила настроек',\n 'card.rulesHint': 'Правила, которые шлюз загружает сейчас (из поля конфигурации rules этой записи плагина; откат к файлу правил, если не настроено). Только чтение — ничто здесь не может их изменить. Чтобы изменить правила, используйте белый список ниже или редактируйте на странице настроек.',\n 'card.rulesRefresh': 'Обновить',\n 'card.rulesLoading': 'Чтение…',\n 'card.rulesPath': 'Источник',\n 'card.rulesNone': 'правила не настроены',\n 'card.rulesCounts': 'Правила',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b байт · %l строк',\n 'card.rulesMissing': 'Правила не найдены. Шлюз откатывается к встроенным значениям по умолчанию.',\n 'card.rulesTruncated': 'Правила большие; показаны только первые 512 КБ.',\n 'card.rulesError': 'Ошибка загрузки: ',\n 'card.rulesStale': 'маршрут отсутствует (плагин не перезапущен?)',\n 'card.rulesNote': 'Только чтение: эта панель не может изменять правила. Секция белого списка и «всегда разрешать» записывают обратно в конфигурацию этой записи плагина.',\n}\n\n/** Spanish dictionary (keys mirror zh). */\nexport const es: Record<PermissiveKey, string> = {\n 'card.title': 'Revisión automática',\n 'section.title': 'Compuerta de revisión automática',\n 'card.description': 'Nivel de aprobación independiente: paralelo a solo lectura / acceso completo / lista blanca, mostrado como «Revisión automática» en el selector de permisos de sesión. El frontend expone un único interruptor; las cuatro estrategias de aprobación del backend son combinables mediante este panel y permanecen fail-closed contra la denegación dura P0.',\n 'card.permissive': 'Habilitar el nivel de revisión automática',\n 'card.permissiveHint': 'Cuando está desactivado, la compuerta se comporta exactamente igual que antes.',\n 'card.scopeNote': 'Ámbito del preajuste: esta compuerta solo actúa mientras el preajuste de permisos de la sesión sea %scope. Bajo cualquier otro preajuste la compuerta completa se retira — incluida la denegación dura P0 — y la política del preajuste seleccionado toma el control. La retirada registra un evento y deja una franja persistente sobre la entrada.',\n 'card.strategies': 'Estrategias de aprobación del backend (al menos una activa; combinables)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — las operaciones seguras dentro del ámbito se auto-permiten; peligrosas/desconocidas → consulta (nivel intermedio base)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — cada cruce pregunta; los «controles de permiso» del panel de aprobación reciben dos botones extendidos: «repetir permiso para este tipo esta sesión» (grant acotado de sesión) y «permitir todas las ocurrencias» (persistir la palabra de comando en la lista blanca de rulesFile)',\n 'card.strategy.llmAssist': 'llmAssist — un LLM personalizado evalúa el riesgo: safe → auto-permiso; deletion/credential/remote/system/bulk → riesgos duros mantienen la consulta humana (el clasificador nunca deniega — solo escala); neutral → aprendizaje por confirmación; fallo/timeout → retorno al humano',\n 'card.strategy.trustEscalation': 'trustEscalation — escalado de sandbox sin aviso: para una llamada ya permitida por esta compuerta, la ampliación de sandbox iniciada internamente por shell / pwsh / edit se aprueba aquí en lugar de preguntarte',\n 'card.strategy.trustEscalationHint': 'La aprobación del escalado de sandbox se solicita desde dentro del cuerpo de la herramienta, después de tools/pre-execute, así que la compuerta nunca la ve — una llamada que el LLM calificó como segura y que la compuerta auto-permitió aun así te pedía aprobar la ampliación. Activado, solo la llamada exacta que la compuerta permitió (coincidencia por callId) omite el aviso; todo lo demás va al humano como antes, al igual que cualquier motivo no reconocido o un destino distinto de workspace-write / danger-full-access. Desactívalo para mantener la ampliación bajo control humano.',\n 'card.readonly': 'Solo lectura',\n 'card.unavailable': 'Espacio de nombres de configuración no disponible: asegúrate de que dsh-perm-gate esté ensamblado en este perfil.',\n 'card.llmReceiver': 'LLM receptor de llmAssist (compatible con OpenAI; cualquier API personalizada)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, ej. https://api.openai.com/v1)',\n 'card.llmModel': 'Model (id del modelo, ej. deepseek-chat)',\n 'card.llmKey': 'API Key (secreta)',\n 'card.llmKeyHidden': 'No establecida · se muestra como * tras la primera entrada',\n 'card.llmKeyMasked': 'Establecida · introduce un nuevo valor para sobrescribir',\n 'card.llmKeyOverwrite': 'Hay un valor secreto almacenado; introduce un nuevo valor y sal del campo para sobrescribirlo.',\n 'card.llmKeyClear': 'Borrar',\n 'card.allowlist': 'Lista blanca (allow, sincronizada con rulesFile)',\n 'card.allowlistHint': 'Los patrones en la sección allow se permiten directamente; agrega o elimina entradas una por una, se escriben en rulesFile y se recargan en vivo.',\n 'card.allowlistPresetNote': 'El equivalente de la lista blanca predefinida es la estrategia trustAutoAllow (operaciones seguras en el ámbito auto-permitidas), habilitada en la sección de estrategias de arriba; esta lista refleja tu sección allow de rulesFile y legítimamente comienza vacía.',\n 'card.allowlistEmpty': 'Sin reglas de lista blanca',\n 'card.allowlistPlaceholder': 'Nuevo patrón de comando, ej. npm test*',\n 'card.allowlistAdd': 'Agregar',\n 'card.allowlistRemove': 'Eliminar este patrón',\n 'card.allowlistBulk': 'Edición masiva',\n 'card.allowlistBulkHide': 'Ocultar edición masiva',\n 'card.allowlistSave': 'Guardar lista blanca',\n 'card.riskLearning': 'riskLearning — aprendizaje de veredictos: las operaciones de riesgo neutral aprobadas por el humano y ejecutadas se contabilizan; la misma operación se auto-permite al umbral con huella coincidente',\n 'card.riskLearningHint': 'El estado de aprendizaje pertenece al plugin ($DSH_HOME/perm-gate/learning.json) y nunca se escribe en tus reglas YAML; un destino diferente nunca reutiliza la autoridad. Desactivado por defecto.',\n 'card.riskThreshold': 'Confirmaciones humanas requeridas antes del auto-permiso (1–10)',\n 'notice.label': 'Actividad de la compuerta de permisos',\n 'history.label': 'Aprobaciones',\n 'history.title': 'Registro de aprobaciones de permisos',\n 'history.subtitle': 'Cada decisión de la compuerta en esta sesión, más recientes primero',\n 'history.loading': 'Cargando…',\n 'history.empty': 'Aún no hay registros de aprobación en esta sesión',\n 'history.error': 'Error al cargar: ',\n 'history.tag.auto': 'Auto-permitido',\n 'history.tag.ask': 'Consultado',\n 'history.tag.deny': 'Denegado',\n 'card.denylistRestore': 'Restaurar lista negra predefinida',\n 'card.denylist': 'Lista negra (palabras clave deny, preajuste del plugin)',\n 'card.denylistHint': 'Una llamada cuyo texto contiene una palabra clave (subcadena sin distinción de mayúsculas) se deniega de inmediato, antes que lista blanca / grants / LLM. La lista predefinida hereda de dsh-approval-gate y está activa desde la instalación; edita libremente — vacía o borrada vuelve al preajuste (restauración con un clic), así que la lista negra nunca se desactiva silenciosamente.',\n 'card.denylistEmpty': 'Lista negra vacía (ninguna llamada es vetada por la capa de palabras clave)',\n 'card.denylistPlaceholder': 'Nueva palabra clave, ej. drop database',\n 'card.denylistAdd': 'Agregar',\n 'card.denylistRemove': 'Eliminar esta palabra clave',\n 'card.denylistTagPreset': 'Preajuste',\n 'card.denylistTagCustom': 'Personalizado',\n 'card.riskSediment': 'riskSediment — sedimentación del aprendizaje: las muestras que alcanzan el umbral se convierten en reglas deterministas de auto-permiso',\n 'card.riskSedimentHint': 'Activado, cuando una clave tool|category alcanza el umbral sus huellas de muestra se sedimentan en reglas de permiso — una coincidencia exacta misma herramienta/mismo destino permite directamente sin otra llamada LLM (sigue funcionando con llmAssist desactivado).',\n 'card.sediment': 'Sedimento de aprendizaje (reglas deterministas de permiso)',\n 'card.sedimentHint': 'Reglas sedimentadas a partir de confirmaciones humanas: solo una coincidencia exacta de huella permite, nunca un destino diferente. Termina un aprendizaje o elimina una muestra.',\n 'card.sedimentEmpty': 'Aún no hay reglas sedimentadas (las muestras que alcanzan el umbral aparecen aquí)',\n 'card.sedimentCount': 'confirmado %n/%t',\n 'card.sedimentStop': 'Terminar',\n 'card.sedimentStopTitle': 'Terminar este aprendizaje (elimina el contador y las muestras)',\n 'card.sedimentStopConfirm': '¿Terminar el aprendizaje de «%k»? Se eliminarán su contador y todas las muestras.',\n 'card.sedimentSampleRemove': 'Eliminar esta muestra sedimentada',\n 'card.llmSource': 'Fuente del LLM receptor',\n 'card.llmSourceCustom': 'API personalizada (compatible con OpenAI)',\n 'card.llmSourceHost': 'Usar el modelo predeterminado actual de la sesión (servicio DSH llm)',\n 'card.llmSourceHostHint': 'Por defecto la evaluación de aprobación se ejecuta en el grupo de modelos seleccionado actualmente en la sesión DSH (el valor efectivo se muestra abajo); deja Provider / Model vacío para seguir la sesión, o elige del desplegable o escribe para fijar — tus grupos personalizados configurados en DSH (ej. local-35b) aparecen automáticamente.',\n 'card.llmProvider': 'Provider (vacío = sigue la selección de sesión)',\n 'card.llmProviderPlaceholder': 'Sigue la selección de sesión',\n 'card.llmModelHostPlaceholder': 'Vacío = sigue la selección de sesión',\n 'card.llmResolved': 'Efectivo ahora: %p / %m',\n 'card.llmPreset': 'Preajustes de endpoint (rellena los campos; aún editable)',\n 'card.llmPresetChoose': 'Elegir un preajuste…',\n 'card.llmPresetPublic': 'Preajustes de API públicas',\n 'card.llmPresetHost': 'Grupos de modelos DSH (seleccionar uno cambia al receptor de sesión)',\n 'card.networkEnabled': 'Intercepción de red (networkEnabled)',\n 'card.networkEnabledHint': 'Activado, inicia un proxy local que intercepta las conexiones salientes de los subprocesos y aplica reglas de permiso/denegación. Desactivado = cero cambio de comportamiento.',\n 'card.watch': 'Recarga en caliente de reglas (watch)',\n 'card.watchHint': 'Activado, vigila automáticamente los cambios en los archivos de reglas y los aplica instantáneamente sin recarga manual.',\n 'card.networkRebindNote': 'Surte efecto de inmediato — el proxy se re-vincula automáticamente, sin necesidad de recargar el plugin.',\n 'card.networkInjectEnv': 'Inyectar variables de entorno del proxy (networkInjectEnv)',\n 'card.networkInjectEnvHint': 'Escribe HTTP(S)_PROXY / ALL_PROXY para los subprocesos (y vacía NO_PROXY). Desactivado = el listener funciona pero no se modifica ningún entorno de proceso.',\n 'card.healthStale': 'Ruta del host no disponible (404) — la mitad node sigue siendo una compilación antigua; reinicia completamente dsh (no solo la página del navegador) e inténtalo de nuevo.',\n 'card.healthTest': 'Prueba de salud',\n 'card.healthRunning': 'Probando…',\n 'card.healthOk': 'OK (%ms ms)',\n 'card.healthFail': 'Fallido: ',\n 'history.tag.learned': 'Aprendido',\n 'history.tag.manualApproved': 'Aprobado',\n 'history.tag.manualRejected': 'Rechazado',\n 'history.tag.manualCancelled': 'Cancelado',\n 'history.tag.standDown': 'Compuerta inactiva',\n 'history.learnedProgress': 'aprendido %n/%t',\n 'history.snapshots': 'instantáneas diff',\n 'history.clearSession': 'Borrar esta sesión',\n 'history.clearAll': 'Borrar todo',\n 'history.clearSessionTitle': 'Borrar solo las instantáneas diff de esta sesión (otras sesiones intactas)',\n 'history.clearAllTitle': 'Borrar las instantáneas diff de todas las sesiones, incluidas las no revisadas — pide confirmación',\n 'history.clearSessionConfirm': '¿Borrar las instantáneas diff de esta sesión? Solo se eliminan los datos de comparación generados por las aprobaciones de esta sesión; los registros de aprobación permanecen.',\n 'history.clearAllConfirm': '¿Borrar las instantáneas diff de TODAS las sesiones? Esto puede eliminar comparaciones que otras sesiones aún no han revisado, y es irreversible.',\n 'history.diffTitle': 'Comparación de cambios de archivo',\n 'history.diffClose': 'Cerrar',\n 'history.diffLoading': 'Cargando…',\n 'history.diffEmpty': 'Sin cambios de contenido (o archivo ilegible)',\n 'history.diffLoadFail': 'Error al cargar diff: ',\n 'history.diffRevert': 'Revertir este cambio',\n 'history.diffReverting': 'Enviando…',\n 'history.diffRevertDone': 'Instrucción de reversión enviada',\n 'history.diffRevertSent': 'Instrucción de reversión enviada a la conversación; la IA restaurará el archivo en consecuencia',\n 'history.diffRevertFail': 'Error de envío: ',\n 'history.diffNoSnapshot': 'Este evento no tiene instantánea para ese archivo',\n 'history.diffChipTitle': 'Ver la comparación de cambios de este archivo',\n 'history.diffStats': '+%a / -%r líneas cambiadas · %c sin cambios',\n 'history.diffGone': ' (el archivo ya no existe)',\n 'history.diffHidden': '%n líneas sin modificar',\n 'card.dryRun': 'Prueba de reglas',\n 'card.dryRunHint': 'Juzga una llamada contra las reglas vigentes. No ejecuta ninguna herramienta ni escribe ninguna regla — comprueba aquí antes de cambiar.',\n 'card.dryRunTool': 'Herramienta',\n 'card.dryRunCommand': 'Comando / argumentos',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'Probar',\n 'card.dryRunRunning': 'Evaluando…',\n 'card.dryRunEmpty': 'Nada probado aún. Rellena una herramienta y un comando, luego pulsa Probar para ver el veredicto.',\n 'card.dryRunVerdict': 'Veredicto',\n 'card.dryRunAllow': 'permitir',\n 'card.dryRunAsk': 'consultar',\n 'card.dryRunDeny': 'denegar',\n 'card.dryRunRule': 'Regla coincidente',\n 'card.dryRunRuleNone': 'ninguna regla coincidió; defaultAction: %d',\n 'card.dryRunDimensions': 'Dimensiones',\n 'card.dryRunReason': 'Razón',\n 'card.dryRunNote': '«Regla coincidente» proviene de la capa de reglas. Cuando el veredicto fue producido por una denegación dura anterior o por la lista negra de palabras clave no hay índice de regla — las dimensiones listadas son solo informativas.',\n 'card.dryRunNoRules': '(0 reglas cargadas — comprueba la ruta de rulesFile)',\n 'card.dryRunFail': 'Prueba fallida: ',\n 'card.dryRunStale': 'ruta ausente (¿plugin no reiniciado?)',\n 'card.rules': 'Reglas integradas de configuración',\n 'card.rulesHint': 'Las reglas que la compuerta está cargando ahora (del campo de configuración rules de esta entrada de plugin; retroceso al archivo de reglas si no está configurado). Solo lectura — nada aquí puede modificarlas. Para cambiar reglas, usa la lista blanca de abajo o edítalas en la página de configuración.',\n 'card.rulesRefresh': 'Actualizar',\n 'card.rulesLoading': 'Leyendo…',\n 'card.rulesPath': 'Origen',\n 'card.rulesNone': 'sin reglas configuradas',\n 'card.rulesCounts': 'Reglas',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b bytes · %l líneas',\n 'card.rulesMissing': 'Reglas no encontradas. La compuerta retrocede a sus valores predeterminados integrados.',\n 'card.rulesTruncated': 'Reglas grandes; se muestran solo los primeros 512 KB.',\n 'card.rulesError': 'Error de carga: ',\n 'card.rulesStale': 'ruta ausente (¿plugin no reiniciado?)',\n 'card.rulesNote': 'Solo lectura: este panel no puede modificar las reglas. La sección de lista blanca y «permitir siempre» escriben de vuelta en la configuración de esta entrada de plugin.',\n}\n\n/**\n * Combined dictionary map for all 9 active languages, registered in ONE\n * `locale.register(NS, dictionaries)` call. The map form is deliberately left\n * with its inferred literal type instead of a loose\n * `Record<string, Record<string, string>>` annotation: `dsh-perm-gate` is a\n * declared namespace in `LocaleNamespaceMap`, so the locale service resolves\n * the TYPED `register(ns, dicts)` overload, which requires the built-in\n * `zh`/`en` keys to be statically present (an index signature would not\n * guarantee them and fails the assignment). The runtime still iterates every\n * entry of the map and accepts any BCP 47-style locale id, so the seven\n * extension languages activate through the very same call.\n */\nexport const dictionaries = { zh, en, ja, ko, fr, de, it, ru, es }\n","/**\n * Preset deny keywords inherited from dsh-approval-gate's `DEFAULT_DENY_KEYWORDS`\n * (the preset blacklist layer of its pipeline). One keyword per entry, matched\n * case-insensitively on word boundaries against the call's command text and its\n * scalar arguments — document bodies are skipped — so a keyword can no longer\n * veto an unrelated identifier or file text that merely contains it.\n *\n * Pure data shared by the node half (deny-keyword pre-layer) and the client\n * bundle (the settings card's preset tags), so it must stay import-free.\n */\n\n/** The preset blacklist; the gate applies it whenever the namespace carries no override. */\nexport const DEFAULT_DENY_KEYWORDS: readonly string[] = [\n 'rm -rf', 'rm -fr', 'rm -r -f', 'rm --recursive --force',\n 'push --force', 'force-push', 'force push', 'drop table', 'drop database',\n 'mkfs', 'mkfs.ext', 'format', 'shutdown', 'reboot', 'dd of=',\n 'delete from', 'truncate table', 'truncate ', 'terraform destroy', 'revoke',\n '清空数据库', '删除数据库', '格式化', 'sudo rm', 'chmod 777 /',\n 'git reset --hard', 'git clean -fd', 'docker rm', 'docker system prune',\n]\n","/**\n * Known OpenAI-compatible endpoint presets for the llmAssist receiver\n * (the settings card fills endpoint + model from one pick; every field stays\n * editable afterwards). Pure data shared by the node half and the client\n * bundle, so it must stay import-free.\n */\n\n/** One preset receiver endpoint. */\nexport interface LlmPreset {\n readonly id: string\n readonly label: string\n /** OpenAI-compatible base URL (the `/chat/completions` suffix is normalized away). */\n readonly endpoint: string\n /** Suggested chat model id (editable after filling). */\n readonly model: string\n}\n\nexport const LLM_PRESETS: readonly LlmPreset[] = [\n { id: 'deepseek', label: 'DeepSeek', endpoint: 'https://api.deepseek.com/v1', model: 'deepseek-chat' },\n { id: 'xiaomi-mimo', label: '小米 MiMo', endpoint: 'https://api.xiaomimimo.com/v1', model: 'mimo-v2.5' },\n { id: 'openai', label: 'OpenAI', endpoint: 'https://api.openai.com/v1', model: 'gpt-4o-mini' },\n]\n","/**\n * Session permission-preset awareness for dsh-perm-gate.\n *\n * `dsh-permission-presets` folds three durable knob events per session\n * (`permission/preset`, `sandbox/mode`, `approval/policy`) and pins an initial\n * `permission/preset` at session creation, so the last `permission/preset`\n * event names the tier the user selected. The gate reads that fold to decide\n * whether its own approval tier is the active one.\n *\n * Reading the session log directly (instead of requiring the\n * `permissionPresets` service) keeps the gate usable in a bare embedding and\n * avoids a hard dependency on a service that may not be composed. The fold\n * matches `effectivePermissionPreset` in dsh-permission-presets: last event\n * wins.\n */\n\n/** The slice of one session event this module folds. */\nexport interface SessionEventLike {\n readonly type?: string\n readonly data?: { readonly preset?: unknown }\n}\n\n/**\n * Fold the last selected permission preset out of one session's event log.\n * @param events - the session's events in log order.\n * @returns the preset name, or `undefined` when the log records none.\n */\nexport function permissionPresetOf(events: readonly SessionEventLike[] | undefined): string | undefined {\n if (events === undefined) return undefined\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index]\n if (event?.type !== 'permission/preset') continue\n const preset = event.data?.preset\n if (typeof preset === 'string' && preset !== '') return preset\n }\n return undefined\n}\n\n/** Whether one preset name is covered by a configured scope list. */\nexport function presetInScope(preset: string | undefined, scope: readonly string[]): boolean {\n if (scope.includes('*')) return true\n if (preset === undefined) return false\n return scope.includes(preset)\n}\n\n/**\n * Presets in which the gate is active. It owns both 自动审查 tiers — the plain\n * one (file sandbox kept) and the full-access one (sandbox restriction lifted,\n * same approval behaviour) — so a user can have the gate without inheriting a\n * sandbox that breaks `git` / Cygwin tools. `'*'` makes it global (every\n * preset, including the hard-deny layer).\n *\n * Lives in this dependency-free module (not `config.ts`) so the browser half can\n * render the scope without pulling schemastery into the client bundle.\n */\nexport const DEFAULT_GATE_PRESETS: readonly string[] = ['permissive', 'permissive-full']\n\n/** Normalize the gate scope: an unset/empty list means the default. */\nexport function resolveGatePresets(configured?: readonly string[]): readonly string[] {\n if (configured === undefined || configured.length === 0) return DEFAULT_GATE_PRESETS\n return configured.filter((name) => typeof name === 'string' && name !== '')\n}\n","/**\n * Learning-sediment management section — the settings-card face of verdict\n * learning's \"沉淀\" (the ⑤ card pattern demonstrated by dsh-approval-gate):\n * every threshold-reached key's confirmed samples, listed as the deterministic\n * auto-allow rules they now are, with per-key terminate and per-sample remove.\n *\n * Data source: the host's `GET /api/dsh-perm-gate/learning` route (the same\n * learning.json store the gate reads); actions POST back. Best-effort: a\n * missing route renders the empty state, never an error.\n */\nimport { useEffect, useRef, useState } from 'react'\nimport type { CSSProperties, JSX } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\n\ninterface LearningSample {\n readonly fp: string\n readonly ctx: string\n readonly at: number\n}\n\ninterface LearningBody {\n readonly ok?: boolean\n readonly threshold?: number\n readonly confirmed?: Record<string, number>\n readonly samples?: Record<string, LearningSample[]>\n}\n\nconst itemStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '4px 8px',\n borderRadius: '6px',\n border: '1px solid var(--dsw-alias-border-l2)',\n background: 'var(--dsw-alias-bg-surface, transparent)',\n}\n\nconst chipStyle: CSSProperties = {\n fontSize: '11px',\n lineHeight: '16px',\n padding: '0 6px',\n borderRadius: '8px',\n color: 'var(--dsw-alias-label-tertiary)',\n border: '1px solid var(--dsw-alias-border-l2)',\n}\n\nconst delButtonStyle: CSSProperties = {\n flex: '0 0 auto',\n width: '20px',\n height: '20px',\n border: 'none',\n borderRadius: '999px',\n background: 'transparent',\n color: 'var(--dsw-alias-label-tertiary)',\n cursor: 'pointer',\n}\n\n/** Full props: the locale seat delivered by the slot system. */\nexport type SedimentSectionProps = PropsLocale<'dsh-perm-gate'>\n\nexport function SedimentSection({ t }: SedimentSectionProps): JSX.Element | null {\n const [body, setBody] = useState<LearningBody | null>(null)\n /** Latest loader, so a mutation can refresh the list without owning the fetch. */\n const reloadRef = useRef<() => void>(() => {})\n\n useEffect(() => {\n let alive = true\n const load = (): void => {\n fetch('/api/dsh-perm-gate/learning', { headers: { 'cache-control': 'no-cache' } })\n .then((r) => (r.ok ? r.json() : Promise.reject(new Error(`HTTP ${r.status}`))))\n .then((data: LearningBody) => { if (alive) setBody(data) })\n .catch(() => { if (alive) setBody({}) })\n }\n reloadRef.current = load\n load()\n // Deliberately no timer: the store only moves when this section mutates it or\n // the gate confirms a sample mid-session, so loading on mount, after every\n // action, and on return to the page covers it at zero idle cost.\n const onVisible = (): void => {\n if (document.visibilityState === 'visible') load()\n }\n window.addEventListener('focus', onVisible)\n document.addEventListener('visibilitychange', onVisible)\n return () => {\n alive = false\n reloadRef.current = () => {}\n window.removeEventListener('focus', onVisible)\n document.removeEventListener('visibilitychange', onVisible)\n }\n }, [])\n\n const post = (payload: { key: string; fp?: string }): void => {\n void fetch('/api/dsh-perm-gate/learning', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n }).then(() => { reloadRef.current() }).catch(() => {})\n }\n\n const threshold = body?.threshold ?? 3\n const confirmed = body?.confirmed ?? {}\n const samples = body?.samples ?? {}\n const keys = Object.entries(confirmed).filter(([, count]) => count >= threshold)\n\n if (body === null) return null\n return (\n <div style={{ marginTop: '6px' }}>\n {keys.length === 0\n ? <div style={{ padding: '4px 0', fontSize: '12px', color: 'var(--dsw-alias-label-tertiary)' }}>{t('card.sedimentEmpty')}</div>\n : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>\n {keys.map(([key, count]) => (\n <div key={key} style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>\n <div style={itemStyle}>\n <code style={{ font: '600 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>{key}</code>\n <span style={chipStyle}>{t('card.sedimentCount').replace('%n', String(count)).replace('%t', String(threshold))}</span>\n <span style={{ flex: '1 1 auto' }} />\n <button\n type=\"button\"\n title={t('card.sedimentStopTitle')}\n onClick={() => {\n if (window.confirm(t('card.sedimentStopConfirm').replace('%k', key))) post({ key })\n }}\n style={{ ...delButtonStyle, width: 'auto', padding: '0 8px', border: '1px solid var(--dsw-alias-border-l2)' }}\n >\n {t('card.sedimentStop')}\n </button>\n </div>\n {(samples[key] ?? []).map((s) => (\n <div key={`${key}:${s.fp}`} style={{ ...itemStyle, marginLeft: '16px' }}>\n <code style={{ flex: '1 1 auto', minWidth: 0, overflowWrap: 'anywhere', font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-secondary, inherit)' }}>\n {s.fp}\n {s.ctx !== '' ? <span style={{ color: 'var(--dsw-alias-label-tertiary)' }}>{` — ${s.ctx}`}</span> : null}\n </code>\n <button\n type=\"button\"\n aria-label={t('card.sedimentSampleRemove')}\n title={t('card.sedimentSampleRemove')}\n onClick={() => { post({ key, fp: s.fp }) }}\n style={delButtonStyle}\n >\n ✕\n </button>\n </div>\n ))}\n </div>\n ))}\n </div>\n )}\n </div>\n )\n}\n","/**\n * Permissive settings card — the top-level `settings.section` (自动审查门) of dsh-perm-gate.\n *\n * The card binds the plugin's profile entry (`dsh-perm-gate`) through the\n * `configForms` cordis service and renders its fields: the single front switch\n * (`permissive`) plus the three combinable backend strategies\n * (`trustAutoAllow` / `alwaysConfirm` / `llmAssist`). Every change commits\n * immediately through the scope (no staged form); the host reads the namespace\n * live, so a committed change applies to the next tool call without a restart.\n *\n * Kept dependency-free beyond react: the scope is subscribed with\n * `useSyncExternalStore`, and the controls are plain HTML.\n */\nimport { useEffect, useState, useSyncExternalStore } from 'react'\nimport type { CSSProperties, JSX } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SettingsDocHandle } from './compat.ts'\nimport { DEFAULT_DENY_KEYWORDS } from '../deny-defaults.ts'\nimport { LLM_PRESETS } from '../llm-presets.ts'\nimport { DEFAULT_GATE_PRESETS } from '../preset.ts'\nimport { SedimentSection } from './sediment.tsx'\n\n/** The settings namespace value the host registers (kept in lockstep with src/index.ts). */\nexport interface PermissiveCardValue {\n permissive?: boolean\n permissiveStrategies?: { trustAutoAllow?: boolean; alwaysConfirm?: boolean; llmAssist?: boolean; trustEscalation?: boolean }\n /** OpenAI-compatible endpoint the llmAssist classifier calls (custom API allowed). */\n classifierEndpoint?: string\n /** llmAssist receiver source: custom endpoint or the DSH host model group. */\n classifierSource?: string\n /** Optional provider override for the host receiver. */\n classifierProvider?: string\n /** Model id used by the llmAssist classifier. */\n classifierModel?: string\n /** Secret bearer token / API key for the classifier endpoint (masked in the UI). */\n classifierApiKey?: string\n /** Timeout for one llmAssist risk call (ms). */\n riskTimeoutMs?: number\n /** Verdict learning: neutral-risk human confirmations may auto-allow the exact same operation later. */\n riskLearning?: boolean\n /** Confirmations required before a learned auto-allow (1–10). */\n riskThreshold?: number\n /** Learning sedimentation: threshold-reached samples become deterministic auto-allows. */\n riskSediment?: boolean\n /** Editable whitelist (allow-list command patterns), one per entry. */\n allowlist?: string[]\n /** Editable deny-keyword blacklist; unset applies the inherited preset list. */\n denyKeywords?: string[]\n /**\n * Session permission presets in which the gate acts at all (the host's\n * resolved `gatePresets`). Outside them the whole gate — P0 hard-deny\n * included — stands down; the card states that scope so the user is not\n * surprised by a silent stand-down.\n */\n gatePresets?: string[]\n // ─── Network (Phase 2) ─────────────────────────────────────────────\n /** Master network switch. When false, no proxy is started. */\n networkEnabled?: boolean\n /** Network policy mode. */\n networkMode?: 'deny-all' | 'whitelist' | 'allow-all'\n /** Rewrite HTTP(S)_PROXY / ALL_PROXY for subprocesses. Default true. */\n networkInjectEnv?: boolean\n // ─── Hot reload (Phase 3) ──────────────────────────────────────────\n /** Enable file watching for rule hot-reload. */\n watch?: boolean\n}\n\n/** One injected face: the plugin's own settings scope. Typed as the local\n * structural handle (compat.ts) instead of the host package's `ConfigForm` —\n * the host type's shape moves between host lines (0.1.5 set/unset vs 0.2.0\n * mutate-centered snapshot), and the card must compile identically against\n * every line's real types. */\nexport interface PermissiveCardInjected {\n scope: SettingsDocHandle\n}\n\n/** Full props: locale seat + the injected scope. */\nexport type PermissiveCardProps = PropsLocale<'dsh-perm-gate'> & PermissiveCardInjected\n\n/** The receiver projection served by GET /api/dsh-perm-gate/receiver. */\ninterface ReceiverInfoBody {\n readonly ok?: boolean\n readonly source?: 'custom' | 'host'\n readonly selection?: { readonly provider: string; readonly model: string } | null\n readonly providers?: readonly { readonly id: string; readonly name: string; readonly models: readonly { readonly id: string; readonly name: string }[]; readonly error?: string }[]\n}\n\n/**\n * The report served by POST /api/dsh-perm-gate/dry-run. `verdict` is the\n * effective result of the whole chain; `ruleLayer` is what the `permissions`\n * chain decides on its own, and only that layer can name a rule index.\n */\ninterface DryRunReport {\n readonly verdict?: 'allow' | 'ask' | 'deny'\n readonly reason?: string\n readonly ruleCount?: number\n readonly defaultAction?: string\n readonly ruleLayer?: {\n readonly action?: 'allow' | 'ask' | 'deny'\n readonly reason?: string\n readonly ruleIndex?: number\n readonly matchedDimensions?: readonly string[]\n }\n}\n\n/**\n * The document served by GET /api/dsh-perm-gate/rules: the permissions YAML the\n * gate is loading, plus what it parsed to.\n *\n * `error` is a rendered state, not a transport failure. A missing or\n * uncompilable file is exactly what the operator opened this section to see —\n * a viewer that only worked on healthy input would be useless precisely when it\n * is needed.\n */\ninterface RulesViewBody {\n readonly path?: string\n readonly exists?: boolean\n readonly bytes?: number\n readonly hash?: string\n readonly lines?: number\n readonly raw?: string\n readonly truncated?: boolean\n readonly defaultAction?: string\n readonly counts?: { readonly allow?: number; readonly deny?: number; readonly ask?: number }\n readonly error?: string\n}\n\nconst rowStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '12px',\n padding: '6px 0',\n fontSize: '13px',\n lineHeight: '20px',\n}\n\nconst labelStyle: CSSProperties = { margin: 0, color: 'var(--dsw-alias-label-primary)' }\n\nconst hintStyle: CSSProperties = { margin: '4px 0 0', fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' }\n\nconst sectionStyle: CSSProperties = {\n marginTop: '12px',\n paddingTop: '10px',\n borderTop: '1px solid var(--dsw-alias-border-l2)',\n}\n\nconst controlStyle: CSSProperties = {\n background: 'var(--dsw-alias-bg-surface, #fff)',\n color: 'var(--dsw-alias-label-primary)',\n border: '1px solid var(--dsw-alias-border-l2)',\n borderRadius: '4px',\n padding: '3px 8px',\n fontSize: '13px',\n}\n\nconst fieldStyle: CSSProperties = { display: 'flex', flexDirection: 'column', gap: '4px' }\n\nconst fieldLabelStyle: CSSProperties = { margin: 0, fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' }\n\n/**\n * The card body, wrapped in a disclosure shell like every peer settings card:\n * a header (name + description + chevron) toggling the body, expanded by\n * default so the section reads as an open page of drawers.\n */\nexport function PermissiveCard({ t, scope }: PermissiveCardProps): JSX.Element {\n const [open, setOpen] = useState(true)\n // The api key is kept OUT of the visible value (secret): a fresh typed draft\n // overwrites on blur; an already-set key shows only a masked placeholder.\n const [apiKeyDraft, setApiKeyDraft] = useState('')\n // Whitelist draft (one pattern per line); `allowDirty` avoids clobbering user\n // edits when the host re-seeds the namespace after mount.\n const [allowText, setAllowText] = useState('')\n const [allowDirty, setAllowDirty] = useState(false)\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<PermissiveCardValue>\n const strategies = value.permissiveStrategies ?? {}\n const hasApiKey = typeof value.classifierApiKey === 'string' && value.classifierApiKey !== ''\n\n // The backend strategy toggles only take effect while the tier is on.\n const effective = value.permissive === true\n\n const commitApiKey = (): void => {\n const next = apiKeyDraft.trim()\n if (next === '') return\n void scope.set('classifierApiKey', next)\n setApiKeyDraft('') // never echo the secret back after it is stored\n }\n const clearApiKey = (): void => {\n void scope.unset('classifierApiKey')\n setApiKeyDraft('')\n }\n\n // Show the persisted allowlist until the user starts editing a fresh draft.\n const allowlistShown = allowDirty ? allowText : (value.allowlist ?? []).join('\\n')\n const commitAllowlist = (): void => {\n const lines = allowlistShown.split('\\n').map((s) => s.trim()).filter((s) => s.length > 0)\n void scope.set('allowlist', lines)\n setAllowDirty(false)\n }\n // List-face state: one add-input draft plus per-row delete (approval-gate's\n // rules-list pattern); the bulk textarea stays behind a toggle.\n const [addDraft, setAddDraft] = useState('')\n const [bulkOpen, setBulkOpen] = useState(false)\n // Health-test state for the llmAssist receiver.\n const [healthBusy, setHealthBusy] = useState(false)\n const [healthResult, setHealthResult] = useState<string | null>(null)\n // Rule-test (dry-run) state: the call to try and its report. Read-only — the\n // panel never writes a rule, so \"test first\" cannot itself change the ruleset.\n const [dryTool, setDryTool] = useState('shell')\n const [dryCommand, setDryCommand] = useState('')\n const [dryBusy, setDryBusy] = useState(false)\n const [dryReport, setDryReport] = useState<DryRunReport | null>(null)\n const [dryError, setDryError] = useState<string | null>(null)\n const runDryRunTest = (): void => {\n const tool = dryTool.trim() === '' ? 'shell' : dryTool.trim()\n const command = dryCommand.trim()\n setDryBusy(true)\n setDryError(null)\n setDryReport(null)\n // A shell call is described by its `command`; any other tool's arguments are\n // not expressible in one line, so the panel honestly tests the empty form.\n const args: Record<string, unknown> = command === '' ? {} : { command }\n fetch('/api/dsh-perm-gate/dry-run', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tool, args }),\n })\n .then(async (r) => {\n const text = await r.text()\n if (r.status === 404) throw new Error(t('card.dryRunStale'))\n try {\n return JSON.parse(text) as { ok?: boolean; result?: DryRunReport; error?: string }\n } catch {\n throw new Error(text.trim().slice(0, 120) !== '' ? text.trim().slice(0, 120) : `HTTP ${r.status}`)\n }\n })\n .then((res) => {\n if (res.ok === true && res.result !== undefined) setDryReport(res.result)\n else setDryError(res.error ?? t('card.dryRunFail'))\n })\n .catch((e: unknown) => { setDryError(String((e as Error)?.message ?? e)) })\n .finally(() => { setDryBusy(false) })\n }\n // Permissions YAML (read-only): the document the gate is actually loading, so\n // the panel can never be editing a file it cannot display. Loaded on mount —\n // a viewer you have to ask to load is one more reason not to look.\n const [rulesBody, setRulesBody] = useState<RulesViewBody | null>(null)\n const [rulesBusy, setRulesBusy] = useState(false)\n const [rulesError, setRulesError] = useState<string | null>(null)\n const loadRules = (): void => {\n setRulesBusy(true)\n setRulesError(null)\n fetch('/api/dsh-perm-gate/rules', { headers: { 'cache-control': 'no-cache' } })\n .then(async (r) => {\n const text = await r.text()\n if (r.status === 404) throw new Error(t('card.rulesStale'))\n try {\n return JSON.parse(text) as { ok?: boolean; result?: RulesViewBody; error?: string }\n } catch {\n throw new Error(text.trim().slice(0, 120) !== '' ? text.trim().slice(0, 120) : `HTTP ${r.status}`)\n }\n })\n .then((res) => {\n if (res.ok === true && res.result !== undefined) setRulesBody(res.result)\n else setRulesError(res.error ?? t('card.rulesError'))\n })\n .catch((e: unknown) => { setRulesError(String((e as Error)?.message ?? e)) })\n .finally(() => { setRulesBusy(false) })\n }\n useEffect(() => { loadRules() }, [])\n // Receiver introspection: the live provider/model-group catalog (host mode)\n // and the provider/model the gate will actually use right now.\n const receiverSource = (value.classifierSource ?? 'custom') === 'host' ? 'host' : 'custom'\n const [receiverInfo, setReceiverInfo] = useState<ReceiverInfoBody | null>(null)\n const [receiverNonce, setReceiverNonce] = useState(0)\n useEffect(() => {\n let alive = true\n fetch('/api/dsh-perm-gate/receiver', { headers: { 'cache-control': 'no-cache' } })\n .then((r) => (r.ok ? r.json() : Promise.reject(new Error(`HTTP ${r.status}`))))\n .then((data: ReceiverInfoBody) => { if (alive) setReceiverInfo(data) })\n .catch(() => { if (alive) setReceiverInfo(null) })\n return () => { alive = false }\n }, [receiverSource, receiverNonce])\n const receiverProviderDraft = value.classifierProvider ?? ''\n const patterns = value.allowlist ?? []\n const removePattern = (index: number): void => {\n void scope.set('allowlist', patterns.filter((_, i) => i !== index))\n }\n const addPattern = (): void => {\n const next = addDraft.trim()\n if (next === '' || readonly) return\n void scope.set('allowlist', [...patterns, next])\n setAddDraft('')\n }\n // Deny-keyword blacklist: an explicit non-empty namespace array replaces the\n // preset; unset OR empty (schemastery materializes unset arrays as `[]`)\n // applies the inherited defaults — the protective blacklist is never off.\n const denyActive = Array.isArray(value.denyKeywords) && value.denyKeywords.length > 0\n const denylist = denyActive ? (value.denyKeywords as string[]) : [...DEFAULT_DENY_KEYWORDS]\n const [denyDraft, setDenyDraft] = useState('')\n const removeDeny = (index: number): void => {\n void scope.set('denyKeywords', denylist.filter((_, i) => i !== index))\n }\n const addDeny = (): void => {\n const next = denyDraft.trim()\n if (next === '' || readonly) return\n void scope.set('denyKeywords', [...denylist, next])\n setDenyDraft('')\n }\n const restoreDeny = (): void => {\n void scope.unset('denyKeywords')\n }\n\n return (\n <div style={{\n border: '1px solid var(--dsw-alias-border-l2, rgba(127,127,127,0.35))',\n background: 'var(--dsw-alias-bg-layer-3, rgba(127,127,127,0.05))',\n borderRadius: '12px',\n transition: 'border-color 0.16s, background 0.16s',\n }}>\n <button\n type=\"button\"\n aria-expanded={open}\n style={{\n appearance: 'none',\n width: '100%',\n font: 'inherit',\n color: 'inherit',\n textAlign: 'left',\n cursor: 'pointer',\n background: 'none',\n border: 0,\n borderRadius: '12px',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '14px 16px',\n }}\n onClick={() => { setOpen(current => !current) }}\n >\n <span style={{ flex: '1 1 0%', minWidth: 0 }}>\n <div style={{ fontSize: '14px', fontWeight: 600, color: 'var(--dsw-alias-label-primary)' }}>{t('card.title')}</div>\n <div style={{ color: 'var(--dsw-alias-label-tertiary, rgba(127,127,127,0.8))', fontSize: '13px', lineHeight: 1.5 }}>{t('card.description')}</div>\n </span>\n <svg\n width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden\n style={{\n color: 'var(--dsw-alias-label-tertiary, rgba(127,127,127,0.8))',\n flex: '0 0 auto',\n transition: 'transform 0.16s',\n transform: open ? 'rotate(180deg)' : 'none',\n }}\n >\n <path d=\"M4 6l4 4 4-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n {open\n ? (\n <div style={{ padding: '12px 16px' }}>\n {unavailable\n ? (\n <div style={{ fontSize: '13px', color: 'var(--dsw-alias-label-tertiary)' }}>\n {t('card.unavailable')}\n </div>\n )\n : (\n <>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-permissive\" style={labelStyle}>{t('card.permissive')}</label>\n <input\n id=\"plugin-config-perm-gate-permissive\"\n type=\"checkbox\"\n checked={effective}\n disabled={readonly}\n onChange={(event) => { void scope.set('permissive', event.currentTarget.checked) }}\n />\n </div>\n <p style={hintStyle}>{t('card.permissiveHint')}</p>\n {/* The gate's own scope: outside these presets the WHOLE gate\n stands down, P0 hard-deny included (see the stand-down note\n in src/runtime.ts). Stated here because the settings card is\n where the tier is configured, and a silent stand-down would\n otherwise look like a gate that approved the call. */}\n <p style={hintStyle}>\n {t('card.scopeNote').replace(\n '%scope',\n ((value.gatePresets ?? []).length > 0 ? (value.gatePresets as string[]) : [...DEFAULT_GATE_PRESETS]).join(' / '),\n )}\n </p>\n\n <section style={sectionStyle}>\n <p style={labelStyle}>{t('card.strategies')}</p>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-trust\" style={{ fontSize: '12px' }}>{t('card.strategy.trustAutoAllow')}</label>\n <input\n id=\"plugin-config-perm-gate-trust\"\n type=\"checkbox\"\n checked={strategies.trustAutoAllow ?? true}\n disabled={readonly || !effective}\n onChange={(event) => {\n void scope.set('permissiveStrategies', {\n ...strategies,\n trustAutoAllow: event.currentTarget.checked,\n })\n }}\n />\n </div>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-confirm\" style={{ fontSize: '12px' }}>{t('card.strategy.alwaysConfirm')}</label>\n <input\n id=\"plugin-config-perm-gate-confirm\"\n type=\"checkbox\"\n checked={strategies.alwaysConfirm ?? false}\n disabled={readonly || !effective}\n onChange={(event) => {\n void scope.set('permissiveStrategies', {\n ...strategies,\n alwaysConfirm: event.currentTarget.checked,\n })\n }}\n />\n </div>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-llm\" style={{ fontSize: '12px' }}>{t('card.strategy.llmAssist')}</label>\n <input\n id=\"plugin-config-perm-gate-llm\"\n type=\"checkbox\"\n checked={strategies.llmAssist ?? false}\n disabled={readonly || !effective}\n onChange={(event) => {\n void scope.set('permissiveStrategies', {\n ...strategies,\n llmAssist: event.currentTarget.checked,\n })\n }}\n />\n </div>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-escalation\" style={{ fontSize: '12px' }}>{t('card.strategy.trustEscalation')}</label>\n <input\n id=\"plugin-config-perm-gate-escalation\"\n type=\"checkbox\"\n checked={strategies.trustEscalation ?? true}\n disabled={readonly || !effective}\n onChange={(event) => {\n void scope.set('permissiveStrategies', {\n ...strategies,\n trustEscalation: event.currentTarget.checked,\n })\n }}\n />\n </div>\n <p style={hintStyle}>{t('card.strategy.trustEscalationHint')}</p>\n {strategies.llmAssist === true\n ? (\n <section style={sectionStyle}>\n <p style={labelStyle}>{t('card.llmReceiver')}</p>\n <label style={fieldStyle}>\n <span style={fieldLabelStyle}>{t('card.llmSource')}</span>\n <select\n value={value.classifierSource ?? 'custom'}\n disabled={readonly}\n style={controlStyle}\n onChange={(event) => { void scope.set('classifierSource', event.currentTarget.value) }}\n >\n <option value=\"custom\">{t('card.llmSourceCustom')}</option>\n <option value=\"host\">{t('card.llmSourceHost')}</option>\n </select>\n </label>\n {(value.classifierSource ?? 'custom') === 'custom'\n ? (\n <>\n <label style={fieldStyle}>\n <span style={fieldLabelStyle}>{t('card.llmPreset')}</span>\n <select\n value=\"\"\n disabled={readonly}\n style={controlStyle}\n onChange={(event) => {\n const v = event.currentTarget.value\n if (v.startsWith('host:')) {\n // A DSH model group: switch to the host receiver\n // and pin the provider (model follows the session).\n void scope.set('classifierSource', 'host')\n void scope.set('classifierProvider', v.slice('host:'.length))\n return\n }\n const preset = LLM_PRESETS.find((p) => p.id === v)\n if (preset !== undefined) {\n void scope.set('classifierEndpoint', preset.endpoint)\n void scope.set('classifierModel', preset.model)\n }\n }}\n >\n <option value=\"\">{t('card.llmPresetChoose')}</option>\n <optgroup label={t('card.llmPresetPublic')}>\n {LLM_PRESETS.map((preset) => (\n <option key={preset.id} value={preset.id}>{preset.label}</option>\n ))}\n </optgroup>\n {(receiverInfo?.providers ?? []).length > 0\n ? (\n <optgroup label={t('card.llmPresetHost')}>\n {(receiverInfo?.providers ?? []).map((p) => (\n <option key={`host:${p.id}`} value={`host:${p.id}`}>\n {`${t('card.llmSourceHost')} · ${p.id}`}\n </option>\n ))}\n </optgroup>\n )\n : null}\n </select>\n </label>\n <label style={fieldStyle}>\n <span style={fieldLabelStyle}>{t('card.llmEndpoint')}</span>\n <input\n type=\"text\"\n value={value.classifierEndpoint ?? ''}\n disabled={readonly}\n placeholder=\"https://api.openai.com/v1\"\n style={controlStyle}\n onChange={(event) => { void scope.set('classifierEndpoint', event.currentTarget.value) }}\n onBlur={(event) => {\n if (event.currentTarget.value.trim() === '') void scope.unset('classifierEndpoint')\n }}\n />\n </label>\n </>\n )\n : (\n <>\n <p style={hintStyle}>{t('card.llmSourceHostHint')}</p>\n <label style={fieldStyle}>\n <span style={fieldLabelStyle}>{t('card.llmProvider')}</span>\n <input\n type=\"text\"\n list=\"perm-gate-provider-options\"\n value={value.classifierProvider ?? ''}\n disabled={readonly}\n placeholder={t('card.llmProviderPlaceholder')}\n style={controlStyle}\n onChange={(event) => { void scope.set('classifierProvider', event.currentTarget.value) }}\n onBlur={(event) => {\n if (event.currentTarget.value.trim() === '') void scope.unset('classifierProvider')\n }}\n />\n <datalist id=\"perm-gate-provider-options\">\n {(receiverInfo?.providers ?? []).map((p) => (\n <option key={p.id} value={p.id}>{p.name}{p.error !== undefined ? ` (${p.error})` : ''}</option>\n ))}\n </datalist>\n </label>\n {receiverInfo?.selection !== null && receiverInfo?.selection !== undefined\n ? (\n <span style={hintStyle}>\n {t('card.llmResolved')\n .replace('%p', receiverInfo.selection.provider)\n .replace('%m', receiverInfo.selection.model)}\n </span>\n )\n : null}\n </>\n )}\n <label style={fieldStyle}>\n <span style={fieldLabelStyle}>{t('card.llmModel')}</span>\n <input\n type=\"text\"\n list={receiverSource === 'host' ? 'perm-gate-model-options' : undefined}\n value={value.classifierModel ?? ''}\n disabled={readonly}\n placeholder={receiverSource === 'host' ? t('card.llmModelHostPlaceholder') : 'deepseek-chat'}\n style={controlStyle}\n onChange={(event) => { void scope.set('classifierModel', event.currentTarget.value) }}\n onBlur={(event) => {\n if (event.currentTarget.value.trim() === '') void scope.unset('classifierModel')\n }}\n />\n <datalist id=\"perm-gate-model-options\">\n {(receiverInfo?.providers ?? [])\n .filter((p) => receiverProviderDraft === '' || p.id === receiverProviderDraft)\n .flatMap((p) => p.models)\n .map((m) => <option key={`${m.id}`} value={m.id}>{m.name}</option>)}\n </datalist>\n </label>\n <label style={fieldStyle}>\n <span style={fieldLabelStyle}>{t('card.llmKey')}</span>\n <div style={{ display: 'flex', gap: '6px' }}>\n <input\n type=\"password\"\n autoComplete=\"off\"\n spellCheck={false}\n value={apiKeyDraft}\n disabled={readonly}\n placeholder={hasApiKey ? t('card.llmKeyMasked') : t('card.llmKeyHidden')}\n style={{ ...controlStyle, flex: '1 1 0%' }}\n onChange={(event) => setApiKeyDraft(event.currentTarget.value)}\n onBlur={commitApiKey}\n onKeyDown={(event) => {\n if (event.key === 'Enter') (event.currentTarget as HTMLInputElement).blur()\n }}\n />\n {hasApiKey\n ? (\n <button type=\"button\" disabled={readonly} onClick={clearApiKey} style={controlStyle}>\n {t('card.llmKeyClear')}\n </button>\n )\n : null}\n </div>\n {hasApiKey && <span style={hintStyle}>{t('card.llmKeyOverwrite')}</span>}\n </label>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '4px' }}>\n <button\n type=\"button\"\n disabled={readonly || healthBusy}\n onClick={() => {\n setHealthBusy(true)\n setHealthResult(null)\n // The dsh webServer rejects bodyless POSTs, so send a\n // JSON envelope; parse defensively either way.\n fetch('/api/dsh-perm-gate/health', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: '{}',\n })\n .then(async (r) => {\n const text = await r.text()\n if (r.status === 404) throw new Error(t('card.healthStale'))\n try {\n return JSON.parse(text) as { ok?: boolean; ms?: number; detail?: string; error?: string }\n } catch {\n throw new Error(text.trim().slice(0, 120) !== '' ? text.trim().slice(0, 120) : `HTTP ${r.status}`)\n }\n })\n .then((res) => {\n setHealthResult(res.ok === true && typeof res.ms === 'number'\n ? t('card.healthOk').replace('%ms', String(res.ms)) + (typeof res.detail === 'string' ? ` · ${res.detail}` : '')\n : t('card.healthFail') + (res.detail ?? res.error ?? 'unknown'))\n setReceiverNonce((n) => n + 1)\n })\n .catch((e: unknown) => { setHealthResult(t('card.healthFail') + String((e as Error)?.message ?? e)) })\n .finally(() => { setHealthBusy(false) })\n }}\n style={{ ...controlStyle, cursor: readonly || healthBusy ? 'default' : 'pointer' }}\n >\n {healthBusy ? t('card.healthRunning') : t('card.healthTest')}\n </button>\n {healthResult !== null && (\n <span style={{ fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-secondary, inherit)', overflowWrap: 'anywhere' }}>\n {healthResult}\n </span>\n )}\n </div>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-risk-learning\" style={{ fontSize: '12px' }}>{t('card.riskLearning')}</label>\n <input\n id=\"plugin-config-perm-gate-risk-learning\"\n type=\"checkbox\"\n checked={value.riskLearning ?? false}\n disabled={readonly || !effective}\n onChange={(event) => { void scope.set('riskLearning', event.currentTarget.checked) }}\n />\n </div>\n <p style={hintStyle}>{t('card.riskLearningHint')}</p>\n {value.riskLearning === true\n ? (\n <label style={fieldStyle}>\n <span style={fieldLabelStyle}>{t('card.riskThreshold')}</span>\n <input\n id=\"plugin-config-perm-gate-risk-threshold\"\n type=\"number\"\n min={1}\n max={10}\n value={value.riskThreshold ?? 3}\n disabled={readonly || !effective}\n style={{ ...controlStyle, width: '96px' }}\n onChange={(event) => {\n const n = Number.parseInt(event.currentTarget.value, 10)\n if (Number.isFinite(n) && n >= 1 && n <= 10) void scope.set('riskThreshold', n)\n }}\n />\n </label>\n )\n : null}\n {value.riskLearning === true\n ? (\n <>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-risk-sediment\" style={{ fontSize: '12px' }}>{t('card.riskSediment')}</label>\n <input\n id=\"plugin-config-perm-gate-risk-sediment\"\n type=\"checkbox\"\n checked={value.riskSediment ?? true}\n disabled={readonly || !effective}\n onChange={(event) => { void scope.set('riskSediment', event.currentTarget.checked) }}\n />\n </div>\n <p style={hintStyle}>{t('card.riskSedimentHint')}</p>\n <div style={sectionStyle}>\n <p style={labelStyle}>{t('card.sediment')}</p>\n <p style={hintStyle}>{t('card.sedimentHint')}</p>\n <SedimentSection t={t} />\n </div>\n </>\n )\n : null}\n </section>\n )\n : null}\n </section>\n\n <section style={sectionStyle}>\n <p style={labelStyle}>{t('card.dryRun')}</p>\n <p style={hintStyle}>{t('card.dryRunHint')}</p>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', alignItems: 'flex-end', margin: '6px 0' }}>\n <label style={{ display: 'flex', flexDirection: 'column', gap: '4px', flex: '0 0 120px' }}>\n <span style={fieldLabelStyle}>{t('card.dryRunTool')}</span>\n <input\n type=\"text\"\n value={dryTool}\n disabled={readonly}\n placeholder=\"shell\"\n onChange={(e) => { setDryTool(e.target.value) }}\n onKeyDown={(e) => { if (e.key === 'Enter') runDryRunTest() }}\n style={controlStyle}\n />\n </label>\n <label style={{ display: 'flex', flexDirection: 'column', gap: '4px', flex: '1 1 260px', minWidth: 0 }}>\n <span style={fieldLabelStyle}>{t('card.dryRunCommand')}</span>\n <input\n type=\"text\"\n value={dryCommand}\n disabled={readonly}\n placeholder={t('card.dryRunCommandPlaceholder')}\n onChange={(e) => { setDryCommand(e.target.value) }}\n onKeyDown={(e) => { if (e.key === 'Enter') runDryRunTest() }}\n style={controlStyle}\n />\n </label>\n <button\n type=\"button\"\n disabled={readonly || dryBusy}\n onClick={runDryRunTest}\n style={{ ...controlStyle, flex: '0 0 auto', cursor: readonly || dryBusy ? 'default' : 'pointer' }}\n >\n {dryBusy ? t('card.dryRunRunning') : t('card.dryRunTest')}\n </button>\n </div>\n {dryError !== null && (\n <p style={{ ...hintStyle, color: 'var(--dsw-alias-label-error, #c0392b)' }}>{t('card.dryRunFail')}{dryError}</p>\n )}\n {dryReport === null\n ? (dryError === null && <p style={hintStyle}>{t('card.dryRunEmpty')}</p>)\n : (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: '4px',\n padding: '8px 10px',\n borderRadius: '6px',\n border: '1px solid var(--dsw-alias-border-l2)',\n background: 'var(--dsw-alias-bg-surface, transparent)',\n fontSize: '12px',\n lineHeight: '18px',\n }}\n >\n {/* The verdict badge: colour carries the same meaning as the word. */}\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <span style={fieldLabelStyle}>{t('card.dryRunVerdict')}</span>\n {(() => {\n const verdict = dryReport.verdict ?? 'ask'\n const colour = verdict === 'deny'\n ? 'var(--dsw-alias-label-error, #c0392b)'\n : verdict === 'allow'\n ? 'var(--dsw-alias-label-success, #2e7d32)'\n : 'var(--dsw-alias-label-warning, #b26a00)'\n const text = verdict === 'deny'\n ? t('card.dryRunDeny')\n : verdict === 'allow' ? t('card.dryRunAllow') : t('card.dryRunAsk')\n return <strong style={{ color: colour }}>{text}</strong>\n })()}\n {(dryReport.ruleCount ?? 0) === 0 && (\n <span style={{ color: 'var(--dsw-alias-label-secondary, inherit)' }}>{t('card.dryRunNoRules')}</span>\n )}\n </div>\n <div style={{ display: 'flex', gap: '8px', overflowWrap: 'anywhere' }}>\n <span style={fieldLabelStyle}>{t('card.dryRunRule')}</span>\n <code style={{ font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\n {dryReport.ruleLayer?.ruleIndex === undefined\n ? t('card.dryRunRuleNone').replace('%d', dryReport.defaultAction ?? 'ask')\n : `#${dryReport.ruleLayer.ruleIndex} (${dryReport.ruleLayer.action ?? '?'})`}\n </code>\n </div>\n <div style={{ display: 'flex', gap: '8px', overflowWrap: 'anywhere' }}>\n <span style={fieldLabelStyle}>{t('card.dryRunDimensions')}</span>\n <code style={{ font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\n {(dryReport.ruleLayer?.matchedDimensions ?? []).length === 0\n ? '—'\n : (dryReport.ruleLayer?.matchedDimensions ?? []).join(', ')}\n </code>\n </div>\n <div style={{ display: 'flex', gap: '8px', overflowWrap: 'anywhere' }}>\n <span style={fieldLabelStyle}>{t('card.dryRunReason')}</span>\n <span style={{ color: 'var(--dsw-alias-label-secondary, inherit)' }}>{dryReport.reason ?? ''}</span>\n </div>\n <p style={{ ...hintStyle, margin: 0 }}>{t('card.dryRunNote')}</p>\n </div>\n )}\n </section>\n\n <section style={sectionStyle}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '8px' }}>\n <p style={labelStyle}>{t('card.rules')}</p>\n <button\n type=\"button\"\n disabled={rulesBusy}\n onClick={loadRules}\n style={{ ...controlStyle, flex: '0 0 auto', cursor: rulesBusy ? 'default' : 'pointer' }}\n >\n {rulesBusy ? t('card.rulesLoading') : t('card.rulesRefresh')}\n </button>\n </div>\n <p style={hintStyle}>{t('card.rulesHint')}</p>\n\n <div style={{ display: 'flex', gap: '8px', overflowWrap: 'anywhere', marginTop: '6px' }}>\n <span style={fieldLabelStyle}>{t('card.rulesPath')}</span>\n <code style={{ font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\n {rulesBody?.path !== undefined && rulesBody.path !== '' ? rulesBody.path : t('card.rulesNone')}\n </code>\n </div>\n\n {rulesError !== null && (\n <p style={{ ...hintStyle, color: 'var(--dsw-alias-label-error, #c0392b)' }}>{t('card.rulesError')}{rulesError}</p>\n )}\n\n {rulesBody !== null && (\n <>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '12px', marginTop: '4px' }}>\n <span>\n <span style={fieldLabelStyle}>{t('card.rulesCounts')} </span>\n <code style={{ font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\n {`deny ${rulesBody.counts?.deny ?? 0} · allow ${rulesBody.counts?.allow ?? 0} · ask ${rulesBody.counts?.ask ?? 0}`}\n </code>\n </span>\n {rulesBody.defaultAction !== undefined && (\n <span>\n <span style={fieldLabelStyle}>{t('card.rulesDefault')} </span>\n <code style={{ font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\n {rulesBody.defaultAction}\n </code>\n </span>\n )}\n <span style={fieldLabelStyle}>\n {t('card.rulesStats')\n .replace('%b', String(rulesBody.bytes ?? 0))\n .replace('%l', String(rulesBody.lines ?? 0))}\n </span>\n </div>\n\n {/* Why the document did not load or did not compile. The text below is still shown. */}\n {rulesBody.error !== undefined && (\n <p style={{ ...hintStyle, color: 'var(--dsw-alias-label-error, #c0392b)' }}>{rulesBody.error}</p>\n )}\n {rulesBody.exists === false && <p style={hintStyle}>{t('card.rulesMissing')}</p>}\n {rulesBody.truncated === true && <p style={hintStyle}>{t('card.rulesTruncated')}</p>}\n\n {(rulesBody.raw ?? '') !== '' && (\n <pre\n style={{\n margin: '6px 0 0',\n padding: '8px 10px',\n maxHeight: '260px',\n overflow: 'auto',\n borderRadius: '6px',\n border: '1px solid var(--dsw-alias-border-l2)',\n background: 'var(--dsw-alias-bg-surface, transparent)',\n font: '500 12px/18px var(--ds-font-family-code, monospace)',\n color: 'var(--dsw-alias-label-primary)',\n whiteSpace: 'pre',\n }}\n >\n {rulesBody.raw}\n </pre>\n )}\n <p style={{ ...hintStyle, margin: 0 }}>{t('card.rulesNote')}</p>\n </>\n )}\n </section>\n\n <section style={sectionStyle}>\n <p style={labelStyle}>{t('card.allowlist')}</p>\n <p style={hintStyle}>{t('card.allowlistHint')}</p>\n <p style={hintStyle}>{t('card.allowlistPresetNote')}</p>\n {patterns.length === 0\n ? (\n <div style={{ padding: '6px 0', fontSize: '12px', color: 'var(--dsw-alias-label-tertiary)' }}>\n {t('card.allowlistEmpty')}\n </div>\n )\n : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '4px', margin: '6px 0' }}>\n {patterns.map((pattern, index) => (\n <div\n key={`${index}:${pattern}`}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '4px 8px',\n borderRadius: '6px',\n border: '1px solid var(--dsw-alias-border-l2)',\n background: 'var(--dsw-alias-bg-surface, transparent)',\n }}\n >\n <code style={{ flex: '1 1 auto', minWidth: 0, overflowWrap: 'anywhere', font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\n {pattern}\n </code>\n <button\n type=\"button\"\n aria-label={t('card.allowlistRemove')}\n title={t('card.allowlistRemove')}\n disabled={readonly}\n onClick={() => { removePattern(index) }}\n style={{\n flex: '0 0 auto',\n width: '20px',\n height: '20px',\n border: 'none',\n borderRadius: '999px',\n background: 'transparent',\n color: 'var(--dsw-alias-label-tertiary)',\n cursor: readonly ? 'default' : 'pointer',\n }}\n >\n ✕\n </button>\n </div>\n ))}\n </div>\n )}\n <div style={{ display: 'flex', gap: '6px', marginTop: '6px' }}>\n <input\n type=\"text\"\n value={addDraft}\n disabled={readonly}\n placeholder={t('card.allowlistPlaceholder')}\n spellCheck={false}\n style={{ ...controlStyle, flex: '1 1 auto', minWidth: 0 }}\n onChange={(event) => { setAddDraft(event.currentTarget.value) }}\n onKeyDown={(event) => {\n if (event.key === 'Enter') addPattern()\n }}\n />\n <button\n type=\"button\"\n disabled={readonly || addDraft.trim() === ''}\n onClick={addPattern}\n style={{\n ...controlStyle,\n flex: '0 0 auto',\n cursor: readonly || addDraft.trim() === '' ? 'default' : 'pointer',\n opacity: readonly || addDraft.trim() === '' ? 0.5 : 1,\n }}\n >\n {t('card.allowlistAdd')}\n </button>\n </div>\n <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '6px' }}>\n <button\n type=\"button\"\n onClick={() => { setBulkOpen(current => !current) }}\n style={{ ...controlStyle, cursor: 'pointer', border: 'none', background: 'transparent', color: 'var(--dsw-alias-label-tertiary)' }}\n >\n {bulkOpen ? t('card.allowlistBulkHide') : t('card.allowlistBulk')}\n </button>\n </div>\n {bulkOpen\n ? (\n <>\n <textarea\n id=\"plugin-config-perm-gate-allowlist\"\n value={allowlistShown}\n disabled={readonly}\n rows={6}\n spellCheck={false}\n style={{\n ...controlStyle,\n width: '100%',\n boxSizing: 'border-box',\n resize: 'vertical',\n fontFamily: 'var(--ds-font-family-code, monospace)',\n whiteSpace: 'pre',\n }}\n onChange={(event) => {\n setAllowDirty(true)\n setAllowText(event.currentTarget.value)\n }}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) commitAllowlist()\n }}\n />\n <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '6px' }}>\n <button\n type=\"button\"\n disabled={readonly || !allowDirty}\n onClick={commitAllowlist}\n style={{\n ...controlStyle,\n cursor: readonly || !allowDirty ? 'default' : 'pointer',\n opacity: readonly || !allowDirty ? 0.5 : 1,\n }}\n >\n {t('card.allowlistSave')}\n </button>\n </div>\n </>\n )\n : null}\n </section>\n\n <section style={sectionStyle}>\n <p style={labelStyle}>{t('card.denylist')}</p>\n <p style={hintStyle}>{t('card.denylistHint')}</p>\n <div style={{ display: 'flex', flexDirection: 'column', gap: '4px', margin: '6px 0' }}>\n {denylist.map((keyword, index) => {\n const preset = (DEFAULT_DENY_KEYWORDS as readonly string[]).includes(keyword)\n return (\n <div\n key={`${index}:${keyword}`}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '4px 8px',\n borderRadius: '6px',\n border: '1px solid var(--dsw-alias-border-l2)',\n background: 'var(--dsw-alias-bg-surface, transparent)',\n }}\n >\n <code style={{ flex: '1 1 auto', minWidth: 0, overflowWrap: 'anywhere', font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\n {keyword}\n </code>\n <span\n style={{\n flex: '0 0 auto',\n fontSize: '11px',\n lineHeight: '16px',\n padding: '0 6px',\n borderRadius: '8px',\n color: preset ? 'var(--dsw-alias-label-tertiary)' : 'var(--dsw-alias-label-secondary, inherit)',\n border: '1px solid var(--dsw-alias-border-l2)',\n }}\n >\n {preset ? t('card.denylistTagPreset') : t('card.denylistTagCustom')}\n </span>\n <button\n type=\"button\"\n aria-label={t('card.denylistRemove')}\n title={t('card.denylistRemove')}\n disabled={readonly}\n onClick={() => { removeDeny(index) }}\n style={{\n flex: '0 0 auto',\n width: '20px',\n height: '20px',\n border: 'none',\n borderRadius: '999px',\n background: 'transparent',\n color: 'var(--dsw-alias-label-tertiary)',\n cursor: readonly ? 'default' : 'pointer',\n }}\n >\n ✕\n </button>\n </div>\n )\n })}\n </div>\n <div style={{ display: 'flex', gap: '6px', marginTop: '6px' }}>\n <input\n type=\"text\"\n value={denyDraft}\n disabled={readonly}\n placeholder={t('card.denylistPlaceholder')}\n spellCheck={false}\n style={{ ...controlStyle, flex: '1 1 auto', minWidth: 0 }}\n onChange={(event) => { setDenyDraft(event.currentTarget.value) }}\n onKeyDown={(event) => {\n if (event.key === 'Enter') addDeny()\n }}\n />\n <button\n type=\"button\"\n disabled={readonly || denyDraft.trim() === ''}\n onClick={addDeny}\n style={{\n ...controlStyle,\n flex: '0 0 auto',\n cursor: readonly || denyDraft.trim() === '' ? 'default' : 'pointer',\n opacity: readonly || denyDraft.trim() === '' ? 0.5 : 1,\n }}\n >\n {t('card.denylistAdd')}\n </button>\n </div>\n {denyActive\n ? (\n <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '6px' }}>\n <button\n type=\"button\"\n disabled={readonly}\n onClick={restoreDeny}\n style={{ ...controlStyle, cursor: readonly ? 'default' : 'pointer', border: 'none', background: 'transparent', color: 'var(--dsw-alias-label-tertiary)' }}\n >\n {t('card.denylistRestore')}\n </button>\n </div>\n )\n : null}\n </section>\n\n {/* ─── Network master switch (Phase 2) ─── */}\n <section style={sectionStyle}>\n <p style={labelStyle}>{t('card.networkEnabled')}</p>\n <p style={hintStyle}>{t('card.networkEnabledHint')}</p>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '6px' }}>\n <input\n type=\"checkbox\"\n checked={value.networkEnabled === true}\n disabled={readonly}\n onChange={(event) => { void scope.set('networkEnabled', event.currentTarget.checked) }}\n />\n <span style={{ fontSize: '13px' }}>{value.networkEnabled === true ? 'ON' : 'OFF'}</span>\n </div>\n <p style={hintStyle}>{t('card.networkRebindNote')}</p>\n </section>\n\n {/* ─── Network env injection (Phase 2) ─── */}\n <section style={sectionStyle}>\n <p style={labelStyle}>{t('card.networkInjectEnv')}</p>\n <p style={hintStyle}>{t('card.networkInjectEnvHint')}</p>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '6px' }}>\n <input\n type=\"checkbox\"\n checked={value.networkInjectEnv !== false}\n disabled={readonly}\n onChange={(event) => { void scope.set('networkInjectEnv', event.currentTarget.checked) }}\n />\n <span style={{ fontSize: '13px' }}>{value.networkInjectEnv !== false ? 'ON' : 'OFF'}</span>\n </div>\n </section>\n\n {/* ─── Hot reload switch (Phase 3) ─── */}\n <section style={sectionStyle}>\n <p style={labelStyle}>{t('card.watch')}</p>\n <p style={hintStyle}>{t('card.watchHint')}</p>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '6px' }}>\n <input\n type=\"checkbox\"\n checked={value.watch !== false}\n disabled={readonly}\n onChange={(event) => { void scope.set('watch', event.currentTarget.checked) }}\n />\n <span style={{ fontSize: '13px' }}>{value.watch !== false ? 'ON' : 'OFF'}</span>\n </div>\n </section>\n\n {!snapshot.writable\n && <p style={{ margin: '8px 0 0', fontSize: '12px', color: 'var(--dsw-alias-label-tertiary)' }}>{t('card.readonly')}</p>}\n </>\n )}\n </div>\n )\n : null}\n </div>\n )\n}","/**\n * Shared decision-feed plumbing for the browser half: the event shape served by\n * the host's `GET /api/dsh-perm-gate/events` route, the polling fetch, the\n * session-id resolution from slot props, the per-kind presentation used by both\n * the notice strip and the approval-history view, and the review-page API calls\n * (snapshot stats / clear, file diff, revert).\n *\n * Everything is best-effort and dependency-free beyond react hooks living in\n * the components; no @deepseek-ai value imports (bundle purity).\n */\n\n/** One event as delivered by the host route (see src/events.ts). */\nexport interface GateEvent {\n readonly id: number\n readonly ts: string\n readonly sessionId: string\n readonly tool: string\n /**\n * `stand-down` is not a decision: it says the gate is inactive in this\n * session's permission preset, so this call was settled by the tier, not by\n * the gate. `VERDICT_LABELS['stand-down']` and `presentation()` carry the\n * user-facing wording; it is always sticky.\n */\n readonly kind: 'auto' | 'ask' | 'deny' | 'learned' | 'manual-approved' | 'manual-rejected' | 'manual-cancelled' | 'stand-down'\n readonly risk?: string\n readonly reason: string\n /** Decision-path label (rule / grant / hard-deny / llm-safe …). */\n readonly verdict?: string\n /** The model's stated intent. */\n readonly justification?: string\n /** Sandbox mode involved, when known. */\n readonly mode?: string\n /** Risk category name (deletion / credential / neutral …). */\n readonly category?: string\n /** Files the decision concerns. */\n readonly files?: readonly string[]\n /** Human confirmations so far for the learned key (manual-approve events). */\n readonly learningCount?: number\n /** Confirmations required before that key auto-allows (manual-approve events). */\n readonly threshold?: number\n}\n\n/**\n * The session-id carriers a slot occupant may receive. A `conversation.view`\n * entry gets the standard props at the top level (`sessionId` / `useSessions`,\n * and whatever its `inject` returned); older/other slots nest them under\n * `slotsProps`. Both shapes are probed.\n */\nexport interface FeedSlotsProps {\n readonly sessionId?: unknown\n readonly useSessions?: SessionSelectorHook\n readonly slotsProps?: {\n readonly sessionId?: unknown\n readonly useSessions?: SessionSelectorHook\n }\n}\n\n/** The DSH session-list selector hook delivered in slot props. */\nexport type SessionSelectorHook = (selector: (state: { current?: unknown }) => unknown) => unknown\n\n/** Fetch decision events for one session; `since > 0` returns only newer ones. */\nexport async function fetchEvents(sessionId: string, since: number): Promise<GateEvent[]> {\n const query = `/api/dsh-perm-gate/events?sessionId=${encodeURIComponent(sessionId)}${since > 0 ? `&since=${since}` : ''}`\n const res = await fetch(query, { headers: { 'cache-control': 'no-cache' } })\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const body = (await res.json()) as { events?: unknown }\n return Array.isArray(body.events) ? (body.events as GateEvent[]) : []\n}\n\n/** The host's push route (see src/events.ts); the browser half prefers it to polling. */\nexport const STREAM_ROUTE = '/api/dsh-perm-gate/stream'\n\n/** Stream attempts before the route is written off as unsupported and polling takes over. */\nconst STREAM_RETRIES = 3\nconst STREAM_RETRY_MS = 3_000\n/**\n * Degraded path only: a host predating the stream route still gets a servable\n * strip. Deliberately slower than the old 2 s tick — it now also pauses while\n * the tab is hidden, so a backgrounded page costs nothing.\n */\nconst FALLBACK_POLL_MS = 5_000\n\n/** One delivery of the feed: either the connect-time replay, or decisions as they land. */\nexport interface GateFeedBatch {\n readonly events: readonly GateEvent[]\n /**\n * True for a connect-time catch-up batch (the stream's backlog, or the\n * fallback's first poll). Callers sync their cursor with it but must not\n * surface it — replaying a session's history as fresh notices is noise.\n */\n readonly backlog: boolean\n}\n\n/**\n * Follow one session's decision feed until the returned close is called.\n *\n * Prefers the host's `text/event-stream` route, which pushes each decision as\n * the gate appends it — no timer, no repeated re-read of the event log. When\n * the stream is unavailable (an older host, a proxy that buffers it) this\n * degrades to polling the JSON route, gated on page visibility.\n *\n * @param sessionId - the session whose decisions to follow.\n * @param getSince - cursor supplier, read at connect and on every fallback poll.\n * @param onBatch - receives the backlog, then live batches.\n * @returns the close: ends the stream and any fallback timer.\n */\nexport function followEvents(\n sessionId: string,\n getSince: () => number,\n onBatch: (batch: GateFeedBatch) => void,\n): () => void {\n let closed = false\n let source: EventSource | null = null\n let pollTimer: ReturnType<typeof setInterval> | null = null\n let retries = 0\n let polls = 0\n\n const stopPolling = (): void => {\n if (pollTimer === null) return\n clearInterval(pollTimer)\n pollTimer = null\n }\n\n const poll = (): void => {\n if (closed) return\n // A hidden tab does not need the strip kept warm; the next visible tick catches up.\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return\n const backlog = polls === 0\n polls += 1\n fetchEvents(sessionId, getSince())\n .then((events) => { if (!closed) onBatch({ events, backlog }) })\n .catch(() => {}) // route missing / transient failure: stay quiet\n }\n\n const startPolling = (): void => {\n if (closed || pollTimer !== null) return\n polls = 0\n poll()\n pollTimer = setInterval(poll, FALLBACK_POLL_MS)\n }\n\n const connect = (): void => {\n if (closed) return\n const query = `?sessionId=${encodeURIComponent(sessionId)}&since=${getSince()}`\n const next = new EventSource(`${STREAM_ROUTE}${query}`)\n source = next\n next.onopen = () => {\n retries = 0\n stopPolling()\n }\n next.onmessage = (message: MessageEvent<string>) => {\n try {\n const body = JSON.parse(message.data) as { events?: unknown; backlog?: unknown }\n if (Array.isArray(body.events)) {\n onBatch({ events: body.events as GateEvent[], backlog: body.backlog === true })\n }\n } catch {\n // an unreadable frame is dropped; the next decision still arrives\n }\n }\n next.onerror = () => {\n if (source === next) source = null\n next.close()\n if (closed) return\n retries += 1\n // The route may be missing or the connection may have dropped: poll meanwhile,\n // and retry the stream a bounded number of times before settling for polling.\n startPolling()\n if (retries <= STREAM_RETRIES) setTimeout(connect, STREAM_RETRY_MS)\n }\n }\n\n if (typeof EventSource === 'undefined') startPolling()\n else connect()\n\n return () => {\n closed = true\n source?.close()\n source = null\n stopPolling()\n }\n}\n\n/** Resolve the current session id from slot props (top level, nested, or hook). */\nexport function resolveSessionId(props: FeedSlotsProps | undefined): string | null {\n const direct = props?.sessionId\n if (typeof direct === 'string' && direct !== '') return direct\n const nested = props?.slotsProps\n if (typeof nested?.sessionId === 'string' && nested.sessionId !== '') return nested.sessionId\n for (const hook of [props?.useSessions, nested?.useSessions]) {\n if (typeof hook !== 'function') continue\n try {\n const state = hook((s) => s) as { current?: unknown } | undefined\n if (typeof state?.current === 'string' && state.current !== '') return state.current\n } catch {\n // fall through to the next carrier\n }\n }\n return null\n}\n\n/** Presentation per event kind: accent color, background wash, and tag. */\nexport function presentation(kind: GateEvent['kind']): { color: string; bg: string; tag: string; sticky: boolean } {\n switch (kind) {\n case 'deny':\n return { color: 'var(--dsw-alias-state-error-primary, #c0392b)', bg: 'var(--dsw-alias-interactive-bg-hover-danger, rgba(192,57,43,0.08))', tag: 'DENY', sticky: false }\n case 'ask':\n return { color: 'var(--dsw-alias-state-warn-label, #b9770e)', bg: 'var(--dsw-alias-state-warn-tertiary, rgba(185,119,14,0.08))', tag: 'ASK', sticky: true }\n case 'learned':\n return { color: 'var(--dsw-alias-state-success-primary, #1e8449)', bg: 'var(--dsw-alias-state-success-tertiary, rgba(30,132,73,0.08))', tag: 'LEARNED', sticky: false }\n case 'manual-approved':\n return { color: 'var(--dsw-alias-state-warn-label, #b9770e)', bg: 'var(--dsw-alias-state-warn-tertiary, rgba(185,119,14,0.08))', tag: 'APPROVED', sticky: false }\n case 'manual-rejected':\n return { color: 'var(--dsw-alias-state-error-primary, #c0392b)', bg: 'var(--dsw-alias-interactive-bg-hover-danger, rgba(192,57,43,0.08))', tag: 'REJECTED', sticky: false }\n case 'manual-cancelled':\n return { color: 'var(--dsw-alias-label-secondary, #666)', bg: 'var(--dsw-alias-bg-module-platform, rgba(127,127,127,0.08))', tag: 'CANCELLED', sticky: false }\n case 'stand-down':\n // Sticky on purpose: an inactive gate is a standing state, not an\n // incident. It must outlive the next auto-allow or it reads as noise.\n return { color: 'var(--dsw-alias-state-warn-label, #b9770e)', bg: 'var(--dsw-alias-state-warn-tertiary, rgba(185,119,14,0.14))', tag: 'GATE OFF', sticky: true }\n default:\n return { color: 'var(--dsw-alias-state-success-primary, #1e8449)', bg: 'var(--dsw-alias-state-success-tertiary, rgba(30,132,73,0.08))', tag: 'ALLOW', sticky: false }\n }\n}\n\n/**\n * Decision-path labels shown beside an event's tool name. Kept alongside\n * `presentation` (not in the dictionary) because they name host-internal\n * decision sources; an unknown value falls through to its raw string.\n */\nexport const VERDICT_LABELS: Readonly<Record<string, string>> = {\n rule: '规则命中',\n grant: '会话授权',\n 'hard-deny': '硬拒绝',\n 'deny-keyword': '黑名单关键词',\n default: '默认策略',\n ask: '默认策略',\n permissive: '自动审查放行',\n classifier: 'LLM 裁决',\n 'llm-safe': 'LLM 判定安全',\n 'llm-learned': 'LLM 学习放行',\n 'learned-sediment': '沉淀规则放行',\n 'learned-confirm': '学习确认',\n 'human-approved': '人工通过',\n 'human-rejected': '人工拒绝',\n 'human-cancelled': '人工取消',\n 'no-approval-channel': '无审批通道',\n // The degrade that hides an ask: the tier declares `approval: ask`, but the\n // session was overridden to `never`, so the gate's ask became a passthrough.\n // Without this label the approvals history shows the raw event string — for\n // the one event that explains why a flagged call ran unreviewed.\n 'preset-passthrough': '审批策略 never · 已放行',\n 'stand-down': '门禁停用',\n}\n\n/** Compact wall-clock rendering of an ISO timestamp. */\nexport function clockTime(iso: string): string {\n const date = new Date(iso)\n if (Number.isNaN(date.getTime())) return iso\n return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })\n}\n\n/** Human-readable byte size for the snapshot bar. */\nexport function fmtBytes(n: number): string {\n if (!Number.isFinite(n) || n <= 0) return '0 B'\n if (n < 1024) return `${n} B`\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`\n return `${(n / (1024 * 1024)).toFixed(2)} MB`\n}\n\n/** Snapshot inventory for the review page's bar and file-chip enablement. */\nexport interface SnapshotStats {\n readonly count: number\n readonly bytes: number\n /** Event ids that currently have a snapshot file. */\n readonly ids: readonly string[]\n /** eventId → absolute snapshot paths (file-level diff availability). */\n readonly files: Readonly<Record<string, readonly string[]>>\n}\n\n/** Load the snapshot inventory (optionally session-scoped); null on failure. */\nexport async function fetchSnapshotStats(sessionId: string | null): Promise<SnapshotStats | null> {\n const query = sessionId === null ? '' : `?sessionId=${encodeURIComponent(sessionId)}`\n const res = await fetch(`/api/dsh-perm-gate/snapshots-stats${query}`, { headers: { 'cache-control': 'no-cache' } })\n if (!res.ok) return null\n const body = (await res.json()) as { ok?: unknown; count?: unknown; bytes?: unknown; ids?: unknown; files?: unknown }\n if (body.ok !== true) return null\n const files: Record<string, readonly string[]> = {}\n if (typeof body.files === 'object' && body.files !== null) {\n for (const [key, value] of Object.entries(body.files as Record<string, unknown>)) {\n if (Array.isArray(value)) files[key] = value.map(String)\n }\n }\n return {\n count: typeof body.count === 'number' ? body.count : 0,\n bytes: typeof body.bytes === 'number' ? body.bytes : 0,\n ids: Array.isArray(body.ids) ? (body.ids as unknown[]).map(String) : [],\n files,\n }\n}\n\n/** Drop snapshots: pass a session id for a session-scoped clear, null for all. */\nexport async function clearSnapshots(sessionId: string | null): Promise<boolean> {\n try {\n const res = await fetch('/api/dsh-perm-gate/snapshots-clear', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(sessionId === null ? {} : { sessionId }),\n })\n return res.ok\n } catch {\n return false\n }\n}\n\n/** One rendered diff line. */\nexport interface DiffLine {\n readonly type: 'same' | 'add' | 'del'\n readonly aNo?: number\n readonly bNo?: number\n readonly text: string\n}\n\nexport interface DiffHunk {\n readonly hiddenBefore: number\n readonly lines: readonly DiffLine[]\n}\n\n/** The diff payload served by `GET /api/dsh-perm-gate/diff`. */\nexport interface DiffResponse {\n readonly hunks: readonly DiffHunk[]\n readonly stats: { readonly added: number; readonly removed: number; readonly contextLines: number }\n readonly afterExists: boolean\n}\n\n/** Load the before/after diff for one event's file; throws on failure. */\nexport async function fetchDiff(eventId: number, path: string): Promise<DiffResponse> {\n const res = await fetch(\n `/api/dsh-perm-gate/diff?eventId=${eventId}&path=${encodeURIComponent(path)}`,\n { headers: { 'cache-control': 'no-cache' } },\n )\n const body = (await res.json().catch(() => null)) as\n | { ok?: unknown; error?: unknown; hunks?: unknown; stats?: unknown; afterExists?: unknown }\n | null\n if (body === null || body.ok !== true) {\n throw new Error(typeof body?.error === 'string' ? body.error : `HTTP ${res.status}`)\n }\n return {\n hunks: Array.isArray(body.hunks) ? (body.hunks as DiffHunk[]) : [],\n stats: (typeof body.stats === 'object' && body.stats !== null\n ? body.stats\n : { added: 0, removed: 0, contextLines: 0 }) as DiffResponse['stats'],\n afterExists: body.afterExists !== false,\n }\n}\n\n/** Deliver a revert instruction for one event into its conversation. */\nexport async function sendRevert(sessionId: string, eventId: number): Promise<{ ok: boolean; error?: string }> {\n try {\n const res = await fetch('/api/dsh-perm-gate/revert', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ sessionId, eventId }),\n })\n const body = (await res.json().catch(() => null)) as { ok?: unknown; error?: unknown } | null\n if (body !== null && body.ok === true) return { ok: true }\n return { ok: false, error: typeof body?.error === 'string' ? body.error : `HTTP ${res.status}` }\n } catch (e) {\n return { ok: false, error: String((e as Error)?.message ?? e) }\n }\n}\n","/**\n * Gate decision notice strip — the `conversation.input.dock` face of\n * dsh-perm-gate (a simplified version of the review-feed pattern demonstrated\n * by dsh-approval-gate).\n *\n * Follows the host's decision feed (`GET /api/dsh-perm-gate/stream`, an SSE\n * push; see `followEvents` for the older-host polling fallback) and shows the\n * latest decision above the conversation input: auto-allows (green) and denies\n * (red) auto-dismiss after a few seconds; an ask (amber) stays until the next\n * event because it needs the human's attention.\n *\n * Everything is best-effort: no session id, a missing route, or any fetch\n * failure simply means \"render nothing\". No @deepseek-ai value imports.\n */\nimport { useEffect, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport { followEvents, presentation, resolveSessionId, type FeedSlotsProps, type GateEvent, type GateFeedBatch } from './feed.ts'\n\nconst AUTO_HIDE_MS = 4_000\n\n/** Full props: the locale seat + the session-id carriers the slot delivers. */\nexport type NoticeStripProps = PropsLocale<'dsh-perm-gate'> & FeedSlotsProps\n\n/** Localized tag for a manual terminal state; other kinds keep their short tag. */\nfunction manualTagKey(kind: GateEvent['kind']): 'history.tag.manualApproved' | 'history.tag.manualRejected' | 'history.tag.manualCancelled' | null {\n if (kind === 'manual-approved') return 'history.tag.manualApproved'\n if (kind === 'manual-rejected') return 'history.tag.manualRejected'\n if (kind === 'manual-cancelled') return 'history.tag.manualCancelled'\n return null\n}\n\nexport function NoticeStrip({ t, ...props }: NoticeStripProps): JSX.Element | null {\n const sessionId = resolveSessionId(props)\n const [notice, setNotice] = useState<GateEvent | null>(null)\n const sinceRef = useRef(0)\n const shownIdRef = useRef(0)\n const hideTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n useEffect(() => {\n sinceRef.current = 0\n shownIdRef.current = 0\n setNotice(null)\n if (sessionId === null) return\n\n let alive = true\n\n const onBatch = (batch: GateFeedBatch): void => {\n if (!alive || batch.events.length === 0) return\n const last = batch.events[batch.events.length - 1]\n if (last === undefined) return\n if (last.id > sinceRef.current) sinceRef.current = last.id\n // On session open the stream replays history: advance the cursor past it\n // silently, so switching sessions never pops a stale decision.\n if (batch.backlog) {\n shownIdRef.current = sinceRef.current\n return\n }\n if (last.id <= shownIdRef.current) return\n shownIdRef.current = last.id\n setNotice(last)\n if (hideTimerRef.current !== null) clearTimeout(hideTimerRef.current)\n if (!presentation(last.kind).sticky) {\n hideTimerRef.current = setTimeout(() => { setNotice(null) }, AUTO_HIDE_MS)\n }\n }\n\n const close = followEvents(sessionId, () => sinceRef.current, onBatch)\n\n return () => {\n alive = false\n close()\n if (hideTimerRef.current !== null) clearTimeout(hideTimerRef.current)\n }\n }, [sessionId])\n\n if (notice === null) return null\n const style = presentation(notice.kind)\n const manualKey = manualTagKey(notice.kind)\n return (\n <div\n role=\"status\"\n style={{\n boxSizing: 'border-box',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n margin: '0 auto 6px',\n maxWidth: '720px',\n border: `1px solid ${style.color}`,\n background: style.bg,\n borderRadius: '10px',\n padding: '5px 10px',\n }}\n >\n <span\n style={{\n flex: '0 0 auto',\n fontSize: '11px',\n lineHeight: '18px',\n padding: '0 8px',\n borderRadius: '9px',\n color: style.color,\n fontWeight: 600,\n }}\n >\n {manualKey === null ? style.tag : t(manualKey)}\n </span>\n <span\n style={{\n flex: '1 1 auto',\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n fontSize: '12px',\n color: 'var(--dsw-alias-label-secondary, inherit)',\n }}\n >\n <code style={{ font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary, inherit)' }}>{notice.tool}</code>\n {' — '}\n {notice.reason}\n </span>\n <button\n type=\"button\"\n aria-label=\"dismiss\"\n onClick={() => { setNotice(null) }}\n style={{\n flex: '0 0 auto',\n width: '22px',\n height: '22px',\n border: 'none',\n borderRadius: '999px',\n background: 'transparent',\n color: 'var(--dsw-alias-label-tertiary, inherit)',\n cursor: 'pointer',\n }}\n >\n ×\n </button>\n </div>\n )\n}\n","/**\n * Approval-history view — the `conversation.view` face of dsh-perm-gate,\n * following the session-scoped review-page pattern demonstrated by\n * dsh-approval-gate: a timeline of every gate decision in the current\n * conversation, newest first, loaded once and then extended by the host's push\n * feed (see `followEvents`).\n *\n * Beyond the decision timeline this view owns the review data plane: a snapshot\n * inventory bar (with session/all clearing), per-event file chips, and a diff\n * overlay that shows the pre-change vs current content of one file and can send\n * a revert instruction back into the conversation.\n *\n * Data source: the host's `GET /api/dsh-perm-gate/events?sessionId=` feed (the\n * same JSONL the notice strip consumes) plus the diff / revert / snapshot\n * routes. Everything is best-effort: no session id or any fetch failure renders\n * the empty / error state. No @deepseek-ai value imports.\n */\nimport { useEffect, useState } from 'react'\nimport type { CSSProperties, JSX } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport {\n clearSnapshots,\n clockTime,\n fetchDiff,\n fetchEvents,\n fetchSnapshotStats,\n fmtBytes,\n followEvents,\n presentation,\n resolveSessionId,\n sendRevert,\n VERDICT_LABELS,\n type DiffHunk,\n type DiffResponse,\n type FeedSlotsProps,\n type GateEvent,\n type GateFeedBatch,\n type SnapshotStats,\n} from './feed.ts'\nimport type { PermissiveKey } from './locales.ts'\n\n/** Tag text per event kind, keyed into the plugin dictionary. */\nconst TAG_KEYS = {\n auto: 'history.tag.auto',\n ask: 'history.tag.ask',\n deny: 'history.tag.deny',\n learned: 'history.tag.learned',\n 'manual-approved': 'history.tag.manualApproved',\n 'manual-rejected': 'history.tag.manualRejected',\n 'manual-cancelled': 'history.tag.manualCancelled',\n 'stand-down': 'history.tag.standDown',\n} as const satisfies Record<GateEvent['kind'], PermissiveKey>\n\n/** Full props: locale seat + the session-id carriers the slot delivers. */\nexport type HistoryViewProps = PropsLocale<'dsh-perm-gate'> & FeedSlotsProps\n\n/** The file name alone (chips show the basename, like the reference page). */\nfunction basename(p: string): string {\n const seg = p.split(/[\\\\/]/)\n return seg[seg.length - 1] ?? p\n}\n\nfunction glyphOf(kind: GateEvent['kind']): { char: string; color: string } {\n const style = presentation(kind)\n switch (kind) {\n case 'deny':\n case 'manual-rejected':\n return { char: '✕', color: style.color }\n case 'ask':\n return { char: '◔', color: style.color }\n case 'manual-cancelled':\n return { char: '—', color: style.color }\n default:\n return { char: '✓', color: style.color }\n }\n}\n\nconst barStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n flexWrap: 'wrap',\n padding: '6px 10px',\n borderRadius: '8px',\n background: 'var(--dsw-alias-bg-layer-3, rgba(127,127,127,0.05))',\n fontSize: '12px',\n lineHeight: '18px',\n color: 'var(--dsw-alias-label-tertiary)',\n}\n\nconst barButtonStyle: CSSProperties = {\n boxSizing: 'border-box',\n height: '26px',\n color: 'var(--dsw-alias-label-primary)',\n cursor: 'pointer',\n font: 'inherit',\n border: '1px solid var(--dsw-alias-border-l2)',\n background: 'transparent',\n borderRadius: '13px',\n padding: '0 12px',\n fontSize: '12px',\n lineHeight: '24px',\n}\n\n/** The snapshot inventory bar: usage plus session/all clearing. */\nfunction SnapshotBar(props: {\n t: HistoryViewProps['t']\n stats: SnapshotStats | null\n sessionId: string | null\n onCleared: () => void\n}): JSX.Element {\n const { t, stats, sessionId, onCleared } = props\n const busy = stats === null || stats.count === 0\n const clear = (mode: 'session' | 'all'): void => {\n const confirmed = window.confirm(\n mode === 'all' ? t('history.clearAllConfirm') : t('history.clearSessionConfirm'),\n )\n if (!confirmed) return\n void clearSnapshots(mode === 'session' ? sessionId : null).then(() => { onCleared() })\n }\n return (\n <div style={barStyle}>\n <span>\n {`${t('history.snapshots')} `}\n <b style={{ color: 'var(--dsw-alias-label-secondary)', fontWeight: 500 }}>\n {stats === null ? '…' : `${fmtBytes(stats.bytes)} · ${stats.count}`}\n </b>\n </span>\n <span style={{ flex: '1 1 auto' }} />\n <button\n type=\"button\"\n title={t('history.clearSessionTitle')}\n disabled={busy}\n onClick={() => { clear('session') }}\n style={{ ...barButtonStyle, opacity: busy ? 0.4 : 1 }}\n >\n {t('history.clearSession')}\n </button>\n <button\n type=\"button\"\n title={t('history.clearAllTitle')}\n disabled={busy}\n onClick={() => { clear('all') }}\n style={{ ...barButtonStyle, opacity: busy ? 0.4 : 1, color: 'var(--dsw-alias-state-error-primary)' }}\n >\n {t('history.clearAll')}\n </button>\n </div>\n )\n}\n\n/** One diff line row (marker + line numbers + text). */\nfunction DiffRow({ line }: { line: DiffHunk['lines'][number] }): JSX.Element {\n const isAdd = line.type === 'add'\n const isDel = line.type === 'del'\n const background = isAdd\n ? 'var(--dsw-alias-state-success-tertiary)'\n : isDel\n ? 'var(--dsw-alias-interactive-bg-hover-danger)'\n : 'transparent'\n const color = isDel\n ? 'var(--dsw-alias-state-error-primary)'\n : isAdd\n ? 'var(--dsw-alias-label-primary)'\n : 'var(--dsw-alias-label-secondary)'\n const aNo = line.aNo === undefined ? '' : String(line.aNo)\n const bNo = line.bNo === undefined ? '' : String(line.bNo)\n return (\n <div\n style={{\n boxSizing: 'border-box',\n display: 'flex',\n gap: '8px',\n padding: '1px 8px',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-all',\n minWidth: 0,\n background,\n color,\n }}\n >\n <span aria-hidden style={{ flex: '0 0 auto', width: '16px', userSelect: 'none' }}>\n {isAdd ? '+' : isDel ? '-' : ' '}\n </span>\n <span\n style={{\n flex: '0 0 auto',\n width: '60px',\n color: 'var(--dsw-alias-label-caption)',\n textAlign: 'right',\n userSelect: 'none',\n fontVariantNumeric: 'tabular-nums',\n }}\n >\n {aNo}\n {aNo !== '' && bNo !== '' ? ' ' : ''}\n {bNo}\n </span>\n <span style={{ flex: '1 1 auto', minWidth: 0 }}>{line.text}</span>\n </div>\n )\n}\n\n/** The file-change overlay: before/after diff plus the revert action. */\nfunction DiffPanel(props: {\n t: HistoryViewProps['t']\n sessionId: string | null\n eventId: number\n path: string\n onClose: () => void\n}): JSX.Element {\n const { t, sessionId, eventId, path, onClose } = props\n const [data, setData] = useState<DiffResponse | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [revertMsg, setRevertMsg] = useState<string | null>(null)\n const [revertOk, setRevertOk] = useState(false)\n const [reverting, setReverting] = useState(false)\n const [revertDone, setRevertDone] = useState(false)\n\n useEffect(() => {\n let alive = true\n setData(null)\n setError(null)\n setRevertDone(false)\n setRevertMsg(null)\n fetchDiff(eventId, path)\n .then((res) => { if (alive) setData(res) })\n .catch((e: unknown) => {\n if (alive) setError(`${t('history.diffLoadFail')}${String((e as Error)?.message ?? e)}`)\n })\n return () => { alive = false }\n }, [eventId, path, t])\n\n const doRevert = (): void => {\n // One revert instruction per event: the same event must never be delivered twice.\n if (reverting || revertDone || sessionId === null) return\n setReverting(true)\n setRevertMsg(null)\n void sendRevert(sessionId, eventId).then((res) => {\n if (res.ok) {\n setRevertMsg(t('history.diffRevertSent'))\n setRevertOk(true)\n setRevertDone(true)\n } else {\n setRevertMsg(`${t('history.diffRevertFail')}${res.error ?? ''}`)\n setRevertOk(false)\n }\n setReverting(false)\n })\n }\n\n const stats = data?.stats\n const body: JSX.Element = error !== null\n ? <div style={diffEmptyStyle}>{error}</div>\n : data === null\n ? <div style={diffEmptyStyle}>{t('history.diffLoading')}</div>\n : data.hunks.length === 0\n ? <div style={diffEmptyStyle}>{t('history.diffEmpty')}</div>\n : (\n <div style={diffBodyStyle}>\n {data.hunks.map((hunk, hi) => (\n <div key={`hunk-${hi}`}>\n {hunk.hiddenBefore > 0\n ? (\n <div style={hunkSepStyle}>\n {t('history.diffHidden').replace('%n', String(hunk.hiddenBefore))}\n </div>\n )\n : null}\n {hunk.lines.map((line, li) => (\n <DiffRow key={`l-${hi}-${li}`} line={line} />\n ))}\n </div>\n ))}\n </div>\n )\n\n return (\n <div style={overlayStyle} onClick={(e) => { if (e.target === e.currentTarget) onClose() }}>\n <div style={panelStyle}>\n <div style={panelHeadStyle}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <span style={{ flex: '1 1 auto', fontSize: '14px', fontWeight: 500, color: 'var(--dsw-alias-label-primary)' }}>\n {t('history.diffTitle')}\n </span>\n <button type=\"button\" aria-label={t('history.diffClose')} title={t('history.diffClose')} onClick={onClose} style={closeStyle}>\n ✕\n </button>\n </div>\n <div style={{ fontSize: '12px', lineHeight: '18px', fontFamily: 'var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-tertiary)', wordBreak: 'break-all' }}>\n {path}\n </div>\n {stats === undefined\n ? null\n : (\n <div style={{ fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-secondary)' }}>\n {t('history.diffStats')\n .replace('%a', String(stats.added))\n .replace('%r', String(stats.removed))\n .replace('%c', String(stats.contextLines))}\n {data !== null && !data.afterExists ? t('history.diffGone') : ''}\n </div>\n )}\n </div>\n {body}\n <div style={panelFootStyle}>\n {revertMsg === null\n ? null\n : (\n <span style={{ marginRight: 'auto', fontSize: '12px', color: revertOk ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-error-primary)' }}>\n {revertMsg}\n </span>\n )}\n <button\n type=\"button\"\n onClick={doRevert}\n disabled={reverting || revertDone || sessionId === null}\n style={{\n ...barButtonStyle,\n border: 'none',\n background: 'var(--dsw-alias-button-primary-fill, var(--dsw-alias-label-primary))',\n color: 'var(--dsw-alias-label-primary-foreground, #fff)',\n opacity: reverting || revertDone ? 0.5 : 1,\n }}\n >\n {reverting ? t('history.diffReverting') : revertDone ? t('history.diffRevertDone') : t('history.diffRevert')}\n </button>\n <button type=\"button\" onClick={onClose} style={barButtonStyle}>\n {t('history.diffClose')}\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nconst overlayStyle: CSSProperties = {\n position: 'fixed',\n inset: 0,\n zIndex: 900,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'var(--dsw-alias-bg-mask-1, rgba(0,0,0,0.35))',\n}\n\nconst panelStyle: CSSProperties = {\n boxSizing: 'border-box',\n width: 'min(760px, calc(100vw - 48px))',\n maxHeight: 'min(720px, calc(100vh - 48px))',\n display: 'flex',\n flexDirection: 'column',\n background: 'var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1))',\n border: '1px solid var(--dsw-alias-border-l1)',\n borderRadius: '16px',\n overflow: 'hidden',\n}\n\nconst panelHeadStyle: CSSProperties = {\n boxSizing: 'border-box',\n flex: '0 0 auto',\n display: 'flex',\n flexDirection: 'column',\n gap: '4px',\n padding: '12px 14px',\n borderBottom: '1px solid var(--dsw-alias-border-l2)',\n}\n\nconst panelFootStyle: CSSProperties = {\n boxSizing: 'border-box',\n flex: '0 0 auto',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n justifyContent: 'flex-end',\n padding: '10px 14px',\n borderTop: '1px solid var(--dsw-alias-border-l2)',\n}\n\nconst diffBodyStyle: CSSProperties = {\n flex: '1 1 auto',\n minHeight: 0,\n overflowY: 'auto',\n padding: '8px 10px',\n display: 'flex',\n flexDirection: 'column',\n fontFamily: 'var(--ds-font-family-code, monospace)',\n fontSize: '12px',\n lineHeight: '19px',\n}\n\nconst diffEmptyStyle: CSSProperties = {\n flex: '1 1 auto',\n color: 'var(--dsw-alias-label-tertiary)',\n fontSize: '13px',\n lineHeight: '20px',\n padding: '16px',\n textAlign: 'center',\n}\n\nconst hunkSepStyle: CSSProperties = {\n boxSizing: 'border-box',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'var(--dsw-alias-label-tertiary)',\n fontSize: '11px',\n lineHeight: '16px',\n padding: '2px 8px',\n margin: '2px 0',\n borderTop: '1px solid var(--dsw-alias-border-l1)',\n borderBottom: '1px solid var(--dsw-alias-border-l1)',\n userSelect: 'none',\n}\n\nconst closeStyle: CSSProperties = {\n flex: '0 0 auto',\n width: '24px',\n height: '24px',\n border: 'none',\n borderRadius: '999px',\n background: 'transparent',\n color: 'var(--dsw-alias-label-tertiary)',\n cursor: 'pointer',\n}\n\nexport function HistoryView({ t, ...props }: HistoryViewProps): JSX.Element | null {\n const sessionId = resolveSessionId(props)\n const [events, setEvents] = useState<GateEvent[] | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [stats, setStats] = useState<SnapshotStats | null>(null)\n const [diffOpen, setDiffOpen] = useState<{ eventId: number; path: string } | null>(null)\n\n useEffect(() => {\n setEvents(null)\n setError(null)\n setStats(null)\n if (sessionId === null) {\n setEvents([])\n return\n }\n let alive = true\n let cursor = 0\n let closeStream: (() => void) | null = null\n void fetchSnapshotStats(sessionId).then((next) => { if (alive) setStats(next) })\n\n /**\n * Decisions landing after the initial load. Both the stream's pushes and the\n * fallback's ticks carry only events past the cursor, so they merge the same\n * way; a batch is also the point where the snapshot inventory can have grown.\n */\n const onBatch = (batch: GateFeedBatch): void => {\n if (!alive || batch.events.length === 0) return\n for (const ev of batch.events) if (ev.id > cursor) cursor = ev.id\n setEvents((current) => {\n const known = new Set((current ?? []).map((ev) => ev.id))\n const added = batch.events.filter((ev) => !known.has(ev.id))\n return added.length === 0 ? current : [...added, ...(current ?? [])].sort((a, b) => b.id - a.id)\n })\n setError(null)\n void fetchSnapshotStats(sessionId).then((next) => { if (alive) setStats(next) })\n }\n\n // One REST load for the list (so a failure is reportable, not silently an\n // empty page); everything after it is pushed rather than re-fetched on a timer.\n fetchEvents(sessionId, 0)\n .then((loaded) => {\n if (!alive) return\n setEvents([...loaded].sort((a, b) => b.id - a.id))\n setError(null)\n cursor = loaded.reduce((max, ev) => (ev.id > max ? ev.id : max), 0)\n })\n .catch((e: unknown) => {\n if (alive) setError(String((e as Error)?.message ?? e))\n })\n .finally(() => {\n // Opens with the cursor the load settled on, so no history is replayed.\n if (alive) closeStream = followEvents(sessionId, () => cursor, onBatch)\n })\n\n return () => {\n alive = false\n closeStream?.()\n }\n }, [sessionId])\n\n /** Whether one event has a snapshot covering this file (chip is clickable). */\n const hasSnapshot = (ev: GateEvent, file: string): boolean => {\n const paths = stats?.files[String(ev.id)]\n if (paths === undefined || paths.length === 0) return false\n const base = basename(file)\n return paths.some((p) => p === file || basename(p) === base)\n }\n\n return (\n <div style={{ boxSizing: 'border-box', maxWidth: '720px', margin: '0 auto', padding: '8px 4px' }}>\n <div style={{ marginBottom: '10px' }}>\n <div style={{ fontSize: '14px', fontWeight: 600, color: 'var(--dsw-alias-label-primary)' }}>{t('history.title')}</div>\n <div style={{ marginTop: '2px', fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-primary) !important' }}>{t('history.subtitle')}</div>\n </div>\n <SnapshotBar\n t={t}\n stats={stats}\n sessionId={sessionId}\n onCleared={() => { void fetchSnapshotStats(sessionId).then(setStats) }}\n />\n {events === null\n ? (\n <div style={{ padding: '16px 0', fontSize: '13px', color: 'var(--dsw-alias-label-tertiary)' }}>\n {error === null ? t('history.loading') : `${t('history.error')}${error}`}\n </div>\n )\n : events.length === 0\n ? (\n <div style={{ padding: '16px 0', fontSize: '13px', color: 'var(--dsw-alias-label-tertiary)' }}>\n {error === null ? t('history.empty') : `${t('history.error')}${error}`}\n </div>\n )\n : (\n <div>\n {events.map((ev) => {\n const style = presentation(ev.kind)\n const mark = glyphOf(ev.kind)\n const verdict = ev.verdict === undefined ? '' : (VERDICT_LABELS[ev.verdict] ?? ev.verdict)\n const files = ev.files ?? []\n // One chip per distinct basename (a decision may name the same\n // file both absolutely and relatively).\n const chips: string[] = []\n const seenBase = new Set<string>()\n for (const f of files) {\n const base = basename(f)\n if (base === '' || seenBase.has(base)) continue\n seenBase.add(base)\n chips.push(f)\n }\n return (\n <div key={ev.id} style={{ display: 'flex', gap: '10px', padding: '6px 10px', borderRadius: '8px', background: 'var(--dsw-alias-bg-layer-3, rgba(127,127,127,0.05))' }}>\n <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', flex: '0 0 auto', width: '20px' }}>\n <span\n aria-hidden\n style={{\n width: '18px',\n height: '18px',\n marginTop: '3px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '11px',\n lineHeight: '18px',\n borderRadius: '999px',\n border: `1px solid ${mark.color}`,\n color: mark.color,\n }}\n >\n {mark.char}\n </span>\n <span aria-hidden style={{ flex: '1 1 auto', width: '1px', minHeight: '10px', background: 'var(--dsw-alias-border-l2, rgba(127,127,127,0.3))' }} />\n </div>\n <div style={{ flex: '1 1 auto', minWidth: 0, paddingBottom: '12px' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }}>\n <code style={{ font: '600 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>{ev.tool}</code>\n <span\n style={{\n fontSize: '11px',\n lineHeight: '18px',\n padding: '0 8px',\n borderRadius: '9px',\n color: style.color,\n background: style.bg,\n fontWeight: 600,\n }}\n >\n {t(TAG_KEYS[ev.kind])}\n </span>\n {verdict === ''\n ? null\n : (\n <span style={{ fontSize: '11px', lineHeight: '18px', padding: '0 6px', borderRadius: '9px', color: 'var(--dsw-alias-label-tertiary)', border: '1px solid var(--dsw-alias-border-l2)' }}>\n {verdict}\n </span>\n )}\n {ev.risk === undefined || ev.risk === ''\n ? null\n : (\n <span style={{ fontSize: '11px', lineHeight: '18px', padding: '0 6px', borderRadius: '9px', color: 'var(--dsw-alias-label-tertiary)', border: '1px solid var(--dsw-alias-border-l2)' }}>\n {ev.risk}\n </span>\n )}\n {ev.kind === 'manual-approved' && ev.learningCount !== undefined && ev.threshold !== undefined\n ? (\n <span style={{ fontSize: '11px', lineHeight: '18px', padding: '0 6px', borderRadius: '9px', color: 'var(--dsw-alias-state-warn-label)', border: '1px solid var(--dsw-alias-border-l2)' }}>\n {t('history.learnedProgress').replace('%n', String(ev.learningCount)).replace('%t', String(ev.threshold))}\n </span>\n )\n : null}\n <span style={{ marginLeft: 'auto', flex: '0 0 auto', fontSize: '11px', color: 'var(--dsw-alias-label-tertiary)' }}>{clockTime(ev.ts)}</span>\n </div>\n <div style={{ marginTop: '2px', fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-secondary, inherit)', overflowWrap: 'anywhere' }}>\n {ev.justification ?? ev.reason}\n </div>\n {chips.length === 0\n ? null\n : (\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px', marginTop: '4px' }}>\n {chips.map((file) => {\n const clickable = hasSnapshot(ev, file)\n return (\n <span\n key={file}\n title={clickable ? t('history.diffChipTitle') : file}\n role={clickable ? 'button' : undefined}\n onClick={clickable ? () => { setDiffOpen({ eventId: ev.id, path: file }) } : undefined}\n style={{\n boxSizing: 'border-box',\n maxWidth: '260px',\n height: '20px',\n display: 'inline-flex',\n alignItems: 'center',\n padding: '0 7px',\n borderRadius: '5px',\n font: '11px/18px var(--ds-font-family-code, monospace)',\n border: `1px solid ${clickable ? 'var(--dsw-alias-state-business-primary)' : 'var(--dsw-alias-border-l1)'}`,\n color: clickable ? 'var(--dsw-alias-state-business-primary)' : 'var(--dsw-alias-label-secondary)',\n background: 'var(--dsw-alias-bg-layer-1, transparent)',\n cursor: clickable ? 'pointer' : 'default',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {basename(file)}\n </span>\n )\n })}\n </div>\n )}\n </div>\n </div>\n )\n })}\n </div>\n )}\n {diffOpen === null\n ? null\n : (\n <DiffPanel\n t={t}\n sessionId={sessionId}\n eventId={diffOpen.eventId}\n path={diffOpen.path}\n onClose={() => { setDiffOpen(null) }}\n />\n )}\n </div>\n )\n}\n","/**\n * compat.ts —— client 半区版本敏感代码的**唯一窄腰**(INDEX §C:版本差异代码\n * 只许出现在窄腰文件,能力探测在严格代理 client ctx 上不可行——inject 清单外\n * 的属性读取直接 throw,故用双 scoped-inject 按代分流)。\n *\n * 已核实的分叉(2026-10-05 六线农场 node_modules 实查 + input-traffic P2 同型\n * 结论):持久化设置面按代互斥——\n * - 0.1.7+ 走 `configForms.get(ns)`;\n * - ≤0.1.5 走 `settingsScope.bind({ namespace })`。\n * 0.1.7-rc.1 的 client-ui-settings 包全文已无 `settingsScope` 字样,两服务\n * 天然不会双触发;缺席线上的 scoped fiber 永久 PENDING,与 family 槽缺席同型,\n * 不阻塞插件其余半区。**插件级 inject 因此只收六线通用服务**(slots/locale),\n * configForms 留在清单里会让 ≤0.1.5 整个 client 半区 PENDING 静默失活\n * (date-wrapper boot-audit 教训的 client 版)。\n *\n * 卡片消费的四个方法(getSnapshot/subscribe/set/unset)在两代都存在:新线的\n * `SettingsScopeSnapshot` 虽然 richer(base/user/revision/mode),但\n * `value`/`writable` 字段保留,`set`/`unset` 退化为 `mutate` 的便利包装\n * (adaptation-reports/dsh-perm-gate.md §1.5)。句柄因此按**本地结构类型**\n * 声明,不做宿主包的类型合并——编译面对每条宿主线的真实类型保持一致\n * (input-traffic compat.ts 同款纪律)。\n *\n * All @deepseek-ai/* imports are type-only (client bundle purity).\n */\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\n\n/** Structural minimum of a durable settings scope — shared by `configForms.get()`\n * (0.1.7+) and `settingsScope.bind()` (≤0.1.5). Declared locally so the compile\n * face stays identical against every host line's real types. */\nexport interface SettingsDocHandle {\n getSnapshot(): { status: string; value: unknown; writable: boolean }\n subscribe(listener: () => void): () => void\n set(field: string, value: unknown): Promise<void> | unknown\n unset(field: string): Promise<void> | unknown\n}\n\n/**\n * Resolve the plugin's durable settings scope through whichever service this\n * host line carries, then hand it to `onScope` exactly once.\n *\n * Both variants are scoped sub-injects: on a host without the service the fiber\n * waits forever WITHOUT blocking the plugin's other faces (same posture as the\n * notice strip's slot-inject when its slot holder is absent).\n */\nexport function resolveSettingsScope(\n ctx: ClientContext,\n namespace: string,\n onScope: (scope: SettingsDocHandle) => void,\n): void {\n // Modern hosts (0.1.7+): configForms owns cross-entry durable scopes.\n ctx.inject(['configForms'], (configForms: unknown) => {\n const scope = (configForms as { get(namespace: string): SettingsDocHandle }).get(namespace)\n onScope(scope)\n })\n // Old hosts (≤0.1.5): namespaced durable scope via bind().\n ctx.inject(['settingsScope'], (settingsScope: unknown) => {\n const scope = (settingsScope as {\n bind(spec: { namespace: string }): SettingsDocHandle\n }).bind({ namespace })\n onScope(scope)\n })\n}\n","/**\n * dsh-perm-gate — browser half.\n *\n * Registers the `dsh-perm-gate` dictionaries and one `settings.plugins.tab`\n * page keyed by the plugin's settings namespace, so the Plugins section of the\n * settings panel renders an editable page: the single 自动审查 tier switch\n * plus the four combinable backend approval strategies.\n *\n * All @deepseek-ai/* imports are type-only at the value level: collaboration\n * happens through cordis services (`slots`, `locale`, `configForms`) and slot\n * registration only (client bundle purity). The `LocaleNamespaceMap`\n * augmentation below is a type-only merge so the `locale:` seat type-checks.\n *\n * `ClientContext` comes from cordis directly. DSH 0.1.1 exported the identical\n * alias from `@deepseek-ai/dsh-client-runtime/client` (`export type ClientContext\n * = Context`), but that package was removed in 0.1.2-alpha.1 — cordis is the one\n * source that names the same type on both lines.\n */\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Declaration merge for `ctx.slots`. On the 0.1.2+ line the slot registry service\n// is declared by the renderer's client entry; on 0.1.1 it came from\n// `dsh-client-runtime/client` (via the settings client's peer), which is why the\n// renderer entry declares nothing there. Importing it is a no-op on the old line.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport { NS, dictionaries, type PermissiveKey } from './locales.ts'\nimport { PermissiveCard, type PermissiveCardInjected } from './card.tsx'\nimport { NoticeStrip } from './notice.tsx'\nimport { HistoryView } from './history.tsx'\nimport { resolveSettingsScope } from './compat.ts'\n\n/** The profile entry id of this plugin — the `configForms` key (kept in lockstep with cordis.patch.yml). */\nconst PERMISSIVE_NS = 'dsh-perm-gate'\n\n// Declare the plugin's dictionary namespace in the locale key domain so the\n// slot `locale:` seat and `ctx.locale.bind` are typed to our key union.\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n 'dsh-perm-gate': PermissiveKey\n }\n // The conversation dock slot is declared at runtime by the conversation UI\n // package (not a dev dependency here); mirror its contract so the typed\n // `slots.register` accepts our notice-strip entry. Approval-gate's client\n // demonstrates the runtime accepts this slot name with id/order/label options.\n interface SlotMap {\n 'conversation.input.dock': {\n kind: 'list'\n scope: 'session-maybe'\n owner: {\n /** Current conversation id (may be absent outside a session). */\n sessionId?: string\n /** Session-store selector hook supplied by the conversation shell. */\n useSessions?: (selector: (state: unknown) => unknown) => unknown\n }\n }\n // The conversation view slot (tab row next to the conversation timeline) is\n // declared at runtime by the conversation UI package; mirror its contract\n // so the typed `slots.register` accepts our approval-history entry.\n 'conversation.view': {\n kind: 'list'\n scope: 'session-maybe'\n owner: {\n sessionId?: string\n useSessions?: (selector: (state: unknown) => unknown) => unknown\n }\n }\n // Plugins-page configuration card (official ui-plugin-manager contract):\n // the host's Plugins page does not render volatile config forms on its\n // own — the page draws a config card on the bundle's detail page only when\n // a client claims this seat, keyed by the bundle's package name. Declared\n // here (the declaring page package is not a dev dependency), mirroring the\n // contract the page renders with (`{ view: 'page', form }` owner props).\n 'plugins.bundle.config': { kind: 'keyed'; scope: 'root'; owner: Record<string, unknown> }\n }\n}\n\n/** Services required by the browser half — generation-neutral only.\n *\n * `configForms` (0.1.7+) / `settingsScope` (≤0.1.5) are generation-exclusive\n * durable-settings faces: keeping either in the plugin-level inject list would\n * leave the WHOLE browser half fiber PENDING on the other line (strict ctx\n * proxy throws on undeclared service reads; pending fiber = silent death).\n * They resolve through scoped sub-injects in compat.ts instead, and the card\n * registrations below move into the resolution callback. */\nexport const inject = ['slots', 'locale']\n\n/**\n * Client plugin body: dictionaries plus the settings page registration.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n if (ctx.locale) ctx.effect(() => ctx.locale.register(NS, dictionaries), 'dsh-perm-gate: dictionaries')\n\n // No permission-picker decoration: the tier's label is the Chinese product\n // string supplied by cordis.patch.yml, and the composer draws glyphs only for\n // the three built-in values, so a plugin-contributed tier is icon-free on\n // every surface.\n\n // Decision notice strip above the conversation input: polls the host's\n // event feed so auto-allows / asks / denies are visible without opening logs.\n ctx.slots.inject('conversation.input.dock', function* () {\n yield ctx.slots.register({\n name: 'conversation.input.dock',\n id: 'dsh-perm-gate.notice',\n order: 30,\n label: () => t('notice.label'),\n locale: NS,\n }, NoticeStrip)\n }) as unknown\n\n // Approval-history page: a conversation-view tab listing every gate decision\n // of the session, newest first (the review-page pattern approval-gate\n // demonstrates; our data is the same events feed the notice strip polls).\n ctx.slots.inject('conversation.view', function* () {\n yield ctx.slots.register({\n name: 'conversation.view',\n id: 'dsh-perm-gate.history',\n order: 20,\n label: () => t('history.label'),\n locale: NS,\n inject: (sessionId: string | undefined) => ({ sessionId }),\n }, HistoryView)\n }) as unknown\n\n // A localized tab label (re-evaluated per read so it follows the active locale).\n const t = ctx.locale.bind(NS)\n\n // 设置卡注册收进 settings scope 解析回调(input-traffic P2 范式):卡片\n // inject 值闭包捕获已解析的句柄,注册体只在回调里跑一次——两代服务按代\n // 互斥,天然不双触发。旧线 ≤0.1.5 经 settingsScope.bind 解析(此时\n // `plugins.bundle.config` 席位在裸宿主上不存在,shadow-inject 为惰性\n // no-op,注册体不执行);0.1.7+ 经 configForms.get 解析。\n resolveSettingsScope(ctx, PERMISSIVE_NS, (scope) => {\n // 独立顶级设置节(范式 A):自动审查门,不再挂在「插件」节的 tab 下。\n ctx.slots.inject('settings.section', function* () {\n yield ctx.slots.register({\n name: 'settings.section',\n id: PERMISSIVE_NS,\n order: 30,\n label: () => t('section.title'),\n locale: NS,\n inject: (): PermissiveCardInjected => ({ scope }),\n }, PermissiveCard)\n }) as unknown\n\n // 插件页配置卡:Plugins 页不会自动渲染 volatile 配置表单——只有客户端注册\n // `plugins.bundle.config` 席位(key = package.json 的 name 字段),页面才会\n // 在 bundle 详情页渲染配置卡。注册同一个 PermissiveCard、传同一份 inject 值\n // (configForms 里的插件作用域),与上面的设置节共用一个事实来源;卡片自带\n // 展开壳,不依赖 tab 容器上下文,可独立渲染。\n ctx.slots.inject('plugins.bundle.config', () => ctx.slots.register({\n name: 'plugins.bundle.config',\n key: 'dsh-perm-gate',\n locale: NS,\n inject: (): PermissiveCardInjected => ({ scope }),\n }, PermissiveCard)) as unknown\n })\n}"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["useState","useRef","useState","useSyncExternalStore","useState","useRef","useState"],"sources":["../src/client/locales.ts","../src/deny-defaults.ts","../src/llm-presets.ts","../src/preset.ts","../src/client/sediment.tsx","../src/client/card.tsx","../src/client/feed.ts","../src/client/notice.tsx","../src/client/history.tsx","../src/client/compat.ts","../src/client/bridge-scope.ts","../src/client/index.ts"],"sourcesContent":["/** `dsh-perm-gate` client dictionaries (zh / en / ja / ko / fr / de / it / ru / es). */\n\n/** Dictionary namespace owned by this plugin. */\nexport const NS = 'dsh-perm-gate'\n\n/** The key union of this plugin's dictionary (source of truth: `zh`). */\nexport type PermissiveKey = keyof typeof zh\n\n/** Simplified Chinese dictionary (the key-set source of truth). */\nexport const zh = {\n 'card.title': '自动审查',\n 'section.title': '自动审查门',\n 'card.description': '独立审批档位:与只读 / 完全权限 / 白名单平行,在会话权限下拉中显示为「自动审查」。前端只暴露一个开关;后台四个审批策略可组合、由此处设置决定,仍对 P0 硬拒绝保持 fail-closed。',\n 'card.permissive': '启用自动审查档位',\n 'card.permissiveHint': '关闭时门禁行为与此前完全一致。',\n 'card.scopeNote': '档位作用域:本门禁仅在会话权限档位为 %scope 时生效。其他档位下整个门禁停用(含 P0 硬拒绝),由所选档位自身的策略接管;停用时会写入一条 stand-down 事件,并在输入框上方常驻一条提示条。',\n 'card.strategies': '后台审批策略(至少一个生效;可组合)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — 作用域内安全操作自动放行,危险/未知转 ask(中间档基线)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — 一律逐次 ask;审批面板「允许控件」含两个扩展按钮:「本会话重复允许该类」(会话语限次 grant)与「允许所有类型」(命令词持久迁入 rulesFile 白名单)',\n 'card.strategy.llmAssist': 'llmAssist — 自定义 LLM 按风险分级裁决:safe 自动放行;deletion/credential/remote/system/bulk 硬风险维持人工确认(分类器永不拒绝,只负责升级判断);neutral 进入确认学习;失败/超时回退人工',\n 'card.strategy.trustEscalation': 'trustEscalation — 沙箱升级免确认:本门禁已放行的调用,其工具内部发起的沙箱提权(shell / pwsh / edit 的 sandbox_permissions)由门禁直接批准,不再弹窗',\n 'card.strategy.trustEscalationHint': '沙箱提权审批发生在 tools/pre-execute 之后、工具体内部,门禁原本看不到它,因此「LLM 判安全已自动放行」的调用仍会弹窗要求你批准提权。开启后,仅对门禁确实放行过的那一次调用(按 callId 精确匹配)免确认,其余一律照旧走人工;目标模式非 workspace-write / danger-full-access 或理由无法识别时同样回退人工。关闭后提权保持人工把关。',\n 'card.readonly': '只读',\n 'card.unavailable': '设置命名空间不可用:请确认 dsh-perm-gate 已装配进 profile。',\n 'card.llmReceiver': 'llmAssist 接收 LLM(OpenAI 兼容,可用自定义 API)',\n 'card.llmEndpoint': 'Endpoint(BaseURL,如 https://api.openai.com/v1)',\n 'card.llmModel': 'Model(模型 id,如 deepseek-chat)',\n 'card.llmKey': 'API Key(保密)',\n 'card.llmKeyHidden': '未设置 · 首次输入后以 * 显示',\n 'card.llmKeyMasked': '已设置 · 输入新值覆盖',\n 'card.llmKeyOverwrite': '已设置保密值,输入新值并失焦即可覆盖。',\n 'card.llmKeyClear': '清除',\n 'card.allowlist': '白名单(allow,rulesFile 同步)',\n 'card.allowlistHint': '命中 allow 段的命令模式直接放行;逐条添加或删除,实时写入 rulesFile 并重载。',\n 'card.allowlistPresetNote': '预置白名单的等价物是 trustAutoAllow 策略(工作区内安全操作自动放行),在上方策略区开启;本列表镜像你的 rulesFile allow 段,初始为空属正常。',\n 'card.allowlistEmpty': '无白名单规则',\n 'card.allowlistPlaceholder': '新命令模式,如 npm test*',\n 'card.allowlistAdd': '添加',\n 'card.allowlistRemove': '删除该模式',\n 'card.allowlistBulk': '批量编辑',\n 'card.allowlistBulkHide': '收起批量编辑',\n 'card.allowlistSave': '保存白名单',\n 'card.riskLearning': 'riskLearning — 裁决学习:neutral 风险操作经人工确认并执行后计数,满阈值且操作指纹一致时自动放行',\n 'card.riskLearningHint': '学习状态为插件自有数据($DSH_HOME/perm-gate/learning.json),不写入你的 YAML 规则文件;不同目标永不复用放行。默认关闭。',\n 'card.riskThreshold': '自动放行所需人工确认次数(1–10)',\n 'notice.label': '权限门禁动态',\n 'history.label': '审批记录',\n 'history.title': '权限审批记录',\n 'history.subtitle': '本会话中门禁的每次判定轨迹(最新在上)',\n 'history.loading': '加载中…',\n 'history.empty': '本会话暂无审批记录',\n 'history.error': '加载失败:',\n 'history.tag.auto': '自动放行',\n 'history.tag.ask': '转人工',\n 'history.tag.deny': '拒绝',\n 'card.denylistRestore': '恢复预置黑名单',\n 'card.denylist': '黑名单(deny 关键词,插件预置)',\n 'card.denylistHint': '命中关键词(大小写不敏感子串)的调用直接拒绝,先于白名单/授权/LLM。预置列表继承自 dsh-approval-gate,安装即生效;可增删,清空或删除后可用「恢复预置黑名单」一键还原(空列表等同预置,黑名单常开)。',\n 'card.denylistEmpty': '黑名单为空(所有调用都不会被关键词层拒绝)',\n 'card.denylistPlaceholder': '新关键词,如 drop database',\n 'card.denylistAdd': '添加',\n 'card.denylistRemove': '删除该关键词',\n 'card.denylistTagPreset': '预置',\n 'card.denylistTagCustom': '自定义',\n 'card.riskSediment': 'riskSediment — 学习沉淀:满阈值的确认样本成为确定性放行规则',\n 'card.riskSedimentHint': '开启后,同一「工具|类别」确认满阈值,其样本指纹即沉淀为放行规则——同工具同目标精确命中时直接放行,不再过 LLM(关闭 llmAssist 也继续生效)。',\n 'card.sediment': '学习沉淀(确定性放行规则)',\n 'card.sedimentHint': '来自人工确认的沉淀规则:样本指纹命中才放行,不同目标永不复用。可终止单个学习或删除单条样本。',\n 'card.sedimentEmpty': '暂无沉淀规则(确认满阈值的样本会出现在这里)',\n 'card.sedimentCount': '已确认 %n/%t',\n 'card.sedimentStop': '终止',\n 'card.sedimentStopTitle': '终止该学习(删除计数与样本)',\n 'card.sedimentStopConfirm': '终止「%k」的学习?将删除其确认计数与全部样本。',\n 'card.sedimentSampleRemove': '删除该沉淀样本',\n 'card.llmSource': '接收 LLM 来源',\n 'card.llmSourceCustom': '自定义 API(OpenAI 兼容)',\n 'card.llmSourceHost': '使用会话当前默认模型(DSH llm 服务)',\n 'card.llmSourceHostHint': '默认使用 DSH 会话当前选中的模型组执行审批判定(下方显示当前生效值);Provider / Model 留空即跟随会话,也可从下拉选择或手动输入固定下来——你在 DSH 里配置的自定义组(如 local-35b)会自动出现在下拉中。',\n 'card.llmProvider': 'Provider(留空 = 跟随会话当前选择)',\n 'card.llmProviderPlaceholder': '跟随会话当前选择',\n 'card.llmModelHostPlaceholder': '留空 = 跟随会话当前选择',\n 'card.llmResolved': '当前生效:%p / %m',\n 'card.llmPreset': '预置端点(选择后自动填充,可再编辑)',\n 'card.llmPresetChoose': '选择预置…',\n 'card.llmPresetPublic': '公共 API 预置',\n 'card.llmPresetHost': 'DSH 模型组(选择后自动切换为会话模式)',\n 'card.networkEnabled': '网络拦截(networkEnabled)',\n 'card.networkEnabledHint': '开启后启动本地代理拦截子进程出站连接,按规则放行/阻断。关闭则零行为变更。',\n 'card.watch': '规则热重载(watch)',\n 'card.watchHint': '开启后自动监听规则文件变更并即时生效,无需手动 reload。',\n 'card.networkRebindNote': '切换后立即生效(自动重绑,无需重载插件)。',\n 'card.networkInjectEnv': '注入代理环境变量(networkInjectEnv)',\n 'card.networkInjectEnvHint': '开启后为子进程写入 HTTP(S)_PROXY / ALL_PROXY(并清空 NO_PROXY)。关闭则只启动监听、不改变任何进程环境。',\n 'card.healthStale': '宿主路由不可用(404)——node 半区仍是旧版本,请完全重启 dsh(而非仅刷新页面)后重试。',\n 'card.healthTest': '健康测试',\n 'card.healthRunning': '测试中…',\n 'card.healthOk': '正常(%ms ms)',\n 'card.healthFail': '失败:',\n 'history.tag.learned': '学习沉淀',\n 'history.tag.manualApproved': '人工通过',\n 'history.tag.manualRejected': '人工拒绝',\n 'history.tag.manualCancelled': '人工取消',\n 'history.tag.standDown': '门禁停用',\n 'history.learnedProgress': '学习 %n/%t',\n 'history.snapshots': 'diff 快照',\n 'history.clearSession': '仅清本会话',\n 'history.clearAll': '清空全部',\n 'history.clearSessionTitle': '仅清除本会话的 diff 快照(不影响其他会话)',\n 'history.clearAllTitle': '清空全部会话(含其他会话未查看过的)diff 快照,需二次确认',\n 'history.clearSessionConfirm': '确定清除【本会话】的 diff 快照?仅删除本会话审批产生的改动对比数据,不影响审批记录本身。',\n 'history.clearAllConfirm': '确定清除【全部会话】的 diff 快照?这可能删除其他会话还没看过的改动对比记录,且不可恢复。',\n 'history.diffTitle': '文件改动对比',\n 'history.diffClose': '关闭',\n 'history.diffLoading': '加载中…',\n 'history.diffEmpty': '该文件无内容变化(或文件不可读)',\n 'history.diffLoadFail': '加载 diff 失败:',\n 'history.diffRevert': '撤销此改动',\n 'history.diffReverting': '发送中…',\n 'history.diffRevertDone': '已发送撤销指令',\n 'history.diffRevertSent': '撤销指令已发送到对话框,AI 将按指令恢复文件',\n 'history.diffRevertFail': '发送失败:',\n 'history.diffNoSnapshot': '该事件没有此文件的快照',\n 'history.diffChipTitle': '查看该文件改动对比',\n 'history.diffStats': '+%a / -%r 行变更 · %c 行未变',\n 'history.diffGone': '(文件当前已不存在)',\n 'history.diffHidden': '%n 行未修改',\n // Rule test (dry-run) panel. `%d` is the defaultAction, `%s` is unused here.\n 'card.dryRun': '规则测试',\n 'card.dryRunHint': '用当前生效的规则判定一次调用,不执行任何工具、不写入任何规则。改规则前先在这里验一遍。',\n 'card.dryRunTool': '工具名',\n 'card.dryRunCommand': '命令 / 参数',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': '测试',\n 'card.dryRunRunning': '判定中…',\n 'card.dryRunEmpty': '尚未测试。填入工具名与命令,点「测试」查看会怎么裁决。',\n 'card.dryRunVerdict': '裁决',\n 'card.dryRunAllow': '放行',\n 'card.dryRunAsk': '人工确认',\n 'card.dryRunDeny': '拒绝',\n 'card.dryRunRule': '命中规则',\n 'card.dryRunRuleNone': '无规则命中,走 defaultAction:%d',\n 'card.dryRunDimensions': '约束维度',\n 'card.dryRunReason': '原因',\n 'card.dryRunNote': '「命中规则」来自规则层。若裁决由更早的硬拒绝或关键词黑名单产生,则不会有规则序号——那种情况下列出的维度仅供参考。',\n 'card.dryRunNoRules': '(当前加载了 0 条规则:检查 rulesFile 路径)',\n 'card.dryRunFail': '测试失败:',\n 'card.dryRunStale': '路由不存在(插件未重启?)',\n 'card.rules': 'Settings 内置规则',\n 'card.rulesHint': '门禁此刻实际加载的规则(来自本插件入口的 rules 配置字段;未配置时回退到规则文件)。只读——这里改不了任何东西。要改规则,用下面的白名单,或在设置页中编辑。',\n 'card.rulesRefresh': '刷新',\n 'card.rulesLoading': '读取中…',\n 'card.rulesPath': '来源',\n 'card.rulesNone': '未配置规则',\n 'card.rulesCounts': '规则',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b 字节 · %l 行',\n 'card.rulesMissing': '规则不存在。门禁会退到内置默认。',\n 'card.rulesTruncated': '规则过大,仅显示前 512 KB。',\n 'card.rulesError': '加载失败:',\n 'card.rulesStale': '路由不存在(插件未重启?)',\n 'card.rulesNote': '此处只读:面板无法修改规则;白名单段与“始终允许”会写回本插件的入口配置。',\n} satisfies Record<string, string>\n\n/** English dictionary (keys mirror zh). */\nexport const en: Record<keyof typeof zh, string> = {\n 'card.title': '自动审查 (Auto review)',\n 'section.title': 'Auto-Review Gate',\n 'card.description': 'Independent approval tier, parallel to read-only / full-access / whitelist, shown as 自动审查 in the session permission picker. The front-end exposes a single switch; the four backend approval strategies are combinable via this panel and still fail-closed against P0 hard-deny.',\n 'card.permissive': 'Enable the 自动审查 tier',\n 'card.permissiveHint': 'When off, the gate behaves exactly as before.',\n 'card.scopeNote': 'Preset scope: this gate only acts while the session permission preset is %scope. Under any other preset the whole gate stands down — P0 hard-deny included — and the selected preset\\'s own policy takes over. A stand-down records one event and leaves a sticky strip above the input.',\n 'card.strategies': 'Backend approval strategies (at least one effective; combinable)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — safe in-scope ops auto-allow; dangerous/unknown ask (baseline middle tier)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — every crossing asks; the approval \"allow controls\" get two extended buttons: \"repeat-allow this type this session\" (bounded session grant) and \"allow every occurrence\" (persist the command word into the rulesFile whitelist)',\n 'card.strategy.llmAssist': 'llmAssist — a custom LLM grades risk: safe auto-allows; deletion/credential/remote/system/bulk hard risks keep the human ask (the classifier never denies — it only escalates); neutral enters confirm-learning; failure/timeout falls back to the human',\n 'card.strategy.trustEscalation': 'trustEscalation — sandbox escalation without a prompt: for a call this gate already allowed, the sandbox widening a shell / pwsh / edit tool raises from inside itself is approved here instead of asking you',\n 'card.strategy.trustEscalationHint': 'A sandbox escalation is asked from inside the tool body, after tools/pre-execute, so the gate never saw it — a call the LLM graded safe and the gate auto-allowed still prompted you to approve the widening. With this on, only the exact call the gate allowed (matched by callId) skips the prompt; everything else goes to the human as before, as does any unrecognized reason or a target other than workspace-write / danger-full-access. Turn it off to keep widening human-gated.',\n 'card.readonly': 'Read-only',\n 'card.unavailable': 'Settings namespace unavailable: make sure dsh-perm-gate is assembled into this profile.',\n 'card.llmReceiver': 'llmAssist receiving LLM (OpenAI-compatible; any custom API)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, e.g. https://api.openai.com/v1)',\n 'card.llmModel': 'Model (model id, e.g. deepseek-chat)',\n 'card.llmKey': 'API Key (secret)',\n 'card.llmKeyHidden': 'Unset · shown as * after first entry',\n 'card.llmKeyMasked': 'Set · type a new value to overwrite',\n 'card.llmKeyOverwrite': 'A secret is stored; type a new value and blur to overwrite it.',\n 'card.llmKeyClear': 'Clear',\n 'card.allowlist': 'Whitelist (allow, synced to rulesFile)',\n 'card.allowlistHint': 'Patterns in the allow section allow directly; add or remove entries one by one, written to the rulesFile and reloaded live.',\n 'card.allowlistPresetNote': 'The preset-whitelist equivalent is the trustAutoAllow strategy (safe in-scope ops auto-allow), enabled in the strategies section above; this list mirrors your rulesFile allow section and legitimately starts empty.',\n 'card.allowlistEmpty': 'No whitelist rules',\n 'card.allowlistPlaceholder': 'New command pattern, e.g. npm test*',\n 'card.allowlistAdd': 'Add',\n 'card.allowlistRemove': 'Remove this pattern',\n 'card.allowlistBulk': 'Bulk edit',\n 'card.allowlistBulkHide': 'Hide bulk edit',\n 'card.allowlistSave': 'Save whitelist',\n 'card.riskLearning': 'riskLearning — verdict learning: neutral-risk asks that the human approves and that execute count up; the same operation auto-allows at threshold with a matching fingerprint',\n 'card.riskLearningHint': 'Learning state is plugin-owned ($DSH_HOME/perm-gate/learning.json) and never written into your YAML rules; a different target never reuses authority. Off by default.',\n 'card.riskThreshold': 'Human confirmations required before auto-allow (1–10)',\n 'notice.label': 'Permission gate activity',\n 'history.label': 'Approvals',\n 'history.title': 'Permission approval records',\n 'history.subtitle': 'Every gate decision in this conversation, newest first',\n 'history.loading': 'Loading…',\n 'history.empty': 'No approval records in this session yet',\n 'history.error': 'Failed to load: ',\n 'history.tag.auto': 'Auto-allowed',\n 'history.tag.ask': 'Asked',\n 'history.tag.deny': 'Denied',\n 'card.denylistRestore': 'Restore preset blacklist',\n 'card.denylist': 'Blacklist (deny keywords, plugin preset)',\n 'card.denylistHint': 'A call whose text contains a keyword (case-insensitive substring) is denied outright, before whitelist / grants / LLM. The preset list is inherited from dsh-approval-gate and active from install; edit freely — empty or cleared falls back to the preset (one-click restore available), so the blacklist never silently turns off.',\n 'card.denylistEmpty': 'Blacklist empty (no call is vetoed by the keyword layer)',\n 'card.denylistPlaceholder': 'New keyword, e.g. drop database',\n 'card.denylistAdd': 'Add',\n 'card.denylistRemove': 'Remove this keyword',\n 'card.denylistTagPreset': 'Preset',\n 'card.denylistTagCustom': 'Custom',\n 'card.riskSediment': 'riskSediment — learning sedimentation: threshold-reached samples become deterministic auto-allows',\n 'card.riskSedimentHint': 'When on, once a tool|category key reaches the threshold its sample fingerprints are sedimented into allow rules — an exact same-tool same-target hit allows outright without another LLM call (keeps working with llmAssist off).',\n 'card.sediment': 'Learning sediment (deterministic allow rules)',\n 'card.sedimentHint': 'Rules sedimented from human confirmations: only an exact fingerprint hit allows, never a different target. Terminate one learning or remove one sample.',\n 'card.sedimentEmpty': 'No sedimented rules yet (samples reaching the threshold appear here)',\n 'card.sedimentCount': 'confirmed %n/%t',\n 'card.sedimentStop': 'Terminate',\n 'card.sedimentStopTitle': \"Terminate this learning (drops the count and samples)\",\n 'card.sedimentStopConfirm': \"Terminate learning for '%k'? Its count and samples are dropped.\",\n 'card.sedimentSampleRemove': 'Remove this sedimented sample',\n 'card.llmSource': 'Receiver source',\n 'card.llmSourceCustom': 'Custom API (OpenAI-compatible)',\n 'card.llmSourceHost': \"Use the session's current default model (DSH llm service)\",\n 'card.llmSourceHostHint': 'By default approval grading runs on the model group the DSH session currently uses (the effective value is shown below); leave Provider / Model empty to follow the session, or pick from the dropdown or type to pin one — custom groups you configured in DSH (e.g. local-35b) appear automatically.',\n 'card.llmProvider': 'Provider (empty = follow the session selection)',\n 'card.llmProviderPlaceholder': 'Follow the session selection',\n 'card.llmModelHostPlaceholder': 'Empty = follow the session selection',\n 'card.llmResolved': 'Effective now: %p / %m',\n 'card.llmPreset': 'Endpoint presets (fills the fields; still editable)',\n 'card.llmPresetChoose': 'Pick a preset…',\n 'card.llmPresetPublic': 'Public API presets',\n 'card.llmPresetHost': 'DSH model groups (selecting one switches to the session receiver)',\n 'card.networkEnabled': 'Network interception (networkEnabled)',\n 'card.networkEnabledHint': 'When on, starts a local proxy that intercepts outbound subprocess connections and applies allow/deny rules. Off = zero behavior change.',\n 'card.watch': 'Rule hot-reload (watch)',\n 'card.watchHint': 'When on, automatically watches rule files for changes and applies them instantly without manual reload.',\n 'card.networkRebindNote': 'Takes effect immediately — the proxy rebinds automatically, no plugin reload needed.',\n 'card.networkInjectEnv': 'Inject proxy environment (networkInjectEnv)',\n 'card.networkInjectEnvHint': 'Writes HTTP(S)_PROXY / ALL_PROXY for subprocesses (and clears NO_PROXY). Off = the listener runs but no process environment is changed.',\n 'card.healthStale': \"Host route unavailable (404) — the node half is still an old build; fully restart dsh (not just the browser page) and retry.\",\n 'card.healthTest': 'Health test',\n 'card.healthRunning': 'Testing…',\n 'card.healthOk': 'OK (%ms ms)',\n 'card.healthFail': 'Failed: ',\n 'history.tag.learned': 'Learned',\n 'history.tag.manualApproved': 'Approved',\n 'history.tag.manualRejected': 'Rejected',\n 'history.tag.manualCancelled': 'Cancelled',\n 'history.tag.standDown': 'Gate off',\n 'history.learnedProgress': 'learned %n/%t',\n 'history.snapshots': 'diff snapshots',\n 'history.clearSession': 'Clear this session',\n 'history.clearAll': 'Clear all',\n 'history.clearSessionTitle': 'Clear only this session\\u2019s diff snapshots (other sessions untouched)',\n 'history.clearAllTitle': 'Clear diff snapshots for every session, including ones never reviewed — asks again',\n 'history.clearSessionConfirm': 'Clear this session\\u2019s diff snapshots? Only the change-comparison data produced by this session\\u2019s approvals is removed; the approval records stay.',\n 'history.clearAllConfirm': 'Clear diff snapshots for ALL sessions? This may delete change comparisons other sessions have not reviewed yet, and cannot be undone.',\n 'history.diffTitle': 'File change comparison',\n 'history.diffClose': 'Close',\n 'history.diffLoading': 'Loading…',\n 'history.diffEmpty': 'No content change (or the file is unreadable)',\n 'history.diffLoadFail': 'Failed to load diff: ',\n 'history.diffRevert': 'Revert this change',\n 'history.diffReverting': 'Sending…',\n 'history.diffRevertDone': 'Revert instruction sent',\n 'history.diffRevertSent': 'Revert instruction sent to the conversation; the AI will restore the file accordingly',\n 'history.diffRevertFail': 'Send failed: ',\n 'history.diffNoSnapshot': 'This event has no snapshot for that file',\n 'history.diffChipTitle': 'View this file\\u2019s change comparison',\n 'history.diffStats': '+%a / -%r lines changed · %c unchanged',\n 'history.diffGone': ' (file no longer exists)',\n 'history.diffHidden': '%n unmodified lines',\n 'card.dryRun': 'Rule test',\n 'card.dryRunHint': 'Judge one call against the rules in force. Runs no tool and writes no rule — check a rule here before you change it.',\n 'card.dryRunTool': 'Tool',\n 'card.dryRunCommand': 'Command / arguments',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'Test',\n 'card.dryRunRunning': 'Judging…',\n 'card.dryRunEmpty': 'Nothing tested yet. Fill in a tool and command, then press Test to see how it would be judged.',\n 'card.dryRunVerdict': 'Verdict',\n 'card.dryRunAllow': 'allow',\n 'card.dryRunAsk': 'ask',\n 'card.dryRunDeny': 'deny',\n 'card.dryRunRule': 'Matched rule',\n 'card.dryRunRuleNone': 'no rule matched; defaultAction: %d',\n 'card.dryRunDimensions': 'Dimensions',\n 'card.dryRunReason': 'Reason',\n 'card.dryRunNote': '\"Matched rule\" comes from the rule layer. When the verdict was produced by an earlier hard-deny or by the keyword blacklist there is no rule index — the dimensions listed are then informational only.',\n 'card.dryRunNoRules': '(0 rules loaded — check the rulesFile path)',\n 'card.dryRunFail': 'Test failed: ',\n 'card.dryRunStale': 'route missing (plugin not restarted?)',\n 'card.rules': 'Settings Built-in Rules',\n 'card.rulesHint': 'The rules the gate is loading right now (from this plugin entry\\'s `rules` config field; falls back to the rules file when unset). Read-only — nothing here can change them. To change rules, use the allowlist below or edit them on the settings page.',\n 'card.rulesRefresh': 'Refresh',\n 'card.rulesLoading': 'Reading…',\n 'card.rulesPath': 'Source',\n 'card.rulesNone': 'no rules configured',\n 'card.rulesCounts': 'Rules',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b bytes · %l lines',\n 'card.rulesMissing': 'Rules not found. The gate falls back to its built-in defaults.',\n 'card.rulesTruncated': 'Rules are large; showing the first 512 KB only.',\n 'card.rulesError': 'Load failed: ',\n 'card.rulesStale': 'route missing (plugin not restarted?)',\n 'card.rulesNote': 'Read-only: this panel cannot modify the rules. The allowlist section and \"allow always\" write back to this plugin\\'s entry config.',\n}\n\n/** Japanese dictionary (keys mirror zh). */\nexport const ja: Record<keyof typeof zh, string> = {\n 'card.title': '自动审查(自動審査)ティア',\n 'section.title': '自動審査ゲート',\n 'card.description': 'read-only / full-access / whitelist と並ぶ独立の承認モード。セッション権限ピッカーでは「自动审查」と表示されます。フロントは単一スイッチのみ。バックエンドの 4 つの承認戦略はこのパネルで組み合わせ可能で、P0 ハード拒否に対して依然 fail-closed。',\n 'card.permissive': '自动审查ティアを有効化',\n 'card.permissiveHint': 'オフのときは以前と完全に同じ動作です。',\n 'card.scopeNote': 'プリセットスコープ: このゲートはセッションの権限プリセットが %scope のときだけ動作します。それ以外のプリセットでは P0 ハード拒否を含むゲート全体が停止し、選択されたプリセット自身のポリシーが引き継ぎます。停止時は stand-down イベントを 1 件記録し、入力欄の上に常駐表示します。',\n 'card.strategies': 'バックエンド承認戦略(少なくとも 1 つ有効、組み合わせ可)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — スコープ内の安全操作は自動許可、危険/不明は ask(中間ティアのベースライン)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — すべて ask。承認パネルの「許可コントロール」に2つの拡張ボタン:「このセッションで当該種別を繰り返し許可」(セッション限次 grant)と「すべての発生を許可」(コマンド語を rulesFile の許可リストへ永続化)',\n 'card.strategy.llmAssist': 'llmAssist — カスタム LLM がリスクを判定:safe は自動許可、deletion/credential/remote/system/bulk のハードリスクは人手確認を維持(分類器は決して拒否せず、判断をエスカレートするだけ)、neutral は確認学習へ、失敗/タイムアウトは人手にフォールバック',\n 'card.strategy.trustEscalation': 'trustEscalation — サンドボックス昇格を確認なしで許可:本ゲートが既に許可した呼び出しについて、shell / pwsh / edit がツール内部から要求するサンドボックス拡張をゲートが承認し、プロンプトを出しません',\n 'card.strategy.trustEscalationHint': 'サンドボックス昇格の承認要求は tools/pre-execute の後、ツール本体の内部で発行されるためゲートには見えず、LLM が safe と判定して自動許可した呼び出しでも拡張の承認を求められていました。オンにすると、ゲートが実際に許可した同一呼び出し(callId で厳密一致)だけがプロンプトを省略し、それ以外は従来どおり人手に回ります。理由を認識できない場合や対象が workspace-write / danger-full-access 以外の場合も同様です。オフにすると拡張は常に人手の判断となります。',\n 'card.readonly': '読み取り専用',\n 'card.unavailable': '設定名前空間が利用できません:dsh-perm-gate がこの profile に組み込まれているか確認してください。',\n 'card.llmReceiver': 'llmAssist 受信 LLM(OpenAI 互換、カスタム API 可)',\n 'card.llmEndpoint': 'Endpoint(BaseURL、例:https://api.openai.com/v1)',\n 'card.llmModel': 'Model(モデル id、例:deepseek-chat)',\n 'card.llmKey': 'API Key(機密)',\n 'card.llmKeyHidden': '未設定・初回入力後は * 表示',\n 'card.llmKeyMasked': '設定済み・新しい値を入力すると上書き',\n 'card.llmKeyOverwrite': '機密値が保存されています。新しい値を入力してフォーカスを外すと上書きします。',\n 'card.llmKeyClear': 'クリア',\n 'card.allowlist': '許可リスト(allow、rulesFile と同期)',\n 'card.allowlistHint': 'allow セクションに一致したパターンは直接許可。1 件ずつ追加・削除でき、rulesFile に即時書き込み&再読込します。',\n 'card.allowlistPresetNote': 'プリセット許可リストの等価物は trustAutoAllow 戦略(スコープ内の安全操作を自動許可)で、上の戦略セクションで有効化します。このリストは rulesFile の allow を反映するため、初期は空で正常です。',\n 'card.allowlistEmpty': '許可ルールはありません',\n 'card.allowlistPlaceholder': '新しいコマンドパターン、例:npm test*',\n 'card.allowlistAdd': '追加',\n 'card.allowlistRemove': 'このパターンを削除',\n 'card.allowlistBulk': '一括編集',\n 'card.allowlistBulkHide': '一括編集を閉じる',\n 'card.allowlistSave': '許可リストを保存',\n 'card.riskLearning': 'riskLearning — 裁決学習:neutral リスク操作が人手で承認され実行されるとカウントし、しきい値到達後は同一操作(指紋一致)のみ自動許可',\n 'card.riskLearningHint': '学習状態はプラグイン所有($DSH_HOME/perm-gate/learning.json)で、YAML ルールには書き込みません。別の対象は決して権限を再利用しません。既定はオフ。',\n 'card.riskThreshold': '自動許可に必要な人手確認回数(1–10)',\n 'notice.label': '権限ゲートの活動',\n 'history.label': '承認記録',\n 'history.title': '権限承認記録',\n 'history.subtitle': 'このセッションでのゲート判定のすべて(新しい順)',\n 'history.loading': '読み込み中…',\n 'history.empty': 'このセッションにはまだ承認記録がありません',\n 'history.error': '読み込み失敗:',\n 'history.tag.auto': '自動許可',\n 'history.tag.ask': '人手へ',\n 'history.tag.deny': '拒否',\n 'card.denylistRestore': 'プリセットの拒否キーワードに戻す',\n 'card.denylist': '拒否キーワード(deny、プリセット)',\n 'card.denylistHint': 'キーワード(大小文字を区別しない部分一致)を含む呼び出しは、許可リスト / 許可 / LLM より先に拒否されます。プリセットは dsh-approval-gate から継承し、導入直後から有効。空または未設定ならプリセットを適用(ワンクリック復元対応)し、黑名単が静かに無効化されることはありません。',\n 'card.denylistEmpty': '拒否キーワードは空です(キーワード層で拒否される呼び出しはありません)',\n 'card.denylistPlaceholder': '新しいキーワード、例:drop database',\n 'card.denylistAdd': '追加',\n 'card.denylistRemove': 'このキーワードを削除',\n 'card.denylistTagPreset': 'プリセット',\n 'card.denylistTagCustom': 'カスタム',\n 'card.riskSediment': 'riskSediment — 学習沈殿:しきい値に達したサンプルが決定論的な自動許可ルールに',\n 'card.riskSedimentHint': 'オンにすると、tool|category キーの確認がしきい値に達した時点でサンプル指紋が許可ルールとして沈殿します。同一ツール・同一ターゲットの正確一致は LLM を経由せず自動許可(llmAssist オフでも継続)。',\n 'card.sediment': '学習沈殿(決定論的許可ルール)',\n 'card.sedimentHint': '人手確認から沈殿したルール:指紋が正確に一致したときのみ許可。別の対象は決して再利用しません。学習の終止やサンプル削除ができます。',\n 'card.sedimentEmpty': '沈殿ルールはまだありません(しきい値に達したサンプルがここに表示されます)',\n 'card.sedimentCount': '確認済み %n/%t',\n 'card.sedimentStop': '終止',\n 'card.sedimentStopTitle': 'この学習を終止する(カウントとサンプルを削除)',\n 'card.sedimentStopConfirm': '「%k」の学習を終止しますか?カウントと全サンプルを削除します。',\n 'card.sedimentSampleRemove': 'この沈殿サンプルを削除',\n 'card.llmSource': '受信 LLM のソース',\n 'card.llmSourceCustom': 'カスタム API(OpenAI 互換)',\n 'card.llmSourceHost': 'セッションの現在の既定モデルを使用(DSH llm サービス)',\n 'card.llmSourceHostHint': '既定では DSH セッションで現在选择中のモデルグループで審査判定を実行します(下に現在の実効値を表示)。Provider / Model を空のままにするとセッションに追従し、ドロップダウンから選ぶか手入力で固定できます——DSH で設定したカスタムグループ(例:local-35b)は自動的にリストに現れます。',\n 'card.llmProvider': 'Provider(空 = セッションの現在の選択に追従)',\n 'card.llmProviderPlaceholder': 'セッションの現在の選択に追従',\n 'card.llmModelHostPlaceholder': '空 = セッションの現在の選択に追従',\n 'card.llmResolved': '現在の実効値:%p / %m',\n 'card.llmPreset': 'プリセットエンドポイント(選択で自動入力、後から編集可)',\n 'card.llmPresetChoose': 'プリセットを選択…',\n 'card.llmPresetPublic': '公開 API プリセット',\n 'card.llmPresetHost': 'DSH モデルグループ(選択するとセッション受信へ切替)',\n 'card.networkEnabled': 'ネットワーク傍受(networkEnabled)',\n 'card.networkEnabledHint': 'オンにするとローカルプロキシが起動し、サブプロセスの送信接続を傍受して許可/拒否ルールを適用します。オフにすると動作変更なし。',\n 'card.watch': 'ルールホットリロード(watch)',\n 'card.watchHint': 'オンにするとルールファイルの変更を自動監視し、手動リロードなしで即座に反映されます。',\n 'card.networkRebindNote': '切り替えは即時反映されます(自動で再バインド、プラグイン再読み込み不要)。',\n 'card.networkInjectEnv': 'プロキシ環境変数の注入(networkInjectEnv)',\n 'card.networkInjectEnvHint': 'サブプロセスに HTTP(S)_PROXY / ALL_PROXY を書き込みます(NO_PROXY はクリア)。オフの場合はリスナーのみ起動し、プロセス環境は変更しません。',\n 'card.healthStale': 'ホストルートが利用できません(404)——node 側が旧ビルドです。ページ再読み込みだけでなく dsh を完全に再起動してから再試行してください。',\n 'card.healthTest': '健全性テスト',\n 'card.healthRunning': 'テスト中…',\n 'card.healthOk': '正常(%ms ms)',\n 'card.healthFail': '失敗:',\n 'history.tag.learned': '学習済み',\n 'history.tag.manualApproved': '人手承認',\n 'history.tag.manualRejected': '人手拒否',\n 'history.tag.manualCancelled': '人手キャンセル',\n 'history.tag.standDown': 'ゲート停止',\n 'history.learnedProgress': '学習 %n/%t',\n 'history.snapshots': 'diff スナップショット',\n 'history.clearSession': 'このセッションのみ削除',\n 'history.clearAll': 'すべて削除',\n 'history.clearSessionTitle': 'このセッションの diff スナップショットのみ削除(他のセッションは対象外)',\n 'history.clearAllTitle': '全セッション(未確認のものも含む)の diff スナップショットを削除。再確認あり',\n 'history.clearSessionConfirm': 'このセッションの diff スナップショットを削除しますか?本セッションの承認で生成された変更比較データのみを削除し、承認記録自体には影響しません。',\n 'history.clearAllConfirm': '【全セッション】の diff スナップショットを削除しますか?他のセッションがまだ確認していない変更比較も削除され、復元できません。',\n 'history.diffTitle': 'ファイル変更の比較',\n 'history.diffClose': '閉じる',\n 'history.diffLoading': '読み込み中…',\n 'history.diffEmpty': '内容の変更なし(またはファイルを読み取れません)',\n 'history.diffLoadFail': 'diff の読み込みに失敗:',\n 'history.diffRevert': 'この変更を元に戻す',\n 'history.diffReverting': '送信中…',\n 'history.diffRevertDone': '取り消し指示を送信しました',\n 'history.diffRevertSent': '取り消し指示を会話に送信しました。AI が指示に従ってファイルを復元します',\n 'history.diffRevertFail': '送信に失敗:',\n 'history.diffNoSnapshot': 'このイベントには該当ファイルのスナップショットがありません',\n 'history.diffChipTitle': 'このファイルの変更比較を表示',\n 'history.diffStats': '+%a / -%r 行変更 · %c 行は未変更',\n 'history.diffGone': '(ファイルは現在存在しません)',\n 'history.diffHidden': '%n 行は未変更',\n 'card.dryRun': 'ルールテスト',\n 'card.dryRunHint': '現在有効なルールで 1 回の呼び出しを判定します。ツールは実行せず、ルールも書き換えません。ルールを変更する前にここで確認してください。',\n 'card.dryRunTool': 'ツール名',\n 'card.dryRunCommand': 'コマンド / 引数',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'テスト',\n 'card.dryRunRunning': '判定中…',\n 'card.dryRunEmpty': 'まだテストしていません。ツール名とコマンドを入力し「テスト」を押すと、どう判定されるか確認できます。',\n 'card.dryRunVerdict': '判定',\n 'card.dryRunAllow': '許可',\n 'card.dryRunAsk': '要確認',\n 'card.dryRunDeny': '拒否',\n 'card.dryRunRule': '一致したルール',\n 'card.dryRunRuleNone': '一致するルールなし。defaultAction:%d',\n 'card.dryRunDimensions': '制約次元',\n 'card.dryRunReason': '理由',\n 'card.dryRunNote': '「一致したルール」はルール層の結果です。判定がより前段のハード拒否やキーワードブラックリストによる場合、ルール番号はありません——その場合の次元表示は参考情報です。',\n 'card.dryRunNoRules': '(読み込まれたルールは 0 件:rulesFile のパスを確認してください)',\n 'card.dryRunFail': 'テスト失敗:',\n 'card.dryRunStale': 'ルートが存在しません(プラグイン未再起動?)',\n 'card.rules': 'Settings 組み込みルール',\n 'card.rulesHint': 'ゲートが今読み込んでいるルール(本プラグインエントリの rules 設定フィールドから。未設定時はルールファイルにフォールバック)。読み取り専用 — 変更するには下の許可リストか設定ページを使ってください。',\n 'card.rulesRefresh': '再読み込み',\n 'card.rulesLoading': '読み込み中…',\n 'card.rulesPath': 'ソース',\n 'card.rulesNone': 'ルールが設定されていません',\n 'card.rulesCounts': 'ルール',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b バイト · %l 行',\n 'card.rulesMissing': 'ルールが存在しません。ゲートは組み込みの既定値にフォールバックします。',\n 'card.rulesTruncated': 'ルールが大きいため、先頭 512 KB のみ表示します。',\n 'card.rulesError': '読み込みに失敗しました:',\n 'card.rulesStale': 'ルートが存在しません(プラグイン未再起動?)',\n 'card.rulesNote': '読み取り専用:このパネルからルールは変更できません。許可リストと「常に許可」は本プラグインのエントリ設定に書き戻されます。',\n}\n\n/** Korean dictionary (keys mirror zh). */\nexport const ko: Record<keyof typeof zh, string> = {\n 'card.title': '自动审查(자동 검토) 티어',\n 'section.title': '자동 검토 게이트',\n 'card.description': 'read-only / full-access / whitelist와 나란한 독립 승인 모드. 세션 권한 선택기에서는 「自动审查」로 표시됩니다. 프론트는 단일 스위치만 노출. 백엔드의 네 가지 승인 전략은 이 패널에서 조합 가능하며 P0 하드 거부에 대해 여전히 fail-closed.',\n 'card.permissive': '自动审查 티어 활성화',\n 'card.permissiveHint': '꺼져 있으면 이전과 완전히 동일하게 동작합니다.',\n 'card.scopeNote': '프리셋 범위: 이 게이트는 세션 권한 프리셋이 %scope일 때만 동작합니다. 다른 프리셋에서는 P0 하드 거부를 포함한 게이트 전체가 정지하고, 선택된 프리셋 자체의 정책이 대신합니다. 정지 시 stand-down 이벤트가 1건 기록되고 입력창 위에 상시 표시됩니다.',\n 'card.strategies': '백엔드 승인 전략(하나 이상 유효, 조합 가능)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — 범위 내 안전 작업은 자동 허용, 위험/미확인은 ask(중간 티어 기준)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — 모든 경계를 ask. 승인 패널의「허용 컨트롤」에 두 개의 확장 버튼:「이 세션에서 해당 유형 반복 허용」(세션 제한 grant) 과「모든 발생 허용」(명령어를 rulesFile 허용 목록에 영구 추가)',\n 'card.strategy.llmAssist': 'llmAssist — 사용자 지정 LLM이 위험을 판정: safe는 자동 허용, deletion/credential/remote/system/bulk 하드 위험은 사람 확인 유지(분류기는 결코 거부하지 않고 판단을 에스컬레이션만 합니다), neutral은 확인 학습으로, 실패/시간 초과는 사람에게 폴백',\n 'card.strategy.trustEscalation': 'trustEscalation — 샌드박스 승격 무확인: 이 게이트가 이미 허용한 호출에 대해 shell / pwsh / edit 이 도구 내부에서 요청하는 샌드박스 확장을 게이트가 승인하고 프롬프트를 띄우지 않습니다',\n 'card.strategy.trustEscalationHint': '샌드박스 승격 승인 요청은 tools/pre-execute 이후 도구 본체 내부에서 발생하므로 게이트가 보지 못했고, LLM이 safe로 판정해 자동 허용한 호출에도 확장 승인을 물었습니다. 켜면 게이트가 실제로 허용한 동일 호출(callId 정확 일치)만 프롬프트를 건너뛰고, 나머지는 이전과 같이 사람에게 전달됩니다. 이유를 인식할 수 없거나 대상이 workspace-write / danger-full-access 가 아닌 경우도 마찬가지입니다. 끄면 확장은 항상 사람이 판단합니다.',\n 'card.readonly': '읽기 전용',\n 'card.unavailable': '설정 네임스페이스를 사용할 수 없습니다: dsh-perm-gate가 이 profile에 조립되었는지 확인하세요.',\n 'card.llmReceiver': 'llmAssist 수신 LLM (OpenAI 호환, 사용자 지정 API 가능)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, 예: https://api.openai.com/v1)',\n 'card.llmModel': 'Model (모델 id, 예: deepseek-chat)',\n 'card.llmKey': 'API Key (비밀)',\n 'card.llmKeyHidden': '미설정 · 최초 입력 후 * 표시',\n 'card.llmKeyMasked': '설정됨 · 새 값을 입력하면 덮어씀',\n 'card.llmKeyOverwrite': '비밀 값이 저장되어 있습니다. 새 값을 입력하고 포커스를 벗어나면 덮어씁니다.',\n 'card.llmKeyClear': '지우기',\n 'card.allowlist': '허용 목록(allow, rulesFile과 동기화)',\n 'card.allowlistHint': 'allow 섹션과 일치하는 패턴은 바로 허용됩니다. 항목을 하나씩 추가·삭제하면 rulesFile에 즉시 기록 후 다시 적재됩니다.',\n 'card.allowlistPresetNote': '프리셋 허용 목록의 등가물은 trustAutoAllow 전략(범위 내 안전 작업 자동 허용)으로, 위 전략 섹션에서 활성화합니다. 이 목록은 rulesFile의 allow를 반영하므로 초기에 비어 있는 것이 정상입니다.',\n 'card.allowlistEmpty': '허용 규칙이 없습니다',\n 'card.allowlistPlaceholder': '새 명령 패턴, 예: npm test*',\n 'card.allowlistAdd': '추가',\n 'card.allowlistRemove': '이 패턴 삭제',\n 'card.allowlistBulk': '일괄 편집',\n 'card.allowlistBulkHide': '일괄 편집 접기',\n 'card.allowlistSave': '허용 목록 저장',\n 'card.riskLearning': 'riskLearning — 판정 학습: neutral 위험 요청이 사람의 승인과 실행까지 완료되면 카운트되며, 임계값 도달 후 동일 작업(지문 일치)만 자동 허용',\n 'card.riskLearningHint': '학습 상태는 플러그인 소유($DSH_HOME/perm-gate/learning.json)이며 YAML 규칙에는 기록하지 않습니다. 다른 대상은 권한을 재사용하지 않습니다. 기본값은 꺼짐.',\n 'card.riskThreshold': '자동 허용 전 필요한 사람 확인 횟수(1–10)',\n 'notice.label': '권한 게이트 활동',\n 'history.label': '승인 기록',\n 'history.title': '권한 승인 기록',\n 'history.subtitle': '이 세션에서 게이트가 판정한 모든 기록(최신 순)',\n 'history.loading': '불러오는 중…',\n 'history.empty': '이 세션에는 아직 승인 기록이 없습니다',\n 'history.error': '불러오기 실패: ',\n 'history.tag.auto': '자동 허용',\n 'history.tag.ask': '사람에게',\n 'history.tag.deny': '거부',\n 'card.denylistRestore': '프리셋 블랙리스트로 복원',\n 'card.denylist': '블랙리스트(deny 키워드, 플러그인 프리셋)',\n 'card.denylistHint': '키워드(대소문자 구분 없는 부분 일치)를 포함한 호출은 허용 목록/권한/LLM보다 먼저 거부됩니다. 프리셋은 dsh-approval-gate에서 계승되어 설치 즉시 활성화되며, 비어 있거나 미설정이면 프리셋이 적용됩니다(원클릭 복원 지원). 블랙리스트가 조용히 꺼지는 일은 없습니다.',\n 'card.denylistEmpty': '블랙리스트가 비어 있음(키워드 계층에서 거부되는 호출 없음)',\n 'card.denylistPlaceholder': '새 키워드, 예: drop database',\n 'card.denylistAdd': '추가',\n 'card.denylistRemove': '이 키워드 삭제',\n 'card.denylistTagPreset': '프리셋',\n 'card.denylistTagCustom': '사용자 지정',\n 'card.riskSediment': 'riskSediment — 학습 침전: 임계값에 도달한 샘플이 결정론적 자동 허용 규칙으로',\n 'card.riskSedimentHint': '켜면 tool|category 키의 확인이 임계값에 도달한 시점에 샘플 지문이 허용 규칙으로 침전됩니다. 동일 도구·동일 대상의 정확 일치는 LLM 없이 바로 허용(llmAssist가 꺼져도 유지).',\n 'card.sediment': '학습 침전(결정론적 허용 규칙)',\n 'card.sedimentHint': '사람의 확인에서 침전된 규칙: 지문이 정확히 일치할 때만 허용되며 다른 대상은 절대 재사용하지 않습니다. 학습 종료 또는 샘플 삭제가 가능합니다.',\n 'card.sedimentEmpty': '아직 침전 규칙이 없습니다(임계값에 도달한 샘플이 여기에 표시됩니다)',\n 'card.sedimentCount': '확인 %n/%t',\n 'card.sedimentStop': '종료',\n 'card.sedimentStopTitle': '이 학습 종료(카운트와 샘플 삭제)',\n 'card.sedimentStopConfirm': \"'%k' 학습을 종료합니까? 카운트와 모든 샘플이 삭제됩니다.\",\n 'card.sedimentSampleRemove': '이 침전 샘플 삭제',\n 'card.llmSource': '수신 LLM 소스',\n 'card.llmSourceCustom': '사용자 지정 API(OpenAI 호환)',\n 'card.llmSourceHost': '세션의 현재 기본 모델 사용(DSH llm 서비스)',\n 'card.llmSourceHostHint': '기본적으로 DSH 세션에서 현재 선택한 모델 그룹으로 승인 판정을 수행합니다(아래에 실제 적용값 표시). Provider / Model을 비우면 세션 선택을 따르며, 드롭다운에서 선택하거나 직접 입력해 고정할 수 있습니다——DSH에 설정한 사용자 지정 그룹(예: local-35b)은 목록에 자동으로 나타납니다.',\n 'card.llmProvider': 'Provider(비움 = 세션 현재 선택 따름)',\n 'card.llmProviderPlaceholder': '세션 현재 선택 따름',\n 'card.llmModelHostPlaceholder': '비움 = 세션 현재 선택 따름',\n 'card.llmResolved': '현재 적용: %p / %m',\n 'card.llmPreset': '프리셋 엔드포인트(선택 시 자동 채움, 이후 편집 가능)',\n 'card.llmPresetChoose': '프리셋 선택…',\n 'card.llmPresetPublic': '공개 API 프리셋',\n 'card.llmPresetHost': 'DSH 모델 그룹(선택 시 세션 수신으로 전환)',\n 'card.networkEnabled': '네트워크 가로채기 (networkEnabled)',\n 'card.networkEnabledHint': '켜면 로컬 프록시가 시작되어 서브프로세스의 아웃바운드 연결을 가로채고 허용/거부 규칙을 적용합니다. 끄면 동작 변경 없음.',\n 'card.watch': '규칙 핫 리로드 (watch)',\n 'card.watchHint': '켜면 규칙 파일 변경을 자동 감시하여 수동 리로드 없이 즉시 적용됩니다.',\n 'card.networkRebindNote': '전환 즉시 적용됩니다(자동 재바인딩, 플러그인 리로드 불필요).',\n 'card.networkInjectEnv': '프록시 환경 변수 주입 (networkInjectEnv)',\n 'card.networkInjectEnvHint': '서브프로세스에 HTTP(S)_PROXY / ALL_PROXY를 기록합니다(NO_PROXY는 비움). 끄면 리스너만 실행되고 프로세스 환경은 변경되지 않습니다.',\n 'card.healthStale': '호스트 라우트를 사용할 수 없음(404)——node 측이 이전 빌드입니다. 페이지 새로고침이 아니라 dsh를 완전히 재시작한 후 다시 시도하세요.',\n 'card.healthTest': '상태 테스트',\n 'card.healthRunning': '테스트 중…',\n 'card.healthOk': '정상(%ms ms)',\n 'card.healthFail': '실패: ',\n 'history.tag.learned': '학습됨',\n 'history.tag.manualApproved': '사람 승인',\n 'history.tag.manualRejected': '사람 거부',\n 'history.tag.manualCancelled': '사람 취소',\n 'history.tag.standDown': '게이트 정지',\n 'history.learnedProgress': '학습 %n/%t',\n 'history.snapshots': 'diff 스냅샷',\n 'history.clearSession': '이 세션만 삭제',\n 'history.clearAll': '전체 삭제',\n 'history.clearSessionTitle': '이 세션의 diff 스냅샷만 삭제(다른 세션은 그대로)',\n 'history.clearAllTitle': '모든 세션(아직 확인하지 않은 것 포함)의 diff 스냅샷을 삭제. 재확인 필요',\n 'history.clearSessionConfirm': '이 세션의 diff 스냅샷을 삭제합니까? 이 세션의 승인으로 생성된 변경 비교 데이터만 삭제하며 승인 기록 자체는 유지됩니다.',\n 'history.clearAllConfirm': '【모든 세션】의 diff 스냅샷을 삭제합니까? 다른 세션이 아직 확인하지 않은 변경 비교도 삭제되며 복구할 수 없습니다.',\n 'history.diffTitle': '파일 변경 비교',\n 'history.diffClose': '닫기',\n 'history.diffLoading': '불러오는 중…',\n 'history.diffEmpty': '내용 변경 없음(또는 파일을 읽을 수 없음)',\n 'history.diffLoadFail': 'diff 불러오기 실패: ',\n 'history.diffRevert': '이 변경 되돌리기',\n 'history.diffReverting': '전송 중…',\n 'history.diffRevertDone': '되돌리기 지시를 보냈습니다',\n 'history.diffRevertSent': '되돌리기 지시를 대화로 보냈습니다. AI가 지시에 따라 파일을 복원합니다',\n 'history.diffRevertFail': '전송 실패: ',\n 'history.diffNoSnapshot': '이 이벤트에는 해당 파일의 스냅샷이 없습니다',\n 'history.diffChipTitle': '이 파일의 변경 비교 보기',\n 'history.diffStats': '+%a / -%r 행 변경 · %c 행 미변경',\n 'history.diffGone': ' (파일이 더 이상 존재하지 않음)',\n 'history.diffHidden': '%n 행 미변경',\n 'card.dryRun': '규칙 테스트',\n 'card.dryRunHint': '현재 적용 중인 규칙으로 호출 한 건을 판정합니다. 도구를 실행하지 않고 규칙도 쓰지 않습니다. 규칙을 바꾸기 전에 여기서 먼저 확인하세요.',\n 'card.dryRunTool': '도구 이름',\n 'card.dryRunCommand': '명령 / 인수',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': '테스트',\n 'card.dryRunRunning': '판정 중…',\n 'card.dryRunEmpty': '아직 테스트하지 않았습니다. 도구 이름과 명령을 입력하고 「테스트」를 누르면 어떻게 판정되는지 볼 수 있습니다.',\n 'card.dryRunVerdict': '판정',\n 'card.dryRunAllow': '허용',\n 'card.dryRunAsk': '확인 필요',\n 'card.dryRunDeny': '거부',\n 'card.dryRunRule': '일치한 규칙',\n 'card.dryRunRuleNone': '일치하는 규칙 없음, defaultAction: %d',\n 'card.dryRunDimensions': '제약 차원',\n 'card.dryRunReason': '이유',\n 'card.dryRunNote': '「일치한 규칙」은 규칙 계층의 결과입니다. 판정이 더 앞선 하드 거부나 키워드 블랙리스트에서 나온 경우 규칙 번호가 없습니다——그때의 차원 표시는 참고용입니다.',\n 'card.dryRunNoRules': '(로드된 규칙 0건: rulesFile 경로를 확인하세요)',\n 'card.dryRunFail': '테스트 실패: ',\n 'card.dryRunStale': '라우트가 없습니다(플러그인 미재시작?)',\n 'card.rules': 'Settings 내장 규칙',\n 'card.rulesHint': '게이트가 지금 불러오는 규칙(이 플러그인 엔트리의 rules 설정 필드에서. 미설정 시 규칙 파일로 폴백). 읽기 전용 — 아래 허용 목록이나 설정 페이지에서 수정하세요.',\n 'card.rulesRefresh': '새로 고침',\n 'card.rulesLoading': '읽는 중…',\n 'card.rulesPath': '소스',\n 'card.rulesNone': '규칙이 설정되지 않았습니다',\n 'card.rulesCounts': '규칙',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b 바이트 · %l 줄',\n 'card.rulesMissing': '규칙이 없습니다. 게이트는 내장 기본값으로 대체합니다.',\n 'card.rulesTruncated': '규칙이 커서 앞 512 KB만 표시합니다.',\n 'card.rulesError': '불러오기 실패: ',\n 'card.rulesStale': '라우트가 없습니다(플러그인 미재시작?)',\n 'card.rulesNote': '읽기 전용: 이 패널은 규칙을 수정할 수 없습니다. 허용 목록과 \"항상 허용\"은 이 플러그인의 엔트리 설정에 기록됩니다.',\n}\n/** French dictionary (keys mirror zh). */\nexport const fr: Record<PermissiveKey, string> = {\n 'card.title': 'Examen automatique',\n 'section.title': 'Porte d\\'examen automatique',\n 'card.description': 'Niveau d\\'approbation indépendant : parallèle à lecture seule / accès complet / liste blanche, affiché comme « Examen automatique » dans le sélecteur de permissions de session. Le front-end n\\'expose qu\\'un seul interrupteur ; les quatre stratégies d\\'approbation backend sont combinables via ce panneau et restent fail-closed contre le refus dur P0.',\n 'card.permissive': 'Activer le niveau d\\'examen automatique',\n 'card.permissiveHint': 'Lorsqu\\'il est désactivé, la porte se comporte exactement comme avant.',\n 'card.scopeNote': 'Portée du préréglage : cette porte n\\'agit que lorsque le préréglage de permission de session est %scope. Sous tout autre préréglage, la porte entière se met en veille — y compris le refus dur P0 — et la politique du préréglage sélectionné prend le relais. La mise en veille enregistre un événement et affiche une bande persistante au-dessus de la saisie.',\n 'card.strategies': 'Stratégies d\\'approbation backend (au moins une active ; combinables)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — les opérations sûres dans le périmètre sont auto-autorisées ; dangereuses/inconnues → demande (niveau intermédiaire de base)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — chaque passage demande ; les « contrôles d\\'autorisation » du panneau d\\'approbation ajoutent deux boutons étendus : « répéter l\\'autorisation pour ce type cette session » (grant borné de session) et « autoriser toutes les occurrences » (persistance du mot de commande dans la liste blanche rulesFile)',\n 'card.strategy.llmAssist': 'llmAssist — un LLM personnalisé évalue le risque : safe → auto-autorisation ; deletion/credential/remote/system/bulk → risques durs maintiennent la demande humaine (le classifieur ne refuse jamais — il ne fait qu\\'escalader) ; neutral → apprentissage par confirmation ; échec/timeout → retour à l\\'humain',\n 'card.strategy.trustEscalation': 'trustEscalation — escalade sandbox sans invite : pour un appel déjà autorisé par cette porte, l\\'élargissement sandbox initié par shell / pwsh / edit depuis l\\'intérieur de l\\'outil est approuvé ici au lieu de vous le demander',\n 'card.strategy.trustEscalationHint': 'L\\'approbation d\\'escalade sandbox est demandée depuis l\\'intérieur du corps de l\\'outil, après tools/pre-execute, donc la porte ne la voit jamais — un appel que le LLM a jugé sûr et que la porte a auto-autorisé vous demandait quand même d\\'approuver l\\'élargissement. Activé, seul l\\'appel exact que la porte a autorisé (correspondance par callId) ignore l\\'invite ; tout le reste passe à l\\'humain comme avant, ainsi que toute raison non reconnue ou cible autre que workspace-write / danger-full-access. Désactivez pour garder l\\'élargissement sous contrôle humain.',\n 'card.readonly': 'Lecture seule',\n 'card.unavailable': 'Espace de noms des paramètres indisponible : assurez-vous que dsh-perm-gate est assemblé dans ce profil.',\n 'card.llmReceiver': 'LLM récepteur llmAssist (compatible OpenAI ; API personnalisée possible)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, ex. https://api.openai.com/v1)',\n 'card.llmModel': 'Model (identifiant du modèle, ex. deepseek-chat)',\n 'card.llmKey': 'API Key (secret)',\n 'card.llmKeyHidden': 'Non défini · affiché comme * après la première saisie',\n 'card.llmKeyMasked': 'Défini · saisir une nouvelle valeur pour écraser',\n 'card.llmKeyOverwrite': 'Une valeur secrète est stockée ; saisissez une nouvelle valeur et quittez le champ pour l\\'écraser.',\n 'card.llmKeyClear': 'Effacer',\n 'card.allowlist': 'Liste blanche (allow, synchronisée avec rulesFile)',\n 'card.allowlistHint': 'Les motifs correspondant à la section allow sont directement autorisés ; ajoutez ou supprimez des entrées une par une, écrites dans rulesFile et rechargées en direct.',\n 'card.allowlistPresetNote': 'L\\'équivalent de la liste blanche prédéfinie est la stratégie trustAutoAllow (opérations sûres dans le périmètre auto-autorisées), activée dans la section stratégies ci-dessus ; cette liste reflète votre section allow de rulesFile et démarre légitimement vide.',\n 'card.allowlistEmpty': 'Aucune règle de liste blanche',\n 'card.allowlistPlaceholder': 'Nouveau motif de commande, ex. npm test*',\n 'card.allowlistAdd': 'Ajouter',\n 'card.allowlistRemove': 'Supprimer ce motif',\n 'card.allowlistBulk': 'Édition groupée',\n 'card.allowlistBulkHide': 'Masquer l\\'édition groupée',\n 'card.allowlistSave': 'Enregistrer la liste blanche',\n 'card.riskLearning': 'riskLearning — apprentissage de verdict : les opérations à risque neutral approuvées et exécutées sont comptées ; la même opération est auto-autorisée au seuil avec une empreinte correspondante',\n 'card.riskLearningHint': 'L\\'état d\\'apprentissage appartient au plugin ($DSH_HOME/perm-gate/learning.json) et n\\'est jamais écrit dans vos règles YAML ; une cible différente ne réutilise jamais l\\'autorité. Désactivé par défaut.',\n 'card.riskThreshold': 'Confirmations humaines requises avant auto-autorisation (1–10)',\n 'notice.label': 'Activité de la porte de permission',\n 'history.label': 'Approbations',\n 'history.title': 'Historique des approbations de permission',\n 'history.subtitle': 'Chaque décision de la porte dans cette session, les plus récentes d\\'abord',\n 'history.loading': 'Chargement…',\n 'history.empty': 'Aucun enregistrement d\\'approbation dans cette session',\n 'history.error': 'Échec du chargement : ',\n 'history.tag.auto': 'Auto-autorisé',\n 'history.tag.ask': 'Demandé',\n 'history.tag.deny': 'Refusé',\n 'card.denylistRestore': 'Restaurer la liste noire prédéfinie',\n 'card.denylist': 'Liste noire (mots-clés deny, prédéfinis par le plugin)',\n 'card.denylistHint': 'Un appel dont le texte contient un mot-clé (sous-chaîne insensible à la casse) est refusé immédiatement, avant liste blanche / grants / LLM. La liste prédéfinie hérite de dsh-approval-gate et est active dès l\\'installation ; modifiez librement — vide ou effacée, retour au préréglage (restauration en un clic), donc la liste noire ne se désactive jamais silencieusement.',\n 'card.denylistEmpty': 'Liste noire vide (aucun appel n\\'est rejeté par la couche de mots-clés)',\n 'card.denylistPlaceholder': 'Nouveau mot-clé, ex. drop database',\n 'card.denylistAdd': 'Ajouter',\n 'card.denylistRemove': 'Supprimer ce mot-clé',\n 'card.denylistTagPreset': 'Prédéfini',\n 'card.denylistTagCustom': 'Personnalisé',\n 'card.riskSediment': 'riskSediment — sédimentation d\\'apprentissage : les échantillons ayant atteint le seuil deviennent des règles d\\'auto-autorisation déterministes',\n 'card.riskSedimentHint': 'Activé, lorsqu\\'une clé tool|category atteint le seuil, ses empreintes d\\'échantillons se sédimentent en règles d\\'autorisation — une correspondance exacte même outil/même cible autorise directement sans autre appel LLM (continue de fonctionner avec llmAssist désactivé).',\n 'card.sediment': 'Sédiment d\\'apprentissage (règles d\\'autorisation déterministes)',\n 'card.sedimentHint': 'Règles sédimentées à partir des confirmations humaines : seule une correspondance exacte d\\'empreinte autorise, jamais une cible différente. Terminez un apprentissage ou supprimez un échantillon.',\n 'card.sedimentEmpty': 'Aucune règle sédimentée pour l\\'instant (les échantillons atteignant le seuil apparaissent ici)',\n 'card.sedimentCount': 'confirmé %n/%t',\n 'card.sedimentStop': 'Terminer',\n 'card.sedimentStopTitle': 'Terminer cet apprentissage (supprime le compteur et les échantillons)',\n 'card.sedimentStopConfirm': 'Terminer l\\'apprentissage pour « %k » ? Son compteur et tous ses échantillons seront supprimés.',\n 'card.sedimentSampleRemove': 'Supprimer cet échantillon sédimenté',\n 'card.llmSource': 'Source du LLM récepteur',\n 'card.llmSourceCustom': 'API personnalisée (compatible OpenAI)',\n 'card.llmSourceHost': 'Utiliser le modèle par défaut actuel de la session (service DSH llm)',\n 'card.llmSourceHostHint': 'Par défaut, l\\'évaluation d\\'approbation utilise le groupe de modèles actuellement sélectionné dans la session DSH (la valeur effective est affichée ci-dessous) ; laissez Provider / Model vide pour suivre la session, ou choisissez dans la liste déroulante ou saisissez pour épingler — vos groupes personnalisés configurés dans DSH (ex. local-35b) apparaissent automatiquement.',\n 'card.llmProvider': 'Provider (vide = suit la sélection de session)',\n 'card.llmProviderPlaceholder': 'Suit la sélection de session',\n 'card.llmModelHostPlaceholder': 'Vide = suit la sélection de session',\n 'card.llmResolved': 'Effectif actuellement : %p / %m',\n 'card.llmPreset': 'Préréglages d\\'endpoint (remplit les champs ; modifiable ensuite)',\n 'card.llmPresetChoose': 'Choisir un préréglage…',\n 'card.llmPresetPublic': 'Préréglages d\\'API publiques',\n 'card.llmPresetHost': 'Groupes de modèles DSH (la sélection bascule vers le récepteur de session)',\n 'card.networkEnabled': 'Interception réseau (networkEnabled)',\n 'card.networkEnabledHint': 'Activé, démarre un proxy local qui intercepte les connexions sortantes des sous-processus et applique les règles d\\'autorisation/refus. Désactivé = aucun changement de comportement.',\n 'card.watch': 'Rechargement à chaud des règles (watch)',\n 'card.watchHint': 'Activé, surveille automatiquement les modifications des fichiers de règles et les applique instantanément sans rechargement manuel.',\n 'card.networkRebindNote': 'Prend effet immédiatement — le proxy se relie automatiquement, pas besoin de recharger le plugin.',\n 'card.networkInjectEnv': 'Injecter les variables d\\'environnement proxy (networkInjectEnv)',\n 'card.networkInjectEnvHint': 'Écrit HTTP(S)_PROXY / ALL_PROXY pour les sous-processus (et vide NO_PROXY). Désactivé = l\\'écouteur fonctionne mais aucun environnement de processus n\\'est modifié.',\n 'card.healthStale': 'Route hôte indisponible (404) — la moitié node est encore une ancienne version ; redémarrez complètement dsh (pas seulement la page du navigateur) et réessayez.',\n 'card.healthTest': 'Test de santé',\n 'card.healthRunning': 'Test en cours…',\n 'card.healthOk': 'OK (%ms ms)',\n 'card.healthFail': 'Échec : ',\n 'history.tag.learned': 'Appris',\n 'history.tag.manualApproved': 'Approuvé',\n 'history.tag.manualRejected': 'Rejeté',\n 'history.tag.manualCancelled': 'Annulé',\n 'history.tag.standDown': 'Porte inactive',\n 'history.learnedProgress': 'appris %n/%t',\n 'history.snapshots': 'instantanés diff',\n 'history.clearSession': 'Effacer cette session',\n 'history.clearAll': 'Tout effacer',\n 'history.clearSessionTitle': 'Effacer uniquement les instantanés diff de cette session (les autres sessions ne sont pas affectées)',\n 'history.clearAllTitle': 'Effacer les instantanés diff de toutes les sessions, y compris celles jamais consultées — demande une reconfirmation',\n 'history.clearSessionConfirm': 'Effacer les instantanés diff de cette session ? Seules les données de comparaison produites par les approbations de cette session sont supprimées ; les enregistrements d\\'approbation restent.',\n 'history.clearAllConfirm': 'Effacer les instantanés diff de TOUTES les sessions ? Cela peut supprimer des comparaisons que d\\'autres sessions n\\'ont pas encore consultées, et c\\'est irréversible.',\n 'history.diffTitle': 'Comparaison des modifications de fichier',\n 'history.diffClose': 'Fermer',\n 'history.diffLoading': 'Chargement…',\n 'history.diffEmpty': 'Aucun changement de contenu (ou fichier illisible)',\n 'history.diffLoadFail': 'Échec du chargement du diff : ',\n 'history.diffRevert': 'Annuler cette modification',\n 'history.diffReverting': 'Envoi…',\n 'history.diffRevertDone': 'Instruction d\\'annulation envoyée',\n 'history.diffRevertSent': 'Instruction d\\'annulation envoyée à la conversation ; l\\'IA restaurera le fichier en conséquence',\n 'history.diffRevertFail': 'Échec de l\\'envoi : ',\n 'history.diffNoSnapshot': 'Cet événement n\\'a pas d\\'instantané pour ce fichier',\n 'history.diffChipTitle': 'Voir la comparaison des modifications de ce fichier',\n 'history.diffStats': '+%a / -%r lignes modifiées · %c inchangées',\n 'history.diffGone': ' (le fichier n\\'existe plus)',\n 'history.diffHidden': '%n lignes non modifiées',\n 'card.dryRun': 'Test de règles',\n 'card.dryRunHint': 'Juge un appel contre les règles en vigueur. N\\'exécute aucun outil et n\\'écrit aucune règle — vérifiez ici avant de modifier.',\n 'card.dryRunTool': 'Outil',\n 'card.dryRunCommand': 'Commande / arguments',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'Tester',\n 'card.dryRunRunning': 'Évaluation…',\n 'card.dryRunEmpty': 'Rien de testé pour l\\'instant. Renseignez un outil et une commande, puis appuyez sur Tester pour voir le verdict.',\n 'card.dryRunVerdict': 'Verdict',\n 'card.dryRunAllow': 'autoriser',\n 'card.dryRunAsk': 'demander',\n 'card.dryRunDeny': 'refuser',\n 'card.dryRunRule': 'Règle correspondante',\n 'card.dryRunRuleNone': 'aucune règle correspondante ; defaultAction : %d',\n 'card.dryRunDimensions': 'Dimensions',\n 'card.dryRunReason': 'Raison',\n 'card.dryRunNote': '« Règle correspondante » provient de la couche de règles. Quand le verdict est produit par un refus dur antérieur ou par la liste noire de mots-clés, il n\\'y a pas d\\'index de règle — les dimensions listées sont alors informatives.',\n 'card.dryRunNoRules': '(0 règles chargées — vérifiez le chemin rulesFile)',\n 'card.dryRunFail': 'Échec du test : ',\n 'card.dryRunStale': 'route manquante (plugin non redémarré ?)',\n 'card.rules': 'Règles intégrées des paramètres',\n 'card.rulesHint': 'Les règles que la porte charge actuellement (depuis le champ de configuration rules de cette entrée de plugin ; retour au fichier de règles si non configuré). Lecture seule — rien ici ne peut les modifier. Pour changer les règles, utilisez la liste blanche ci-dessous ou modifiez-les dans la page des paramètres.',\n 'card.rulesRefresh': 'Actualiser',\n 'card.rulesLoading': 'Lecture…',\n 'card.rulesPath': 'Source',\n 'card.rulesNone': 'aucune règle configurée',\n 'card.rulesCounts': 'Règles',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b octets · %l lignes',\n 'card.rulesMissing': 'Règles introuvables. La porte retombe sur ses valeurs par défaut intégrées.',\n 'card.rulesTruncated': 'Règles volumineuses ; affichage des 512 Ko premiers uniquement.',\n 'card.rulesError': 'Échec du chargement : ',\n 'card.rulesStale': 'route manquante (plugin non redémarré ?)',\n 'card.rulesNote': 'Lecture seule : ce panneau ne peut pas modifier les règles. La section liste blanche et « toujours autoriser » écrivent dans la configuration d\\'entrée de ce plugin.',\n}\n\n/** German dictionary (keys mirror zh). */\nexport const de: Record<PermissiveKey, string> = {\n 'card.title': 'Automatische Überprüfung',\n 'section.title': 'Automatische Prüfschleuse',\n 'card.description': 'Unabhängige Genehmigungsstufe: parallel zu Nur-Lesen / Vollzugriff / Whitelist, angezeigt als „Automatische Überprüfung\" im Sitzungs-Berechtigungswähler. Das Frontend bietet einen einzigen Schalter; die vier Backend-Genehmigungsstrategien sind über dieses Panel kombinierbar und bleiben fail-closed gegen P0-Hartablehnung.',\n 'card.permissive': 'Stufe „Automatische Überprüfung\" aktivieren',\n 'card.permissiveHint': 'Wenn deaktiviert, verhält sich das Gate genau wie zuvor.',\n 'card.scopeNote': 'Voreinstellungsbereich: Dieses Gate wirkt nur, während die Sitzungsberechtigungsvoreinstellung %scope ist. Unter jeder anderen Voreinstellung tritt das gesamte Gate zurück — einschließlich P0-Hartablehnung — und die Richtlinie der gewählten Voreinstellung übernimmt. Der Rücktritt protokolliert ein Ereignis und zeigt einen dauerhaften Hinweis über der Eingabe.',\n 'card.strategies': 'Backend-Genehmigungsstrategien (mindestens eine aktiv; kombinierbar)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — sichere Operationen im Bereich werden automatisch erlaubt; gefährliche/unbekannte → Nachfrage (mittlere Baseline-Stufe)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — jeder Übergang fragt; die „Erlaubnis-Steuerelemente\" des Genehmigungspanels erhalten zwei erweiterte Buttons: „Diesen Typ in dieser Sitzung wiederholt erlauben\" (begrenztes Sitzungs-Grant) und „Alle Vorkommen erlauben\" (Befehlswort dauerhaft in die rulesFile-Whitelist aufnehmen)',\n 'card.strategy.llmAssist': 'llmAssist — ein benutzerdefiniertes LLM bewertet das Risiko: safe → automatische Erlaubnis; deletion/credential/remote/system/bulk → Hartrisiken behalten die menschliche Nachfrage (der Klassifizierer lehnt nie ab — er eskaliert nur); neutral → Bestätigungslernen; Fehler/Timeout → Rückfall auf den Menschen',\n 'card.strategy.trustEscalation': 'trustEscalation — Sandbox-Eskalation ohne Eingabeaufforderung: Für einen bereits von diesem Gate erlaubten Aufruf wird die Sandbox-Erweiterung, die shell / pwsh / edit intern anfordert, hier genehmigt statt Sie zu fragen',\n 'card.strategy.trustEscalationHint': 'Die Sandbox-Eskalationsgenehmigung wird nach tools/pre-execute im Tool-Körper angefordert, sodass das Gate sie nie sieht — ein vom LLM als sicher eingestufter und automatisch erlaubter Aufruf fragte Sie dennoch nach der Erweiterung. Aktiviert überspringt nur der exakte vom Gate erlaubte Aufruf (übereinstimmend per callId) die Eingabeaufforderung; alles andere geht wie zuvor zum Menschen, ebenso jeder unerkannte Grund oder ein anderes Ziel als workspace-write / danger-full-access. Deaktivieren, um die Erweiterung unter menschlicher Kontrolle zu halten.',\n 'card.readonly': 'Nur-Lesen',\n 'card.unavailable': 'Einstellungs-Namensraum nicht verfügbar: Stellen Sie sicher, dass dsh-perm-gate in diesem Profil zusammengebaut ist.',\n 'card.llmReceiver': 'llmAssist empfangendes LLM (OpenAI-kompatibel; jede benutzerdefinierte API)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, z. B. https://api.openai.com/v1)',\n 'card.llmModel': 'Model (Modell-ID, z. B. deepseek-chat)',\n 'card.llmKey': 'API Key (geheim)',\n 'card.llmKeyHidden': 'Nicht gesetzt · nach erster Eingabe als * angezeigt',\n 'card.llmKeyMasked': 'Gesetzt · neuen Wert eingeben zum Überschreiben',\n 'card.llmKeyOverwrite': 'Ein geheimer Wert ist gespeichert; geben Sie einen neuen Wert ein und verlassen Sie das Feld zum Überschreiben.',\n 'card.llmKeyClear': 'Löschen',\n 'card.allowlist': 'Whitelist (allow, mit rulesFile synchronisiert)',\n 'card.allowlistHint': 'Muster im allow-Abschnitt werden direkt erlaubt; Einträge einzeln hinzufügen oder entfernen, live in rulesFile geschrieben und neu geladen.',\n 'card.allowlistPresetNote': 'Das Äquivalent der Voreinstellungs-Whitelist ist die trustAutoAllow-Strategie (sichere Operationen im Bereich automatisch erlaubt), aktiviert im Strategiebereich oben; diese Liste spiegelt Ihren rulesFile-allow-Abschnitt und startet berechtigterweise leer.',\n 'card.allowlistEmpty': 'Keine Whitelist-Regeln',\n 'card.allowlistPlaceholder': 'Neues Befehlsmuster, z. B. npm test*',\n 'card.allowlistAdd': 'Hinzufügen',\n 'card.allowlistRemove': 'Dieses Muster entfernen',\n 'card.allowlistBulk': 'Massenbearbeitung',\n 'card.allowlistBulkHide': 'Massenbearbeitung ausblenden',\n 'card.allowlistSave': 'Whitelist speichern',\n 'card.riskLearning': 'riskLearning — Verdiktlernen: neutrale Risikoanfragen, die der Mensch genehmigt und die ausgeführt werden, zählen hoch; dieselbe Operation wird am Schwellenwert mit passendem Fingerabdruck automatisch erlaubt',\n 'card.riskLearningHint': 'Der Lernzustand gehört dem Plugin ($DSH_HOME/perm-gate/learning.json) und wird nie in Ihre YAML-Regeln geschrieben; ein anderes Ziel nutzt nie die Autorität wieder. Standardmäßig deaktiviert.',\n 'card.riskThreshold': 'Menschliche Bestätigungen vor automatischer Erlaubnis erforderlich (1–10)',\n 'notice.label': 'Berechtigungs-Gate-Aktivität',\n 'history.label': 'Genehmigungen',\n 'history.title': 'Berechtigungsgenehmigungsprotokolle',\n 'history.subtitle': 'Jede Gate-Entscheidung in dieser Sitzung, neueste zuerst',\n 'history.loading': 'Wird geladen…',\n 'history.empty': 'Noch keine Genehmigungsprotokolle in dieser Sitzung',\n 'history.error': 'Laden fehlgeschlagen: ',\n 'history.tag.auto': 'Automatisch erlaubt',\n 'history.tag.ask': 'Angefragt',\n 'history.tag.deny': 'Abgelehnt',\n 'card.denylistRestore': 'Standard-Blacklist wiederherstellen',\n 'card.denylist': 'Blacklist (deny-Schlüsselwörter, Plugin-Standard)',\n 'card.denylistHint': 'Ein Aufruf, dessen Text ein Schlüsselwort enthält (Groß-/Kleinschreibung-unempfindliche Teilzeichenkette), wird sofort abgelehnt, vor Whitelist / Grants / LLM. Die Standardliste erbt von dsh-approval-gate und ist ab Installation aktiv; frei bearbeitbar — leer oder geleert fällt auf den Standard zurück (Ein-Klick-Wiederherstellung verfügbar), sodass die Blacklist sich nie stillschweigend abschaltet.',\n 'card.denylistEmpty': 'Blacklist leer (kein Aufruf wird von der Schlüsselwortschicht abgelehnt)',\n 'card.denylistPlaceholder': 'Neues Schlüsselwort, z. B. drop database',\n 'card.denylistAdd': 'Hinzufügen',\n 'card.denylistRemove': 'Dieses Schlüsselwort entfernen',\n 'card.denylistTagPreset': 'Standard',\n 'card.denylistTagCustom': 'Benutzerdefiniert',\n 'card.riskSediment': 'riskSediment — Lernsedimentation: Proben am Schwellenwert werden zu deterministischen Auto-Erlaubnisregeln',\n 'card.riskSedimentHint': 'Wenn aktiv, werden bei Erreichen des Schwellenwerts für einen tool|category-Schlüssel dessen Proben-Fingerabdrücke als Erlaubnisregeln sedimentiert — eine exakte Übereinstimmung bei gleichem Tool und gleichem Ziel erlaubt direkt ohne weiteren LLM-Aufruf (funktioniert weiter mit deaktiviertem llmAssist).',\n 'card.sediment': 'Lernsediment (deterministische Erlaubnisregeln)',\n 'card.sedimentHint': 'Aus menschlichen Bestätigungen sedimentierte Regeln: Nur eine exakte Fingerabdruckübereinstimmung erlaubt, nie ein anderes Ziel. Beenden Sie ein Lernen oder entfernen Sie eine Probe.',\n 'card.sedimentEmpty': 'Noch keine sedimentierten Regeln (Proben am Schwellenwert erscheinen hier)',\n 'card.sedimentCount': 'bestätigt %n/%t',\n 'card.sedimentStop': 'Beenden',\n 'card.sedimentStopTitle': 'Dieses Lernen beenden (Zähler und Proben löschen)',\n 'card.sedimentStopConfirm': 'Lernen für „%k\" beenden? Zähler und alle Proben werden gelöscht.',\n 'card.sedimentSampleRemove': 'Diese sedimentierte Probe entfernen',\n 'card.llmSource': 'Empfängerquelle',\n 'card.llmSourceCustom': 'Benutzerdefinierte API (OpenAI-kompatibel)',\n 'card.llmSourceHost': 'Das aktuelle Standardmodell der Sitzung verwenden (DSH-llm-Dienst)',\n 'card.llmSourceHostHint': 'Standardmäßig läuft die Genehmigungsbewertung auf der Modellgruppe, die die DSH-Sitzung aktuell verwendet (der effektive Wert wird unten angezeigt); Provider / Model leer lassen, um der Sitzung zu folgen, oder aus dem Dropdown wählen bzw. eingeben zum Festlegen — Ihre in DSH konfigurierten benutzerdefinierten Gruppen (z. B. local-35b) erscheinen automatisch.',\n 'card.llmProvider': 'Provider (leer = folgt der Sitzungsauswahl)',\n 'card.llmProviderPlaceholder': 'Folgt der Sitzungsauswahl',\n 'card.llmModelHostPlaceholder': 'Leer = folgt der Sitzungsauswahl',\n 'card.llmResolved': 'Aktuell wirksam: %p / %m',\n 'card.llmPreset': 'Endpoint-Voreinstellungen (füllt die Felder; weiter bearbeitbar)',\n 'card.llmPresetChoose': 'Voreinstellung wählen…',\n 'card.llmPresetPublic': 'Öffentliche API-Voreinstellungen',\n 'card.llmPresetHost': 'DSH-Modellgruppen (Auswahl wechselt zum Sitzungsempfänger)',\n 'card.networkEnabled': 'Netzwerk-Interception (networkEnabled)',\n 'card.networkEnabledHint': 'Wenn aktiv, startet ein lokaler Proxy, der ausgehende Verbindungen von Unterprozessen abfängt und Erlaubnis-/Ablehnungsregeln anwendet. Deaktiviert = keine Verhaltensänderung.',\n 'card.watch': 'Regel-Hot-Reload (watch)',\n 'card.watchHint': 'Wenn aktiv, werden Regeldateien automatisch auf Änderungen überwacht und sofort ohne manuelles Neuladen angewendet.',\n 'card.networkRebindNote': 'Wirkt sofort — der Proxy bindet sich automatisch neu, kein Plugin-Reload nötig.',\n 'card.networkInjectEnv': 'Proxy-Umgebungsvariablen injizieren (networkInjectEnv)',\n 'card.networkInjectEnvHint': 'Schreibt HTTP(S)_PROXY / ALL_PROXY für Unterprozesse (und leert NO_PROXY). Deaktiviert = der Listener läuft, aber keine Prozessumgebung wird geändert.',\n 'card.healthStale': 'Host-Route nicht verfügbar (404) — die Node-Hälfte ist noch ein alter Build; starten Sie dsh vollständig neu (nicht nur die Browserseite) und versuchen Sie es erneut.',\n 'card.healthTest': 'Zustandstest',\n 'card.healthRunning': 'Wird getestet…',\n 'card.healthOk': 'OK (%ms ms)',\n 'card.healthFail': 'Fehlgeschlagen: ',\n 'history.tag.learned': 'Gelernt',\n 'history.tag.manualApproved': 'Genehmigt',\n 'history.tag.manualRejected': 'Abgelehnt',\n 'history.tag.manualCancelled': 'Abgebrochen',\n 'history.tag.standDown': 'Gate aus',\n 'history.learnedProgress': 'gelernt %n/%t',\n 'history.snapshots': 'Diff-Snapshots',\n 'history.clearSession': 'Diese Sitzung löschen',\n 'history.clearAll': 'Alle löschen',\n 'history.clearSessionTitle': 'Nur die Diff-Snapshots dieser Sitzung löschen (andere Sitzungen unberührt)',\n 'history.clearAllTitle': 'Diff-Snapshots aller Sitzungen löschen, einschließlich nie überprüfter — fragt erneut',\n 'history.clearSessionConfirm': 'Diff-Snapshots dieser Sitzung löschen? Nur die von dieser Sitzung erzeugten Änderungsvergleichsdaten werden entfernt; die Genehmigungsprotokolle bleiben.',\n 'history.clearAllConfirm': 'Diff-Snapshots ALLER Sitzungen löschen? Dies kann Änderungsvergleiche löschen, die andere Sitzungen noch nicht überprüft haben, und ist unwiderruflich.',\n 'history.diffTitle': 'Dateiänderungsvergleich',\n 'history.diffClose': 'Schließen',\n 'history.diffLoading': 'Wird geladen…',\n 'history.diffEmpty': 'Keine Inhaltsänderung (oder Datei unlesbar)',\n 'history.diffLoadFail': 'Diff-Laden fehlgeschlagen: ',\n 'history.diffRevert': 'Diese Änderung zurücksetzen',\n 'history.diffReverting': 'Wird gesendet…',\n 'history.diffRevertDone': 'Zurücksetzungsanweisung gesendet',\n 'history.diffRevertSent': 'Zurücksetzungsanweisung an die Konversation gesendet; die KI stellt die Datei entsprechend wieder her',\n 'history.diffRevertFail': 'Senden fehlgeschlagen: ',\n 'history.diffNoSnapshot': 'Dieses Ereignis hat keinen Snapshot für diese Datei',\n 'history.diffChipTitle': 'Änderungsvergleich dieser Datei anzeigen',\n 'history.diffStats': '+%a / -%r Zeilen geändert · %c unverändert',\n 'history.diffGone': ' (Datei existiert nicht mehr)',\n 'history.diffHidden': '%n unveränderte Zeilen',\n 'card.dryRun': 'Regeltest',\n 'card.dryRunHint': 'Beurteilt einen Aufruf gegen die aktuellen Regeln. Führt kein Tool aus und schreibt keine Regel — prüfen Sie hier, bevor Sie ändern.',\n 'card.dryRunTool': 'Werkzeug',\n 'card.dryRunCommand': 'Befehl / Argumente',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'Testen',\n 'card.dryRunRunning': 'Wird bewertet…',\n 'card.dryRunEmpty': 'Noch nichts getestet. Geben Sie ein Werkzeug und einen Befehl ein und drücken Sie Testen, um das Verdikt zu sehen.',\n 'card.dryRunVerdict': 'Verdikt',\n 'card.dryRunAllow': 'erlauben',\n 'card.dryRunAsk': 'anfragen',\n 'card.dryRunDeny': 'ablehnen',\n 'card.dryRunRule': 'Übereinstimmende Regel',\n 'card.dryRunRuleNone': 'keine Regel gefunden; defaultAction: %d',\n 'card.dryRunDimensions': 'Dimensionen',\n 'card.dryRunReason': 'Begründung',\n 'card.dryRunNote': '„Übereinstimmende Regel\" stammt aus der Regelebene. Wenn das Verdikt von einer früheren Hartablehnung oder der Schlüsselwort-Blacklist erzeugt wurde, gibt es keinen Regelindex — die aufgelisteten Dimensionen sind dann nur informativ.',\n 'card.dryRunNoRules': '(0 Regeln geladen — prüfen Sie den rulesFile-Pfad)',\n 'card.dryRunFail': 'Test fehlgeschlagen: ',\n 'card.dryRunStale': 'Route fehlt (Plugin nicht neu gestartet?)',\n 'card.rules': 'Einstellungen: Integrierte Regeln',\n 'card.rulesHint': 'Die Regeln, die das Gate gerade lädt (aus dem rules-Konfigurationsfeld dieses Plugin-Eintrags; Fallback auf die Regeldatei, wenn nicht konfiguriert). Nur-Lesen — nichts hier kann sie ändern. Um Regeln zu ändern, verwenden Sie die Whitelist unten oder bearbeiten Sie sie auf der Einstellungsseite.',\n 'card.rulesRefresh': 'Aktualisieren',\n 'card.rulesLoading': 'Wird gelesen…',\n 'card.rulesPath': 'Quelle',\n 'card.rulesNone': 'keine Regeln konfiguriert',\n 'card.rulesCounts': 'Regeln',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b Bytes · %l Zeilen',\n 'card.rulesMissing': 'Regeln nicht gefunden. Das Gate fällt auf seine integrierten Standardwerte zurück.',\n 'card.rulesTruncated': 'Regeln sind groß; nur die ersten 512 KB werden angezeigt.',\n 'card.rulesError': 'Laden fehlgeschlagen: ',\n 'card.rulesStale': 'Route fehlt (Plugin nicht neu gestartet?)',\n 'card.rulesNote': 'Nur-Lesen: Dieses Panel kann die Regeln nicht ändern. Der Whitelist-Abschnitt und „Immer erlauben\" schreiben in die Konfiguration dieses Plugin-Eintrags zurück.',\n}\n\n/** Italian dictionary (keys mirror zh). */\nexport const it: Record<PermissiveKey, string> = {\n 'card.title': 'Revisione automatica',\n 'section.title': 'Portale di revisione automatica',\n 'card.description': 'Livello di approvazione indipendente: parallelo a sola lettura / accesso completo / whitelist, mostrato come «Revisione automatica» nel selettore delle autorizzazioni della sessione. Il front-end espone un unico interruttore; le quattro strategie di approvazione backend sono combinabili tramite questo pannello e restano fail-closed contro il rifiuto rigido P0.',\n 'card.permissive': 'Abilita il livello di revisione automatica',\n 'card.permissiveHint': 'Quando disattivato, il portale si comporta esattamente come prima.',\n 'card.scopeNote': 'Ambito del preset: questo portale agisce solo quando il preset di autorizzazione della sessione è %scope. Con qualsiasi altro preset l\\'intero portale si mette in pausa — incluso il rifiuto rigido P0 — e la politica del preset selezionato prende il controllo. La pausa registra un evento e lascia una striscia persistente sopra l\\'input.',\n 'card.strategies': 'Strategie di approvazione backend (almeno una attiva; combinabili)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — le operazioni sicure nell\\'ambito sono auto-consentite; pericolose/sconosciute → richiesta (livello intermedio di base)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — ogni attraversamento chiede; i «controlli di consenso» del pannello di approvazione aggiungono due pulsanti estesi: «ripeti consenso per questo tipo in questa sessione» (grant limitato alla sessione) e «consenti tutte le occorrenze» (persistenza della parola comando nella whitelist rulesFile)',\n 'card.strategy.llmAssist': 'llmAssist — un LLM personalizzato valuta il rischio: safe → auto-consenso; deletion/credential/remote/system/bulk → rischi rigidi mantengono la richiesta umana (il classificatore non rifiuta mai — scala solo); neutral → apprendimento per conferma; fallimento/timeout → ritorno all\\'umano',\n 'card.strategy.trustEscalation': 'trustEscalation — escalation sandbox senza prompt: per una chiamata già consentita da questo portale, l\\'ampliamento sandbox avviato internamente da shell / pwsh / edit è approvato qui invece di chiedere a te',\n 'card.strategy.trustEscalationHint': 'L\\'approvazione dell\\'escalation sandbox è richiesta dall\\'interno del corpo dello strumento, dopo tools/pre-execute, quindi il portale non la vede mai — una chiamata che il LLM ha giudicato sicura e che il portale ha auto-consentito ti chiedeva comunque di approvare l\\'ampliamento. Attivato, solo la chiamata esatta consentita dal portale (corrispondenza per callId) salta il prompt; tutto il resto va all\\'umano come prima, così come ogni motivo non riconosciuto o un target diverso da workspace-write / danger-full-access. Disattiva per mantenere l\\'ampliamento sotto controllo umano.',\n 'card.readonly': 'Sola lettura',\n 'card.unavailable': 'Namespace delle impostazioni non disponibile: assicurati che dsh-perm-gate sia assemblato in questo profilo.',\n 'card.llmReceiver': 'LLM ricevente llmAssist (compatibile OpenAI; qualsiasi API personalizzata)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, es. https://api.openai.com/v1)',\n 'card.llmModel': 'Model (ID modello, es. deepseek-chat)',\n 'card.llmKey': 'API Key (segreta)',\n 'card.llmKeyHidden': 'Non impostata · mostrata come * dopo il primo inserimento',\n 'card.llmKeyMasked': 'Impostata · inserisci un nuovo valore per sovrascrivere',\n 'card.llmKeyOverwrite': 'Un valore segreto è memorizzato; inserisci un nuovo valore e lascia il campo per sovrascriverlo.',\n 'card.llmKeyClear': 'Cancella',\n 'card.allowlist': 'Whitelist (allow, sincronizzata con rulesFile)',\n 'card.allowlistHint': 'I pattern nella sezione allow consentono direttamente; aggiungi o rimuovi voci una alla volta, scritte in rulesFile e ricaricate in tempo reale.',\n 'card.allowlistPresetNote': 'L\\'equivalente della whitelist predefinita è la strategia trustAutoAllow (operazioni sicure nell\\'ambito auto-consentite), attivata nella sezione strategie sopra; questa lista rispecchia la tua sezione allow di rulesFile e inizia legittimamente vuota.',\n 'card.allowlistEmpty': 'Nessuna regola whitelist',\n 'card.allowlistPlaceholder': 'Nuovo pattern di comando, es. npm test*',\n 'card.allowlistAdd': 'Aggiungi',\n 'card.allowlistRemove': 'Rimuovi questo pattern',\n 'card.allowlistBulk': 'Modifica in blocco',\n 'card.allowlistBulkHide': 'Nascondi modifica in blocco',\n 'card.allowlistSave': 'Salva whitelist',\n 'card.riskLearning': 'riskLearning — apprendimento del verdetto: le operazioni a rischio neutral approvate ed eseguite vengono conteggiate; la stessa operazione è auto-consentita alla soglia con impronta corrispondente',\n 'card.riskLearningHint': 'Lo stato di apprendimento appartiene al plugin ($DSH_HOME/perm-gate/learning.json) e non viene mai scritto nelle tue regole YAML; un target diverso non riutilizza mai l\\'autorità. Disattivato per impostazione predefinita.',\n 'card.riskThreshold': 'Conferme umane richieste prima dell\\'auto-consenso (1–10)',\n 'notice.label': 'Attività del portale autorizzazioni',\n 'history.label': 'Approvazioni',\n 'history.title': 'Registro approvazioni autorizzazioni',\n 'history.subtitle': 'Ogni decisione del portale in questa sessione, più recenti prima',\n 'history.loading': 'Caricamento…',\n 'history.empty': 'Nessun record di approvazione in questa sessione',\n 'history.error': 'Caricamento non riuscito: ',\n 'history.tag.auto': 'Auto-consentito',\n 'history.tag.ask': 'Richiesto',\n 'history.tag.deny': 'Rifiutato',\n 'card.denylistRestore': 'Ripristina blacklist predefinita',\n 'card.denylist': 'Blacklist (parole chiave deny, preset plugin)',\n 'card.denylistHint': 'Una chiamata il cui testo contiene una parola chiave (sottostringa senza distinzione maiuscole/minuscole) è rifiutata immediatamente, prima di whitelist / grant / LLM. La lista predefinita eredita da dsh-approval-gate ed è attiva dall\\'installazione; modifica liberamente — vuota o cancellata torna al predefinito (ripristino con un clic), quindi la blacklist non si disattiva mai silenziosamente.',\n 'card.denylistEmpty': 'Blacklist vuota (nessuna chiamata è respinta dal livello parole chiave)',\n 'card.denylistPlaceholder': 'Nuova parola chiave, es. drop database',\n 'card.denylistAdd': 'Aggiungi',\n 'card.denylistRemove': 'Rimuovi questa parola chiave',\n 'card.denylistTagPreset': 'Preset',\n 'card.denylistTagCustom': 'Personalizzato',\n 'card.riskSediment': 'riskSediment — sedimentazione dell\\'apprendimento: i campioni alla soglia diventano regole deterministiche di auto-consenso',\n 'card.riskSedimentHint': 'Attivato, quando una chiave tool|category raggiunge la soglia le sue impronte campione si sedimentano in regole di consenso — una corrispondenza esatta stesso strumento/stesso target consente direttamente senza altra chiamata LLM (continua a funzionare con llmAssist disattivato).',\n 'card.sediment': 'Sedimento di apprendimento (regole deterministiche di consenso)',\n 'card.sedimentHint': 'Regole sedimentate dalle conferme umane: solo una corrispondenza esatta dell\\'impronta consente, mai un target diverso. Termina un apprendimento o rimuovi un campione.',\n 'card.sedimentEmpty': 'Nessuna regola sedimentata per ora (i campioni che raggiungono la soglia appaiono qui)',\n 'card.sedimentCount': 'confermato %n/%t',\n 'card.sedimentStop': 'Termina',\n 'card.sedimentStopTitle': 'Termina questo apprendimento (elimina conteggio e campioni)',\n 'card.sedimentStopConfirm': 'Terminare l\\'apprendimento per «%k»? Il conteggio e tutti i campioni saranno eliminati.',\n 'card.sedimentSampleRemove': 'Rimuovi questo campione sedimentato',\n 'card.llmSource': 'Sorgente LLM ricevente',\n 'card.llmSourceCustom': 'API personalizzata (compatibile OpenAI)',\n 'card.llmSourceHost': 'Usa il modello predefinito attuale della sessione (servizio DSH llm)',\n 'card.llmSourceHostHint': 'Per impostazione predefinita la valutazione dell\\'approvazione usa il gruppo di modelli attualmente selezionato nella sessione DSH (il valore effettivo è mostrato sotto); lascia Provider / Model vuoto per seguire la sessione, oppure scegli dal menu a tendina o digita per fissare — i gruppi personalizzati configurati in DSH (es. local-35b) appaiono automaticamente.',\n 'card.llmProvider': 'Provider (vuoto = segue la selezione della sessione)',\n 'card.llmProviderPlaceholder': 'Segue la selezione della sessione',\n 'card.llmModelHostPlaceholder': 'Vuoto = segue la selezione della sessione',\n 'card.llmResolved': 'Attualmente effettivo: %p / %m',\n 'card.llmPreset': 'Preset endpoint (compila i campi; ancora modificabile)',\n 'card.llmPresetChoose': 'Scegli un preset…',\n 'card.llmPresetPublic': 'Preset API pubbliche',\n 'card.llmPresetHost': 'Gruppi modelli DSH (la selezione passa al ricevitore di sessione)',\n 'card.networkEnabled': 'Intercettazione rete (networkEnabled)',\n 'card.networkEnabledHint': 'Attivato, avvia un proxy locale che intercetta le connessioni in uscita dei sottoprocessi e applica regole di consenso/rifiuto. Disattivato = nessun cambiamento di comportamento.',\n 'card.watch': 'Ricaricamento a caldo regole (watch)',\n 'card.watchHint': 'Attivato, monitora automaticamente le modifiche ai file di regole e le applica istantaneamente senza ricaricamento manuale.',\n 'card.networkRebindNote': 'Ha effetto immediato — il proxy si ricollega automaticamente, nessun ricaricamento del plugin necessario.',\n 'card.networkInjectEnv': 'Inietta variabili d\\'ambiente proxy (networkInjectEnv)',\n 'card.networkInjectEnvHint': 'Scrive HTTP(S)_PROXY / ALL_PROXY per i sottoprocessi (e svuota NO_PROXY). Disattivato = il listener è in esecuzione ma nessun ambiente di processo viene modificato.',\n 'card.healthStale': 'Route host non disponibile (404) — la metà node è ancora una build vecchia; riavvia completamente dsh (non solo la pagina del browser) e riprova.',\n 'card.healthTest': 'Test di salute',\n 'card.healthRunning': 'Test in corso…',\n 'card.healthOk': 'OK (%ms ms)',\n 'card.healthFail': 'Fallito: ',\n 'history.tag.learned': 'Appreso',\n 'history.tag.manualApproved': 'Approvato',\n 'history.tag.manualRejected': 'Rifiutato',\n 'history.tag.manualCancelled': 'Annullato',\n 'history.tag.standDown': 'Portale inattivo',\n 'history.learnedProgress': 'appreso %n/%t',\n 'history.snapshots': 'snapshot diff',\n 'history.clearSession': 'Cancella questa sessione',\n 'history.clearAll': 'Cancella tutto',\n 'history.clearSessionTitle': 'Cancella solo gli snapshot diff di questa sessione (altre sessioni intatte)',\n 'history.clearAllTitle': 'Cancella gli snapshot diff di tutte le sessioni, incluse quelle mai revisionate — chiede di nuovo',\n 'history.clearSessionConfirm': 'Cancellare gli snapshot diff di questa sessione? Solo i dati di confronto prodotti dalle approvazioni di questa sessione sono rimossi; i record di approvazione restano.',\n 'history.clearAllConfirm': 'Cancellare gli snapshot diff di TUTTE le sessioni? Potrebbe eliminare confronti che altre sessioni non hanno ancora revisionato, ed è irreversibile.',\n 'history.diffTitle': 'Confronto modifiche file',\n 'history.diffClose': 'Chiudi',\n 'history.diffLoading': 'Caricamento…',\n 'history.diffEmpty': 'Nessuna modifica al contenuto (o file illeggibile)',\n 'history.diffLoadFail': 'Caricamento diff non riuscito: ',\n 'history.diffRevert': 'Annulla questa modifica',\n 'history.diffReverting': 'Invio…',\n 'history.diffRevertDone': 'Istruzione di ripristino inviata',\n 'history.diffRevertSent': 'Istruzione di ripristino inviata alla conversazione; l\\'IA ripristinerà il file di conseguenza',\n 'history.diffRevertFail': 'Invio non riuscito: ',\n 'history.diffNoSnapshot': 'Questo evento non ha uno snapshot per quel file',\n 'history.diffChipTitle': 'Visualizza il confronto modifiche di questo file',\n 'history.diffStats': '+%a / -%r righe modificate · %c invariate',\n 'history.diffGone': ' (il file non esiste più)',\n 'history.diffHidden': '%n righe non modificate',\n 'card.dryRun': 'Test regole',\n 'card.dryRunHint': 'Giudica una chiamata contro le regole in vigore. Non esegue alcun strumento e non scrive alcuna regola — verifica qui prima di modificare.',\n 'card.dryRunTool': 'Strumento',\n 'card.dryRunCommand': 'Comando / argomenti',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'Testa',\n 'card.dryRunRunning': 'Valutazione…',\n 'card.dryRunEmpty': 'Nulla di testato finora. Inserisci uno strumento e un comando, poi premi Testa per vedere il verdetto.',\n 'card.dryRunVerdict': 'Verdetto',\n 'card.dryRunAllow': 'consenti',\n 'card.dryRunAsk': 'richiedi',\n 'card.dryRunDeny': 'rifiuta',\n 'card.dryRunRule': 'Regola corrispondente',\n 'card.dryRunRuleNone': 'nessuna regola corrispondente; defaultAction: %d',\n 'card.dryRunDimensions': 'Dimensioni',\n 'card.dryRunReason': 'Motivo',\n 'card.dryRunNote': '«Regola corrispondente» proviene dal livello regole. Quando il verdetto è prodotto da un rifiuto rigido precedente o dalla blacklist di parole chiave non c\\'è indice di regola — le dimensioni elencate sono solo informative.',\n 'card.dryRunNoRules': '(0 regole caricate — controlla il percorso rulesFile)',\n 'card.dryRunFail': 'Test non riuscito: ',\n 'card.dryRunStale': 'route mancante (plugin non riavviato?)',\n 'card.rules': 'Regole integrate delle impostazioni',\n 'card.rulesHint': 'Le regole che il portale sta caricando ora (dal campo di configurazione rules di questa voce plugin; fallback al file regole se non configurato). Sola lettura — nulla qui può modificarle. Per cambiare le regole, usa la whitelist sotto o modificale nella pagina impostazioni.',\n 'card.rulesRefresh': 'Aggiorna',\n 'card.rulesLoading': 'Lettura…',\n 'card.rulesPath': 'Sorgente',\n 'card.rulesNone': 'nessuna regola configurata',\n 'card.rulesCounts': 'Regole',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b byte · %l righe',\n 'card.rulesMissing': 'Regole non trovate. Il portale ripiega sui suoi valori predefiniti integrati.',\n 'card.rulesTruncated': 'Regole grandi; mostrati solo i primi 512 KB.',\n 'card.rulesError': 'Caricamento non riuscito: ',\n 'card.rulesStale': 'route mancante (plugin non riavviato?)',\n 'card.rulesNote': 'Sola lettura: questo pannello non può modificare le regole. La sezione whitelist e «consenti sempre» scrivono nella configurazione di questa voce plugin.',\n}\n\n/** Russian dictionary (keys mirror zh). */\nexport const ru: Record<PermissiveKey, string> = {\n 'card.title': 'Автоматическая проверка',\n 'section.title': 'Шлюз автоматической проверки',\n 'card.description': 'Независимый уровень одобрения: параллельно с «только чтение» / «полный доступ» / «белый список», отображается как «Автоматическая проверка» в выборе разрешений сессии. Фронтенд предоставляет один переключатель; четыре серверные стратегии одобрения комбинируемы через эту панель и остаются fail-closed против жёсткого отказа P0.',\n 'card.permissive': 'Включить уровень автоматической проверки',\n 'card.permissiveHint': 'Когда выключено, шлюз ведёт себя точно так же, как раньше.',\n 'card.scopeNote': 'Область пресета: этот шлюз действует только когда пресет разрешений сессии — %scope. При любом другом пресете весь шлюз отключается — включая жёсткий отказ P0 — и политика выбранного пресета берёт управление на себя. Отключение записывает событие и оставляет постоянную полоску над полем ввода.',\n 'card.strategies': 'Серверные стратегии одобрения (хотя бы одна активна; комбинируемы)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — безопасные операции в области автоматически разрешаются; опасные/неизвестные → запрос (базовый средний уровень)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — каждый переход спрашивает; «элементы управления разрешением» панели одобрения получают две расширенные кнопки: «повторно разрешить этот тип в этой сессии» (ограниченный grant сессии) и «разрешить все вхождения» (постоянное добавление слова команды в белый список rulesFile)',\n 'card.strategy.llmAssist': 'llmAssist — пользовательская LLM оценивает риск: safe → авто-разрешение; deletion/credential/remote/system/bulk → жёсткие риски сохраняют запрос к человеку (классификатор никогда не отказывает — только эскалирует); neutral → обучение подтверждением; сбой/таймаут → возврат к человеку',\n 'card.strategy.trustEscalation': 'trustEscalation — эскалация песочницы без запроса: для вызова, уже разрешённого этим шлюзом, расширение песочницы, инициированное shell / pwsh / edit изнутри инструмента, одобряется здесь вместо запроса к вам',\n 'card.strategy.trustEscalationHint': 'Запрос на одобрение эскалации песочницы происходит изнутри тела инструмента после tools/pre-execute, поэтому шлюз его не видит — вызов, который LLM оценила как безопасный и шлюз авто-разрешил, всё равно спрашивал вас об одобрении расширения. При включении только точный вызов, разрешённый шлюзом (совпадение по callId), пропускает запрос; всё остальное идёт к человеку как раньше, равно как и любая нераспознанная причина или цель, отличная от workspace-write / danger-full-access. Выключите, чтобы расширение оставалось под контролем человека.',\n 'card.readonly': 'Только чтение',\n 'card.unavailable': 'Пространство имён настроек недоступно: убедитесь, что dsh-perm-gate собран в этом профиле.',\n 'card.llmReceiver': 'Принимающая LLM для llmAssist (совместимая с OpenAI; любой пользовательский API)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, напр. https://api.openai.com/v1)',\n 'card.llmModel': 'Model (идентификатор модели, напр. deepseek-chat)',\n 'card.llmKey': 'API Key (секрет)',\n 'card.llmKeyHidden': 'Не задан · после первого ввода отображается как *',\n 'card.llmKeyMasked': 'Задан · введите новое значение для перезаписи',\n 'card.llmKeyOverwrite': 'Секретное значение сохранено; введите новое значение и покиньте поле для перезаписи.',\n 'card.llmKeyClear': 'Очистить',\n 'card.allowlist': 'Белый список (allow, синхронизирован с rulesFile)',\n 'card.allowlistHint': 'Паттерны в секции allow разрешаются напрямую; добавляйте или удаляйте записи по одной, они записываются в rulesFile и перезагружаются в реальном времени.',\n 'card.allowlistPresetNote': 'Эквивалент пресетного белого списка — стратегия trustAutoAllow (безопасные операции в области автоматически разрешаются), активируется в секции стратегий выше; этот список отражает вашу секцию allow в rulesFile и закономерно начинается пустым.',\n 'card.allowlistEmpty': 'Нет правил белого списка',\n 'card.allowlistPlaceholder': 'Новый паттерн команды, напр. npm test*',\n 'card.allowlistAdd': 'Добавить',\n 'card.allowlistRemove': 'Удалить этот паттерн',\n 'card.allowlistBulk': 'Массовое редактирование',\n 'card.allowlistBulkHide': 'Скрыть массовое редактирование',\n 'card.allowlistSave': 'Сохранить белый список',\n 'card.riskLearning': 'riskLearning — обучение вердиктам: операции с нейтральным риском, одобренные человеком и выполненные, подсчитываются; та же операция автоматически разрешается при достижении порога с совпадающим отпечатком',\n 'card.riskLearningHint': 'Состояние обучения принадлежит плагину ($DSH_HOME/perm-gate/learning.json) и никогда не записывается в ваши YAML-правила; другая цель никогда не переиспользует полномочие. По умолчанию выключено.',\n 'card.riskThreshold': 'Подтверждений человеком перед авто-разрешением (1–10)',\n 'notice.label': 'Активность шлюза разрешений',\n 'history.label': 'Одобрения',\n 'history.title': 'Журнал одобрений разрешений',\n 'history.subtitle': 'Каждое решение шлюза в этой сессии, последние сверху',\n 'history.loading': 'Загрузка…',\n 'history.empty': 'В этой сессии пока нет записей одобрения',\n 'history.error': 'Ошибка загрузки: ',\n 'history.tag.auto': 'Авто-разрешено',\n 'history.tag.ask': 'Запрошено',\n 'history.tag.deny': 'Отклонено',\n 'card.denylistRestore': 'Восстановить пресетный чёрный список',\n 'card.denylist': 'Чёрный список (ключевые слова deny, пресет плагина)',\n 'card.denylistHint': 'Вызов, текст которого содержит ключевое слово (подстрока без учёта регистра), немедленно отклоняется — до белого списка / grants / LLM. Пресетный список наследуется от dsh-approval-gate и активен с момента установки; редактируйте свободно — пустой или очищенный возвращается к пресету (восстановление в один клик), поэтому чёрный список никогда не отключается молча.',\n 'card.denylistEmpty': 'Чёрный список пуст (ни один вызов не отклоняется на уровне ключевых слов)',\n 'card.denylistPlaceholder': 'Новое ключевое слово, напр. drop database',\n 'card.denylistAdd': 'Добавить',\n 'card.denylistRemove': 'Удалить это ключевое слово',\n 'card.denylistTagPreset': 'Пресет',\n 'card.denylistTagCustom': 'Пользовательское',\n 'card.riskSediment': 'riskSediment — седиментация обучения: образцы, достигшие порога, становятся детерминированными правилами авто-разрешения',\n 'card.riskSedimentHint': 'При включении, когда ключ tool|category достигает порога, отпечатки его образцов оседают в правила разрешения — точное совпадение тот же инструмент/та же цель разрешает напрямую без нового вызова LLM (продолжает работать с выключенным llmAssist).',\n 'card.sediment': 'Осадок обучения (детерминированные правила разрешения)',\n 'card.sedimentHint': 'Правила, осевшие из подтверждений человека: только точное совпадение отпечатка разрешает, никогда другая цель. Завершите одно обучение или удалите один образец.',\n 'card.sedimentEmpty': 'Пока нет осаждённых правил (образцы, достигшие порога, появятся здесь)',\n 'card.sedimentCount': 'подтверждено %n/%t',\n 'card.sedimentStop': 'Завершить',\n 'card.sedimentStopTitle': 'Завершить это обучение (удаляет счётчик и образцы)',\n 'card.sedimentStopConfirm': 'Завершить обучение для «%k»? Его счётчик и все образцы будут удалены.',\n 'card.sedimentSampleRemove': 'Удалить этот осаждённый образец',\n 'card.llmSource': 'Источник принимающей LLM',\n 'card.llmSourceCustom': 'Пользовательский API (совместимый с OpenAI)',\n 'card.llmSourceHost': 'Использовать текущую модель по умолчанию сессии (сервис DSH llm)',\n 'card.llmSourceHostHint': 'По умолчанию оценка одобрения выполняется на группе моделей, выбранной в текущей сессии DSH (эффективное значение показано ниже); оставьте Provider / Model пустым, чтобы следовать за сессией, или выберите из выпадающего списка / введите для фиксации — ваши пользовательские группы, настроенные в DSH (напр. local-35b), появляются автоматически.',\n 'card.llmProvider': 'Provider (пусто = следует выбору сессии)',\n 'card.llmProviderPlaceholder': 'Следует выбору сессии',\n 'card.llmModelHostPlaceholder': 'Пусто = следует выбору сессии',\n 'card.llmResolved': 'Текущий эффективный: %p / %m',\n 'card.llmPreset': 'Пресеты эндпоинтов (заполняет поля; далее редактируемо)',\n 'card.llmPresetChoose': 'Выбрать пресет…',\n 'card.llmPresetPublic': 'Пресеты публичных API',\n 'card.llmPresetHost': 'Группы моделей DSH (выбор переключает на приёмник сессии)',\n 'card.networkEnabled': 'Перехват сети (networkEnabled)',\n 'card.networkEnabledHint': 'При включении запускается локальный прокси, перехватывающий исходящие соединения подпроцессов и применяющий правила разрешения/отказа. Выключено = никаких изменений поведения.',\n 'card.watch': 'Горячая перезагрузка правил (watch)',\n 'card.watchHint': 'При включении автоматически отслеживает изменения файлов правил и применяет их мгновенно без ручной перезагрузки.',\n 'card.networkRebindNote': 'Вступает в силу немедленно — прокси автоматически перепривязывается, перезагрузка плагина не нужна.',\n 'card.networkInjectEnv': 'Инъекция переменных окружения прокси (networkInjectEnv)',\n 'card.networkInjectEnvHint': 'Записывает HTTP(S)_PROXY / ALL_PROXY для подпроцессов (и очищает NO_PROXY). Выключено = слушатель работает, но окружение процессов не изменяется.',\n 'card.healthStale': 'Маршрут хоста недоступен (404) — половина node всё ещё старой сборки; полностью перезапустите dsh (не только страницу браузера) и повторите.',\n 'card.healthTest': 'Тест состояния',\n 'card.healthRunning': 'Тестирование…',\n 'card.healthOk': 'OK (%ms мс)',\n 'card.healthFail': 'Ошибка: ',\n 'history.tag.learned': 'Изучено',\n 'history.tag.manualApproved': 'Одобрено',\n 'history.tag.manualRejected': 'Отклонено',\n 'history.tag.manualCancelled': 'Отменено',\n 'history.tag.standDown': 'Шлюз выключен',\n 'history.learnedProgress': 'изучено %n/%t',\n 'history.snapshots': 'снимки diff',\n 'history.clearSession': 'Очистить эту сессию',\n 'history.clearAll': 'Очистить всё',\n 'history.clearSessionTitle': 'Очистить только снимки diff этой сессии (другие сессии не затрагиваются)',\n 'history.clearAllTitle': 'Очистить снимки diff всех сессий, включая непросмотренные — запрашивает подтверждение',\n 'history.clearSessionConfirm': 'Очистить снимки diff этой сессии? Удаляются только данные сравнения, созданные одобрениями этой сессии; записи одобрений остаются.',\n 'history.clearAllConfirm': 'Очистить снимки diff ВСЕХ сессий? Это может удалить сравнения, которые другие сессии ещё не просмотрели, и необратимо.',\n 'history.diffTitle': 'Сравнение изменений файла',\n 'history.diffClose': 'Закрыть',\n 'history.diffLoading': 'Загрузка…',\n 'history.diffEmpty': 'Нет изменений содержимого (или файл нечитаем)',\n 'history.diffLoadFail': 'Ошибка загрузки diff: ',\n 'history.diffRevert': 'Отменить это изменение',\n 'history.diffReverting': 'Отправка…',\n 'history.diffRevertDone': 'Инструкция отмены отправлена',\n 'history.diffRevertSent': 'Инструкция отмены отправлена в диалог; ИИ восстановит файл соответственно',\n 'history.diffRevertFail': 'Ошибка отправки: ',\n 'history.diffNoSnapshot': 'У этого события нет снимка для данного файла',\n 'history.diffChipTitle': 'Просмотреть сравнение изменений этого файла',\n 'history.diffStats': '+%a / -%r строк изменено · %c без изменений',\n 'history.diffGone': ' (файл больше не существует)',\n 'history.diffHidden': '%n неизменённых строк',\n 'card.dryRun': 'Тест правил',\n 'card.dryRunHint': 'Оценивает один вызов по действующим правилам. Не выполняет инструмент и не записывает правило — проверьте здесь перед изменением.',\n 'card.dryRunTool': 'Инструмент',\n 'card.dryRunCommand': 'Команда / аргументы',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'Тестировать',\n 'card.dryRunRunning': 'Оценка…',\n 'card.dryRunEmpty': 'Пока ничего не протестировано. Укажите инструмент и команду, затем нажмите «Тестировать», чтобы увидеть вердикт.',\n 'card.dryRunVerdict': 'Вердикт',\n 'card.dryRunAllow': 'разрешить',\n 'card.dryRunAsk': 'запросить',\n 'card.dryRunDeny': 'отклонить',\n 'card.dryRunRule': 'Совпавшее правило',\n 'card.dryRunRuleNone': 'ни одно правило не совпало; defaultAction: %d',\n 'card.dryRunDimensions': 'Измерения',\n 'card.dryRunReason': 'Причина',\n 'card.dryRunNote': '«Совпавшее правило» происходит из уровня правил. Когда вердикт выработан более ранним жёстким отказом или чёрным списком ключевых слов, индекса правила нет — перечисленные измерения носят справочный характер.',\n 'card.dryRunNoRules': '(загружено 0 правил — проверьте путь rulesFile)',\n 'card.dryRunFail': 'Ошибка теста: ',\n 'card.dryRunStale': 'маршрут отсутствует (плагин не перезапущен?)',\n 'card.rules': 'Встроенные правила настроек',\n 'card.rulesHint': 'Правила, которые шлюз загружает сейчас (из поля конфигурации rules этой записи плагина; откат к файлу правил, если не настроено). Только чтение — ничто здесь не может их изменить. Чтобы изменить правила, используйте белый список ниже или редактируйте на странице настроек.',\n 'card.rulesRefresh': 'Обновить',\n 'card.rulesLoading': 'Чтение…',\n 'card.rulesPath': 'Источник',\n 'card.rulesNone': 'правила не настроены',\n 'card.rulesCounts': 'Правила',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b байт · %l строк',\n 'card.rulesMissing': 'Правила не найдены. Шлюз откатывается к встроенным значениям по умолчанию.',\n 'card.rulesTruncated': 'Правила большие; показаны только первые 512 КБ.',\n 'card.rulesError': 'Ошибка загрузки: ',\n 'card.rulesStale': 'маршрут отсутствует (плагин не перезапущен?)',\n 'card.rulesNote': 'Только чтение: эта панель не может изменять правила. Секция белого списка и «всегда разрешать» записывают обратно в конфигурацию этой записи плагина.',\n}\n\n/** Spanish dictionary (keys mirror zh). */\nexport const es: Record<PermissiveKey, string> = {\n 'card.title': 'Revisión automática',\n 'section.title': 'Compuerta de revisión automática',\n 'card.description': 'Nivel de aprobación independiente: paralelo a solo lectura / acceso completo / lista blanca, mostrado como «Revisión automática» en el selector de permisos de sesión. El frontend expone un único interruptor; las cuatro estrategias de aprobación del backend son combinables mediante este panel y permanecen fail-closed contra la denegación dura P0.',\n 'card.permissive': 'Habilitar el nivel de revisión automática',\n 'card.permissiveHint': 'Cuando está desactivado, la compuerta se comporta exactamente igual que antes.',\n 'card.scopeNote': 'Ámbito del preajuste: esta compuerta solo actúa mientras el preajuste de permisos de la sesión sea %scope. Bajo cualquier otro preajuste la compuerta completa se retira — incluida la denegación dura P0 — y la política del preajuste seleccionado toma el control. La retirada registra un evento y deja una franja persistente sobre la entrada.',\n 'card.strategies': 'Estrategias de aprobación del backend (al menos una activa; combinables)',\n 'card.strategy.trustAutoAllow': 'trustAutoAllow — las operaciones seguras dentro del ámbito se auto-permiten; peligrosas/desconocidas → consulta (nivel intermedio base)',\n 'card.strategy.alwaysConfirm': 'alwaysConfirm — cada cruce pregunta; los «controles de permiso» del panel de aprobación reciben dos botones extendidos: «repetir permiso para este tipo esta sesión» (grant acotado de sesión) y «permitir todas las ocurrencias» (persistir la palabra de comando en la lista blanca de rulesFile)',\n 'card.strategy.llmAssist': 'llmAssist — un LLM personalizado evalúa el riesgo: safe → auto-permiso; deletion/credential/remote/system/bulk → riesgos duros mantienen la consulta humana (el clasificador nunca deniega — solo escala); neutral → aprendizaje por confirmación; fallo/timeout → retorno al humano',\n 'card.strategy.trustEscalation': 'trustEscalation — escalado de sandbox sin aviso: para una llamada ya permitida por esta compuerta, la ampliación de sandbox iniciada internamente por shell / pwsh / edit se aprueba aquí en lugar de preguntarte',\n 'card.strategy.trustEscalationHint': 'La aprobación del escalado de sandbox se solicita desde dentro del cuerpo de la herramienta, después de tools/pre-execute, así que la compuerta nunca la ve — una llamada que el LLM calificó como segura y que la compuerta auto-permitió aun así te pedía aprobar la ampliación. Activado, solo la llamada exacta que la compuerta permitió (coincidencia por callId) omite el aviso; todo lo demás va al humano como antes, al igual que cualquier motivo no reconocido o un destino distinto de workspace-write / danger-full-access. Desactívalo para mantener la ampliación bajo control humano.',\n 'card.readonly': 'Solo lectura',\n 'card.unavailable': 'Espacio de nombres de configuración no disponible: asegúrate de que dsh-perm-gate esté ensamblado en este perfil.',\n 'card.llmReceiver': 'LLM receptor de llmAssist (compatible con OpenAI; cualquier API personalizada)',\n 'card.llmEndpoint': 'Endpoint (BaseURL, ej. https://api.openai.com/v1)',\n 'card.llmModel': 'Model (id del modelo, ej. deepseek-chat)',\n 'card.llmKey': 'API Key (secreta)',\n 'card.llmKeyHidden': 'No establecida · se muestra como * tras la primera entrada',\n 'card.llmKeyMasked': 'Establecida · introduce un nuevo valor para sobrescribir',\n 'card.llmKeyOverwrite': 'Hay un valor secreto almacenado; introduce un nuevo valor y sal del campo para sobrescribirlo.',\n 'card.llmKeyClear': 'Borrar',\n 'card.allowlist': 'Lista blanca (allow, sincronizada con rulesFile)',\n 'card.allowlistHint': 'Los patrones en la sección allow se permiten directamente; agrega o elimina entradas una por una, se escriben en rulesFile y se recargan en vivo.',\n 'card.allowlistPresetNote': 'El equivalente de la lista blanca predefinida es la estrategia trustAutoAllow (operaciones seguras en el ámbito auto-permitidas), habilitada en la sección de estrategias de arriba; esta lista refleja tu sección allow de rulesFile y legítimamente comienza vacía.',\n 'card.allowlistEmpty': 'Sin reglas de lista blanca',\n 'card.allowlistPlaceholder': 'Nuevo patrón de comando, ej. npm test*',\n 'card.allowlistAdd': 'Agregar',\n 'card.allowlistRemove': 'Eliminar este patrón',\n 'card.allowlistBulk': 'Edición masiva',\n 'card.allowlistBulkHide': 'Ocultar edición masiva',\n 'card.allowlistSave': 'Guardar lista blanca',\n 'card.riskLearning': 'riskLearning — aprendizaje de veredictos: las operaciones de riesgo neutral aprobadas por el humano y ejecutadas se contabilizan; la misma operación se auto-permite al umbral con huella coincidente',\n 'card.riskLearningHint': 'El estado de aprendizaje pertenece al plugin ($DSH_HOME/perm-gate/learning.json) y nunca se escribe en tus reglas YAML; un destino diferente nunca reutiliza la autoridad. Desactivado por defecto.',\n 'card.riskThreshold': 'Confirmaciones humanas requeridas antes del auto-permiso (1–10)',\n 'notice.label': 'Actividad de la compuerta de permisos',\n 'history.label': 'Aprobaciones',\n 'history.title': 'Registro de aprobaciones de permisos',\n 'history.subtitle': 'Cada decisión de la compuerta en esta sesión, más recientes primero',\n 'history.loading': 'Cargando…',\n 'history.empty': 'Aún no hay registros de aprobación en esta sesión',\n 'history.error': 'Error al cargar: ',\n 'history.tag.auto': 'Auto-permitido',\n 'history.tag.ask': 'Consultado',\n 'history.tag.deny': 'Denegado',\n 'card.denylistRestore': 'Restaurar lista negra predefinida',\n 'card.denylist': 'Lista negra (palabras clave deny, preajuste del plugin)',\n 'card.denylistHint': 'Una llamada cuyo texto contiene una palabra clave (subcadena sin distinción de mayúsculas) se deniega de inmediato, antes que lista blanca / grants / LLM. La lista predefinida hereda de dsh-approval-gate y está activa desde la instalación; edita libremente — vacía o borrada vuelve al preajuste (restauración con un clic), así que la lista negra nunca se desactiva silenciosamente.',\n 'card.denylistEmpty': 'Lista negra vacía (ninguna llamada es vetada por la capa de palabras clave)',\n 'card.denylistPlaceholder': 'Nueva palabra clave, ej. drop database',\n 'card.denylistAdd': 'Agregar',\n 'card.denylistRemove': 'Eliminar esta palabra clave',\n 'card.denylistTagPreset': 'Preajuste',\n 'card.denylistTagCustom': 'Personalizado',\n 'card.riskSediment': 'riskSediment — sedimentación del aprendizaje: las muestras que alcanzan el umbral se convierten en reglas deterministas de auto-permiso',\n 'card.riskSedimentHint': 'Activado, cuando una clave tool|category alcanza el umbral sus huellas de muestra se sedimentan en reglas de permiso — una coincidencia exacta misma herramienta/mismo destino permite directamente sin otra llamada LLM (sigue funcionando con llmAssist desactivado).',\n 'card.sediment': 'Sedimento de aprendizaje (reglas deterministas de permiso)',\n 'card.sedimentHint': 'Reglas sedimentadas a partir de confirmaciones humanas: solo una coincidencia exacta de huella permite, nunca un destino diferente. Termina un aprendizaje o elimina una muestra.',\n 'card.sedimentEmpty': 'Aún no hay reglas sedimentadas (las muestras que alcanzan el umbral aparecen aquí)',\n 'card.sedimentCount': 'confirmado %n/%t',\n 'card.sedimentStop': 'Terminar',\n 'card.sedimentStopTitle': 'Terminar este aprendizaje (elimina el contador y las muestras)',\n 'card.sedimentStopConfirm': '¿Terminar el aprendizaje de «%k»? Se eliminarán su contador y todas las muestras.',\n 'card.sedimentSampleRemove': 'Eliminar esta muestra sedimentada',\n 'card.llmSource': 'Fuente del LLM receptor',\n 'card.llmSourceCustom': 'API personalizada (compatible con OpenAI)',\n 'card.llmSourceHost': 'Usar el modelo predeterminado actual de la sesión (servicio DSH llm)',\n 'card.llmSourceHostHint': 'Por defecto la evaluación de aprobación se ejecuta en el grupo de modelos seleccionado actualmente en la sesión DSH (el valor efectivo se muestra abajo); deja Provider / Model vacío para seguir la sesión, o elige del desplegable o escribe para fijar — tus grupos personalizados configurados en DSH (ej. local-35b) aparecen automáticamente.',\n 'card.llmProvider': 'Provider (vacío = sigue la selección de sesión)',\n 'card.llmProviderPlaceholder': 'Sigue la selección de sesión',\n 'card.llmModelHostPlaceholder': 'Vacío = sigue la selección de sesión',\n 'card.llmResolved': 'Efectivo ahora: %p / %m',\n 'card.llmPreset': 'Preajustes de endpoint (rellena los campos; aún editable)',\n 'card.llmPresetChoose': 'Elegir un preajuste…',\n 'card.llmPresetPublic': 'Preajustes de API públicas',\n 'card.llmPresetHost': 'Grupos de modelos DSH (seleccionar uno cambia al receptor de sesión)',\n 'card.networkEnabled': 'Intercepción de red (networkEnabled)',\n 'card.networkEnabledHint': 'Activado, inicia un proxy local que intercepta las conexiones salientes de los subprocesos y aplica reglas de permiso/denegación. Desactivado = cero cambio de comportamiento.',\n 'card.watch': 'Recarga en caliente de reglas (watch)',\n 'card.watchHint': 'Activado, vigila automáticamente los cambios en los archivos de reglas y los aplica instantáneamente sin recarga manual.',\n 'card.networkRebindNote': 'Surte efecto de inmediato — el proxy se re-vincula automáticamente, sin necesidad de recargar el plugin.',\n 'card.networkInjectEnv': 'Inyectar variables de entorno del proxy (networkInjectEnv)',\n 'card.networkInjectEnvHint': 'Escribe HTTP(S)_PROXY / ALL_PROXY para los subprocesos (y vacía NO_PROXY). Desactivado = el listener funciona pero no se modifica ningún entorno de proceso.',\n 'card.healthStale': 'Ruta del host no disponible (404) — la mitad node sigue siendo una compilación antigua; reinicia completamente dsh (no solo la página del navegador) e inténtalo de nuevo.',\n 'card.healthTest': 'Prueba de salud',\n 'card.healthRunning': 'Probando…',\n 'card.healthOk': 'OK (%ms ms)',\n 'card.healthFail': 'Fallido: ',\n 'history.tag.learned': 'Aprendido',\n 'history.tag.manualApproved': 'Aprobado',\n 'history.tag.manualRejected': 'Rechazado',\n 'history.tag.manualCancelled': 'Cancelado',\n 'history.tag.standDown': 'Compuerta inactiva',\n 'history.learnedProgress': 'aprendido %n/%t',\n 'history.snapshots': 'instantáneas diff',\n 'history.clearSession': 'Borrar esta sesión',\n 'history.clearAll': 'Borrar todo',\n 'history.clearSessionTitle': 'Borrar solo las instantáneas diff de esta sesión (otras sesiones intactas)',\n 'history.clearAllTitle': 'Borrar las instantáneas diff de todas las sesiones, incluidas las no revisadas — pide confirmación',\n 'history.clearSessionConfirm': '¿Borrar las instantáneas diff de esta sesión? Solo se eliminan los datos de comparación generados por las aprobaciones de esta sesión; los registros de aprobación permanecen.',\n 'history.clearAllConfirm': '¿Borrar las instantáneas diff de TODAS las sesiones? Esto puede eliminar comparaciones que otras sesiones aún no han revisado, y es irreversible.',\n 'history.diffTitle': 'Comparación de cambios de archivo',\n 'history.diffClose': 'Cerrar',\n 'history.diffLoading': 'Cargando…',\n 'history.diffEmpty': 'Sin cambios de contenido (o archivo ilegible)',\n 'history.diffLoadFail': 'Error al cargar diff: ',\n 'history.diffRevert': 'Revertir este cambio',\n 'history.diffReverting': 'Enviando…',\n 'history.diffRevertDone': 'Instrucción de reversión enviada',\n 'history.diffRevertSent': 'Instrucción de reversión enviada a la conversación; la IA restaurará el archivo en consecuencia',\n 'history.diffRevertFail': 'Error de envío: ',\n 'history.diffNoSnapshot': 'Este evento no tiene instantánea para ese archivo',\n 'history.diffChipTitle': 'Ver la comparación de cambios de este archivo',\n 'history.diffStats': '+%a / -%r líneas cambiadas · %c sin cambios',\n 'history.diffGone': ' (el archivo ya no existe)',\n 'history.diffHidden': '%n líneas sin modificar',\n 'card.dryRun': 'Prueba de reglas',\n 'card.dryRunHint': 'Juzga una llamada contra las reglas vigentes. No ejecuta ninguna herramienta ni escribe ninguna regla — comprueba aquí antes de cambiar.',\n 'card.dryRunTool': 'Herramienta',\n 'card.dryRunCommand': 'Comando / argumentos',\n 'card.dryRunCommandPlaceholder': 'git push --force origin main',\n 'card.dryRunTest': 'Probar',\n 'card.dryRunRunning': 'Evaluando…',\n 'card.dryRunEmpty': 'Nada probado aún. Rellena una herramienta y un comando, luego pulsa Probar para ver el veredicto.',\n 'card.dryRunVerdict': 'Veredicto',\n 'card.dryRunAllow': 'permitir',\n 'card.dryRunAsk': 'consultar',\n 'card.dryRunDeny': 'denegar',\n 'card.dryRunRule': 'Regla coincidente',\n 'card.dryRunRuleNone': 'ninguna regla coincidió; defaultAction: %d',\n 'card.dryRunDimensions': 'Dimensiones',\n 'card.dryRunReason': 'Razón',\n 'card.dryRunNote': '«Regla coincidente» proviene de la capa de reglas. Cuando el veredicto fue producido por una denegación dura anterior o por la lista negra de palabras clave no hay índice de regla — las dimensiones listadas son solo informativas.',\n 'card.dryRunNoRules': '(0 reglas cargadas — comprueba la ruta de rulesFile)',\n 'card.dryRunFail': 'Prueba fallida: ',\n 'card.dryRunStale': 'ruta ausente (¿plugin no reiniciado?)',\n 'card.rules': 'Reglas integradas de configuración',\n 'card.rulesHint': 'Las reglas que la compuerta está cargando ahora (del campo de configuración rules de esta entrada de plugin; retroceso al archivo de reglas si no está configurado). Solo lectura — nada aquí puede modificarlas. Para cambiar reglas, usa la lista blanca de abajo o edítalas en la página de configuración.',\n 'card.rulesRefresh': 'Actualizar',\n 'card.rulesLoading': 'Leyendo…',\n 'card.rulesPath': 'Origen',\n 'card.rulesNone': 'sin reglas configuradas',\n 'card.rulesCounts': 'Reglas',\n 'card.rulesDefault': 'defaultAction',\n 'card.rulesStats': '%b bytes · %l líneas',\n 'card.rulesMissing': 'Reglas no encontradas. La compuerta retrocede a sus valores predeterminados integrados.',\n 'card.rulesTruncated': 'Reglas grandes; se muestran solo los primeros 512 KB.',\n 'card.rulesError': 'Error de carga: ',\n 'card.rulesStale': 'ruta ausente (¿plugin no reiniciado?)',\n 'card.rulesNote': 'Solo lectura: este panel no puede modificar las reglas. La sección de lista blanca y «permitir siempre» escriben de vuelta en la configuración de esta entrada de plugin.',\n}\n\n/**\n * Combined dictionary map for all 9 active languages, registered in ONE\n * `locale.register(NS, dictionaries)` call. The map form is deliberately left\n * with its inferred literal type instead of a loose\n * `Record<string, Record<string, string>>` annotation: `dsh-perm-gate` is a\n * declared namespace in `LocaleNamespaceMap`, so the locale service resolves\n * the TYPED `register(ns, dicts)` overload, which requires the built-in\n * `zh`/`en` keys to be statically present (an index signature would not\n * guarantee them and fails the assignment). The runtime still iterates every\n * entry of the map and accepts any BCP 47-style locale id, so the seven\n * extension languages activate through the very same call.\n */\nexport const dictionaries = { zh, en, ja, ko, fr, de, it, ru, es }\n","/**\n * Preset deny keywords inherited from dsh-approval-gate's `DEFAULT_DENY_KEYWORDS`\n * (the preset blacklist layer of its pipeline). One keyword per entry, matched\n * case-insensitively on word boundaries against the call's command text and its\n * scalar arguments — document bodies are skipped — so a keyword can no longer\n * veto an unrelated identifier or file text that merely contains it.\n *\n * Pure data shared by the node half (deny-keyword pre-layer) and the client\n * bundle (the settings card's preset tags), so it must stay import-free.\n */\n\n/** The preset blacklist; the gate applies it whenever the namespace carries no override. */\nexport const DEFAULT_DENY_KEYWORDS: readonly string[] = [\n 'rm -rf', 'rm -fr', 'rm -r -f', 'rm --recursive --force',\n 'push --force', 'force-push', 'force push', 'drop table', 'drop database',\n 'mkfs', 'mkfs.ext', 'format', 'shutdown', 'reboot', 'dd of=',\n 'delete from', 'truncate table', 'truncate ', 'terraform destroy', 'revoke',\n '清空数据库', '删除数据库', '格式化', 'sudo rm', 'chmod 777 /',\n 'git reset --hard', 'git clean -fd', 'docker rm', 'docker system prune',\n]\n","/**\n * Known OpenAI-compatible endpoint presets for the llmAssist receiver\n * (the settings card fills endpoint + model from one pick; every field stays\n * editable afterwards). Pure data shared by the node half and the client\n * bundle, so it must stay import-free.\n */\n\n/** One preset receiver endpoint. */\nexport interface LlmPreset {\n readonly id: string\n readonly label: string\n /** OpenAI-compatible base URL (the `/chat/completions` suffix is normalized away). */\n readonly endpoint: string\n /** Suggested chat model id (editable after filling). */\n readonly model: string\n}\n\nexport const LLM_PRESETS: readonly LlmPreset[] = [\n { id: 'deepseek', label: 'DeepSeek', endpoint: 'https://api.deepseek.com/v1', model: 'deepseek-chat' },\n { id: 'xiaomi-mimo', label: '小米 MiMo', endpoint: 'https://api.xiaomimimo.com/v1', model: 'mimo-v2.5' },\n { id: 'openai', label: 'OpenAI', endpoint: 'https://api.openai.com/v1', model: 'gpt-4o-mini' },\n]\n","/**\n * Session permission-preset awareness for dsh-perm-gate.\n *\n * `dsh-permission-presets` folds three durable knob events per session\n * (`permission/preset`, `sandbox/mode`, `approval/policy`) and pins an initial\n * `permission/preset` at session creation, so the last `permission/preset`\n * event names the tier the user selected. The gate reads that fold to decide\n * whether its own approval tier is the active one.\n *\n * Reading the session log directly (instead of requiring the\n * `permissionPresets` service) keeps the gate usable in a bare embedding and\n * avoids a hard dependency on a service that may not be composed. The fold\n * matches `effectivePermissionPreset` in dsh-permission-presets: last event\n * wins.\n */\n\n/** The slice of one session event this module folds. */\nexport interface SessionEventLike {\n readonly type?: string\n readonly data?: { readonly preset?: unknown }\n}\n\n/**\n * Fold the last selected permission preset out of one session's event log.\n * @param events - the session's events in log order.\n * @returns the preset name, or `undefined` when the log records none.\n */\nexport function permissionPresetOf(events: readonly SessionEventLike[] | undefined): string | undefined {\n if (events === undefined) return undefined\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index]\n if (event?.type !== 'permission/preset') continue\n const preset = event.data?.preset\n if (typeof preset === 'string' && preset !== '') return preset\n }\n return undefined\n}\n\n/** Whether one preset name is covered by a configured scope list. */\nexport function presetInScope(preset: string | undefined, scope: readonly string[]): boolean {\n if (scope.includes('*')) return true\n if (preset === undefined) return false\n return scope.includes(preset)\n}\n\n/**\n * Presets in which the gate is active. It owns both 自动审查 tiers — the plain\n * one (file sandbox kept) and the full-access one (sandbox restriction lifted,\n * same approval behaviour) — so a user can have the gate without inheriting a\n * sandbox that breaks `git` / Cygwin tools. `'*'` makes it global (every\n * preset, including the hard-deny layer).\n *\n * Lives in this dependency-free module (not `config.ts`) so the browser half can\n * render the scope without pulling schemastery into the client bundle.\n */\nexport const DEFAULT_GATE_PRESETS: readonly string[] = ['permissive', 'permissive-full']\n\n/** Normalize the gate scope: an unset/empty list means the default. */\nexport function resolveGatePresets(configured?: readonly string[]): readonly string[] {\n if (configured === undefined || configured.length === 0) return DEFAULT_GATE_PRESETS\n return configured.filter((name) => typeof name === 'string' && name !== '')\n}\n","/**\n * Learning-sediment management section — the settings-card face of verdict\n * learning's \"沉淀\" (the ⑤ card pattern demonstrated by dsh-approval-gate):\n * every threshold-reached key's confirmed samples, listed as the deterministic\n * auto-allow rules they now are, with per-key terminate and per-sample remove.\n *\n * Data source: the host's `GET /api/dsh-perm-gate/learning` route (the same\n * learning.json store the gate reads); actions POST back. Best-effort: a\n * missing route renders the empty state, never an error.\n */\nimport { useEffect, useRef, useState } from 'react'\nimport type { CSSProperties, JSX } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\n\ninterface LearningSample {\n readonly fp: string\n readonly ctx: string\n readonly at: number\n}\n\ninterface LearningBody {\n readonly ok?: boolean\n readonly threshold?: number\n readonly confirmed?: Record<string, number>\n readonly samples?: Record<string, LearningSample[]>\n}\n\nconst itemStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '4px 8px',\n borderRadius: '6px',\n border: '1px solid var(--dsw-alias-border-l2)',\n background: 'var(--dsw-alias-bg-surface, transparent)',\n}\n\nconst chipStyle: CSSProperties = {\n fontSize: '11px',\n lineHeight: '16px',\n padding: '0 6px',\n borderRadius: '8px',\n color: 'var(--dsw-alias-label-tertiary)',\n border: '1px solid var(--dsw-alias-border-l2)',\n}\n\nconst delButtonStyle: CSSProperties = {\n flex: '0 0 auto',\n width: '20px',\n height: '20px',\n border: 'none',\n borderRadius: '999px',\n background: 'transparent',\n color: 'var(--dsw-alias-label-tertiary)',\n cursor: 'pointer',\n}\n\n/** Full props: the locale seat delivered by the slot system. */\nexport type SedimentSectionProps = PropsLocale<'dsh-perm-gate'>\n\nexport function SedimentSection({ t }: SedimentSectionProps): JSX.Element | null {\n const [body, setBody] = useState<LearningBody | null>(null)\n /** Latest loader, so a mutation can refresh the list without owning the fetch. */\n const reloadRef = useRef<() => void>(() => {})\n\n useEffect(() => {\n let alive = true\n const load = (): void => {\n fetch('/api/dsh-perm-gate/learning', { headers: { 'cache-control': 'no-cache' } })\n .then((r) => (r.ok ? r.json() : Promise.reject(new Error(`HTTP ${r.status}`))))\n .then((data: LearningBody) => { if (alive) setBody(data) })\n .catch(() => { if (alive) setBody({}) })\n }\n reloadRef.current = load\n load()\n // Deliberately no timer: the store only moves when this section mutates it or\n // the gate confirms a sample mid-session, so loading on mount, after every\n // action, and on return to the page covers it at zero idle cost.\n const onVisible = (): void => {\n if (document.visibilityState === 'visible') load()\n }\n window.addEventListener('focus', onVisible)\n document.addEventListener('visibilitychange', onVisible)\n return () => {\n alive = false\n reloadRef.current = () => {}\n window.removeEventListener('focus', onVisible)\n document.removeEventListener('visibilitychange', onVisible)\n }\n }, [])\n\n const post = (payload: { key: string; fp?: string }): void => {\n void fetch('/api/dsh-perm-gate/learning', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n }).then(() => { reloadRef.current() }).catch(() => {})\n }\n\n const threshold = body?.threshold ?? 3\n const confirmed = body?.confirmed ?? {}\n const samples = body?.samples ?? {}\n const keys = Object.entries(confirmed).filter(([, count]) => count >= threshold)\n\n if (body === null) return null\n return (\n <div style={{ marginTop: '6px' }}>\n {keys.length === 0\n ? <div style={{ padding: '4px 0', fontSize: '12px', color: 'var(--dsw-alias-label-tertiary)' }}>{t('card.sedimentEmpty')}</div>\n : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>\n {keys.map(([key, count]) => (\n <div key={key} style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>\n <div style={itemStyle}>\n <code style={{ font: '600 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>{key}</code>\n <span style={chipStyle}>{t('card.sedimentCount').replace('%n', String(count)).replace('%t', String(threshold))}</span>\n <span style={{ flex: '1 1 auto' }} />\n <button\n type=\"button\"\n title={t('card.sedimentStopTitle')}\n onClick={() => {\n if (window.confirm(t('card.sedimentStopConfirm').replace('%k', key))) post({ key })\n }}\n style={{ ...delButtonStyle, width: 'auto', padding: '0 8px', border: '1px solid var(--dsw-alias-border-l2)' }}\n >\n {t('card.sedimentStop')}\n </button>\n </div>\n {(samples[key] ?? []).map((s) => (\n <div key={`${key}:${s.fp}`} style={{ ...itemStyle, marginLeft: '16px' }}>\n <code style={{ flex: '1 1 auto', minWidth: 0, overflowWrap: 'anywhere', font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-secondary, inherit)' }}>\n {s.fp}\n {s.ctx !== '' ? <span style={{ color: 'var(--dsw-alias-label-tertiary)' }}>{` — ${s.ctx}`}</span> : null}\n </code>\n <button\n type=\"button\"\n aria-label={t('card.sedimentSampleRemove')}\n title={t('card.sedimentSampleRemove')}\n onClick={() => { post({ key, fp: s.fp }) }}\n style={delButtonStyle}\n >\n ✕\n </button>\n </div>\n ))}\n </div>\n ))}\n </div>\n )}\n </div>\n )\n}\n","/**\r\n * Permissive settings card — the top-level `settings.section` (自动审查门) of dsh-perm-gate.\r\n *\r\n * The card binds the plugin's profile entry (`dsh-perm-gate`) through the\r\n * `configForms` cordis service and renders its fields: the single front switch\r\n * (`permissive`) plus the three combinable backend strategies\r\n * (`trustAutoAllow` / `alwaysConfirm` / `llmAssist`). Every change commits\r\n * immediately through the scope (no staged form); the host reads the namespace\r\n * live, so a committed change applies to the next tool call without a restart.\r\n *\r\n * Kept dependency-free beyond react: the scope is subscribed with\r\n * `useSyncExternalStore`, and the controls are plain HTML.\r\n */\r\nimport { useEffect, useState, useSyncExternalStore } from 'react'\r\nimport type { CSSProperties, JSX } from 'react'\r\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\r\nimport type { SettingsDocHandle } from './compat.ts'\r\nimport { DEFAULT_DENY_KEYWORDS } from '../deny-defaults.ts'\r\nimport { LLM_PRESETS } from '../llm-presets.ts'\r\nimport { DEFAULT_GATE_PRESETS } from '../preset.ts'\r\nimport { SedimentSection } from './sediment.tsx'\r\n\r\n/** The settings namespace value the host registers (kept in lockstep with src/index.ts). */\r\nexport interface PermissiveCardValue {\r\n permissive?: boolean\r\n permissiveStrategies?: { trustAutoAllow?: boolean; alwaysConfirm?: boolean; llmAssist?: boolean; trustEscalation?: boolean }\r\n /** OpenAI-compatible endpoint the llmAssist classifier calls (custom API allowed). */\r\n classifierEndpoint?: string\r\n /** llmAssist receiver source: custom endpoint or the DSH host model group. */\r\n classifierSource?: string\r\n /** Optional provider override for the host receiver. */\r\n classifierProvider?: string\r\n /** Model id used by the llmAssist classifier. */\r\n classifierModel?: string\r\n /** Secret bearer token / API key for the classifier endpoint (masked in the UI). */\r\n classifierApiKey?: string\r\n /** Timeout for one llmAssist risk call (ms). */\r\n riskTimeoutMs?: number\r\n /** Verdict learning: neutral-risk human confirmations may auto-allow the exact same operation later. */\r\n riskLearning?: boolean\r\n /** Confirmations required before a learned auto-allow (1–10). */\r\n riskThreshold?: number\r\n /** Learning sedimentation: threshold-reached samples become deterministic auto-allows. */\r\n riskSediment?: boolean\r\n /** Editable whitelist (allow-list command patterns), one per entry. */\r\n allowlist?: string[]\r\n /** Editable deny-keyword blacklist; unset applies the inherited preset list. */\r\n denyKeywords?: string[]\r\n /**\r\n * Session permission presets in which the gate acts at all (the host's\r\n * resolved `gatePresets`). Outside them the whole gate — P0 hard-deny\r\n * included — stands down; the card states that scope so the user is not\r\n * surprised by a silent stand-down.\r\n */\r\n gatePresets?: string[]\r\n // ─── Network (Phase 2) ─────────────────────────────────────────────\r\n /** Master network switch. When false, no proxy is started. */\r\n networkEnabled?: boolean\r\n /** Network policy mode. */\r\n networkMode?: 'deny-all' | 'whitelist' | 'allow-all'\r\n /** Rewrite HTTP(S)_PROXY / ALL_PROXY for subprocesses. Default true. */\r\n networkInjectEnv?: boolean\r\n // ─── Hot reload (Phase 3) ──────────────────────────────────────────\r\n /** Enable file watching for rule hot-reload. */\r\n watch?: boolean\r\n}\r\n\r\n/** One injected face: the plugin's own settings scope. Typed as the local\r\n * structural handle (compat.ts) instead of the host package's `ConfigForm` —\r\n * the host type's shape moves between host lines (0.1.5 set/unset vs 0.2.0\r\n * mutate-centered snapshot), and the card must compile identically against\r\n * every line's real types. */\r\nexport interface PermissiveCardInjected {\r\n scope: SettingsDocHandle\r\n}\r\n\r\n/** Full props: locale seat + the injected scope. */\r\nexport type PermissiveCardProps = PropsLocale<'dsh-perm-gate'> & PermissiveCardInjected\r\n\r\n/** The receiver projection served by GET /api/dsh-perm-gate/receiver. */\r\ninterface ReceiverInfoBody {\r\n readonly ok?: boolean\r\n readonly source?: 'custom' | 'host'\r\n readonly selection?: { readonly provider: string; readonly model: string } | null\r\n readonly providers?: readonly { readonly id: string; readonly name: string; readonly models: readonly { readonly id: string; readonly name: string }[]; readonly error?: string }[]\r\n}\r\n\r\n/**\r\n * The report served by POST /api/dsh-perm-gate/dry-run. `verdict` is the\r\n * effective result of the whole chain; `ruleLayer` is what the `permissions`\r\n * chain decides on its own, and only that layer can name a rule index.\r\n */\r\ninterface DryRunReport {\r\n readonly verdict?: 'allow' | 'ask' | 'deny'\r\n readonly reason?: string\r\n readonly ruleCount?: number\r\n readonly defaultAction?: string\r\n readonly ruleLayer?: {\r\n readonly action?: 'allow' | 'ask' | 'deny'\r\n readonly reason?: string\r\n readonly ruleIndex?: number\r\n readonly matchedDimensions?: readonly string[]\r\n }\r\n}\r\n\r\n/**\r\n * The document served by GET /api/dsh-perm-gate/rules: the permissions YAML the\r\n * gate is loading, plus what it parsed to.\r\n *\r\n * `error` is a rendered state, not a transport failure. A missing or\r\n * uncompilable file is exactly what the operator opened this section to see —\r\n * a viewer that only worked on healthy input would be useless precisely when it\r\n * is needed.\r\n */\r\ninterface RulesViewBody {\r\n readonly path?: string\r\n readonly exists?: boolean\r\n readonly bytes?: number\r\n readonly hash?: string\r\n readonly lines?: number\r\n readonly raw?: string\r\n readonly truncated?: boolean\r\n readonly defaultAction?: string\r\n readonly counts?: { readonly allow?: number; readonly deny?: number; readonly ask?: number }\r\n readonly error?: string\r\n}\r\n\r\nconst rowStyle: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'space-between',\r\n gap: '12px',\r\n padding: '6px 0',\r\n fontSize: '13px',\r\n lineHeight: '20px',\r\n}\r\n\r\nconst labelStyle: CSSProperties = { margin: 0, color: 'var(--dsw-alias-label-primary)' }\r\n\r\nconst hintStyle: CSSProperties = { margin: '4px 0 0', fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' }\r\n\r\nconst sectionStyle: CSSProperties = {\r\n marginTop: '12px',\r\n paddingTop: '10px',\r\n borderTop: '1px solid var(--dsw-alias-border-l2)',\r\n}\r\n\r\nconst controlStyle: CSSProperties = {\r\n background: 'var(--dsw-alias-bg-surface, #fff)',\r\n color: 'var(--dsw-alias-label-primary)',\r\n border: '1px solid var(--dsw-alias-border-l2)',\r\n borderRadius: '4px',\r\n padding: '3px 8px',\r\n fontSize: '13px',\r\n}\r\n\r\nconst fieldStyle: CSSProperties = { display: 'flex', flexDirection: 'column', gap: '4px' }\r\n\r\nconst fieldLabelStyle: CSSProperties = { margin: 0, fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' }\r\n\r\n/**\r\n * The card body, wrapped in a disclosure shell like every peer settings card:\r\n * a header (name + description + chevron) toggling the body, expanded by\r\n * default so the section reads as an open page of drawers.\r\n */\r\nexport function PermissiveCard({ t, scope }: PermissiveCardProps): JSX.Element {\r\n // 诊断守卫(2026-10-07):scope 未解析时不能在 render 里炸——宿主设置壳对\r\n // 内容槽异常静默吞(面板空白无报错),无法与「根本没渲染」区分。守卫后\r\n // 面板显式出占位文案,把「渲染了但 scope 没到」与「没渲染」分开。\r\n // 注意:守卫分支跳过了下方 hooks,scope 到位后该实例 hook 数会变——\r\n // 仅作诊断用途,定位后移除或改为 hook 稳定形态。\r\n if (!scope) {\r\n return <div style={{ padding: 16, color: 'var(--dsw-alias-label-tertiary, #888)' }}>\r\n {t('card.unavailable')}(scope 未解析 — 诊断占位)\r\n </div>\r\n }\r\n const [open, setOpen] = useState(true)\r\n // The api key is kept OUT of the visible value (secret): a fresh typed draft\r\n // overwrites on blur; an already-set key shows only a masked placeholder.\r\n const [apiKeyDraft, setApiKeyDraft] = useState('')\r\n // Whitelist draft (one pattern per line); `allowDirty` avoids clobbering user\r\n // edits when the host re-seeds the namespace after mount.\r\n const [allowText, setAllowText] = useState('')\r\n const [allowDirty, setAllowDirty] = useState(false)\r\n const snapshot = useSyncExternalStore(\r\n (listener) => scope.subscribe(listener),\r\n () => scope.getSnapshot(),\r\n )\r\n const unavailable = snapshot.status === 'unavailable'\r\n const readonly = unavailable || !snapshot.writable\r\n const raw = (snapshot.value ?? {}) as Record<string, unknown>\r\n // 形状防御(T13b 桥轨实测):宿主各线的 settings 值可能残留非数组形态的\r\n // 列表字段(0.1.5 installSection base=resolved config,deployment patch 里\r\n // 的历史 allowlist:{} 透传到 value),卡片只认 string[]——非数组一律按空\r\n // 处理,用户在卡里保存一次即写回正确形态。\r\n const listOf = (v: unknown): string[] => (Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string') : [])\r\n const value = {\r\n ...raw,\r\n allowlist: listOf(raw.allowlist),\r\n denyKeywords: listOf(raw.denyKeywords),\r\n } as unknown as Partial<PermissiveCardValue>\r\n const strategies = value.permissiveStrategies ?? {}\r\n const hasApiKey = typeof value.classifierApiKey === 'string' && value.classifierApiKey !== ''\r\n\r\n // The backend strategy toggles only take effect while the tier is on.\r\n const effective = value.permissive === true\r\n\r\n const commitApiKey = (): void => {\r\n const next = apiKeyDraft.trim()\r\n if (next === '') return\r\n void scope.set('classifierApiKey', next)\r\n setApiKeyDraft('') // never echo the secret back after it is stored\r\n }\r\n const clearApiKey = (): void => {\r\n void scope.unset('classifierApiKey')\r\n setApiKeyDraft('')\r\n }\r\n\r\n // Show the persisted allowlist until the user starts editing a fresh draft.\r\n const allowlistShown = allowDirty ? allowText : (value.allowlist ?? []).join('\\n')\r\n const commitAllowlist = (): void => {\r\n const lines = allowlistShown.split('\\n').map((s) => s.trim()).filter((s) => s.length > 0)\r\n void scope.set('allowlist', lines)\r\n setAllowDirty(false)\r\n }\r\n // List-face state: one add-input draft plus per-row delete (approval-gate's\r\n // rules-list pattern); the bulk textarea stays behind a toggle.\r\n const [addDraft, setAddDraft] = useState('')\r\n const [bulkOpen, setBulkOpen] = useState(false)\r\n // Health-test state for the llmAssist receiver.\r\n const [healthBusy, setHealthBusy] = useState(false)\r\n const [healthResult, setHealthResult] = useState<string | null>(null)\r\n // Rule-test (dry-run) state: the call to try and its report. Read-only — the\r\n // panel never writes a rule, so \"test first\" cannot itself change the ruleset.\r\n const [dryTool, setDryTool] = useState('shell')\r\n const [dryCommand, setDryCommand] = useState('')\r\n const [dryBusy, setDryBusy] = useState(false)\r\n const [dryReport, setDryReport] = useState<DryRunReport | null>(null)\r\n const [dryError, setDryError] = useState<string | null>(null)\r\n const runDryRunTest = (): void => {\r\n const tool = dryTool.trim() === '' ? 'shell' : dryTool.trim()\r\n const command = dryCommand.trim()\r\n setDryBusy(true)\r\n setDryError(null)\r\n setDryReport(null)\r\n // A shell call is described by its `command`; any other tool's arguments are\r\n // not expressible in one line, so the panel honestly tests the empty form.\r\n const args: Record<string, unknown> = command === '' ? {} : { command }\r\n fetch('/api/dsh-perm-gate/dry-run', {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n body: JSON.stringify({ tool, args }),\r\n })\r\n .then(async (r) => {\r\n const text = await r.text()\r\n if (r.status === 404) throw new Error(t('card.dryRunStale'))\r\n try {\r\n return JSON.parse(text) as { ok?: boolean; result?: DryRunReport; error?: string }\r\n } catch {\r\n throw new Error(text.trim().slice(0, 120) !== '' ? text.trim().slice(0, 120) : `HTTP ${r.status}`)\r\n }\r\n })\r\n .then((res) => {\r\n if (res.ok === true && res.result !== undefined) setDryReport(res.result)\r\n else setDryError(res.error ?? t('card.dryRunFail'))\r\n })\r\n .catch((e: unknown) => { setDryError(String((e as Error)?.message ?? e)) })\r\n .finally(() => { setDryBusy(false) })\r\n }\r\n // Permissions YAML (read-only): the document the gate is actually loading, so\r\n // the panel can never be editing a file it cannot display. Loaded on mount —\r\n // a viewer you have to ask to load is one more reason not to look.\r\n const [rulesBody, setRulesBody] = useState<RulesViewBody | null>(null)\r\n const [rulesBusy, setRulesBusy] = useState(false)\r\n const [rulesError, setRulesError] = useState<string | null>(null)\r\n const loadRules = (): void => {\r\n setRulesBusy(true)\r\n setRulesError(null)\r\n fetch('/api/dsh-perm-gate/rules', { headers: { 'cache-control': 'no-cache' } })\r\n .then(async (r) => {\r\n const text = await r.text()\r\n if (r.status === 404) throw new Error(t('card.rulesStale'))\r\n try {\r\n return JSON.parse(text) as { ok?: boolean; result?: RulesViewBody; error?: string }\r\n } catch {\r\n throw new Error(text.trim().slice(0, 120) !== '' ? text.trim().slice(0, 120) : `HTTP ${r.status}`)\r\n }\r\n })\r\n .then((res) => {\r\n if (res.ok === true && res.result !== undefined) setRulesBody(res.result)\r\n else setRulesError(res.error ?? t('card.rulesError'))\r\n })\r\n .catch((e: unknown) => { setRulesError(String((e as Error)?.message ?? e)) })\r\n .finally(() => { setRulesBusy(false) })\r\n }\r\n useEffect(() => { loadRules() }, [])\r\n // Receiver introspection: the live provider/model-group catalog (host mode)\r\n // and the provider/model the gate will actually use right now.\r\n const receiverSource = (value.classifierSource ?? 'custom') === 'host' ? 'host' : 'custom'\r\n const [receiverInfo, setReceiverInfo] = useState<ReceiverInfoBody | null>(null)\r\n const [receiverNonce, setReceiverNonce] = useState(0)\r\n useEffect(() => {\r\n let alive = true\r\n fetch('/api/dsh-perm-gate/receiver', { headers: { 'cache-control': 'no-cache' } })\r\n .then((r) => (r.ok ? r.json() : Promise.reject(new Error(`HTTP ${r.status}`))))\r\n .then((data: ReceiverInfoBody) => { if (alive) setReceiverInfo(data) })\r\n .catch(() => { if (alive) setReceiverInfo(null) })\r\n return () => { alive = false }\r\n }, [receiverSource, receiverNonce])\r\n const receiverProviderDraft = value.classifierProvider ?? ''\r\n const patterns = value.allowlist ?? []\r\n const removePattern = (index: number): void => {\r\n void scope.set('allowlist', patterns.filter((_, i) => i !== index))\r\n }\r\n const addPattern = (): void => {\r\n const next = addDraft.trim()\r\n if (next === '' || readonly) return\r\n void scope.set('allowlist', [...patterns, next])\r\n setAddDraft('')\r\n }\r\n // Deny-keyword blacklist: an explicit non-empty namespace array replaces the\r\n // preset; unset OR empty (schemastery materializes unset arrays as `[]`)\r\n // applies the inherited defaults — the protective blacklist is never off.\r\n const denyActive = Array.isArray(value.denyKeywords) && value.denyKeywords.length > 0\r\n const denylist = denyActive ? (value.denyKeywords as string[]) : [...DEFAULT_DENY_KEYWORDS]\r\n const [denyDraft, setDenyDraft] = useState('')\r\n const removeDeny = (index: number): void => {\r\n void scope.set('denyKeywords', denylist.filter((_, i) => i !== index))\r\n }\r\n const addDeny = (): void => {\r\n const next = denyDraft.trim()\r\n if (next === '' || readonly) return\r\n void scope.set('denyKeywords', [...denylist, next])\r\n setDenyDraft('')\r\n }\r\n const restoreDeny = (): void => {\r\n void scope.unset('denyKeywords')\r\n }\r\n\r\n return (\r\n <div style={{\r\n border: '1px solid var(--dsw-alias-border-l2, rgba(127,127,127,0.35))',\r\n background: 'var(--dsw-alias-bg-layer-3, rgba(127,127,127,0.05))',\r\n borderRadius: '12px',\r\n transition: 'border-color 0.16s, background 0.16s',\r\n }}>\r\n <button\r\n type=\"button\"\r\n aria-expanded={open}\r\n style={{\r\n appearance: 'none',\r\n width: '100%',\r\n font: 'inherit',\r\n color: 'inherit',\r\n textAlign: 'left',\r\n cursor: 'pointer',\r\n background: 'none',\r\n border: 0,\r\n borderRadius: '12px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '12px',\r\n padding: '14px 16px',\r\n }}\r\n onClick={() => { setOpen(current => !current) }}\r\n >\r\n <span style={{ flex: '1 1 0%', minWidth: 0 }}>\r\n <div style={{ fontSize: '14px', fontWeight: 600, color: 'var(--dsw-alias-label-primary)' }}>{t('card.title')}</div>\r\n <div style={{ color: 'var(--dsw-alias-label-tertiary, rgba(127,127,127,0.8))', fontSize: '13px', lineHeight: 1.5 }}>{t('card.description')}</div>\r\n </span>\r\n <svg\r\n width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden\r\n style={{\r\n color: 'var(--dsw-alias-label-tertiary, rgba(127,127,127,0.8))',\r\n flex: '0 0 auto',\r\n transition: 'transform 0.16s',\r\n transform: open ? 'rotate(180deg)' : 'none',\r\n }}\r\n >\r\n <path d=\"M4 6l4 4 4-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n </button>\r\n {open\r\n ? (\r\n <div style={{ padding: '12px 16px' }}>\r\n {unavailable\r\n ? (\r\n <div style={{ fontSize: '13px', color: 'var(--dsw-alias-label-tertiary)' }}>\r\n {t('card.unavailable')}\r\n </div>\r\n )\r\n : (\r\n <>\r\n <div style={rowStyle}>\r\n <label htmlFor=\"plugin-config-perm-gate-permissive\" style={labelStyle}>{t('card.permissive')}</label>\r\n <input\r\n id=\"plugin-config-perm-gate-permissive\"\r\n type=\"checkbox\"\r\n checked={effective}\r\n disabled={readonly}\r\n onChange={(event) => { void scope.set('permissive', event.currentTarget.checked) }}\r\n />\r\n </div>\r\n <p style={hintStyle}>{t('card.permissiveHint')}</p>\r\n {/* The gate's own scope: outside these presets the WHOLE gate\r\n stands down, P0 hard-deny included (see the stand-down note\r\n in src/runtime.ts). Stated here because the settings card is\r\n where the tier is configured, and a silent stand-down would\r\n otherwise look like a gate that approved the call. */}\r\n <p style={hintStyle}>\r\n {t('card.scopeNote').replace(\r\n '%scope',\r\n ((value.gatePresets ?? []).length > 0 ? (value.gatePresets as string[]) : [...DEFAULT_GATE_PRESETS]).join(' / '),\r\n )}\r\n </p>\r\n\r\n <section style={sectionStyle}>\r\n <p style={labelStyle}>{t('card.strategies')}</p>\r\n <div style={rowStyle}>\r\n <label htmlFor=\"plugin-config-perm-gate-trust\" style={{ fontSize: '12px' }}>{t('card.strategy.trustAutoAllow')}</label>\r\n <input\r\n id=\"plugin-config-perm-gate-trust\"\r\n type=\"checkbox\"\r\n checked={strategies.trustAutoAllow ?? true}\r\n disabled={readonly || !effective}\r\n onChange={(event) => {\r\n void scope.set('permissiveStrategies', {\r\n ...strategies,\r\n trustAutoAllow: event.currentTarget.checked,\r\n })\r\n }}\r\n />\r\n </div>\r\n <div style={rowStyle}>\r\n <label htmlFor=\"plugin-config-perm-gate-confirm\" style={{ fontSize: '12px' }}>{t('card.strategy.alwaysConfirm')}</label>\r\n <input\r\n id=\"plugin-config-perm-gate-confirm\"\r\n type=\"checkbox\"\r\n checked={strategies.alwaysConfirm ?? false}\r\n disabled={readonly || !effective}\r\n onChange={(event) => {\r\n void scope.set('permissiveStrategies', {\r\n ...strategies,\r\n alwaysConfirm: event.currentTarget.checked,\r\n })\r\n }}\r\n />\r\n </div>\r\n <div style={rowStyle}>\r\n <label htmlFor=\"plugin-config-perm-gate-llm\" style={{ fontSize: '12px' }}>{t('card.strategy.llmAssist')}</label>\r\n <input\r\n id=\"plugin-config-perm-gate-llm\"\r\n type=\"checkbox\"\r\n checked={strategies.llmAssist ?? false}\r\n disabled={readonly || !effective}\r\n onChange={(event) => {\r\n void scope.set('permissiveStrategies', {\r\n ...strategies,\r\n llmAssist: event.currentTarget.checked,\r\n })\r\n }}\r\n />\r\n </div>\r\n <div style={rowStyle}>\r\n <label htmlFor=\"plugin-config-perm-gate-escalation\" style={{ fontSize: '12px' }}>{t('card.strategy.trustEscalation')}</label>\r\n <input\r\n id=\"plugin-config-perm-gate-escalation\"\r\n type=\"checkbox\"\r\n checked={strategies.trustEscalation ?? true}\r\n disabled={readonly || !effective}\r\n onChange={(event) => {\r\n void scope.set('permissiveStrategies', {\r\n ...strategies,\r\n trustEscalation: event.currentTarget.checked,\r\n })\r\n }}\r\n />\r\n </div>\r\n <p style={hintStyle}>{t('card.strategy.trustEscalationHint')}</p>\r\n {strategies.llmAssist === true\r\n ? (\r\n <section style={sectionStyle}>\r\n <p style={labelStyle}>{t('card.llmReceiver')}</p>\r\n <label style={fieldStyle}>\r\n <span style={fieldLabelStyle}>{t('card.llmSource')}</span>\r\n <select\r\n value={value.classifierSource ?? 'custom'}\r\n disabled={readonly}\r\n style={controlStyle}\r\n onChange={(event) => { void scope.set('classifierSource', event.currentTarget.value) }}\r\n >\r\n <option value=\"custom\">{t('card.llmSourceCustom')}</option>\r\n <option value=\"host\">{t('card.llmSourceHost')}</option>\r\n </select>\r\n </label>\r\n {(value.classifierSource ?? 'custom') === 'custom'\r\n ? (\r\n <>\r\n <label style={fieldStyle}>\r\n <span style={fieldLabelStyle}>{t('card.llmPreset')}</span>\r\n <select\r\n value=\"\"\r\n disabled={readonly}\r\n style={controlStyle}\r\n onChange={(event) => {\r\n const v = event.currentTarget.value\r\n if (v.startsWith('host:')) {\r\n // A DSH model group: switch to the host receiver\r\n // and pin the provider (model follows the session).\r\n void scope.set('classifierSource', 'host')\r\n void scope.set('classifierProvider', v.slice('host:'.length))\r\n return\r\n }\r\n const preset = LLM_PRESETS.find((p) => p.id === v)\r\n if (preset !== undefined) {\r\n void scope.set('classifierEndpoint', preset.endpoint)\r\n void scope.set('classifierModel', preset.model)\r\n }\r\n }}\r\n >\r\n <option value=\"\">{t('card.llmPresetChoose')}</option>\r\n <optgroup label={t('card.llmPresetPublic')}>\r\n {LLM_PRESETS.map((preset) => (\r\n <option key={preset.id} value={preset.id}>{preset.label}</option>\r\n ))}\r\n </optgroup>\r\n {(receiverInfo?.providers ?? []).length > 0\r\n ? (\r\n <optgroup label={t('card.llmPresetHost')}>\r\n {(receiverInfo?.providers ?? []).map((p) => (\r\n <option key={`host:${p.id}`} value={`host:${p.id}`}>\r\n {`${t('card.llmSourceHost')} · ${p.id}`}\r\n </option>\r\n ))}\r\n </optgroup>\r\n )\r\n : null}\r\n </select>\r\n </label>\r\n <label style={fieldStyle}>\r\n <span style={fieldLabelStyle}>{t('card.llmEndpoint')}</span>\r\n <input\r\n type=\"text\"\r\n value={value.classifierEndpoint ?? ''}\r\n disabled={readonly}\r\n placeholder=\"https://api.openai.com/v1\"\r\n style={controlStyle}\r\n onChange={(event) => { void scope.set('classifierEndpoint', event.currentTarget.value) }}\r\n onBlur={(event) => {\r\n if (event.currentTarget.value.trim() === '') void scope.unset('classifierEndpoint')\r\n }}\r\n />\r\n </label>\r\n </>\r\n )\r\n : (\r\n <>\r\n <p style={hintStyle}>{t('card.llmSourceHostHint')}</p>\r\n <label style={fieldStyle}>\r\n <span style={fieldLabelStyle}>{t('card.llmProvider')}</span>\r\n <input\r\n type=\"text\"\r\n list=\"perm-gate-provider-options\"\r\n value={value.classifierProvider ?? ''}\r\n disabled={readonly}\r\n placeholder={t('card.llmProviderPlaceholder')}\r\n style={controlStyle}\r\n onChange={(event) => { void scope.set('classifierProvider', event.currentTarget.value) }}\r\n onBlur={(event) => {\r\n if (event.currentTarget.value.trim() === '') void scope.unset('classifierProvider')\r\n }}\r\n />\r\n <datalist id=\"perm-gate-provider-options\">\r\n {(receiverInfo?.providers ?? []).map((p) => (\r\n <option key={p.id} value={p.id}>{p.name}{p.error !== undefined ? ` (${p.error})` : ''}</option>\r\n ))}\r\n </datalist>\r\n </label>\r\n {receiverInfo?.selection !== null && receiverInfo?.selection !== undefined\r\n ? (\r\n <span style={hintStyle}>\r\n {t('card.llmResolved')\r\n .replace('%p', receiverInfo.selection.provider)\r\n .replace('%m', receiverInfo.selection.model)}\r\n </span>\r\n )\r\n : null}\r\n </>\r\n )}\r\n <label style={fieldStyle}>\r\n <span style={fieldLabelStyle}>{t('card.llmModel')}</span>\r\n <input\r\n type=\"text\"\r\n list={receiverSource === 'host' ? 'perm-gate-model-options' : undefined}\r\n value={value.classifierModel ?? ''}\r\n disabled={readonly}\r\n placeholder={receiverSource === 'host' ? t('card.llmModelHostPlaceholder') : 'deepseek-chat'}\r\n style={controlStyle}\r\n onChange={(event) => { void scope.set('classifierModel', event.currentTarget.value) }}\r\n onBlur={(event) => {\r\n if (event.currentTarget.value.trim() === '') void scope.unset('classifierModel')\r\n }}\r\n />\r\n <datalist id=\"perm-gate-model-options\">\r\n {(receiverInfo?.providers ?? [])\r\n .filter((p) => receiverProviderDraft === '' || p.id === receiverProviderDraft)\r\n .flatMap((p) => p.models)\r\n .map((m) => <option key={`${m.id}`} value={m.id}>{m.name}</option>)}\r\n </datalist>\r\n </label>\r\n <label style={fieldStyle}>\r\n <span style={fieldLabelStyle}>{t('card.llmKey')}</span>\r\n <div style={{ display: 'flex', gap: '6px' }}>\r\n <input\r\n type=\"password\"\r\n autoComplete=\"off\"\r\n spellCheck={false}\r\n value={apiKeyDraft}\r\n disabled={readonly}\r\n placeholder={hasApiKey ? t('card.llmKeyMasked') : t('card.llmKeyHidden')}\r\n style={{ ...controlStyle, flex: '1 1 0%' }}\r\n onChange={(event) => setApiKeyDraft(event.currentTarget.value)}\r\n onBlur={commitApiKey}\r\n onKeyDown={(event) => {\r\n if (event.key === 'Enter') (event.currentTarget as HTMLInputElement).blur()\r\n }}\r\n />\r\n {hasApiKey\r\n ? (\r\n <button type=\"button\" disabled={readonly} onClick={clearApiKey} style={controlStyle}>\r\n {t('card.llmKeyClear')}\r\n </button>\r\n )\r\n : null}\r\n </div>\r\n {hasApiKey && <span style={hintStyle}>{t('card.llmKeyOverwrite')}</span>}\r\n </label>\r\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '4px' }}>\r\n <button\r\n type=\"button\"\r\n disabled={readonly || healthBusy}\r\n onClick={() => {\r\n setHealthBusy(true)\r\n setHealthResult(null)\r\n // The dsh webServer rejects bodyless POSTs, so send a\r\n // JSON envelope; parse defensively either way.\r\n fetch('/api/dsh-perm-gate/health', {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n body: '{}',\r\n })\r\n .then(async (r) => {\r\n const text = await r.text()\r\n if (r.status === 404) throw new Error(t('card.healthStale'))\r\n try {\r\n return JSON.parse(text) as { ok?: boolean; ms?: number; detail?: string; error?: string }\r\n } catch {\r\n throw new Error(text.trim().slice(0, 120) !== '' ? text.trim().slice(0, 120) : `HTTP ${r.status}`)\r\n }\r\n })\r\n .then((res) => {\r\n setHealthResult(res.ok === true && typeof res.ms === 'number'\r\n ? t('card.healthOk').replace('%ms', String(res.ms)) + (typeof res.detail === 'string' ? ` · ${res.detail}` : '')\r\n : t('card.healthFail') + (res.detail ?? res.error ?? 'unknown'))\r\n setReceiverNonce((n) => n + 1)\r\n })\r\n .catch((e: unknown) => { setHealthResult(t('card.healthFail') + String((e as Error)?.message ?? e)) })\r\n .finally(() => { setHealthBusy(false) })\r\n }}\r\n style={{ ...controlStyle, cursor: readonly || healthBusy ? 'default' : 'pointer' }}\r\n >\r\n {healthBusy ? t('card.healthRunning') : t('card.healthTest')}\r\n </button>\r\n {healthResult !== null && (\r\n <span style={{ fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-secondary, inherit)', overflowWrap: 'anywhere' }}>\r\n {healthResult}\r\n </span>\r\n )}\r\n </div>\r\n <div style={rowStyle}>\r\n <label htmlFor=\"plugin-config-perm-gate-risk-learning\" style={{ fontSize: '12px' }}>{t('card.riskLearning')}</label>\r\n <input\r\n id=\"plugin-config-perm-gate-risk-learning\"\r\n type=\"checkbox\"\r\n checked={value.riskLearning ?? false}\r\n disabled={readonly || !effective}\r\n onChange={(event) => { void scope.set('riskLearning', event.currentTarget.checked) }}\r\n />\r\n </div>\r\n <p style={hintStyle}>{t('card.riskLearningHint')}</p>\r\n {value.riskLearning === true\r\n ? (\r\n <label style={fieldStyle}>\r\n <span style={fieldLabelStyle}>{t('card.riskThreshold')}</span>\r\n <input\r\n id=\"plugin-config-perm-gate-risk-threshold\"\r\n type=\"number\"\r\n min={1}\r\n max={10}\r\n value={value.riskThreshold ?? 3}\r\n disabled={readonly || !effective}\r\n style={{ ...controlStyle, width: '96px' }}\r\n onChange={(event) => {\r\n const n = Number.parseInt(event.currentTarget.value, 10)\r\n if (Number.isFinite(n) && n >= 1 && n <= 10) void scope.set('riskThreshold', n)\r\n }}\r\n />\r\n </label>\r\n )\r\n : null}\r\n {value.riskLearning === true\r\n ? (\r\n <>\r\n <div style={rowStyle}>\r\n <label htmlFor=\"plugin-config-perm-gate-risk-sediment\" style={{ fontSize: '12px' }}>{t('card.riskSediment')}</label>\r\n <input\r\n id=\"plugin-config-perm-gate-risk-sediment\"\r\n type=\"checkbox\"\r\n checked={value.riskSediment ?? true}\r\n disabled={readonly || !effective}\r\n onChange={(event) => { void scope.set('riskSediment', event.currentTarget.checked) }}\r\n />\r\n </div>\r\n <p style={hintStyle}>{t('card.riskSedimentHint')}</p>\r\n <div style={sectionStyle}>\r\n <p style={labelStyle}>{t('card.sediment')}</p>\r\n <p style={hintStyle}>{t('card.sedimentHint')}</p>\r\n <SedimentSection t={t} />\r\n </div>\r\n </>\r\n )\r\n : null}\r\n </section>\r\n )\r\n : null}\r\n </section>\r\n\r\n <section style={sectionStyle}>\r\n <p style={labelStyle}>{t('card.dryRun')}</p>\r\n <p style={hintStyle}>{t('card.dryRunHint')}</p>\r\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', alignItems: 'flex-end', margin: '6px 0' }}>\r\n <label style={{ display: 'flex', flexDirection: 'column', gap: '4px', flex: '0 0 120px' }}>\r\n <span style={fieldLabelStyle}>{t('card.dryRunTool')}</span>\r\n <input\r\n type=\"text\"\r\n value={dryTool}\r\n disabled={readonly}\r\n placeholder=\"shell\"\r\n onChange={(e) => { setDryTool(e.target.value) }}\r\n onKeyDown={(e) => { if (e.key === 'Enter') runDryRunTest() }}\r\n style={controlStyle}\r\n />\r\n </label>\r\n <label style={{ display: 'flex', flexDirection: 'column', gap: '4px', flex: '1 1 260px', minWidth: 0 }}>\r\n <span style={fieldLabelStyle}>{t('card.dryRunCommand')}</span>\r\n <input\r\n type=\"text\"\r\n value={dryCommand}\r\n disabled={readonly}\r\n placeholder={t('card.dryRunCommandPlaceholder')}\r\n onChange={(e) => { setDryCommand(e.target.value) }}\r\n onKeyDown={(e) => { if (e.key === 'Enter') runDryRunTest() }}\r\n style={controlStyle}\r\n />\r\n </label>\r\n <button\r\n type=\"button\"\r\n disabled={readonly || dryBusy}\r\n onClick={runDryRunTest}\r\n style={{ ...controlStyle, flex: '0 0 auto', cursor: readonly || dryBusy ? 'default' : 'pointer' }}\r\n >\r\n {dryBusy ? t('card.dryRunRunning') : t('card.dryRunTest')}\r\n </button>\r\n </div>\r\n {dryError !== null && (\r\n <p style={{ ...hintStyle, color: 'var(--dsw-alias-label-error, #c0392b)' }}>{t('card.dryRunFail')}{dryError}</p>\r\n )}\r\n {dryReport === null\r\n ? (dryError === null && <p style={hintStyle}>{t('card.dryRunEmpty')}</p>)\r\n : (\r\n <div\r\n style={{\r\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: '4px',\r\n padding: '8px 10px',\r\n borderRadius: '6px',\r\n border: '1px solid var(--dsw-alias-border-l2)',\r\n background: 'var(--dsw-alias-bg-surface, transparent)',\r\n fontSize: '12px',\r\n lineHeight: '18px',\r\n }}\r\n >\r\n {/* The verdict badge: colour carries the same meaning as the word. */}\r\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\r\n <span style={fieldLabelStyle}>{t('card.dryRunVerdict')}</span>\r\n {(() => {\r\n const verdict = dryReport.verdict ?? 'ask'\r\n const colour = verdict === 'deny'\r\n ? 'var(--dsw-alias-label-error, #c0392b)'\r\n : verdict === 'allow'\r\n ? 'var(--dsw-alias-label-success, #2e7d32)'\r\n : 'var(--dsw-alias-label-warning, #b26a00)'\r\n const text = verdict === 'deny'\r\n ? t('card.dryRunDeny')\r\n : verdict === 'allow' ? t('card.dryRunAllow') : t('card.dryRunAsk')\r\n return <strong style={{ color: colour }}>{text}</strong>\r\n })()}\r\n {(dryReport.ruleCount ?? 0) === 0 && (\r\n <span style={{ color: 'var(--dsw-alias-label-secondary, inherit)' }}>{t('card.dryRunNoRules')}</span>\r\n )}\r\n </div>\r\n <div style={{ display: 'flex', gap: '8px', overflowWrap: 'anywhere' }}>\r\n <span style={fieldLabelStyle}>{t('card.dryRunRule')}</span>\r\n <code style={{ font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\r\n {dryReport.ruleLayer?.ruleIndex === undefined\r\n ? t('card.dryRunRuleNone').replace('%d', dryReport.defaultAction ?? 'ask')\r\n : `#${dryReport.ruleLayer.ruleIndex} (${dryReport.ruleLayer.action ?? '?'})`}\r\n </code>\r\n </div>\r\n <div style={{ display: 'flex', gap: '8px', overflowWrap: 'anywhere' }}>\r\n <span style={fieldLabelStyle}>{t('card.dryRunDimensions')}</span>\r\n <code style={{ font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\r\n {(dryReport.ruleLayer?.matchedDimensions ?? []).length === 0\r\n ? '—'\r\n : (dryReport.ruleLayer?.matchedDimensions ?? []).join(', ')}\r\n </code>\r\n </div>\r\n <div style={{ display: 'flex', gap: '8px', overflowWrap: 'anywhere' }}>\r\n <span style={fieldLabelStyle}>{t('card.dryRunReason')}</span>\r\n <span style={{ color: 'var(--dsw-alias-label-secondary, inherit)' }}>{dryReport.reason ?? ''}</span>\r\n </div>\r\n <p style={{ ...hintStyle, margin: 0 }}>{t('card.dryRunNote')}</p>\r\n </div>\r\n )}\r\n </section>\r\n\r\n <section style={sectionStyle}>\r\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '8px' }}>\r\n <p style={labelStyle}>{t('card.rules')}</p>\r\n <button\r\n type=\"button\"\r\n disabled={rulesBusy}\r\n onClick={loadRules}\r\n style={{ ...controlStyle, flex: '0 0 auto', cursor: rulesBusy ? 'default' : 'pointer' }}\r\n >\r\n {rulesBusy ? t('card.rulesLoading') : t('card.rulesRefresh')}\r\n </button>\r\n </div>\r\n <p style={hintStyle}>{t('card.rulesHint')}</p>\r\n\r\n <div style={{ display: 'flex', gap: '8px', overflowWrap: 'anywhere', marginTop: '6px' }}>\r\n <span style={fieldLabelStyle}>{t('card.rulesPath')}</span>\r\n <code style={{ font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\r\n {rulesBody?.path !== undefined && rulesBody.path !== '' ? rulesBody.path : t('card.rulesNone')}\r\n </code>\r\n </div>\r\n\r\n {rulesError !== null && (\r\n <p style={{ ...hintStyle, color: 'var(--dsw-alias-label-error, #c0392b)' }}>{t('card.rulesError')}{rulesError}</p>\r\n )}\r\n\r\n {rulesBody !== null && (\r\n <>\r\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '12px', marginTop: '4px' }}>\r\n <span>\r\n <span style={fieldLabelStyle}>{t('card.rulesCounts')} </span>\r\n <code style={{ font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\r\n {`deny ${rulesBody.counts?.deny ?? 0} · allow ${rulesBody.counts?.allow ?? 0} · ask ${rulesBody.counts?.ask ?? 0}`}\r\n </code>\r\n </span>\r\n {rulesBody.defaultAction !== undefined && (\r\n <span>\r\n <span style={fieldLabelStyle}>{t('card.rulesDefault')} </span>\r\n <code style={{ font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\r\n {rulesBody.defaultAction}\r\n </code>\r\n </span>\r\n )}\r\n <span style={fieldLabelStyle}>\r\n {t('card.rulesStats')\r\n .replace('%b', String(rulesBody.bytes ?? 0))\r\n .replace('%l', String(rulesBody.lines ?? 0))}\r\n </span>\r\n </div>\r\n\r\n {/* Why the document did not load or did not compile. The text below is still shown. */}\r\n {rulesBody.error !== undefined && (\r\n <p style={{ ...hintStyle, color: 'var(--dsw-alias-label-error, #c0392b)' }}>{rulesBody.error}</p>\r\n )}\r\n {rulesBody.exists === false && <p style={hintStyle}>{t('card.rulesMissing')}</p>}\r\n {rulesBody.truncated === true && <p style={hintStyle}>{t('card.rulesTruncated')}</p>}\r\n\r\n {(rulesBody.raw ?? '') !== '' && (\r\n <pre\r\n style={{\r\n margin: '6px 0 0',\r\n padding: '8px 10px',\r\n maxHeight: '260px',\r\n overflow: 'auto',\r\n borderRadius: '6px',\r\n border: '1px solid var(--dsw-alias-border-l2)',\r\n background: 'var(--dsw-alias-bg-surface, transparent)',\r\n font: '500 12px/18px var(--ds-font-family-code, monospace)',\r\n color: 'var(--dsw-alias-label-primary)',\r\n whiteSpace: 'pre',\r\n }}\r\n >\r\n {rulesBody.raw}\r\n </pre>\r\n )}\r\n <p style={{ ...hintStyle, margin: 0 }}>{t('card.rulesNote')}</p>\r\n </>\r\n )}\r\n </section>\r\n\r\n <section style={sectionStyle}>\r\n <p style={labelStyle}>{t('card.allowlist')}</p>\r\n <p style={hintStyle}>{t('card.allowlistHint')}</p>\r\n <p style={hintStyle}>{t('card.allowlistPresetNote')}</p>\r\n {patterns.length === 0\r\n ? (\r\n <div style={{ padding: '6px 0', fontSize: '12px', color: 'var(--dsw-alias-label-tertiary)' }}>\r\n {t('card.allowlistEmpty')}\r\n </div>\r\n )\r\n : (\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '4px', margin: '6px 0' }}>\r\n {patterns.map((pattern, index) => (\r\n <div\r\n key={`${index}:${pattern}`}\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n padding: '4px 8px',\r\n borderRadius: '6px',\r\n border: '1px solid var(--dsw-alias-border-l2)',\r\n background: 'var(--dsw-alias-bg-surface, transparent)',\r\n }}\r\n >\r\n <code style={{ flex: '1 1 auto', minWidth: 0, overflowWrap: 'anywhere', font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\r\n {pattern}\r\n </code>\r\n <button\r\n type=\"button\"\r\n aria-label={t('card.allowlistRemove')}\r\n title={t('card.allowlistRemove')}\r\n disabled={readonly}\r\n onClick={() => { removePattern(index) }}\r\n style={{\r\n flex: '0 0 auto',\r\n width: '20px',\r\n height: '20px',\r\n border: 'none',\r\n borderRadius: '999px',\r\n background: 'transparent',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n cursor: readonly ? 'default' : 'pointer',\r\n }}\r\n >\r\n ✕\r\n </button>\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n <div style={{ display: 'flex', gap: '6px', marginTop: '6px' }}>\r\n <input\r\n type=\"text\"\r\n value={addDraft}\r\n disabled={readonly}\r\n placeholder={t('card.allowlistPlaceholder')}\r\n spellCheck={false}\r\n style={{ ...controlStyle, flex: '1 1 auto', minWidth: 0 }}\r\n onChange={(event) => { setAddDraft(event.currentTarget.value) }}\r\n onKeyDown={(event) => {\r\n if (event.key === 'Enter') addPattern()\r\n }}\r\n />\r\n <button\r\n type=\"button\"\r\n disabled={readonly || addDraft.trim() === ''}\r\n onClick={addPattern}\r\n style={{\r\n ...controlStyle,\r\n flex: '0 0 auto',\r\n cursor: readonly || addDraft.trim() === '' ? 'default' : 'pointer',\r\n opacity: readonly || addDraft.trim() === '' ? 0.5 : 1,\r\n }}\r\n >\r\n {t('card.allowlistAdd')}\r\n </button>\r\n </div>\r\n <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '6px' }}>\r\n <button\r\n type=\"button\"\r\n onClick={() => { setBulkOpen(current => !current) }}\r\n style={{ ...controlStyle, cursor: 'pointer', border: 'none', background: 'transparent', color: 'var(--dsw-alias-label-tertiary)' }}\r\n >\r\n {bulkOpen ? t('card.allowlistBulkHide') : t('card.allowlistBulk')}\r\n </button>\r\n </div>\r\n {bulkOpen\r\n ? (\r\n <>\r\n <textarea\r\n id=\"plugin-config-perm-gate-allowlist\"\r\n value={allowlistShown}\r\n disabled={readonly}\r\n rows={6}\r\n spellCheck={false}\r\n style={{\r\n ...controlStyle,\r\n width: '100%',\r\n boxSizing: 'border-box',\r\n resize: 'vertical',\r\n fontFamily: 'var(--ds-font-family-code, monospace)',\r\n whiteSpace: 'pre',\r\n }}\r\n onChange={(event) => {\r\n setAllowDirty(true)\r\n setAllowText(event.currentTarget.value)\r\n }}\r\n onKeyDown={(event) => {\r\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) commitAllowlist()\r\n }}\r\n />\r\n <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '6px' }}>\r\n <button\r\n type=\"button\"\r\n disabled={readonly || !allowDirty}\r\n onClick={commitAllowlist}\r\n style={{\r\n ...controlStyle,\r\n cursor: readonly || !allowDirty ? 'default' : 'pointer',\r\n opacity: readonly || !allowDirty ? 0.5 : 1,\r\n }}\r\n >\r\n {t('card.allowlistSave')}\r\n </button>\r\n </div>\r\n </>\r\n )\r\n : null}\r\n </section>\r\n\r\n <section style={sectionStyle}>\r\n <p style={labelStyle}>{t('card.denylist')}</p>\r\n <p style={hintStyle}>{t('card.denylistHint')}</p>\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '4px', margin: '6px 0' }}>\r\n {denylist.map((keyword, index) => {\r\n const preset = (DEFAULT_DENY_KEYWORDS as readonly string[]).includes(keyword)\r\n return (\r\n <div\r\n key={`${index}:${keyword}`}\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n padding: '4px 8px',\r\n borderRadius: '6px',\r\n border: '1px solid var(--dsw-alias-border-l2)',\r\n background: 'var(--dsw-alias-bg-surface, transparent)',\r\n }}\r\n >\r\n <code style={{ flex: '1 1 auto', minWidth: 0, overflowWrap: 'anywhere', font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>\r\n {keyword}\r\n </code>\r\n <span\r\n style={{\r\n flex: '0 0 auto',\r\n fontSize: '11px',\r\n lineHeight: '16px',\r\n padding: '0 6px',\r\n borderRadius: '8px',\r\n color: preset ? 'var(--dsw-alias-label-tertiary)' : 'var(--dsw-alias-label-secondary, inherit)',\r\n border: '1px solid var(--dsw-alias-border-l2)',\r\n }}\r\n >\r\n {preset ? t('card.denylistTagPreset') : t('card.denylistTagCustom')}\r\n </span>\r\n <button\r\n type=\"button\"\r\n aria-label={t('card.denylistRemove')}\r\n title={t('card.denylistRemove')}\r\n disabled={readonly}\r\n onClick={() => { removeDeny(index) }}\r\n style={{\r\n flex: '0 0 auto',\r\n width: '20px',\r\n height: '20px',\r\n border: 'none',\r\n borderRadius: '999px',\r\n background: 'transparent',\r\n color: 'var(--dsw-alias-label-tertiary)',\r\n cursor: readonly ? 'default' : 'pointer',\r\n }}\r\n >\r\n ✕\r\n </button>\r\n </div>\r\n )\r\n })}\r\n </div>\r\n <div style={{ display: 'flex', gap: '6px', marginTop: '6px' }}>\r\n <input\r\n type=\"text\"\r\n value={denyDraft}\r\n disabled={readonly}\r\n placeholder={t('card.denylistPlaceholder')}\r\n spellCheck={false}\r\n style={{ ...controlStyle, flex: '1 1 auto', minWidth: 0 }}\r\n onChange={(event) => { setDenyDraft(event.currentTarget.value) }}\r\n onKeyDown={(event) => {\r\n if (event.key === 'Enter') addDeny()\r\n }}\r\n />\r\n <button\r\n type=\"button\"\r\n disabled={readonly || denyDraft.trim() === ''}\r\n onClick={addDeny}\r\n style={{\r\n ...controlStyle,\r\n flex: '0 0 auto',\r\n cursor: readonly || denyDraft.trim() === '' ? 'default' : 'pointer',\r\n opacity: readonly || denyDraft.trim() === '' ? 0.5 : 1,\r\n }}\r\n >\r\n {t('card.denylistAdd')}\r\n </button>\r\n </div>\r\n {denyActive\r\n ? (\r\n <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '6px' }}>\r\n <button\r\n type=\"button\"\r\n disabled={readonly}\r\n onClick={restoreDeny}\r\n style={{ ...controlStyle, cursor: readonly ? 'default' : 'pointer', border: 'none', background: 'transparent', color: 'var(--dsw-alias-label-tertiary)' }}\r\n >\r\n {t('card.denylistRestore')}\r\n </button>\r\n </div>\r\n )\r\n : null}\r\n </section>\r\n\r\n {/* ─── Network master switch (Phase 2) ─── */}\r\n <section style={sectionStyle}>\r\n <p style={labelStyle}>{t('card.networkEnabled')}</p>\r\n <p style={hintStyle}>{t('card.networkEnabledHint')}</p>\r\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '6px' }}>\r\n <input\r\n type=\"checkbox\"\r\n checked={value.networkEnabled === true}\r\n disabled={readonly}\r\n onChange={(event) => { void scope.set('networkEnabled', event.currentTarget.checked) }}\r\n />\r\n <span style={{ fontSize: '13px' }}>{value.networkEnabled === true ? 'ON' : 'OFF'}</span>\r\n </div>\r\n <p style={hintStyle}>{t('card.networkRebindNote')}</p>\r\n </section>\r\n\r\n {/* ─── Network env injection (Phase 2) ─── */}\r\n <section style={sectionStyle}>\r\n <p style={labelStyle}>{t('card.networkInjectEnv')}</p>\r\n <p style={hintStyle}>{t('card.networkInjectEnvHint')}</p>\r\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '6px' }}>\r\n <input\r\n type=\"checkbox\"\r\n checked={value.networkInjectEnv !== false}\r\n disabled={readonly}\r\n onChange={(event) => { void scope.set('networkInjectEnv', event.currentTarget.checked) }}\r\n />\r\n <span style={{ fontSize: '13px' }}>{value.networkInjectEnv !== false ? 'ON' : 'OFF'}</span>\r\n </div>\r\n </section>\r\n\r\n {/* ─── Hot reload switch (Phase 3) ─── */}\r\n <section style={sectionStyle}>\r\n <p style={labelStyle}>{t('card.watch')}</p>\r\n <p style={hintStyle}>{t('card.watchHint')}</p>\r\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '6px' }}>\r\n <input\r\n type=\"checkbox\"\r\n checked={value.watch !== false}\r\n disabled={readonly}\r\n onChange={(event) => { void scope.set('watch', event.currentTarget.checked) }}\r\n />\r\n <span style={{ fontSize: '13px' }}>{value.watch !== false ? 'ON' : 'OFF'}</span>\r\n </div>\r\n </section>\r\n\r\n {!snapshot.writable\r\n && <p style={{ margin: '8px 0 0', fontSize: '12px', color: 'var(--dsw-alias-label-tertiary)' }}>{t('card.readonly')}</p>}\r\n </>\r\n )}\r\n </div>\r\n )\r\n : null}\r\n </div>\r\n )\r\n}\r\n// ── Floating settings entry(0.1.0/0.1.1 等无设置页宿主)──────────────────────\r\n/** 浮窗齿轮 + 固定定位浮层承载完整审批门卡。自绘定位,不依赖宿主容器布局。 */\r\nexport function FloatingPermissiveGate(props: PermissiveCardProps): JSX.Element {\r\n const [open, setOpen] = useState(false)\r\n return (\r\n <div style={{ position: 'fixed', right: 16, bottom: 64, zIndex: 10000 }}>\r\n {open ? (\r\n <div\r\n onClick={() => setOpen(false)}\r\n style={{ position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, background: 'rgba(0,0,0,.45)', zIndex: 10000 }}\r\n />\r\n ) : null}\r\n {open ? (\r\n <div\r\n style={{ position: 'fixed', top: '6vh', left: '50%', transform: 'translateX(-50%)', width: 'min(760px, 92vw)', maxHeight: '84vh', overflowY: 'auto', zIndex: 10001 }}\r\n >\r\n <button\r\n type=\"button\"\r\n onClick={() => setOpen(false)}\r\n style={{ position: 'sticky', top: 6, float: 'right', marginRight: 8, zIndex: 2, font: 'inherit', cursor: 'pointer', borderRadius: 8, border: '1px solid rgba(127,127,127,.4)', background: 'rgba(30,30,32,.85)', color: 'inherit', padding: '2px 10px' }}\r\n >\r\n ✕ 关闭\r\n </button>\r\n <PermissiveCard t={props.t} scope={props.scope} />\r\n </div>\r\n ) : null}\r\n <button\r\n type=\"button\"\r\n title=\"审批门设置\"\r\n onClick={() => setOpen(!open)}\r\n style={{ width: 40, height: 40, borderRadius: '50%', border: '1px solid rgba(127,127,127,.4)', background: 'rgba(30,30,32,.85)', color: 'inherit', cursor: 'pointer', fontSize: 16, boxShadow: '0 4px 16px rgba(0,0,0,.35)' }}\r\n >\r\n 🛡\r\n </button>\r\n </div>\r\n )\r\n}\r\n","/**\n * Shared decision-feed plumbing for the browser half: the event shape served by\n * the host's `GET /api/dsh-perm-gate/events` route, the polling fetch, the\n * session-id resolution from slot props, the per-kind presentation used by both\n * the notice strip and the approval-history view, and the review-page API calls\n * (snapshot stats / clear, file diff, revert).\n *\n * Everything is best-effort and dependency-free beyond react hooks living in\n * the components; no @deepseek-ai value imports (bundle purity).\n */\n\n/** One event as delivered by the host route (see src/events.ts). */\nexport interface GateEvent {\n readonly id: number\n readonly ts: string\n readonly sessionId: string\n readonly tool: string\n /**\n * `stand-down` is not a decision: it says the gate is inactive in this\n * session's permission preset, so this call was settled by the tier, not by\n * the gate. `VERDICT_LABELS['stand-down']` and `presentation()` carry the\n * user-facing wording; it is always sticky.\n */\n readonly kind: 'auto' | 'ask' | 'deny' | 'learned' | 'manual-approved' | 'manual-rejected' | 'manual-cancelled' | 'stand-down'\n readonly risk?: string\n readonly reason: string\n /** Decision-path label (rule / grant / hard-deny / llm-safe …). */\n readonly verdict?: string\n /** The model's stated intent. */\n readonly justification?: string\n /** Sandbox mode involved, when known. */\n readonly mode?: string\n /** Risk category name (deletion / credential / neutral …). */\n readonly category?: string\n /** Files the decision concerns. */\n readonly files?: readonly string[]\n /** Human confirmations so far for the learned key (manual-approve events). */\n readonly learningCount?: number\n /** Confirmations required before that key auto-allows (manual-approve events). */\n readonly threshold?: number\n}\n\n/**\n * The session-id carriers a slot occupant may receive. A `conversation.view`\n * entry gets the standard props at the top level (`sessionId` / `useSessions`,\n * and whatever its `inject` returned); older/other slots nest them under\n * `slotsProps`. Both shapes are probed.\n */\nexport interface FeedSlotsProps {\n readonly sessionId?: unknown\n readonly useSessions?: SessionSelectorHook\n readonly slotsProps?: {\n readonly sessionId?: unknown\n readonly useSessions?: SessionSelectorHook\n }\n}\n\n/** The DSH session-list selector hook delivered in slot props. */\nexport type SessionSelectorHook = (selector: (state: { current?: unknown }) => unknown) => unknown\n\n/** Fetch decision events for one session; `since > 0` returns only newer ones. */\nexport async function fetchEvents(sessionId: string, since: number): Promise<GateEvent[]> {\n const query = `/api/dsh-perm-gate/events?sessionId=${encodeURIComponent(sessionId)}${since > 0 ? `&since=${since}` : ''}`\n const res = await fetch(query, { headers: { 'cache-control': 'no-cache' } })\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const body = (await res.json()) as { events?: unknown }\n return Array.isArray(body.events) ? (body.events as GateEvent[]) : []\n}\n\n/** The host's push route (see src/events.ts); the browser half prefers it to polling. */\nexport const STREAM_ROUTE = '/api/dsh-perm-gate/stream'\n\n/** Stream attempts before the route is written off as unsupported and polling takes over. */\nconst STREAM_RETRIES = 3\nconst STREAM_RETRY_MS = 3_000\n/**\n * Degraded path only: a host predating the stream route still gets a servable\n * strip. Deliberately slower than the old 2 s tick — it now also pauses while\n * the tab is hidden, so a backgrounded page costs nothing.\n */\nconst FALLBACK_POLL_MS = 5_000\n\n/** One delivery of the feed: either the connect-time replay, or decisions as they land. */\nexport interface GateFeedBatch {\n readonly events: readonly GateEvent[]\n /**\n * True for a connect-time catch-up batch (the stream's backlog, or the\n * fallback's first poll). Callers sync their cursor with it but must not\n * surface it — replaying a session's history as fresh notices is noise.\n */\n readonly backlog: boolean\n}\n\n/**\n * Follow one session's decision feed until the returned close is called.\n *\n * Prefers the host's `text/event-stream` route, which pushes each decision as\n * the gate appends it — no timer, no repeated re-read of the event log. When\n * the stream is unavailable (an older host, a proxy that buffers it) this\n * degrades to polling the JSON route, gated on page visibility.\n *\n * @param sessionId - the session whose decisions to follow.\n * @param getSince - cursor supplier, read at connect and on every fallback poll.\n * @param onBatch - receives the backlog, then live batches.\n * @returns the close: ends the stream and any fallback timer.\n */\nexport function followEvents(\n sessionId: string,\n getSince: () => number,\n onBatch: (batch: GateFeedBatch) => void,\n): () => void {\n let closed = false\n let source: EventSource | null = null\n let pollTimer: ReturnType<typeof setInterval> | null = null\n let retries = 0\n let polls = 0\n\n const stopPolling = (): void => {\n if (pollTimer === null) return\n clearInterval(pollTimer)\n pollTimer = null\n }\n\n const poll = (): void => {\n if (closed) return\n // A hidden tab does not need the strip kept warm; the next visible tick catches up.\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return\n const backlog = polls === 0\n polls += 1\n fetchEvents(sessionId, getSince())\n .then((events) => { if (!closed) onBatch({ events, backlog }) })\n .catch(() => {}) // route missing / transient failure: stay quiet\n }\n\n const startPolling = (): void => {\n if (closed || pollTimer !== null) return\n polls = 0\n poll()\n pollTimer = setInterval(poll, FALLBACK_POLL_MS)\n }\n\n const connect = (): void => {\n if (closed) return\n const query = `?sessionId=${encodeURIComponent(sessionId)}&since=${getSince()}`\n const next = new EventSource(`${STREAM_ROUTE}${query}`)\n source = next\n next.onopen = () => {\n retries = 0\n stopPolling()\n }\n next.onmessage = (message: MessageEvent<string>) => {\n try {\n const body = JSON.parse(message.data) as { events?: unknown; backlog?: unknown }\n if (Array.isArray(body.events)) {\n onBatch({ events: body.events as GateEvent[], backlog: body.backlog === true })\n }\n } catch {\n // an unreadable frame is dropped; the next decision still arrives\n }\n }\n next.onerror = () => {\n if (source === next) source = null\n next.close()\n if (closed) return\n retries += 1\n // The route may be missing or the connection may have dropped: poll meanwhile,\n // and retry the stream a bounded number of times before settling for polling.\n startPolling()\n if (retries <= STREAM_RETRIES) setTimeout(connect, STREAM_RETRY_MS)\n }\n }\n\n if (typeof EventSource === 'undefined') startPolling()\n else connect()\n\n return () => {\n closed = true\n source?.close()\n source = null\n stopPolling()\n }\n}\n\n/** Resolve the current session id from slot props (top level, nested, or hook). */\nexport function resolveSessionId(props: FeedSlotsProps | undefined): string | null {\n const direct = props?.sessionId\n if (typeof direct === 'string' && direct !== '') return direct\n const nested = props?.slotsProps\n if (typeof nested?.sessionId === 'string' && nested.sessionId !== '') return nested.sessionId\n for (const hook of [props?.useSessions, nested?.useSessions]) {\n if (typeof hook !== 'function') continue\n try {\n const state = hook((s) => s) as { current?: unknown } | undefined\n if (typeof state?.current === 'string' && state.current !== '') return state.current\n } catch {\n // fall through to the next carrier\n }\n }\n return null\n}\n\n/** Presentation per event kind: accent color, background wash, and tag. */\nexport function presentation(kind: GateEvent['kind']): { color: string; bg: string; tag: string; sticky: boolean } {\n switch (kind) {\n case 'deny':\n return { color: 'var(--dsw-alias-state-error-primary, #c0392b)', bg: 'var(--dsw-alias-interactive-bg-hover-danger, rgba(192,57,43,0.08))', tag: 'DENY', sticky: false }\n case 'ask':\n return { color: 'var(--dsw-alias-state-warn-label, #b9770e)', bg: 'var(--dsw-alias-state-warn-tertiary, rgba(185,119,14,0.08))', tag: 'ASK', sticky: true }\n case 'learned':\n return { color: 'var(--dsw-alias-state-success-primary, #1e8449)', bg: 'var(--dsw-alias-state-success-tertiary, rgba(30,132,73,0.08))', tag: 'LEARNED', sticky: false }\n case 'manual-approved':\n return { color: 'var(--dsw-alias-state-warn-label, #b9770e)', bg: 'var(--dsw-alias-state-warn-tertiary, rgba(185,119,14,0.08))', tag: 'APPROVED', sticky: false }\n case 'manual-rejected':\n return { color: 'var(--dsw-alias-state-error-primary, #c0392b)', bg: 'var(--dsw-alias-interactive-bg-hover-danger, rgba(192,57,43,0.08))', tag: 'REJECTED', sticky: false }\n case 'manual-cancelled':\n return { color: 'var(--dsw-alias-label-secondary, #666)', bg: 'var(--dsw-alias-bg-module-platform, rgba(127,127,127,0.08))', tag: 'CANCELLED', sticky: false }\n case 'stand-down':\n // Sticky on purpose: an inactive gate is a standing state, not an\n // incident. It must outlive the next auto-allow or it reads as noise.\n return { color: 'var(--dsw-alias-state-warn-label, #b9770e)', bg: 'var(--dsw-alias-state-warn-tertiary, rgba(185,119,14,0.14))', tag: 'GATE OFF', sticky: true }\n default:\n return { color: 'var(--dsw-alias-state-success-primary, #1e8449)', bg: 'var(--dsw-alias-state-success-tertiary, rgba(30,132,73,0.08))', tag: 'ALLOW', sticky: false }\n }\n}\n\n/**\n * Decision-path labels shown beside an event's tool name. Kept alongside\n * `presentation` (not in the dictionary) because they name host-internal\n * decision sources; an unknown value falls through to its raw string.\n */\nexport const VERDICT_LABELS: Readonly<Record<string, string>> = {\n rule: '规则命中',\n grant: '会话授权',\n 'hard-deny': '硬拒绝',\n 'deny-keyword': '黑名单关键词',\n default: '默认策略',\n ask: '默认策略',\n permissive: '自动审查放行',\n classifier: 'LLM 裁决',\n 'llm-safe': 'LLM 判定安全',\n 'llm-learned': 'LLM 学习放行',\n 'learned-sediment': '沉淀规则放行',\n 'learned-confirm': '学习确认',\n 'human-approved': '人工通过',\n 'human-rejected': '人工拒绝',\n 'human-cancelled': '人工取消',\n 'no-approval-channel': '无审批通道',\n // The degrade that hides an ask: the tier declares `approval: ask`, but the\n // session was overridden to `never`, so the gate's ask became a passthrough.\n // Without this label the approvals history shows the raw event string — for\n // the one event that explains why a flagged call ran unreviewed.\n 'preset-passthrough': '审批策略 never · 已放行',\n 'stand-down': '门禁停用',\n}\n\n/** Compact wall-clock rendering of an ISO timestamp. */\nexport function clockTime(iso: string): string {\n const date = new Date(iso)\n if (Number.isNaN(date.getTime())) return iso\n return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })\n}\n\n/** Human-readable byte size for the snapshot bar. */\nexport function fmtBytes(n: number): string {\n if (!Number.isFinite(n) || n <= 0) return '0 B'\n if (n < 1024) return `${n} B`\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`\n return `${(n / (1024 * 1024)).toFixed(2)} MB`\n}\n\n/** Snapshot inventory for the review page's bar and file-chip enablement. */\nexport interface SnapshotStats {\n readonly count: number\n readonly bytes: number\n /** Event ids that currently have a snapshot file. */\n readonly ids: readonly string[]\n /** eventId → absolute snapshot paths (file-level diff availability). */\n readonly files: Readonly<Record<string, readonly string[]>>\n}\n\n/** Load the snapshot inventory (optionally session-scoped); null on failure. */\nexport async function fetchSnapshotStats(sessionId: string | null): Promise<SnapshotStats | null> {\n const query = sessionId === null ? '' : `?sessionId=${encodeURIComponent(sessionId)}`\n const res = await fetch(`/api/dsh-perm-gate/snapshots-stats${query}`, { headers: { 'cache-control': 'no-cache' } })\n if (!res.ok) return null\n const body = (await res.json()) as { ok?: unknown; count?: unknown; bytes?: unknown; ids?: unknown; files?: unknown }\n if (body.ok !== true) return null\n const files: Record<string, readonly string[]> = {}\n if (typeof body.files === 'object' && body.files !== null) {\n for (const [key, value] of Object.entries(body.files as Record<string, unknown>)) {\n if (Array.isArray(value)) files[key] = value.map(String)\n }\n }\n return {\n count: typeof body.count === 'number' ? body.count : 0,\n bytes: typeof body.bytes === 'number' ? body.bytes : 0,\n ids: Array.isArray(body.ids) ? (body.ids as unknown[]).map(String) : [],\n files,\n }\n}\n\n/** Drop snapshots: pass a session id for a session-scoped clear, null for all. */\nexport async function clearSnapshots(sessionId: string | null): Promise<boolean> {\n try {\n const res = await fetch('/api/dsh-perm-gate/snapshots-clear', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(sessionId === null ? {} : { sessionId }),\n })\n return res.ok\n } catch {\n return false\n }\n}\n\n/** One rendered diff line. */\nexport interface DiffLine {\n readonly type: 'same' | 'add' | 'del'\n readonly aNo?: number\n readonly bNo?: number\n readonly text: string\n}\n\nexport interface DiffHunk {\n readonly hiddenBefore: number\n readonly lines: readonly DiffLine[]\n}\n\n/** The diff payload served by `GET /api/dsh-perm-gate/diff`. */\nexport interface DiffResponse {\n readonly hunks: readonly DiffHunk[]\n readonly stats: { readonly added: number; readonly removed: number; readonly contextLines: number }\n readonly afterExists: boolean\n}\n\n/** Load the before/after diff for one event's file; throws on failure. */\nexport async function fetchDiff(eventId: number, path: string): Promise<DiffResponse> {\n const res = await fetch(\n `/api/dsh-perm-gate/diff?eventId=${eventId}&path=${encodeURIComponent(path)}`,\n { headers: { 'cache-control': 'no-cache' } },\n )\n const body = (await res.json().catch(() => null)) as\n | { ok?: unknown; error?: unknown; hunks?: unknown; stats?: unknown; afterExists?: unknown }\n | null\n if (body === null || body.ok !== true) {\n throw new Error(typeof body?.error === 'string' ? body.error : `HTTP ${res.status}`)\n }\n return {\n hunks: Array.isArray(body.hunks) ? (body.hunks as DiffHunk[]) : [],\n stats: (typeof body.stats === 'object' && body.stats !== null\n ? body.stats\n : { added: 0, removed: 0, contextLines: 0 }) as DiffResponse['stats'],\n afterExists: body.afterExists !== false,\n }\n}\n\n/** Deliver a revert instruction for one event into its conversation. */\nexport async function sendRevert(sessionId: string, eventId: number): Promise<{ ok: boolean; error?: string }> {\n try {\n const res = await fetch('/api/dsh-perm-gate/revert', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ sessionId, eventId }),\n })\n const body = (await res.json().catch(() => null)) as { ok?: unknown; error?: unknown } | null\n if (body !== null && body.ok === true) return { ok: true }\n return { ok: false, error: typeof body?.error === 'string' ? body.error : `HTTP ${res.status}` }\n } catch (e) {\n return { ok: false, error: String((e as Error)?.message ?? e) }\n }\n}\n","/**\n * Gate decision notice strip — the `conversation.input.dock` face of\n * dsh-perm-gate (a simplified version of the review-feed pattern demonstrated\n * by dsh-approval-gate).\n *\n * Follows the host's decision feed (`GET /api/dsh-perm-gate/stream`, an SSE\n * push; see `followEvents` for the older-host polling fallback) and shows the\n * latest decision above the conversation input: auto-allows (green) and denies\n * (red) auto-dismiss after a few seconds; an ask (amber) stays until the next\n * event because it needs the human's attention.\n *\n * Everything is best-effort: no session id, a missing route, or any fetch\n * failure simply means \"render nothing\". No @deepseek-ai value imports.\n */\nimport { useEffect, useRef, useState } from 'react'\nimport type { JSX } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport { followEvents, presentation, resolveSessionId, type FeedSlotsProps, type GateEvent, type GateFeedBatch } from './feed.ts'\n\nconst AUTO_HIDE_MS = 4_000\n\n/** Full props: the locale seat + the session-id carriers the slot delivers. */\nexport type NoticeStripProps = PropsLocale<'dsh-perm-gate'> & FeedSlotsProps\n\n/** Localized tag for a manual terminal state; other kinds keep their short tag. */\nfunction manualTagKey(kind: GateEvent['kind']): 'history.tag.manualApproved' | 'history.tag.manualRejected' | 'history.tag.manualCancelled' | null {\n if (kind === 'manual-approved') return 'history.tag.manualApproved'\n if (kind === 'manual-rejected') return 'history.tag.manualRejected'\n if (kind === 'manual-cancelled') return 'history.tag.manualCancelled'\n return null\n}\n\nexport function NoticeStrip({ t, ...props }: NoticeStripProps): JSX.Element | null {\n const sessionId = resolveSessionId(props)\n const [notice, setNotice] = useState<GateEvent | null>(null)\n const sinceRef = useRef(0)\n const shownIdRef = useRef(0)\n const hideTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n useEffect(() => {\n sinceRef.current = 0\n shownIdRef.current = 0\n setNotice(null)\n if (sessionId === null) return\n\n let alive = true\n\n const onBatch = (batch: GateFeedBatch): void => {\n if (!alive || batch.events.length === 0) return\n const last = batch.events[batch.events.length - 1]\n if (last === undefined) return\n if (last.id > sinceRef.current) sinceRef.current = last.id\n // On session open the stream replays history: advance the cursor past it\n // silently, so switching sessions never pops a stale decision.\n if (batch.backlog) {\n shownIdRef.current = sinceRef.current\n return\n }\n if (last.id <= shownIdRef.current) return\n shownIdRef.current = last.id\n setNotice(last)\n if (hideTimerRef.current !== null) clearTimeout(hideTimerRef.current)\n if (!presentation(last.kind).sticky) {\n hideTimerRef.current = setTimeout(() => { setNotice(null) }, AUTO_HIDE_MS)\n }\n }\n\n const close = followEvents(sessionId, () => sinceRef.current, onBatch)\n\n return () => {\n alive = false\n close()\n if (hideTimerRef.current !== null) clearTimeout(hideTimerRef.current)\n }\n }, [sessionId])\n\n if (notice === null) return null\n const style = presentation(notice.kind)\n const manualKey = manualTagKey(notice.kind)\n return (\n <div\n role=\"status\"\n style={{\n boxSizing: 'border-box',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n margin: '0 auto 6px',\n maxWidth: '720px',\n border: `1px solid ${style.color}`,\n background: style.bg,\n borderRadius: '10px',\n padding: '5px 10px',\n }}\n >\n <span\n style={{\n flex: '0 0 auto',\n fontSize: '11px',\n lineHeight: '18px',\n padding: '0 8px',\n borderRadius: '9px',\n color: style.color,\n fontWeight: 600,\n }}\n >\n {manualKey === null ? style.tag : t(manualKey)}\n </span>\n <span\n style={{\n flex: '1 1 auto',\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n fontSize: '12px',\n color: 'var(--dsw-alias-label-secondary, inherit)',\n }}\n >\n <code style={{ font: '500 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary, inherit)' }}>{notice.tool}</code>\n {' — '}\n {notice.reason}\n </span>\n <button\n type=\"button\"\n aria-label=\"dismiss\"\n onClick={() => { setNotice(null) }}\n style={{\n flex: '0 0 auto',\n width: '22px',\n height: '22px',\n border: 'none',\n borderRadius: '999px',\n background: 'transparent',\n color: 'var(--dsw-alias-label-tertiary, inherit)',\n cursor: 'pointer',\n }}\n >\n ×\n </button>\n </div>\n )\n}\n","/**\n * Approval-history view — the `conversation.view` face of dsh-perm-gate,\n * following the session-scoped review-page pattern demonstrated by\n * dsh-approval-gate: a timeline of every gate decision in the current\n * conversation, newest first, loaded once and then extended by the host's push\n * feed (see `followEvents`).\n *\n * Beyond the decision timeline this view owns the review data plane: a snapshot\n * inventory bar (with session/all clearing), per-event file chips, and a diff\n * overlay that shows the pre-change vs current content of one file and can send\n * a revert instruction back into the conversation.\n *\n * Data source: the host's `GET /api/dsh-perm-gate/events?sessionId=` feed (the\n * same JSONL the notice strip consumes) plus the diff / revert / snapshot\n * routes. Everything is best-effort: no session id or any fetch failure renders\n * the empty / error state. No @deepseek-ai value imports.\n */\nimport { useEffect, useState } from 'react'\nimport type { CSSProperties, JSX } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport {\n clearSnapshots,\n clockTime,\n fetchDiff,\n fetchEvents,\n fetchSnapshotStats,\n fmtBytes,\n followEvents,\n presentation,\n resolveSessionId,\n sendRevert,\n VERDICT_LABELS,\n type DiffHunk,\n type DiffResponse,\n type FeedSlotsProps,\n type GateEvent,\n type GateFeedBatch,\n type SnapshotStats,\n} from './feed.ts'\nimport type { PermissiveKey } from './locales.ts'\n\n/** Tag text per event kind, keyed into the plugin dictionary. */\nconst TAG_KEYS = {\n auto: 'history.tag.auto',\n ask: 'history.tag.ask',\n deny: 'history.tag.deny',\n learned: 'history.tag.learned',\n 'manual-approved': 'history.tag.manualApproved',\n 'manual-rejected': 'history.tag.manualRejected',\n 'manual-cancelled': 'history.tag.manualCancelled',\n 'stand-down': 'history.tag.standDown',\n} as const satisfies Record<GateEvent['kind'], PermissiveKey>\n\n/** Full props: locale seat + the session-id carriers the slot delivers. */\nexport type HistoryViewProps = PropsLocale<'dsh-perm-gate'> & FeedSlotsProps\n\n/** The file name alone (chips show the basename, like the reference page). */\nfunction basename(p: string): string {\n const seg = p.split(/[\\\\/]/)\n return seg[seg.length - 1] ?? p\n}\n\nfunction glyphOf(kind: GateEvent['kind']): { char: string; color: string } {\n const style = presentation(kind)\n switch (kind) {\n case 'deny':\n case 'manual-rejected':\n return { char: '✕', color: style.color }\n case 'ask':\n return { char: '◔', color: style.color }\n case 'manual-cancelled':\n return { char: '—', color: style.color }\n default:\n return { char: '✓', color: style.color }\n }\n}\n\nconst barStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n flexWrap: 'wrap',\n padding: '6px 10px',\n borderRadius: '8px',\n background: 'var(--dsw-alias-bg-layer-3, rgba(127,127,127,0.05))',\n fontSize: '12px',\n lineHeight: '18px',\n color: 'var(--dsw-alias-label-tertiary)',\n}\n\nconst barButtonStyle: CSSProperties = {\n boxSizing: 'border-box',\n height: '26px',\n color: 'var(--dsw-alias-label-primary)',\n cursor: 'pointer',\n font: 'inherit',\n border: '1px solid var(--dsw-alias-border-l2)',\n background: 'transparent',\n borderRadius: '13px',\n padding: '0 12px',\n fontSize: '12px',\n lineHeight: '24px',\n}\n\n/** The snapshot inventory bar: usage plus session/all clearing. */\nfunction SnapshotBar(props: {\n t: HistoryViewProps['t']\n stats: SnapshotStats | null\n sessionId: string | null\n onCleared: () => void\n}): JSX.Element {\n const { t, stats, sessionId, onCleared } = props\n const busy = stats === null || stats.count === 0\n const clear = (mode: 'session' | 'all'): void => {\n const confirmed = window.confirm(\n mode === 'all' ? t('history.clearAllConfirm') : t('history.clearSessionConfirm'),\n )\n if (!confirmed) return\n void clearSnapshots(mode === 'session' ? sessionId : null).then(() => { onCleared() })\n }\n return (\n <div style={barStyle}>\n <span>\n {`${t('history.snapshots')} `}\n <b style={{ color: 'var(--dsw-alias-label-secondary)', fontWeight: 500 }}>\n {stats === null ? '…' : `${fmtBytes(stats.bytes)} · ${stats.count}`}\n </b>\n </span>\n <span style={{ flex: '1 1 auto' }} />\n <button\n type=\"button\"\n title={t('history.clearSessionTitle')}\n disabled={busy}\n onClick={() => { clear('session') }}\n style={{ ...barButtonStyle, opacity: busy ? 0.4 : 1 }}\n >\n {t('history.clearSession')}\n </button>\n <button\n type=\"button\"\n title={t('history.clearAllTitle')}\n disabled={busy}\n onClick={() => { clear('all') }}\n style={{ ...barButtonStyle, opacity: busy ? 0.4 : 1, color: 'var(--dsw-alias-state-error-primary)' }}\n >\n {t('history.clearAll')}\n </button>\n </div>\n )\n}\n\n/** One diff line row (marker + line numbers + text). */\nfunction DiffRow({ line }: { line: DiffHunk['lines'][number] }): JSX.Element {\n const isAdd = line.type === 'add'\n const isDel = line.type === 'del'\n const background = isAdd\n ? 'var(--dsw-alias-state-success-tertiary)'\n : isDel\n ? 'var(--dsw-alias-interactive-bg-hover-danger)'\n : 'transparent'\n const color = isDel\n ? 'var(--dsw-alias-state-error-primary)'\n : isAdd\n ? 'var(--dsw-alias-label-primary)'\n : 'var(--dsw-alias-label-secondary)'\n const aNo = line.aNo === undefined ? '' : String(line.aNo)\n const bNo = line.bNo === undefined ? '' : String(line.bNo)\n return (\n <div\n style={{\n boxSizing: 'border-box',\n display: 'flex',\n gap: '8px',\n padding: '1px 8px',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-all',\n minWidth: 0,\n background,\n color,\n }}\n >\n <span aria-hidden style={{ flex: '0 0 auto', width: '16px', userSelect: 'none' }}>\n {isAdd ? '+' : isDel ? '-' : ' '}\n </span>\n <span\n style={{\n flex: '0 0 auto',\n width: '60px',\n color: 'var(--dsw-alias-label-caption)',\n textAlign: 'right',\n userSelect: 'none',\n fontVariantNumeric: 'tabular-nums',\n }}\n >\n {aNo}\n {aNo !== '' && bNo !== '' ? ' ' : ''}\n {bNo}\n </span>\n <span style={{ flex: '1 1 auto', minWidth: 0 }}>{line.text}</span>\n </div>\n )\n}\n\n/** The file-change overlay: before/after diff plus the revert action. */\nfunction DiffPanel(props: {\n t: HistoryViewProps['t']\n sessionId: string | null\n eventId: number\n path: string\n onClose: () => void\n}): JSX.Element {\n const { t, sessionId, eventId, path, onClose } = props\n const [data, setData] = useState<DiffResponse | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [revertMsg, setRevertMsg] = useState<string | null>(null)\n const [revertOk, setRevertOk] = useState(false)\n const [reverting, setReverting] = useState(false)\n const [revertDone, setRevertDone] = useState(false)\n\n useEffect(() => {\n let alive = true\n setData(null)\n setError(null)\n setRevertDone(false)\n setRevertMsg(null)\n fetchDiff(eventId, path)\n .then((res) => { if (alive) setData(res) })\n .catch((e: unknown) => {\n if (alive) setError(`${t('history.diffLoadFail')}${String((e as Error)?.message ?? e)}`)\n })\n return () => { alive = false }\n }, [eventId, path, t])\n\n const doRevert = (): void => {\n // One revert instruction per event: the same event must never be delivered twice.\n if (reverting || revertDone || sessionId === null) return\n setReverting(true)\n setRevertMsg(null)\n void sendRevert(sessionId, eventId).then((res) => {\n if (res.ok) {\n setRevertMsg(t('history.diffRevertSent'))\n setRevertOk(true)\n setRevertDone(true)\n } else {\n setRevertMsg(`${t('history.diffRevertFail')}${res.error ?? ''}`)\n setRevertOk(false)\n }\n setReverting(false)\n })\n }\n\n const stats = data?.stats\n const body: JSX.Element = error !== null\n ? <div style={diffEmptyStyle}>{error}</div>\n : data === null\n ? <div style={diffEmptyStyle}>{t('history.diffLoading')}</div>\n : data.hunks.length === 0\n ? <div style={diffEmptyStyle}>{t('history.diffEmpty')}</div>\n : (\n <div style={diffBodyStyle}>\n {data.hunks.map((hunk, hi) => (\n <div key={`hunk-${hi}`}>\n {hunk.hiddenBefore > 0\n ? (\n <div style={hunkSepStyle}>\n {t('history.diffHidden').replace('%n', String(hunk.hiddenBefore))}\n </div>\n )\n : null}\n {hunk.lines.map((line, li) => (\n <DiffRow key={`l-${hi}-${li}`} line={line} />\n ))}\n </div>\n ))}\n </div>\n )\n\n return (\n <div style={overlayStyle} onClick={(e) => { if (e.target === e.currentTarget) onClose() }}>\n <div style={panelStyle}>\n <div style={panelHeadStyle}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <span style={{ flex: '1 1 auto', fontSize: '14px', fontWeight: 500, color: 'var(--dsw-alias-label-primary)' }}>\n {t('history.diffTitle')}\n </span>\n <button type=\"button\" aria-label={t('history.diffClose')} title={t('history.diffClose')} onClick={onClose} style={closeStyle}>\n ✕\n </button>\n </div>\n <div style={{ fontSize: '12px', lineHeight: '18px', fontFamily: 'var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-tertiary)', wordBreak: 'break-all' }}>\n {path}\n </div>\n {stats === undefined\n ? null\n : (\n <div style={{ fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-secondary)' }}>\n {t('history.diffStats')\n .replace('%a', String(stats.added))\n .replace('%r', String(stats.removed))\n .replace('%c', String(stats.contextLines))}\n {data !== null && !data.afterExists ? t('history.diffGone') : ''}\n </div>\n )}\n </div>\n {body}\n <div style={panelFootStyle}>\n {revertMsg === null\n ? null\n : (\n <span style={{ marginRight: 'auto', fontSize: '12px', color: revertOk ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-error-primary)' }}>\n {revertMsg}\n </span>\n )}\n <button\n type=\"button\"\n onClick={doRevert}\n disabled={reverting || revertDone || sessionId === null}\n style={{\n ...barButtonStyle,\n border: 'none',\n background: 'var(--dsw-alias-button-primary-fill, var(--dsw-alias-label-primary))',\n color: 'var(--dsw-alias-label-primary-foreground, #fff)',\n opacity: reverting || revertDone ? 0.5 : 1,\n }}\n >\n {reverting ? t('history.diffReverting') : revertDone ? t('history.diffRevertDone') : t('history.diffRevert')}\n </button>\n <button type=\"button\" onClick={onClose} style={barButtonStyle}>\n {t('history.diffClose')}\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nconst overlayStyle: CSSProperties = {\n position: 'fixed',\n inset: 0,\n zIndex: 900,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'var(--dsw-alias-bg-mask-1, rgba(0,0,0,0.35))',\n}\n\nconst panelStyle: CSSProperties = {\n boxSizing: 'border-box',\n width: 'min(760px, calc(100vw - 48px))',\n maxHeight: 'min(720px, calc(100vh - 48px))',\n display: 'flex',\n flexDirection: 'column',\n background: 'var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1))',\n border: '1px solid var(--dsw-alias-border-l1)',\n borderRadius: '16px',\n overflow: 'hidden',\n}\n\nconst panelHeadStyle: CSSProperties = {\n boxSizing: 'border-box',\n flex: '0 0 auto',\n display: 'flex',\n flexDirection: 'column',\n gap: '4px',\n padding: '12px 14px',\n borderBottom: '1px solid var(--dsw-alias-border-l2)',\n}\n\nconst panelFootStyle: CSSProperties = {\n boxSizing: 'border-box',\n flex: '0 0 auto',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n justifyContent: 'flex-end',\n padding: '10px 14px',\n borderTop: '1px solid var(--dsw-alias-border-l2)',\n}\n\nconst diffBodyStyle: CSSProperties = {\n flex: '1 1 auto',\n minHeight: 0,\n overflowY: 'auto',\n padding: '8px 10px',\n display: 'flex',\n flexDirection: 'column',\n fontFamily: 'var(--ds-font-family-code, monospace)',\n fontSize: '12px',\n lineHeight: '19px',\n}\n\nconst diffEmptyStyle: CSSProperties = {\n flex: '1 1 auto',\n color: 'var(--dsw-alias-label-tertiary)',\n fontSize: '13px',\n lineHeight: '20px',\n padding: '16px',\n textAlign: 'center',\n}\n\nconst hunkSepStyle: CSSProperties = {\n boxSizing: 'border-box',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'var(--dsw-alias-label-tertiary)',\n fontSize: '11px',\n lineHeight: '16px',\n padding: '2px 8px',\n margin: '2px 0',\n borderTop: '1px solid var(--dsw-alias-border-l1)',\n borderBottom: '1px solid var(--dsw-alias-border-l1)',\n userSelect: 'none',\n}\n\nconst closeStyle: CSSProperties = {\n flex: '0 0 auto',\n width: '24px',\n height: '24px',\n border: 'none',\n borderRadius: '999px',\n background: 'transparent',\n color: 'var(--dsw-alias-label-tertiary)',\n cursor: 'pointer',\n}\n\nexport function HistoryView({ t, ...props }: HistoryViewProps): JSX.Element | null {\n const sessionId = resolveSessionId(props)\n const [events, setEvents] = useState<GateEvent[] | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [stats, setStats] = useState<SnapshotStats | null>(null)\n const [diffOpen, setDiffOpen] = useState<{ eventId: number; path: string } | null>(null)\n\n useEffect(() => {\n setEvents(null)\n setError(null)\n setStats(null)\n if (sessionId === null) {\n setEvents([])\n return\n }\n let alive = true\n let cursor = 0\n let closeStream: (() => void) | null = null\n void fetchSnapshotStats(sessionId).then((next) => { if (alive) setStats(next) })\n\n /**\n * Decisions landing after the initial load. Both the stream's pushes and the\n * fallback's ticks carry only events past the cursor, so they merge the same\n * way; a batch is also the point where the snapshot inventory can have grown.\n */\n const onBatch = (batch: GateFeedBatch): void => {\n if (!alive || batch.events.length === 0) return\n for (const ev of batch.events) if (ev.id > cursor) cursor = ev.id\n setEvents((current) => {\n const known = new Set((current ?? []).map((ev) => ev.id))\n const added = batch.events.filter((ev) => !known.has(ev.id))\n return added.length === 0 ? current : [...added, ...(current ?? [])].sort((a, b) => b.id - a.id)\n })\n setError(null)\n void fetchSnapshotStats(sessionId).then((next) => { if (alive) setStats(next) })\n }\n\n // One REST load for the list (so a failure is reportable, not silently an\n // empty page); everything after it is pushed rather than re-fetched on a timer.\n fetchEvents(sessionId, 0)\n .then((loaded) => {\n if (!alive) return\n setEvents([...loaded].sort((a, b) => b.id - a.id))\n setError(null)\n cursor = loaded.reduce((max, ev) => (ev.id > max ? ev.id : max), 0)\n })\n .catch((e: unknown) => {\n if (alive) setError(String((e as Error)?.message ?? e))\n })\n .finally(() => {\n // Opens with the cursor the load settled on, so no history is replayed.\n if (alive) closeStream = followEvents(sessionId, () => cursor, onBatch)\n })\n\n return () => {\n alive = false\n closeStream?.()\n }\n }, [sessionId])\n\n /** Whether one event has a snapshot covering this file (chip is clickable). */\n const hasSnapshot = (ev: GateEvent, file: string): boolean => {\n const paths = stats?.files[String(ev.id)]\n if (paths === undefined || paths.length === 0) return false\n const base = basename(file)\n return paths.some((p) => p === file || basename(p) === base)\n }\n\n return (\n <div style={{ boxSizing: 'border-box', maxWidth: '720px', margin: '0 auto', padding: '8px 4px' }}>\n <div style={{ marginBottom: '10px' }}>\n <div style={{ fontSize: '14px', fontWeight: 600, color: 'var(--dsw-alias-label-primary)' }}>{t('history.title')}</div>\n <div style={{ marginTop: '2px', fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-primary) !important' }}>{t('history.subtitle')}</div>\n </div>\n <SnapshotBar\n t={t}\n stats={stats}\n sessionId={sessionId}\n onCleared={() => { void fetchSnapshotStats(sessionId).then(setStats) }}\n />\n {events === null\n ? (\n <div style={{ padding: '16px 0', fontSize: '13px', color: 'var(--dsw-alias-label-tertiary)' }}>\n {error === null ? t('history.loading') : `${t('history.error')}${error}`}\n </div>\n )\n : events.length === 0\n ? (\n <div style={{ padding: '16px 0', fontSize: '13px', color: 'var(--dsw-alias-label-tertiary)' }}>\n {error === null ? t('history.empty') : `${t('history.error')}${error}`}\n </div>\n )\n : (\n <div>\n {events.map((ev) => {\n const style = presentation(ev.kind)\n const mark = glyphOf(ev.kind)\n const verdict = ev.verdict === undefined ? '' : (VERDICT_LABELS[ev.verdict] ?? ev.verdict)\n const files = ev.files ?? []\n // One chip per distinct basename (a decision may name the same\n // file both absolutely and relatively).\n const chips: string[] = []\n const seenBase = new Set<string>()\n for (const f of files) {\n const base = basename(f)\n if (base === '' || seenBase.has(base)) continue\n seenBase.add(base)\n chips.push(f)\n }\n return (\n <div key={ev.id} style={{ display: 'flex', gap: '10px', padding: '6px 10px', borderRadius: '8px', background: 'var(--dsw-alias-bg-layer-3, rgba(127,127,127,0.05))' }}>\n <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', flex: '0 0 auto', width: '20px' }}>\n <span\n aria-hidden\n style={{\n width: '18px',\n height: '18px',\n marginTop: '3px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '11px',\n lineHeight: '18px',\n borderRadius: '999px',\n border: `1px solid ${mark.color}`,\n color: mark.color,\n }}\n >\n {mark.char}\n </span>\n <span aria-hidden style={{ flex: '1 1 auto', width: '1px', minHeight: '10px', background: 'var(--dsw-alias-border-l2, rgba(127,127,127,0.3))' }} />\n </div>\n <div style={{ flex: '1 1 auto', minWidth: 0, paddingBottom: '12px' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }}>\n <code style={{ font: '600 12px/18px var(--ds-font-family-code, monospace)', color: 'var(--dsw-alias-label-primary)' }}>{ev.tool}</code>\n <span\n style={{\n fontSize: '11px',\n lineHeight: '18px',\n padding: '0 8px',\n borderRadius: '9px',\n color: style.color,\n background: style.bg,\n fontWeight: 600,\n }}\n >\n {t(TAG_KEYS[ev.kind])}\n </span>\n {verdict === ''\n ? null\n : (\n <span style={{ fontSize: '11px', lineHeight: '18px', padding: '0 6px', borderRadius: '9px', color: 'var(--dsw-alias-label-tertiary)', border: '1px solid var(--dsw-alias-border-l2)' }}>\n {verdict}\n </span>\n )}\n {ev.risk === undefined || ev.risk === ''\n ? null\n : (\n <span style={{ fontSize: '11px', lineHeight: '18px', padding: '0 6px', borderRadius: '9px', color: 'var(--dsw-alias-label-tertiary)', border: '1px solid var(--dsw-alias-border-l2)' }}>\n {ev.risk}\n </span>\n )}\n {ev.kind === 'manual-approved' && ev.learningCount !== undefined && ev.threshold !== undefined\n ? (\n <span style={{ fontSize: '11px', lineHeight: '18px', padding: '0 6px', borderRadius: '9px', color: 'var(--dsw-alias-state-warn-label)', border: '1px solid var(--dsw-alias-border-l2)' }}>\n {t('history.learnedProgress').replace('%n', String(ev.learningCount)).replace('%t', String(ev.threshold))}\n </span>\n )\n : null}\n <span style={{ marginLeft: 'auto', flex: '0 0 auto', fontSize: '11px', color: 'var(--dsw-alias-label-tertiary)' }}>{clockTime(ev.ts)}</span>\n </div>\n <div style={{ marginTop: '2px', fontSize: '12px', lineHeight: '18px', color: 'var(--dsw-alias-label-secondary, inherit)', overflowWrap: 'anywhere' }}>\n {ev.justification ?? ev.reason}\n </div>\n {chips.length === 0\n ? null\n : (\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px', marginTop: '4px' }}>\n {chips.map((file) => {\n const clickable = hasSnapshot(ev, file)\n return (\n <span\n key={file}\n title={clickable ? t('history.diffChipTitle') : file}\n role={clickable ? 'button' : undefined}\n onClick={clickable ? () => { setDiffOpen({ eventId: ev.id, path: file }) } : undefined}\n style={{\n boxSizing: 'border-box',\n maxWidth: '260px',\n height: '20px',\n display: 'inline-flex',\n alignItems: 'center',\n padding: '0 7px',\n borderRadius: '5px',\n font: '11px/18px var(--ds-font-family-code, monospace)',\n border: `1px solid ${clickable ? 'var(--dsw-alias-state-business-primary)' : 'var(--dsw-alias-border-l1)'}`,\n color: clickable ? 'var(--dsw-alias-state-business-primary)' : 'var(--dsw-alias-label-secondary)',\n background: 'var(--dsw-alias-bg-layer-1, transparent)',\n cursor: clickable ? 'pointer' : 'default',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {basename(file)}\n </span>\n )\n })}\n </div>\n )}\n </div>\n </div>\n )\n })}\n </div>\n )}\n {diffOpen === null\n ? null\n : (\n <DiffPanel\n t={t}\n sessionId={sessionId}\n eventId={diffOpen.eventId}\n path={diffOpen.path}\n onClose={() => { setDiffOpen(null) }}\n />\n )}\n </div>\n )\n}\n","/**\n * compat.ts —— client 半区版本敏感代码的**唯一窄腰**(INDEX §C:版本差异代码\n * 只许出现在窄腰文件,能力探测在严格代理 client ctx 上不可行——inject 清单外\n * 的属性读取直接 throw,故用双 scoped-inject 按代分流)。\n *\n * 已核实的分叉(2026-10-05 六线农场 node_modules 实查 + input-traffic P2 同型\n * 结论):持久化设置面按代互斥——\n * - 0.1.7+ 走 `configForms.get(ns)`;\n * - ≤0.1.5 走 `settingsScope.bind({ namespace })`。\n * 0.1.7-rc.1 的 client-ui-settings 包全文已无 `settingsScope` 字样,两服务\n * 天然不会双触发;缺席线上的 scoped fiber 永久 PENDING,与 family 槽缺席同型,\n * 不阻塞插件其余半区。**插件级 inject 因此只收六线通用服务**(slots/locale),\n * configForms 留在清单里会让 ≤0.1.5 整个 client 半区 PENDING 静默失活\n * (date-wrapper boot-audit 教训的 client 版)。\n *\n * 卡片消费的四个方法(getSnapshot/subscribe/set/unset)在两代都存在:新线的\n * `SettingsScopeSnapshot` 虽然 richer(base/user/revision/mode),但\n * `value`/`writable` 字段保留,`set`/`unset` 退化为 `mutate` 的便利包装\n * (adaptation-reports/dsh-perm-gate.md §1.5)。句柄因此按**本地结构类型**\n * 声明,不做宿主包的类型合并——编译面对每条宿主线的真实类型保持一致\n * (input-traffic compat.ts 同款纪律)。\n *\n * All @deepseek-ai/* imports are type-only (client bundle purity).\n */\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\n\n/** Structural minimum of a durable settings scope — shared by `configForms.get()`\n * (0.1.7+) and `settingsScope.bind()` (≤0.1.5). Declared locally so the compile\n * face stays identical against every host line's real types. */\nexport interface SettingsDocHandle {\n getSnapshot(): { status: string; value: unknown; writable: boolean }\n subscribe(listener: () => void): () => void\n set(field: string, value: unknown): Promise<void> | unknown\n unset(field: string): Promise<void> | unknown\n}\n\n/** Which durable-settings service resolved — `configForms` only exists on\n * 0.1.7+, `settingsScope` only on ≤0.1.5. Surfaces that are generation-specific\n * (e.g. the ≤0.1.5 `settings.plugin.item` card) key off this tag. */\nexport type SettingsGeneration = 'configForms' | 'settingsScope'\n\n/**\n * Resolve the plugin's durable settings scope through whichever service this\n * host line carries, then hand it to `onScope` exactly once.\n *\n * Both variants are scoped sub-injects: on a host without the service the fiber\n * waits forever WITHOUT blocking the plugin's other faces (same posture as the\n * notice strip's slot-inject when its slot holder is absent). session-guard\n * 4.1.0 proves the `settingsScope` branch resolves on 0.1.5-rc.3 (its\n * shell.overlay gear registers inside this callback and renders there).\n */\nexport function resolveSettingsScope(\n ctx: ClientContext,\n namespace: string,\n onScope: (scope: SettingsDocHandle, generation: SettingsGeneration) => void,\n): void {\n // Modern hosts (0.1.7+): configForms owns cross-entry durable scopes.\n ctx.inject(['configForms'], (configForms: unknown) => {\n const scope = (configForms as { get(namespace: string): SettingsDocHandle }).get(namespace)\n onScope(scope, 'configForms')\n })\n // Old hosts (≤0.1.5): namespaced durable scope via bind().\n ctx.inject(['settingsScope'], (settingsScope: unknown) => {\n const scope = (settingsScope as {\n bind(spec: { namespace: string }): SettingsDocHandle\n }).bind({ namespace })\n onScope(scope, 'settingsScope')\n })\n}\n","/**\n * BridgeDocHandle — T13b 双轨数据源的桥轨(≤0.1.5 settingsScope 不解析时的兜底)。\n *\n * 与原生 SettingsDocHandle(configForms.get / settingsScope.bind)同构:\n * getSnapshot/subscribe/set/unset。读 = POST /api/dsh-perm-gate/settings/describe;\n * 写 = POST …/mutate(ops 转发宿主 settings 服务),成功即用回填描述符刷新快照并\n * 通知订阅者(乐观刷新,无本地第二份状态——权威值始终在宿主服务里)。\n * 初始 describe 拉取在构造时异步发起;拉取完成前快照 status='pending',卡片据此\n * 呈现加载态。\n */\nimport type { SettingsDocHandle } from './compat.js'\n\nconst DESCRIBE = '/api/dsh-perm-gate/settings/describe'\nconst MUTATE = '/api/dsh-perm-gate/settings/mutate'\n\ninterface Snapshot { status: string; value: unknown; writable: boolean }\ninterface Descriptor { value?: unknown; revision?: number }\ninterface BridgeBody { ok?: boolean; code?: string; message?: string; value?: { descriptor?: Descriptor; writable?: boolean } }\n\nexport class BridgeDocHandle implements SettingsDocHandle {\n private snapshot: Snapshot = { status: 'pending', value: undefined, writable: true }\n private listeners = new Set<() => void>()\n private revision: number | undefined\n private inflight: Promise<void> | undefined\n\n constructor() {\n void this.refresh()\n }\n\n getSnapshot(): Snapshot {\n return this.snapshot\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n async set(field: string, value: unknown): Promise<void> {\n await this.mutate([{ op: 'set', path: [field], value }])\n }\n\n async unset(field: string): Promise<void> {\n await this.mutate([{ op: 'unset', path: [field] }])\n }\n\n private notify(): void {\n for (const l of [...this.listeners]) l()\n }\n\n private async request(path: string, body?: unknown): Promise<BridgeBody> {\n const response = await fetch(path, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body ?? {}),\n })\n if (!response.ok) throw new Error(`bridge ${path} HTTP ${response.status}`)\n return await response.json() as BridgeBody\n }\n\n private async refresh(): Promise<void> {\n if (this.inflight !== undefined) return this.inflight\n this.inflight = (async () => {\n try {\n const body = await this.request(DESCRIBE)\n if (body.ok && body.value?.descriptor !== undefined) {\n const d = body.value.descriptor\n this.revision = typeof d.revision === 'number' ? d.revision : undefined\n this.snapshot = { status: 'ready', value: d.value, writable: body.value.writable !== false }\n } else {\n this.snapshot = { status: 'error', value: undefined, writable: false }\n }\n } catch {\n this.snapshot = { status: 'error', value: undefined, writable: false }\n } finally {\n this.inflight = undefined\n }\n this.notify()\n })()\n return this.inflight\n }\n\n private async mutate(ops: Array<{ op: string; path: string[]; value?: unknown }>): Promise<void> {\n const body = await this.request(MUTATE, { ops, expectedRevision: this.revision })\n if (body.ok && body.value?.descriptor !== undefined) {\n const d = body.value.descriptor\n this.revision = typeof d.revision === 'number' ? d.revision : undefined\n this.snapshot = { status: 'ready', value: d.value, writable: this.snapshot.writable }\n } else if (body.code === 'settings-conflict') {\n await this.refresh() // 乐观并发失败:拉权威值再让下次写入带新 revision\n } else {\n throw new Error(`bridge mutate failed: ${body.code ?? 'unknown'} ${body.message ?? ''}`)\n }\n this.notify()\n }\n}\n","/**\n * dsh-perm-gate — browser half.\n *\n * Registers the `dsh-perm-gate` dictionaries and one `settings.plugins.tab`\n * page keyed by the plugin's settings namespace, so the Plugins section of the\n * settings panel renders an editable page: the single 自动审查 tier switch\n * plus the four combinable backend approval strategies.\n *\n * All @deepseek-ai/* imports are type-only at the value level: collaboration\n * happens through cordis services (`slots`, `locale`, `configForms`) and slot\n * registration only (client bundle purity). The `LocaleNamespaceMap`\n * augmentation below is a type-only merge so the `locale:` seat type-checks.\n *\n * `ClientContext` comes from cordis directly. DSH 0.1.1 exported the identical\n * alias from `@deepseek-ai/dsh-client-runtime/client` (`export type ClientContext\n * = Context`), but that package was removed in 0.1.2-alpha.1 — cordis is the one\n * source that names the same type on both lines.\n */\nimport type { JSX } from 'react'\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Declaration merge for `ctx.slots`. On the 0.1.2+ line the slot registry service\n// is declared by the renderer's client entry; on 0.1.1 it came from\n// `dsh-client-runtime/client` (via the settings client's peer), which is why the\n// renderer entry declares nothing there. Importing it is a no-op on the old line.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport { NS, dictionaries, type PermissiveKey } from './locales.ts'\nimport { FloatingPermissiveGate, PermissiveCard, type PermissiveCardInjected, type PermissiveCardProps } from './card.tsx'\nimport { NoticeStrip } from './notice.tsx'\nimport { HistoryView } from './history.tsx'\nimport { resolveSettingsScope } from './compat.ts'\nimport { BridgeDocHandle } from './bridge-scope.ts'\n\n/** The profile entry id of this plugin — the `configForms` key (kept in lockstep with cordis.patch.yml). */\nconst PERMISSIVE_NS = 'dsh-perm-gate'\n\n// Declare the plugin's dictionary namespace in the locale key domain so the\n// slot `locale:` seat and `ctx.locale.bind` are typed to our key union.\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n 'dsh-perm-gate': PermissiveKey\n }\n // The conversation dock slot is declared at runtime by the conversation UI\n // package (not a dev dependency here); mirror its contract so the typed\n // `slots.register` accepts our notice-strip entry. Approval-gate's client\n // demonstrates the runtime accepts this slot name with id/order/label options.\n interface SlotMap {\n 'conversation.input.dock': {\n kind: 'list'\n scope: 'session-maybe'\n owner: {\n /** Current conversation id (may be absent outside a session). */\n sessionId?: string\n /** Session-store selector hook supplied by the conversation shell. */\n useSessions?: (selector: (state: unknown) => unknown) => unknown\n }\n }\n // The conversation view slot (tab row next to the conversation timeline) is\n // declared at runtime by the conversation UI package; mirror its contract\n // so the typed `slots.register` accepts our approval-history entry.\n 'conversation.view': {\n kind: 'list'\n scope: 'session-maybe'\n owner: {\n sessionId?: string\n useSessions?: (selector: (state: unknown) => unknown) => unknown\n }\n }\n // Plugins-page configuration card (official ui-plugin-manager contract):\n // the host's Plugins page does not render volatile config forms on its\n // own — the page draws a config card on the bundle's detail page only when\n // a client claims this seat, keyed by the bundle's package name. Declared\n // here (the declaring page package is not a dev dependency), mirroring the\n // contract the page renders with (`{ view: 'page', form }` owner props).\n 'plugins.bundle.config': { kind: 'keyed'; scope: 'root'; owner: Record<string, unknown> }\n // ≤0.1.5 settings-panel plugin-config tab: keyed by the settings namespace,\n // dispatched as `served namespaces ∩ settings.plugin.item cards` (host\n // client-ui-settings-plugins ConfigurablePluginsTabController.publish — the\n // key is compared against the namespaces the host serves, which our\n // server-side installSection registration provides). Declared here because\n // the declaring page package is not a dev dependency; the host renders the\n // card with empty owner props (`renderSlot(..., {}, { entryKey: ns })`).\n 'settings.plugin.item': { kind: 'keyed'; scope: 'root'; owner: Record<string, unknown> }\n }\n}\n\n/** Services required by the browser half — generation-neutral only.\n *\n * `configForms` (0.1.7+) / `settingsScope` (≤0.1.5) are generation-exclusive\n * durable-settings faces: keeping either in the plugin-level inject list would\n * leave the WHOLE browser half fiber PENDING on the other line (strict ctx\n * proxy throws on undeclared service reads; pending fiber = silent death).\n * They resolve through scoped sub-injects in compat.ts instead, and the card\n * registrations below move into the resolution callback. */\nexport const inject = ['slots', 'locale']\n\n/**\n * Client plugin body: dictionaries plus the settings page registration.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n if (ctx.locale) ctx.effect(() => ctx.locale.register(NS, dictionaries), 'dsh-perm-gate: dictionaries')\n\n // No permission-picker decoration: the tier's label is the Chinese product\n // string supplied by cordis.patch.yml, and the composer draws glyphs only for\n // the three built-in values, so a plugin-contributed tier is icon-free on\n // every surface.\n\n // Decision notice strip above the conversation input: polls the host's\n // event feed so auto-allows / asks / denies are visible without opening logs.\n ctx.slots.inject('conversation.input.dock', function* () {\n yield ctx.slots.register({\n name: 'conversation.input.dock',\n id: 'dsh-perm-gate.notice',\n order: 30,\n label: () => t('notice.label'),\n locale: NS,\n }, NoticeStrip)\n }) as unknown\n\n // Approval-history page: a conversation-view tab listing every gate decision\n // of the session, newest first (the review-page pattern approval-gate\n // demonstrates; our data is the same events feed the notice strip polls).\n ctx.slots.inject('conversation.view', function* () {\n yield ctx.slots.register({\n name: 'conversation.view',\n id: 'dsh-perm-gate.history',\n order: 20,\n label: () => t('history.label'),\n locale: NS,\n inject: (sessionId: string | undefined) => ({ sessionId }),\n }, HistoryView)\n }) as unknown\n\n // A localized tab label (re-evaluated per read so it follows the active locale).\n const t = ctx.locale.bind(NS)\n\n // 设置卡注册收进 settings scope 解析回调(input-traffic P2 范式):卡片\n // inject 值闭包捕获已解析的句柄,注册体只在回调里跑一次——两代服务按代\n // 互斥,天然不双触发。旧线 ≤0.1.5 经 settingsScope.bind 解析(session-guard\n // 4.1.0 在 0.1.5-rc.3 实证该分支会 resolve:它的浮窗齿轮就注册在同一回调里);\n // 0.1.7+ 经 configForms.get 解析。\n //\n // 每个面独立 safe()(free-search/session-guard 同款纪律):未知槽名在个别\n // 宿主线上可能同步抛错,cordis inject 回调抛错会静默吞掉整段 apply——绝不能\n // 让一个面的失败带走其它面(0.1.5 上浮窗齿轮曾因前面 plugins.bundle.config\n // 抛错而被连带吞掉的教训)。\n const safe = (tag: string, fn: () => void): void => {\n try {\n fn()\n } catch (e) {\n // 诊断通道:农场 IAB 拿不到 console,失败面写入 window.__pgSurf 供\n // evaluate 直接读取(失败才初始化——页面侧读到 undefined 即零失败)。\n const surf = ((globalThis as Record<string, unknown>).__pgSurf ??= []) as string[]\n surf.push(`${tag}: ${(e as Error)?.message ?? String(e)}`)\n console.warn(`[dsh-perm-gate] client surface '${tag}' failed:`, e)\n }\n }\n // 2026-10-07 农场 0.1.5 实测定案:0.1.5 上 ctx.inject(['settingsScope']) 的\n // scoped fiber 永不解(free-search 记忆「≤0.1.5 卡片派发 settingsScope 镜像\n // 未证实」的反面坐实),把注册关进回调 = 卡片永不出。同线实证:free-search\n // 的卡注册在 apply 顶层(回调只管数据 bind)所以能出;session-guard 露出的\n // 卡是宿主按 describe 原生渲染的,不是它的回调卡。因此改为 free-search 形态:\n // 注册全部顶层执行,scope 走活引用——回调解到就填,卡片 inject 每次现读。\n const scopeRef: { scope?: PermissiveCardInjected['scope'] } = {}\n resolveSettingsScope(ctx, PERMISSIVE_NS, (scope, _generation) => {\n scopeRef.scope = scope\n })\n\n // T13b 双轨数据源的桥轨:settingsScope(≤0.1.5)不解、且 configForms(0.1.7+)\n // 也没有的线上,卡片数据走自家 webServer 桥(free-search 同架构)。原生句柄\n // 优先——解到就用原生(0.2.0 实测可解),桥只在原生缺席时兜底。\n const bridgeScope: PermissiveCardInjected['scope'] = new BridgeDocHandle()\n\n // 卡片 inject 读活引用:注册先于 scope 解析也不空窗(未解析时回落桥轨,\n // 桥首拉 pending 期间卡片呈现加载态)。\n const cardInjected = (): PermissiveCardInjected => ({ scope: scopeRef.scope ?? bridgeScope }) as PermissiveCardInjected\n\n // 独立顶级设置节(范式 A):自动审查门,不再挂在「插件」节的 tab 下。\n safe('settings.section', () => {\n ctx.slots.inject('settings.section', function* () {\n yield ctx.slots.register({\n name: 'settings.section',\n id: PERMISSIVE_NS,\n order: 30,\n label: () => t('section.title'),\n locale: NS,\n inject: cardInjected,\n }, PermissiveCard)\n }) as unknown\n })\n\n // 插件页配置卡:Plugins 页不会自动渲染 volatile 配置表单——只有客户端注册\n // `plugins.bundle.config` 席位(key = package.json 的 name 字段),页面才会\n // 在 bundle 详情页渲染配置卡。\n safe('plugins.bundle.config', () => {\n ctx.slots.inject('plugins.bundle.config', () => ctx.slots.register({\n name: 'plugins.bundle.config',\n key: 'dsh-perm-gate',\n locale: NS,\n inject: cardInjected,\n }, PermissiveCard)) as unknown\n })\n\n // 0.1.7+/0.2.0「内置插件」页的插件 tab(T14,宿主 client-ui-settings-plugins\n // SettingsRoot:tab 行 = 本槽 entries 的 {id, order, label},内容按 only:id 渲染;\n // 0.2.0 的 settings.section 无消费者——本槽是 0.2.0 唯一插件页入口)。\n // ≤0.1.5 无该槽持有者,注入静默闲置不阻塞(free-search 同款纪律)。\n safe('settings.plugins.tab', () => {\n ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({\n name: 'settings.plugins.tab',\n id: PERMISSIVE_NS,\n order: 50,\n label: () => t('section.title'),\n locale: NS,\n inject: cardInjected,\n }, PermissiveCard)) as unknown\n })\n\n // ≤0.1.5 设置面板「插件配置」tab 的派发卡:宿主按\n // 「服务端 served namespaces ∩ settings.plugin.item 卡 key」交集派发\n // (key 必须 = settings namespace,与 installSection 注册的 ENTRY_ID 一致)。\n // 顶层注册:0.1.7+ 无该槽持有者,注入静默闲置不阻塞(free-search 同款纪律)。\n safe('settings.plugin.item', () => {\n // 槽型联合未收录 id/order(0.1.5 宿主 .d.ts 落后于运行时),运行时按\n // options.id 建行去重——必须带。用松类型别名注册(shell.overlay 同款纪律)。\n const itemSlots = ctx.slots as unknown as {\n inject: (name: string, factory: () => unknown) => unknown\n register: (options: Record<string, unknown>, component: (props: PermissiveCardProps) => JSX.Element) => unknown\n }\n itemSlots.inject('settings.plugin.item', () => itemSlots.register({\n name: 'settings.plugin.item',\n id: PERMISSIVE_NS,\n key: PERMISSIVE_NS,\n order: 40,\n locale: NS,\n inject: cardInjected,\n }, PermissiveCard))\n })\n\n // 0.1.0/0.1.1 等无设置页宿主的兜底入口:壳级 overlay 浮窗齿轮承载审批门卡\n // (数据层与上方几个面共用同一 scope;宿主有设置页的线上与既有入口并存)。\n // shell.overlay 席位在 0.1.0-0.1.5 的壳布局里无条件渲染(AppFrame\n // overlayLayer,list 槽),但不在 0.2.0 槽型联合里(该线上无渲染宿主=无害\n // 空操作)——用松类型别名注册;t 经 inject 显式直传。\n safe('shell.overlay', () => {\n const overlaySlots = ctx.slots as unknown as {\n inject: (name: string, factory: () => unknown) => unknown\n register: (options: { name: string; id?: string; inject: () => PermissiveCardProps }, component: (props: PermissiveCardProps) => JSX.Element) => unknown\n }\n overlaySlots.inject('shell.overlay', () => overlaySlots.register({\n name: 'shell.overlay',\n id: PERMISSIVE_NS,\n inject: (): PermissiveCardProps => ({ t, scope: scopeRef.scope ?? bridgeScope }) as PermissiveCardProps,\n }, FloatingPermissiveGate))\n })\n}"],"mappings":"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"}
|