dsh-perm-gate 5.4.3 → 5.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["useState","useRef","useState","useSyncExternalStore","useState","useRef","useState"],"sources":["../src/client/locales.ts","../src/client/switch-state.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.unattended': '无人值守档位(三套实现,每颗开关决定自己那一档是否存在)',\n 'card.unattendedHint': '三颗开关,每颗只管它旁边标着的那一档:关掉即实现不存在,那一档退回普通人工流,不会偷偷变成别的档。',\n 'card.mode.ask': '保留人工',\n 'card.mode.pass': '机械直通',\n 'card.askHint': '(危险/不确定才人工确认)仍接回沙箱组:作用域内的安全操作照由 trustAutoAllow 自动静默放行、不弹确认;确定性机械审查器只对运行前的危险(破坏性 Git 与文件系统命令、SSH 密钥/.env 等机密访问)与未知残局列出疑点、交人工确认,一次审查模型都不叫——不触发确认的安全操作照常执行。适用于无审查 LLM 可用、或不值当花 token 的运行。',\n 'card.passHint': '(检查通过直接放行、不问人)只跑确定性机械审查器:运行前命中不可逆 / 不可沉淀 / 读不懂的载荷(含破坏性 Git 与文件系统命令、SSH 密钥/.env 等机密访问)就拦截并把理由回喂主模型,检查后无问题的其余照常直接执行。零模型调用——相当于 approval: never 的有审查版,也是 yolo 拿掉 LLM 后的劣化形态。',\n 'card.tierScopeHint': '只有落在门禁作用域(%scope)里的预设才会走到这一步;预设不在作用域内时整个门禁停用,任何开关都不会接管它的确认。',\n 'card.yolo': 'YOLO — 永不人工确认:危险才拦,其余放行',\n 'card.yoloHint': '命中不可逆 / 不可沉淀 / 读不懂的载荷,或模型报硬风险时拦截,并把理由以「工具审核意见」回喂主模型;其余照常执行。没有可用模型时只靠确定性规则网拦截。',\n 'card.rulesFallback': '无模型时降级成规则闸门(cc-safety-net 级)',\n 'card.rulesFallbackHint': '只在审查模型未配置、或模型未能给出裁决时生效:按确定性规则拦危险、放行其余,不再把调用挂在没人应答的确认框上。模型正常回答时行为与之前完全一致。',\n 'card.allowProtectedBranchPush': '允许强推保护分支(默认关=保留地板)',\n 'card.allowProtectedBranchPushHint': '默认用 P0 地板拦下针对 main/master/production/release/stable 的 git push --force/--force-with-lease/--delete(模型不可降级)。开启后地板让位,并豁免黑名单里三条扁平 push 词;调用落到预设的 git.push-force 规则——它仍会问人,除非你撤销该条或加白名单。不放宽任何其他面:删除、重定向、凭据地板照常。',\n 'card.credFamily': '凭据类型阶梯',\n 'card.credFamilyHint': '每类凭据一个档位:deny=读写全拦;ask=读需人工确认(默认);readonly=读放行、写删仍被 P0 硬拦;readwrite=本族内置路径的凭据 store 写判据退让(npm login 类工作流),其余地板(根盘、受保护路径、.dsh、外发)任何档位都不让。档位状态存在规则文档条目与写豁免清单两处,由本卡成对写回。',\n 'card.credFamilyLoading': '正在读取凭据档位…',\n 'card.credFamilyFootnote': '无人值守档(机械直通/YOLO)会把 ask 残局放行;需要硬挡请选 deny。自定义 credentialPaths 不参与写豁免;readwrite 不影响任何非凭据判据。',\n 'card.credReadwriteConfirm': 'readwrite 将放行对该类凭据文件的写入/修改(如重写 ~/.npmrc);这是唯一会退让部分 P0 的档位。确认?',\n 'card.credConfirmYes': '确认',\n 'card.credConfirmNo': '取消',\n 'card.credRung.deny': '拦截',\n 'card.credRung.ask': '确认',\n 'card.credRung.readonly': '只读',\n 'card.credRung.readwrite': '读写',\n 'card.scriptReview': '脚本正文随审查一并送审(默认开)',\n 'card.scriptReviewHint': '调用运行脚本文件时读取它的正文:审查模型与人看的是同一份代码,规则层也按正文判定不可逆(文件名看不出危险的删除正是这么漏掉的)。正文出境前脱敏并截断;关掉它就不会让文件内容离开本机,代价是工作区外的脚本回到「看不清」档位。',\n 'card.credentialPaths': '自定义凭据路径(长尾)',\n 'card.credentialPathsHint': '插件内置清单之外的机密文件。写法是路径 glob:双星跨目录、单星与问号只在一段内;不含通配符时按路径片段匹配(token 不会命中 ambient.txt);行首 ~/ 会展开为你的 home;相对写法也在任意深度匹配(secrets/*.env 覆盖 a/b/secrets/prod.env)。命中后与 .ssh 同档:工作区外读取被硬拒、被文件工具改写被硬拒(这一档不可申诉,也不会被审查模型放行),所以只写确实需要保护的路径。',\n 'card.credentialPathsPlaceholder': '新路径,如 ~/.myco/vault.token 或 secrets/*.env',\n 'card.denyKeywordsExtra': '追加黑名单关键词(不替换预置)',\n 'card.denyKeywordsExtraHint': '在你自己的命令词上加一道确定性拦截,例如公司内部 CLI 的吊销/清库子命令或自有令牌前缀。这里只做追加:无论上面「黑名单」是预置还是你替换过,这些词都会并进去。',\n 'card.listRemove': '移除该条目',\n 'card.extraContentArgKeys': '追加正文键(这些参数不被当操作读)',\n 'card.extraContentArgKeysHint': '内置清单(content/text/plan…)之外的文档字段名,例如某个自有工具的 steps/notes:加进来后,它的文字不再进入危险词与凭据形态的扁平扫描。只追加、不替换内置表——漏写一个内置键就会重现“把计划当操作拒掉”的静默失效。被执行的命令本身与被改写的路径走各自判据,这张表关不掉它们。',\n 'card.extraContentArgKeysPlaceholder': '新参数名,如 steps',\n 'card.extraOperationArgKeys': '追加操作键(把该字段当会执行的代码读)',\n 'card.extraOperationArgKeysHint': '给「正文其实会被执行」的字段开口子(如 workflowYaml):它的文本会进入黑名单与凭据预筛;与上一张表撞名时本表获胜。代价:把真正的文档字段写进来,就等于让「计划里提到 rm -rf」重新变成拒绝理由。',\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.llmEffort': '推理强度(仅 host 模式)',\n 'card.llmEffortHost': '跟随宿主默认',\n 'card.llmEffortHint': '留空=不干预,由宿主模型配置决定;被宿主拒绝时改 low 或 off。',\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 'doubt.no-rule': '没有规则覆盖这次调用,按默认策略交给人 — 这不表示它危险',\n 'doubt.opaque': '命令载荷读不懂(编码过 / 工作区外的脚本 / 认不出程序名),规则层无法定位目标',\n 'doubt.irreversible': '规则判定不可逆:跑完无法撤回',\n 'doubt.never-learn': '这类确认不会沉淀,下次同样的操作还会再问',\n 'doubt.delete': '会删除内容',\n 'doubt.remote-write': '会产生对外可见的副作用(推送 / 发布 / 写请求),撤回需要额外手动操作',\n 'doubt.exec-external': '会执行工作区之外的代码,本次调用无法静态看清它做什么',\n 'doubt.outside-paths': '涉及工作区之外的路径',\n 'doubt.model-flagged': '风险模型认为可疑(它只能升级,不能放行)',\n 'doubt.write': '会写入或修改文件',\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.unattended': 'Unattended tiers (three implementations — each switch decides whether its own tier exists)',\n 'card.unattendedHint': 'Three switches, each governing only the tier named beside it: switching an implementation off returns that tier to the ordinary human flow — it never quietly becomes a different tier.',\n 'card.mode.ask': 'Keep human',\n 'card.mode.pass': 'Mechanical pass-through',\n 'card.askHint': '(Manual confirmation only for danger / uncertainty) Still on the sandbox group: safe operations inside the scope are auto-allowed silently by trustAutoAllow with no popup; the deterministic mechanical screen lists its doubts and asks a person only for pre-execution danger (destructive Git and filesystem commands, access to SSH keys / .env credentials) and unreadable or unknown residuals, calling no grader at all — anything that does not trigger a confirmation runs as normal. The shape for runs with no reviewer LLM connected, or where the tokens are not worth spending.',\n 'card.passHint': '(Auto-allow once the check passes, no human prompt) Runs the deterministic mechanical judge only: before execution an irreversible, unlearnable or unreadable call (including destructive Git and filesystem commands and access to SSH keys / .env credentials) is blocked and the reason fed back to the main model, everything that passes runs directly. No model call — the reviewed form of approval: never, and YOLO with the model taken away.',\n 'card.tierScopeHint': 'Only presets inside the gate\\'s scope (%scope) reach this step; outside it the whole gate stands down, so no switch takes over its confirmations.',\n 'card.yolo': 'YOLO — never ask a human: block the dangerous, run the rest',\n 'card.yoloHint': 'Blocks an irreversible / unlearnable / unreadable payload, or a hard-risk verdict from the model, and feeds the reason back to the main LLM as a 工具审核意见 message; everything else executes. With no reviewer available only the deterministic nets catch anything.',\n 'card.rulesFallback': 'Degrade to a rule-only gate when there is no model (cc-safety-net class)',\n 'card.rulesFallbackHint': 'Takes effect only when the risk reviewer is not configured or gave no verdict: the deterministic nets block what they can name and let the rest through, instead of parking the call on a popup nobody will answer. While a reviewer answers, behaviour is unchanged.',\n 'card.allowProtectedBranchPush': 'Allow force-pushing protected branches (default off = floor stands)',\n 'card.allowProtectedBranchPushHint': 'By default the P0 floor hard-blocks git push --force/--force-with-lease/--delete aimed at main/master/production/release/stable (not downgradable by any model). Turning it on steps the floor aside and exempts the three flat push keywords in the blacklist; the call then falls to the seeded git.push-force rule, which still asks a person unless you revoke that entry or allowlist it. Nothing else widens: wipes, redirects and the credential floor stay armed.',\n 'card.credFamily': 'Credential family ladder',\n 'card.credFamilyHint': 'One rung per family: deny = block reads and writes; ask = reads need a person (default); readonly = reads pass, writes stay hard-blocked by P0; readwrite = the credential-store WRITE clause steps aside for that family\\u0027s built-in paths (npm-login style) — every other floor (roots, protected paths, .dsh, exfil) stays armed at any rung. The rung lives in the rules-document row plus the paired write-exemption list; this card writes both together.',\n 'card.credFamilyLoading': 'Loading credential rungs…',\n 'card.credFamilyFootnote': 'Unattended tiers (mechanical pass / YOLO) let ask residuals run — pick deny to hard-block. Custom credentialPaths never join the write exemption; readwrite changes nothing outside credential stores.',\n 'card.credReadwriteConfirm': 'readwrite lets tools WRITE/modify this family\\u0027s credential files (e.g. rewrite ~/.npmrc). This is the only rung that steps a piece of P0 aside. Confirm?',\n 'card.credConfirmYes': 'Confirm',\n 'card.credConfirmNo': 'Cancel',\n 'card.credRung.deny': 'deny',\n 'card.credRung.ask': 'ask',\n 'card.credRung.readonly': 'readonly',\n 'card.credRung.readwrite': 'readwrite',\n 'card.scriptReview': 'Attach script bodies to the review (on by default)',\n 'card.scriptReviewHint': 'When a call runs a script file, its body is read and given to the risk model and the human alike, and the deterministic nets grade the body too (a delete that only shows up inside the file is exactly what used to slip through). Bodies are redacted and length-capped before leaving the host; switching this off keeps file contents local at the cost of sending out-of-workspace scripts back to the unreadable tier.',\n 'card.credentialPaths': 'Custom credential paths (the long tail)',\n 'card.credentialPathsHint': 'Secret files the built-in list does not know. Entries are path globs: a double star crosses directories, a single star and a question mark stay inside one segment; without a wildcard it matches a whole path fragment (token will not hit ambient.txt); a leading ~/ expands to your home; a relative pattern also matches at any depth (secrets/*.env covers a/b/secrets/prod.env). A hit is held to the same standard as .ssh: reading it outside the workspace is hard-denied, mutating it with a file tool is hard-denied — that tier cannot be appealed or talked past by the reviewer, so declare only paths you truly need protected.',\n 'card.credentialPathsPlaceholder': 'New path, e.g. ~/.myco/vault.token or secrets/*.env',\n 'card.denyKeywordsExtra': 'Appended blacklist keywords (never replaces the preset)',\n 'card.denyKeywordsExtraHint': 'A deterministic block on words of your own — a revoke/wipe subcommand of a company CLI, a token prefix you issue. This list only ever appends: whatever the blacklist above holds (preset or your own replacement), these words are merged in.',\n 'card.listRemove': 'Remove this entry',\n 'card.extraContentArgKeys': 'Appended document keys (never read as an operation)',\n 'card.extraContentArgKeysHint': 'Document field names beyond the built-in list (content/text/plan…): once listed, their text stops entering the flattened scan that the destructive-word blacklist and the credential pre-screen read. Additive only — the built-in list cannot be replaced, because dropping one of its keys would silently re-create the bug where a plan gets refused for describing work. The executed command and the mutated path are judged on their own terms; this list cannot switch them off.',\n 'card.extraContentArgKeysPlaceholder': 'New argument name, e.g. steps',\n 'card.extraOperationArgKeys': 'Appended operation keys (read this field as code that runs)',\n 'card.extraOperationArgKeysHint': 'Opens a route for fields whose body really is executed (workflowYaml and friends): their text enters the blacklist and the credential screen, and this list wins when both name the same key. Cost: naming a genuine document field here makes “the plan mentions rm -rf” a refusal reason again.',\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.llmEffort': 'Reasoning effort (host mode only)',\n 'card.llmEffortHost': 'Follow the host default',\n 'card.llmEffortHint': 'Empty = send no effort and let the host model config decide; switch to low or off if the host rejects it.',\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 'doubt.no-rule': 'no rule covers this call, so the default is to ask — that does not mean it is dangerous',\n 'doubt.opaque': 'the payload cannot be read (encoded, a script outside the workspace, or no recognisable program), so no rule can locate its target',\n 'doubt.irreversible': 'a rule says this is irreversible: it cannot be undone once run',\n 'doubt.never-learn': 'this answer will not be learned; the same call will ask again next time',\n 'doubt.delete': 'it deletes content',\n 'doubt.remote-write': 'it has an externally visible effect (push / publish / write request); undoing it takes extra manual steps',\n 'doubt.exec-external': 'it runs code from outside the workspace, which this call cannot inspect',\n 'doubt.outside-paths': 'it touches paths outside the workspace',\n 'doubt.model-flagged': 'the risk model flagged it (it can only escalate, never clear)',\n 'doubt.write': 'it writes or modifies files',\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.unattended': '無人確認ティア(3 つの実装 — スイッチは各自のティアの有無を決めます)',\n 'card.unattendedHint': 'スイッチは三つ。それぞれ脇に書いたティアだけを制御します。実装をオフにするとそのティアは通常の人確認に戻り、別のティアに化けることはありません。',\n 'card.mode.ask': '人手確認を残す',\n 'card.mode.pass': '機械直通',\n 'card.askHint': '機械スクリーニングは引き続き危険を絞り疑点を列挙しますが、確認は人に残り審査モデルは一度も呼びません — 審査 LLM 未接続、またはトークンを費やさない運用の形です。',\n 'card.passHint': '決定論的な機械審査器のみを実行:不可逆 / 復元不能 / 読めない処理を検知したら遮断して理由を主モデルへ返し、それ以外は実行します。モデル呼び出しゼロ・人手確認なし。approval: never の審査付き版であり、LLM を外した YOLO の劣化形態でもあります。',\n 'card.tierScopeHint': 'このステップまで到達するのはゲートの適用範囲(%scope)内のプリセットだけです。範囲外ではゲート全体が停止し、どのスイッチも確認を代行しません。',\n 'card.yolo': 'YOLO — 人工確認は決して求めない:危険のみ遮断、他は実行',\n 'card.yoloHint': '復元不能 / 学習不能 / 読解不能なペイロード、またはモデルの重リスク判定を遮断し、理由を「工具審核意見」メッセージでメイン LLM に返します。それ以外は実行されます。レビューモデルが無い場合は決定論的ネットのみが機能します。',\n 'card.rulesFallback': 'モデル不在時はルールゲートへ劣化(cc-safety-net 級)',\n 'card.rulesFallbackHint': 'レビューモデルが未設定、または判定を返せなかったときだけ発効します。決定論的ルールが名指しできる危険を遮断し、残りは通します。誰も答えない確認画面で処理を止めないためです。モデルが答えている間は挙動は変わりません。',\n 'card.allowProtectedBranchPush': '保護ブランチへの force push を許可(既定オフ=床を維持)',\n 'card.allowProtectedBranchPushHint': '既定では main/master/production/release/stable を狙った git push --force/--force-with-lease/--delete を P0 床で確定遮断します(モデルで降格不可)。オンにすると床が退き、ブラックリストの3つの扁平 push 語も免除されます。呼び出しはプリセット git.push-force(人間確認が必要)に落ち、該当エントリを取り消すか許可リストに入れるまで毎回確認します。他の面は広がりません:削除・リダイレクト・認証情報の床はそのまま。',\n 'card.credFamily': '認証情報ファミリーの階段',\n 'card.credFamilyHint': 'ファミリーごとに1段:deny=読み書きとも遮断;ask=読みは人間確認(既定);readonly=読み通過、書き/削除はP0で確定遮断のまま;readwrite=このファミリーの認証情報ストア書き込み判据のみ退く(npm login 系)。その他の床(ルートディスク・保護パス・.dsh・外部送信)はどの段でも動かさない。段の状態はルール文書の条目と書き込み免除リストの2箇所に置かれ、本カードが対で書き戻す。',\n 'card.credFamilyLoading': '認証情報の段を読み込み中…',\n 'card.credFamilyFootnote': '無人運用モード(機械直通/YOLO)では確認残局がそのまま通ります。硬く止めるには deny を選択してください。カスタム credentialPaths は書き込み免除に参加しません。',\n 'card.credReadwriteConfirm': 'readwrite はこの種の認証情報ファイルへの書き込み/変更を許可します(~/.npmrc の上書きなど)。P0 の一部を退かす唯一の段です。確認しますか?',\n 'card.credConfirmYes': '確認',\n 'card.credConfirmNo': 'キャンセル',\n 'card.credRung.deny': '遮断',\n 'card.credRung.ask': '確認',\n 'card.credRung.readonly': '読取のみ',\n 'card.credRung.readwrite': '読み書き',\n 'card.scriptReview': 'スクリプト本文をレビューに添付(既定はオン)',\n 'card.scriptReviewHint': '呼び出しがスクリプトファイルを実行するとき、その本文を読み取り、レビューモデルと人が同じコードを見ます。決定論的ネットも本文を評価します(ファイル名からは見えない削除がまさに通過していた箇所)。送出前に秘匿化と長さ制限を実施。オフにするとファイル内容が外部へ出ませんが、ワークスペース外のスクリプトは「読解不能」ティアに戻ります。',\n 'card.credentialPaths': 'カスタム認証情報パス(長尾)',\n 'card.credentialPathsHint': '内蔵リスト外の機密ファイル。書き方はパス glob:双アスタリスクはディレクトリを横断、単アスタリスクとはてなは 1 段内。ワイルドカードなしならパス断片として一致(token は ambient.txt に掛からない)。先頭の ~/ は home に展開、相対指定は任意の深さでも一致(secrets/*.env は a/b/secrets/prod.env を覆う)。該当すれば .ssh と同格:ワークスペース外からの読み取りもファイルツールでの書き換えも強制拒否——このティアは異議申立て、レビューモデルの通過も不可なので、本当に守るべきパスだけを宣言してください。',\n 'card.credentialPathsPlaceholder': '新しいパス、例:~/.myco/vault.token または secrets/*.env',\n 'card.denyKeywordsExtra': 'ブラックリスト追加キーワード(プリセットを置き換えない)',\n 'card.denyKeywordsExtraHint': '自社 CLI の取消し/消去サブコマンドや自社トークン接頭語など、自分の語彙に決定論的な遮断を一段足します。ここは追加のみ:上のブラックリストがプリセットでも自分で置き換えたものでも、これらの語はマージされます。',\n 'card.listRemove': 'この項目を削除',\n 'card.extraContentArgKeys': '追加のドキュメントキー(操作として読ませない)',\n 'card.extraContentArgKeysHint': '内蔵リスト(content/text/plan…)外のドキュメント項目名。追加すると、その文言は危険語と認証情報の平坦スキャンに入らなくなります。追加専用で内蔵表は置き換えません——内蔵キーを一つ落とすと「計画書を書いたという理由で拒否される」不具合が静かに復活します。実行されるコマンド自体と書き換えられるパスはそれぞれの判別経路なので、この表では無効化できません。',\n 'card.extraContentArgKeysPlaceholder': '新しい引数名、例:steps',\n 'card.extraOperationArgKeys': '追加の操作キー(その項目を実行されるコードとして読む)',\n 'card.extraOperationArgKeysHint': '本文が実際に実行される項目(workflowYaml など)用の出口です。その文言はブラックリストと認証情報スクリーンに入り、上の表と同名ならこちらが勝ちます。代償:本物のドキュメント項目を指定すると、「計画に rm -rf と書いた」ことが再び拒否理由になります。',\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.llmEffort': '推論強度(host モードのみ)',\n 'card.llmEffortHost': 'ホスト既定に従う',\n 'card.llmEffortHint': '空 = 指定せずホストのモデル設定に任せる。ホストに拒否されたら low か off に変更。',\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 'doubt.no-rule': 'この呼び出しを覆うルールがなく、既定で人間に委ねました — 危険という意味ではありません',\n 'doubt.opaque': 'ペイロードを読み取れません(エンコード済み / ワークスペース外スクリプト / プログラム名不明)、ルールは対象を特定できません',\n 'doubt.irreversible': 'ルール上 不可逆:実行後は取り消せません',\n 'doubt.never-learn': 'この承認は学習されません。次回も同じ確認が出ます',\n 'doubt.delete': '内容を削除します',\n 'doubt.remote-write': '外部から見える変更(push / publish / 書き込みリクエスト)が発生し、取り消しに手作業が必要',\n 'doubt.exec-external': 'ワークスペース外のコードを実行します。この呼び出しでは内容を抜き取れません',\n 'doubt.outside-paths': 'ワークスペース外のパ스에接触します',\n 'doubt.model-flagged': '风险モデルが疑わしいと判定(エスカレートののみ可能、クリアは不可)',\n 'doubt.write': 'ファイルを書き込みまたは変更します',\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.unattended': '무인 등급(구현 세 개 — 각 스위치가 자기 등급의 존재 여부를 정합니다)',\n 'card.unattendedHint': '스위치는 셋, 각자 옆에 적힌 등급만 제어합니다. 구현을 끄면 그 등급은 보통의 사람 확인으로 돌아가며, 다른 등급으로 몰래 바뀌지 않습니다.',\n 'card.mode.ask': '사람 확인 유지',\n 'card.mode.pass': '기계 직통과',\n 'card.askHint': '기계 선별로 위험을 걸러 내고 의문점을 적지만, 확인은 그대로 사람에게 남고 심사 모델은 한 번도 부르지 않습니다 — 심사 LLM 미연결이나 토큰을 아끼는 운용에 맞는 형태입니다.',\n 'card.passHint': '결정론적 기계 심사기만 실행:되돌릴 수 없음 / 복원 불가 / 읽히지 않는 처리를 감지하면 차단하고 이유를 주모델에 되돌려 보내며, 나머지는 실행합니다. 모델 호출 0회·사람 확인 없음. approval: never 의 심사판이며, LLM 을 뺀 YOLO 의 열화된 형태이기도 합니다.',\n 'card.tierScopeHint': '게이트 적용 범위(%scope) 안의 프리셋만 이 단계까지 옵니다. 범위 밖에서는 게이트 전체가 중지되므로 어떤 스위치도 확인을 대신하지 않습니다.',\n 'card.yolo': 'YOLO — 사람 확인은 절대 요구하지 않음: 위험만 차단하고 나머지는 실행',\n 'card.yoloHint': '복구 불가 / 학습 불가 / 해석 불가 페이로드, 또는 모델이 위험 판정을 내리면 차단하고 이유를 「工具审核意见」 메시지로 메인 LLM에 알려합니다. 나머지는 그대로 실행됩니다. 검토 모델이 없으면 결정론적 규칙망만 작동합니다.',\n 'card.rulesFallback': '모델이 없을 때 규칙 게이트로 강등 (cc-safety-net 급)',\n 'card.rulesFallbackHint': '검토 모델이 설정되지 않았거나 판정을 내리지 못했을 때만 발동합니다. 결정론적 규칙이 식별한 위험은 차단하고 나머지는 통과시켜, 아무도 응답하지 않는 확인 창에 호출을 대기시키지 않습니다. 모델이 정상 응답하는 동안에는 동작이 변하지 않습니다.',\n 'card.allowProtectedBranchPush': '보호 브랜치 force push 허용 (기본 꺼짐 = 바닥 유지)',\n 'card.allowProtectedBranchPushHint': '기본에서 main/master/production/release/stable 을 노린 git push --force/--force-with-lease/--delete 를 P0 바닥으로 확정 차단합니다(모델로 강등 불가). 켜면 바닥이 물러나고 블랙리스트의 세 평면 push 키워드도 면제됩니다. 호출은 프리셋 git.push-force(사람 확인 필요) 규칙으로 떨어져, 해당 항목을 취소하거나 허용 목록에 넣기 전엔 매번 확인합니다. 다른 면은 넓어지지 않습니다: 삭제·리다이렉트·자격증명 바닥은 그대로.',\n 'card.credFamily': '자격증명 계열 사다리',\n 'card.credFamilyHint': '계열별 한 칸: deny=읽기·쓰기 모두 차단; ask=읽기 사람 확인(기본); readonly=읽기 통과, 쓰기·삭제는 P0 확정 차단 유지; readwrite=해당 계열의 자격증명 store 쓰기 판정만 물러남(npm login 계열). 그 외 바닥(루트·보호 경로·.dsh·유출)은 어떤 칸에서도 움직이지 않습니다. 상태는 규칙 문서 항목과 쓰기 면제 목록 두 곳에 저장되며 이 카드가 한 쌍으로 함께 씁니다.',\n 'card.credFamilyLoading': '자격증명 단계 로딩 중…',\n 'card.credFamilyFootnote': '무인 등급(기계 직통/YOLO)에서는 ask 잔여가 통과합니다. 단단히 막으려면 deny를 선택하세요. 사용자 지정 credentialPaths는 쓰기 면제에 참여하지 않습니다.',\n 'card.credReadwriteConfirm': 'readwrite는 이 종 자격증명 파일의 쓰기/수정을 허용합니다(~/.npmrc 재작성 등). P0의 일부를 퇴각시키는 유일한 칸입니다. 확인하시겠습니까?',\n 'card.credConfirmYes': '확인',\n 'card.credConfirmNo': '취소',\n 'card.credRung.deny': '차단',\n 'card.credRung.ask': '확인',\n 'card.credRung.readonly': '읽기 전용',\n 'card.credRung.readwrite': '읽기쓰기',\n 'card.scriptReview': '스크립트 본문 검토 함께 전송 (기본 켜짐)',\n 'card.scriptReviewHint': '호출이 스크립트 파일을 실행하면 본문을 읽어 검토 모델과 사람이 같은 코드를 보게 하고, 결정론적 규칙도 본문을 평가합니다 (파일명으로는 위험이 보이지 않는 삭제가 바로 그 통과 지점이었습니다). 전송 전 마스킹과 길이 제한을 적용합니다. 끄면 파일 내용이 외부로 나가지 않지만, 작업 공간 외부 스크립트는 다시 해석 불가 등급이 됩니다.',\n 'card.credentialPaths': '사용자 정의 자격증명 경로 (롱테일)',\n 'card.credentialPathsHint': '내장 목록이 모르는 비밀 파일입니다. 항목은 경로 glob: 이중 별은 디렉터리를 횡단하고 단별과 물음표는 한 단계 안에서만 동작합니다. 와일드카드가 없으면 경로 단편 전체로 일치 (token 은 ambient.txt 에 걸리지 않음). 선행 ~/ 는 home 으로 확장되고, 상대 지정은 어떤 깊이에서도 일치합니다 (secrets/*.env 는 a/b/secrets/prod.env 를 커버). 걸리면 .ssh 와 동일한 등급: 작업 공간 외부 읽기와 파일 도구 통한 변경 모두 경성 거부입니다—이 등급은 이의 제기나 검토 모델 우회가 불가능하니 정말 보호할 경로만 선언하세요.',\n 'card.credentialPathsPlaceholder': '새 경로, 예: ~/.myco/vault.token 또는 secrets/*.env',\n 'card.denyKeywordsExtra': '추가 블랙리스트 키워드 (프리셋을 대체하지 않음)',\n 'card.denyKeywordsExtraHint': '사내 CLI 의 폐기/삭제 서브커맨드나 자체 토큰 접두사처럼 자신만의 용어에 결정론적 차단을 한 겹 더합니다. 여기는 추가만 합니다: 위의 블랙리스트가 프리셋이든 대체한 것이든 이 단어들은 병합됩니다.',\n 'card.listRemove': '이 항목 삭제',\n 'card.extraContentArgKeys': '추가 문서 키 (작업으로 읽지 않음)',\n 'card.extraContentArgKeysHint': '내장 목록(content/text/plan…) 밖의 문서 필드명입니다. 추가하면 그 텍스트가 위험 단어 · 자격증물 평탄화 스캔에 들어가지 않습니다. 추가 전용이며 내장 표를 대체하지 않습니다 — 내장 키 하나를 빠뜨리면 『계획서를 작성했다는 이유로 거부되는』 결함이 조용히 부활합니다. 실제로 실행되는 명령과 변경되는 경로는 각자의 판정을 따르므로 이 표로는 끌 수 없습니다.',\n 'card.extraContentArgKeysPlaceholder': '새 인자 이름, 예: steps',\n 'card.extraOperationArgKeys': '추가 작업 키 (해당 필드를 실행되는 코드로 읽음)',\n 'card.extraOperationArgKeysHint': '본문이 실제로 실행되는 필드(workflowYaml 등)를 위한 통로입니다. 텍스트가 블랙리스트와 자격증물 스크린에 들어가며 위 표와 같은 키를 지정하면 이쪽이 이깁니다. 대가: 진짜 문서 필드를 지정하면 『계획에 rm -rf 가 적혀 있다』는 다시 거부 이유가 됩니다.',\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.llmEffort': '추론 강도 (host 모드 전용)',\n 'card.llmEffortHost': '호스트 기본값 따름',\n 'card.llmEffortHint': '비움 = 지정하지 않고 호스트 모델 설정을 따름. 호스트가 거부하면 low 나 off 로 변경.',\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 'doubt.no-rule': '이 호출을 작용하는 규칙이 없어 기본 전략으로 사람에게 양도합니다 — 위험하다는 의미가 아닙니다',\n 'doubt.opaque': '페이로드를 읽을 수 없음 (인코딩됨 / 작업 공간 밖 스크립트 / 프로그램명 불명) → 규칙이 대상을 특정할 수 없음',\n 'doubt.irreversible': '규칙상 불가역: 실행 후 채취 불가',\n 'doubt.never-learn': '이 승인은 학습되지 않습니다. 다음에도 같은 확인이 나옵니다',\n 'doubt.delete': '내용을 삭제합니다',\n 'doubt.remote-write': '외부에 보이는 변경(push / publish / 쓰기 요청)이 발생하며, 취소하려면 수동 작업이 필요합니다',\n 'doubt.exec-external': '작업 공간 밖의 코드를 실행합니다. 이 호출에서는 내용을 확인할 수 없습니다',\n 'doubt.outside-paths': '작업 공간 밖 경로에 접촉합니다',\n 'doubt.model-flagged': '위험 모델이 의심됨 (증액만 가능, 해소 불가)',\n 'doubt.write': '파일을 쓰거나 수정합니다',\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.unattended': 'Modes sans supervision (trois implémentations ; chaque interrupteur décide si son palier existe)',\n 'card.unattendedHint': 'Trois interrupteurs, chacun ne régit que le palier nommé à côté : éteindre une implémentation rend ce palier au flux humain ordinaire — il ne devient jamais un autre palier en secret.',\n 'card.mode.ask': 'Garder l\\'humain',\n 'card.mode.pass': 'Passage mécanique',\n 'card.askHint': 'Le tamis mécanique filtre toujours et expose ses doutes, mais la demande reste soumise à une personne et aucun évaluateur n\\'est appelé — la forme qui convient quand aucun LLM relecteur n\\'est branché, ou quand les jetons ne valent pas la dépense.',\n 'card.passHint': 'N\\'exécute que le juge mécanique déterministe : une opération irréversible, irrécupérable ou illisible est bloquée et justifiée en retour au modèle principal, le reste s\\'exécute. Aucun appel de modèle, aucune demande humaine — la version examinée de approval: never, et le YOLO privé de son modèle.',\n 'card.tierScopeHint': 'Seuls les préréglages compris dans le périmètre du garde (%scope) atteignent cette étape ; en dehors, le garde s\\'efface complètement et aucun interrupteur ne prend ses confirmations en charge.',\n 'card.yolo': 'YOLO — ne jamais demander un humain : bloquer le dangereux, exécuter le reste',\n 'card.yoloHint': 'Bloque une charge irréversible / inapprenable / illisible, ou un verdict à risque dur du modèle, et renvoie la raison au LLM principal dans un message 工具审核意见 ; tout le reste s\\'exécute. Sans modèle disponible, seules les filets déterministes bloquent.',\n 'card.rulesFallback': 'Dégrader vers une porte à règles quand il n\\'y a pas de modèle (classe cc-safety-net)',\n 'card.rulesFallbackHint': 'Ne s\\'applique que lorsque le relecteur de risque n\\'est pas configuré ou n\\'a pas rendu de verdict : les filets déterministes bloquent ce qu\\'ils peuvent nommer et laissent passer le reste, au lieu de immobiliser l\\'appel sur une popup que personne ne répondra. Tant qu\\'un relecteur répond, le comportement est inchangé.',\n 'card.allowProtectedBranchPush': 'Autoriser le force-push sur les branches protégées (par défaut inactif = plancher maintenu)',\n 'card.allowProtectedBranchPushHint': 'Par défaut, le plancher P0 bloque git push --force/--force-with-lease/--delete visant main/master/production/release/stable (non rétrogradable par un modèle). L\\'activer écarte le plancher et exempte les trois mots-clés push de la liste noire ; l\\'appel retombe sur la règle git.push-force intégrée, qui demande toujours un humain sauf si vous révoquez cette entrée ou l\\'ajoutez en allowlist. Rien d\\'autre ne s\\'élargit : suppressions, redirections et le plancher d\\'identifiants restent armés.',\n 'card.credFamily': 'Escalier des familles de secrets',\n 'card.credFamilyHint': 'Un cran par famille : deny = lectures et écritures bloquées ; ask = lecture avec validation humaine (défaut) ; readonly = lectures libres, écritures toujours refusées par le plancher P0 ; readwrite = la clause d\\u0027écriture du store de credentials se retire pour cette famille (cas npm login). Les autres planchers (racines, chemins protégés, .dsh, exfiltration) restent armés à tout cran. L\\u0027état vit dans la ligne du document de règles plus la liste d\\u0027exemption ; la carte écrit les deux ensemble.',\n 'card.credFamilyLoading': 'Chargement des crans…',\n 'card.credFamilyFootnote': 'Les paliers sans humain (passage mécanique / YOLO) laissent passer le reliquat des ask — choisir deny pour bloquer. Les credentialPaths personnalisés ne bénéficient jamais de l\\u0027exemption d\\u0027écriture.',\n 'card.credReadwriteConfirm': 'readwrite autorise l\\u0027écriture/modification des fichiers de secrets de cette famille (réécriture de ~/.npmrc). Seul cran qui écarte une part du P0. Confirmer ?',\n 'card.credConfirmYes': 'Confirmer',\n 'card.credConfirmNo': 'Annuler',\n 'card.credRung.deny': 'bloquer',\n 'card.credRung.ask': 'demander',\n 'card.credRung.readonly': 'lecture seule',\n 'card.credRung.readwrite': 'lecture écriture',\n 'card.scriptReview': 'Joindre le contenu des scripts à la revue (activé par défaut)',\n 'card.scriptReviewHint': 'Quand un appel exécute un fichier script, son corps est lu et donné au modèle de risque comme à l\\'humain, et les filets déterministes évaluent aussi ce corps (une suppression invisible dans le nom de fichier est précisément ce qui passait). Le corps est masqué et borné avant sortie ; le désactiver garde le contenu des fichiers en local, au prix de renvoyer les scripts hors espace de travail dans le palier « illisible ».',\n 'card.credentialPaths': 'Chemins de credentials personnalisés (la longue traîne)',\n 'card.credentialPathsHint': 'Des fichiers secrets que la liste intégrée ne connaît pas. Les entrées sont des globs de chemin : une double étoile traverse les répertoires, une étoile simple et un point d\\'interrogation restent dans un segment ; sans joker, la correspondance se fait sur un fragment de chemin entier (token ne touchera pas ambient.txt) ; un ~/ initial se développe vers votre home ; un motif relatif correspond aussi à n\\'importe quelle profondeur (secrets/*.env couvre a/b/secrets/prod.env). Une correspondance est tenue au même standard que .ssh : la lecture hors espace de travail et la mutation par un outil de fichier sont refusées durablement — ce niveau n\\'est ni contestable ni franchissable par le relecteur, ne déclarez donc que les paths à protéger vraiment.',\n 'card.credentialPathsPlaceholder': 'Nouveau chemin, ex. ~/.myco/vault.token ou secrets/*.env',\n 'card.denyKeywordsExtra': 'Mots-clés blacklist ajoutés (ne remplace pas le prédéfini)',\n 'card.denyKeywordsExtraHint': 'Un blocage déterministe sur vos propres termes — une sous-commande de révocation d\\'un CLI interne, un préfixe de jeton qui vous est propre. Cette liste n\\'ajoute que des termes : quel que soit le contenu de la blacklist au-dessus (prédéfinie ou remplacée par vous), ces mots sont fusionnés.',\n 'card.listRemove': 'Retirer cette entrée',\n 'card.extraContentArgKeys': 'Clés de document ajoutées (jamais lues comme une opération)',\n 'card.extraContentArgKeysHint': 'Des noms de champs documentaires absents de la liste intégrée (content/text/plan…) : une fois déclarés, leur texte ne participe plus à la lecture à plat des mots dangereux et des formes d\\'identifiants. Purement additif : la liste intégrée ne peut pas être remplacée, car oublier une de ses clés ferait reparaître en silence le bug où un plan est refusé pour décrire une action. La commande réellement exécutée et le chemin modifié jugés par leurs propres voies, cette liste ne peut pas les éteindre.',\n 'card.extraContentArgKeysPlaceholder': 'Nouveau nom d\\'argument, ex. steps',\n 'card.extraOperationArgKeys': 'Clés d\\'opération ajoutées (lire ce champ comme du code exécuté)',\n 'card.extraOperationArgKeysHint': 'Un passage pour les champs dont le corps est réellement exécuté (workflowYaml etc.) : leur texte entre dans la blacklist et l\\'écran d\\'identifiants, et cette liste gagne en cas de doublon. Coût : désigner un vrai champ documentaire rend de nouveau « le plan mentionne rm -rf » motif de refus.',\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.llmEffort': 'Effort de raisonnement (mode host)',\n 'card.llmEffortHost': 'Suivre l’hôte',\n 'card.llmEffortHint': 'Vide = ne rien imposer, la config du modèle hôte décide ; passer à low ou off si l’hôte refuse.',\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 'doubt.no-rule': 'aucune règle ne couvre cet appel, le défaut est de demander — cela ne signifie pas qu’il est dangereux',\n 'doubt.opaque': 'le payload est illisible (encodé, script hors workspace, ou programme non reconnu), aucune règle ne peut localiser sa cible',\n 'doubt.irreversible': 'règle irréversible : après exécution, annulation impossible',\n 'doubt.never-learn': 'cette réponse ne sera pas mémorisée ; la même question se reposera',\n 'doubt.delete': 'supprime du contenu',\n 'doubt.remote-write': 'effet visible de l’extérieur (push / publish / écriture) ; annuler nécessite des étapes manuelles',\n 'doubt.exec-external': 'exécute du code hors workspace, non inspectable par cet appel',\n 'doubt.outside-paths': 'accède à des chemins hors workspace',\n 'doubt.model-flagged': 'le modèle de risque l’a signalé (il peut uniquement escalader, jamais lever)',\n 'doubt.write': 'écrit ou modifie des fichiers',\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.unattended': 'Unbeaufsichtigte Stufen (drei Implementierungen; jeder Schalter entscheidet, ob seine Stufe existiert)',\n 'card.unattendedHint': 'Drei Schalter, jeder steuert nur die Stufe daneben: wer die Implementierung abschaltet, lässt diese Stufe zum normalen Menschenablauf zurückkehren — sie wird nie stillschweigend zu einer anderen.',\n 'card.mode.ask': 'Mensch behalten',\n 'card.mode.pass': 'Mechanischer Durchlass',\n 'card.askHint': 'Die mechanische Vorprüfung filtert und nennt ihre Zweifel, aber die Anfrage bleibt bei einem Menschen, und das Bewertungsmodell wird kein einziges Mal aufgerufen — die Form für Läufe ohne verbundenen Reviewer-LLM oder wenn sich die Tokens nicht lohnen.',\n 'card.passHint': 'Lässt nur den deterministischen mechanischen Prüfer laufen: eine irreversible, nicht rücknehmbare oder unlesbare Anfrage wird blockt und dem Hauptmodell begründet zurückgemeldet, alles andere läuft. Kein Modellaufruf, keine Frage an einen Menschen — die geprüfte Form von approval: never und YOLO ohne Modell.',\n 'card.tierScopeHint': 'Nur Presets innerhalb des Gate-Umfangs (%scope) erreichen diesen Schritt; außerhalb davon schaltet sich das Gate komplett ab, kein Schalter übernimmt dann dessen Bestätigungen.',\n 'card.yolo': 'YOLO — niemals einen Menschen fragen: nur Gefährliches blockieren, Rest ausführen',\n 'card.yoloHint': 'Blockiert eine unwiderrufliche / nicht lernbare / unlesbare Last oder ein Hartrisiko-Urteil des Modells und meldet den Grund dem Haupt-LLM als 工具审核意见-Nachricht; alles andere läuft. Ohne erreichbares Review-Modell fangen nur die deterministischen Netze.',\n 'card.rulesFallback': 'Ohne Modell zu einem Regel-Gate degradieren (cc-safety-net-Klasse)',\n 'card.rulesFallbackHint': 'Greift nur, wenn das Review-Modell nicht konfiguriert ist oder kein Urteil geliefert hat: die deterministischen Netze blockieren, was sie benennen können, und lassen den Rest durch, statt den Aufruf in einem Popup warten zu lassen, das niemand beantwortet. Solange ein Modell antwortet, bleibt das Verhalten unverändert.',\n 'card.allowProtectedBranchPush': 'Force-Push auf geschützte Branches erlauben (Standard aus = Boden bleibt)',\n 'card.allowProtectedBranchPushHint': 'Standardmäßig blockiert der P0-Boden git push --force/--force-with-lease/--delete auf main/master/production/release/stable (per Modell nicht herabstufbar). Beim Einschalten weicht der Boden und die drei flachen push-Schlüsselwörter der Blacklist werden ausgenommen; der Aufruf fällt auf die eingepasste Regel git.push-force, die weiterhin eine Person fragt — solange Sie den Eintrag nicht widerrufen oder auf die Allowlist setzen. Nichts anderes weitet sich: Löschen, Redirects und der Credential-Boden bleiben scharf.',\n 'card.credFamily': 'Credential-Familien-Stufenleiter',\n 'card.credFamilyHint': 'Eine Stufe pro Familie: deny = Lesen und Schreiben blockiert; ask = Lesen mit Bestätigung (Standard); readonly = Lesen frei, Schreiben bleibt P0-hart blockiert; readwrite = die Credential-Store-Schreibklausel weicht für diese Familie (npm-login-Fall). Alle anderen Böden (Roots, geschützte Pfade, .dsh, Exfiltration) bleiben in jeder Stufe scharf. Der Zustand lebt in der Regelzeile plus der Schreibausnahme-Liste; diese Karte schreibt beide gepaart zurück.',\n 'card.credFamilyLoading': 'Stufen werden geladen…',\n 'card.credFamilyFootnote': 'Unbeaufsichtigte Stufen (mechanischer Durchlass / YOLO) lassen ask-Reste durch — für harte Blockierung deny wählen. Eigene credentialPaths nehmen nie an der Schreibausnahme teil.',\n 'card.credReadwriteConfirm': 'readwrite erlaubt Schreiben/Ändern der Credential-Datei dieser Familie (z. B. ~/.npmrc überschreiben). Die einzige Stufe, die einen Teil von P0 zurücktritt. Bestätigen?',\n 'card.credConfirmYes': 'Bestätigen',\n 'card.credConfirmNo': 'Abbrechen',\n 'card.credRung.deny': 'blockieren',\n 'card.credRung.ask': 'fragen',\n 'card.credRung.readonly': 'nur Lesen',\n 'card.credRung.readwrite': 'Lesen+Schreiben',\n 'card.scriptReview': 'Skriptinhalte der Prüfung beifügen (standardmäßig an)',\n 'card.scriptReviewHint': 'Führt ein Aufruf eine Skriptdatei aus, wird ihr Inhalt gelesen und dem Risikomodell wie dem Menschen gezeigt, und die deterministischen Netze bewerten ebenfalls den Inhalt (ein Löschen, das nur in der Datei sichtbar ist, war genau das, was durchrutschte). Inhalte werden vor dem Verlassen des Rechners maskiert und begrenzt; abschalten hält Dateiinhalte lokal, kostet aber, dass Skripte außerhalb des Arbeitsbereichs wieder als „unlesbar“ gelten.',\n 'card.credentialPaths': 'Eigene Credential-Pfade (der lange Schwanz)',\n 'card.credentialPathsHint': 'Geheime Dateien, die die eingebaute Liste nicht kennt. Einträge sind Pfad-Globs: ein Doppelstern überquert Verzeichnisse, ein Einzelstern und ein Fragezeichen bleiben in einem Segment; ohne Joker wird über ein ganzes Pfadfragment verglichen (token trifft nicht ambient.txt); ein führendes ~/ wird zu Ihrem Home aufgelöst; ein relativer Muster passt auch in jeder Tiefe (secrets/*.env deckt a/b/secrets/prod.env ab). Ein Treffer gilt nach demselben Maßstab wie .ssh: Lesen außerhalb des Arbeitsbereichs und Ändern durch ein Dateiwerkzeug werden hart abgelehnt — diese Stufe ist weder anfechtbar noch vom Prüfer umgehbar, erklären Sie also nur Pfade, die wirklich geschützt müssen werden.',\n 'card.credentialPathsPlaceholder': 'Neuer Pfad, z. B. ~/.myco/vault.token oder secrets/*.env',\n 'card.denyKeywordsExtra': 'Zusätzliche Blacklist-Schlüsselwörter (ersetzt den Voreinstellung nicht)',\n 'card.denyKeywordsExtraHint': 'Eine deterministische Blockierung für Ihre eigenen Begriffe — ein Sperr-/Lösch-Unterbefehl einer firmeneigenen CLI, ein von Ihnen ausgegebener Token-Präfix. Diese Liste fügt nur hinzu: was die Blacklist oben enthält (Voreinstellung oder eigene Ersetzung), diese Wörter werden übernommen.',\n 'card.listRemove': 'Diesen Eintrag entfernen',\n 'card.extraContentArgKeys': 'Zusätzliche Dokument-Schlüssel (nicht als Operation gelesen)',\n 'card.extraContentArgKeysHint': 'Feldnamen außerhalb der eingebauten Liste (content/text/plan…): gelistet, gelangt ihr Text nicht mehr in das flache Lesen von Gefahrwörtern und Credential-Formen. Nur ergänzend — die eingebaute Liste ist nicht ersetzbar, denn ein fehlender Schlüssel würde den Fehler leise zurückbringen, dass ein Plan für das bloße Beschreiben einer Arbeit abgelehnt wird. Das tatsächlich ausgeführte Kommando und der geänderte Pfad werden auf eigenen Wegen geprüft; diese Liste kann sie nicht abschalten.',\n 'card.extraContentArgKeysPlaceholder': 'Neuer Argumentname, z. B. steps',\n 'card.extraOperationArgKeys': 'Zusätzliche Operations-Schlüssel (Feld als ausgeführten Code lesen)',\n 'card.extraOperationArgKeysHint': 'Ein Weg für Felder, deren Inhalt wirklich ausgeführt wird (workflowYaml u. ä.): ihr Text erreicht Blacklist und Credential-Prüfung, und bei Namensgleichheit gewinnt diese Liste. Preis: ein echtes Dokumentfeld hier einzutragen macht „der Plan erwähnt rm -rf\" wieder zum Ablehnungsgrund.',\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.llmEffort': 'Reasoning-Aufwand (nur Host-Modus)',\n 'card.llmEffortHost': 'Host-Standard folgen',\n 'card.llmEffortHint': 'Leer = nichts vorgeben, die Host-Modellkonfiguration entscheidet; auf low oder off wechseln, wenn der Host es ablehnt.',\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 'doubt.no-rule': 'keine Regel deckt diesen Aufruf ab, daher wird standardmäßig gefragt — das bedeutet nicht, dass er gefährlich ist',\n 'doubt.opaque': 'der Payload ist nicht lesbar (kodiert, Script außerhalb des Workspace, oder kein erkennbares Programm), keine Regel kann das Ziel bestimmen',\n 'doubt.irreversible': 'Regel besagt: irreversibel — nach der Ausführung nicht mehr rückgängig',\n 'doubt.never-learn': 'diese Antwort wird nicht gelernt; dieselbe Frage wird erneut gestellt',\n 'doubt.delete': 'es löscht Inhalte',\n 'doubt.remote-write': 'extern sichtbare Wirkung (push / publish / Schreib-Request); Rückgängig machen erfordert manuelle Schritte',\n 'doubt.exec-external': 'führt Code außerhalb des Workspaces aus, nicht überprüfbar durch diesen Aufruf',\n 'doubt.outside-paths': 'berührt Pfade außerhalb des Workspaces',\n 'doubt.model-flagged': 'das Risikomodell hat es markiert (nur Eskalation möglich, keine Freigabe)',\n 'doubt.write': 'schreibt oder ändert Dateien',\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.unattended': 'Modalità senza supervisione (tre implementazioni; ogni interruttore decide se il proprio livello esiste)',\n 'card.unattendedHint': 'Tre interruttori, ciascuno governa solo il livello scritto accanto: spegnere un\\'implementazione fa tornare quel livello al flusso umano ordinario, senza che diventi di nascosto un altro.',\n 'card.mode.ask': 'Mantieni umano',\n 'card.mode.pass': 'Passaggio meccanico',\n 'card.askHint': 'La selezione meccanica filtra ed elenca i dubbi, ma la richiesta resta a una persona e il modello revisore non viene chiamato nemmeno una volta — la forma adatta quando nessun LLM revisore è collegato o quando i token non valgono la spesa.',\n 'card.passHint': 'Esegue solo il giudice meccanico deterministico: un\\'operazione irreversibile, irrecuperabile o illeggibile viene bloccata e motivata al modello principale, il resto esegue. Nessuna chiamata al modello, nessuna richiesta umana: la forma esaminata di approval: never, e YOLO privato del modello.',\n 'card.tierScopeHint': 'Solo i preset dentro l\\'ambito del gate (%scope) arrivano a questo passo; fuori dall\\'ambito il gate si disattiva del tutto e nessun interruttore prende in carico le sue conferme.',\n 'card.yolo': 'YOLO — non chiedere mai un umano: blocca il pericoloso, esegui il resto',\n 'card.yoloHint': 'Blocca un carico irreversibile / non apprendibile / illeggibile, o un verdetto a rischio duro del modello, e restituisce il motivo al LLM principale come messaggio 工具审核意见; tutto il resto viene eseguito. Senza un modello disponibile, solo le reti deterministiche intercettano.',\n 'card.rulesFallback': 'Degradare a una porta a regole quando non c’è modello (classe cc-safety-net)',\n 'card.rulesFallbackHint': 'Agisce solo quando il revisore di rischio non è configurato o non ha dato un verdetto: le reti deterministiche bloccano ciò che sanno nominare e lasciano passare il resto, invece di parcheggiare la chiamata su un popup che nessuno risponderà. Finché un modello risponde, il comportamento resta invariato.',\n 'card.allowProtectedBranchPush': 'Consenti force-push su branch protetti (default off = pavimento attivo)',\n 'card.allowProtectedBranchPushHint': 'Di default il pavimento P0 blocca git push --force/--force-with-lease/--delete verso main/master/production/release/stable (non declassabile dal modello). Attivandolo il pavimento si fa da parte e le tre parole push piatte della blacklist vengono escluse; la chiamata ricade nella regola git.push-force predefinita, che chiede comunque una persona finché non revochi la voce o la aggiungi all\\'allowlist. Nient\\'altro si allarga: cancellazioni, redirect e il pavimento credenziali restano armati.',\n 'card.credFamily': 'Gradini delle famiglie di credenziali',\n 'card.credFamilyHint': 'Un gradino per famiglia: deny = lettura e scrittura bloccate; ask = lettura con conferma umana (predefinito); readonly = lettura libera, scrittura ancora bloccata dal pavimento P0; readwrite = la clausola di scrittura del credential store si ritira per questa famiglia (caso npm login). Gli altri pavimenti (root, percorsi protetti, .dsh, esfiltrazione) restano armati a ogni gradino. Lo stato vive nella riga del documento regole più la lista di esenzione; questa scheda scrive entrambe insieme.',\n 'card.credFamilyLoading': 'Caricamento gradini…',\n 'card.credFamilyFootnote': 'I livelli senza umano (passaggio meccanico / YOLO) lasciano passare il residuo degli ask — scegliere deny per bloccare. I credentialPaths personalizzati non partecipano mai all\\u0027esenzione di scrittura.',\n 'card.credReadwriteConfirm': 'readwrite consente di scrivere/modificare i file di credenziali di questa famiglia (sovrascrittura di ~/.npmrc). È l’unico gradino che ritira parte del P0. Confermare?',\n 'card.credConfirmYes': 'Conferma',\n 'card.credConfirmNo': 'Annulla',\n 'card.credRung.deny': 'blocca',\n 'card.credRung.ask': 'chiedi',\n 'card.credRung.readonly': 'sola lettura',\n 'card.credRung.readwrite': 'lettura scrittura',\n 'card.scriptReview': 'Allega il contenuto degli script alla revisione (attivo per impostazione predefinita)',\n 'card.scriptReviewHint': 'Quando una chiamata esegue uno script, il suo corpo viene letto e mostrato al modello di rischio come all’umano, e le reti deterministiche valutano anch’esse il corpo (un’eliminazione visibile solo dentro il file è esattamente ciò che passava). I corpi sono oscurati e limitati prima di lasciare l’host; disattivarli tiene il contenuto dei file in locale, al prezzo di rimandare gli script fuori dal workspace nel livello «illeggibile».',\n 'card.credentialPaths': 'Percorsi di credenziali personalizzati (la coda lunga)',\n 'card.credentialPathsHint': 'File segreti che l’elenco integrato non conosce. Le voci sono glob di percorso: un doppio asterisco attraversa le directory, un asterisco semplice e un punto di domanda restano dentro un segmento; senza jolly si confronta un frammento di percorso intero (token non colpisce ambient.txt); un ~/ iniziale si espande nella tua home; un modello relativo corrisponde anche a qualsiasi profondità (secrets/*.env copre a/b/secrets/prod.env). Una corrispondenza è trattata allo stesso livello di .ssh: la lettura fuori dal workspace e la modifica tramite strumento di file sono rifiutate in modo duro — questo livello non è appellabile né aggirabile dal revisore, dichiara solo percorsi che devi davvero proteggere.',\n 'card.credentialPathsPlaceholder': 'Nuovo percorso, es. ~/.myco/vault.token o secrets/*.env',\n 'card.denyKeywordsExtra': 'Parole chiave blacklist aggiunte (non sostituiscono il preset)',\n 'card.denyKeywordsExtraHint': 'Un blocco deterministico per termini tuoi — un sottocomando di revoca/cancellazione di una CLI aziendale, un prefisso di token che emetti. Questa lista aggiunge soltanto: qualunque cosa contenga la blacklist sopra (preset o tua sostituzione), queste parole vengono unite.',\n 'card.listRemove': 'Rimuovi questa voce',\n 'card.extraContentArgKeys': 'Chiavi documento aggiunte (mai lette come operazione)',\n 'card.extraContentArgKeysHint': 'Nomi di campi documentali fuori dall’elenco integrato (content/text/plan…): una volta dichiarati, il loro testo non entra più nella scansione piatta di parole pericolose e forme di credenziali. Solo in aggiunta: l’elenco integrato non è sostituibile, perché dimenticare una chiave riporterebbe in silenzio il bug per cui un piano viene rifiutato per aver descritto un’azione. Il comando effettivamente eseguito e il percorso modificato sono giudicati sui propri binari; questo elenco non può disattivarli.',\n 'card.extraContentArgKeysPlaceholder': 'Nuovo nome argomento, es. steps',\n 'card.extraOperationArgKeys': 'Chiavi operazione aggiunte (leggi il campo come codice eseguito)',\n 'card.extraOperationArgKeysHint': 'Un passaggio per i campi il cui corpo è davvero eseguito (workflowYaml e simili): il testo raggiunge blacklist e controllo credenziali, e in caso di omonimia questo elenco vince. Costo: indicare un campo documentale reale rende di nuovo «il piano menziona rm -rf» un motivo di rifiuto.',\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.llmEffort': 'Sforzo di ragionamento (solo modalità host)',\n 'card.llmEffortHost': 'Segui l’host',\n 'card.llmEffortHint': 'Vuoto = non imporre nulla, decide la configurazione del modello host; passa a low o off se l’host lo rifiuta.',\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 'doubt.no-rule': 'nessuna regola copre questa chiamata, la scelta predefinita è chiedere — non significa che sia pericolosa',\n 'doubt.opaque': 'il payload non è leggibile (codificato, script fuori dal workspace, o programma non riconosciuto), nessuna regola può individuare il bersaglio',\n 'doubt.irreversible': 'regola irreversibile: dopo l’esecuzione non si può annullare',\n 'doubt.never-learn': 'questa risposta non verrà imparata; la stessa domanda si ripresenterà',\n 'doubt.delete': 'elimina contenuto',\n 'doubt.remote-write': 'effetto visibile all’esterno (push / publish / richiesta di scrittura); annullare richiede intervento manuale',\n 'doubt.exec-external': 'esegue codice fuori dal workspace, non ispezionabile da questa chiamata',\n 'doubt.outside-paths': 'tocca percorsi fuori dal workspace',\n 'doubt.model-flagged': 'il modello di rischio lo ha segnalato (può solo elevare, non autorizzare)',\n 'doubt.write': 'scrive o modifica file',\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.unattended': 'Режимы без подтверждения человеком (три реализации; каждый переключатель решает, существует ли его уровень)',\n 'card.unattendedHint': 'Переключателя три, каждый управляет только тем уровнем, что написан рядом: выключить реализацию — значит вернуть этот уровень обычному человеческому потоку; тайно стать другим он не может.',\n 'card.mode.ask': 'Оставить человека',\n 'card.mode.pass': 'Механический пропуск',\n 'card.askHint': 'Механический отбор фильтрует и перечисляет сомнения, но запрос остаётся человеку, а модель-ревизор не вызывается ни разу — это форма для запусков без подключённого LLM-ревизора или когда токены не стоят затрат.',\n 'card.passHint': 'Работает только детерминированный механический судья: необратимое, невосстановимое или нечитаемое действие блокируется с причиной обратно основной модели, остальное выполняется. Ни вызова модели, ни вопроса человеку — проверенная форма approval: never и YOLO без модели.',\n 'card.tierScopeHint': 'До этого шага доходят только пресеты внутри области гейта (%scope); вне области гейт отключается целиком, и ни один переключатель не берёт его подтверждения на себя.',\n 'card.yolo': 'YOLO — никогда не спрашивать человека: блокировать опасное, остальное выполнять',\n 'card.yoloHint': 'Блокирует необратимую / необучаемую / неразбираемую нагрузку или жёсткий вердикт модели и возвращает причину основной LLM сообщением 工具审核意见; остальное выполняется. Когда доступной модели нет, срабатывают только детерминированные сети.',\n 'card.rulesFallback': 'Деградировать в шлюз по правилам, когда модели нет (класс cc-safety-net)',\n 'card.rulesFallbackHint': 'Действует только когда проверяющая модель не настроена или не дала вердикта: детерминированные сети блокируют то, что могут назвать, и пропускают остальное, вместо того чтобы вешать вызов на окно, которое никто не ответит. Пока модель отвечает, поведение не меняется.',\n 'card.allowProtectedBranchPush': 'Разрешить force-push в защищённые ветки (по умолчанию выкл = пол стоит)',\n 'card.allowProtectedBranchPushHint': 'По умолчанию пол P0 блокирует git push --force/--force-with-lease/--delete в main/master/production/release/stable (модель не может понизить). При включении пол отступает и три плоских push-ключа из чёрного списка освобождаются; вызов попадает в правило git.push-force, которое всё равно спрашивает человека, пока вы не отзовете запись или не добавите его в allowlist. Ничего другое не расширяется: удаления, редиректы и пол учётных данных остаются взведены.',\n 'card.credFamily': 'Ступени семей учётных данных',\n 'card.credFamilyHint': 'Одна ступень на семейство: deny = блокирует чтение и запись; ask = чтение с подтверждением человека (по умолчанию); readonly = чтение свободно, запись по-прежнему твёрдо блокируется полом P0; readwrite = клауза записи credential-store отступает для этого семейства (случай npm login). Остальные полы (корни, защищённые пути, .dsh, эксфильтрация) взведены на любой ступени. Состояние живёт в строке документа правил и в списке изъятий записи; карта пишет оба вместе.',\n 'card.credFamilyLoading': 'Загрузка ступеней…',\n 'card.credFamilyFootnote': 'Безчеловечные уровни (механический пропуск / YOLO) пропускают остаток ask — для жёсткой блокировки выберите deny. Свои credentialPaths никогда не участвуют в изъятии записи.',\n 'card.credReadwriteConfirm': 'readwrite разрешает запись/изменение файлов учётных данных этого семейства (перезапись ~/.npmrc). Единственная ступень, отступающая часть P0. Подтвердить?',\n 'card.credConfirmYes': 'Подтвердить',\n 'card.credConfirmNo': 'Отмена',\n 'card.credRung.deny': 'блок',\n 'card.credRung.ask': 'спрос',\n 'card.credRung.readonly': 'только чтение',\n 'card.credRung.readwrite': 'чтение запись',\n 'card.scriptReview': 'Прилагать содержимое скриптов к проверке (по умолчанию включено)',\n 'card.scriptReviewHint': 'Когда вызов запускает скрипт-файл, его тело читается и даётся модели риска и человеку, и детерминированные сети тоже оценивают тело (удаление, видимое только внутри файла, — ровно то, что пропускалось). Тела маскируются и ограничиваются по длине до отправки; отключение оставляет содержимое файлов локально, ценой возврата скриптов вне рабочей области в уровень «неразбираемо».',\n 'card.credentialPaths': 'Свои пути к учётным данным (длинный хвост)',\n 'card.credentialPathsHint': 'Секретные файлы, которых нет во встроенном списке. Записи — это глобы путей: двойная звёздочка переходит между каталогами, одиночная звёздочка и вопросительный знак остаются внутри одного сегмента; без маска-символов совпадение идёт по целому фрагменту пути (token не попадёт в ambient.txt); ведущий ~/ раскрывается в ваш home; относительный шаблон совпадает и на любой глубине (secrets/*.env покрывает a/b/secrets/prod.env). Совпадение держится по тому же стандарту, что и .ssh: чтение вне рабочей области и изменение файловым инструментом жёстко отклоняются — этот уровень нельзя оспорить и не обходят проверяющей моделью, поэтому объявляйте только те пути, которые действительно нужно защитить.',\n 'card.credentialPathsPlaceholder': 'Новый путь, напр. ~/.myco/vault.token или secrets/*.env',\n 'card.denyKeywordsExtra': 'Добавляемые ключевые слова чёрного списка (не заменяют пресет)',\n 'card.denyKeywordsExtraHint': 'Детерминированная блокировка для ваших собственных терминов — подкоманда отзыва/стирания внутреннего CLI, префикс выдаваемого вами токена. Этот список только добавляет: что бы ни содержал чёрный список выше (пресет или ваша замена), эти слова сливаются с ним.',\n 'card.listRemove': 'Удалить эту запись',\n 'card.extraContentArgKeys': 'Дополнительные ключи документов (не читаются как операция)',\n 'card.extraContentArgKeysHint': 'Имена полей вне встроенного списка (content/text/plan…): после добавления их текст не попадает в плоское чтение опасных слов и форм учётных данных. Только дополняет — встроенный список не заменяется, потому что пропуск одного из его ключей молча вернёт баг, когда план отклоняют за само описание работы. Реально выполняемая команда и изменяемый путь проверяются своими путями; этот список их не отключает.',\n 'card.extraContentArgKeysPlaceholder': 'Новое имя аргумента, напр. steps',\n 'card.extraOperationArgKeys': 'Дополнительные ключи операций (читать поле как исполняемый код)',\n 'card.extraOperationArgKeysHint': 'Канал для полей, чьё тело действительно исполняется (workflowYaml и т. п.): их текст попадает в чёрный список и проверку учётных данных, и при совпадении ключа выигрывает этот список. Цена: вписав сюда настоящий документ, вы снова делаете «в плане упоминается rm -rf» причиной отказа.',\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.llmEffort': 'Усилие рассуждения (только режим host)',\n 'card.llmEffortHost': 'Как у хоста',\n 'card.llmEffortHint': 'Пусто = не навязывать, решает конфигурация модели хоста; выберите low или off, если хост отклоняет.',\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 'doubt.no-rule': 'ни одно правило не покрывает этот вызов, по умолчанию спрашивается человек — это не значит что он опасен',\n 'doubt.opaque': 'нагрузка не читается (закодирована, скрипт за пределами рабочей зоны, или не распознаётся программа), правило не может определить цель',\n 'doubt.irreversible': 'правило: необратимо, отменить после выполнения нельзя',\n 'doubt.never-learn': 'это решение не запомнится, тот же вызов спросит снова',\n 'doubt.delete': 'удаляет данные',\n 'doubt.remote-write': 'видимый снаружи эффект (push / publish / запись); отмена требует ручных действий',\n 'doubt.exec-external': 'выполняет код за пределами рабочего пространства, не подлежит инспекции',\n 'doubt.outside-paths': 'затрагивает пути вне рабочего пространства',\n 'doubt.model-flagged': 'модель риска пометила (только усиливает, не снижает)',\n 'doubt.write': 'записывает или изменяет файлы',\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.unattended': 'Modos sin supervisión (tres implementaciones; cada interruptor decide si su nivel existe)',\n 'card.unattendedHint': 'Tres interruptores, cada uno gobierna solo el nivel escrito a su lado: apagar una implementación devuelve ese nivel al flujo humano ordinario, sin convertirse a escondidas en otro.',\n 'card.mode.ask': 'Mantener humano',\n 'card.mode.pass': 'Paso mecánico',\n 'card.askHint': 'El tamiz mecánico filtra y enumera sus dudas, pero la solicitud sigue quedando con una persona y no se llama al modelo revisor ni una vez — la forma para ejecuciones sin LLM revisor conectado, o cuando los tokens no valen la pena.',\n 'card.passHint': 'Ejecuta solo el juez mecánico determinista: una operación irreversible, irrecuperable o ilegible se bloquea y se devuelve justificada al modelo principal; lo demás corre. Ninguna llamada al modelo, ninguna pregunta humana: la forma revisada de approval: never, y un YOLO sin modelo.',\n 'card.tierScopeHint': 'Solo los presets dentro del alcance del gate (%scope) llegan a este paso; fuera de él el gate se aparta por completo y ningún interruptor toma sus confirmaciones.',\n 'card.yolo': 'YOLO — nunca pedir un humano: bloquear lo peligroso, ejecutar el resto',\n 'card.yoloHint': 'Bloquea una carga irreversible / no aprendible / ilegible, o un veredicto de riesgo duro del modelo, y devuelve la razón al LLM principal como mensaje 工具审核意见; todo lo demás se ejecuta. Sin un modelo disponible, solo las redes deterministas interceptan.',\n 'card.rulesFallback': 'Degradar a una compuerta de reglas cuando no hay modelo (clase cc-safety-net)',\n 'card.rulesFallbackHint': 'Solo actúa cuando el revisor de riesgo no está configurado o no dio veredicto: las redes deterministas bloquean lo que saben nombrar y dejan pasar el resto, en lugar de dejar la llamada colgada en un emergente que nadie responderá. Mientras un modelo responde, el comportamiento no cambia.',\n 'card.allowProtectedBranchPush': 'Permitir force-push a ramas protegidas (por defecto off = suelo activo)',\n 'card.allowProtectedBranchPushHint': 'Por defecto el suelo P0 bloquea git push --force/--force-with-lease/--delete hacia main/master/production/release/stable (no degradable por el modelo). Al activarlo el suelo se aparta y se eximen las tres palabras push planas de la lista negra; la llamada cae en la regla git.push-force integrada, que aún pregunta a una persona salvo que revoques esa entrada o la añada a la allowlist. Nada más se amplía: borrados, redirecciones y el suelo de credenciales siguen armados.',\n 'card.credFamily': 'Escalón por familia de credenciales',\n 'card.credFamilyHint': 'Un escalón por familia: deny = lectura y escritura bloqueadas; ask = lectura con validación humana (predeterminado); readonly = lectura libre, la escritura sigue bloqueada por el suelo P0; readwrite = la cláusula de escritura del credential store se aparta para esta familia (caso npm login). Los demás suelos (raíces, rutas protegidas, .dsh, exfiltración) siguen armados en cualquier escalón. El estado vive en la fila del documento de reglas más la lista de exención; esta tarjeta escribe ambas juntas.',\n 'card.credFamilyLoading': 'Cargando escalones…',\n 'card.credFamilyFootnote': 'Los niveles sin humano (paso mecánico / YOLO) dejan pasar el residuo de los ask — elige deny para bloquear duro. Los credentialPaths personalizados nunca participan en la exención de escritura.',\n 'card.credReadwriteConfirm': 'readwrite permite escribir/modificar los archivos de credenciales de esta familia (reescribir ~/.npmrc). Es el único escalón que aparta parte del P0. ¿Confirmar?',\n 'card.credConfirmYes': 'Confirmar',\n 'card.credConfirmNo': 'Cancelar',\n 'card.credRung.deny': 'bloquear',\n 'card.credRung.ask': 'preguntar',\n 'card.credRung.readonly': 'solo lectura',\n 'card.credRung.readwrite': 'lectura escritura',\n 'card.scriptReview': 'Adjuntar el contenido de los scripts a la revisión (activado por defecto)',\n 'card.scriptReviewHint': 'Cuando una llamada ejecuta un archivo script, su cuerpo se lee y se da al modelo de riesgo y al humano por igual, y las redes deterministas también evalúan el cuerpo (un borrado que solo se ve dentro del archivo es justo lo que se escapaba). Los cuerpos se redactan y limitan antes de salir del host; desactivarlo mantiene el contenido de archivos local, al costo de devolver los scripts fuera del espacio de trabajo al nivel «ilegible».',\n 'card.credentialPaths': 'Rutas de credenciales personalizadas (la cola larga)',\n 'card.credentialPathsHint': 'Archivos secretos que la lista integrada no conoce. Las entradas son globos de ruta: un doble asterisco cruza directorios, un asterisco simple y un signo de interrogación se quedan dentro de un segmento; sin comodines se compara un fragmento de ruta completo (token no toca ambient.txt); un ~/ inicial se expande a tu home; un patrón relativo también coincide a cualquier profundidad (secrets/*.env cubre a/b/secrets/prod.env). Una coincidencia se trata al mismo estándar que .ssh: leerla fuera del espacio de trabajo y mutarla con una herramienta de archivo se deniegan de forma dura — ese nivel no se puede apelar ni sortear por el revisor, así que declara solo las rutas que de verdad necesitas proteger.',\n 'card.credentialPathsPlaceholder': 'Nueva ruta, p. ej. ~/.myco/vault.token o secrets/*.env',\n 'card.denyKeywordsExtra': 'Palabras clave añadidas a la blacklist (no reemplaza el preajuste)',\n 'card.denyKeywordsExtraHint': 'Un bloqueo determinista sobre términos propios — una subcomando de revocación/borrado de una CLI interna, un prefijo de token que emites. Esta lista solo añade: lo que contenga la blacklist de arriba (preajuste o tu propio reemplazo), estas palabras se fusionan.',\n 'card.listRemove': 'Quitar esta entrada',\n 'card.extraContentArgKeys': 'Claves de documento añadidas (nunca leídas como operación)',\n 'card.extraContentArgKeysHint': 'Nombres de campos documentales fuera de la lista integrada (content/text/plan…): una vez declarados, su texto deja de entrar en la lectura plana de palabras peligrosas y formas de credenciales. Solo se añade: la lista integrada no se reemplaza, porque olvidar una de sus claves traería de vuelta en silencio el fallo por el que un plan se rechaza por describir una acción. El comando realmente ejecutado y la ruta modificada se juzgan por sus propios caminos; esta lista no puede apagarlos.',\n 'card.extraContentArgKeysPlaceholder': 'Nuevo nombre de argumento, p. ej. steps',\n 'card.extraOperationArgKeys': 'Claves de operación añadidas (leer el campo como código que se ejecuta)',\n 'card.extraOperationArgKeysHint': 'Una vía para campos cuyo cuerpo sí se ejecuta (workflowYaml etc.): su texto entra en la blacklist y en el filtro de credenciales, y esta lista gana si ambas nombran la misma clave. Costo: declarar aquí un campo documental real vuelve a hacer que «el plan menciona rm -rf» sea motivo de rechazo.',\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.llmEffort': 'Esfuerzo de razonamiento (solo modo host)',\n 'card.llmEffortHost': 'Seguir el host',\n 'card.llmEffortHint': 'Vacío = no imponer nada, decide la configuración del modelo del host; cambia a low u off si el host lo rechaza.',\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 'doubt.no-rule': 'ninguna regla cubre esta llamada, el valor por defecto es preguntar — eso no significa que sea peligrosa',\n 'doubt.opaque': 'el payload no puede leerse (codificado, script fuera del workspace o programa no reconocido), ninguna regla puede localizar su objetivo',\n 'doubt.irreversible': 'regla irreversible: tras la ejecución no se puede deshacer',\n 'doubt.never-learn': 'esta respuesta no se aprenderá; la misma llamada volverá a preguntar',\n 'doubt.delete': 'elimina contenido',\n 'doubt.remote-write': 'efecto visible externamente (push / publish / solicitud de escritura); deshacer requiere pasos manuales',\n 'doubt.exec-external': 'ejecuta código fuera del workspace, no inspeccionable por esta llamada',\n 'doubt.outside-paths': 'usa rutas fuera del workspace',\n 'doubt.model-flagged': 'el modelo de riesgo lo marcó (solo puede escalar, nunca aprobar)',\n 'doubt.write': 'escribe o modifica archivos',\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","/**\r\n * The optimistic state machine behind the settings card's pill switch and its tier\r\n * picker, kept out of the components so its three rules are testable without a DOM\r\n * renderer (the client half ships no react-dom).\r\n *\r\n * The posture: the control flips the instant it is clicked and holds that\r\n * position while the write round-trips through the host settings service — a\r\n * checkbox that waits for the snapshot reads as a dead control. The store stays\r\n * the truth, so the local override is dropped the moment the snapshot agrees\r\n * with it, on a rejected write, and on a watchdog in case a host line neither\r\n * applies nor reports the change.\r\n */\r\n\r\n/** How long an unconfirmed click is allowed to hold the control before it snaps back. */\r\nexport const SWITCH_SETTLE_MS = 4_000\r\n\r\n/**\r\n * What the control displays: the pending click wins over the store until the store\r\n * catches up (or the watchdog gives up on it). Generic because the same posture covers a\r\n * two-state pill and a multi-state tier picker alike.\r\n */\r\nexport function shownValue<T>(pending: T | null, checked: T): T {\r\n return pending ?? checked\r\n}\r\n\r\n/**\r\n * Store update: once the snapshot reports the requested value the override is redundant,\r\n * and handing the visual back to the snapshot is what keeps the control honest if another\r\n * writer (a patch file, the app's own plugin manager) moved the same field meanwhile.\r\n */\r\nexport function pendingAfterSync<T>(pending: T | null, checked: T): T | null {\r\n return pending !== null && pending === checked ? null : pending\r\n}\r\n\r\n/** A write that came back rejected: fall back to whatever the store holds. */\r\nexport function pendingAfterFailure<T>(_pending: T | null): null {\r\n return null\r\n}\r\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. The plugin ships five 自动审查 tiers of its own\n * (declared in its `cordis.patch.yml`, which is how they reach the composer picker at all):\n * the plain one (file sandbox kept), the full-access one (sandbox lifted, same approval\n * behaviour), and the three human-free / model-free implementations — mechanical takeover of\n * asks (`permissive-mech`), mechanical screen that still asks (`permissive-snet`), and the\n * model-backed YOLO. Each has exactly one preset and one switch, so they never cross: a\n * switch changes the behaviour of its own tier and of nothing else. `'*'` makes the gate\n * global (every 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[] = [\n 'permissive',\n 'permissive-full',\n 'permissive-mech',\n 'permissive-snet',\n 'permissive-yolo',\n]\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 { pendingAfterFailure, pendingAfterSync, shownValue, SWITCH_SETTLE_MS } from './switch-state.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 /** Permissive tier: the human handles what the grader flags. */\n /** YOLO tier (`permissive-yolo`): the grader answers in the person's place, never asks. */\n yolo?: boolean\n /** Safenet-pass tier (`permissive-mech`): the mechanical screen takes over asks. */\n safenetPass?: boolean\n /** Safenet-ask tier (`permissive-snet`): mechanical screen, still asks, no grader. */\n safenetAsk?: boolean\n /** Protected-branch push floor opt-out. Default false keeps the P0 floor. */\n allowProtectedBranchPush?: boolean\n /** Unattended tiers: never a human popup (see src/config.ts for the semantics). */\n rulesFallback?: boolean\n /** On unless explicitly unset to false — the default attaches script bodies. */\n scriptReview?: 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 /** Reasoning effort for the host receiver; empty follows the host model config. */\n classifierEffort?: 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 /** Keywords appended to whichever blacklist is live (never replaces it). */\n denyKeywordsExtra?: string[]\n /** User-declared credential paths, held to the same standard as `.ssh`. */\n credentialPaths?: string[]\n /** Extra argument keys treated as document bodies (never replaces the built-in list). */\n extraContentArgKeys?: string[]\n /** Extra argument keys treated as operations; wins over the prose list on the same key. */\n extraOperationArgKeys?: 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/** Focus ring for the pill switch. `:focus-visible` cannot be expressed inline, so\n * the one pseudo-class the card needs rides on a single injected rule. */\nconst switchCss = '.pg-switch:focus-visible{outline:var(--dsw-focus-ring-width,2px) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary,#3b82f6));outline-offset:2px}.pg-seg:focus-visible{outline:var(--dsw-focus-ring-width,2px) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary,#3b82f6));outline-offset:1px}'\n\n/**\n * Optimistic control state, shared by the pill switch and the tier picker: show the\n * requested value the instant it is clicked and hold it while the write round-trips\n * through the host settings service, then hand the visual back to the store — on the\n * snapshot catching up, on a rejected write, and on a watchdog for a host line that\n * neither applies nor reports the change. A control may be fast, but it may not lie.\n */\nfunction useOptimistic<T>(stored: T): readonly [T, (next: T, write: () => unknown) => void] {\n const [pending, setPending] = useState<T | null>(null)\n useEffect(() => { setPending((current) => pendingAfterSync(current, stored)) }, [stored])\n useEffect(() => {\n if (pending === null) return undefined\n const timer = setTimeout(() => { setPending(pendingAfterFailure(pending)) }, SWITCH_SETTLE_MS)\n return () => { clearTimeout(timer) }\n }, [pending])\n const commit = (next: T, write: () => unknown): void => {\n setPending(next)\n void Promise.resolve(write()).catch(() => { setPending(null) })\n }\n return [shownValue(pending, stored), commit] as const\n}\n\n/**\n * One row of the unattended block: a switch, and the preset it owns.\n *\n * The preset id is rendered next to the label because the mapping is the whole design —\n * one switch, one implementation, one tier — and a person who sees 「机械直通」 in the\n * composer needs to know which row governs it. The id is a machine key, so it stays\n * untranslated on purpose.\n */\nfunction TierRow(props: {\n readonly id: string\n readonly label: string\n readonly preset: string\n readonly checked: boolean\n readonly disabled: boolean\n readonly hint: string\n readonly onCommit: (next: boolean) => unknown\n}): JSX.Element {\n const { id, label, preset, checked, disabled, hint, onCommit } = props\n return (\n <>\n <div style={rowStyle}>\n <label htmlFor={id} style={{ fontSize: '12px' }}>\n {label}\n <span style={{ color: 'var(--dsw-alias-label-tertiary)', fontSize: '11px' }}> · {preset}</span>\n </label>\n <PillSwitch\n id={id}\n checked={checked}\n disabled={disabled}\n onCommit={onCommit}\n />\n </div>\n <p style={hintStyle}>{hint}</p>\n </>\n )\n}\n\n/**\n * Pill switch — the card's boolean control, cut to the shape of the host's own\n * `ui-primitives` Switch: 36×20 capsule, 16px thumb, and the on/off appearance\n * keyed off `aria-checked` so assistive tech can never read a state the eye does\n * not see.\n *\n * Optimistic by design: the capsule flips on click and holds that position while\n * `scope.set` round-trips through the host settings service. A checkbox that\n * waits for the snapshot to come back reads as a dead control on a slow write.\n * The snapshot stays the truth — the state machine lives in `switch-state.ts`\n * (and under test there) so the pill can never sit in a state the profile does\n * not have.\n *\n * Every colour is a theme token with a fallback: `--dsw-alias-brand-primary`\n * only exists on newer host lines, and an \"on\" state that resolves to nothing is\n * an invisible control in dark mode.\n */\nfunction PillSwitch(props: {\n readonly id: string\n readonly checked: boolean\n /** Accessible name for rows whose text is not a `<label>` (the host Switch demands one). */\n readonly label?: string | undefined\n readonly disabled?: boolean | undefined\n readonly title?: string | undefined\n readonly onCommit: (next: boolean) => unknown\n}): JSX.Element {\n const { id, checked, label, disabled = false, title, onCommit } = props\n const [shown, commit] = useOptimistic<boolean>(checked)\n return (\n <button\n id={id}\n type=\"button\"\n role=\"switch\"\n aria-checked={shown}\n aria-label={label}\n title={title}\n disabled={disabled}\n className=\"pg-switch\"\n style={{\n boxSizing: 'border-box',\n position: 'relative',\n flex: '0 0 auto',\n width: '36px',\n height: '20px',\n padding: '2px',\n border: '0',\n borderRadius: '999px',\n background: shown\n ? 'var(--dsw-alias-brand-primary, var(--dsw-alias-state-business-primary, #3b82f6))'\n : 'var(--dsw-alias-border-l3, var(--dsw-alias-border-l2, rgba(128,128,128,0.35)))',\n cursor: disabled ? 'default' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n transition: 'background 120ms ease',\n }}\n onClick={() => {\n const next = !shown\n commit(next, () => onCommit(next))\n }}\n >\n <span\n aria-hidden\n style={{\n display: 'block',\n width: '16px',\n height: '16px',\n borderRadius: '50%',\n background: 'var(--dsw-alias-label-primary-foreground, #fff)',\n transform: shown ? 'translateX(16px)' : 'translateX(0)',\n transition: 'transform 120ms ease',\n }}\n />\n </button>\n )\n}\n\n/**\n * A minimal add/remove editor for one string-array setting.\n *\n * Deliberately generic and small: the long-tail protection lists (`credentialPaths`,\n * `denyKeywordsExtra`) are the same shape — lines a person types to protect something\n * the preset cannot know — and they should not each grow their own copy of the row\n * markup the deny blacklist already has.\n */\n/**\n * cred family ladder — server-backed rows (`GET/POST /api/dsh-perm-gate/cred`).\n * The rung state lives in TWO stores the plugin owns — the family's row inside the\n * rules document (section + enabled) and the paired `credWriteExemptFamilies` list —\n * so the card must not keep a local mirror; it reads and writes through the route,\n * which applies both stores in one settings update. `readwrite` asks for an inline\n * confirmation: it is the only rung that steps a piece of P0 aside.\n */\nconst CRED_FAMILIES_UI: readonly (readonly [string, string])[] = [\n ['ssh', 'SSH (~/.ssh)'],\n ['cloud', 'Cloud (.aws/.gcloud/.azure)'],\n ['package', 'Registry (.npmrc/.pypirc/.netrc)'],\n ['gitcreds', 'Git store (.git-credentials)'],\n ['env', 'Project (.env)'],\n ['cli', 'Coding CLI (~/.claude/.codex/gh)'],\n ['db', 'Database (.pgpass/.my.cnf)'],\n]\nconst CRED_RUNGS_UI: readonly string[] = ['deny', 'ask', 'readonly', 'readwrite']\n// Literal key map: the locale dictionary is a literal union — a computed\n// `card.credRung.${rung}` template widens to string and fails the seat typing.\nconst CRED_RUNG_LABEL_KEY = {\n deny: 'card.credRung.deny',\n ask: 'card.credRung.ask',\n readonly: 'card.credRung.readonly',\n readwrite: 'card.credRung.readwrite',\n} as const\n\nfunction CredLadderSection(props: { t: PermissiveCardProps['t']; readonly: boolean }) {\n const { t, readonly } = props\n const [rungs, setRungs] = useState<Record<string, string> | null>(null)\n const [confirm, setConfirm] = useState<string | null>(null)\n const [busy, setBusy] = useState<string | null>(null)\n // Row-scoped error: a failure at the bottom of the section is invisible to the\n // person who just clicked a row — the feedback must sit on the row that failed.\n const [rowError, setRowError] = useState<{ family: string; msg: string } | null>(null)\n useEffect(() => {\n let alive = true\n fetch('/api/dsh-perm-gate/cred', { headers: { 'cache-control': 'no-cache' } })\n .then((r) => r.json())\n .then((b: { rungs?: Record<string, string> }) => { if (alive && b?.rungs !== undefined) setRungs(b.rungs) })\n .catch(() => { /* route unavailable: the section keeps showing the loading line */ })\n return () => { alive = false }\n }, [])\n const apply = (family: string, rung: string): void => {\n setBusy(family)\n setRowError(null)\n // A hanging POST used to leave the row in silent `busy` forever (desktop webServer\n // body-stream mismatch) — 10s ceiling turns it into a visible, named failure.\n const abort = new AbortController()\n const timer = setTimeout(() => { abort.abort() }, 10_000)\n fetch('/api/dsh-perm-gate/cred', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ family, rung }),\n signal: abort.signal,\n })\n .then((r) => r.json())\n .then((b: { ok?: boolean; rungs?: Record<string, string>; error?: string }) => {\n if (b?.ok === true && b.rungs !== undefined) setRungs(b.rungs)\n else setRowError({ family, msg: String(b?.error ?? 'failed') })\n })\n .catch((e: unknown) => {\n const msg = String((e as Error)?.name ?? e) === 'AbortError' ? 'timeout (10s)' : String(e)\n setRowError({ family, msg })\n })\n .finally(() => { clearTimeout(timer); setBusy(null); setConfirm(null) })\n }\n return (\n <section style={sectionStyle}>\n <p style={labelStyle}>{t('card.credFamily')}</p>\n <p style={hintStyle}>{t('card.credFamilyHint')}</p>\n {rungs === null ? (\n <p style={hintStyle}>{t('card.credFamilyLoading')}</p>\n ) : (\n CRED_FAMILIES_UI.map(([family, display]) => (\n <div key={family} style={{ ...rowStyle, flexWrap: 'wrap' }}>\n <span style={{ fontSize: '12px', color: 'var(--dsw-alias-label-primary)' }}>{display}</span>\n <span style={{ display: 'inline-flex', gap: '4px' }}>\n {CRED_RUNGS_UI.map((rung) => (\n <button\n key={rung}\n type=\"button\"\n disabled={readonly || busy === family}\n style={{\n fontSize: '11px',\n padding: '2px 8px',\n cursor: 'pointer',\n borderRadius: '10px',\n border: rungs[family] === rung ? '1px solid var(--dsw-alias-primary, #4a90d9)' : '1px solid transparent',\n background: rungs[family] === rung ? 'rgba(74, 144, 217, 0.15)' : 'transparent',\n }}\n onClick={() => {\n if (rung === 'readwrite' && confirm !== family) { setConfirm(family); return }\n setConfirm(null)\n apply(family, rung)\n }}\n >\n {t(CRED_RUNG_LABEL_KEY[rung as keyof typeof CRED_RUNG_LABEL_KEY])}\n </button>\n ))}\n </span>\n {confirm === family && (\n <span style={{ width: '100%', fontSize: '12px', color: 'var(--dsw-alias-label-secondary)' }}>\n {t('card.credReadwriteConfirm')}\n <button type=\"button\" disabled={busy === family} style={{ fontSize: '11px', marginLeft: '6px' }} onClick={() => apply(family, 'readwrite')}>{t('card.credConfirmYes')}</button>\n <button type=\"button\" style={{ fontSize: '11px', marginLeft: '4px' }} onClick={() => setConfirm(null)}>{t('card.credConfirmNo')}</button>\n </span>\n )}\n {rowError !== null && rowError.family === family && (\n <span style={{ width: '100%', fontSize: '11px', color: 'var(--dsw-alias-danger, #c0392b)' }}>{family}: {rowError.msg}</span>\n )}\n </div>\n ))\n )}\n <p style={hintStyle}>{t('card.credFamilyFootnote')}</p>\n </section>\n )\n}\n\nfunction StringListField(props: {\n readonly label: string\n readonly hint: string\n readonly placeholder: string\n readonly addLabel: string\n readonly removeLabel: string\n readonly items: readonly string[]\n readonly locked: boolean\n readonly onAdd: (value: string) => void\n readonly onRemove: (index: number) => void\n}): JSX.Element {\n const [draft, setDraft] = useState('')\n const add = (): void => {\n const next = draft.trim()\n if (next === '') return\n props.onAdd(next)\n setDraft('')\n }\n return (\n <>\n <p style={labelStyle}>{props.label}</p>\n <p style={hintStyle}>{props.hint}</p>\n <div style={{ display: 'flex', flexDirection: 'column', gap: '4px', margin: '6px 0' }}>\n {props.items.map((item, index) => (\n <div\n key={`${index}:${item}`}\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 {item}\n </code>\n <button\n type=\"button\"\n aria-label={props.removeLabel}\n title={props.removeLabel}\n disabled={props.locked}\n onClick={() => { props.onRemove(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: props.locked ? 'default' : 'pointer',\n }}\n >\n ✕\n </button>\n </div>\n ))}\n </div>\n <div style={{ display: 'flex', gap: '6px', marginTop: '6px' }}>\n <input\n type=\"text\"\n value={draft}\n disabled={props.locked}\n placeholder={props.placeholder}\n spellCheck={false}\n style={{ ...controlStyle, flex: '1 1 auto', minWidth: 0 }}\n onChange={(event) => { setDraft(event.currentTarget.value) }}\n onKeyDown={(event) => { if (event.key === 'Enter') add() }}\n />\n <button\n type=\"button\"\n disabled={props.locked || draft.trim() === ''}\n onClick={add}\n style={{ ...controlStyle, flex: '0 0 auto', cursor: props.locked || draft.trim() === '' ? 'default' : 'pointer', opacity: props.locked || draft.trim() === '' ? 0.5 : 1 }}\n >\n {props.addLabel}\n </button>\n </div>\n </>\n )\n}\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 // 诊断守卫(2026-10-07):scope 未解析时不能在 render 里炸——宿主设置壳对\n // 内容槽异常静默吞(面板空白无报错),无法与「根本没渲染」区分。守卫后\n // 面板显式出占位文案,把「渲染了但 scope 没到」与「没渲染」分开。\n // 注意:守卫分支跳过了下方 hooks,scope 到位后该实例 hook 数会变——\n // 仅作诊断用途,定位后移除或改为 hook 稳定形态。\n if (!scope) {\n return <div style={{ padding: 16, color: 'var(--dsw-alias-label-tertiary, #888)' }}>\n {t('card.unavailable')}(scope 未解析 — 诊断占位)\n </div>\n }\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 raw = (snapshot.value ?? {}) as Record<string, unknown>\n // 形状防御(T13b 桥轨实测):宿主各线的 settings 值可能残留非数组形态的\n // 列表字段(0.1.5 installSection base=resolved config,deployment patch 里\n // 的历史 allowlist:{} 透传到 value),卡片只认 string[]——非数组一律按空\n // 处理,用户在卡里保存一次即写回正确形态。\n const listOf = (v: unknown): string[] => (Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string') : [])\n const value = {\n ...raw,\n allowlist: listOf(raw.allowlist),\n denyKeywords: listOf(raw.denyKeywords),\n denyKeywordsExtra: listOf(raw.denyKeywordsExtra),\n credentialPaths: listOf(raw.credentialPaths),\n extraContentArgKeys: listOf(raw.extraContentArgKeys),\n extraOperationArgKeys: listOf(raw.extraOperationArgKeys),\n } as unknown 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 // The presets the gate acts in at all — outside them the whole gate stands down.\n const gateScope = (value.gatePresets ?? []).length > 0 ? (value.gatePresets as string[]) : [...DEFAULT_GATE_PRESETS]\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 <style>{switchCss}</style>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-permissive\" style={labelStyle}>{t('card.permissive')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-permissive\"\n checked={effective}\n disabled={readonly}\n onCommit={(next) => scope.set('permissive', next)}\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('%scope', gateScope.join(' / '))}\n </p>\n\n {/* Each unattended implementation owns one preset and one switch, so the\n rows below cannot cross: a switch changes the behaviour of the tier\n named beside it and of no other. Script review is independent of all\n of them and on by default. */}\n <section style={sectionStyle}>\n <p style={labelStyle}>{t('card.unattended')}</p>\n <p style={hintStyle}>{t('card.unattendedHint')}</p>\n <TierRow\n id=\"plugin-config-perm-gate-yolo\"\n label={t('card.yolo')}\n preset=\"permissive-yolo\"\n checked={value.yolo === true}\n disabled={readonly}\n hint={t('card.yoloHint')}\n onCommit={(next) => scope.set('yolo', next)}\n />\n <TierRow\n id=\"plugin-config-perm-gate-safenet-pass\"\n label={t('card.mode.pass')}\n preset=\"permissive-mech\"\n checked={value.safenetPass !== false}\n disabled={readonly}\n hint={t('card.passHint')}\n onCommit={(next) => scope.set('safenetPass', next)}\n />\n <TierRow\n id=\"plugin-config-perm-gate-safenet-ask\"\n label={t('card.mode.ask')}\n preset=\"permissive-snet\"\n checked={value.safenetAsk === true}\n disabled={readonly}\n hint={t('card.askHint')}\n onCommit={(next) => scope.set('safenetAsk', next)}\n />\n <p style={hintStyle}>{t('card.tierScopeHint').replace('%scope', gateScope.join(' / '))}</p>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-rules-fallback\" style={{ fontSize: '12px' }}>{t('card.rulesFallback')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-rules-fallback\"\n checked={value.rulesFallback === true}\n disabled={readonly}\n onCommit={(next) => scope.set('rulesFallback', next)}\n />\n </div>\n <p style={hintStyle}>{t('card.rulesFallbackHint')}</p>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-allow-protected-push\" style={{ fontSize: '12px' }}>{t('card.allowProtectedBranchPush')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-allow-protected-push\"\n checked={value.allowProtectedBranchPush === true}\n disabled={readonly}\n onCommit={(next) => scope.set('allowProtectedBranchPush', next)}\n />\n </div>\n <p style={hintStyle}>{t('card.allowProtectedBranchPushHint')}</p>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-script-review\" style={{ fontSize: '12px' }}>{t('card.scriptReview')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-script-review\"\n checked={value.scriptReview !== false}\n disabled={readonly}\n onCommit={(next) => scope.set('scriptReview', next)}\n />\n </div>\n <p style={hintStyle}>{t('card.scriptReviewHint')}</p>\n </section>\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 <PillSwitch\n id=\"plugin-config-perm-gate-trust\"\n checked={strategies.trustAutoAllow ?? true}\n disabled={readonly || !effective}\n onCommit={(next) => scope.set('permissiveStrategies', { ...strategies, trustAutoAllow: next })}\n />\n </div>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-confirm\" style={{ fontSize: '12px' }}>{t('card.strategy.alwaysConfirm')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-confirm\"\n checked={strategies.alwaysConfirm ?? false}\n disabled={readonly || !effective}\n onCommit={(next) => scope.set('permissiveStrategies', { ...strategies, alwaysConfirm: next })}\n />\n </div>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-llm\" style={{ fontSize: '12px' }}>{t('card.strategy.llmAssist')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-llm\"\n checked={strategies.llmAssist ?? false}\n disabled={readonly || !effective}\n onCommit={(next) => scope.set('permissiveStrategies', { ...strategies, llmAssist: next })}\n />\n </div>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-escalation\" style={{ fontSize: '12px' }}>{t('card.strategy.trustEscalation')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-escalation\"\n checked={strategies.trustEscalation ?? true}\n disabled={readonly || !effective}\n onCommit={(next) => scope.set('permissiveStrategies', { ...strategies, trustEscalation: next })}\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.llmEffort')}</span>\n <select\n value={value.classifierEffort ?? ''}\n disabled={readonly || receiverSource !== 'host'}\n style={controlStyle}\n title={t('card.llmEffortHint')}\n onChange={(event) => { void scope.set('classifierEffort', event.currentTarget.value) }}\n >\n <option value=\"\">{t('card.llmEffortHost')}</option>\n <option value=\"off\">off</option>\n <option value=\"low\">low</option>\n <option value=\"medium\">medium</option>\n <option value=\"high\">high</option>\n </select>\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 <PillSwitch\n id=\"plugin-config-perm-gate-risk-learning\"\n checked={value.riskLearning ?? false}\n disabled={readonly || !effective}\n onCommit={(next) => scope.set('riskLearning', next)}\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 <PillSwitch\n id=\"plugin-config-perm-gate-risk-sediment\"\n checked={value.riskSediment ?? true}\n disabled={readonly || !effective}\n onCommit={(next) => scope.set('riskSediment', next)}\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 {/* Long-tail protection the preset cannot know about: the user's own\n secret paths and their own blacklist words. Kept out of the deny\n blacklist section because the semantics differ — that list replaces\n the preset, these two never do. */}\n <section style={sectionStyle}>\n <StringListField\n label={t('card.credentialPaths')}\n hint={t('card.credentialPathsHint')}\n placeholder={t('card.credentialPathsPlaceholder')}\n addLabel={t('card.denylistAdd')}\n removeLabel={t('card.listRemove')}\n items={value.credentialPaths ?? []}\n locked={readonly}\n onAdd={(entry) => { void scope.set('credentialPaths', [...(value.credentialPaths ?? []), entry]) }}\n onRemove={(index) => { void scope.set('credentialPaths', (value.credentialPaths ?? []).filter((_, i) => i !== index)) }}\n />\n <div style={{ height: '10px' }} />\n <StringListField\n label={t('card.denyKeywordsExtra')}\n hint={t('card.denyKeywordsExtraHint')}\n placeholder={t('card.denylistPlaceholder')}\n addLabel={t('card.denylistAdd')}\n removeLabel={t('card.listRemove')}\n items={value.denyKeywordsExtra ?? []}\n locked={readonly}\n onAdd={(entry) => { void scope.set('denyKeywordsExtra', [...(value.denyKeywordsExtra ?? []), entry]) }}\n onRemove={(index) => { void scope.set('denyKeywordsExtra', (value.denyKeywordsExtra ?? []).filter((_, i) => i !== index)) }}\n />\n <div style={{ height: '10px' }} />\n <StringListField\n label={t('card.extraContentArgKeys')}\n hint={t('card.extraContentArgKeysHint')}\n placeholder={t('card.extraContentArgKeysPlaceholder')}\n addLabel={t('card.denylistAdd')}\n removeLabel={t('card.listRemove')}\n items={value.extraContentArgKeys ?? []}\n locked={readonly}\n onAdd={(entry) => { void scope.set('extraContentArgKeys', [...(value.extraContentArgKeys ?? []), entry]) }}\n onRemove={(index) => { void scope.set('extraContentArgKeys', (value.extraContentArgKeys ?? []).filter((_, i) => i !== index)) }}\n />\n <div style={{ height: '10px' }} />\n <StringListField\n label={t('card.extraOperationArgKeys')}\n hint={t('card.extraOperationArgKeysHint')}\n placeholder={t('card.extraContentArgKeysPlaceholder')}\n addLabel={t('card.denylistAdd')}\n removeLabel={t('card.listRemove')}\n items={value.extraOperationArgKeys ?? []}\n locked={readonly}\n onAdd={(entry) => { void scope.set('extraOperationArgKeys', [...(value.extraOperationArgKeys ?? []), entry]) }}\n onRemove={(index) => { void scope.set('extraOperationArgKeys', (value.extraOperationArgKeys ?? []).filter((_, i) => i !== index)) }}\n />\n </section>\n\n {/* Credential-family ladder: rows live in the rules document (section +\n enabled) and in credWriteExemptFamilies — read and written through\n the cred route, never mirrored here. */}\n <CredLadderSection t={t} readonly={readonly} />\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 <PillSwitch\n id=\"plugin-config-perm-gate-network-enabled\"\n label={t('card.networkEnabled')}\n checked={value.networkEnabled === true}\n disabled={readonly}\n onCommit={(next) => scope.set('networkEnabled', next)}\n />\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 <PillSwitch\n id=\"plugin-config-perm-gate-network-inject-env\"\n label={t('card.networkInjectEnv')}\n checked={value.networkInjectEnv !== false}\n disabled={readonly}\n onCommit={(next) => scope.set('networkInjectEnv', next)}\n />\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 <PillSwitch\n id=\"plugin-config-perm-gate-watch\"\n label={t('card.watch')}\n checked={value.watch !== false}\n disabled={readonly}\n onCommit={(next) => scope.set('watch', next)}\n />\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","/**\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 /**\n * The card the human decided from (why it asks / what it touches / what each\n * button costs). Preferred over `reason` in the review list: the audit reason is\n * a machine label, and a list of machine labels cannot be read back as \"what did\n * I just approve, and why\".\n */\n readonly humanBrief?: string\n /** The redacted command, kept apart from the prose so the list can show it as code. */\n readonly humanCommand?: string\n /** Machine keys of \"why it asked\", for localized rendering. */\n readonly doubtKinds?: readonly 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 /** Salted digest of the redacted input behind the decision, when recorded. */\n readonly inputDigest?: string\n /** Which grading prompt produced this verdict, when recorded. */\n readonly promptVersion?: string\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 // The unattended tiers never raise a prompt, so the approvals history is the only\n // place their decisions surface — an untranslated tag there reads as a leak.\n 'yolo-allow': 'YOLO 放行',\n // The YOLO tier advertises a reviewer model. When none answered, the tier still refuses to\n // ask a person and settles mechanically — and the history has to say that out loud, or the\n // two human-free tiers silently become one.\n 'yolo-allow-no-reviewer': 'YOLO 放行(无审查模型·机械处置)',\n 'yolo-block': 'YOLO 拦截',\n 'rules-fallback-allow': '无模型规则闸门放行',\n 'rules-fallback-block': '无模型规则闸门拦截',\n 'safety-net-passthrough-allow': '机械审查放行(零模型)',\n 'safety-net-passthrough-block': '机械审查拦截(零模型)',\n // Longer-standing paths that also reach the feed without a label.\n 'cleanup-safe': '清理类安全放行',\n 'escalation-auto': '沙箱升级自动放行',\n 'learned-granted': '学习授权放行',\n 'network-ask': '网络审批',\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'\nimport type { PermissiveKey } from './locales.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 {' \\u2014 '}\n {notice.doubtKinds !== undefined && notice.doubtKinds.length > 0\n ? notice.doubtKinds.map((k) => t(`doubt.${k}` as PermissiveKey)).join(' \\u00b7 ')\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.doubtKinds !== undefined && ev.doubtKinds.length > 0\n ? ev.doubtKinds.map((k) => t(`doubt.${k}` as PermissiveKey)).join(' · ')\n : (ev.humanBrief ?? ev.justification ?? ev.reason)}\n </div>\n {ev.humanCommand === undefined || ev.humanCommand === ''\n ? null\n : (\n /*\n * The command gets its own block in the host's code font, the way the approval\n * popup shows it (`.command` vs `.headline`): prose and payload must not share a\n * line, or the reader cannot tell what they are about to run from why they are\n * being asked.\n */\n <div\n style={{\n marginTop: '4px',\n fontFamily: 'var(--ds-font-family-code, monospace)',\n fontSize: '12px',\n lineHeight: '18px',\n whiteSpace: 'pre-wrap',\n overflowWrap: 'anywhere',\n color: 'var(--dsw-alias-label-primary, inherit)',\n }}\n >\n {ev.humanCommand}\n </div>\n )}\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/<ns>/settings/describe;\n * 写 = POST …/mutate(ops 转发宿主 settings 服务),成功即用回填描述符刷新快照并\n * 通知订阅者(乐观刷新,无本地第二份状态——权威值始终在宿主服务里)。\n * 初始 describe 拉取在构造时异步发起;拉取完成前快照 status='pending',卡片据此\n * 呈现加载态。\n *\n * T20-b 泛化(2026-10-08):路由由构造参数 ns 派生(与 server 侧 bridgeRoutesFor\n * 同式,两半一致性由测试钉死)——同一宿主进程多 ns 各持一个句柄(steward 双 ns)。\n * client tsconfig include 仅 src/client,故此处持本地派生式而非跨目录 import。\n */\nimport type { SettingsDocHandle } from './compat.js'\n\n/** 与 server 侧 bridgeRoutesFor(src/bridge.ts)必须逐字符一致。 */\nfunction bridgeRoutesFor(ns: string): { describe: string; mutate: string } {\n return { describe: `/api/${ns}/settings/describe`, mutate: `/api/${ns}/settings/mutate` }\n}\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 private readonly routes: { describe: string; mutate: string }\n\n constructor(ns: string) {\n this.routes = bridgeRoutesFor(ns)\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(this.routes.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(this.routes.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 top-level `settings.section`\n * entry (自动审查门) so the settings sidebar renders a standalone editable\n * section: the single 自动审查 tier switch plus the four combinable backend\n * 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'\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 // (settings.plugin.item 槽型镜像已随该席位退役一并删除——与顶级独立节\n // 重复的 ≤0.1.5 派发卡不再出现。settings.section 的槽型由\n // @deepseek-ai/dsh-client-ui-settings/client 的声明提供,无需本地镜像。)\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(PERMISSIVE_NS)\n\n // 卡片 inject 读活引用:注册先于 scope 解析也不空窗(未解析时回落桥轨,\n // 桥首拉 pending 期间卡片呈现加载态)。\n const cardInjected = (): PermissiveCardInjected => ({ scope: scopeRef.scope ?? bridgeScope }) as PermissiveCardInjected\n\n // 独立顶级设置节(范式 A;2026-10-08 回退定案:本插件不在家族 tab 化范围内\n // ——自动审查门是独立 insection,与「权限/上下文优化独立分节」的参考样本\n // 一致)。卡组件与数据臂(原生句柄优先 + 桥兜底)原样复用;server 侧数据面\n // (installSection 三代 + 桥路由)不动。与插件页 tab / ≤0.1.5 派发卡的\n // 去重取舍见下方注释。\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)已于 2026-10-08 移除:0.1.0\n // 实测它与顶级 settings.section 同时渲染,同一张卡出现两次;顶级独立节是\n // 唯一设置导航入口(同日家族 tab 收拢已回退——本插件不在 tab 化范围内)。\n\n // ≤0.1.5 设置面板「插件配置」tab 的派发卡(settings.plugin.item)同批退役:\n // 与顶级独立节重复。server 侧 installSection 数据面保留——它同时是桥\n // describe/mutate 与 served ns 的来源。\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/client/switch-state.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.unattended': '无人值守档位(三套实现,每颗开关决定自己那一档是否存在)',\n 'card.unattendedHint': '三颗开关,每颗只管它旁边标着的那一档:关掉即实现不存在,那一档退回普通人工流,不会偷偷变成别的档。',\n 'card.mode.ask': '保留人工',\n 'card.mode.pass': '机械直通',\n 'card.askHint': '(危险/不确定才人工确认)仍接回沙箱组:作用域内的安全操作照由 trustAutoAllow 自动静默放行、不弹确认;确定性机械审查器只对运行前的危险(破坏性 Git 与文件系统命令、SSH 密钥/.env 等机密访问)与未知残局列出疑点、交人工确认,一次审查模型都不叫——不触发确认的安全操作照常执行。适用于无审查 LLM 可用、或不值当花 token 的运行。',\n 'card.passHint': '(检查通过直接放行、不问人)只跑确定性机械审查器:运行前命中不可逆 / 不可沉淀 / 读不懂的载荷(含破坏性 Git 与文件系统命令、SSH 密钥/.env 等机密访问)就拦截并把理由回喂主模型,检查后无问题的其余照常直接执行。零模型调用——相当于 approval: never 的有审查版,也是 yolo 拿掉 LLM 后的劣化形态。',\n 'card.tierScopeHint': '只有落在门禁作用域(%scope)里的预设才会走到这一步;预设不在作用域内时整个门禁停用,任何开关都不会接管它的确认。',\n 'card.yolo': 'YOLO — 永不人工确认:危险才拦,其余放行',\n 'card.yoloExempt': 'YOLO:工作区内「落点未知」也放行',\n 'card.yoloExemptHint': '只在 YOLO 档生效。打开后,仅「位置判不清」的调用(无参数工具、工作区外脚本未读到正文)不再按「看不见」拦截;编码载荷、读不到正文的脚本、删除与远端写仍然拦,P0/凭据/不可逆一律不变。',\n 'card.yoloHint': '命中不可逆 / 不可沉淀 / 读不懂的载荷,或模型报硬风险时拦截,并把理由以「工具审核意见」回喂主模型;其余照常执行。没有可用模型时只靠确定性规则网拦截。',\n 'card.rulesFallback': '无模型时降级成规则闸门(cc-safety-net 级)',\n 'card.rulesFallbackHint': '只在审查模型未配置、或模型未能给出裁决时生效:按确定性规则拦危险、放行其余,不再把调用挂在没人应答的确认框上。模型正常回答时行为与之前完全一致。',\n 'card.allowProtectedBranchPush': '允许强推保护分支(默认关=保留地板)',\n 'card.allowProtectedBranchPushHint': '默认用 P0 地板拦下针对 main/master/production/release/stable 的 git push --force/--force-with-lease/--delete(模型不可降级)。开启后地板让位,并豁免黑名单里三条扁平 push 词;调用落到预设的 git.push-force 规则——它仍会问人,除非你撤销该条或加白名单。不放宽任何其他面:删除、重定向、凭据地板照常。',\n 'card.credFamily': '凭据类型阶梯',\n 'card.credFamilyHint': '每类凭据一个档位:deny=读写全拦;ask=读需人工确认(默认);readonly=读放行、写删仍被 P0 硬拦;readwrite=本族内置路径的凭据 store 写判据退让(npm login 类工作流),其余地板(根盘、受保护路径、.dsh、外发)任何档位都不让。档位状态存在规则文档条目与写豁免清单两处,由本卡成对写回。',\n 'card.credFamilyLoading': '正在读取凭据档位…',\n 'card.credFamilyFootnote': '无人值守档(机械直通/YOLO)会把 ask 残局放行;需要硬挡请选 deny。自定义 credentialPaths 不参与写豁免;readwrite 不影响任何非凭据判据。',\n 'card.credReadwriteConfirm': 'readwrite 将放行对该类凭据文件的写入/修改(如重写 ~/.npmrc);这是唯一会退让部分 P0 的档位。确认?',\n 'card.credConfirmYes': '确认',\n 'card.credConfirmNo': '取消',\n 'card.credRung.deny': '拦截',\n 'card.credRung.ask': '确认',\n 'card.credRung.readonly': '只读',\n 'card.credRung.readwrite': '读写',\n 'card.scriptReview': '脚本正文随审查一并送审(默认开)',\n 'card.scriptReviewHint': '调用运行脚本文件时读取它的正文:审查模型与人看的是同一份代码,规则层也按正文判定不可逆(文件名看不出危险的删除正是这么漏掉的)。正文出境前脱敏并截断;关掉它就不会让文件内容离开本机,代价是工作区外的脚本回到「看不清」档位。',\n 'card.credentialPaths': '自定义凭据路径(长尾)',\n 'card.credentialPathsHint': '插件内置清单之外的机密文件。写法是路径 glob:双星跨目录、单星与问号只在一段内;不含通配符时按路径片段匹配(token 不会命中 ambient.txt);行首 ~/ 会展开为你的 home;相对写法也在任意深度匹配(secrets/*.env 覆盖 a/b/secrets/prod.env)。命中后与 .ssh 同档:工作区外读取被硬拒、被文件工具改写被硬拒(这一档不可申诉,也不会被审查模型放行),所以只写确实需要保护的路径。',\n 'card.credentialPathsPlaceholder': '新路径,如 ~/.myco/vault.token 或 secrets/*.env',\n 'card.denyKeywordsExtra': '追加黑名单关键词(不替换预置)',\n 'card.denyKeywordsExtraHint': '在你自己的命令词上加一道确定性拦截,例如公司内部 CLI 的吊销/清库子命令或自有令牌前缀。这里只做追加:无论上面「黑名单」是预置还是你替换过,这些词都会并进去。',\n 'card.listRemove': '移除该条目',\n 'card.extraContentArgKeys': '追加正文键(这些参数不被当操作读)',\n 'card.extraContentArgKeysHint': '内置清单(content/text/plan…)之外的文档字段名,例如某个自有工具的 steps/notes:加进来后,它的文字不再进入危险词与凭据形态的扁平扫描。只追加、不替换内置表——漏写一个内置键就会重现“把计划当操作拒掉”的静默失效。被执行的命令本身与被改写的路径走各自判据,这张表关不掉它们。',\n 'card.extraContentArgKeysPlaceholder': '新参数名,如 steps',\n 'card.extraOperationArgKeys': '追加操作键(把该字段当会执行的代码读)',\n 'card.extraOperationArgKeysHint': '给「正文其实会被执行」的字段开口子(如 workflowYaml):它的文本会进入黑名单与凭据预筛;与上一张表撞名时本表获胜。代价:把真正的文档字段写进来,就等于让「计划里提到 rm -rf」重新变成拒绝理由。',\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.llmEffort': '推理强度(仅 host 模式)',\n 'card.llmEffortHost': '跟随宿主默认',\n 'card.llmEffortHint': '留空=不干预,由宿主模型配置决定;被宿主拒绝时改 low 或 off。',\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 'doubt.no-rule': '没有规则覆盖这次调用,按默认策略交给人 — 这不表示它危险',\n 'doubt.opaque': '命令载荷读不懂(编码过 / 工作区外的脚本 / 认不出程序名),规则层无法定位目标',\n 'doubt.irreversible': '规则判定不可逆:跑完无法撤回',\n 'doubt.never-learn': '这类确认不会沉淀,下次同样的操作还会再问',\n 'doubt.delete': '会删除内容',\n 'doubt.remote-write': '会产生对外可见的副作用(推送 / 发布 / 写请求),撤回需要额外手动操作',\n 'doubt.exec-external': '会执行工作区之外的代码,本次调用无法静态看清它做什么',\n 'doubt.outside-paths': '涉及工作区之外的路径',\n 'doubt.model-flagged': '风险模型认为可疑(它只能升级,不能放行)',\n 'doubt.write': '会写入或修改文件',\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.unattended': 'Unattended tiers (three implementations — each switch decides whether its own tier exists)',\n 'card.unattendedHint': 'Three switches, each governing only the tier named beside it: switching an implementation off returns that tier to the ordinary human flow — it never quietly becomes a different tier.',\n 'card.mode.ask': 'Keep human',\n 'card.mode.pass': 'Mechanical pass-through',\n 'card.askHint': '(Manual confirmation only for danger / uncertainty) Still on the sandbox group: safe operations inside the scope are auto-allowed silently by trustAutoAllow with no popup; the deterministic mechanical screen lists its doubts and asks a person only for pre-execution danger (destructive Git and filesystem commands, access to SSH keys / .env credentials) and unreadable or unknown residuals, calling no grader at all — anything that does not trigger a confirmation runs as normal. The shape for runs with no reviewer LLM connected, or where the tokens are not worth spending.',\n 'card.passHint': '(Auto-allow once the check passes, no human prompt) Runs the deterministic mechanical judge only: before execution an irreversible, unlearnable or unreadable call (including destructive Git and filesystem commands and access to SSH keys / .env credentials) is blocked and the reason fed back to the main model, everything that passes runs directly. No model call — the reviewed form of approval: never, and YOLO with the model taken away.',\n 'card.tierScopeHint': 'Only presets inside the gate\\'s scope (%scope) reach this step; outside it the whole gate stands down, so no switch takes over its confirmations.',\n 'card.yolo': 'YOLO — never ask a human: block the dangerous, run the rest',\n 'card.yoloExempt': 'YOLO: also allow \"unknown location\" inside the workspace',\n 'card.yoloExemptHint': 'YOLO only. When on, a call whose target simply cannot be pinned down (no-argument tools, a script outside the workspace whose body was not read) is no longer blocked as \"unseen\". Encoded payloads, unreadable script bodies, deletes and remote writes are still blocked; P0, credentials and irreversible acts never change.',\n 'card.yoloHint': 'Blocks an irreversible / unlearnable / unreadable payload, or a hard-risk verdict from the model, and feeds the reason back to the main LLM as a 工具审核意见 message; everything else executes. With no reviewer available only the deterministic nets catch anything.',\n 'card.rulesFallback': 'Degrade to a rule-only gate when there is no model (cc-safety-net class)',\n 'card.rulesFallbackHint': 'Takes effect only when the risk reviewer is not configured or gave no verdict: the deterministic nets block what they can name and let the rest through, instead of parking the call on a popup nobody will answer. While a reviewer answers, behaviour is unchanged.',\n 'card.allowProtectedBranchPush': 'Allow force-pushing protected branches (default off = floor stands)',\n 'card.allowProtectedBranchPushHint': 'By default the P0 floor hard-blocks git push --force/--force-with-lease/--delete aimed at main/master/production/release/stable (not downgradable by any model). Turning it on steps the floor aside and exempts the three flat push keywords in the blacklist; the call then falls to the seeded git.push-force rule, which still asks a person unless you revoke that entry or allowlist it. Nothing else widens: wipes, redirects and the credential floor stay armed.',\n 'card.credFamily': 'Credential family ladder',\n 'card.credFamilyHint': 'One rung per family: deny = block reads and writes; ask = reads need a person (default); readonly = reads pass, writes stay hard-blocked by P0; readwrite = the credential-store WRITE clause steps aside for that family\\u0027s built-in paths (npm-login style) — every other floor (roots, protected paths, .dsh, exfil) stays armed at any rung. The rung lives in the rules-document row plus the paired write-exemption list; this card writes both together.',\n 'card.credFamilyLoading': 'Loading credential rungs…',\n 'card.credFamilyFootnote': 'Unattended tiers (mechanical pass / YOLO) let ask residuals run — pick deny to hard-block. Custom credentialPaths never join the write exemption; readwrite changes nothing outside credential stores.',\n 'card.credReadwriteConfirm': 'readwrite lets tools WRITE/modify this family\\u0027s credential files (e.g. rewrite ~/.npmrc). This is the only rung that steps a piece of P0 aside. Confirm?',\n 'card.credConfirmYes': 'Confirm',\n 'card.credConfirmNo': 'Cancel',\n 'card.credRung.deny': 'deny',\n 'card.credRung.ask': 'ask',\n 'card.credRung.readonly': 'readonly',\n 'card.credRung.readwrite': 'readwrite',\n 'card.scriptReview': 'Attach script bodies to the review (on by default)',\n 'card.scriptReviewHint': 'When a call runs a script file, its body is read and given to the risk model and the human alike, and the deterministic nets grade the body too (a delete that only shows up inside the file is exactly what used to slip through). Bodies are redacted and length-capped before leaving the host; switching this off keeps file contents local at the cost of sending out-of-workspace scripts back to the unreadable tier.',\n 'card.credentialPaths': 'Custom credential paths (the long tail)',\n 'card.credentialPathsHint': 'Secret files the built-in list does not know. Entries are path globs: a double star crosses directories, a single star and a question mark stay inside one segment; without a wildcard it matches a whole path fragment (token will not hit ambient.txt); a leading ~/ expands to your home; a relative pattern also matches at any depth (secrets/*.env covers a/b/secrets/prod.env). A hit is held to the same standard as .ssh: reading it outside the workspace is hard-denied, mutating it with a file tool is hard-denied — that tier cannot be appealed or talked past by the reviewer, so declare only paths you truly need protected.',\n 'card.credentialPathsPlaceholder': 'New path, e.g. ~/.myco/vault.token or secrets/*.env',\n 'card.denyKeywordsExtra': 'Appended blacklist keywords (never replaces the preset)',\n 'card.denyKeywordsExtraHint': 'A deterministic block on words of your own — a revoke/wipe subcommand of a company CLI, a token prefix you issue. This list only ever appends: whatever the blacklist above holds (preset or your own replacement), these words are merged in.',\n 'card.listRemove': 'Remove this entry',\n 'card.extraContentArgKeys': 'Appended document keys (never read as an operation)',\n 'card.extraContentArgKeysHint': 'Document field names beyond the built-in list (content/text/plan…): once listed, their text stops entering the flattened scan that the destructive-word blacklist and the credential pre-screen read. Additive only — the built-in list cannot be replaced, because dropping one of its keys would silently re-create the bug where a plan gets refused for describing work. The executed command and the mutated path are judged on their own terms; this list cannot switch them off.',\n 'card.extraContentArgKeysPlaceholder': 'New argument name, e.g. steps',\n 'card.extraOperationArgKeys': 'Appended operation keys (read this field as code that runs)',\n 'card.extraOperationArgKeysHint': 'Opens a route for fields whose body really is executed (workflowYaml and friends): their text enters the blacklist and the credential screen, and this list wins when both name the same key. Cost: naming a genuine document field here makes “the plan mentions rm -rf” a refusal reason again.',\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.llmEffort': 'Reasoning effort (host mode only)',\n 'card.llmEffortHost': 'Follow the host default',\n 'card.llmEffortHint': 'Empty = send no effort and let the host model config decide; switch to low or off if the host rejects it.',\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 'doubt.no-rule': 'no rule covers this call, so the default is to ask — that does not mean it is dangerous',\n 'doubt.opaque': 'the payload cannot be read (encoded, a script outside the workspace, or no recognisable program), so no rule can locate its target',\n 'doubt.irreversible': 'a rule says this is irreversible: it cannot be undone once run',\n 'doubt.never-learn': 'this answer will not be learned; the same call will ask again next time',\n 'doubt.delete': 'it deletes content',\n 'doubt.remote-write': 'it has an externally visible effect (push / publish / write request); undoing it takes extra manual steps',\n 'doubt.exec-external': 'it runs code from outside the workspace, which this call cannot inspect',\n 'doubt.outside-paths': 'it touches paths outside the workspace',\n 'doubt.model-flagged': 'the risk model flagged it (it can only escalate, never clear)',\n 'doubt.write': 'it writes or modifies files',\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.unattended': '無人確認ティア(3 つの実装 — スイッチは各自のティアの有無を決めます)',\n 'card.unattendedHint': 'スイッチは三つ。それぞれ脇に書いたティアだけを制御します。実装をオフにするとそのティアは通常の人確認に戻り、別のティアに化けることはありません。',\n 'card.mode.ask': '人手確認を残す',\n 'card.mode.pass': '機械直通',\n 'card.askHint': '機械スクリーニングは引き続き危険を絞り疑点を列挙しますが、確認は人に残り審査モデルは一度も呼びません — 審査 LLM 未接続、またはトークンを費やさない運用の形です。',\n 'card.passHint': '決定論的な機械審査器のみを実行:不可逆 / 復元不能 / 読めない処理を検知したら遮断して理由を主モデルへ返し、それ以外は実行します。モデル呼び出しゼロ・人手確認なし。approval: never の審査付き版であり、LLM を外した YOLO の劣化形態でもあります。',\n 'card.tierScopeHint': 'このステップまで到達するのはゲートの適用範囲(%scope)内のプリセットだけです。範囲外ではゲート全体が停止し、どのスイッチも確認を代行しません。',\n 'card.yolo': 'YOLO — 人工確認は決して求めない:危険のみ遮断、他は実行',\n 'card.yoloExempt': 'YOLO:ワークスペース内の「場所不明」も許可',\n 'card.yoloExemptHint': 'YOLO 専用。オンのとき、対象の「場所」が特定できないだけの呼び出し(引数なしのツール、本文を読めていない外部スクリプト)は「見えない」としては遮断しません。エンコードされたペイロード、読めないスクリプト本文、削除・リモート書込みは従来通り遮断し、P0/資格情報/不可逆は一切変わりません。',\n 'card.yoloHint': '復元不能 / 学習不能 / 読解不能なペイロード、またはモデルの重リスク判定を遮断し、理由を「工具審核意見」メッセージでメイン LLM に返します。それ以外は実行されます。レビューモデルが無い場合は決定論的ネットのみが機能します。',\n 'card.rulesFallback': 'モデル不在時はルールゲートへ劣化(cc-safety-net 級)',\n 'card.rulesFallbackHint': 'レビューモデルが未設定、または判定を返せなかったときだけ発効します。決定論的ルールが名指しできる危険を遮断し、残りは通します。誰も答えない確認画面で処理を止めないためです。モデルが答えている間は挙動は変わりません。',\n 'card.allowProtectedBranchPush': '保護ブランチへの force push を許可(既定オフ=床を維持)',\n 'card.allowProtectedBranchPushHint': '既定では main/master/production/release/stable を狙った git push --force/--force-with-lease/--delete を P0 床で確定遮断します(モデルで降格不可)。オンにすると床が退き、ブラックリストの3つの扁平 push 語も免除されます。呼び出しはプリセット git.push-force(人間確認が必要)に落ち、該当エントリを取り消すか許可リストに入れるまで毎回確認します。他の面は広がりません:削除・リダイレクト・認証情報の床はそのまま。',\n 'card.credFamily': '認証情報ファミリーの階段',\n 'card.credFamilyHint': 'ファミリーごとに1段:deny=読み書きとも遮断;ask=読みは人間確認(既定);readonly=読み通過、書き/削除はP0で確定遮断のまま;readwrite=このファミリーの認証情報ストア書き込み判据のみ退く(npm login 系)。その他の床(ルートディスク・保護パス・.dsh・外部送信)はどの段でも動かさない。段の状態はルール文書の条目と書き込み免除リストの2箇所に置かれ、本カードが対で書き戻す。',\n 'card.credFamilyLoading': '認証情報の段を読み込み中…',\n 'card.credFamilyFootnote': '無人運用モード(機械直通/YOLO)では確認残局がそのまま通ります。硬く止めるには deny を選択してください。カスタム credentialPaths は書き込み免除に参加しません。',\n 'card.credReadwriteConfirm': 'readwrite はこの種の認証情報ファイルへの書き込み/変更を許可します(~/.npmrc の上書きなど)。P0 の一部を退かす唯一の段です。確認しますか?',\n 'card.credConfirmYes': '確認',\n 'card.credConfirmNo': 'キャンセル',\n 'card.credRung.deny': '遮断',\n 'card.credRung.ask': '確認',\n 'card.credRung.readonly': '読取のみ',\n 'card.credRung.readwrite': '読み書き',\n 'card.scriptReview': 'スクリプト本文をレビューに添付(既定はオン)',\n 'card.scriptReviewHint': '呼び出しがスクリプトファイルを実行するとき、その本文を読み取り、レビューモデルと人が同じコードを見ます。決定論的ネットも本文を評価します(ファイル名からは見えない削除がまさに通過していた箇所)。送出前に秘匿化と長さ制限を実施。オフにするとファイル内容が外部へ出ませんが、ワークスペース外のスクリプトは「読解不能」ティアに戻ります。',\n 'card.credentialPaths': 'カスタム認証情報パス(長尾)',\n 'card.credentialPathsHint': '内蔵リスト外の機密ファイル。書き方はパス glob:双アスタリスクはディレクトリを横断、単アスタリスクとはてなは 1 段内。ワイルドカードなしならパス断片として一致(token は ambient.txt に掛からない)。先頭の ~/ は home に展開、相対指定は任意の深さでも一致(secrets/*.env は a/b/secrets/prod.env を覆う)。該当すれば .ssh と同格:ワークスペース外からの読み取りもファイルツールでの書き換えも強制拒否——このティアは異議申立て、レビューモデルの通過も不可なので、本当に守るべきパスだけを宣言してください。',\n 'card.credentialPathsPlaceholder': '新しいパス、例:~/.myco/vault.token または secrets/*.env',\n 'card.denyKeywordsExtra': 'ブラックリスト追加キーワード(プリセットを置き換えない)',\n 'card.denyKeywordsExtraHint': '自社 CLI の取消し/消去サブコマンドや自社トークン接頭語など、自分の語彙に決定論的な遮断を一段足します。ここは追加のみ:上のブラックリストがプリセットでも自分で置き換えたものでも、これらの語はマージされます。',\n 'card.listRemove': 'この項目を削除',\n 'card.extraContentArgKeys': '追加のドキュメントキー(操作として読ませない)',\n 'card.extraContentArgKeysHint': '内蔵リスト(content/text/plan…)外のドキュメント項目名。追加すると、その文言は危険語と認証情報の平坦スキャンに入らなくなります。追加専用で内蔵表は置き換えません——内蔵キーを一つ落とすと「計画書を書いたという理由で拒否される」不具合が静かに復活します。実行されるコマンド自体と書き換えられるパスはそれぞれの判別経路なので、この表では無効化できません。',\n 'card.extraContentArgKeysPlaceholder': '新しい引数名、例:steps',\n 'card.extraOperationArgKeys': '追加の操作キー(その項目を実行されるコードとして読む)',\n 'card.extraOperationArgKeysHint': '本文が実際に実行される項目(workflowYaml など)用の出口です。その文言はブラックリストと認証情報スクリーンに入り、上の表と同名ならこちらが勝ちます。代償:本物のドキュメント項目を指定すると、「計画に rm -rf と書いた」ことが再び拒否理由になります。',\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.llmEffort': '推論強度(host モードのみ)',\n 'card.llmEffortHost': 'ホスト既定に従う',\n 'card.llmEffortHint': '空 = 指定せずホストのモデル設定に任せる。ホストに拒否されたら low か off に変更。',\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 'doubt.no-rule': 'この呼び出しを覆うルールがなく、既定で人間に委ねました — 危険という意味ではありません',\n 'doubt.opaque': 'ペイロードを読み取れません(エンコード済み / ワークスペース外スクリプト / プログラム名不明)、ルールは対象を特定できません',\n 'doubt.irreversible': 'ルール上 不可逆:実行後は取り消せません',\n 'doubt.never-learn': 'この承認は学習されません。次回も同じ確認が出ます',\n 'doubt.delete': '内容を削除します',\n 'doubt.remote-write': '外部から見える変更(push / publish / 書き込みリクエスト)が発生し、取り消しに手作業が必要',\n 'doubt.exec-external': 'ワークスペース外のコードを実行します。この呼び出しでは内容を抜き取れません',\n 'doubt.outside-paths': 'ワークスペース外のパ스에接触します',\n 'doubt.model-flagged': '风险モデルが疑わしいと判定(エスカレートののみ可能、クリアは不可)',\n 'doubt.write': 'ファイルを書き込みまたは変更します',\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.unattended': '무인 등급(구현 세 개 — 각 스위치가 자기 등급의 존재 여부를 정합니다)',\n 'card.unattendedHint': '스위치는 셋, 각자 옆에 적힌 등급만 제어합니다. 구현을 끄면 그 등급은 보통의 사람 확인으로 돌아가며, 다른 등급으로 몰래 바뀌지 않습니다.',\n 'card.mode.ask': '사람 확인 유지',\n 'card.mode.pass': '기계 직통과',\n 'card.askHint': '기계 선별로 위험을 걸러 내고 의문점을 적지만, 확인은 그대로 사람에게 남고 심사 모델은 한 번도 부르지 않습니다 — 심사 LLM 미연결이나 토큰을 아끼는 운용에 맞는 형태입니다.',\n 'card.passHint': '결정론적 기계 심사기만 실행:되돌릴 수 없음 / 복원 불가 / 읽히지 않는 처리를 감지하면 차단하고 이유를 주모델에 되돌려 보내며, 나머지는 실행합니다. 모델 호출 0회·사람 확인 없음. approval: never 의 심사판이며, LLM 을 뺀 YOLO 의 열화된 형태이기도 합니다.',\n 'card.tierScopeHint': '게이트 적용 범위(%scope) 안의 프리셋만 이 단계까지 옵니다. 범위 밖에서는 게이트 전체가 중지되므로 어떤 스위치도 확인을 대신하지 않습니다.',\n 'card.yolo': 'YOLO — 사람 확인은 절대 요구하지 않음: 위험만 차단하고 나머지는 실행',\n 'card.yoloExempt': 'YOLO: 워크스페이스 내 “위치 불명”도 허용',\n 'card.yoloExemptHint': 'YOLO 전용. 켜면 대상의 “위치”만 확인할 수 없는 호출(인자 없는 도구, 본문을 읽지 못한 외부 스크립트)은 “보이지 않음”으로 차단하지 않습니다. 인코딩된 페이로드, 읽을 수 없는 스크립트 본문, 삭제·원격 쓰기는 계속 차단되며 P0/자격 증명/비가역 작업은 전혀 바뀌지 않습니다.',\n 'card.yoloHint': '복구 불가 / 학습 불가 / 해석 불가 페이로드, 또는 모델이 위험 판정을 내리면 차단하고 이유를 「工具审核意见」 메시지로 메인 LLM에 알려합니다. 나머지는 그대로 실행됩니다. 검토 모델이 없으면 결정론적 규칙망만 작동합니다.',\n 'card.rulesFallback': '모델이 없을 때 규칙 게이트로 강등 (cc-safety-net 급)',\n 'card.rulesFallbackHint': '검토 모델이 설정되지 않았거나 판정을 내리지 못했을 때만 발동합니다. 결정론적 규칙이 식별한 위험은 차단하고 나머지는 통과시켜, 아무도 응답하지 않는 확인 창에 호출을 대기시키지 않습니다. 모델이 정상 응답하는 동안에는 동작이 변하지 않습니다.',\n 'card.allowProtectedBranchPush': '보호 브랜치 force push 허용 (기본 꺼짐 = 바닥 유지)',\n 'card.allowProtectedBranchPushHint': '기본에서 main/master/production/release/stable 을 노린 git push --force/--force-with-lease/--delete 를 P0 바닥으로 확정 차단합니다(모델로 강등 불가). 켜면 바닥이 물러나고 블랙리스트의 세 평면 push 키워드도 면제됩니다. 호출은 프리셋 git.push-force(사람 확인 필요) 규칙으로 떨어져, 해당 항목을 취소하거나 허용 목록에 넣기 전엔 매번 확인합니다. 다른 면은 넓어지지 않습니다: 삭제·리다이렉트·자격증명 바닥은 그대로.',\n 'card.credFamily': '자격증명 계열 사다리',\n 'card.credFamilyHint': '계열별 한 칸: deny=읽기·쓰기 모두 차단; ask=읽기 사람 확인(기본); readonly=읽기 통과, 쓰기·삭제는 P0 확정 차단 유지; readwrite=해당 계열의 자격증명 store 쓰기 판정만 물러남(npm login 계열). 그 외 바닥(루트·보호 경로·.dsh·유출)은 어떤 칸에서도 움직이지 않습니다. 상태는 규칙 문서 항목과 쓰기 면제 목록 두 곳에 저장되며 이 카드가 한 쌍으로 함께 씁니다.',\n 'card.credFamilyLoading': '자격증명 단계 로딩 중…',\n 'card.credFamilyFootnote': '무인 등급(기계 직통/YOLO)에서는 ask 잔여가 통과합니다. 단단히 막으려면 deny를 선택하세요. 사용자 지정 credentialPaths는 쓰기 면제에 참여하지 않습니다.',\n 'card.credReadwriteConfirm': 'readwrite는 이 종 자격증명 파일의 쓰기/수정을 허용합니다(~/.npmrc 재작성 등). P0의 일부를 퇴각시키는 유일한 칸입니다. 확인하시겠습니까?',\n 'card.credConfirmYes': '확인',\n 'card.credConfirmNo': '취소',\n 'card.credRung.deny': '차단',\n 'card.credRung.ask': '확인',\n 'card.credRung.readonly': '읽기 전용',\n 'card.credRung.readwrite': '읽기쓰기',\n 'card.scriptReview': '스크립트 본문 검토 함께 전송 (기본 켜짐)',\n 'card.scriptReviewHint': '호출이 스크립트 파일을 실행하면 본문을 읽어 검토 모델과 사람이 같은 코드를 보게 하고, 결정론적 규칙도 본문을 평가합니다 (파일명으로는 위험이 보이지 않는 삭제가 바로 그 통과 지점이었습니다). 전송 전 마스킹과 길이 제한을 적용합니다. 끄면 파일 내용이 외부로 나가지 않지만, 작업 공간 외부 스크립트는 다시 해석 불가 등급이 됩니다.',\n 'card.credentialPaths': '사용자 정의 자격증명 경로 (롱테일)',\n 'card.credentialPathsHint': '내장 목록이 모르는 비밀 파일입니다. 항목은 경로 glob: 이중 별은 디렉터리를 횡단하고 단별과 물음표는 한 단계 안에서만 동작합니다. 와일드카드가 없으면 경로 단편 전체로 일치 (token 은 ambient.txt 에 걸리지 않음). 선행 ~/ 는 home 으로 확장되고, 상대 지정은 어떤 깊이에서도 일치합니다 (secrets/*.env 는 a/b/secrets/prod.env 를 커버). 걸리면 .ssh 와 동일한 등급: 작업 공간 외부 읽기와 파일 도구 통한 변경 모두 경성 거부입니다—이 등급은 이의 제기나 검토 모델 우회가 불가능하니 정말 보호할 경로만 선언하세요.',\n 'card.credentialPathsPlaceholder': '새 경로, 예: ~/.myco/vault.token 또는 secrets/*.env',\n 'card.denyKeywordsExtra': '추가 블랙리스트 키워드 (프리셋을 대체하지 않음)',\n 'card.denyKeywordsExtraHint': '사내 CLI 의 폐기/삭제 서브커맨드나 자체 토큰 접두사처럼 자신만의 용어에 결정론적 차단을 한 겹 더합니다. 여기는 추가만 합니다: 위의 블랙리스트가 프리셋이든 대체한 것이든 이 단어들은 병합됩니다.',\n 'card.listRemove': '이 항목 삭제',\n 'card.extraContentArgKeys': '추가 문서 키 (작업으로 읽지 않음)',\n 'card.extraContentArgKeysHint': '내장 목록(content/text/plan…) 밖의 문서 필드명입니다. 추가하면 그 텍스트가 위험 단어 · 자격증물 평탄화 스캔에 들어가지 않습니다. 추가 전용이며 내장 표를 대체하지 않습니다 — 내장 키 하나를 빠뜨리면 『계획서를 작성했다는 이유로 거부되는』 결함이 조용히 부활합니다. 실제로 실행되는 명령과 변경되는 경로는 각자의 판정을 따르므로 이 표로는 끌 수 없습니다.',\n 'card.extraContentArgKeysPlaceholder': '새 인자 이름, 예: steps',\n 'card.extraOperationArgKeys': '추가 작업 키 (해당 필드를 실행되는 코드로 읽음)',\n 'card.extraOperationArgKeysHint': '본문이 실제로 실행되는 필드(workflowYaml 등)를 위한 통로입니다. 텍스트가 블랙리스트와 자격증물 스크린에 들어가며 위 표와 같은 키를 지정하면 이쪽이 이깁니다. 대가: 진짜 문서 필드를 지정하면 『계획에 rm -rf 가 적혀 있다』는 다시 거부 이유가 됩니다.',\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.llmEffort': '추론 강도 (host 모드 전용)',\n 'card.llmEffortHost': '호스트 기본값 따름',\n 'card.llmEffortHint': '비움 = 지정하지 않고 호스트 모델 설정을 따름. 호스트가 거부하면 low 나 off 로 변경.',\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 'doubt.no-rule': '이 호출을 작용하는 규칙이 없어 기본 전략으로 사람에게 양도합니다 — 위험하다는 의미가 아닙니다',\n 'doubt.opaque': '페이로드를 읽을 수 없음 (인코딩됨 / 작업 공간 밖 스크립트 / 프로그램명 불명) → 규칙이 대상을 특정할 수 없음',\n 'doubt.irreversible': '규칙상 불가역: 실행 후 채취 불가',\n 'doubt.never-learn': '이 승인은 학습되지 않습니다. 다음에도 같은 확인이 나옵니다',\n 'doubt.delete': '내용을 삭제합니다',\n 'doubt.remote-write': '외부에 보이는 변경(push / publish / 쓰기 요청)이 발생하며, 취소하려면 수동 작업이 필요합니다',\n 'doubt.exec-external': '작업 공간 밖의 코드를 실행합니다. 이 호출에서는 내용을 확인할 수 없습니다',\n 'doubt.outside-paths': '작업 공간 밖 경로에 접촉합니다',\n 'doubt.model-flagged': '위험 모델이 의심됨 (증액만 가능, 해소 불가)',\n 'doubt.write': '파일을 쓰거나 수정합니다',\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.unattended': 'Modes sans supervision (trois implémentations ; chaque interrupteur décide si son palier existe)',\n 'card.unattendedHint': 'Trois interrupteurs, chacun ne régit que le palier nommé à côté : éteindre une implémentation rend ce palier au flux humain ordinaire — il ne devient jamais un autre palier en secret.',\n 'card.mode.ask': 'Garder l\\'humain',\n 'card.mode.pass': 'Passage mécanique',\n 'card.askHint': 'Le tamis mécanique filtre toujours et expose ses doutes, mais la demande reste soumise à une personne et aucun évaluateur n\\'est appelé — la forme qui convient quand aucun LLM relecteur n\\'est branché, ou quand les jetons ne valent pas la dépense.',\n 'card.passHint': 'N\\'exécute que le juge mécanique déterministe : une opération irréversible, irrécupérable ou illisible est bloquée et justifiée en retour au modèle principal, le reste s\\'exécute. Aucun appel de modèle, aucune demande humaine — la version examinée de approval: never, et le YOLO privé de son modèle.',\n 'card.tierScopeHint': 'Seuls les préréglages compris dans le périmètre du garde (%scope) atteignent cette étape ; en dehors, le garde s\\'efface complètement et aucun interrupteur ne prend ses confirmations en charge.',\n 'card.yolo': 'YOLO — ne jamais demander un humain : bloquer le dangereux, exécuter le reste',\n 'card.yoloExempt': 'YOLO : autoriser aussi « lieu inconnu » dans l’espace de travail',\n 'card.yoloExemptHint': 'Mode YOLO uniquement. Activé, un appel dont seule la « localisation » est indéterminable (outil sans argument, script hors de l’espace de travail dont le corps n’a pas été lu) n’est plus bloqué comme « invisible ». Les charges encodées, les corps illisibles, les suppressions et les écritures distantes restent bloqués ; P0, identifiants et irréversible ne changent jamais.',\n 'card.yoloHint': 'Bloque une charge irréversible / inapprenable / illisible, ou un verdict à risque dur du modèle, et renvoie la raison au LLM principal dans un message 工具审核意见 ; tout le reste s\\'exécute. Sans modèle disponible, seules les filets déterministes bloquent.',\n 'card.rulesFallback': 'Dégrader vers une porte à règles quand il n\\'y a pas de modèle (classe cc-safety-net)',\n 'card.rulesFallbackHint': 'Ne s\\'applique que lorsque le relecteur de risque n\\'est pas configuré ou n\\'a pas rendu de verdict : les filets déterministes bloquent ce qu\\'ils peuvent nommer et laissent passer le reste, au lieu de immobiliser l\\'appel sur une popup que personne ne répondra. Tant qu\\'un relecteur répond, le comportement est inchangé.',\n 'card.allowProtectedBranchPush': 'Autoriser le force-push sur les branches protégées (par défaut inactif = plancher maintenu)',\n 'card.allowProtectedBranchPushHint': 'Par défaut, le plancher P0 bloque git push --force/--force-with-lease/--delete visant main/master/production/release/stable (non rétrogradable par un modèle). L\\'activer écarte le plancher et exempte les trois mots-clés push de la liste noire ; l\\'appel retombe sur la règle git.push-force intégrée, qui demande toujours un humain sauf si vous révoquez cette entrée ou l\\'ajoutez en allowlist. Rien d\\'autre ne s\\'élargit : suppressions, redirections et le plancher d\\'identifiants restent armés.',\n 'card.credFamily': 'Escalier des familles de secrets',\n 'card.credFamilyHint': 'Un cran par famille : deny = lectures et écritures bloquées ; ask = lecture avec validation humaine (défaut) ; readonly = lectures libres, écritures toujours refusées par le plancher P0 ; readwrite = la clause d\\u0027écriture du store de credentials se retire pour cette famille (cas npm login). Les autres planchers (racines, chemins protégés, .dsh, exfiltration) restent armés à tout cran. L\\u0027état vit dans la ligne du document de règles plus la liste d\\u0027exemption ; la carte écrit les deux ensemble.',\n 'card.credFamilyLoading': 'Chargement des crans…',\n 'card.credFamilyFootnote': 'Les paliers sans humain (passage mécanique / YOLO) laissent passer le reliquat des ask — choisir deny pour bloquer. Les credentialPaths personnalisés ne bénéficient jamais de l\\u0027exemption d\\u0027écriture.',\n 'card.credReadwriteConfirm': 'readwrite autorise l\\u0027écriture/modification des fichiers de secrets de cette famille (réécriture de ~/.npmrc). Seul cran qui écarte une part du P0. Confirmer ?',\n 'card.credConfirmYes': 'Confirmer',\n 'card.credConfirmNo': 'Annuler',\n 'card.credRung.deny': 'bloquer',\n 'card.credRung.ask': 'demander',\n 'card.credRung.readonly': 'lecture seule',\n 'card.credRung.readwrite': 'lecture écriture',\n 'card.scriptReview': 'Joindre le contenu des scripts à la revue (activé par défaut)',\n 'card.scriptReviewHint': 'Quand un appel exécute un fichier script, son corps est lu et donné au modèle de risque comme à l\\'humain, et les filets déterministes évaluent aussi ce corps (une suppression invisible dans le nom de fichier est précisément ce qui passait). Le corps est masqué et borné avant sortie ; le désactiver garde le contenu des fichiers en local, au prix de renvoyer les scripts hors espace de travail dans le palier « illisible ».',\n 'card.credentialPaths': 'Chemins de credentials personnalisés (la longue traîne)',\n 'card.credentialPathsHint': 'Des fichiers secrets que la liste intégrée ne connaît pas. Les entrées sont des globs de chemin : une double étoile traverse les répertoires, une étoile simple et un point d\\'interrogation restent dans un segment ; sans joker, la correspondance se fait sur un fragment de chemin entier (token ne touchera pas ambient.txt) ; un ~/ initial se développe vers votre home ; un motif relatif correspond aussi à n\\'importe quelle profondeur (secrets/*.env couvre a/b/secrets/prod.env). Une correspondance est tenue au même standard que .ssh : la lecture hors espace de travail et la mutation par un outil de fichier sont refusées durablement — ce niveau n\\'est ni contestable ni franchissable par le relecteur, ne déclarez donc que les paths à protéger vraiment.',\n 'card.credentialPathsPlaceholder': 'Nouveau chemin, ex. ~/.myco/vault.token ou secrets/*.env',\n 'card.denyKeywordsExtra': 'Mots-clés blacklist ajoutés (ne remplace pas le prédéfini)',\n 'card.denyKeywordsExtraHint': 'Un blocage déterministe sur vos propres termes — une sous-commande de révocation d\\'un CLI interne, un préfixe de jeton qui vous est propre. Cette liste n\\'ajoute que des termes : quel que soit le contenu de la blacklist au-dessus (prédéfinie ou remplacée par vous), ces mots sont fusionnés.',\n 'card.listRemove': 'Retirer cette entrée',\n 'card.extraContentArgKeys': 'Clés de document ajoutées (jamais lues comme une opération)',\n 'card.extraContentArgKeysHint': 'Des noms de champs documentaires absents de la liste intégrée (content/text/plan…) : une fois déclarés, leur texte ne participe plus à la lecture à plat des mots dangereux et des formes d\\'identifiants. Purement additif : la liste intégrée ne peut pas être remplacée, car oublier une de ses clés ferait reparaître en silence le bug où un plan est refusé pour décrire une action. La commande réellement exécutée et le chemin modifié jugés par leurs propres voies, cette liste ne peut pas les éteindre.',\n 'card.extraContentArgKeysPlaceholder': 'Nouveau nom d\\'argument, ex. steps',\n 'card.extraOperationArgKeys': 'Clés d\\'opération ajoutées (lire ce champ comme du code exécuté)',\n 'card.extraOperationArgKeysHint': 'Un passage pour les champs dont le corps est réellement exécuté (workflowYaml etc.) : leur texte entre dans la blacklist et l\\'écran d\\'identifiants, et cette liste gagne en cas de doublon. Coût : désigner un vrai champ documentaire rend de nouveau « le plan mentionne rm -rf » motif de refus.',\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.llmEffort': 'Effort de raisonnement (mode host)',\n 'card.llmEffortHost': 'Suivre l’hôte',\n 'card.llmEffortHint': 'Vide = ne rien imposer, la config du modèle hôte décide ; passer à low ou off si l’hôte refuse.',\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 'doubt.no-rule': 'aucune règle ne couvre cet appel, le défaut est de demander — cela ne signifie pas qu’il est dangereux',\n 'doubt.opaque': 'le payload est illisible (encodé, script hors workspace, ou programme non reconnu), aucune règle ne peut localiser sa cible',\n 'doubt.irreversible': 'règle irréversible : après exécution, annulation impossible',\n 'doubt.never-learn': 'cette réponse ne sera pas mémorisée ; la même question se reposera',\n 'doubt.delete': 'supprime du contenu',\n 'doubt.remote-write': 'effet visible de l’extérieur (push / publish / écriture) ; annuler nécessite des étapes manuelles',\n 'doubt.exec-external': 'exécute du code hors workspace, non inspectable par cet appel',\n 'doubt.outside-paths': 'accède à des chemins hors workspace',\n 'doubt.model-flagged': 'le modèle de risque l’a signalé (il peut uniquement escalader, jamais lever)',\n 'doubt.write': 'écrit ou modifie des fichiers',\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.unattended': 'Unbeaufsichtigte Stufen (drei Implementierungen; jeder Schalter entscheidet, ob seine Stufe existiert)',\n 'card.unattendedHint': 'Drei Schalter, jeder steuert nur die Stufe daneben: wer die Implementierung abschaltet, lässt diese Stufe zum normalen Menschenablauf zurückkehren — sie wird nie stillschweigend zu einer anderen.',\n 'card.mode.ask': 'Mensch behalten',\n 'card.mode.pass': 'Mechanischer Durchlass',\n 'card.askHint': 'Die mechanische Vorprüfung filtert und nennt ihre Zweifel, aber die Anfrage bleibt bei einem Menschen, und das Bewertungsmodell wird kein einziges Mal aufgerufen — die Form für Läufe ohne verbundenen Reviewer-LLM oder wenn sich die Tokens nicht lohnen.',\n 'card.passHint': 'Lässt nur den deterministischen mechanischen Prüfer laufen: eine irreversible, nicht rücknehmbare oder unlesbare Anfrage wird blockt und dem Hauptmodell begründet zurückgemeldet, alles andere läuft. Kein Modellaufruf, keine Frage an einen Menschen — die geprüfte Form von approval: never und YOLO ohne Modell.',\n 'card.tierScopeHint': 'Nur Presets innerhalb des Gate-Umfangs (%scope) erreichen diesen Schritt; außerhalb davon schaltet sich das Gate komplett ab, kein Schalter übernimmt dann dessen Bestätigungen.',\n 'card.yolo': 'YOLO — niemals einen Menschen fragen: nur Gefährliches blockieren, Rest ausführen',\n 'card.yoloExempt': 'YOLO: auch „Ort unbekannt“ im Arbeitsbereich zulassen',\n 'card.yoloExemptHint': 'Nur YOLO. Aktiviert wird ein Aufruf, bei dem nur der „Ort“ unbestimmbar ist (Werkzeug ohne Argumente, Skript außerhalb des Arbeitsbereichs ohne gelesenen Rumpf), nicht mehr als „unsichtbar“ blockiert. Kodierte Nutzlasten, unlesbare Skriptrümpfe, Löschungen und Remote-Schreibvorgänge bleiben blockiert; P0, Anmeldedaten und Unwiederbringliches ändern sich nie.',\n 'card.yoloHint': 'Blockiert eine unwiderrufliche / nicht lernbare / unlesbare Last oder ein Hartrisiko-Urteil des Modells und meldet den Grund dem Haupt-LLM als 工具审核意见-Nachricht; alles andere läuft. Ohne erreichbares Review-Modell fangen nur die deterministischen Netze.',\n 'card.rulesFallback': 'Ohne Modell zu einem Regel-Gate degradieren (cc-safety-net-Klasse)',\n 'card.rulesFallbackHint': 'Greift nur, wenn das Review-Modell nicht konfiguriert ist oder kein Urteil geliefert hat: die deterministischen Netze blockieren, was sie benennen können, und lassen den Rest durch, statt den Aufruf in einem Popup warten zu lassen, das niemand beantwortet. Solange ein Modell antwortet, bleibt das Verhalten unverändert.',\n 'card.allowProtectedBranchPush': 'Force-Push auf geschützte Branches erlauben (Standard aus = Boden bleibt)',\n 'card.allowProtectedBranchPushHint': 'Standardmäßig blockiert der P0-Boden git push --force/--force-with-lease/--delete auf main/master/production/release/stable (per Modell nicht herabstufbar). Beim Einschalten weicht der Boden und die drei flachen push-Schlüsselwörter der Blacklist werden ausgenommen; der Aufruf fällt auf die eingepasste Regel git.push-force, die weiterhin eine Person fragt — solange Sie den Eintrag nicht widerrufen oder auf die Allowlist setzen. Nichts anderes weitet sich: Löschen, Redirects und der Credential-Boden bleiben scharf.',\n 'card.credFamily': 'Credential-Familien-Stufenleiter',\n 'card.credFamilyHint': 'Eine Stufe pro Familie: deny = Lesen und Schreiben blockiert; ask = Lesen mit Bestätigung (Standard); readonly = Lesen frei, Schreiben bleibt P0-hart blockiert; readwrite = die Credential-Store-Schreibklausel weicht für diese Familie (npm-login-Fall). Alle anderen Böden (Roots, geschützte Pfade, .dsh, Exfiltration) bleiben in jeder Stufe scharf. Der Zustand lebt in der Regelzeile plus der Schreibausnahme-Liste; diese Karte schreibt beide gepaart zurück.',\n 'card.credFamilyLoading': 'Stufen werden geladen…',\n 'card.credFamilyFootnote': 'Unbeaufsichtigte Stufen (mechanischer Durchlass / YOLO) lassen ask-Reste durch — für harte Blockierung deny wählen. Eigene credentialPaths nehmen nie an der Schreibausnahme teil.',\n 'card.credReadwriteConfirm': 'readwrite erlaubt Schreiben/Ändern der Credential-Datei dieser Familie (z. B. ~/.npmrc überschreiben). Die einzige Stufe, die einen Teil von P0 zurücktritt. Bestätigen?',\n 'card.credConfirmYes': 'Bestätigen',\n 'card.credConfirmNo': 'Abbrechen',\n 'card.credRung.deny': 'blockieren',\n 'card.credRung.ask': 'fragen',\n 'card.credRung.readonly': 'nur Lesen',\n 'card.credRung.readwrite': 'Lesen+Schreiben',\n 'card.scriptReview': 'Skriptinhalte der Prüfung beifügen (standardmäßig an)',\n 'card.scriptReviewHint': 'Führt ein Aufruf eine Skriptdatei aus, wird ihr Inhalt gelesen und dem Risikomodell wie dem Menschen gezeigt, und die deterministischen Netze bewerten ebenfalls den Inhalt (ein Löschen, das nur in der Datei sichtbar ist, war genau das, was durchrutschte). Inhalte werden vor dem Verlassen des Rechners maskiert und begrenzt; abschalten hält Dateiinhalte lokal, kostet aber, dass Skripte außerhalb des Arbeitsbereichs wieder als „unlesbar“ gelten.',\n 'card.credentialPaths': 'Eigene Credential-Pfade (der lange Schwanz)',\n 'card.credentialPathsHint': 'Geheime Dateien, die die eingebaute Liste nicht kennt. Einträge sind Pfad-Globs: ein Doppelstern überquert Verzeichnisse, ein Einzelstern und ein Fragezeichen bleiben in einem Segment; ohne Joker wird über ein ganzes Pfadfragment verglichen (token trifft nicht ambient.txt); ein führendes ~/ wird zu Ihrem Home aufgelöst; ein relativer Muster passt auch in jeder Tiefe (secrets/*.env deckt a/b/secrets/prod.env ab). Ein Treffer gilt nach demselben Maßstab wie .ssh: Lesen außerhalb des Arbeitsbereichs und Ändern durch ein Dateiwerkzeug werden hart abgelehnt — diese Stufe ist weder anfechtbar noch vom Prüfer umgehbar, erklären Sie also nur Pfade, die wirklich geschützt müssen werden.',\n 'card.credentialPathsPlaceholder': 'Neuer Pfad, z. B. ~/.myco/vault.token oder secrets/*.env',\n 'card.denyKeywordsExtra': 'Zusätzliche Blacklist-Schlüsselwörter (ersetzt den Voreinstellung nicht)',\n 'card.denyKeywordsExtraHint': 'Eine deterministische Blockierung für Ihre eigenen Begriffe — ein Sperr-/Lösch-Unterbefehl einer firmeneigenen CLI, ein von Ihnen ausgegebener Token-Präfix. Diese Liste fügt nur hinzu: was die Blacklist oben enthält (Voreinstellung oder eigene Ersetzung), diese Wörter werden übernommen.',\n 'card.listRemove': 'Diesen Eintrag entfernen',\n 'card.extraContentArgKeys': 'Zusätzliche Dokument-Schlüssel (nicht als Operation gelesen)',\n 'card.extraContentArgKeysHint': 'Feldnamen außerhalb der eingebauten Liste (content/text/plan…): gelistet, gelangt ihr Text nicht mehr in das flache Lesen von Gefahrwörtern und Credential-Formen. Nur ergänzend — die eingebaute Liste ist nicht ersetzbar, denn ein fehlender Schlüssel würde den Fehler leise zurückbringen, dass ein Plan für das bloße Beschreiben einer Arbeit abgelehnt wird. Das tatsächlich ausgeführte Kommando und der geänderte Pfad werden auf eigenen Wegen geprüft; diese Liste kann sie nicht abschalten.',\n 'card.extraContentArgKeysPlaceholder': 'Neuer Argumentname, z. B. steps',\n 'card.extraOperationArgKeys': 'Zusätzliche Operations-Schlüssel (Feld als ausgeführten Code lesen)',\n 'card.extraOperationArgKeysHint': 'Ein Weg für Felder, deren Inhalt wirklich ausgeführt wird (workflowYaml u. ä.): ihr Text erreicht Blacklist und Credential-Prüfung, und bei Namensgleichheit gewinnt diese Liste. Preis: ein echtes Dokumentfeld hier einzutragen macht „der Plan erwähnt rm -rf\" wieder zum Ablehnungsgrund.',\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.llmEffort': 'Reasoning-Aufwand (nur Host-Modus)',\n 'card.llmEffortHost': 'Host-Standard folgen',\n 'card.llmEffortHint': 'Leer = nichts vorgeben, die Host-Modellkonfiguration entscheidet; auf low oder off wechseln, wenn der Host es ablehnt.',\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 'doubt.no-rule': 'keine Regel deckt diesen Aufruf ab, daher wird standardmäßig gefragt — das bedeutet nicht, dass er gefährlich ist',\n 'doubt.opaque': 'der Payload ist nicht lesbar (kodiert, Script außerhalb des Workspace, oder kein erkennbares Programm), keine Regel kann das Ziel bestimmen',\n 'doubt.irreversible': 'Regel besagt: irreversibel — nach der Ausführung nicht mehr rückgängig',\n 'doubt.never-learn': 'diese Antwort wird nicht gelernt; dieselbe Frage wird erneut gestellt',\n 'doubt.delete': 'es löscht Inhalte',\n 'doubt.remote-write': 'extern sichtbare Wirkung (push / publish / Schreib-Request); Rückgängig machen erfordert manuelle Schritte',\n 'doubt.exec-external': 'führt Code außerhalb des Workspaces aus, nicht überprüfbar durch diesen Aufruf',\n 'doubt.outside-paths': 'berührt Pfade außerhalb des Workspaces',\n 'doubt.model-flagged': 'das Risikomodell hat es markiert (nur Eskalation möglich, keine Freigabe)',\n 'doubt.write': 'schreibt oder ändert Dateien',\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.unattended': 'Modalità senza supervisione (tre implementazioni; ogni interruttore decide se il proprio livello esiste)',\n 'card.unattendedHint': 'Tre interruttori, ciascuno governa solo il livello scritto accanto: spegnere un\\'implementazione fa tornare quel livello al flusso umano ordinario, senza che diventi di nascosto un altro.',\n 'card.mode.ask': 'Mantieni umano',\n 'card.mode.pass': 'Passaggio meccanico',\n 'card.askHint': 'La selezione meccanica filtra ed elenca i dubbi, ma la richiesta resta a una persona e il modello revisore non viene chiamato nemmeno una volta — la forma adatta quando nessun LLM revisore è collegato o quando i token non valgono la spesa.',\n 'card.passHint': 'Esegue solo il giudice meccanico deterministico: un\\'operazione irreversibile, irrecuperabile o illeggibile viene bloccata e motivata al modello principale, il resto esegue. Nessuna chiamata al modello, nessuna richiesta umana: la forma esaminata di approval: never, e YOLO privato del modello.',\n 'card.tierScopeHint': 'Solo i preset dentro l\\'ambito del gate (%scope) arrivano a questo passo; fuori dall\\'ambito il gate si disattiva del tutto e nessun interruttore prende in carico le sue conferme.',\n 'card.yolo': 'YOLO — non chiedere mai un umano: blocca il pericoloso, esegui il resto',\n 'card.yoloExempt': 'YOLO: consenti anche “posizione sconosciuta” nel workspace',\n 'card.yoloExemptHint': 'Solo YOLO. Se attivo, una chiamata di cui è indeterminabile solo la “posizione” (strumento senza argomenti, script fuori dal workspace il cui corpo non è stato letto) non viene più bloccata come “invisibile”. Payload codificati, corpi illeggibili, eliminazioni e scritture remote restano bloccati; P0, credenziali e operazioni irreversibili non cambiano mai.',\n 'card.yoloHint': 'Blocca un carico irreversibile / non apprendibile / illeggibile, o un verdetto a rischio duro del modello, e restituisce il motivo al LLM principale come messaggio 工具审核意见; tutto il resto viene eseguito. Senza un modello disponibile, solo le reti deterministiche intercettano.',\n 'card.rulesFallback': 'Degradare a una porta a regole quando non c’è modello (classe cc-safety-net)',\n 'card.rulesFallbackHint': 'Agisce solo quando il revisore di rischio non è configurato o non ha dato un verdetto: le reti deterministiche bloccano ciò che sanno nominare e lasciano passare il resto, invece di parcheggiare la chiamata su un popup che nessuno risponderà. Finché un modello risponde, il comportamento resta invariato.',\n 'card.allowProtectedBranchPush': 'Consenti force-push su branch protetti (default off = pavimento attivo)',\n 'card.allowProtectedBranchPushHint': 'Di default il pavimento P0 blocca git push --force/--force-with-lease/--delete verso main/master/production/release/stable (non declassabile dal modello). Attivandolo il pavimento si fa da parte e le tre parole push piatte della blacklist vengono escluse; la chiamata ricade nella regola git.push-force predefinita, che chiede comunque una persona finché non revochi la voce o la aggiungi all\\'allowlist. Nient\\'altro si allarga: cancellazioni, redirect e il pavimento credenziali restano armati.',\n 'card.credFamily': 'Gradini delle famiglie di credenziali',\n 'card.credFamilyHint': 'Un gradino per famiglia: deny = lettura e scrittura bloccate; ask = lettura con conferma umana (predefinito); readonly = lettura libera, scrittura ancora bloccata dal pavimento P0; readwrite = la clausola di scrittura del credential store si ritira per questa famiglia (caso npm login). Gli altri pavimenti (root, percorsi protetti, .dsh, esfiltrazione) restano armati a ogni gradino. Lo stato vive nella riga del documento regole più la lista di esenzione; questa scheda scrive entrambe insieme.',\n 'card.credFamilyLoading': 'Caricamento gradini…',\n 'card.credFamilyFootnote': 'I livelli senza umano (passaggio meccanico / YOLO) lasciano passare il residuo degli ask — scegliere deny per bloccare. I credentialPaths personalizzati non partecipano mai all\\u0027esenzione di scrittura.',\n 'card.credReadwriteConfirm': 'readwrite consente di scrivere/modificare i file di credenziali di questa famiglia (sovrascrittura di ~/.npmrc). È l’unico gradino che ritira parte del P0. Confermare?',\n 'card.credConfirmYes': 'Conferma',\n 'card.credConfirmNo': 'Annulla',\n 'card.credRung.deny': 'blocca',\n 'card.credRung.ask': 'chiedi',\n 'card.credRung.readonly': 'sola lettura',\n 'card.credRung.readwrite': 'lettura scrittura',\n 'card.scriptReview': 'Allega il contenuto degli script alla revisione (attivo per impostazione predefinita)',\n 'card.scriptReviewHint': 'Quando una chiamata esegue uno script, il suo corpo viene letto e mostrato al modello di rischio come all’umano, e le reti deterministiche valutano anch’esse il corpo (un’eliminazione visibile solo dentro il file è esattamente ciò che passava). I corpi sono oscurati e limitati prima di lasciare l’host; disattivarli tiene il contenuto dei file in locale, al prezzo di rimandare gli script fuori dal workspace nel livello «illeggibile».',\n 'card.credentialPaths': 'Percorsi di credenziali personalizzati (la coda lunga)',\n 'card.credentialPathsHint': 'File segreti che l’elenco integrato non conosce. Le voci sono glob di percorso: un doppio asterisco attraversa le directory, un asterisco semplice e un punto di domanda restano dentro un segmento; senza jolly si confronta un frammento di percorso intero (token non colpisce ambient.txt); un ~/ iniziale si espande nella tua home; un modello relativo corrisponde anche a qualsiasi profondità (secrets/*.env copre a/b/secrets/prod.env). Una corrispondenza è trattata allo stesso livello di .ssh: la lettura fuori dal workspace e la modifica tramite strumento di file sono rifiutate in modo duro — questo livello non è appellabile né aggirabile dal revisore, dichiara solo percorsi che devi davvero proteggere.',\n 'card.credentialPathsPlaceholder': 'Nuovo percorso, es. ~/.myco/vault.token o secrets/*.env',\n 'card.denyKeywordsExtra': 'Parole chiave blacklist aggiunte (non sostituiscono il preset)',\n 'card.denyKeywordsExtraHint': 'Un blocco deterministico per termini tuoi — un sottocomando di revoca/cancellazione di una CLI aziendale, un prefisso di token che emetti. Questa lista aggiunge soltanto: qualunque cosa contenga la blacklist sopra (preset o tua sostituzione), queste parole vengono unite.',\n 'card.listRemove': 'Rimuovi questa voce',\n 'card.extraContentArgKeys': 'Chiavi documento aggiunte (mai lette come operazione)',\n 'card.extraContentArgKeysHint': 'Nomi di campi documentali fuori dall’elenco integrato (content/text/plan…): una volta dichiarati, il loro testo non entra più nella scansione piatta di parole pericolose e forme di credenziali. Solo in aggiunta: l’elenco integrato non è sostituibile, perché dimenticare una chiave riporterebbe in silenzio il bug per cui un piano viene rifiutato per aver descritto un’azione. Il comando effettivamente eseguito e il percorso modificato sono giudicati sui propri binari; questo elenco non può disattivarli.',\n 'card.extraContentArgKeysPlaceholder': 'Nuovo nome argomento, es. steps',\n 'card.extraOperationArgKeys': 'Chiavi operazione aggiunte (leggi il campo come codice eseguito)',\n 'card.extraOperationArgKeysHint': 'Un passaggio per i campi il cui corpo è davvero eseguito (workflowYaml e simili): il testo raggiunge blacklist e controllo credenziali, e in caso di omonimia questo elenco vince. Costo: indicare un campo documentale reale rende di nuovo «il piano menziona rm -rf» un motivo di rifiuto.',\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.llmEffort': 'Sforzo di ragionamento (solo modalità host)',\n 'card.llmEffortHost': 'Segui l’host',\n 'card.llmEffortHint': 'Vuoto = non imporre nulla, decide la configurazione del modello host; passa a low o off se l’host lo rifiuta.',\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 'doubt.no-rule': 'nessuna regola copre questa chiamata, la scelta predefinita è chiedere — non significa che sia pericolosa',\n 'doubt.opaque': 'il payload non è leggibile (codificato, script fuori dal workspace, o programma non riconosciuto), nessuna regola può individuare il bersaglio',\n 'doubt.irreversible': 'regola irreversibile: dopo l’esecuzione non si può annullare',\n 'doubt.never-learn': 'questa risposta non verrà imparata; la stessa domanda si ripresenterà',\n 'doubt.delete': 'elimina contenuto',\n 'doubt.remote-write': 'effetto visibile all’esterno (push / publish / richiesta di scrittura); annullare richiede intervento manuale',\n 'doubt.exec-external': 'esegue codice fuori dal workspace, non ispezionabile da questa chiamata',\n 'doubt.outside-paths': 'tocca percorsi fuori dal workspace',\n 'doubt.model-flagged': 'il modello di rischio lo ha segnalato (può solo elevare, non autorizzare)',\n 'doubt.write': 'scrive o modifica file',\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.unattended': 'Режимы без подтверждения человеком (три реализации; каждый переключатель решает, существует ли его уровень)',\n 'card.unattendedHint': 'Переключателя три, каждый управляет только тем уровнем, что написан рядом: выключить реализацию — значит вернуть этот уровень обычному человеческому потоку; тайно стать другим он не может.',\n 'card.mode.ask': 'Оставить человека',\n 'card.mode.pass': 'Механический пропуск',\n 'card.askHint': 'Механический отбор фильтрует и перечисляет сомнения, но запрос остаётся человеку, а модель-ревизор не вызывается ни разу — это форма для запусков без подключённого LLM-ревизора или когда токены не стоят затрат.',\n 'card.passHint': 'Работает только детерминированный механический судья: необратимое, невосстановимое или нечитаемое действие блокируется с причиной обратно основной модели, остальное выполняется. Ни вызова модели, ни вопроса человеку — проверенная форма approval: never и YOLO без модели.',\n 'card.tierScopeHint': 'До этого шага доходят только пресеты внутри области гейта (%scope); вне области гейт отключается целиком, и ни один переключатель не берёт его подтверждения на себя.',\n 'card.yolo': 'YOLO — никогда не спрашивать человека: блокировать опасное, остальное выполнять',\n 'card.yoloExempt': 'YOLO: разрешить и «неизвестное расположение» внутри рабочей области',\n 'card.yoloExemptHint': 'Только для YOLO. Если включено, вызов, у которого неопределимо только «расположение» (инструмент без аргументов, скрипт вне рабочей области, тело которого не прочитано), больше не блокируется как «невидимый». Кодированные полезные нагрузки, нечитаемые тела скриптов, удаления и удалённые записи по-прежнему блокируются; P0, учётные данные и необратимые действия не меняются никогда.',\n 'card.yoloHint': 'Блокирует необратимую / необучаемую / неразбираемую нагрузку или жёсткий вердикт модели и возвращает причину основной LLM сообщением 工具审核意见; остальное выполняется. Когда доступной модели нет, срабатывают только детерминированные сети.',\n 'card.rulesFallback': 'Деградировать в шлюз по правилам, когда модели нет (класс cc-safety-net)',\n 'card.rulesFallbackHint': 'Действует только когда проверяющая модель не настроена или не дала вердикта: детерминированные сети блокируют то, что могут назвать, и пропускают остальное, вместо того чтобы вешать вызов на окно, которое никто не ответит. Пока модель отвечает, поведение не меняется.',\n 'card.allowProtectedBranchPush': 'Разрешить force-push в защищённые ветки (по умолчанию выкл = пол стоит)',\n 'card.allowProtectedBranchPushHint': 'По умолчанию пол P0 блокирует git push --force/--force-with-lease/--delete в main/master/production/release/stable (модель не может понизить). При включении пол отступает и три плоских push-ключа из чёрного списка освобождаются; вызов попадает в правило git.push-force, которое всё равно спрашивает человека, пока вы не отзовете запись или не добавите его в allowlist. Ничего другое не расширяется: удаления, редиректы и пол учётных данных остаются взведены.',\n 'card.credFamily': 'Ступени семей учётных данных',\n 'card.credFamilyHint': 'Одна ступень на семейство: deny = блокирует чтение и запись; ask = чтение с подтверждением человека (по умолчанию); readonly = чтение свободно, запись по-прежнему твёрдо блокируется полом P0; readwrite = клауза записи credential-store отступает для этого семейства (случай npm login). Остальные полы (корни, защищённые пути, .dsh, эксфильтрация) взведены на любой ступени. Состояние живёт в строке документа правил и в списке изъятий записи; карта пишет оба вместе.',\n 'card.credFamilyLoading': 'Загрузка ступеней…',\n 'card.credFamilyFootnote': 'Безчеловечные уровни (механический пропуск / YOLO) пропускают остаток ask — для жёсткой блокировки выберите deny. Свои credentialPaths никогда не участвуют в изъятии записи.',\n 'card.credReadwriteConfirm': 'readwrite разрешает запись/изменение файлов учётных данных этого семейства (перезапись ~/.npmrc). Единственная ступень, отступающая часть P0. Подтвердить?',\n 'card.credConfirmYes': 'Подтвердить',\n 'card.credConfirmNo': 'Отмена',\n 'card.credRung.deny': 'блок',\n 'card.credRung.ask': 'спрос',\n 'card.credRung.readonly': 'только чтение',\n 'card.credRung.readwrite': 'чтение запись',\n 'card.scriptReview': 'Прилагать содержимое скриптов к проверке (по умолчанию включено)',\n 'card.scriptReviewHint': 'Когда вызов запускает скрипт-файл, его тело читается и даётся модели риска и человеку, и детерминированные сети тоже оценивают тело (удаление, видимое только внутри файла, — ровно то, что пропускалось). Тела маскируются и ограничиваются по длине до отправки; отключение оставляет содержимое файлов локально, ценой возврата скриптов вне рабочей области в уровень «неразбираемо».',\n 'card.credentialPaths': 'Свои пути к учётным данным (длинный хвост)',\n 'card.credentialPathsHint': 'Секретные файлы, которых нет во встроенном списке. Записи — это глобы путей: двойная звёздочка переходит между каталогами, одиночная звёздочка и вопросительный знак остаются внутри одного сегмента; без маска-символов совпадение идёт по целому фрагменту пути (token не попадёт в ambient.txt); ведущий ~/ раскрывается в ваш home; относительный шаблон совпадает и на любой глубине (secrets/*.env покрывает a/b/secrets/prod.env). Совпадение держится по тому же стандарту, что и .ssh: чтение вне рабочей области и изменение файловым инструментом жёстко отклоняются — этот уровень нельзя оспорить и не обходят проверяющей моделью, поэтому объявляйте только те пути, которые действительно нужно защитить.',\n 'card.credentialPathsPlaceholder': 'Новый путь, напр. ~/.myco/vault.token или secrets/*.env',\n 'card.denyKeywordsExtra': 'Добавляемые ключевые слова чёрного списка (не заменяют пресет)',\n 'card.denyKeywordsExtraHint': 'Детерминированная блокировка для ваших собственных терминов — подкоманда отзыва/стирания внутреннего CLI, префикс выдаваемого вами токена. Этот список только добавляет: что бы ни содержал чёрный список выше (пресет или ваша замена), эти слова сливаются с ним.',\n 'card.listRemove': 'Удалить эту запись',\n 'card.extraContentArgKeys': 'Дополнительные ключи документов (не читаются как операция)',\n 'card.extraContentArgKeysHint': 'Имена полей вне встроенного списка (content/text/plan…): после добавления их текст не попадает в плоское чтение опасных слов и форм учётных данных. Только дополняет — встроенный список не заменяется, потому что пропуск одного из его ключей молча вернёт баг, когда план отклоняют за само описание работы. Реально выполняемая команда и изменяемый путь проверяются своими путями; этот список их не отключает.',\n 'card.extraContentArgKeysPlaceholder': 'Новое имя аргумента, напр. steps',\n 'card.extraOperationArgKeys': 'Дополнительные ключи операций (читать поле как исполняемый код)',\n 'card.extraOperationArgKeysHint': 'Канал для полей, чьё тело действительно исполняется (workflowYaml и т. п.): их текст попадает в чёрный список и проверку учётных данных, и при совпадении ключа выигрывает этот список. Цена: вписав сюда настоящий документ, вы снова делаете «в плане упоминается rm -rf» причиной отказа.',\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.llmEffort': 'Усилие рассуждения (только режим host)',\n 'card.llmEffortHost': 'Как у хоста',\n 'card.llmEffortHint': 'Пусто = не навязывать, решает конфигурация модели хоста; выберите low или off, если хост отклоняет.',\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 'doubt.no-rule': 'ни одно правило не покрывает этот вызов, по умолчанию спрашивается человек — это не значит что он опасен',\n 'doubt.opaque': 'нагрузка не читается (закодирована, скрипт за пределами рабочей зоны, или не распознаётся программа), правило не может определить цель',\n 'doubt.irreversible': 'правило: необратимо, отменить после выполнения нельзя',\n 'doubt.never-learn': 'это решение не запомнится, тот же вызов спросит снова',\n 'doubt.delete': 'удаляет данные',\n 'doubt.remote-write': 'видимый снаружи эффект (push / publish / запись); отмена требует ручных действий',\n 'doubt.exec-external': 'выполняет код за пределами рабочего пространства, не подлежит инспекции',\n 'doubt.outside-paths': 'затрагивает пути вне рабочего пространства',\n 'doubt.model-flagged': 'модель риска пометила (только усиливает, не снижает)',\n 'doubt.write': 'записывает или изменяет файлы',\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.unattended': 'Modos sin supervisión (tres implementaciones; cada interruptor decide si su nivel existe)',\n 'card.unattendedHint': 'Tres interruptores, cada uno gobierna solo el nivel escrito a su lado: apagar una implementación devuelve ese nivel al flujo humano ordinario, sin convertirse a escondidas en otro.',\n 'card.mode.ask': 'Mantener humano',\n 'card.mode.pass': 'Paso mecánico',\n 'card.askHint': 'El tamiz mecánico filtra y enumera sus dudas, pero la solicitud sigue quedando con una persona y no se llama al modelo revisor ni una vez — la forma para ejecuciones sin LLM revisor conectado, o cuando los tokens no valen la pena.',\n 'card.passHint': 'Ejecuta solo el juez mecánico determinista: una operación irreversible, irrecuperable o ilegible se bloquea y se devuelve justificada al modelo principal; lo demás corre. Ninguna llamada al modelo, ninguna pregunta humana: la forma revisada de approval: never, y un YOLO sin modelo.',\n 'card.tierScopeHint': 'Solo los presets dentro del alcance del gate (%scope) llegan a este paso; fuera de él el gate se aparta por completo y ningún interruptor toma sus confirmaciones.',\n 'card.yolo': 'YOLO — nunca pedir un humano: bloquear lo peligroso, ejecutar el resto',\n 'card.yoloExempt': 'YOLO: permitir también “ubicación desconocida” dentro del workspace',\n 'card.yoloExemptHint': 'Solo YOLO. Activado, una llamada en la que solo la “ubicación” es indeterminable (herramienta sin argumentos, script fuera del workspace cuyo cuerpo no se leyó) ya no se bloquea por “invisible”. Las cargas codificadas, los cuerpos ilegibles, los borrados y las escrituras remotas siguen bloqueados; P0, credenciales e irreversible nunca cambian.',\n 'card.yoloHint': 'Bloquea una carga irreversible / no aprendible / ilegible, o un veredicto de riesgo duro del modelo, y devuelve la razón al LLM principal como mensaje 工具审核意见; todo lo demás se ejecuta. Sin un modelo disponible, solo las redes deterministas interceptan.',\n 'card.rulesFallback': 'Degradar a una compuerta de reglas cuando no hay modelo (clase cc-safety-net)',\n 'card.rulesFallbackHint': 'Solo actúa cuando el revisor de riesgo no está configurado o no dio veredicto: las redes deterministas bloquean lo que saben nombrar y dejan pasar el resto, en lugar de dejar la llamada colgada en un emergente que nadie responderá. Mientras un modelo responde, el comportamiento no cambia.',\n 'card.allowProtectedBranchPush': 'Permitir force-push a ramas protegidas (por defecto off = suelo activo)',\n 'card.allowProtectedBranchPushHint': 'Por defecto el suelo P0 bloquea git push --force/--force-with-lease/--delete hacia main/master/production/release/stable (no degradable por el modelo). Al activarlo el suelo se aparta y se eximen las tres palabras push planas de la lista negra; la llamada cae en la regla git.push-force integrada, que aún pregunta a una persona salvo que revoques esa entrada o la añada a la allowlist. Nada más se amplía: borrados, redirecciones y el suelo de credenciales siguen armados.',\n 'card.credFamily': 'Escalón por familia de credenciales',\n 'card.credFamilyHint': 'Un escalón por familia: deny = lectura y escritura bloqueadas; ask = lectura con validación humana (predeterminado); readonly = lectura libre, la escritura sigue bloqueada por el suelo P0; readwrite = la cláusula de escritura del credential store se aparta para esta familia (caso npm login). Los demás suelos (raíces, rutas protegidas, .dsh, exfiltración) siguen armados en cualquier escalón. El estado vive en la fila del documento de reglas más la lista de exención; esta tarjeta escribe ambas juntas.',\n 'card.credFamilyLoading': 'Cargando escalones…',\n 'card.credFamilyFootnote': 'Los niveles sin humano (paso mecánico / YOLO) dejan pasar el residuo de los ask — elige deny para bloquear duro. Los credentialPaths personalizados nunca participan en la exención de escritura.',\n 'card.credReadwriteConfirm': 'readwrite permite escribir/modificar los archivos de credenciales de esta familia (reescribir ~/.npmrc). Es el único escalón que aparta parte del P0. ¿Confirmar?',\n 'card.credConfirmYes': 'Confirmar',\n 'card.credConfirmNo': 'Cancelar',\n 'card.credRung.deny': 'bloquear',\n 'card.credRung.ask': 'preguntar',\n 'card.credRung.readonly': 'solo lectura',\n 'card.credRung.readwrite': 'lectura escritura',\n 'card.scriptReview': 'Adjuntar el contenido de los scripts a la revisión (activado por defecto)',\n 'card.scriptReviewHint': 'Cuando una llamada ejecuta un archivo script, su cuerpo se lee y se da al modelo de riesgo y al humano por igual, y las redes deterministas también evalúan el cuerpo (un borrado que solo se ve dentro del archivo es justo lo que se escapaba). Los cuerpos se redactan y limitan antes de salir del host; desactivarlo mantiene el contenido de archivos local, al costo de devolver los scripts fuera del espacio de trabajo al nivel «ilegible».',\n 'card.credentialPaths': 'Rutas de credenciales personalizadas (la cola larga)',\n 'card.credentialPathsHint': 'Archivos secretos que la lista integrada no conoce. Las entradas son globos de ruta: un doble asterisco cruza directorios, un asterisco simple y un signo de interrogación se quedan dentro de un segmento; sin comodines se compara un fragmento de ruta completo (token no toca ambient.txt); un ~/ inicial se expande a tu home; un patrón relativo también coincide a cualquier profundidad (secrets/*.env cubre a/b/secrets/prod.env). Una coincidencia se trata al mismo estándar que .ssh: leerla fuera del espacio de trabajo y mutarla con una herramienta de archivo se deniegan de forma dura — ese nivel no se puede apelar ni sortear por el revisor, así que declara solo las rutas que de verdad necesitas proteger.',\n 'card.credentialPathsPlaceholder': 'Nueva ruta, p. ej. ~/.myco/vault.token o secrets/*.env',\n 'card.denyKeywordsExtra': 'Palabras clave añadidas a la blacklist (no reemplaza el preajuste)',\n 'card.denyKeywordsExtraHint': 'Un bloqueo determinista sobre términos propios — una subcomando de revocación/borrado de una CLI interna, un prefijo de token que emites. Esta lista solo añade: lo que contenga la blacklist de arriba (preajuste o tu propio reemplazo), estas palabras se fusionan.',\n 'card.listRemove': 'Quitar esta entrada',\n 'card.extraContentArgKeys': 'Claves de documento añadidas (nunca leídas como operación)',\n 'card.extraContentArgKeysHint': 'Nombres de campos documentales fuera de la lista integrada (content/text/plan…): una vez declarados, su texto deja de entrar en la lectura plana de palabras peligrosas y formas de credenciales. Solo se añade: la lista integrada no se reemplaza, porque olvidar una de sus claves traería de vuelta en silencio el fallo por el que un plan se rechaza por describir una acción. El comando realmente ejecutado y la ruta modificada se juzgan por sus propios caminos; esta lista no puede apagarlos.',\n 'card.extraContentArgKeysPlaceholder': 'Nuevo nombre de argumento, p. ej. steps',\n 'card.extraOperationArgKeys': 'Claves de operación añadidas (leer el campo como código que se ejecuta)',\n 'card.extraOperationArgKeysHint': 'Una vía para campos cuyo cuerpo sí se ejecuta (workflowYaml etc.): su texto entra en la blacklist y en el filtro de credenciales, y esta lista gana si ambas nombran la misma clave. Costo: declarar aquí un campo documental real vuelve a hacer que «el plan menciona rm -rf» sea motivo de rechazo.',\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.llmEffort': 'Esfuerzo de razonamiento (solo modo host)',\n 'card.llmEffortHost': 'Seguir el host',\n 'card.llmEffortHint': 'Vacío = no imponer nada, decide la configuración del modelo del host; cambia a low u off si el host lo rechaza.',\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 'doubt.no-rule': 'ninguna regla cubre esta llamada, el valor por defecto es preguntar — eso no significa que sea peligrosa',\n 'doubt.opaque': 'el payload no puede leerse (codificado, script fuera del workspace o programa no reconocido), ninguna regla puede localizar su objetivo',\n 'doubt.irreversible': 'regla irreversible: tras la ejecución no se puede deshacer',\n 'doubt.never-learn': 'esta respuesta no se aprenderá; la misma llamada volverá a preguntar',\n 'doubt.delete': 'elimina contenido',\n 'doubt.remote-write': 'efecto visible externamente (push / publish / solicitud de escritura); deshacer requiere pasos manuales',\n 'doubt.exec-external': 'ejecuta código fuera del workspace, no inspeccionable por esta llamada',\n 'doubt.outside-paths': 'usa rutas fuera del workspace',\n 'doubt.model-flagged': 'el modelo de riesgo lo marcó (solo puede escalar, nunca aprobar)',\n 'doubt.write': 'escribe o modifica archivos',\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","/**\r\n * The optimistic state machine behind the settings card's pill switch and its tier\r\n * picker, kept out of the components so its three rules are testable without a DOM\r\n * renderer (the client half ships no react-dom).\r\n *\r\n * The posture: the control flips the instant it is clicked and holds that\r\n * position while the write round-trips through the host settings service — a\r\n * checkbox that waits for the snapshot reads as a dead control. The store stays\r\n * the truth, so the local override is dropped the moment the snapshot agrees\r\n * with it, on a rejected write, and on a watchdog in case a host line neither\r\n * applies nor reports the change.\r\n */\r\n\r\n/** How long an unconfirmed click is allowed to hold the control before it snaps back. */\r\nexport const SWITCH_SETTLE_MS = 4_000\r\n\r\n/**\r\n * What the control displays: the pending click wins over the store until the store\r\n * catches up (or the watchdog gives up on it). Generic because the same posture covers a\r\n * two-state pill and a multi-state tier picker alike.\r\n */\r\nexport function shownValue<T>(pending: T | null, checked: T): T {\r\n return pending ?? checked\r\n}\r\n\r\n/**\r\n * Store update: once the snapshot reports the requested value the override is redundant,\r\n * and handing the visual back to the snapshot is what keeps the control honest if another\r\n * writer (a patch file, the app's own plugin manager) moved the same field meanwhile.\r\n */\r\nexport function pendingAfterSync<T>(pending: T | null, checked: T): T | null {\r\n return pending !== null && pending === checked ? null : pending\r\n}\r\n\r\n/** A write that came back rejected: fall back to whatever the store holds. */\r\nexport function pendingAfterFailure<T>(_pending: T | null): null {\r\n return null\r\n}\r\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. The plugin ships five 自动审查 tiers of its own\n * (declared in its `cordis.patch.yml`, which is how they reach the composer picker at all):\n * the plain one (file sandbox kept), the full-access one (sandbox lifted, same approval\n * behaviour), and the three human-free / model-free implementations — mechanical takeover of\n * asks (`permissive-mech`), mechanical screen that still asks (`permissive-snet`), and the\n * model-backed YOLO. Each has exactly one preset and one switch, so they never cross: a\n * switch changes the behaviour of its own tier and of nothing else. `'*'` makes the gate\n * global (every 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[] = [\n 'permissive',\n 'permissive-full',\n 'permissive-mech',\n 'permissive-snet',\n 'permissive-yolo',\n]\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 { pendingAfterFailure, pendingAfterSync, shownValue, SWITCH_SETTLE_MS } from './switch-state.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 /** Permissive tier: the human handles what the grader flags. */\n /** YOLO tier (`permissive-yolo`): the grader answers in the person's place, never asks. */\n yolo?: boolean\n /**\n * YOLO only: stop treating \"the target could not be pinned down\" as a danger signal.\n * Invisible content, deletes and remote writes stay blocked; default off.\n */\n yoloWorkspaceExempt?: boolean\n /** Safenet-pass tier (`permissive-mech`): the mechanical screen takes over asks. */\n safenetPass?: boolean\n /** Safenet-ask tier (`permissive-snet`): mechanical screen, still asks, no grader. */\n safenetAsk?: boolean\n /** Protected-branch push floor opt-out. Default false keeps the P0 floor. */\n allowProtectedBranchPush?: boolean\n /** Unattended tiers: never a human popup (see src/config.ts for the semantics). */\n rulesFallback?: boolean\n /** On unless explicitly unset to false — the default attaches script bodies. */\n scriptReview?: 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 /** Reasoning effort for the host receiver; empty follows the host model config. */\n classifierEffort?: 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 /** Keywords appended to whichever blacklist is live (never replaces it). */\n denyKeywordsExtra?: string[]\n /** User-declared credential paths, held to the same standard as `.ssh`. */\n credentialPaths?: string[]\n /** Extra argument keys treated as document bodies (never replaces the built-in list). */\n extraContentArgKeys?: string[]\n /** Extra argument keys treated as operations; wins over the prose list on the same key. */\n extraOperationArgKeys?: 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/** Focus ring for the pill switch. `:focus-visible` cannot be expressed inline, so\n * the one pseudo-class the card needs rides on a single injected rule. */\nconst switchCss = '.pg-switch:focus-visible{outline:var(--dsw-focus-ring-width,2px) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary,#3b82f6));outline-offset:2px}.pg-seg:focus-visible{outline:var(--dsw-focus-ring-width,2px) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary,#3b82f6));outline-offset:1px}'\n\n/**\n * Optimistic control state, shared by the pill switch and the tier picker: show the\n * requested value the instant it is clicked and hold it while the write round-trips\n * through the host settings service, then hand the visual back to the store — on the\n * snapshot catching up, on a rejected write, and on a watchdog for a host line that\n * neither applies nor reports the change. A control may be fast, but it may not lie.\n */\nfunction useOptimistic<T>(stored: T): readonly [T, (next: T, write: () => unknown) => void] {\n const [pending, setPending] = useState<T | null>(null)\n useEffect(() => { setPending((current) => pendingAfterSync(current, stored)) }, [stored])\n useEffect(() => {\n if (pending === null) return undefined\n const timer = setTimeout(() => { setPending(pendingAfterFailure(pending)) }, SWITCH_SETTLE_MS)\n return () => { clearTimeout(timer) }\n }, [pending])\n const commit = (next: T, write: () => unknown): void => {\n setPending(next)\n void Promise.resolve(write()).catch(() => { setPending(null) })\n }\n return [shownValue(pending, stored), commit] as const\n}\n\n/**\n * One row of the unattended block: a switch, and the preset it owns.\n *\n * The preset id is rendered next to the label because the mapping is the whole design —\n * one switch, one implementation, one tier — and a person who sees 「机械直通」 in the\n * composer needs to know which row governs it. The id is a machine key, so it stays\n * untranslated on purpose.\n */\nfunction TierRow(props: {\n readonly id: string\n readonly label: string\n readonly preset: string\n readonly checked: boolean\n readonly disabled: boolean\n readonly hint: string\n readonly onCommit: (next: boolean) => unknown\n}): JSX.Element {\n const { id, label, preset, checked, disabled, hint, onCommit } = props\n return (\n <>\n <div style={rowStyle}>\n <label htmlFor={id} style={{ fontSize: '12px' }}>\n {label}\n <span style={{ color: 'var(--dsw-alias-label-tertiary)', fontSize: '11px' }}> · {preset}</span>\n </label>\n <PillSwitch\n id={id}\n checked={checked}\n disabled={disabled}\n onCommit={onCommit}\n />\n </div>\n <p style={hintStyle}>{hint}</p>\n </>\n )\n}\n\n/**\n * Pill switch — the card's boolean control, cut to the shape of the host's own\n * `ui-primitives` Switch: 36×20 capsule, 16px thumb, and the on/off appearance\n * keyed off `aria-checked` so assistive tech can never read a state the eye does\n * not see.\n *\n * Optimistic by design: the capsule flips on click and holds that position while\n * `scope.set` round-trips through the host settings service. A checkbox that\n * waits for the snapshot to come back reads as a dead control on a slow write.\n * The snapshot stays the truth — the state machine lives in `switch-state.ts`\n * (and under test there) so the pill can never sit in a state the profile does\n * not have.\n *\n * Every colour is a theme token with a fallback: `--dsw-alias-brand-primary`\n * only exists on newer host lines, and an \"on\" state that resolves to nothing is\n * an invisible control in dark mode.\n */\nfunction PillSwitch(props: {\n readonly id: string\n readonly checked: boolean\n /** Accessible name for rows whose text is not a `<label>` (the host Switch demands one). */\n readonly label?: string | undefined\n readonly disabled?: boolean | undefined\n readonly title?: string | undefined\n readonly onCommit: (next: boolean) => unknown\n}): JSX.Element {\n const { id, checked, label, disabled = false, title, onCommit } = props\n const [shown, commit] = useOptimistic<boolean>(checked)\n return (\n <button\n id={id}\n type=\"button\"\n role=\"switch\"\n aria-checked={shown}\n aria-label={label}\n title={title}\n disabled={disabled}\n className=\"pg-switch\"\n style={{\n boxSizing: 'border-box',\n position: 'relative',\n flex: '0 0 auto',\n width: '36px',\n height: '20px',\n padding: '2px',\n border: '0',\n borderRadius: '999px',\n background: shown\n ? 'var(--dsw-alias-brand-primary, var(--dsw-alias-state-business-primary, #3b82f6))'\n : 'var(--dsw-alias-border-l3, var(--dsw-alias-border-l2, rgba(128,128,128,0.35)))',\n cursor: disabled ? 'default' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n transition: 'background 120ms ease',\n }}\n onClick={() => {\n const next = !shown\n commit(next, () => onCommit(next))\n }}\n >\n <span\n aria-hidden\n style={{\n display: 'block',\n width: '16px',\n height: '16px',\n borderRadius: '50%',\n background: 'var(--dsw-alias-label-primary-foreground, #fff)',\n transform: shown ? 'translateX(16px)' : 'translateX(0)',\n transition: 'transform 120ms ease',\n }}\n />\n </button>\n )\n}\n\n/**\n * A minimal add/remove editor for one string-array setting.\n *\n * Deliberately generic and small: the long-tail protection lists (`credentialPaths`,\n * `denyKeywordsExtra`) are the same shape — lines a person types to protect something\n * the preset cannot know — and they should not each grow their own copy of the row\n * markup the deny blacklist already has.\n */\n/**\n * cred family ladder — server-backed rows (`GET/POST /api/dsh-perm-gate/cred`).\n * The rung state lives in TWO stores the plugin owns — the family's row inside the\n * rules document (section + enabled) and the paired `credWriteExemptFamilies` list —\n * so the card must not keep a local mirror; it reads and writes through the route,\n * which applies both stores in one settings update. `readwrite` asks for an inline\n * confirmation: it is the only rung that steps a piece of P0 aside.\n */\nconst CRED_FAMILIES_UI: readonly (readonly [string, string])[] = [\n ['ssh', 'SSH (~/.ssh)'],\n ['cloud', 'Cloud (.aws/.gcloud/.azure)'],\n ['package', 'Registry (.npmrc/.pypirc/.netrc)'],\n ['gitcreds', 'Git store (.git-credentials)'],\n ['env', 'Project (.env)'],\n ['cli', 'Coding CLI (~/.claude/.codex/gh)'],\n ['db', 'Database (.pgpass/.my.cnf)'],\n]\nconst CRED_RUNGS_UI: readonly string[] = ['deny', 'ask', 'readonly', 'readwrite']\n// Literal key map: the locale dictionary is a literal union — a computed\n// `card.credRung.${rung}` template widens to string and fails the seat typing.\nconst CRED_RUNG_LABEL_KEY = {\n deny: 'card.credRung.deny',\n ask: 'card.credRung.ask',\n readonly: 'card.credRung.readonly',\n readwrite: 'card.credRung.readwrite',\n} as const\n\nfunction CredLadderSection(props: { t: PermissiveCardProps['t']; readonly: boolean }) {\n const { t, readonly } = props\n const [rungs, setRungs] = useState<Record<string, string> | null>(null)\n const [confirm, setConfirm] = useState<string | null>(null)\n const [busy, setBusy] = useState<string | null>(null)\n // Row-scoped error: a failure at the bottom of the section is invisible to the\n // person who just clicked a row — the feedback must sit on the row that failed.\n const [rowError, setRowError] = useState<{ family: string; msg: string } | null>(null)\n useEffect(() => {\n let alive = true\n fetch('/api/dsh-perm-gate/cred', { headers: { 'cache-control': 'no-cache' } })\n .then((r) => r.json())\n .then((b: { rungs?: Record<string, string> }) => { if (alive && b?.rungs !== undefined) setRungs(b.rungs) })\n .catch(() => { /* route unavailable: the section keeps showing the loading line */ })\n return () => { alive = false }\n }, [])\n const apply = (family: string, rung: string): void => {\n setBusy(family)\n setRowError(null)\n // A hanging POST used to leave the row in silent `busy` forever (desktop webServer\n // body-stream mismatch) — 10s ceiling turns it into a visible, named failure.\n const abort = new AbortController()\n const timer = setTimeout(() => { abort.abort() }, 10_000)\n fetch('/api/dsh-perm-gate/cred', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ family, rung }),\n signal: abort.signal,\n })\n .then((r) => r.json())\n .then((b: { ok?: boolean; rungs?: Record<string, string>; error?: string }) => {\n if (b?.ok === true && b.rungs !== undefined) setRungs(b.rungs)\n else setRowError({ family, msg: String(b?.error ?? 'failed') })\n })\n .catch((e: unknown) => {\n const msg = String((e as Error)?.name ?? e) === 'AbortError' ? 'timeout (10s)' : String(e)\n setRowError({ family, msg })\n })\n .finally(() => { clearTimeout(timer); setBusy(null); setConfirm(null) })\n }\n return (\n <section style={sectionStyle}>\n <p style={labelStyle}>{t('card.credFamily')}</p>\n <p style={hintStyle}>{t('card.credFamilyHint')}</p>\n {rungs === null ? (\n <p style={hintStyle}>{t('card.credFamilyLoading')}</p>\n ) : (\n CRED_FAMILIES_UI.map(([family, display]) => (\n <div key={family} style={{ ...rowStyle, flexWrap: 'wrap' }}>\n <span style={{ fontSize: '12px', color: 'var(--dsw-alias-label-primary)' }}>{display}</span>\n <span style={{ display: 'inline-flex', gap: '4px' }}>\n {CRED_RUNGS_UI.map((rung) => (\n <button\n key={rung}\n type=\"button\"\n disabled={readonly || busy === family}\n style={{\n fontSize: '11px',\n padding: '2px 8px',\n cursor: 'pointer',\n borderRadius: '10px',\n border: rungs[family] === rung ? '1px solid var(--dsw-alias-primary, #4a90d9)' : '1px solid transparent',\n background: rungs[family] === rung ? 'rgba(74, 144, 217, 0.15)' : 'transparent',\n }}\n onClick={() => {\n if (rung === 'readwrite' && confirm !== family) { setConfirm(family); return }\n setConfirm(null)\n apply(family, rung)\n }}\n >\n {t(CRED_RUNG_LABEL_KEY[rung as keyof typeof CRED_RUNG_LABEL_KEY])}\n </button>\n ))}\n </span>\n {confirm === family && (\n <span style={{ width: '100%', fontSize: '12px', color: 'var(--dsw-alias-label-secondary)' }}>\n {t('card.credReadwriteConfirm')}\n <button type=\"button\" disabled={busy === family} style={{ fontSize: '11px', marginLeft: '6px' }} onClick={() => apply(family, 'readwrite')}>{t('card.credConfirmYes')}</button>\n <button type=\"button\" style={{ fontSize: '11px', marginLeft: '4px' }} onClick={() => setConfirm(null)}>{t('card.credConfirmNo')}</button>\n </span>\n )}\n {rowError !== null && rowError.family === family && (\n <span style={{ width: '100%', fontSize: '11px', color: 'var(--dsw-alias-danger, #c0392b)' }}>{family}: {rowError.msg}</span>\n )}\n </div>\n ))\n )}\n <p style={hintStyle}>{t('card.credFamilyFootnote')}</p>\n </section>\n )\n}\n\nfunction StringListField(props: {\n readonly label: string\n readonly hint: string\n readonly placeholder: string\n readonly addLabel: string\n readonly removeLabel: string\n readonly items: readonly string[]\n readonly locked: boolean\n readonly onAdd: (value: string) => void\n readonly onRemove: (index: number) => void\n}): JSX.Element {\n const [draft, setDraft] = useState('')\n const add = (): void => {\n const next = draft.trim()\n if (next === '') return\n props.onAdd(next)\n setDraft('')\n }\n return (\n <>\n <p style={labelStyle}>{props.label}</p>\n <p style={hintStyle}>{props.hint}</p>\n <div style={{ display: 'flex', flexDirection: 'column', gap: '4px', margin: '6px 0' }}>\n {props.items.map((item, index) => (\n <div\n key={`${index}:${item}`}\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 {item}\n </code>\n <button\n type=\"button\"\n aria-label={props.removeLabel}\n title={props.removeLabel}\n disabled={props.locked}\n onClick={() => { props.onRemove(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: props.locked ? 'default' : 'pointer',\n }}\n >\n ✕\n </button>\n </div>\n ))}\n </div>\n <div style={{ display: 'flex', gap: '6px', marginTop: '6px' }}>\n <input\n type=\"text\"\n value={draft}\n disabled={props.locked}\n placeholder={props.placeholder}\n spellCheck={false}\n style={{ ...controlStyle, flex: '1 1 auto', minWidth: 0 }}\n onChange={(event) => { setDraft(event.currentTarget.value) }}\n onKeyDown={(event) => { if (event.key === 'Enter') add() }}\n />\n <button\n type=\"button\"\n disabled={props.locked || draft.trim() === ''}\n onClick={add}\n style={{ ...controlStyle, flex: '0 0 auto', cursor: props.locked || draft.trim() === '' ? 'default' : 'pointer', opacity: props.locked || draft.trim() === '' ? 0.5 : 1 }}\n >\n {props.addLabel}\n </button>\n </div>\n </>\n )\n}\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 // 诊断守卫(2026-10-07):scope 未解析时不能在 render 里炸——宿主设置壳对\n // 内容槽异常静默吞(面板空白无报错),无法与「根本没渲染」区分。守卫后\n // 面板显式出占位文案,把「渲染了但 scope 没到」与「没渲染」分开。\n // 注意:守卫分支跳过了下方 hooks,scope 到位后该实例 hook 数会变——\n // 仅作诊断用途,定位后移除或改为 hook 稳定形态。\n if (!scope) {\n return <div style={{ padding: 16, color: 'var(--dsw-alias-label-tertiary, #888)' }}>\n {t('card.unavailable')}(scope 未解析 — 诊断占位)\n </div>\n }\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 raw = (snapshot.value ?? {}) as Record<string, unknown>\n // 形状防御(T13b 桥轨实测):宿主各线的 settings 值可能残留非数组形态的\n // 列表字段(0.1.5 installSection base=resolved config,deployment patch 里\n // 的历史 allowlist:{} 透传到 value),卡片只认 string[]——非数组一律按空\n // 处理,用户在卡里保存一次即写回正确形态。\n const listOf = (v: unknown): string[] => (Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string') : [])\n const value = {\n ...raw,\n allowlist: listOf(raw.allowlist),\n denyKeywords: listOf(raw.denyKeywords),\n denyKeywordsExtra: listOf(raw.denyKeywordsExtra),\n credentialPaths: listOf(raw.credentialPaths),\n extraContentArgKeys: listOf(raw.extraContentArgKeys),\n extraOperationArgKeys: listOf(raw.extraOperationArgKeys),\n } as unknown 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 // The presets the gate acts in at all — outside them the whole gate stands down.\n const gateScope = (value.gatePresets ?? []).length > 0 ? (value.gatePresets as string[]) : [...DEFAULT_GATE_PRESETS]\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 <style>{switchCss}</style>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-permissive\" style={labelStyle}>{t('card.permissive')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-permissive\"\n checked={effective}\n disabled={readonly}\n onCommit={(next) => scope.set('permissive', next)}\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('%scope', gateScope.join(' / '))}\n </p>\n\n {/* Each unattended implementation owns one preset and one switch, so the\n rows below cannot cross: a switch changes the behaviour of the tier\n named beside it and of no other. Script review is independent of all\n of them and on by default. */}\n <section style={sectionStyle}>\n <p style={labelStyle}>{t('card.unattended')}</p>\n <p style={hintStyle}>{t('card.unattendedHint')}</p>\n <TierRow\n id=\"plugin-config-perm-gate-yolo\"\n label={t('card.yolo')}\n preset=\"permissive-yolo\"\n checked={value.yolo === true}\n disabled={readonly}\n hint={t('card.yoloHint')}\n onCommit={(next) => scope.set('yolo', next)}\n />\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-yolo-exempt\" style={{ fontSize: '12px' }}>\n {t('card.yoloExempt')}\n </label>\n <PillSwitch\n id=\"plugin-config-perm-gate-yolo-exempt\"\n checked={value.yoloWorkspaceExempt === true}\n disabled={readonly}\n onCommit={(next) => scope.set('yoloWorkspaceExempt', next)}\n />\n </div>\n <p style={hintStyle}>{t('card.yoloExemptHint')}</p>\n <TierRow\n id=\"plugin-config-perm-gate-safenet-pass\"\n label={t('card.mode.pass')}\n preset=\"permissive-mech\"\n checked={value.safenetPass !== false}\n disabled={readonly}\n hint={t('card.passHint')}\n onCommit={(next) => scope.set('safenetPass', next)}\n />\n <TierRow\n id=\"plugin-config-perm-gate-safenet-ask\"\n label={t('card.mode.ask')}\n preset=\"permissive-snet\"\n checked={value.safenetAsk === true}\n disabled={readonly}\n hint={t('card.askHint')}\n onCommit={(next) => scope.set('safenetAsk', next)}\n />\n <p style={hintStyle}>{t('card.tierScopeHint').replace('%scope', gateScope.join(' / '))}</p>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-rules-fallback\" style={{ fontSize: '12px' }}>{t('card.rulesFallback')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-rules-fallback\"\n checked={value.rulesFallback === true}\n disabled={readonly}\n onCommit={(next) => scope.set('rulesFallback', next)}\n />\n </div>\n <p style={hintStyle}>{t('card.rulesFallbackHint')}</p>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-allow-protected-push\" style={{ fontSize: '12px' }}>{t('card.allowProtectedBranchPush')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-allow-protected-push\"\n checked={value.allowProtectedBranchPush === true}\n disabled={readonly}\n onCommit={(next) => scope.set('allowProtectedBranchPush', next)}\n />\n </div>\n <p style={hintStyle}>{t('card.allowProtectedBranchPushHint')}</p>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-script-review\" style={{ fontSize: '12px' }}>{t('card.scriptReview')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-script-review\"\n checked={value.scriptReview !== false}\n disabled={readonly}\n onCommit={(next) => scope.set('scriptReview', next)}\n />\n </div>\n <p style={hintStyle}>{t('card.scriptReviewHint')}</p>\n </section>\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 <PillSwitch\n id=\"plugin-config-perm-gate-trust\"\n checked={strategies.trustAutoAllow ?? true}\n disabled={readonly || !effective}\n onCommit={(next) => scope.set('permissiveStrategies', { ...strategies, trustAutoAllow: next })}\n />\n </div>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-confirm\" style={{ fontSize: '12px' }}>{t('card.strategy.alwaysConfirm')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-confirm\"\n checked={strategies.alwaysConfirm ?? false}\n disabled={readonly || !effective}\n onCommit={(next) => scope.set('permissiveStrategies', { ...strategies, alwaysConfirm: next })}\n />\n </div>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-llm\" style={{ fontSize: '12px' }}>{t('card.strategy.llmAssist')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-llm\"\n checked={strategies.llmAssist ?? false}\n disabled={readonly || !effective}\n onCommit={(next) => scope.set('permissiveStrategies', { ...strategies, llmAssist: next })}\n />\n </div>\n <div style={rowStyle}>\n <label htmlFor=\"plugin-config-perm-gate-escalation\" style={{ fontSize: '12px' }}>{t('card.strategy.trustEscalation')}</label>\n <PillSwitch\n id=\"plugin-config-perm-gate-escalation\"\n checked={strategies.trustEscalation ?? true}\n disabled={readonly || !effective}\n onCommit={(next) => scope.set('permissiveStrategies', { ...strategies, trustEscalation: next })}\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.llmEffort')}</span>\n <select\n value={value.classifierEffort ?? ''}\n disabled={readonly || receiverSource !== 'host'}\n style={controlStyle}\n title={t('card.llmEffortHint')}\n onChange={(event) => { void scope.set('classifierEffort', event.currentTarget.value) }}\n >\n <option value=\"\">{t('card.llmEffortHost')}</option>\n <option value=\"off\">off</option>\n <option value=\"low\">low</option>\n <option value=\"medium\">medium</option>\n <option value=\"high\">high</option>\n </select>\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 <PillSwitch\n id=\"plugin-config-perm-gate-risk-learning\"\n checked={value.riskLearning ?? false}\n disabled={readonly || !effective}\n onCommit={(next) => scope.set('riskLearning', next)}\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 <PillSwitch\n id=\"plugin-config-perm-gate-risk-sediment\"\n checked={value.riskSediment ?? true}\n disabled={readonly || !effective}\n onCommit={(next) => scope.set('riskSediment', next)}\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 {/* Long-tail protection the preset cannot know about: the user's own\n secret paths and their own blacklist words. Kept out of the deny\n blacklist section because the semantics differ — that list replaces\n the preset, these two never do. */}\n <section style={sectionStyle}>\n <StringListField\n label={t('card.credentialPaths')}\n hint={t('card.credentialPathsHint')}\n placeholder={t('card.credentialPathsPlaceholder')}\n addLabel={t('card.denylistAdd')}\n removeLabel={t('card.listRemove')}\n items={value.credentialPaths ?? []}\n locked={readonly}\n onAdd={(entry) => { void scope.set('credentialPaths', [...(value.credentialPaths ?? []), entry]) }}\n onRemove={(index) => { void scope.set('credentialPaths', (value.credentialPaths ?? []).filter((_, i) => i !== index)) }}\n />\n <div style={{ height: '10px' }} />\n <StringListField\n label={t('card.denyKeywordsExtra')}\n hint={t('card.denyKeywordsExtraHint')}\n placeholder={t('card.denylistPlaceholder')}\n addLabel={t('card.denylistAdd')}\n removeLabel={t('card.listRemove')}\n items={value.denyKeywordsExtra ?? []}\n locked={readonly}\n onAdd={(entry) => { void scope.set('denyKeywordsExtra', [...(value.denyKeywordsExtra ?? []), entry]) }}\n onRemove={(index) => { void scope.set('denyKeywordsExtra', (value.denyKeywordsExtra ?? []).filter((_, i) => i !== index)) }}\n />\n <div style={{ height: '10px' }} />\n <StringListField\n label={t('card.extraContentArgKeys')}\n hint={t('card.extraContentArgKeysHint')}\n placeholder={t('card.extraContentArgKeysPlaceholder')}\n addLabel={t('card.denylistAdd')}\n removeLabel={t('card.listRemove')}\n items={value.extraContentArgKeys ?? []}\n locked={readonly}\n onAdd={(entry) => { void scope.set('extraContentArgKeys', [...(value.extraContentArgKeys ?? []), entry]) }}\n onRemove={(index) => { void scope.set('extraContentArgKeys', (value.extraContentArgKeys ?? []).filter((_, i) => i !== index)) }}\n />\n <div style={{ height: '10px' }} />\n <StringListField\n label={t('card.extraOperationArgKeys')}\n hint={t('card.extraOperationArgKeysHint')}\n placeholder={t('card.extraContentArgKeysPlaceholder')}\n addLabel={t('card.denylistAdd')}\n removeLabel={t('card.listRemove')}\n items={value.extraOperationArgKeys ?? []}\n locked={readonly}\n onAdd={(entry) => { void scope.set('extraOperationArgKeys', [...(value.extraOperationArgKeys ?? []), entry]) }}\n onRemove={(index) => { void scope.set('extraOperationArgKeys', (value.extraOperationArgKeys ?? []).filter((_, i) => i !== index)) }}\n />\n </section>\n\n {/* Credential-family ladder: rows live in the rules document (section +\n enabled) and in credWriteExemptFamilies — read and written through\n the cred route, never mirrored here. */}\n <CredLadderSection t={t} readonly={readonly} />\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 <PillSwitch\n id=\"plugin-config-perm-gate-network-enabled\"\n label={t('card.networkEnabled')}\n checked={value.networkEnabled === true}\n disabled={readonly}\n onCommit={(next) => scope.set('networkEnabled', next)}\n />\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 <PillSwitch\n id=\"plugin-config-perm-gate-network-inject-env\"\n label={t('card.networkInjectEnv')}\n checked={value.networkInjectEnv !== false}\n disabled={readonly}\n onCommit={(next) => scope.set('networkInjectEnv', next)}\n />\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 <PillSwitch\n id=\"plugin-config-perm-gate-watch\"\n label={t('card.watch')}\n checked={value.watch !== false}\n disabled={readonly}\n onCommit={(next) => scope.set('watch', next)}\n />\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","/**\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 /**\n * The card the human decided from (why it asks / what it touches / what each\n * button costs). Preferred over `reason` in the review list: the audit reason is\n * a machine label, and a list of machine labels cannot be read back as \"what did\n * I just approve, and why\".\n */\n readonly humanBrief?: string\n /** The redacted command, kept apart from the prose so the list can show it as code. */\n readonly humanCommand?: string\n /** Machine keys of \"why it asked\", for localized rendering. */\n readonly doubtKinds?: readonly 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 /** Salted digest of the redacted input behind the decision, when recorded. */\n readonly inputDigest?: string\n /** Which grading prompt produced this verdict, when recorded. */\n readonly promptVersion?: string\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 // The unattended tiers never raise a prompt, so the approvals history is the only\n // place their decisions surface — an untranslated tag there reads as a leak.\n 'yolo-allow': 'YOLO 放行',\n // The YOLO tier advertises a reviewer model. When none answered, the tier still refuses to\n // ask a person and settles mechanically — and the history has to say that out loud, or the\n // two human-free tiers silently become one.\n 'yolo-allow-no-reviewer': 'YOLO 放行(无审查模型·机械处置)',\n 'yolo-block': 'YOLO 拦截',\n 'rules-fallback-allow': '无模型规则闸门放行',\n 'rules-fallback-block': '无模型规则闸门拦截',\n 'safety-net-passthrough-allow': '机械审查放行(零模型)',\n 'safety-net-passthrough-block': '机械审查拦截(零模型)',\n // Longer-standing paths that also reach the feed without a label.\n 'cleanup-safe': '清理类安全放行',\n 'escalation-auto': '沙箱升级自动放行',\n 'learned-granted': '学习授权放行',\n 'network-ask': '网络审批',\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'\nimport type { PermissiveKey } from './locales.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 {' \\u2014 '}\n {notice.doubtKinds !== undefined && notice.doubtKinds.length > 0\n ? notice.doubtKinds.map((k) => t(`doubt.${k}` as PermissiveKey)).join(' \\u00b7 ')\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.doubtKinds !== undefined && ev.doubtKinds.length > 0\n ? ev.doubtKinds.map((k) => t(`doubt.${k}` as PermissiveKey)).join(' · ')\n : (ev.humanBrief ?? ev.justification ?? ev.reason)}\n </div>\n {ev.humanCommand === undefined || ev.humanCommand === ''\n ? null\n : (\n /*\n * The command gets its own block in the host's code font, the way the approval\n * popup shows it (`.command` vs `.headline`): prose and payload must not share a\n * line, or the reader cannot tell what they are about to run from why they are\n * being asked.\n */\n <div\n style={{\n marginTop: '4px',\n fontFamily: 'var(--ds-font-family-code, monospace)',\n fontSize: '12px',\n lineHeight: '18px',\n whiteSpace: 'pre-wrap',\n overflowWrap: 'anywhere',\n color: 'var(--dsw-alias-label-primary, inherit)',\n }}\n >\n {ev.humanCommand}\n </div>\n )}\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/<ns>/settings/describe;\n * 写 = POST …/mutate(ops 转发宿主 settings 服务),成功即用回填描述符刷新快照并\n * 通知订阅者(乐观刷新,无本地第二份状态——权威值始终在宿主服务里)。\n * 初始 describe 拉取在构造时异步发起;拉取完成前快照 status='pending',卡片据此\n * 呈现加载态。\n *\n * T20-b 泛化(2026-10-08):路由由构造参数 ns 派生(与 server 侧 bridgeRoutesFor\n * 同式,两半一致性由测试钉死)——同一宿主进程多 ns 各持一个句柄(steward 双 ns)。\n * client tsconfig include 仅 src/client,故此处持本地派生式而非跨目录 import。\n */\nimport type { SettingsDocHandle } from './compat.js'\n\n/** 与 server 侧 bridgeRoutesFor(src/bridge.ts)必须逐字符一致。 */\nfunction bridgeRoutesFor(ns: string): { describe: string; mutate: string } {\n return { describe: `/api/${ns}/settings/describe`, mutate: `/api/${ns}/settings/mutate` }\n}\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 private readonly routes: { describe: string; mutate: string }\n\n constructor(ns: string) {\n this.routes = bridgeRoutesFor(ns)\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(this.routes.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(this.routes.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 top-level `settings.section`\n * entry (自动审查门) so the settings sidebar renders a standalone editable\n * section: the single 自动审查 tier switch plus the four combinable backend\n * 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'\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 // (settings.plugin.item 槽型镜像已随该席位退役一并删除——与顶级独立节\n // 重复的 ≤0.1.5 派发卡不再出现。settings.section 的槽型由\n // @deepseek-ai/dsh-client-ui-settings/client 的声明提供,无需本地镜像。)\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(PERMISSIVE_NS)\n\n // 卡片 inject 读活引用:注册先于 scope 解析也不空窗(未解析时回落桥轨,\n // 桥首拉 pending 期间卡片呈现加载态)。\n const cardInjected = (): PermissiveCardInjected => ({ scope: scopeRef.scope ?? bridgeScope }) as PermissiveCardInjected\n\n // 独立顶级设置节(范式 A;2026-10-08 回退定案:本插件不在家族 tab 化范围内\n // ——自动审查门是独立 insection,与「权限/上下文优化独立分节」的参考样本\n // 一致)。卡组件与数据臂(原生句柄优先 + 桥兜底)原样复用;server 侧数据面\n // (installSection 三代 + 桥路由)不动。与插件页 tab / ≤0.1.5 派发卡的\n // 去重取舍见下方注释。\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)已于 2026-10-08 移除:0.1.0\n // 实测它与顶级 settings.section 同时渲染,同一张卡出现两次;顶级独立节是\n // 唯一设置导航入口(同日家族 tab 收拢已回退——本插件不在 tab 化范围内)。\n\n // ≤0.1.5 设置面板「插件配置」tab 的派发卡(settings.plugin.item)同批退役:\n // 与顶级独立节重复。server 侧 installSection 数据面保留——它同时是桥\n // describe/mutate 与 served ns 的来源。\n\n}"],"mappings":"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"}