dsh-perm-gate 2.1.0 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.ja.md +108 -0
- package/CHANGELOG.ko.md +104 -0
- package/CHANGELOG.md +347 -0
- package/INSTALL.ja.md +84 -8
- package/INSTALL.ko.md +80 -9
- package/INSTALL.md +83 -8
- package/INSTALL.zh.md +70 -7
- package/README.ja.md +130 -16
- package/README.ko.md +128 -17
- package/README.md +179 -25
- package/README.zh.md +121 -12
- package/assets/allow1.png +0 -0
- package/assets/allow2.png +0 -0
- package/assets/gateoff.png +0 -0
- package/assets/llms.png +0 -0
- package/assets/permlist.png +0 -0
- package/assets/setting-head.png +0 -0
- package/assets/setting-rules.png +0 -0
- package/cordis.patch.yml +37 -3
- package/docs/baseline-guard.md +56 -0
- package/docs/plan-rules-to-settings.md +217 -0
- package/docs/rules-format.en.md +294 -0
- package/docs/rules-format.md +279 -0
- package/docs/ui-gap-analysis-and-branch-permissions.md +338 -0
- package/dsh.plugin.json +22 -0
- package/examples/permissions.example.yaml +16 -1
- package/lib/agent-identity.d.ts +43 -0
- package/lib/agent-identity.js +95 -0
- package/lib/allowlist.d.ts +27 -0
- package/lib/allowlist.js +103 -1
- package/lib/cli.js +11 -14
- package/lib/client.js +598 -6
- package/lib/client.js.map +1 -1
- package/lib/command-dispatcher.d.ts +22 -0
- package/lib/command-dispatcher.js +97 -0
- package/lib/command-semantics.d.ts +62 -0
- package/lib/command-semantics.js +6 -0
- package/lib/compiler.d.ts +50 -0
- package/lib/compiler.js +122 -0
- package/lib/config.d.ts +161 -7
- package/lib/config.js +78 -11
- package/lib/dry-run.d.ts +87 -0
- package/lib/dry-run.js +110 -0
- package/lib/engine.js +61 -4
- package/lib/evaluate.d.ts +9 -0
- package/lib/evaluate.js +264 -1
- package/lib/events.d.ts +69 -2
- package/lib/events.js +123 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +320 -11
- package/lib/network-lifecycle.d.ts +107 -0
- package/lib/network-lifecycle.js +180 -0
- package/lib/network.d.ts +109 -0
- package/lib/network.js +196 -0
- package/lib/parsers/git.d.ts +43 -0
- package/lib/parsers/git.js +404 -0
- package/lib/parsers/shell-cmds.d.ts +32 -0
- package/lib/parsers/shell-cmds.js +293 -0
- package/lib/preset.d.ts +13 -0
- package/lib/preset.js +17 -0
- package/lib/proxy.d.ts +160 -0
- package/lib/proxy.js +529 -0
- package/lib/risk.d.ts +17 -3
- package/lib/risk.js +19 -6
- package/lib/rule-chain.d.ts +39 -0
- package/lib/rule-chain.js +213 -0
- package/lib/rule-dims.d.ts +174 -0
- package/lib/rule-dims.js +230 -0
- package/lib/rule.d.ts +60 -0
- package/lib/rule.js +69 -7
- package/lib/rules-view.d.ts +52 -0
- package/lib/rules-view.js +126 -0
- package/lib/runtime.d.ts +208 -7
- package/lib/runtime.js +433 -27
- package/lib/session-sweep.d.ts +45 -0
- package/lib/session-sweep.js +153 -0
- package/lib/shadow.d.ts +34 -0
- package/lib/shadow.js +143 -0
- package/lib/shell.d.ts +14 -0
- package/lib/shell.js +17 -0
- package/lib/watch.d.ts +42 -0
- package/lib/watch.js +170 -0
- package/package.json +26 -3
- package/scripts/patch-permission-glyph.mjs +392 -0
package/lib/client.js
CHANGED
|
@@ -16,10 +16,11 @@ window.__ModuleLoader__.load({
|
|
|
16
16
|
"card.description": "独立审批档位:与只读 / 完全权限 / 白名单平行,在会话权限下拉中显示为「自动审查」。前端只暴露一个开关;后台四个审批策略可组合、由此处设置决定,仍对 P0 硬拒绝保持 fail-closed。",
|
|
17
17
|
"card.permissive": "启用自动审查档位",
|
|
18
18
|
"card.permissiveHint": "关闭时门禁行为与此前完全一致。",
|
|
19
|
+
"card.scopeNote": "档位作用域:本门禁仅在会话权限档位为 %scope 时生效。其他档位下整个门禁停用(含 P0 硬拒绝),由所选档位自身的策略接管;停用时会写入一条 stand-down 事件,并在输入框上方常驻一条提示条。",
|
|
19
20
|
"card.strategies": "后台审批策略(至少一个生效;可组合)",
|
|
20
21
|
"card.strategy.trustAutoAllow": "trustAutoAllow — 作用域内安全操作自动放行,危险/未知转 ask(中间档基线)",
|
|
21
22
|
"card.strategy.alwaysConfirm": "alwaysConfirm — 一律逐次 ask;审批面板「允许控件」含两个扩展按钮:「本会话重复允许该类」(会话语限次 grant)与「允许所有类型」(命令词持久迁入 rulesFile 白名单)",
|
|
22
|
-
"card.strategy.llmAssist": "llmAssist — 自定义 LLM 按风险分级裁决:safe 自动放行;deletion/credential/remote/system/bulk
|
|
23
|
+
"card.strategy.llmAssist": "llmAssist — 自定义 LLM 按风险分级裁决:safe 自动放行;deletion/credential/remote/system/bulk 硬风险维持人工确认(分类器永不拒绝,只负责升级判断);neutral 进入确认学习;失败/超时回退人工",
|
|
23
24
|
"card.strategy.trustEscalation": "trustEscalation — 沙箱升级免确认:本门禁已放行的调用,其工具内部发起的沙箱提权(shell / pwsh / edit 的 sandbox_permissions)由门禁直接批准,不再弹窗",
|
|
24
25
|
"card.strategy.trustEscalationHint": "沙箱提权审批发生在 tools/pre-execute 之后、工具体内部,门禁原本看不到它,因此「LLM 判安全已自动放行」的调用仍会弹窗要求你批准提权。开启后,仅对门禁确实放行过的那一次调用(按 callId 精确匹配)免确认,其余一律照旧走人工;目标模式非 workspace-write / danger-full-access 或理由无法识别时同样回退人工。关闭后提权保持人工把关。",
|
|
25
26
|
"card.readonly": "只读",
|
|
@@ -86,6 +87,13 @@ window.__ModuleLoader__.load({
|
|
|
86
87
|
"card.llmPresetChoose": "选择预置…",
|
|
87
88
|
"card.llmPresetPublic": "公共 API 预置",
|
|
88
89
|
"card.llmPresetHost": "DSH 模型组(选择后自动切换为会话模式)",
|
|
90
|
+
"card.networkEnabled": "网络拦截(networkEnabled)",
|
|
91
|
+
"card.networkEnabledHint": "开启后启动本地代理拦截子进程出站连接,按规则放行/阻断。关闭则零行为变更。",
|
|
92
|
+
"card.watch": "规则热重载(watch)",
|
|
93
|
+
"card.watchHint": "开启后自动监听规则文件变更并即时生效,无需手动 reload。",
|
|
94
|
+
"card.networkRebindNote": "切换后立即生效(自动重绑,无需重载插件)。",
|
|
95
|
+
"card.networkInjectEnv": "注入代理环境变量(networkInjectEnv)",
|
|
96
|
+
"card.networkInjectEnvHint": "开启后为子进程写入 HTTP(S)_PROXY / ALL_PROXY(并清空 NO_PROXY)。关闭则只启动监听、不改变任何进程环境。",
|
|
89
97
|
"card.healthStale": "宿主路由不可用(404)——node 半区仍是旧版本,请完全重启 dsh(而非仅刷新页面)后重试。",
|
|
90
98
|
"card.healthTest": "健康测试",
|
|
91
99
|
"card.healthRunning": "测试中…",
|
|
@@ -95,6 +103,7 @@ window.__ModuleLoader__.load({
|
|
|
95
103
|
"history.tag.manualApproved": "人工通过",
|
|
96
104
|
"history.tag.manualRejected": "人工拒绝",
|
|
97
105
|
"history.tag.manualCancelled": "人工取消",
|
|
106
|
+
"history.tag.standDown": "门禁停用",
|
|
98
107
|
"history.learnedProgress": "学习 %n/%t",
|
|
99
108
|
"history.snapshots": "diff 快照",
|
|
100
109
|
"history.clearSession": "仅清本会话",
|
|
@@ -117,7 +126,41 @@ window.__ModuleLoader__.load({
|
|
|
117
126
|
"history.diffChipTitle": "查看该文件改动对比",
|
|
118
127
|
"history.diffStats": "+%a / -%r 行变更 · %c 行未变",
|
|
119
128
|
"history.diffGone": "(文件当前已不存在)",
|
|
120
|
-
"history.diffHidden": "%n 行未修改"
|
|
129
|
+
"history.diffHidden": "%n 行未修改",
|
|
130
|
+
"card.dryRun": "规则测试",
|
|
131
|
+
"card.dryRunHint": "用当前生效的规则判定一次调用,不执行任何工具、不写入任何规则。改规则前先在这里验一遍。",
|
|
132
|
+
"card.dryRunTool": "工具名",
|
|
133
|
+
"card.dryRunCommand": "命令 / 参数",
|
|
134
|
+
"card.dryRunCommandPlaceholder": "git push --force origin main",
|
|
135
|
+
"card.dryRunTest": "测试",
|
|
136
|
+
"card.dryRunRunning": "判定中…",
|
|
137
|
+
"card.dryRunEmpty": "尚未测试。填入工具名与命令,点「测试」查看会怎么裁决。",
|
|
138
|
+
"card.dryRunVerdict": "裁决",
|
|
139
|
+
"card.dryRunAllow": "放行",
|
|
140
|
+
"card.dryRunAsk": "人工确认",
|
|
141
|
+
"card.dryRunDeny": "拒绝",
|
|
142
|
+
"card.dryRunRule": "命中规则",
|
|
143
|
+
"card.dryRunRuleNone": "无规则命中,走 defaultAction:%d",
|
|
144
|
+
"card.dryRunDimensions": "约束维度",
|
|
145
|
+
"card.dryRunReason": "原因",
|
|
146
|
+
"card.dryRunNote": "「命中规则」来自规则层。若裁决由更早的硬拒绝或关键词黑名单产生,则不会有规则序号——那种情况下列出的维度仅供参考。",
|
|
147
|
+
"card.dryRunNoRules": "(当前加载了 0 条规则:检查 rulesFile 路径)",
|
|
148
|
+
"card.dryRunFail": "测试失败:",
|
|
149
|
+
"card.dryRunStale": "路由不存在(插件未重启?)",
|
|
150
|
+
"card.rules": "权限 YAML",
|
|
151
|
+
"card.rulesHint": "门禁此刻实际加载的规则文件原文。只读——这里改不了任何东西。要改规则,用下面的白名单,或直接编辑该文件。",
|
|
152
|
+
"card.rulesRefresh": "刷新",
|
|
153
|
+
"card.rulesLoading": "读取中…",
|
|
154
|
+
"card.rulesPath": "文件",
|
|
155
|
+
"card.rulesNone": "未配置规则文件",
|
|
156
|
+
"card.rulesCounts": "规则",
|
|
157
|
+
"card.rulesDefault": "defaultAction",
|
|
158
|
+
"card.rulesStats": "%b 字节 · %l 行",
|
|
159
|
+
"card.rulesMissing": "文件不存在。门禁会退到内置默认。",
|
|
160
|
+
"card.rulesTruncated": "文件过大,仅显示前 512 KB。",
|
|
161
|
+
"card.rulesError": "加载失败:",
|
|
162
|
+
"card.rulesStale": "路由不存在(插件未重启?)",
|
|
163
|
+
"card.rulesNote": "此处只读:面板无法修改该文件,白名单段是唯一会写入它的地方。"
|
|
121
164
|
};
|
|
122
165
|
/** English dictionary (keys mirror zh). */
|
|
123
166
|
const en = {
|
|
@@ -125,10 +168,11 @@ window.__ModuleLoader__.load({
|
|
|
125
168
|
"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.",
|
|
126
169
|
"card.permissive": "Enable the 自动审查 tier",
|
|
127
170
|
"card.permissiveHint": "When off, the gate behaves exactly as before.",
|
|
171
|
+
"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.",
|
|
128
172
|
"card.strategies": "Backend approval strategies (at least one effective; combinable)",
|
|
129
173
|
"card.strategy.trustAutoAllow": "trustAutoAllow — safe in-scope ops auto-allow; dangerous/unknown ask (baseline middle tier)",
|
|
130
174
|
"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)",
|
|
131
|
-
"card.strategy.llmAssist": "llmAssist — a custom LLM grades risk: safe auto-allows; deletion/credential/remote/system/bulk hard risks
|
|
175
|
+
"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",
|
|
132
176
|
"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",
|
|
133
177
|
"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.",
|
|
134
178
|
"card.readonly": "Read-only",
|
|
@@ -195,6 +239,13 @@ window.__ModuleLoader__.load({
|
|
|
195
239
|
"card.llmPresetChoose": "Pick a preset…",
|
|
196
240
|
"card.llmPresetPublic": "Public API presets",
|
|
197
241
|
"card.llmPresetHost": "DSH model groups (selecting one switches to the session receiver)",
|
|
242
|
+
"card.networkEnabled": "Network interception (networkEnabled)",
|
|
243
|
+
"card.networkEnabledHint": "When on, starts a local proxy that intercepts outbound subprocess connections and applies allow/deny rules. Off = zero behavior change.",
|
|
244
|
+
"card.watch": "Rule hot-reload (watch)",
|
|
245
|
+
"card.watchHint": "When on, automatically watches rule files for changes and applies them instantly without manual reload.",
|
|
246
|
+
"card.networkRebindNote": "Takes effect immediately — the proxy rebinds automatically, no plugin reload needed.",
|
|
247
|
+
"card.networkInjectEnv": "Inject proxy environment (networkInjectEnv)",
|
|
248
|
+
"card.networkInjectEnvHint": "Writes HTTP(S)_PROXY / ALL_PROXY for subprocesses (and clears NO_PROXY). Off = the listener runs but no process environment is changed.",
|
|
198
249
|
"card.healthStale": "Host route unavailable (404) — the node half is still an old build; fully restart dsh (not just the browser page) and retry.",
|
|
199
250
|
"card.healthTest": "Health test",
|
|
200
251
|
"card.healthRunning": "Testing…",
|
|
@@ -204,6 +255,7 @@ window.__ModuleLoader__.load({
|
|
|
204
255
|
"history.tag.manualApproved": "Approved",
|
|
205
256
|
"history.tag.manualRejected": "Rejected",
|
|
206
257
|
"history.tag.manualCancelled": "Cancelled",
|
|
258
|
+
"history.tag.standDown": "Gate off",
|
|
207
259
|
"history.learnedProgress": "learned %n/%t",
|
|
208
260
|
"history.snapshots": "diff snapshots",
|
|
209
261
|
"history.clearSession": "Clear this session",
|
|
@@ -226,7 +278,41 @@ window.__ModuleLoader__.load({
|
|
|
226
278
|
"history.diffChipTitle": "View this file’s change comparison",
|
|
227
279
|
"history.diffStats": "+%a / -%r lines changed · %c unchanged",
|
|
228
280
|
"history.diffGone": " (file no longer exists)",
|
|
229
|
-
"history.diffHidden": "%n unmodified lines"
|
|
281
|
+
"history.diffHidden": "%n unmodified lines",
|
|
282
|
+
"card.dryRun": "Rule test",
|
|
283
|
+
"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.",
|
|
284
|
+
"card.dryRunTool": "Tool",
|
|
285
|
+
"card.dryRunCommand": "Command / arguments",
|
|
286
|
+
"card.dryRunCommandPlaceholder": "git push --force origin main",
|
|
287
|
+
"card.dryRunTest": "Test",
|
|
288
|
+
"card.dryRunRunning": "Judging…",
|
|
289
|
+
"card.dryRunEmpty": "Nothing tested yet. Fill in a tool and command, then press Test to see how it would be judged.",
|
|
290
|
+
"card.dryRunVerdict": "Verdict",
|
|
291
|
+
"card.dryRunAllow": "allow",
|
|
292
|
+
"card.dryRunAsk": "ask",
|
|
293
|
+
"card.dryRunDeny": "deny",
|
|
294
|
+
"card.dryRunRule": "Matched rule",
|
|
295
|
+
"card.dryRunRuleNone": "no rule matched; defaultAction: %d",
|
|
296
|
+
"card.dryRunDimensions": "Dimensions",
|
|
297
|
+
"card.dryRunReason": "Reason",
|
|
298
|
+
"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.",
|
|
299
|
+
"card.dryRunNoRules": "(0 rules loaded — check the rulesFile path)",
|
|
300
|
+
"card.dryRunFail": "Test failed: ",
|
|
301
|
+
"card.dryRunStale": "route missing (plugin not restarted?)",
|
|
302
|
+
"card.rules": "Permissions YAML",
|
|
303
|
+
"card.rulesHint": "The rules file the gate is loading right now, verbatim. Read-only — nothing here can change it. To change rules, use the allowlist below or edit the file directly.",
|
|
304
|
+
"card.rulesRefresh": "Refresh",
|
|
305
|
+
"card.rulesLoading": "Reading…",
|
|
306
|
+
"card.rulesPath": "File",
|
|
307
|
+
"card.rulesNone": "no rules file configured",
|
|
308
|
+
"card.rulesCounts": "Rules",
|
|
309
|
+
"card.rulesDefault": "defaultAction",
|
|
310
|
+
"card.rulesStats": "%b bytes · %l lines",
|
|
311
|
+
"card.rulesMissing": "The file does not exist. The gate falls back to its built-in defaults.",
|
|
312
|
+
"card.rulesTruncated": "File is large; showing the first 512 KB only.",
|
|
313
|
+
"card.rulesError": "Load failed: ",
|
|
314
|
+
"card.rulesStale": "route missing (plugin not restarted?)",
|
|
315
|
+
"card.rulesNote": "Read-only: this panel cannot modify the file. The allowlist section is the only place that writes to it."
|
|
230
316
|
};
|
|
231
317
|
//#endregion
|
|
232
318
|
//#region src/deny-defaults.ts
|
|
@@ -295,6 +381,19 @@ window.__ModuleLoader__.load({
|
|
|
295
381
|
}
|
|
296
382
|
];
|
|
297
383
|
//#endregion
|
|
384
|
+
//#region src/preset.ts
|
|
385
|
+
/**
|
|
386
|
+
* Presets in which the gate is active. It owns both 自动审查 tiers — the plain
|
|
387
|
+
* one (file sandbox kept) and the full-access one (sandbox restriction lifted,
|
|
388
|
+
* same approval behaviour) — so a user can have the gate without inheriting a
|
|
389
|
+
* sandbox that breaks `git` / Cygwin tools. `'*'` makes it global (every
|
|
390
|
+
* preset, including the hard-deny layer).
|
|
391
|
+
*
|
|
392
|
+
* Lives in this dependency-free module (not `config.ts`) so the browser half can
|
|
393
|
+
* render the scope without pulling schemastery into the client bundle.
|
|
394
|
+
*/
|
|
395
|
+
const DEFAULT_GATE_PRESETS = ["permissive", "permissive-full"];
|
|
396
|
+
//#endregion
|
|
298
397
|
//#region src/client/sediment.tsx
|
|
299
398
|
/**
|
|
300
399
|
* Learning-sediment management section — the settings-card face of verdict
|
|
@@ -545,6 +644,67 @@ window.__ModuleLoader__.load({
|
|
|
545
644
|
const [bulkOpen, setBulkOpen] = (0, react.useState)(false);
|
|
546
645
|
const [healthBusy, setHealthBusy] = (0, react.useState)(false);
|
|
547
646
|
const [healthResult, setHealthResult] = (0, react.useState)(null);
|
|
647
|
+
const [dryTool, setDryTool] = (0, react.useState)("shell");
|
|
648
|
+
const [dryCommand, setDryCommand] = (0, react.useState)("");
|
|
649
|
+
const [dryBusy, setDryBusy] = (0, react.useState)(false);
|
|
650
|
+
const [dryReport, setDryReport] = (0, react.useState)(null);
|
|
651
|
+
const [dryError, setDryError] = (0, react.useState)(null);
|
|
652
|
+
const runDryRunTest = () => {
|
|
653
|
+
const tool = dryTool.trim() === "" ? "shell" : dryTool.trim();
|
|
654
|
+
const command = dryCommand.trim();
|
|
655
|
+
setDryBusy(true);
|
|
656
|
+
setDryError(null);
|
|
657
|
+
setDryReport(null);
|
|
658
|
+
fetch("/api/dsh-perm-gate/dry-run", {
|
|
659
|
+
method: "POST",
|
|
660
|
+
headers: { "content-type": "application/json" },
|
|
661
|
+
body: JSON.stringify({
|
|
662
|
+
tool,
|
|
663
|
+
args: command === "" ? {} : { command }
|
|
664
|
+
})
|
|
665
|
+
}).then(async (r) => {
|
|
666
|
+
const text = await r.text();
|
|
667
|
+
if (r.status === 404) throw new Error(t("card.dryRunStale"));
|
|
668
|
+
try {
|
|
669
|
+
return JSON.parse(text);
|
|
670
|
+
} catch {
|
|
671
|
+
throw new Error(text.trim().slice(0, 120) !== "" ? text.trim().slice(0, 120) : `HTTP ${r.status}`);
|
|
672
|
+
}
|
|
673
|
+
}).then((res) => {
|
|
674
|
+
if (res.ok === true && res.result !== void 0) setDryReport(res.result);
|
|
675
|
+
else setDryError(res.error ?? t("card.dryRunFail"));
|
|
676
|
+
}).catch((e) => {
|
|
677
|
+
setDryError(String(e?.message ?? e));
|
|
678
|
+
}).finally(() => {
|
|
679
|
+
setDryBusy(false);
|
|
680
|
+
});
|
|
681
|
+
};
|
|
682
|
+
const [rulesBody, setRulesBody] = (0, react.useState)(null);
|
|
683
|
+
const [rulesBusy, setRulesBusy] = (0, react.useState)(false);
|
|
684
|
+
const [rulesError, setRulesError] = (0, react.useState)(null);
|
|
685
|
+
const loadRules = () => {
|
|
686
|
+
setRulesBusy(true);
|
|
687
|
+
setRulesError(null);
|
|
688
|
+
fetch("/api/dsh-perm-gate/rules", { headers: { "cache-control": "no-cache" } }).then(async (r) => {
|
|
689
|
+
const text = await r.text();
|
|
690
|
+
if (r.status === 404) throw new Error(t("card.rulesStale"));
|
|
691
|
+
try {
|
|
692
|
+
return JSON.parse(text);
|
|
693
|
+
} catch {
|
|
694
|
+
throw new Error(text.trim().slice(0, 120) !== "" ? text.trim().slice(0, 120) : `HTTP ${r.status}`);
|
|
695
|
+
}
|
|
696
|
+
}).then((res) => {
|
|
697
|
+
if (res.ok === true && res.result !== void 0) setRulesBody(res.result);
|
|
698
|
+
else setRulesError(res.error ?? t("card.rulesError"));
|
|
699
|
+
}).catch((e) => {
|
|
700
|
+
setRulesError(String(e?.message ?? e));
|
|
701
|
+
}).finally(() => {
|
|
702
|
+
setRulesBusy(false);
|
|
703
|
+
});
|
|
704
|
+
};
|
|
705
|
+
(0, react.useEffect)(() => {
|
|
706
|
+
loadRules();
|
|
707
|
+
}, []);
|
|
548
708
|
const receiverSource = (value.classifierSource ?? "custom") === "host" ? "host" : "custom";
|
|
549
709
|
const [receiverInfo, setReceiverInfo] = (0, react.useState)(null);
|
|
550
710
|
const [receiverNonce, setReceiverNonce] = (0, react.useState)(0);
|
|
@@ -682,6 +842,10 @@ window.__ModuleLoader__.load({
|
|
|
682
842
|
style: hintStyle,
|
|
683
843
|
children: t("card.permissiveHint")
|
|
684
844
|
}),
|
|
845
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
846
|
+
style: hintStyle,
|
|
847
|
+
children: t("card.scopeNote").replace("%scope", ((value.gatePresets ?? []).length > 0 ? value.gatePresets : [...DEFAULT_GATE_PRESETS]).join(" / "))
|
|
848
|
+
}),
|
|
685
849
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
686
850
|
style: sectionStyle,
|
|
687
851
|
children: [
|
|
@@ -1101,6 +1265,325 @@ window.__ModuleLoader__.load({
|
|
|
1101
1265
|
}) : null
|
|
1102
1266
|
]
|
|
1103
1267
|
}),
|
|
1268
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1269
|
+
style: sectionStyle,
|
|
1270
|
+
children: [
|
|
1271
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1272
|
+
style: labelStyle,
|
|
1273
|
+
children: t("card.dryRun")
|
|
1274
|
+
}),
|
|
1275
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1276
|
+
style: hintStyle,
|
|
1277
|
+
children: t("card.dryRunHint")
|
|
1278
|
+
}),
|
|
1279
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1280
|
+
style: {
|
|
1281
|
+
display: "flex",
|
|
1282
|
+
flexWrap: "wrap",
|
|
1283
|
+
gap: "8px",
|
|
1284
|
+
alignItems: "flex-end",
|
|
1285
|
+
margin: "6px 0"
|
|
1286
|
+
},
|
|
1287
|
+
children: [
|
|
1288
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1289
|
+
style: {
|
|
1290
|
+
display: "flex",
|
|
1291
|
+
flexDirection: "column",
|
|
1292
|
+
gap: "4px",
|
|
1293
|
+
flex: "0 0 120px"
|
|
1294
|
+
},
|
|
1295
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1296
|
+
style: fieldLabelStyle,
|
|
1297
|
+
children: t("card.dryRunTool")
|
|
1298
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1299
|
+
type: "text",
|
|
1300
|
+
value: dryTool,
|
|
1301
|
+
disabled: readonly,
|
|
1302
|
+
placeholder: "shell",
|
|
1303
|
+
onChange: (e) => {
|
|
1304
|
+
setDryTool(e.target.value);
|
|
1305
|
+
},
|
|
1306
|
+
onKeyDown: (e) => {
|
|
1307
|
+
if (e.key === "Enter") runDryRunTest();
|
|
1308
|
+
},
|
|
1309
|
+
style: controlStyle
|
|
1310
|
+
})]
|
|
1311
|
+
}),
|
|
1312
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1313
|
+
style: {
|
|
1314
|
+
display: "flex",
|
|
1315
|
+
flexDirection: "column",
|
|
1316
|
+
gap: "4px",
|
|
1317
|
+
flex: "1 1 260px",
|
|
1318
|
+
minWidth: 0
|
|
1319
|
+
},
|
|
1320
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1321
|
+
style: fieldLabelStyle,
|
|
1322
|
+
children: t("card.dryRunCommand")
|
|
1323
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1324
|
+
type: "text",
|
|
1325
|
+
value: dryCommand,
|
|
1326
|
+
disabled: readonly,
|
|
1327
|
+
placeholder: t("card.dryRunCommandPlaceholder"),
|
|
1328
|
+
onChange: (e) => {
|
|
1329
|
+
setDryCommand(e.target.value);
|
|
1330
|
+
},
|
|
1331
|
+
onKeyDown: (e) => {
|
|
1332
|
+
if (e.key === "Enter") runDryRunTest();
|
|
1333
|
+
},
|
|
1334
|
+
style: controlStyle
|
|
1335
|
+
})]
|
|
1336
|
+
}),
|
|
1337
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1338
|
+
type: "button",
|
|
1339
|
+
disabled: readonly || dryBusy,
|
|
1340
|
+
onClick: runDryRunTest,
|
|
1341
|
+
style: {
|
|
1342
|
+
...controlStyle,
|
|
1343
|
+
flex: "0 0 auto",
|
|
1344
|
+
cursor: readonly || dryBusy ? "default" : "pointer"
|
|
1345
|
+
},
|
|
1346
|
+
children: dryBusy ? t("card.dryRunRunning") : t("card.dryRunTest")
|
|
1347
|
+
})
|
|
1348
|
+
]
|
|
1349
|
+
}),
|
|
1350
|
+
dryError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1351
|
+
style: {
|
|
1352
|
+
...hintStyle,
|
|
1353
|
+
color: "var(--dsw-alias-label-error, #c0392b)"
|
|
1354
|
+
},
|
|
1355
|
+
children: [t("card.dryRunFail"), dryError]
|
|
1356
|
+
}),
|
|
1357
|
+
dryReport === null ? dryError === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1358
|
+
style: hintStyle,
|
|
1359
|
+
children: t("card.dryRunEmpty")
|
|
1360
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1361
|
+
style: {
|
|
1362
|
+
display: "flex",
|
|
1363
|
+
flexDirection: "column",
|
|
1364
|
+
gap: "4px",
|
|
1365
|
+
padding: "8px 10px",
|
|
1366
|
+
borderRadius: "6px",
|
|
1367
|
+
border: "1px solid var(--dsw-alias-border-l2)",
|
|
1368
|
+
background: "var(--dsw-alias-bg-surface, transparent)",
|
|
1369
|
+
fontSize: "12px",
|
|
1370
|
+
lineHeight: "18px"
|
|
1371
|
+
},
|
|
1372
|
+
children: [
|
|
1373
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1374
|
+
style: {
|
|
1375
|
+
display: "flex",
|
|
1376
|
+
alignItems: "center",
|
|
1377
|
+
gap: "8px"
|
|
1378
|
+
},
|
|
1379
|
+
children: [
|
|
1380
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1381
|
+
style: fieldLabelStyle,
|
|
1382
|
+
children: t("card.dryRunVerdict")
|
|
1383
|
+
}),
|
|
1384
|
+
(() => {
|
|
1385
|
+
const verdict = dryReport.verdict ?? "ask";
|
|
1386
|
+
const colour = verdict === "deny" ? "var(--dsw-alias-label-error, #c0392b)" : verdict === "allow" ? "var(--dsw-alias-label-success, #2e7d32)" : "var(--dsw-alias-label-warning, #b26a00)";
|
|
1387
|
+
const text = verdict === "deny" ? t("card.dryRunDeny") : verdict === "allow" ? t("card.dryRunAllow") : t("card.dryRunAsk");
|
|
1388
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
1389
|
+
style: { color: colour },
|
|
1390
|
+
children: text
|
|
1391
|
+
});
|
|
1392
|
+
})(),
|
|
1393
|
+
(dryReport.ruleCount ?? 0) === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1394
|
+
style: { color: "var(--dsw-alias-label-secondary, inherit)" },
|
|
1395
|
+
children: t("card.dryRunNoRules")
|
|
1396
|
+
})
|
|
1397
|
+
]
|
|
1398
|
+
}),
|
|
1399
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1400
|
+
style: {
|
|
1401
|
+
display: "flex",
|
|
1402
|
+
gap: "8px",
|
|
1403
|
+
overflowWrap: "anywhere"
|
|
1404
|
+
},
|
|
1405
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1406
|
+
style: fieldLabelStyle,
|
|
1407
|
+
children: t("card.dryRunRule")
|
|
1408
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
1409
|
+
style: {
|
|
1410
|
+
font: "500 12px/18px var(--ds-font-family-code, monospace)",
|
|
1411
|
+
color: "var(--dsw-alias-label-primary)"
|
|
1412
|
+
},
|
|
1413
|
+
children: dryReport.ruleLayer?.ruleIndex === void 0 ? t("card.dryRunRuleNone").replace("%d", dryReport.defaultAction ?? "ask") : `#${dryReport.ruleLayer.ruleIndex} (${dryReport.ruleLayer.action ?? "?"})`
|
|
1414
|
+
})]
|
|
1415
|
+
}),
|
|
1416
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1417
|
+
style: {
|
|
1418
|
+
display: "flex",
|
|
1419
|
+
gap: "8px",
|
|
1420
|
+
overflowWrap: "anywhere"
|
|
1421
|
+
},
|
|
1422
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1423
|
+
style: fieldLabelStyle,
|
|
1424
|
+
children: t("card.dryRunDimensions")
|
|
1425
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
1426
|
+
style: {
|
|
1427
|
+
font: "500 12px/18px var(--ds-font-family-code, monospace)",
|
|
1428
|
+
color: "var(--dsw-alias-label-primary)"
|
|
1429
|
+
},
|
|
1430
|
+
children: (dryReport.ruleLayer?.matchedDimensions ?? []).length === 0 ? "—" : (dryReport.ruleLayer?.matchedDimensions ?? []).join(", ")
|
|
1431
|
+
})]
|
|
1432
|
+
}),
|
|
1433
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1434
|
+
style: {
|
|
1435
|
+
display: "flex",
|
|
1436
|
+
gap: "8px",
|
|
1437
|
+
overflowWrap: "anywhere"
|
|
1438
|
+
},
|
|
1439
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1440
|
+
style: fieldLabelStyle,
|
|
1441
|
+
children: t("card.dryRunReason")
|
|
1442
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1443
|
+
style: { color: "var(--dsw-alias-label-secondary, inherit)" },
|
|
1444
|
+
children: dryReport.reason ?? ""
|
|
1445
|
+
})]
|
|
1446
|
+
}),
|
|
1447
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1448
|
+
style: {
|
|
1449
|
+
...hintStyle,
|
|
1450
|
+
margin: 0
|
|
1451
|
+
},
|
|
1452
|
+
children: t("card.dryRunNote")
|
|
1453
|
+
})
|
|
1454
|
+
]
|
|
1455
|
+
})
|
|
1456
|
+
]
|
|
1457
|
+
}),
|
|
1458
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1459
|
+
style: sectionStyle,
|
|
1460
|
+
children: [
|
|
1461
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1462
|
+
style: {
|
|
1463
|
+
display: "flex",
|
|
1464
|
+
alignItems: "center",
|
|
1465
|
+
justifyContent: "space-between",
|
|
1466
|
+
gap: "8px"
|
|
1467
|
+
},
|
|
1468
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1469
|
+
style: labelStyle,
|
|
1470
|
+
children: t("card.rules")
|
|
1471
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1472
|
+
type: "button",
|
|
1473
|
+
disabled: rulesBusy,
|
|
1474
|
+
onClick: loadRules,
|
|
1475
|
+
style: {
|
|
1476
|
+
...controlStyle,
|
|
1477
|
+
flex: "0 0 auto",
|
|
1478
|
+
cursor: rulesBusy ? "default" : "pointer"
|
|
1479
|
+
},
|
|
1480
|
+
children: rulesBusy ? t("card.rulesLoading") : t("card.rulesRefresh")
|
|
1481
|
+
})]
|
|
1482
|
+
}),
|
|
1483
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1484
|
+
style: hintStyle,
|
|
1485
|
+
children: t("card.rulesHint")
|
|
1486
|
+
}),
|
|
1487
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1488
|
+
style: {
|
|
1489
|
+
display: "flex",
|
|
1490
|
+
gap: "8px",
|
|
1491
|
+
overflowWrap: "anywhere",
|
|
1492
|
+
marginTop: "6px"
|
|
1493
|
+
},
|
|
1494
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1495
|
+
style: fieldLabelStyle,
|
|
1496
|
+
children: t("card.rulesPath")
|
|
1497
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
1498
|
+
style: {
|
|
1499
|
+
font: "500 12px/18px var(--ds-font-family-code, monospace)",
|
|
1500
|
+
color: "var(--dsw-alias-label-primary)"
|
|
1501
|
+
},
|
|
1502
|
+
children: rulesBody?.path !== void 0 && rulesBody.path !== "" ? rulesBody.path : t("card.rulesNone")
|
|
1503
|
+
})]
|
|
1504
|
+
}),
|
|
1505
|
+
rulesError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1506
|
+
style: {
|
|
1507
|
+
...hintStyle,
|
|
1508
|
+
color: "var(--dsw-alias-label-error, #c0392b)"
|
|
1509
|
+
},
|
|
1510
|
+
children: [t("card.rulesError"), rulesError]
|
|
1511
|
+
}),
|
|
1512
|
+
rulesBody !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1513
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1514
|
+
style: {
|
|
1515
|
+
display: "flex",
|
|
1516
|
+
flexWrap: "wrap",
|
|
1517
|
+
gap: "12px",
|
|
1518
|
+
marginTop: "4px"
|
|
1519
|
+
},
|
|
1520
|
+
children: [
|
|
1521
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1522
|
+
style: fieldLabelStyle,
|
|
1523
|
+
children: [t("card.rulesCounts"), " "]
|
|
1524
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
1525
|
+
style: {
|
|
1526
|
+
font: "500 12px/18px var(--ds-font-family-code, monospace)",
|
|
1527
|
+
color: "var(--dsw-alias-label-primary)"
|
|
1528
|
+
},
|
|
1529
|
+
children: `deny ${rulesBody.counts?.deny ?? 0} · allow ${rulesBody.counts?.allow ?? 0} · ask ${rulesBody.counts?.ask ?? 0}`
|
|
1530
|
+
})] }),
|
|
1531
|
+
rulesBody.defaultAction !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1532
|
+
style: fieldLabelStyle,
|
|
1533
|
+
children: [t("card.rulesDefault"), " "]
|
|
1534
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
1535
|
+
style: {
|
|
1536
|
+
font: "500 12px/18px var(--ds-font-family-code, monospace)",
|
|
1537
|
+
color: "var(--dsw-alias-label-primary)"
|
|
1538
|
+
},
|
|
1539
|
+
children: rulesBody.defaultAction
|
|
1540
|
+
})] }),
|
|
1541
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1542
|
+
style: fieldLabelStyle,
|
|
1543
|
+
children: t("card.rulesStats").replace("%b", String(rulesBody.bytes ?? 0)).replace("%l", String(rulesBody.lines ?? 0))
|
|
1544
|
+
})
|
|
1545
|
+
]
|
|
1546
|
+
}),
|
|
1547
|
+
rulesBody.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1548
|
+
style: {
|
|
1549
|
+
...hintStyle,
|
|
1550
|
+
color: "var(--dsw-alias-label-error, #c0392b)"
|
|
1551
|
+
},
|
|
1552
|
+
children: rulesBody.error
|
|
1553
|
+
}),
|
|
1554
|
+
rulesBody.exists === false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1555
|
+
style: hintStyle,
|
|
1556
|
+
children: t("card.rulesMissing")
|
|
1557
|
+
}),
|
|
1558
|
+
rulesBody.truncated === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1559
|
+
style: hintStyle,
|
|
1560
|
+
children: t("card.rulesTruncated")
|
|
1561
|
+
}),
|
|
1562
|
+
(rulesBody.raw ?? "") !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
1563
|
+
style: {
|
|
1564
|
+
margin: "6px 0 0",
|
|
1565
|
+
padding: "8px 10px",
|
|
1566
|
+
maxHeight: "260px",
|
|
1567
|
+
overflow: "auto",
|
|
1568
|
+
borderRadius: "6px",
|
|
1569
|
+
border: "1px solid var(--dsw-alias-border-l2)",
|
|
1570
|
+
background: "var(--dsw-alias-bg-surface, transparent)",
|
|
1571
|
+
font: "500 12px/18px var(--ds-font-family-code, monospace)",
|
|
1572
|
+
color: "var(--dsw-alias-label-primary)",
|
|
1573
|
+
whiteSpace: "pre"
|
|
1574
|
+
},
|
|
1575
|
+
children: rulesBody.raw
|
|
1576
|
+
}),
|
|
1577
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1578
|
+
style: {
|
|
1579
|
+
...hintStyle,
|
|
1580
|
+
margin: 0
|
|
1581
|
+
},
|
|
1582
|
+
children: t("card.rulesNote")
|
|
1583
|
+
})
|
|
1584
|
+
] })
|
|
1585
|
+
]
|
|
1586
|
+
}),
|
|
1104
1587
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1105
1588
|
style: sectionStyle,
|
|
1106
1589
|
children: [
|
|
@@ -1404,6 +1887,106 @@ window.__ModuleLoader__.load({
|
|
|
1404
1887
|
}) : null
|
|
1405
1888
|
]
|
|
1406
1889
|
}),
|
|
1890
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1891
|
+
style: sectionStyle,
|
|
1892
|
+
children: [
|
|
1893
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1894
|
+
style: labelStyle,
|
|
1895
|
+
children: t("card.networkEnabled")
|
|
1896
|
+
}),
|
|
1897
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1898
|
+
style: hintStyle,
|
|
1899
|
+
children: t("card.networkEnabledHint")
|
|
1900
|
+
}),
|
|
1901
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1902
|
+
style: {
|
|
1903
|
+
display: "flex",
|
|
1904
|
+
alignItems: "center",
|
|
1905
|
+
gap: "8px",
|
|
1906
|
+
marginTop: "6px"
|
|
1907
|
+
},
|
|
1908
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1909
|
+
type: "checkbox",
|
|
1910
|
+
checked: value.networkEnabled === true,
|
|
1911
|
+
disabled: readonly,
|
|
1912
|
+
onChange: (event) => {
|
|
1913
|
+
scope.set("networkEnabled", event.currentTarget.checked);
|
|
1914
|
+
}
|
|
1915
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1916
|
+
style: { fontSize: "13px" },
|
|
1917
|
+
children: value.networkEnabled === true ? "ON" : "OFF"
|
|
1918
|
+
})]
|
|
1919
|
+
}),
|
|
1920
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1921
|
+
style: hintStyle,
|
|
1922
|
+
children: t("card.networkRebindNote")
|
|
1923
|
+
})
|
|
1924
|
+
]
|
|
1925
|
+
}),
|
|
1926
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1927
|
+
style: sectionStyle,
|
|
1928
|
+
children: [
|
|
1929
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1930
|
+
style: labelStyle,
|
|
1931
|
+
children: t("card.networkInjectEnv")
|
|
1932
|
+
}),
|
|
1933
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1934
|
+
style: hintStyle,
|
|
1935
|
+
children: t("card.networkInjectEnvHint")
|
|
1936
|
+
}),
|
|
1937
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1938
|
+
style: {
|
|
1939
|
+
display: "flex",
|
|
1940
|
+
alignItems: "center",
|
|
1941
|
+
gap: "8px",
|
|
1942
|
+
marginTop: "6px"
|
|
1943
|
+
},
|
|
1944
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1945
|
+
type: "checkbox",
|
|
1946
|
+
checked: value.networkInjectEnv !== false,
|
|
1947
|
+
disabled: readonly,
|
|
1948
|
+
onChange: (event) => {
|
|
1949
|
+
scope.set("networkInjectEnv", event.currentTarget.checked);
|
|
1950
|
+
}
|
|
1951
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1952
|
+
style: { fontSize: "13px" },
|
|
1953
|
+
children: value.networkInjectEnv !== false ? "ON" : "OFF"
|
|
1954
|
+
})]
|
|
1955
|
+
})
|
|
1956
|
+
]
|
|
1957
|
+
}),
|
|
1958
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1959
|
+
style: sectionStyle,
|
|
1960
|
+
children: [
|
|
1961
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1962
|
+
style: labelStyle,
|
|
1963
|
+
children: t("card.watch")
|
|
1964
|
+
}),
|
|
1965
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1966
|
+
style: hintStyle,
|
|
1967
|
+
children: t("card.watchHint")
|
|
1968
|
+
}),
|
|
1969
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1970
|
+
style: {
|
|
1971
|
+
display: "flex",
|
|
1972
|
+
alignItems: "center",
|
|
1973
|
+
gap: "8px",
|
|
1974
|
+
marginTop: "6px"
|
|
1975
|
+
},
|
|
1976
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1977
|
+
type: "checkbox",
|
|
1978
|
+
checked: value.watch !== false,
|
|
1979
|
+
disabled: readonly,
|
|
1980
|
+
onChange: (event) => {
|
|
1981
|
+
scope.set("watch", event.currentTarget.checked);
|
|
1982
|
+
}
|
|
1983
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1984
|
+
style: { fontSize: "13px" },
|
|
1985
|
+
children: value.watch !== false ? "ON" : "OFF"
|
|
1986
|
+
})]
|
|
1987
|
+
})
|
|
1988
|
+
]
|
|
1989
|
+
}),
|
|
1407
1990
|
!snapshot.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1408
1991
|
style: {
|
|
1409
1992
|
margin: "8px 0 0",
|
|
@@ -1480,6 +2063,12 @@ window.__ModuleLoader__.load({
|
|
|
1480
2063
|
tag: "CANCELLED",
|
|
1481
2064
|
sticky: false
|
|
1482
2065
|
};
|
|
2066
|
+
case "stand-down": return {
|
|
2067
|
+
color: "var(--dsw-alias-state-warn-label, #b9770e)",
|
|
2068
|
+
bg: "var(--dsw-alias-state-warn-tertiary, rgba(185,119,14,0.14))",
|
|
2069
|
+
tag: "GATE OFF",
|
|
2070
|
+
sticky: true
|
|
2071
|
+
};
|
|
1483
2072
|
default: return {
|
|
1484
2073
|
color: "var(--dsw-alias-state-success-primary, #1e8449)",
|
|
1485
2074
|
bg: "var(--dsw-alias-state-success-tertiary, rgba(30,132,73,0.08))",
|
|
@@ -1509,7 +2098,9 @@ window.__ModuleLoader__.load({
|
|
|
1509
2098
|
"human-approved": "人工通过",
|
|
1510
2099
|
"human-rejected": "人工拒绝",
|
|
1511
2100
|
"human-cancelled": "人工取消",
|
|
1512
|
-
"no-approval-channel": "无审批通道"
|
|
2101
|
+
"no-approval-channel": "无审批通道",
|
|
2102
|
+
"preset-passthrough": "审批策略 never · 已放行",
|
|
2103
|
+
"stand-down": "门禁停用"
|
|
1513
2104
|
};
|
|
1514
2105
|
/** Compact wall-clock rendering of an ISO timestamp. */
|
|
1515
2106
|
function clockTime(iso) {
|
|
@@ -1765,7 +2356,8 @@ window.__ModuleLoader__.load({
|
|
|
1765
2356
|
learned: "history.tag.learned",
|
|
1766
2357
|
"manual-approved": "history.tag.manualApproved",
|
|
1767
2358
|
"manual-rejected": "history.tag.manualRejected",
|
|
1768
|
-
"manual-cancelled": "history.tag.manualCancelled"
|
|
2359
|
+
"manual-cancelled": "history.tag.manualCancelled",
|
|
2360
|
+
"stand-down": "history.tag.standDown"
|
|
1769
2361
|
};
|
|
1770
2362
|
/** The file name alone (chips show the basename, like the reference page). */
|
|
1771
2363
|
function basename(p) {
|