dsh-decision-layer 0.6.4 → 0.7.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/lib/client.js CHANGED
@@ -32,324 +32,397 @@ __export(index_exports, {
32
32
  module.exports = __toCommonJS(index_exports);
33
33
 
34
34
  // src/client/i18n.ts
35
- var dictionaries = {
36
- zh: {
37
- summary: "\u5371\u9669\u8C03\u7528\u95E8\u63A7\u3001\u4EA7\u51FA\u81EA\u68C0\u4E0E\u9632\u5FAA\u73AF\uFF0C\u7531\u53EF\u63D2\u62D4\u88C1\u51B3\u6A21\u578B\u9A71\u52A8\u3002",
38
- button: "\u51B3\u7B56\u5C42",
39
- title: "\u51B3\u7B56\u5C42",
40
- close: "\u5173\u95ED",
41
- metrics: "\u81EA\u52A8\u88C1\u51B3\u7EDF\u8BA1",
42
- triggerDecisions: "\u51B3\u7B56",
43
- empty: "\u5C1A\u65E0\u81EA\u52A8\u88C1\u51B3\u3002\u624B\u52A8\u88C1\u51B3\u4E0D\u8BA1\u5165\u8FD9\u91CC\u3002",
44
- attempts: "\u8BC4\u4F30\u6B21\u6570",
45
- failures: "\u5931\u8D25\u56DE\u9000",
46
- suggestions: "\u6A21\u578B\u5EFA\u8BAE\uFF08\u653E\u884C / \u8BE2\u95EE / \u62D2\u7EDD\uFF09",
47
- actual: "\u5B9E\u9645\u5BBF\u4E3B\u7ED3\u679C\uFF08\u653E\u884C / \u62D2\u7EDD\uFF09",
48
- checkAttempts: "\u81EA\u68C0\u8BC4\u4F30\u6B21\u6570",
49
- checkLow: "\u4F4E\u5206",
50
- checkOk: "\u901A\u8FC7",
51
- settings: "\u4F1A\u8BDD\u8BBE\u7F6E",
52
- cardGate: "\u5371\u9669\u95E8\u63A7",
53
- cardCheck: "\u4EA7\u51FA\u81EA\u68C0",
54
- cardNarrow: "\u5DE5\u5177\u6536\u7A84",
55
- cardComplete: "\u5B8C\u6210\u6838\u5BF9",
56
- cardTimes: " \u6B21",
57
- allow: "\u653E\u884C",
58
- ask: "\u8BE2\u95EE",
59
- deny: "\u62D2\u7EDD",
60
- actualShort: "\u5B9E\u9645\u7ED3\u679C",
61
- narrowAppliedLabel: "\u6536\u7A84",
62
- narrowDroppedLabel: "\u6458\u9664\u5DE5\u5177",
63
- narrowDropped: "\u6458\u9664",
64
- narrowKept: "\u672A\u6536\u7A84",
65
- narrowKeptCount: "\u4FDD\u7559",
66
- narrowMore: " \u7B49 {count} \u4E2A",
67
- narrowObserve: "\u4EC5\u89C2\u5BDF",
68
- narrowEnforce: "\u5DF2\u751F\u6548",
69
- checkPassRate: "\u901A\u8FC7\u7387",
70
- narrowApplyRate: "\u6536\u7A84\u7387",
71
- rateNa: "\u2014",
72
- enabled: "\u672C\u4F1A\u8BDD\u5185\u542F\u7528\u81EA\u52A8\u4ECB\u5165",
73
- backendStatus: "\u540E\u7AEF\u8FDE\u63A5",
74
- statusChecking: "\u68C0\u6D4B\u4E2D\u2026",
75
- statusIdle: "\u672A\u68C0\u6D4B",
76
- statusOk: "\u6B63\u5E38",
77
- statusDown: "\u4E0D\u53EF\u7528",
78
- recheck: "\u91CD\u65B0\u68C0\u6D4B",
79
- log: "\u51B3\u7B56\u65E5\u5FD7",
80
- logEmpty: "\u672C\u4F1A\u8BDD\u5C1A\u65E0\u51B3\u7B56\u8BB0\u5F55\u3002",
81
- logGate: "\u95E8\u63A7",
82
- logCheck: "\u81EA\u68C0",
83
- logNarrow: "\u6536\u7A84",
84
- logComplete: "\u5B8C\u6210\u6838\u5BF9",
85
- logSuggested: "\u6A21\u578B\u5EFA\u8BAE",
86
- logEvalFailed: "\u8BC4\u4F30\u5931\u8D25",
87
- logScore: "\u5F97\u5206",
88
- logConnection: "\u8FDE\u63A5",
89
- logConfidence: "\u7F6E\u4FE1\u5EA6",
90
- logCommandLabel: "\u547D\u4EE4\uFF1A",
91
- logPathLabel: "\u8DEF\u5F84\uFF1A",
92
- logSubjectLabel: "\u8BF7\u6C42\uFF1A",
93
- logScoreHint: "\u5F97\u5206\u4E3A\u5404\u6863\u4F4D\u6309\u6982\u7387\u52A0\u6743\u7684\u7ED3\u679C\uFF0C\u53EF\u80FD\u662F\u5C0F\u6570\uFF08\u5982 1.4\uFF09\uFF0C\u6EE1\u5206\u4E3A\u9876\u6863\u53F7 2\u3002",
94
- logCheckHint: "\u6BCF\u56DE\u5408\u7ED3\u675F\u540E\uFF0C\u628A\u8FD9\u8F6E AI \u7684\u6700\u7EC8\u56DE\u590D\u4EA4\u7ED9\u88C1\u51B3\u6A21\u578B\uFF0C\u6309\u300C\u4E25\u91CD\u9057\u6F0F/\u81EA\u76F8\u77DB\u76FE \u2192 \u6709\u5C0F\u9057\u6F0F \u2192 \u5B8C\u6574\u51C6\u786E\u300D\u4E09\u6863\u6253\u4E00\u4E2A 0\u20132 \u7684\u8D28\u91CF\u5206\uFF0C\u7528\u6765\u53D1\u73B0\u9057\u6F0F\u6216\u77DB\u76FE\u3002",
95
- logNarrowHint: "\u6BCF\u56DE\u5408\u5F00\u59CB\u65F6\uFF0C\u628A\u8FD9\u8F6E\u4EFB\u52A1\u4E0E\u5F53\u524D\u53EF\u7528\u5DE5\u5177\u9010\u4E2A\u4EA4\u7ED9\u88C1\u51B3\u6A21\u578B\u5224\u65AD\u76F8\u5173\u6027\uFF08noul\uFF09\uFF0C\u6458\u6389\u660E\u663E\u7528\u4E0D\u4E0A\u7684\u5DE5\u5177\uFF0C\u53EA\u5728\u5F53\u524D\u5BBF\u4E3B\u5DF2\u5141\u8BB8\u7684\u96C6\u5408\u5185\u53D6\u4EA4\u96C6\u3001\u7EDD\u4E0D\u6269\u6743\uFF1B\u300C\u4EC5\u89C2\u5BDF\u300D\u53EA\u8BB0\u5F55\u5EFA\u8BAE\uFF0C\u300C\u5DF2\u751F\u6548\u300D\u624D\u771F\u6B63\u5BF9\u672C\u56DE\u5408\u9650\u5236\u5DE5\u5177\u3002",
96
- actionDeny: "\u5DF2\u62D2\u7EDD",
97
- actionAsk: "\u8F6C\u4EA4\u5BA1\u6279",
98
- actionPass: "\u672A\u5E72\u9884",
99
- gatePassThrough: "\u672A\u5E72\u9884\uFF08\u6309\u539F\u8DEF\u5F84\u6267\u884C\uFF09",
100
- checkResultLow: "\u5F97\u5206\u504F\u4F4E",
101
- checkResultOk: "\u901A\u8FC7",
102
- checkResultLowNoisy: "\u5F97\u5206\u504F\u4F4E\uFF08\u4F4E\u7F6E\u4FE1\uFF09",
103
- checkNoiseTag: "\u566A\u58F0\uFF0C\u53EF\u5FFD\u7565",
104
- checkNoiseHint: "\u6A21\u578B\u5BF9\u8FD9\u6B21\u6253\u5206\u51E0\u4E4E\u6CA1\u6709\u628A\u63E1\uFF08\u7F6E\u4FE1\u5EA6\u6781\u4F4E\uFF09\uFF0C\u8FD9\u6761\u4F4E\u5206\u4E0D\u8BA1\u5165\u8D28\u91CF\u8D8B\u52BF\u3001\u4E5F\u4E0D\u89E6\u53D1\u4EFB\u4F55\u8865\u5B8C\uFF0C\u89C6\u4F5C\u566A\u58F0\u5FFD\u7565\u5373\u53EF\u3002\u771F\u6B63\u503C\u5F97\u5173\u6CE8\u7684\u662F\u8FDE\u7EED\u591A\u6B21\u9AD8\u7F6E\u4FE1\u7684\u4F4E\u5206\u3002",
105
- reasonUnavailable: "\u540E\u7AEF\u4E0D\u53EF\u8FBE",
106
- reasonHttpError: "\u540E\u7AEF\u8FD4\u56DE\u9519\u8BEF",
107
- reasonInvalidResponse: "\u54CD\u5E94\u683C\u5F0F\u4E0D\u7B26",
108
- reasonLowConfidence: "\u7F6E\u4FE1\u5EA6\u4E0D\u8DB3",
109
- reasonConfig: "\u914D\u7F6E\u65E0\u6548",
110
- reasonTooMany: "\u5019\u9009\u8FC7\u591A",
111
- reasonTooManyCount: "\u5019\u9009 {count} \u4E2A\u504F\u591A",
112
- reasonLowKeep: "\u4FDD\u7559\u8FC7\u5C11\uFF0C\u672A\u751F\u6548",
113
- selfCheck: "\u4EA7\u51FA\u81EA\u68C0",
114
- advancedSwitches: "\u4ECB\u5165\u5F00\u5173",
115
- advancedParams: "\u6536\u7A84\u53C2\u6570",
116
- selfCheckSteer: "\u5F97\u5206\u504F\u4F4E\u65F6\u81EA\u52A8\u8865\u4E00\u8F6E",
117
- selfCheckHint: "\u6BCF\u56DE\u5408\u7ED3\u675F\u7ED9\u6700\u7EC8\u56DE\u590D\u6253\u5206\uFF080\u20132\uFF0C\u6309\u5404\u6863\u4F4D\u6982\u7387\u52A0\u6743\uFF0C\u53EF\u80FD\u662F\u5C0F\u6570\u5982 1.4\uFF09\u3002\u5173\u95ED\uFF1A\u53EA\u628A\u4F4E\u5206\u8BB0\u8FDB\u65E5\u5FD7\u548C\u7EDF\u8BA1\uFF0C\u4E0D\u6253\u65AD\u5BF9\u8BDD\u3002\u5F00\u542F\uFF1A\u5F97\u5206\u504F\u4F4E\uFF08\u22641\uFF09\u4E14\u6A21\u578B\u6709\u628A\u63E1\u65F6\uFF0C\u81EA\u52A8\u4EE5\u4F60\u7684\u540D\u4E49\u8FFD\u52A0\u4E00\u6761\u63D0\u793A\uFF0C\u8BA9 AI \u590D\u6838\u6709\u65E0\u9057\u6F0F\u6216\u77DB\u76FE\u5E76\u8865\u5B8C\uFF1B\u7F6E\u4FE1\u5EA6\u504F\u4F4E\u7684\u6253\u5206\u53EA\u8BB0\u5F55\u3001\u4E0D\u6253\u65AD\uFF0C\u540C\u4E00\u56DE\u5408\u6700\u591A\u8865\u4E00\u6B21\u3002",
118
- narrow: "\u5DE5\u5177\u6536\u7A84",
119
- narrowObserveLabel: "\u4EC5\u89C2\u5BDF\uFF08\u4E0D\u771F\u6B63\u9650\u5236\u5DE5\u5177\uFF09",
120
- narrowHint: "\u6BCF\u56DE\u5408\u5F00\u59CB\u65F6\uFF0C\u7528\u88C1\u51B3\u6A21\u578B\u5224\u65AD\u5F53\u524D\u53EF\u9009\u5DE5\u5177\u4E0E\u8FD9\u8F6E\u4EFB\u52A1\u7684\u76F8\u5173\u6027\uFF0C\u6458\u6389\u7528\u4E0D\u4E0A\u7684\uFF1B\u8BFB\u5199\u3001\u7F16\u8F91\u3001Shell\u3001\u68C0\u7D22\u3001\u5F85\u529E\u7B49\u6838\u5FC3\u5DE5\u5177\u59CB\u7EC8\u4FDD\u7559\u3001\u4E0D\u53C2\u4E0E\u5224\u5B9A\u3002\u9ED8\u8BA4\u771F\u6B63\u751F\u6548\uFF1A\u672C\u56DE\u5408\u53EA\u4FDD\u7559\u5224\u4E3A\u76F8\u5173\u7684\u5DE5\u5177\uFF0C\u4E14\u53EA\u5728\u5BBF\u4E3B\u5DF2\u5141\u8BB8\u7684\u8303\u56F4\u5185\u53D6\u4EA4\u96C6\u3001\u4E0D\u6269\u6743\u3002\u5F00\u542F\u300C\u4EC5\u89C2\u5BDF\u300D\u540E\u53EA\u628A\u53EF\u6458\u6389\u7684\u5DE5\u5177\u8BB0\u8FDB\u65E5\u5FD7\u548C\u7EDF\u8BA1\uFF0C\u4E0D\u6539\u52A8\u5DE5\u5177\u96C6\u3002\u4E09\u91CD\u4FDD\u62A4\uFF1A\u6838\u5FC3\u5DE5\u5177\u59CB\u7EC8\u4FDD\u7559\uFF1B\u53EF\u9009\u5DE5\u5177\u8D85\u8FC7 20 \u4E2A\u65F6\u81EA\u52A8\u53EA\u89C2\u5BDF\u4E0D\u9650\u5236\uFF1B\u4FDD\u7559\u4E0B\u6765\u4E0D\u8DB3 5 \u4E2A\u65F6\u89C6\u4E3A\u5224\u5B9A\u4E0D\u53EF\u4FE1\u3001\u8DF3\u8FC7\u3002",
121
- narrowKeepLabel: "\u59CB\u7EC8\u4FDD\u7559\u7684\u5DE5\u5177\u524D\u7F00",
122
- narrowKeepHint: "\u540D\u5B57\u4EE5\u8FD9\u4E9B\u524D\u7F00\u5F00\u5934\u7684\u5DE5\u5177\u6C38\u8FDC\u4FDD\u7559\u3001\u4E0D\u53C2\u4E0E\u76F8\u5173\u6027\u5224\u5B9A\uFF0C\u9002\u5408\u8BB0\u5FC6/\u68C0\u7D22\u8FD9\u7C7B\u300C\u5E38\u9A7B\u3001\u6309\u9700\u89E6\u53D1\u300D\u7684\u5DE5\u5177\uFF08\u9ED8\u8BA4\u542B mcp__openviking\u3001team_task_\uFF09\u3002\u7528\u82F1\u6587\u9017\u53F7\u6216\u6362\u884C\u5206\u9694\u591A\u4E2A\u524D\u7F00\uFF1B\u7559\u7A7A\u5219\u4E0D\u989D\u5916\u4FDD\u7559\u3002",
123
- narrowMaxLabel: "\u5019\u9009\u5DE5\u5177\u4E0A\u9650",
124
- narrowMaxHint: "\u4E00\u56DE\u5408\u91CC\u53C2\u4E0E\u5224\u5B9A\u7684\u300C\u53EF\u9009\u5DE5\u5177\u300D\u8D85\u8FC7\u8FD9\u4E2A\u6570\uFF08\u9ED8\u8BA4 20\uFF09\uFF0C\u5C31\u81EA\u52A8\u964D\u7EA7\u4E3A\u4EC5\u89C2\u5BDF\u3001\u4E0D\u771F\u6B63\u6536\u7A84\uFF0C\u907F\u514D\u4E00\u6B21\u585E\u592A\u591A\u5DE5\u5177\u8BA9\u6A21\u578B\u8BEF\u6458\u3002\u53D6\u503C 1\u2013200\uFF0C\u8C03\u5927\u66F4\u503E\u5411\u771F\u6B63\u6536\u7A84\u3002\u6838\u5FC3\u5DE5\u5177\u4E0E\u4FDD\u7559\u524D\u7F00\u547D\u4E2D\u7684\u5DE5\u5177\u4E0D\u8BA1\u5165\u3002",
125
- narrowThresholdLabel: "\u6458\u9664\u9608\u503C",
126
- narrowThresholdHint: "\u76F8\u5173\u6027\u6982\u7387\u4F4E\u4E8E\u8FD9\u4E2A\u503C\u624D\u6458\u6389\u5DE5\u5177\uFF08\u9ED8\u8BA4 0.3\uFF09\u3002\u6982\u7387\u63A5\u8FD1 0.5 \u8868\u793A\u6A21\u578B\u62FF\u4E0D\u51C6\u3001\u5E76\u975E\u300C\u4E2D\u7B49\u76F8\u5173\u300D\uFF0C\u6B64\u65F6\u4FDD\u7559\u66F4\u7A33\u59A5\uFF1B\u8C03\u4F4E\u66F4\u4FDD\u5B88\uFF08\u5C11\u6458\u3001\u5B81\u53EF\u591A\u7559\uFF09\uFF0C\u8C03\u9AD8\u66F4\u6FC0\u8FDB\uFF08\u591A\u6458\uFF09\u3002\u53D6\u503C 0\u20131\u3002",
127
- features: "\u51B3\u7B56\u70B9\u5F00\u5173",
128
- basicFeatures: "\u57FA\u7840\u529F\u80FD",
129
- advancedConfig: "\u9AD8\u7EA7\u914D\u7F6E",
130
- featureGate: "\u5371\u9669\u95E8\u63A7",
131
- featureGateHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5BF9\u7834\u574F\u6027\u5DE5\u5177\u8C03\u7528\u505A\u62E6\u622A\u8BC4\u4F30\uFF0C\u8C03\u7528\u53EA\u53D7\u5BBF\u4E3B\u539F\u751F\u6743\u9650\u7EA6\u675F\u3002",
132
- featureCheck: "\u4EA7\u51FA\u81EA\u68C0",
133
- featureCheckHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u7ED3\u675F\u65F6\u7ED9\u6700\u7EC8\u56DE\u590D\u6253\u5206\u3002",
134
- featureNarrow: "\u5DE5\u5177\u6536\u7A84",
135
- featureNarrowHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u5F00\u59CB\u65F6\u8BC4\u4F30\u5DE5\u5177\u76F8\u5173\u6027\u3002\u9632\u5FAA\u73AF\u4E3A\u786E\u5B9A\u6027\u672C\u5730\u4FDD\u62A4\uFF0C\u59CB\u7EC8\u751F\u6548\uFF0C\u4E0D\u5728\u6B64\u5F00\u5173\u8303\u56F4\u3002",
136
- featureComplete: "\u4EFB\u52A1\u5B8C\u6210\u6838\u5BF9",
137
- featureCompleteHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u7ED3\u675F\u65F6\u9010\u9879\u6838\u5BF9\u7528\u6237\u660E\u786E\u5217\u51FA\u7684\u4EA4\u4ED8\u6761\u4EF6\u3002",
138
- trendWarnHint: "\u672C\u4F1A\u8BDD\u6700\u8FD1\u8FDE\u7EED\u51E0\u8F6E\u4EA7\u51FA\u8D28\u91CF\u504F\u4F4E\uFF08\u9AD8\u7F6E\u4FE1\uFF09\u3002\u53EF\u80FD\u662F\u4EFB\u52A1\u96BE\u5EA6\u4E0A\u5347\u6216\u6A21\u578B\u72B6\u6001\u6CE2\u52A8\uFF0C\u5EFA\u8BAE\u5C1D\u8BD5\u8C03\u6574 prompt \u6216\u66F4\u6362\u6A21\u578B\u3002",
139
- trendSevereHint: "\u672C\u4F1A\u8BDD\u4EA7\u51FA\u8D28\u91CF\u6301\u7EED\u504F\u4F4E\uFF08\u9AD8\u7F6E\u4FE1\uFF09\u3002\u5EFA\u8BAE\u8C03\u6574 prompt \u6216\u66F4\u6362\u6A21\u578B\uFF0C\u6216\u91CD\u5F00\u4F1A\u8BDD\u3002",
140
- rateGroup: "\u6807\u6CE8\u8FD9\u6B21\u5224\u65AD",
141
- rateGood: "\u5224\u5BF9\u4E86",
142
- rateBad: "\u5224\u9519\u4E86",
143
- rateUnsure: "\u8BF4\u4E0D\u51C6",
144
- rateSummary: "\u5DF2\u6807\u6CE8 {rated} \u6761\uFF08\u5224\u5BF9 {good} / \u5224\u9519 {bad} / \u8BF4\u4E0D\u51C6 {unsure}\uFF09",
145
- annotateFailed: "\u6807\u6CE8\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
146
- completeSteer: "\u6709\u672A\u6EE1\u8DB3\u6761\u4EF6\u65F6\u81EA\u52A8\u8865\u4E00\u8F6E",
147
- completeHint: "\u56DE\u5408\u7ED3\u675F\u65F6\uFF0C\u5BF9\u7528\u6237\u660E\u786E\u5217\u51FA\u7684\u591A\u4E2A\u4EA4\u4ED8\u6761\u4EF6\uFF08\u7F16\u53F7 / \u9879\u76EE\u7B26\u53F7 / \u591A\u547D\u4EE4\uFF09\u9010\u9879\u5224\u5B9A\u300C\u5DF2\u6EE1\u8DB3 / \u672A\u6EE1\u8DB3 / \u8BC1\u636E\u4E0D\u8DB3\u300D\uFF0C\u4EE5\u5DE5\u5177\u8BC1\u636E\u4E3A\u51C6\u3001\u56DE\u590D\u81EA\u79F0\u5B8C\u6210\u4E0D\u7B97\u8BC1\u636E\u3002\u5173\u95ED\uFF1A\u53EA\u628A\u7ED3\u679C\u8BB0\u8FDB\u65E5\u5FD7\u548C\u7EDF\u8BA1\uFF0C\u4E0D\u6253\u65AD\u5BF9\u8BDD\u3002\u5F00\u542F\uFF1A\u786E\u6709\u6761\u4EF6\u88AB\u5224\u300C\u672A\u6EE1\u8DB3\u300D\u4E14\u6A21\u578B\u6709\u628A\u63E1\u65F6\uFF0C\u81EA\u52A8\u4EE5\u4F60\u7684\u540D\u4E49\u8FFD\u52A0\u4E00\u6761\u63D0\u793A\u8BA9 AI \u590D\u6838\u8865\u5B8C\uFF1B\u300C\u8BC1\u636E\u4E0D\u8DB3\u300D\u4E0D\u89E6\u53D1\u8865\u5B8C\uFF0C\u540C\u4E00\u56DE\u5408\u6700\u591A\u8865\u4E00\u6B21\u3002",
148
- completeResultOk: "\u6761\u4EF6\u9F50\u5907",
149
- completeResultUnsatisfied: "\u6709\u672A\u6EE1\u8DB3",
150
- completeConditions: "\u6761\u4EF6",
151
- completeSatisfied: "\u6EE1\u8DB3",
152
- completeUnsatisfied: "\u672A\u6EE1\u8DB3",
153
- completeInsufficient: "\u8BC1\u636E\u4E0D\u8DB3",
154
- completeSteered: "\u5DF2\u8865\u4E00\u8F6E",
155
- backend: "\u88C1\u51B3\u540E\u7AEF",
156
- url: "\u670D\u52A1\u5730\u5740",
157
- model: "\u6A21\u578B",
158
- key: "API Key",
159
- keyHintSaved: "\u5DF2\u4FDD\u5B58\u4E00\u4E2A Key\u3002\u7559\u7A7A\u5E76\u4FDD\u5B58\uFF1D\u6CBF\u7528\u5B83\uFF08\u4E0D\u6539\u52A8\uFF09\uFF1B\u586B\u65B0\u503C\u5E76\u4FDD\u5B58\uFF1D\u8986\u76D6\u5B83\u3002",
160
- keyHintEmpty: "\u5C1A\u672A\u4FDD\u5B58 Key\u3002\u7559\u7A7A\u5219\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u91CC\u7684 Key\uFF1B\u586B\u5165\u5219\u4FDD\u5B58\u5230\u672C\u673A\u3002",
161
- removeKey: "\u5220\u9664\u5DF2\u4FDD\u5B58\u7684 Key",
162
- removeKeyHint: "\u628A\u672C\u63D2\u4EF6\u4FDD\u5B58\u5728\u672C\u673A\u7684 Key \u6C38\u4E45\u5220\u9664\uFF0C\u4E4B\u540E\u81EA\u52A8\u56DE\u843D\u5230\u73AF\u5883\u53D8\u91CF\u91CC\u7684 Key\uFF1B\u4E0D\u5F71\u54CD\u4F60\u5728\u522B\u5904\u914D\u7F6E\u7684\u51ED\u636E\u3002",
163
- removeKeyButton: "\u5220\u9664",
164
- removeKeyConfirm: "\u786E\u5B9A\u5220\u9664\u672C\u673A\u4FDD\u5B58\u7684 API Key\uFF1F\u5220\u9664\u540E\u5C06\u56DE\u843D\u5230\u73AF\u5883\u53D8\u91CF\u7684 Key\u3002",
165
- removeKeyDone: "\u5DF2\u5220\u9664\u4FDD\u5B58\u7684 Key",
166
- save: "\u4FDD\u5B58\u914D\u7F6E",
167
- saveAdvanced: "\u4FDD\u5B58\u9AD8\u7EA7\u914D\u7F6E",
168
- probe: "\u6D4B\u8BD5\u8FDE\u63A5",
169
- saved: "\u914D\u7F6E\u5DF2\u4FDD\u5B58",
170
- connected: "\u8FDE\u63A5\u6210\u529F",
171
- unavailable: "\u8FDE\u63A5\u4E0D\u53EF\u7528",
172
- error: "\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
173
- loading: "\u6B63\u5728\u8BFB\u53D6\u4F1A\u8BDD\u72B6\u6001",
174
- destination: "\u88C1\u51B3\u65F6\u4F1A\u5411\u4EE5\u4E0B\u540E\u7AEF\u53D1\u9001\u5FC5\u8981\u7684\u8BC4\u4F30\u4E0A\u4E0B\u6587\uFF1A",
175
- httpWarning: "\u6B64\u5730\u5740\u4F7F\u7528\u672A\u52A0\u5BC6\u7684 HTTP\u3002\u786E\u8BA4\u540E\uFF0CAPI Key \u4E0E\u8BC4\u4F30\u4E0A\u4E0B\u6587\u5C06\u4EE5\u660E\u6587\u53D1\u9001\u81F3\u8BE5\u5730\u5740\u3002",
176
- analysisTab: "\u51B3\u7B56\u5206\u6790",
177
- analysisTitle: "\u51B3\u7B56\u5206\u6790",
178
- analysisIntro: "\u57FA\u4E8E\u672C\u4F1A\u8BDD\u5DF2\u843D\u76D8\u7684\u51B3\u7B56\u65E5\u5FD7\u505A\u53EA\u8BFB\u805A\u5408\u4E0E\u4EBA\u5DE5\u6807\u6CE8\uFF0C\u4E0D\u6539\u53D8\u4EFB\u4F55 agent \u884C\u4E3A\u3002",
179
- analysisProfile: "\u8FC7\u7A0B\u753B\u50CF",
180
- analysisMeanScore: "\u5E73\u5747\u5206",
181
- analysisTrend: "\u8D28\u91CF\u8D8B\u52BF\u56DE\u6D4B",
182
- analysisTrendWarn: "\u544A\u8B66\u89E6\u53D1",
183
- analysisTrendSevere: "\u4E25\u91CD\u89E6\u53D1",
184
- analysisTrendMaxRun: "\u6700\u957F\u8FDE\u7EED\u4F4E\u5206",
185
- analysisTrendNote: "\u7528\u5F53\u524D\u9608\u503C\u628A\u672C\u4F1A\u8BDD\u7684\u81EA\u68C0\u5206\u6570\u6309\u65F6\u95F4\u91CD\u653E\uFF0C\u7EDF\u8BA1\u544A\u8B66\u672C\u4F1A\u300C\u4F1A\u300D\u89E6\u53D1\u51E0\u6B21\uFF0C\u7528\u4E8E\u6821\u51C6\u9608\u503C\uFF0C\u4E0D\u662F\u5B9E\u65F6\u4FE1\u53F7\u3002",
186
- analysisAccuracy: "\u5224\u65AD\u51C6\u786E\u5EA6",
187
- analysisAccuracyEmpty: "\u5C1A\u672A\u6807\u6CE8\u4EFB\u4F55\u51B3\u7B56\u3002\u5728\u4E0B\u65B9\u51B3\u7B56\u5217\u8868\u9010\u6761\u6807\u6CE8\u300C\u5224\u5BF9 / \u5224\u9519 / \u8BF4\u4E0D\u51C6\u300D\u540E\uFF0C\u8FD9\u91CC\u7ED9\u51FA\u6C47\u603B\u3002",
188
- analysisLogNote: "\u6807\u6CE8\u5728\u6B64\u4E0E\u4ECB\u5165\u9762\u677F\u540C\u6E90\uFF1A\u4EFB\u4E00\u5904\u6807\u6CE8\u90FD\u5199\u5165\u540C\u4E00\u4EFD\u65E5\u5FD7\u3001\u6309\u51B3\u7B56 id \u5173\u8054\u3001\u53D6\u6700\u65B0\u3002",
189
- analysisLogTruncated: "\u672C\u4F1A\u8BDD\u6682\u65E0\u53EF\u5C55\u793A\u7684\u51B3\u7B56\u8BB0\u5F55\u3002",
190
- pagerPrev: "\u4E0A\u4E00\u9875",
191
- pagerNext: "\u4E0B\u4E00\u9875",
192
- pagerStatus: "\u7B2C {page}/{pages} \u9875 \xB7 \u5171 {total} \u6761"
193
- },
194
- en: {
195
- summary: "A danger-call gate, output self-check, and loop guard driven by a pluggable adjudication model.",
196
- button: "Decision layer",
197
- title: "Decision layer",
198
- close: "Close",
199
- metrics: "Automatic decisions",
200
- triggerDecisions: "decisions",
201
- empty: "No automatic decisions yet. Manual verdicts are not counted here.",
202
- attempts: "Evaluations",
203
- failures: "Fallback failures",
204
- suggestions: "Model suggestions (allow / ask / deny)",
205
- actual: "Actual host outcomes (allow / deny)",
206
- checkAttempts: "Self-check evaluations",
207
- checkLow: "Low",
208
- checkOk: "Passed",
209
- settings: "Session settings",
210
- cardGate: "Danger gate",
211
- cardCheck: "Output self-check",
212
- cardNarrow: "Tool narrowing",
213
- cardComplete: "Task completion",
214
- cardTimes: "",
215
- allow: "Allow",
216
- ask: "Ask",
217
- deny: "Deny",
218
- actualShort: "Actual",
219
- narrowAppliedLabel: "Narrowed",
220
- narrowDroppedLabel: "Tools dropped",
221
- narrowDropped: "dropped",
222
- narrowKept: "kept all",
223
- narrowKeptCount: "kept",
224
- narrowMore: " and {count} in total",
225
- narrowObserve: "observe",
226
- narrowEnforce: "enforced",
227
- checkPassRate: "Pass rate",
228
- narrowApplyRate: "Narrow rate",
229
- rateNa: "\u2014",
230
- enabled: "Enable automatic interventions in this session",
231
- backendStatus: "Backend",
232
- statusChecking: "Checking\u2026",
233
- statusIdle: "Not checked",
234
- statusOk: "Connected",
235
- statusDown: "Unavailable",
236
- recheck: "Recheck",
237
- log: "Decision log",
238
- logEmpty: "No decisions recorded for this session yet.",
239
- logGate: "Gate",
240
- logCheck: "Self-check",
241
- logNarrow: "Narrow",
242
- logComplete: "Completion",
243
- logSuggested: "model suggested",
244
- logEvalFailed: "evaluation failed",
245
- logScore: "score",
246
- logConnection: "connection",
247
- logConfidence: "confidence",
248
- logCommandLabel: "command: ",
249
- logPathLabel: "path: ",
250
- logSubjectLabel: "request: ",
251
- logScoreHint: "The score is a probability-weighted mean across the levels, so it can be fractional (e.g. 1.4); the top score is the highest level number, 2.",
252
- logCheckHint: "After each turn, the AI\u2019s final reply for that turn is sent to the adjudication model, which grades its quality on three levels (severe omission/contradiction \u2192 minor gaps \u2192 complete and accurate) as a 0\u20132 score, to catch omissions or contradictions.",
253
- logNarrowHint: "At the start of each turn, the current task and each available tool are sent to the adjudication model (a noul per tool) to judge relevance, dropping tools clearly not needed. It only intersects the host-allowed set and never expands it; observe merely logs the suggestion, enforced actually restricts the tools for this turn.",
254
- actionDeny: "denied",
255
- actionAsk: "sent to approval",
256
- actionPass: "no intervention",
257
- gatePassThrough: "no intervention (proceeded on its original path)",
258
- checkResultLow: "low score",
259
- checkResultOk: "passed",
260
- checkResultLowNoisy: "low score (low confidence)",
261
- checkNoiseTag: "noise, ignore",
262
- checkNoiseHint: "The model had almost no confidence in this score (near-zero confidence). This low score does not count toward the quality trend and triggers no re-prompt \u2014 treat it as noise. What matters is several consecutive high-confidence low scores.",
263
- reasonUnavailable: "backend unreachable",
264
- reasonHttpError: "backend returned an error",
265
- reasonInvalidResponse: "unexpected response shape",
266
- reasonLowConfidence: "low confidence",
267
- reasonConfig: "invalid configuration",
268
- reasonTooMany: "too many candidates",
269
- reasonTooManyCount: "{count} candidates is too many",
270
- reasonLowKeep: "too few kept, not enforced",
271
- selfCheck: "Output self-check",
272
- advancedSwitches: "Intervention switches",
273
- advancedParams: "Narrowing parameters",
274
- selfCheckSteer: "Auto re-prompt on a low score",
275
- selfCheckHint: "Each turn ends by scoring the final reply (0\u20132, a probability-weighted mean across the levels, so it can be fractional like 1.4). Off: low scores are only logged, the conversation is not interrupted. On: when the score is low (\u22641) and the model is confident enough, one prompt is appended on your behalf asking the AI to review for gaps or contradictions and finish the work; low-confidence scores are only logged, never interrupt, and at most one prompt per turn.",
276
- narrow: "Tool narrowing",
277
- narrowObserveLabel: "Observe only (do not restrict tools)",
278
- narrowHint: "At the start of each turn, the adjudication model judges how relevant each optional tool is to the task and drops the ones not needed; core tools (read, write, edit, shell, search, todos) are always kept and never judged. Enforced by default: only the relevant tools are kept for this turn, intersected with the host-allowed set and never expanded. Turn on Observe only to just log the tools that could be dropped, without changing the tool set. Three safeguards: core tools always kept; more than 20 optional tools falls back to observe only; fewer than 5 tools remaining is treated as untrustworthy and skipped.",
279
- narrowKeepLabel: "Always-kept tool prefixes",
280
- narrowKeepHint: "Tools whose names start with any of these prefixes are always kept and never judged for relevance \u2014 good for resident, on-demand tools like memory/retrieval (defaults to mcp__openviking and team_task_). Separate prefixes with commas or newlines; leave empty to keep nothing extra.",
281
- narrowMaxLabel: "Candidate tool cap",
282
- narrowMaxHint: "When more than this many optional tools are judged in one turn (default 20), narrowing downgrades to observe only instead of actually restricting, so a large surface is never mass-pruned. Range 1\u2013200; a higher value leans toward actually narrowing. Core tools and keep-prefix matches do not count.",
283
- narrowThresholdLabel: "Drop threshold",
284
- narrowThresholdHint: 'A tool is dropped only when its relevance probability is below this value (default 0.3). A probability near 0.5 means the model is unsure, not "moderately relevant", so keeping is safer there; lower is more conservative (drops fewer), higher is more aggressive. Range 0\u20131.',
285
- features: "Decision points",
286
- basicFeatures: "Basic features",
287
- advancedConfig: "Advanced settings",
288
- featureGate: "Danger gate",
289
- featureGateHint: "When off, destructive tool calls are no longer evaluated for interception and are only bound by the host permission rules.",
290
- featureCheck: "Output self-check",
291
- featureCheckHint: "When off, the final reply is no longer scored at the end of a turn.",
292
- featureNarrow: "Tool narrowing",
293
- featureNarrowHint: "When off, tool relevance is no longer evaluated at the start of a turn. The loop guard is a deterministic local safeguard that is always on and not covered by this switch.",
294
- featureComplete: "Task completion check",
295
- featureCompleteHint: "When off, the explicit deliverable conditions the user listed are no longer checked at turn end.",
296
- trendWarnHint: "Output quality has been low for a few consecutive turns this session (high confidence). It may be rising task difficulty or model drift \u2014 consider adjusting the prompt or switching models.",
297
- trendSevereHint: "Output quality has stayed low this session (high confidence). Consider adjusting the prompt, switching models, or starting a new session.",
298
- rateGroup: "Rate this decision",
299
- rateGood: "Correct",
300
- rateBad: "Wrong",
301
- rateUnsure: "Unsure",
302
- rateSummary: "Rated {rated} ({good} correct / {bad} wrong / {unsure} unsure)",
303
- annotateFailed: "Could not save the rating. Please retry.",
304
- completeSteer: "Auto re-prompt on an unmet condition",
305
- completeHint: "At turn end, each explicit deliverable condition the user listed (numbered / bulleted / multi-command) is judged satisfied / unsatisfied / insufficient evidence, with tool evidence as the source of truth \u2014 a reply claiming completion is not evidence. Off: results are only logged, the conversation is not interrupted. On: when a condition is confidently judged unsatisfied, one prompt is appended on your behalf asking the AI to review and finish it; insufficient evidence never triggers a re-prompt, and at most one per turn.",
306
- completeResultOk: "conditions met",
307
- completeResultUnsatisfied: "unmet found",
308
- completeConditions: "conditions",
309
- completeSatisfied: "met",
310
- completeUnsatisfied: "unmet",
311
- completeInsufficient: "insufficient",
312
- completeSteered: "re-prompted",
313
- backend: "Decision backend",
314
- url: "Server URL",
315
- model: "Model",
316
- key: "API key",
317
- keyHintSaved: "A key is saved. Leave blank and save to keep it; enter a new value and save to overwrite it.",
318
- keyHintEmpty: "No key saved yet. Leave blank to use an environment credential, or enter one to save it locally.",
319
- removeKey: "Delete saved API key",
320
- removeKeyHint: "Permanently deletes the key this plugin stored locally, then falls back to the environment credential; credentials configured elsewhere are untouched.",
321
- removeKeyButton: "Delete",
322
- removeKeyConfirm: "Delete the locally saved API key? It will fall back to the environment credential.",
323
- removeKeyDone: "Saved key deleted",
324
- save: "Save configuration",
325
- saveAdvanced: "Save advanced settings",
326
- probe: "Test connection",
327
- saved: "Configuration saved",
328
- connected: "Connected",
329
- unavailable: "Connection unavailable",
330
- error: "Request failed. Please retry.",
331
- loading: "Loading session settings",
332
- destination: "Decisions send the necessary evaluation context to this backend:",
333
- httpWarning: "This address uses unencrypted HTTP. Your API key and evaluation context will be sent in plaintext to this address.",
334
- analysisTab: "Decision analysis",
335
- analysisTitle: "Decision analysis",
336
- analysisIntro: "A read-only aggregate and manual annotation over this session\u2019s persisted decision log. It changes no agent behavior.",
337
- analysisProfile: "Process profile",
338
- analysisMeanScore: "Mean score",
339
- analysisTrend: "Quality-trend backtest",
340
- analysisTrendWarn: "Warn fires",
341
- analysisTrendSevere: "Severe fires",
342
- analysisTrendMaxRun: "Longest low run",
343
- analysisTrendNote: "Replays this session\u2019s self-check scores in time order under the current thresholds to count how often the alarm would fire \u2014 a calibration aid, not a live signal.",
344
- analysisAccuracy: "Decision accuracy",
345
- analysisAccuracyEmpty: "No decisions rated yet. Rate rows below as correct / wrong / unsure and a summary appears here.",
346
- analysisLogNote: "Ratings here share one source with the intervention panel: a rating on either surface writes to the same log, keyed by decision id, latest wins.",
347
- analysisLogTruncated: "No decision rows to show for this session.",
348
- pagerPrev: "Prev",
349
- pagerNext: "Next",
350
- pagerStatus: "Page {page}/{pages} \xB7 {total} total"
351
- }
35
+ var zh = {
36
+ summary: "\u5371\u9669\u8C03\u7528\u95E8\u63A7\u3001\u4EA7\u51FA\u81EA\u68C0\u4E0E\u9632\u5FAA\u73AF\uFF0C\u7531\u53EF\u63D2\u62D4\u88C1\u51B3\u6A21\u578B\u9A71\u52A8\u3002",
37
+ button: "\u51B3\u7B56\u5C42",
38
+ title: "\u51B3\u7B56\u5C42",
39
+ close: "\u5173\u95ED",
40
+ metrics: "\u81EA\u52A8\u88C1\u51B3\u7EDF\u8BA1",
41
+ triggerDecisions: "\u51B3\u7B56",
42
+ empty: "\u5C1A\u65E0\u81EA\u52A8\u88C1\u51B3\u3002\u624B\u52A8\u88C1\u51B3\u4E0D\u8BA1\u5165\u8FD9\u91CC\u3002",
43
+ attempts: "\u8BC4\u4F30\u6B21\u6570",
44
+ failures: "\u5931\u8D25\u56DE\u9000",
45
+ suggestions: "\u6A21\u578B\u5EFA\u8BAE\uFF08\u653E\u884C / \u8BE2\u95EE / \u62D2\u7EDD\uFF09",
46
+ actual: "\u5B9E\u9645\u5BBF\u4E3B\u7ED3\u679C\uFF08\u653E\u884C / \u62D2\u7EDD\uFF09",
47
+ checkAttempts: "\u81EA\u68C0\u8BC4\u4F30\u6B21\u6570",
48
+ checkLow: "\u4F4E\u5206",
49
+ checkOk: "\u901A\u8FC7",
50
+ settings: "\u4F1A\u8BDD\u8BBE\u7F6E",
51
+ cardGate: "\u5371\u9669\u95E8\u63A7",
52
+ cardCheck: "\u4EA7\u51FA\u81EA\u68C0",
53
+ cardNarrow: "\u5DE5\u5177\u6536\u7A84",
54
+ cardComplete: "\u5B8C\u6210\u6838\u5BF9",
55
+ cardTimes: " \u6B21",
56
+ allow: "\u653E\u884C",
57
+ ask: "\u8BE2\u95EE",
58
+ deny: "\u62D2\u7EDD",
59
+ actualShort: "\u5B9E\u9645\u7ED3\u679C",
60
+ narrowAppliedLabel: "\u6536\u7A84",
61
+ narrowDroppedLabel: "\u6458\u9664\u5DE5\u5177",
62
+ narrowDropped: "\u6458\u9664",
63
+ narrowKept: "\u672A\u6536\u7A84",
64
+ narrowKeptCount: "\u4FDD\u7559",
65
+ narrowMore: " \u7B49 {count} \u4E2A",
66
+ narrowObserve: "\u4EC5\u89C2\u5BDF",
67
+ narrowEnforce: "\u5DF2\u751F\u6548",
68
+ narrowNotApplied: "\u672A\u751F\u6548",
69
+ checkPassRate: "\u901A\u8FC7\u7387",
70
+ narrowApplyRate: "\u6536\u7A84\u7387",
71
+ rateNa: "\u2014",
72
+ enabled: "\u672C\u4F1A\u8BDD\u5185\u542F\u7528\u81EA\u52A8\u4ECB\u5165",
73
+ backendStatus: "\u540E\u7AEF\u8FDE\u63A5",
74
+ statusChecking: "\u68C0\u6D4B\u4E2D\u2026",
75
+ statusIdle: "\u672A\u68C0\u6D4B",
76
+ statusOk: "\u6B63\u5E38",
77
+ statusDown: "\u4E0D\u53EF\u7528",
78
+ recheck: "\u91CD\u65B0\u68C0\u6D4B",
79
+ log: "\u51B3\u7B56\u65E5\u5FD7",
80
+ logEmpty: "\u672C\u4F1A\u8BDD\u5C1A\u65E0\u51B3\u7B56\u8BB0\u5F55\u3002",
81
+ logGate: "\u95E8\u63A7",
82
+ logCheck: "\u81EA\u68C0",
83
+ logNarrow: "\u6536\u7A84",
84
+ logComplete: "\u5B8C\u6210\u6838\u5BF9",
85
+ logSuggested: "\u6A21\u578B\u5EFA\u8BAE",
86
+ logEvalFailed: "\u8BC4\u4F30\u5931\u8D25",
87
+ logScore: "\u5F97\u5206",
88
+ logConnection: "\u8FDE\u63A5",
89
+ logConfidence: "\u7F6E\u4FE1\u5EA6",
90
+ logCommandLabel: "\u547D\u4EE4\uFF1A",
91
+ logPathLabel: "\u8DEF\u5F84\uFF1A",
92
+ logSubjectLabel: "\u8BF7\u6C42\uFF1A",
93
+ logScoreHint: "\u5F97\u5206\u4E3A\u5404\u6863\u4F4D\u6309\u6982\u7387\u52A0\u6743\u7684\u7ED3\u679C\uFF0C\u53EF\u80FD\u662F\u5C0F\u6570\uFF08\u5982 1.4\uFF09\uFF0C\u6EE1\u5206\u4E3A\u9876\u6863\u53F7 2\u3002",
94
+ logCheckHint: "\u6BCF\u56DE\u5408\u7ED3\u675F\u540E\uFF0C\u628A\u8FD9\u8F6E AI \u7684\u6700\u7EC8\u56DE\u590D\u4EA4\u7ED9\u88C1\u51B3\u6A21\u578B\uFF0C\u6309\u300C\u4E25\u91CD\u9057\u6F0F/\u81EA\u76F8\u77DB\u76FE \u2192 \u6709\u5C0F\u9057\u6F0F \u2192 \u5B8C\u6574\u51C6\u786E\u300D\u4E09\u6863\u6253\u4E00\u4E2A 0\u20132 \u7684\u8D28\u91CF\u5206\uFF0C\u7528\u6765\u53D1\u73B0\u9057\u6F0F\u6216\u77DB\u76FE\u3002",
95
+ logNarrowHint: "\u6BCF\u56DE\u5408\u5F00\u59CB\u65F6\uFF0C\u628A\u8FD9\u8F6E\u4EFB\u52A1\u4E0E\u5F53\u524D\u53EF\u7528\u5DE5\u5177\u9010\u4E2A\u4EA4\u7ED9\u88C1\u51B3\u6A21\u578B\u5224\u65AD\u76F8\u5173\u6027\uFF08noul\uFF09\uFF0C\u6458\u6389\u660E\u663E\u7528\u4E0D\u4E0A\u7684\u5DE5\u5177\uFF0C\u53EA\u5728\u5F53\u524D\u5BBF\u4E3B\u5DF2\u5141\u8BB8\u7684\u96C6\u5408\u5185\u53D6\u4EA4\u96C6\u3001\u7EDD\u4E0D\u6269\u6743\uFF1B\u300C\u4EC5\u89C2\u5BDF\u300D\u53EA\u8BB0\u5F55\u5EFA\u8BAE\uFF0C\u300C\u5DF2\u751F\u6548\u300D\u624D\u771F\u6B63\u5BF9\u672C\u56DE\u5408\u9650\u5236\u5DE5\u5177\u3002",
96
+ actionDeny: "\u5DF2\u62D2\u7EDD",
97
+ actionAsk: "\u8F6C\u4EA4\u5BA1\u6279",
98
+ actionPass: "\u672A\u5E72\u9884",
99
+ gatePassThrough: "\u672A\u5E72\u9884\uFF08\u6309\u539F\u8DEF\u5F84\u6267\u884C\uFF09",
100
+ checkResultLow: "\u5F97\u5206\u504F\u4F4E",
101
+ checkResultOk: "\u901A\u8FC7",
102
+ checkResultLowNoisy: "\u5F97\u5206\u504F\u4F4E\uFF08\u4F4E\u7F6E\u4FE1\uFF09",
103
+ checkNoiseTag: "\u566A\u58F0\uFF0C\u53EF\u5FFD\u7565",
104
+ checkNoiseHint: "\u6A21\u578B\u5BF9\u8FD9\u6B21\u6253\u5206\u51E0\u4E4E\u6CA1\u6709\u628A\u63E1\uFF08\u7F6E\u4FE1\u5EA6\u6781\u4F4E\uFF09\uFF0C\u8FD9\u6761\u4F4E\u5206\u4E0D\u8BA1\u5165\u8D28\u91CF\u8D8B\u52BF\u3001\u4E5F\u4E0D\u89E6\u53D1\u4EFB\u4F55\u8865\u5B8C\uFF0C\u89C6\u4F5C\u566A\u58F0\u5FFD\u7565\u5373\u53EF\u3002\u771F\u6B63\u503C\u5F97\u5173\u6CE8\u7684\u662F\u8FDE\u7EED\u591A\u6B21\u9AD8\u7F6E\u4FE1\u7684\u4F4E\u5206\u3002",
105
+ reasonUnavailable: "\u540E\u7AEF\u4E0D\u53EF\u8FBE",
106
+ reasonHttpError: "\u540E\u7AEF\u8FD4\u56DE\u9519\u8BEF",
107
+ reasonInvalidResponse: "\u54CD\u5E94\u683C\u5F0F\u4E0D\u7B26",
108
+ reasonLowConfidence: "\u7F6E\u4FE1\u5EA6\u4E0D\u8DB3",
109
+ reasonConfig: "\u914D\u7F6E\u65E0\u6548",
110
+ reasonTooMany: "\u5019\u9009\u8FC7\u591A",
111
+ reasonTooManyCount: "\u5019\u9009 {count} \u4E2A\u504F\u591A",
112
+ reasonLowKeep: "\u4FDD\u7559\u8FC7\u5C11",
113
+ selfCheck: "\u4EA7\u51FA\u81EA\u68C0",
114
+ advancedSwitches: "\u4ECB\u5165\u5F00\u5173",
115
+ advancedParams: "\u6536\u7A84\u53C2\u6570",
116
+ selfCheckSteer: "\u5F97\u5206\u504F\u4F4E\u65F6\u81EA\u52A8\u8865\u4E00\u8F6E",
117
+ selfCheckHint: "\u6BCF\u56DE\u5408\u7ED3\u675F\u7ED9\u6700\u7EC8\u56DE\u590D\u6253\u5206\uFF080\u20132\uFF0C\u6309\u5404\u6863\u4F4D\u6982\u7387\u52A0\u6743\uFF0C\u53EF\u80FD\u662F\u5C0F\u6570\u5982 1.4\uFF09\u3002\u5173\u95ED\uFF1A\u53EA\u628A\u4F4E\u5206\u8BB0\u8FDB\u65E5\u5FD7\u548C\u7EDF\u8BA1\uFF0C\u4E0D\u6253\u65AD\u5BF9\u8BDD\u3002\u5F00\u542F\uFF1A\u5F97\u5206\u504F\u4F4E\uFF08\u22641\uFF09\u4E14\u6A21\u578B\u6709\u628A\u63E1\u65F6\uFF0C\u81EA\u52A8\u4EE5\u4F60\u7684\u540D\u4E49\u8FFD\u52A0\u4E00\u6761\u63D0\u793A\uFF0C\u8BA9 AI \u590D\u6838\u6709\u65E0\u9057\u6F0F\u6216\u77DB\u76FE\u5E76\u8865\u5B8C\uFF1B\u7F6E\u4FE1\u5EA6\u504F\u4F4E\u7684\u6253\u5206\u53EA\u8BB0\u5F55\u3001\u4E0D\u6253\u65AD\uFF0C\u540C\u4E00\u56DE\u5408\u6700\u591A\u8865\u4E00\u6B21\u3002",
118
+ narrow: "\u5DE5\u5177\u6536\u7A84",
119
+ narrowObserveLabel: "\u4EC5\u89C2\u5BDF\uFF08\u4E0D\u771F\u6B63\u9650\u5236\u5DE5\u5177\uFF09",
120
+ narrowHint: "\u6BCF\u56DE\u5408\u5F00\u59CB\u65F6\uFF0C\u7528\u88C1\u51B3\u6A21\u578B\u5224\u65AD\u5F53\u524D\u53EF\u9009\u5DE5\u5177\u4E0E\u8FD9\u8F6E\u4EFB\u52A1\u7684\u76F8\u5173\u6027\uFF0C\u6458\u6389\u7528\u4E0D\u4E0A\u7684\uFF1B\u8BFB\u5199\u3001\u7F16\u8F91\u3001Shell\u3001\u68C0\u7D22\u3001\u5F85\u529E\u7B49\u6838\u5FC3\u5DE5\u5177\u59CB\u7EC8\u4FDD\u7559\u3001\u4E0D\u53C2\u4E0E\u5224\u5B9A\u3002\u9ED8\u8BA4\u771F\u6B63\u751F\u6548\uFF1A\u672C\u56DE\u5408\u53EA\u4FDD\u7559\u5224\u4E3A\u76F8\u5173\u7684\u5DE5\u5177\uFF0C\u4E14\u53EA\u5728\u5BBF\u4E3B\u5DF2\u5141\u8BB8\u7684\u8303\u56F4\u5185\u53D6\u4EA4\u96C6\u3001\u4E0D\u6269\u6743\u3002\u5F00\u542F\u300C\u4EC5\u89C2\u5BDF\u300D\u540E\u53EA\u628A\u53EF\u6458\u6389\u7684\u5DE5\u5177\u8BB0\u8FDB\u65E5\u5FD7\u548C\u7EDF\u8BA1\uFF0C\u4E0D\u6539\u52A8\u5DE5\u5177\u96C6\u3002\u4E09\u91CD\u4FDD\u62A4\uFF1A\u6838\u5FC3\u5DE5\u5177\u59CB\u7EC8\u4FDD\u7559\uFF1B\u53EF\u9009\u5DE5\u5177\u8D85\u8FC7 20 \u4E2A\u65F6\u81EA\u52A8\u53EA\u89C2\u5BDF\u4E0D\u9650\u5236\uFF1B\u4FDD\u7559\u4E0B\u6765\u4E0D\u8DB3 5 \u4E2A\u65F6\u89C6\u4E3A\u5224\u5B9A\u4E0D\u53EF\u4FE1\u3001\u8DF3\u8FC7\u3002",
121
+ narrowKeepLabel: "\u59CB\u7EC8\u4FDD\u7559\u7684\u5DE5\u5177\u524D\u7F00",
122
+ narrowKeepHint: "\u540D\u5B57\u4EE5\u8FD9\u4E9B\u524D\u7F00\u5F00\u5934\u7684\u5DE5\u5177\u6C38\u8FDC\u4FDD\u7559\u3001\u4E0D\u53C2\u4E0E\u76F8\u5173\u6027\u5224\u5B9A\uFF0C\u9002\u5408\u8BB0\u5FC6/\u68C0\u7D22\u8FD9\u7C7B\u300C\u5E38\u9A7B\u3001\u6309\u9700\u89E6\u53D1\u300D\u7684\u5DE5\u5177\uFF08\u9ED8\u8BA4\u53EA\u6709 mcp__openviking\uFF09\u3002\u7528\u82F1\u6587\u9017\u53F7\u6216\u6362\u884C\u5206\u9694\u591A\u4E2A\u524D\u7F00\uFF1B\u7559\u7A7A\u5219\u4E0D\u989D\u5916\u4FDD\u7559\u3002",
123
+ narrowMaxLabel: "\u5019\u9009\u5DE5\u5177\u4E0A\u9650",
124
+ narrowMaxHint: "\u4E00\u56DE\u5408\u91CC\u53C2\u4E0E\u5224\u5B9A\u7684\u300C\u53EF\u9009\u5DE5\u5177\u300D\u8D85\u8FC7\u8FD9\u4E2A\u6570\uFF08\u9ED8\u8BA4 20\uFF09\uFF0C\u5C31\u81EA\u52A8\u964D\u7EA7\u4E3A\u4EC5\u89C2\u5BDF\u3001\u4E0D\u771F\u6B63\u6536\u7A84\uFF0C\u907F\u514D\u4E00\u6B21\u585E\u592A\u591A\u5DE5\u5177\u8BA9\u6A21\u578B\u8BEF\u6458\u3002\u53D6\u503C 1\u2013200\uFF0C\u8C03\u5927\u66F4\u503E\u5411\u771F\u6B63\u6536\u7A84\u3002\u6838\u5FC3\u5DE5\u5177\u4E0E\u4FDD\u7559\u524D\u7F00\u547D\u4E2D\u7684\u5DE5\u5177\u4E0D\u8BA1\u5165\u3002",
125
+ narrowThresholdLabel: "\u6458\u9664\u9608\u503C",
126
+ narrowThresholdHint: "\u76F8\u5173\u6027\u6982\u7387\u4F4E\u4E8E\u8FD9\u4E2A\u503C\u624D\u6458\u6389\u5DE5\u5177\uFF08\u9ED8\u8BA4 0.7\uFF0C\u504F\u6FC0\u8FDB\uFF1A\u53EA\u7559\u6A21\u578B\u8F83\u6709\u628A\u63E1\u5224\u4E3A\u76F8\u5173\u7684\u5DE5\u5177\uFF09\u3002\u8C03\u4F4E\u66F4\u4FDD\u5B88\uFF08\u5C11\u6458\u3001\u5B81\u53EF\u591A\u7559\uFF09\uFF0C\u8C03\u9AD8\u66F4\u6FC0\u8FDB\uFF08\u591A\u6458\uFF09\u3002\u6982\u7387\u63A5\u8FD1 0.5 \u8868\u793A\u6A21\u578B\u62FF\u4E0D\u51C6\uFF0C\u6309\u9ED8\u8BA4\u9608\u503C\u4F1A\u88AB\u6458\u6389\uFF1B\u60F3\u7559\u4F4F\u8FD9\u7C7B\u300C\u53EF\u80FD\u7528\u5230\u300D\u7684\u5DE5\u5177\uFF0C\u628A\u9608\u503C\u8C03\u4F4E\u3002\u53D6\u503C 0\u20131\u3002",
127
+ batchModeLabel: "\u5206\u6279\u7B56\u7565",
128
+ batchModeHint: "\u300C\u81EA\u52A8\u300D\uFF08\u9ED8\u8BA4\uFF09\u5148\u6574\u6279\u53D1\u4E00\u6B21\u8BF7\u6C42\uFF0C\u9047\u5230\u4E0A\u4E0B\u6587\u8D85\u9650\u518D\u81EA\u52A8\u964D\u7EA7\u4E3A\u9010\u5DE5\u5177\u5E76\u8BB0\u4F4F\uFF1B\u300C\u6574\u6279\u300D\u4E00\u6B21\u5224\u5B8C\u5168\u90E8\u5DE5\u5177\uFF0C\u9002\u5408\u5927\u4E0A\u4E0B\u6587\u540E\u7AEF\uFF08\u5982 Jev\uFF09\uFF1B\u300C\u9010\u5DE5\u5177\u300D\u6BCF\u4E2A\u5DE5\u5177\u4E00\u6B21\u8BF7\u6C42\u3001\u5E76\u53D1\u6267\u884C\uFF0C\u9002\u5408\u5C0F\u4E0A\u4E0B\u6587\u540E\u7AEF\uFF08\u5982\u672C\u5730 tev1\uFF0C\u7EA6 2050 token \u5355\u8BF7\u6C42\u4E0A\u9650\uFF09\u3002",
129
+ batchModeAuto: "\u81EA\u52A8",
130
+ batchModeSingle: "\u6574\u6279",
131
+ batchModeSplit: "\u9010\u5DE5\u5177",
132
+ advancedThresholds: "\u5E72\u9884\u9608\u503C",
133
+ gateMinConfidenceLabel: "\u95E8\u63A7\u62E6\u622A\u7F6E\u4FE1\u5EA6",
134
+ gateMinConfidenceHint: "\u6A21\u578B\u5224\u300C\u62D2\u7EDD\u300D\u7684\u7F6E\u4FE1\u5EA6\u8FBE\u5230\u8FD9\u4E2A\u503C\u624D\u771F\u6B63\u62E6\u4E0B\u5371\u9669\u8C03\u7528\uFF08\u9ED8\u8BA4 0.6\uFF09\u3002\u8C03\u4F4E\u66F4\u5BB9\u6613\u62E6\u3001\u4E5F\u53EF\u80FD\u8BEF\u62E6\u6B63\u5E38\u547D\u4EE4\uFF1B\u8C03\u9AD8\u66F4\u5BBD\u677E\u3001\u66F4\u591A\u653E\u884C\u3002\u53D6\u503C 0\u20131\u3002",
135
+ checkMinConfidenceLabel: "\u81EA\u68C0\u8865\u5B8C\u7F6E\u4FE1\u5EA6",
136
+ checkMinConfidenceHint: "\u81EA\u68C0\u5F97\u5206\u504F\u4F4E\u65F6\uFF0C\u7F6E\u4FE1\u5EA6\u8FBE\u5230\u8FD9\u4E2A\u503C\u624D\u81EA\u52A8\u8865\u4E00\u8F6E\uFF08\u9ED8\u8BA4 0.4\uFF09\uFF1B\u4F4E\u4E8E\u5B83\u53EA\u8BB0\u5F55\u3001\u4E0D\u6253\u65AD\u3002\u53D6\u503C 0\u20131\u3002",
137
+ lowScoreThresholdLabel: "\u4F4E\u5206\u9608\u503C",
138
+ lowScoreThresholdHint: "\u5F97\u5206\u5C0F\u4E8E\u7B49\u4E8E\u8FD9\u4E2A\u503C\u7B97\u300C\u504F\u4F4E\u300D\uFF08\u9ED8\u8BA4 1\uFF0C\u8BC4\u5206\u8303\u56F4 0\u20132\uFF09\u3002\u53D6\u503C 0\u20139 \u7684\u6574\u6570\u3002",
139
+ trendMinConfidenceLabel: "\u8D8B\u52BF\u544A\u8B66\u7F6E\u4FE1\u5EA6",
140
+ trendMinConfidenceHint: "\u53EA\u6709\u7F6E\u4FE1\u5EA6\u8FBE\u5230\u8FD9\u4E2A\u503C\u7684\u4F4E\u5206\u624D\u8BA1\u5165\u8D28\u91CF\u8D8B\u52BF\uFF08\u9ED8\u8BA4 0.6\uFF09\uFF0C\u907F\u514D\u628A\u6A21\u578B\u6CA1\u628A\u63E1\u7684\u4F4E\u5206\u5F53\u6210\u771F\u5B9E\u4E0B\u6ED1\u3002\u53D6\u503C 0\u20131\u3002",
141
+ trendRunLabel: "\u544A\u8B66\u8FDE\u7EED\u6B21\u6570",
142
+ trendRunHint: "\u8FDE\u7EED\u8FD9\u4E48\u591A\u6B21\u9AD8\u7F6E\u4FE1\u4F4E\u5206\u53D1\u51FA\u300C\u544A\u8B66\u300D\uFF08\u9ED8\u8BA4 3\uFF09\u3002\u53D6\u503C 2\u201310\u3002",
143
+ trendSevereRunLabel: "\u4E25\u91CD\u8FDE\u7EED\u6B21\u6570",
144
+ trendSevereRunHint: "\u8FDE\u7EED\u8FD9\u4E48\u591A\u6B21\u9AD8\u7F6E\u4FE1\u4F4E\u5206\u5347\u7EA7\u4E3A\u300C\u4E25\u91CD\u300D\u544A\u8B66\uFF08\u9ED8\u8BA4 5\uFF09\u3002\u5FC5\u987B\u5927\u4E8E\u544A\u8B66\u8FDE\u7EED\u6B21\u6570\uFF0C\u53D6\u503C 2\u201320\u3002",
145
+ completeMinConfidenceLabel: "\u5B8C\u6210\u6838\u5BF9\u7F6E\u4FE1\u5EA6",
146
+ completeMinConfidenceHint: "\u5224\u5B9A\u67D0\u6761\u4EF6\u300C\u672A\u6EE1\u8DB3\u300D\u7684\u7F6E\u4FE1\u5EA6\u8FBE\u5230\u8FD9\u4E2A\u503C\u624D\u81EA\u52A8\u8865\u4E00\u8F6E\uFF08\u9ED8\u8BA4 0.4\uFF09\u3002\u53D6\u503C 0\u20131\u3002",
147
+ minConditionsLabel: "\u6700\u5C11\u4EA4\u4ED8\u6761\u4EF6\u6570",
148
+ minConditionsHint: "\u7528\u6237\u660E\u786E\u5217\u51FA\u7684\u6761\u4EF6\u8FBE\u5230\u8FD9\u4E2A\u6570\u91CF\u624D\u505A\u5B8C\u6210\u6838\u5BF9\uFF08\u9ED8\u8BA4 2\uFF09\u3002\u53D6\u503C 2\u201320\u3002",
149
+ advancedRubric: "\u81EA\u68C0\u6863\u4F4D",
150
+ selfCheckRubricLabel: "\u8BC4\u5206\u6863\u4F4D",
151
+ selfCheckRubricHint: "\u6BCF\u884C\u4E00\u6863\u3001\u7531\u4F4E\u5230\u9AD8\uFF0C\u7528\u4E8E\u7ED9\u6700\u7EC8\u56DE\u590D\u6253\u5206\uFF08\u9ED8\u8BA4\u4E09\u6863\uFF0C\u5BF9\u5E94 0\u20132 \u5206\uFF09\u3002\u81F3\u5C11 2 \u6863\u3001\u6700\u591A 10 \u6863\uFF0C\u6BCF\u6863\u4E0D\u8D85\u8FC7 256 \u5B57\u3002\u4E0D\u5408\u89C4\u65F6\u4E0D\u4F1A\u4FDD\u5B58\uFF0C\u4F1A\u5728\u4E0B\u65B9\u63D0\u793A\u5177\u4F53\u95EE\u9898\u3002",
152
+ rubricTooFew: "\u81F3\u5C11\u9700\u8981 2 \u6863\uFF08\u6BCF\u884C\u4E00\u6863\uFF09\u3002",
153
+ rubricTooMany: "\u6700\u591A 10 \u6863\uFF0C\u8BF7\u5220\u6389\u591A\u4F59\u7684\u6863\u4F4D\u3002",
154
+ rubricLevelTooLong: "\u7B2C {line} \u6863\u8D85\u8FC7 256 \u5B57\uFF0C\u8BF7\u7CBE\u7B80\u540E\u518D\u4FDD\u5B58\u3002",
155
+ features: "\u51B3\u7B56\u70B9\u5F00\u5173",
156
+ basicFeatures: "\u57FA\u7840\u529F\u80FD",
157
+ advancedConfig: "\u9AD8\u7EA7\u914D\u7F6E",
158
+ featureGate: "\u5371\u9669\u95E8\u63A7",
159
+ featureGateHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5BF9\u7834\u574F\u6027\u5DE5\u5177\u8C03\u7528\u505A\u62E6\u622A\u8BC4\u4F30\uFF0C\u8C03\u7528\u53EA\u53D7\u5BBF\u4E3B\u539F\u751F\u6743\u9650\u7EA6\u675F\u3002",
160
+ featureCheck: "\u4EA7\u51FA\u81EA\u68C0",
161
+ featureCheckHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u7ED3\u675F\u65F6\u7ED9\u6700\u7EC8\u56DE\u590D\u6253\u5206\u3002",
162
+ featureNarrow: "\u5DE5\u5177\u6536\u7A84",
163
+ featureNarrowHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u5F00\u59CB\u65F6\u8BC4\u4F30\u5DE5\u5177\u76F8\u5173\u6027\u3002\u9632\u5FAA\u73AF\u4E3A\u786E\u5B9A\u6027\u672C\u5730\u4FDD\u62A4\uFF0C\u4E0D\u53D7\u5404\u51B3\u7B56\u70B9\u5F00\u5173\u5F71\u54CD\uFF0C\u4F46\u4F1A\u8BDD\u603B\u5F00\u5173\u5173\u95ED\u65F6\u540C\u6837\u6682\u505C\u3002",
164
+ featureComplete: "\u4EFB\u52A1\u5B8C\u6210\u6838\u5BF9",
165
+ featureCompleteHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u7ED3\u675F\u65F6\u9010\u9879\u6838\u5BF9\u7528\u6237\u660E\u786E\u5217\u51FA\u7684\u4EA4\u4ED8\u6761\u4EF6\u3002",
166
+ trendWarnHint: "\u672C\u4F1A\u8BDD\u6700\u8FD1\u8FDE\u7EED\u51E0\u8F6E\u4EA7\u51FA\u8D28\u91CF\u504F\u4F4E\uFF08\u9AD8\u7F6E\u4FE1\uFF09\u3002\u53EF\u80FD\u662F\u4EFB\u52A1\u96BE\u5EA6\u4E0A\u5347\u6216\u6A21\u578B\u72B6\u6001\u6CE2\u52A8\uFF0C\u5EFA\u8BAE\u5C1D\u8BD5\u8C03\u6574 prompt \u6216\u66F4\u6362\u6A21\u578B\u3002",
167
+ trendSevereHint: "\u672C\u4F1A\u8BDD\u4EA7\u51FA\u8D28\u91CF\u6301\u7EED\u504F\u4F4E\uFF08\u9AD8\u7F6E\u4FE1\uFF09\u3002\u5EFA\u8BAE\u8C03\u6574 prompt \u6216\u66F4\u6362\u6A21\u578B\uFF0C\u6216\u91CD\u5F00\u4F1A\u8BDD\u3002",
168
+ rateGroup: "\u6807\u6CE8\u8FD9\u6B21\u5224\u65AD",
169
+ rateGood: "\u5224\u5BF9\u4E86",
170
+ rateBad: "\u5224\u9519\u4E86",
171
+ rateUnsure: "\u8BF4\u4E0D\u51C6",
172
+ rateSummary: "\u5DF2\u6807\u6CE8 {rated} \u6761\uFF08\u5224\u5BF9 {good} / \u5224\u9519 {bad} / \u8BF4\u4E0D\u51C6 {unsure}\uFF09",
173
+ annotateFailed: "\u6807\u6CE8\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
174
+ completeSteer: "\u6709\u672A\u6EE1\u8DB3\u6761\u4EF6\u65F6\u81EA\u52A8\u8865\u4E00\u8F6E",
175
+ completeHint: "\u56DE\u5408\u7ED3\u675F\u65F6\uFF0C\u5BF9\u7528\u6237\u660E\u786E\u5217\u51FA\u7684\u591A\u4E2A\u4EA4\u4ED8\u6761\u4EF6\uFF08\u7F16\u53F7 / \u9879\u76EE\u7B26\u53F7 / \u591A\u547D\u4EE4\uFF09\u9010\u9879\u5224\u5B9A\u300C\u5DF2\u6EE1\u8DB3 / \u672A\u6EE1\u8DB3 / \u8BC1\u636E\u4E0D\u8DB3\u300D\uFF0C\u4EE5\u5DE5\u5177\u8BC1\u636E\u4E3A\u51C6\u3001\u56DE\u590D\u81EA\u79F0\u5B8C\u6210\u4E0D\u7B97\u8BC1\u636E\u3002\u5173\u95ED\uFF1A\u53EA\u628A\u7ED3\u679C\u8BB0\u8FDB\u65E5\u5FD7\u548C\u7EDF\u8BA1\uFF0C\u4E0D\u6253\u65AD\u5BF9\u8BDD\u3002\u5F00\u542F\uFF1A\u786E\u6709\u6761\u4EF6\u88AB\u5224\u300C\u672A\u6EE1\u8DB3\u300D\u4E14\u6A21\u578B\u6709\u628A\u63E1\u65F6\uFF0C\u81EA\u52A8\u4EE5\u4F60\u7684\u540D\u4E49\u8FFD\u52A0\u4E00\u6761\u63D0\u793A\u8BA9 AI \u590D\u6838\u8865\u5B8C\uFF1B\u300C\u8BC1\u636E\u4E0D\u8DB3\u300D\u4E0D\u89E6\u53D1\u8865\u5B8C\uFF0C\u540C\u4E00\u56DE\u5408\u6700\u591A\u8865\u4E00\u6B21\u3002",
176
+ completeResultOk: "\u6761\u4EF6\u9F50\u5907",
177
+ completeResultUnsatisfied: "\u6709\u672A\u6EE1\u8DB3",
178
+ completeConditions: "\u6761\u4EF6",
179
+ completeSatisfied: "\u6EE1\u8DB3",
180
+ completeUnsatisfied: "\u672A\u6EE1\u8DB3",
181
+ completeInsufficient: "\u8BC1\u636E\u4E0D\u8DB3",
182
+ completeSteered: "\u5DF2\u8865\u4E00\u8F6E",
183
+ backend: "\u88C1\u51B3\u540E\u7AEF",
184
+ url: "\u670D\u52A1\u5730\u5740",
185
+ model: "\u6A21\u578B",
186
+ key: "API Key",
187
+ keyHintSaved: "\u5DF2\u4FDD\u5B58\u4E00\u4E2A Key\u3002\u7559\u7A7A\u5E76\u4FDD\u5B58\uFF1D\u6CBF\u7528\u5B83\uFF08\u4E0D\u6539\u52A8\uFF09\uFF1B\u586B\u65B0\u503C\u5E76\u4FDD\u5B58\uFF1D\u8986\u76D6\u5B83\u3002",
188
+ keyHintEmpty: "\u5C1A\u672A\u4FDD\u5B58 Key\u3002\u7559\u7A7A\u5219\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u91CC\u7684 Key\uFF1B\u586B\u5165\u5219\u4FDD\u5B58\u5230\u672C\u673A\u3002",
189
+ removeKey: "\u5220\u9664\u5DF2\u4FDD\u5B58\u7684 Key",
190
+ removeKeyHint: "\u628A\u672C\u63D2\u4EF6\u4FDD\u5B58\u5728\u672C\u673A\u7684 Key \u6C38\u4E45\u5220\u9664\uFF0C\u4E4B\u540E\u81EA\u52A8\u56DE\u843D\u5230\u73AF\u5883\u53D8\u91CF\u91CC\u7684 Key\uFF1B\u4E0D\u5F71\u54CD\u4F60\u5728\u522B\u5904\u914D\u7F6E\u7684\u51ED\u636E\u3002",
191
+ removeKeyButton: "\u5220\u9664",
192
+ removeKeyConfirm: "\u786E\u5B9A\u5220\u9664\u672C\u673A\u4FDD\u5B58\u7684 API Key\uFF1F\u5220\u9664\u540E\u5C06\u56DE\u843D\u5230\u73AF\u5883\u53D8\u91CF\u7684 Key\u3002",
193
+ removeKeyDone: "\u5DF2\u5220\u9664\u4FDD\u5B58\u7684 Key",
194
+ save: "\u4FDD\u5B58\u914D\u7F6E",
195
+ saveAdvanced: "\u4FDD\u5B58\u9AD8\u7EA7\u914D\u7F6E",
196
+ probe: "\u6D4B\u8BD5\u8FDE\u63A5",
197
+ saved: "\u914D\u7F6E\u5DF2\u4FDD\u5B58",
198
+ connected: "\u8FDE\u63A5\u6210\u529F",
199
+ unavailable: "\u8FDE\u63A5\u4E0D\u53EF\u7528",
200
+ error: "\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
201
+ loading: "\u6B63\u5728\u8BFB\u53D6\u4F1A\u8BDD\u72B6\u6001",
202
+ destination: "\u88C1\u51B3\u65F6\u4F1A\u5411\u4EE5\u4E0B\u540E\u7AEF\u53D1\u9001\u5FC5\u8981\u7684\u8BC4\u4F30\u4E0A\u4E0B\u6587\uFF1A",
203
+ httpWarning: "\u6B64\u5730\u5740\u4F7F\u7528\u672A\u52A0\u5BC6\u7684 HTTP\u3002\u786E\u8BA4\u540E\uFF0CAPI Key \u4E0E\u8BC4\u4F30\u4E0A\u4E0B\u6587\u5C06\u4EE5\u660E\u6587\u53D1\u9001\u81F3\u8BE5\u5730\u5740\u3002",
204
+ analysisTab: "\u51B3\u7B56\u5206\u6790",
205
+ analysisTitle: "\u51B3\u7B56\u5206\u6790",
206
+ analysisIntro: "\u57FA\u4E8E\u672C\u4F1A\u8BDD\u5DF2\u843D\u76D8\u7684\u51B3\u7B56\u65E5\u5FD7\u505A\u805A\u5408\u4E0E\u4EBA\u5DE5\u6807\u6CE8\uFF1B\u9875\u5934\u5F00\u5173\u53EA\u63A7\u5236\u672C\u4F1A\u8BDD\u662F\u5426\u81EA\u52A8\u4ECB\u5165\uFF0C\u4E0D\u6539\u52A8\u5386\u53F2\u8BB0\u5F55\u3002",
207
+ analysisDecisionSwitch: "\u672C\u4F1A\u8BDD\u81EA\u52A8\u4ECB\u5165",
208
+ analysisDecisionOn: "\u5DF2\u5F00\u542F",
209
+ analysisDecisionOff: "\u5DF2\u5173\u95ED",
210
+ analysisDecisionUnavailable: "\u4E0D\u53EF\u7528",
211
+ analysisDecisionRetry: "\u8BFB\u53D6\u4F1A\u8BDD\u72B6\u6001\u5931\u8D25\uFF0C\u70B9\u51FB\u91CD\u8BD5\u3002",
212
+ analysisDecisionHintOn: "\u70B9\u51FB\u5173\u95ED\u672C\u4F1A\u8BDD\u7684\u81EA\u52A8\u4ECB\u5165\uFF08\u542B\u9632\u5FAA\u73AF\uFF09\uFF1B\u5DF2\u4EA7\u751F\u7684\u51B3\u7B56\u8BB0\u5F55\u4E0D\u53D7\u5F71\u54CD\u3002",
213
+ analysisDecisionHintOff: "\u70B9\u51FB\u5F00\u542F\u540E\uFF0C\u672C\u4F1A\u8BDD\u7684\u95E8\u63A7\u3001\u81EA\u68C0\u3001\u6536\u7A84\u3001\u5B8C\u6210\u6838\u5BF9\u4E0E\u9632\u5FAA\u73AF\u4F1A\u81EA\u52A8\u4ECB\u5165\u3002",
214
+ analysisDecisionDisabled: "\u672C\u4F1A\u8BDD\u7684\u81EA\u52A8\u4ECB\u5165\u5DF2\u5173\u95ED\u3002\u5F00\u542F\u540E\uFF0C\u65B0\u7684\u56DE\u5408\u624D\u4F1A\u4EA7\u751F\u51B3\u7B56\u8BB0\u5F55\u3002",
215
+ analysisProfile: "\u8FC7\u7A0B\u753B\u50CF",
216
+ analysisMeanScore: "\u5E73\u5747\u5206",
217
+ analysisTrend: "\u8D28\u91CF\u8D8B\u52BF\u56DE\u6D4B",
218
+ analysisTrendWarn: "\u544A\u8B66\u89E6\u53D1",
219
+ analysisTrendSevere: "\u4E25\u91CD\u89E6\u53D1",
220
+ analysisTrendMaxRun: "\u6700\u957F\u8FDE\u7EED\u4F4E\u5206",
221
+ analysisTrendNote: "\u7528\u5F53\u524D\u9608\u503C\u628A\u672C\u4F1A\u8BDD\u7684\u81EA\u68C0\u5206\u6570\u6309\u65F6\u95F4\u91CD\u653E\uFF0C\u7EDF\u8BA1\u544A\u8B66\u672C\u4F1A\u300C\u4F1A\u300D\u89E6\u53D1\u51E0\u6B21\uFF0C\u7528\u4E8E\u6821\u51C6\u9608\u503C\uFF0C\u4E0D\u662F\u5B9E\u65F6\u4FE1\u53F7\u3002",
222
+ analysisAccuracy: "\u5224\u65AD\u51C6\u786E\u5EA6",
223
+ analysisAccuracyEmpty: "\u5C1A\u672A\u6807\u6CE8\u4EFB\u4F55\u51B3\u7B56\u3002\u5728\u4E0B\u65B9\u51B3\u7B56\u5217\u8868\u9010\u6761\u6807\u6CE8\u300C\u5224\u5BF9 / \u5224\u9519 / \u8BF4\u4E0D\u51C6\u300D\u540E\uFF0C\u8FD9\u91CC\u7ED9\u51FA\u6C47\u603B\u3002",
224
+ analysisLogNote: "\u6807\u6CE8\u5728\u6B64\u4E0E\u4ECB\u5165\u9762\u677F\u540C\u6E90\uFF1A\u4EFB\u4E00\u5904\u6807\u6CE8\u90FD\u5199\u5165\u540C\u4E00\u4EFD\u65E5\u5FD7\u3001\u6309\u51B3\u7B56 id \u5173\u8054\u3001\u53D6\u6700\u65B0\u3002",
225
+ analysisLogTruncated: "\u672C\u4F1A\u8BDD\u6682\u65E0\u53EF\u5C55\u793A\u7684\u51B3\u7B56\u8BB0\u5F55\u3002",
226
+ pagerPrev: "\u4E0A\u4E00\u9875",
227
+ pagerNext: "\u4E0B\u4E00\u9875",
228
+ pagerStatus: "\u7B2C {page}/{pages} \u9875 \xB7 \u5171 {total} \u6761"
229
+ };
230
+ var en = {
231
+ summary: "A danger-call gate, output self-check, and loop guard driven by a pluggable adjudication model.",
232
+ button: "Decision layer",
233
+ title: "Decision layer",
234
+ close: "Close",
235
+ metrics: "Automatic decisions",
236
+ triggerDecisions: "decisions",
237
+ empty: "No automatic decisions yet. Manual verdicts are not counted here.",
238
+ attempts: "Evaluations",
239
+ failures: "Fallback failures",
240
+ suggestions: "Model suggestions (allow / ask / deny)",
241
+ actual: "Actual host outcomes (allow / deny)",
242
+ checkAttempts: "Self-check evaluations",
243
+ checkLow: "Low",
244
+ checkOk: "Passed",
245
+ settings: "Session settings",
246
+ cardGate: "Danger gate",
247
+ cardCheck: "Output self-check",
248
+ cardNarrow: "Tool narrowing",
249
+ cardComplete: "Task completion",
250
+ cardTimes: "",
251
+ allow: "Allow",
252
+ ask: "Ask",
253
+ deny: "Deny",
254
+ actualShort: "Actual",
255
+ narrowAppliedLabel: "Narrowed",
256
+ narrowDroppedLabel: "Tools dropped",
257
+ narrowDropped: "dropped",
258
+ narrowKept: "kept all",
259
+ narrowKeptCount: "kept",
260
+ narrowMore: " and {count} in total",
261
+ narrowObserve: "observe",
262
+ narrowEnforce: "enforced",
263
+ narrowNotApplied: "not applied",
264
+ checkPassRate: "Pass rate",
265
+ narrowApplyRate: "Narrow rate",
266
+ rateNa: "\u2014",
267
+ enabled: "Enable automatic interventions in this session",
268
+ backendStatus: "Backend",
269
+ statusChecking: "Checking\u2026",
270
+ statusIdle: "Not checked",
271
+ statusOk: "Connected",
272
+ statusDown: "Unavailable",
273
+ recheck: "Recheck",
274
+ log: "Decision log",
275
+ logEmpty: "No decisions recorded for this session yet.",
276
+ logGate: "Gate",
277
+ logCheck: "Self-check",
278
+ logNarrow: "Narrow",
279
+ logComplete: "Completion",
280
+ logSuggested: "model suggested",
281
+ logEvalFailed: "evaluation failed",
282
+ logScore: "score",
283
+ logConnection: "connection",
284
+ logConfidence: "confidence",
285
+ logCommandLabel: "command: ",
286
+ logPathLabel: "path: ",
287
+ logSubjectLabel: "request: ",
288
+ logScoreHint: "The score is a probability-weighted mean across the levels, so it can be fractional (e.g. 1.4); the top score is the highest level number, 2.",
289
+ logCheckHint: "After each turn, the AI\u2019s final reply for that turn is sent to the adjudication model, which grades its quality on three levels (severe omission/contradiction \u2192 minor gaps \u2192 complete and accurate) as a 0\u20132 score, to catch omissions or contradictions.",
290
+ logNarrowHint: "At the start of each turn, the current task and each available tool are sent to the adjudication model (a noul per tool) to judge relevance, dropping tools clearly not needed. It only intersects the host-allowed set and never expands it; observe merely logs the suggestion, enforced actually restricts the tools for this turn.",
291
+ actionDeny: "denied",
292
+ actionAsk: "sent to approval",
293
+ actionPass: "no intervention",
294
+ gatePassThrough: "no intervention (proceeded on its original path)",
295
+ checkResultLow: "low score",
296
+ checkResultOk: "passed",
297
+ checkResultLowNoisy: "low score (low confidence)",
298
+ checkNoiseTag: "noise, ignore",
299
+ checkNoiseHint: "The model had almost no confidence in this score (near-zero confidence). This low score does not count toward the quality trend and triggers no re-prompt \u2014 treat it as noise. What matters is several consecutive high-confidence low scores.",
300
+ reasonUnavailable: "backend unreachable",
301
+ reasonHttpError: "backend returned an error",
302
+ reasonInvalidResponse: "unexpected response shape",
303
+ reasonLowConfidence: "low confidence",
304
+ reasonConfig: "invalid configuration",
305
+ reasonTooMany: "too many candidates",
306
+ reasonTooManyCount: "{count} candidates is too many",
307
+ reasonLowKeep: "too few kept",
308
+ selfCheck: "Output self-check",
309
+ advancedSwitches: "Intervention switches",
310
+ advancedParams: "Narrowing parameters",
311
+ selfCheckSteer: "Auto re-prompt on a low score",
312
+ selfCheckHint: "Each turn ends by scoring the final reply (0\u20132, a probability-weighted mean across the levels, so it can be fractional like 1.4). Off: low scores are only logged, the conversation is not interrupted. On: when the score is low (\u22641) and the model is confident enough, one prompt is appended on your behalf asking the AI to review for gaps or contradictions and finish the work; low-confidence scores are only logged, never interrupt, and at most one prompt per turn.",
313
+ narrow: "Tool narrowing",
314
+ narrowObserveLabel: "Observe only (do not restrict tools)",
315
+ narrowHint: "At the start of each turn, the adjudication model judges how relevant each optional tool is to the task and drops the ones not needed; core tools (read, write, edit, shell, search, todos) are always kept and never judged. Enforced by default: only the relevant tools are kept for this turn, intersected with the host-allowed set and never expanded. Turn on Observe only to just log the tools that could be dropped, without changing the tool set. Three safeguards: core tools always kept; more than 20 optional tools falls back to observe only; fewer than 5 tools remaining is treated as untrustworthy and skipped.",
316
+ narrowKeepLabel: "Always-kept tool prefixes",
317
+ narrowKeepHint: "Tools whose names start with any of these prefixes are always kept and never judged for relevance \u2014 good for resident, on-demand tools like memory/retrieval (defaults to mcp__openviking only). Separate prefixes with commas or newlines; leave empty to keep nothing extra.",
318
+ narrowMaxLabel: "Candidate tool cap",
319
+ narrowMaxHint: "When more than this many optional tools are judged in one turn (default 20), narrowing downgrades to observe only instead of actually restricting, so a large surface is never mass-pruned. Range 1\u2013200; a higher value leans toward actually narrowing. Core tools and keep-prefix matches do not count.",
320
+ narrowThresholdLabel: "Drop threshold",
321
+ narrowThresholdHint: "A tool is dropped only when its relevance probability is below this value (default 0.7, leaning aggressive: only tools the model rates as fairly relevant survive). Lower is more conservative (drops fewer), higher is more aggressive. A probability near 0.5 means the model is unsure and falls below the default, so lower the threshold to keep such may-need tools. Range 0\u20131.",
322
+ batchModeLabel: "Batch strategy",
323
+ batchModeHint: "Auto (default) sends one whole-batch request first and, on a context overflow, falls back to one request per tool and remembers it; Single judges every tool in one request, best for a large-context backend (e.g. Jev); Split sends one request per tool concurrently, for a small-context backend (e.g. a local tev1 with a ~2050-token request limit).",
324
+ batchModeAuto: "Auto",
325
+ batchModeSingle: "Single",
326
+ batchModeSplit: "Split",
327
+ advancedThresholds: "Intervention thresholds",
328
+ gateMinConfidenceLabel: "Gate block confidence",
329
+ gateMinConfidenceHint: 'A "deny" verdict blocks a dangerous call only when the model is at least this confident (default 0.6). Lower blocks more and may block legitimate commands; higher is more permissive. Range 0\u20131.',
330
+ checkMinConfidenceLabel: "Self-check re-prompt confidence",
331
+ checkMinConfidenceHint: "On a low score, the supplemental prompt fires only when the model is at least this confident (default 0.4); below it the score is only logged. Range 0\u20131.",
332
+ lowScoreThresholdLabel: "Low-score threshold",
333
+ lowScoreThresholdHint: "A score at or below this counts as low (default 1; the scale is 0\u20132). Integer, 0\u20139.",
334
+ trendMinConfidenceLabel: "Trend alarm confidence",
335
+ trendMinConfidenceHint: "Only low scores at least this confident count toward the quality trend (default 0.6), so an unsure low score is not read as a real decline. Range 0\u20131.",
336
+ trendRunLabel: "Warn after",
337
+ trendRunHint: "This many consecutive high-confidence low scores raise a warning (default 3). Integer, 2\u201310.",
338
+ trendSevereRunLabel: "Severe after",
339
+ trendSevereRunHint: "This many consecutive high-confidence low scores escalate to severe (default 5). Must exceed the warn count; integer, 2\u201320.",
340
+ completeMinConfidenceLabel: "Completion re-prompt confidence",
341
+ completeMinConfidenceHint: "A condition judged unmet triggers the supplemental step only at this confidence or above (default 0.4). Range 0\u20131.",
342
+ minConditionsLabel: "Minimum listed conditions",
343
+ minConditionsHint: "The completion check runs only when the user listed at least this many explicit conditions (default 2). Integer, 2\u201320.",
344
+ advancedRubric: "Grading levels",
345
+ selfCheckRubricLabel: "Grading levels",
346
+ selfCheckRubricHint: "One level per line, lowest first, used to score the final reply (three levels by default, i.e. scores 0\u20132). At least 2 and at most 10 levels, 256 characters each. An invalid list is not saved; the specific problem is shown below the box.",
347
+ rubricTooFew: "At least 2 levels are required (one per line).",
348
+ rubricTooMany: "At most 10 levels are allowed; remove the extra ones.",
349
+ rubricLevelTooLong: "Level {line} exceeds 256 characters; shorten it before saving.",
350
+ features: "Decision points",
351
+ basicFeatures: "Basic features",
352
+ advancedConfig: "Advanced settings",
353
+ featureGate: "Danger gate",
354
+ featureGateHint: "When off, destructive tool calls are no longer evaluated for interception and are only bound by the host permission rules.",
355
+ featureCheck: "Output self-check",
356
+ featureCheckHint: "When off, the final reply is no longer scored at the end of a turn.",
357
+ featureNarrow: "Tool narrowing",
358
+ featureNarrowHint: "When off, tool relevance is no longer evaluated at the start of a turn. The loop guard is a deterministic local safeguard outside these switches, but the session master switch pauses it too.",
359
+ featureComplete: "Task completion check",
360
+ featureCompleteHint: "When off, the explicit deliverable conditions the user listed are no longer checked at turn end.",
361
+ trendWarnHint: "Output quality has been low for a few consecutive turns this session (high confidence). It may be rising task difficulty or model drift \u2014 consider adjusting the prompt or switching models.",
362
+ trendSevereHint: "Output quality has stayed low this session (high confidence). Consider adjusting the prompt, switching models, or starting a new session.",
363
+ rateGroup: "Rate this decision",
364
+ rateGood: "Correct",
365
+ rateBad: "Wrong",
366
+ rateUnsure: "Unsure",
367
+ rateSummary: "Rated {rated} ({good} correct / {bad} wrong / {unsure} unsure)",
368
+ annotateFailed: "Could not save the rating. Please retry.",
369
+ completeSteer: "Auto re-prompt on an unmet condition",
370
+ completeHint: "At turn end, each explicit deliverable condition the user listed (numbered / bulleted / multi-command) is judged satisfied / unsatisfied / insufficient evidence, with tool evidence as the source of truth \u2014 a reply claiming completion is not evidence. Off: results are only logged, the conversation is not interrupted. On: when a condition is confidently judged unsatisfied, one prompt is appended on your behalf asking the AI to review and finish it; insufficient evidence never triggers a re-prompt, and at most one per turn.",
371
+ completeResultOk: "conditions met",
372
+ completeResultUnsatisfied: "unmet found",
373
+ completeConditions: "conditions",
374
+ completeSatisfied: "met",
375
+ completeUnsatisfied: "unmet",
376
+ completeInsufficient: "insufficient",
377
+ completeSteered: "re-prompted",
378
+ backend: "Decision backend",
379
+ url: "Server URL",
380
+ model: "Model",
381
+ key: "API key",
382
+ keyHintSaved: "A key is saved. Leave blank and save to keep it; enter a new value and save to overwrite it.",
383
+ keyHintEmpty: "No key saved yet. Leave blank to use an environment credential, or enter one to save it locally.",
384
+ removeKey: "Delete saved API key",
385
+ removeKeyHint: "Permanently deletes the key this plugin stored locally, then falls back to the environment credential; credentials configured elsewhere are untouched.",
386
+ removeKeyButton: "Delete",
387
+ removeKeyConfirm: "Delete the locally saved API key? It will fall back to the environment credential.",
388
+ removeKeyDone: "Saved key deleted",
389
+ save: "Save configuration",
390
+ saveAdvanced: "Save advanced settings",
391
+ probe: "Test connection",
392
+ saved: "Configuration saved",
393
+ connected: "Connected",
394
+ unavailable: "Connection unavailable",
395
+ error: "Request failed. Please retry.",
396
+ loading: "Loading session settings",
397
+ destination: "Decisions send the necessary evaluation context to this backend:",
398
+ httpWarning: "This address uses unencrypted HTTP. Your API key and evaluation context will be sent in plaintext to this address.",
399
+ analysisTab: "Decision analysis",
400
+ analysisTitle: "Decision analysis",
401
+ analysisIntro: "An aggregate and manual annotation over this session\u2019s persisted decision log. The switch in the header only controls automatic interventions for this session and never rewrites history.",
402
+ analysisDecisionSwitch: "Automatic interventions",
403
+ analysisDecisionOn: "on",
404
+ analysisDecisionOff: "off",
405
+ analysisDecisionUnavailable: "unavailable",
406
+ analysisDecisionRetry: "Could not read the session state. Click to retry.",
407
+ analysisDecisionHintOn: "Turn off automatic interventions for this session, including the loop guard. Existing decision records are unaffected.",
408
+ analysisDecisionHintOff: "Turn on automatic interventions (gate, self-check, narrowing, completion check, and loop guard) for this session.",
409
+ analysisDecisionDisabled: "Automatic interventions are off for this session. New decision records appear after you enable them.",
410
+ analysisProfile: "Process profile",
411
+ analysisMeanScore: "Mean score",
412
+ analysisTrend: "Quality-trend backtest",
413
+ analysisTrendWarn: "Warn fires",
414
+ analysisTrendSevere: "Severe fires",
415
+ analysisTrendMaxRun: "Longest low run",
416
+ analysisTrendNote: "Replays this session\u2019s self-check scores in time order under the current thresholds to count how often the alarm would fire \u2014 a calibration aid, not a live signal.",
417
+ analysisAccuracy: "Decision accuracy",
418
+ analysisAccuracyEmpty: "No decisions rated yet. Rate rows below as correct / wrong / unsure and a summary appears here.",
419
+ analysisLogNote: "Ratings here share one source with the intervention panel: a rating on either surface writes to the same log, keyed by decision id, latest wins.",
420
+ analysisLogTruncated: "No decision rows to show for this session.",
421
+ pagerPrev: "Prev",
422
+ pagerNext: "Next",
423
+ pagerStatus: "Page {page}/{pages} \xB7 {total} total"
352
424
  };
425
+ var dictionaries = { zh, en };
353
426
 
354
427
  // src/client/panel.tsx
355
428
  var import_react2 = require("react");
@@ -363,6 +436,23 @@ async function request(path, init) {
363
436
  return body.value;
364
437
  }
365
438
 
439
+ // src/client/session-events.ts
440
+ var SESSION_ENABLED_EVENT = "dsh-decision-layer:session-enabled";
441
+ function announceSessionEnabled(change) {
442
+ if (typeof window === "undefined") return;
443
+ window.dispatchEvent(new window.CustomEvent(SESSION_ENABLED_EVENT, { detail: change }));
444
+ }
445
+ function onSessionEnabled(listener) {
446
+ if (typeof window === "undefined") return () => {
447
+ };
448
+ const handler = (event) => {
449
+ const change = event.detail;
450
+ if (change && typeof change.sessionId === "string" && typeof change.enabled === "boolean") listener(change);
451
+ };
452
+ window.addEventListener(SESSION_ENABLED_EVENT, handler);
453
+ return () => window.removeEventListener(SESSION_ENABLED_EVENT, handler);
454
+ }
455
+
366
456
  // src/client/decision-log.tsx
367
457
  var import_jsx_runtime = require("react/jsx-runtime");
368
458
  var time = (at) => new Date(at).toLocaleTimeString();
@@ -519,9 +609,13 @@ function renderNarrow({ t }, entry) {
519
609
  " \xB7 ",
520
610
  guardText
521
611
  ] }) : null;
522
- const modeTag = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "decision-log-detail", children: [
612
+ const notApplied = entry.applied === false || entry.reason === "low-keep" || entry.reason === "too-many-candidates";
613
+ const modeTag = entry.mode === "observe" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "decision-log-detail", children: [
614
+ " \xB7 ",
615
+ t("narrowObserve")
616
+ ] }) : dropped === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "decision-log-detail", children: [
523
617
  " \xB7 ",
524
- entry.mode === "enforce" ? t("narrowEnforce") : t("narrowObserve")
618
+ notApplied ? t("narrowNotApplied") : t("narrowEnforce")
525
619
  ] });
526
620
  if (dropped === 0) {
527
621
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
@@ -700,6 +794,7 @@ var import_jsx_runtime3 = require("react/jsx-runtime");
700
794
  function DecisionPanel(props) {
701
795
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SessionPanel, { ...props }, props.sessionId);
702
796
  }
797
+ var NO_PROJECTION = () => void 0;
703
798
  function Bar({ allow, ask, deny }) {
704
799
  const total = allow + ask + deny;
705
800
  if (total === 0) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "decision-bar decision-bar-empty", "aria-hidden": "true" });
@@ -710,7 +805,7 @@ function Bar({ allow, ask, deny }) {
710
805
  deny > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "decision-bar-deny", style: { width: pct(deny) } })
711
806
  ] });
712
807
  }
713
- function SessionPanel({ sessionId, t }) {
808
+ function SessionPanel({ sessionId, t, useProjection }) {
714
809
  const dialog = (0, import_react2.useRef)(null);
715
810
  const trigger = (0, import_react2.useRef)(null);
716
811
  const mounted = (0, import_react2.useRef)(true);
@@ -740,6 +835,9 @@ function SessionPanel({ sessionId, t }) {
740
835
  live = false;
741
836
  };
742
837
  }, [sessionId, t]);
838
+ (0, import_react2.useEffect)(() => onSessionEnabled((change) => {
839
+ if (change.sessionId === sessionId) setEnabled(change.enabled);
840
+ }), [sessionId]);
743
841
  const checkStatus = () => {
744
842
  setStatus("checking");
745
843
  void request("probe", { method: "POST" }).then((value) => {
@@ -781,6 +879,7 @@ function SessionPanel({ sessionId, t }) {
781
879
  body: JSON.stringify({ sessionId, enabled: next })
782
880
  });
783
881
  setEnabled(value.enabled);
882
+ announceSessionEnabled({ sessionId, enabled: value.enabled });
784
883
  } catch {
785
884
  setMessage(t("error"));
786
885
  } finally {
@@ -795,6 +894,11 @@ function SessionPanel({ sessionId, t }) {
795
894
  const checkPassRate = metrics?.check && checkValid > 0 ? Math.round((checkValid - metrics.check.low) / checkValid * 100) : null;
796
895
  const narrowValid = metrics?.narrow ? metrics.narrow.attempts - metrics.narrow.failures : 0;
797
896
  const narrowApplyRate = metrics?.narrow && narrowValid > 0 ? Math.round(metrics.narrow.applied / narrowValid * 100) : null;
897
+ const readProjection = useProjection ?? NO_PROJECTION;
898
+ const pressure = readProjection("contextPressure");
899
+ const usedTokens = pressure?.projectedTokens ?? pressure?.pressureTokens;
900
+ const contextReady = useProjection === void 0 || usedTokens !== void 0 && pressure?.contextWindow !== void 0;
901
+ if (!contextReady) return null;
798
902
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
799
903
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { ref: trigger, className: `decision-trigger decision-trend-${severity}`, type: "button", "aria-haspopup": "dialog", "aria-expanded": open, "aria-busy": enabled === null, "aria-label": t("button"), title: trendTitle, onClick: () => setOpen(true), children: [
800
904
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { className: "decision-trigger-icon", width: "15", height: "15", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
@@ -983,7 +1087,30 @@ function AnalysisView({ sessionId, t }) {
983
1087
  const [logPage, setLogPage] = (0, import_react3.useState)(1);
984
1088
  const [loaded, setLoaded] = (0, import_react3.useState)(false);
985
1089
  const [message, setMessage] = (0, import_react3.useState)("");
1090
+ const [enabled, setEnabled] = (0, import_react3.useState)(null);
1091
+ const [sessionError, setSessionError] = (0, import_react3.useState)(false);
1092
+ const [busy, setBusy] = (0, import_react3.useState)(false);
986
1093
  const { ratings, seed, annotate } = useAnnotations(sessionId, () => setMessage(t("annotateFailed")));
1094
+ const active = (0, import_react3.useRef)(sessionId);
1095
+ const loadSession = () => {
1096
+ const session = sessionId;
1097
+ setEnabled(null);
1098
+ setSessionError(false);
1099
+ void request(`session?sessionId=${encodeURIComponent(session)}`).then((value) => {
1100
+ if (active.current === session) setEnabled(value.enabled);
1101
+ }).catch(() => {
1102
+ if (active.current === session) setSessionError(true);
1103
+ });
1104
+ };
1105
+ (0, import_react3.useEffect)(() => {
1106
+ active.current = sessionId;
1107
+ setBusy(false);
1108
+ setMessage("");
1109
+ loadSession();
1110
+ }, [sessionId]);
1111
+ (0, import_react3.useEffect)(() => onSessionEnabled((change) => {
1112
+ if (change.sessionId === sessionId) setEnabled(change.enabled);
1113
+ }), [sessionId]);
987
1114
  (0, import_react3.useEffect)(() => {
988
1115
  let alive = true;
989
1116
  setMessage("");
@@ -1003,6 +1130,32 @@ function AnalysisView({ sessionId, t }) {
1003
1130
  alive = false;
1004
1131
  };
1005
1132
  }, [sessionId, seed]);
1133
+ const toggleEnabled = async () => {
1134
+ if (sessionError) {
1135
+ loadSession();
1136
+ return;
1137
+ }
1138
+ if (enabled === null || busy) return;
1139
+ const next = !enabled;
1140
+ const session = sessionId;
1141
+ setBusy(true);
1142
+ try {
1143
+ const value = await request("session", {
1144
+ method: "PUT",
1145
+ headers: { "content-type": "application/json" },
1146
+ body: JSON.stringify({ sessionId: session, enabled: next })
1147
+ });
1148
+ if (active.current === session) {
1149
+ setEnabled(value.enabled);
1150
+ setMessage("");
1151
+ announceSessionEnabled({ sessionId: session, enabled: value.enabled });
1152
+ }
1153
+ } catch {
1154
+ if (active.current === session) setMessage(t("error"));
1155
+ } finally {
1156
+ if (active.current === session) setBusy(false);
1157
+ }
1158
+ };
1006
1159
  (0, import_react3.useEffect)(() => {
1007
1160
  let alive = true;
1008
1161
  void request(`logrows?sessionId=${encodeURIComponent(sessionId)}&page=${logPage}&pageSize=${LOG_PAGE_SIZE}`).then((value) => {
@@ -1019,9 +1172,30 @@ function AnalysisView({ sessionId, t }) {
1019
1172
  const meanScore = profile && profile.check.scoreCount > 0 ? Math.round(profile.check.scoreSum / profile.check.scoreCount * 10) / 10 : null;
1020
1173
  const completeTotal = profile ? profile.complete.satisfied + profile.complete.unsatisfied + profile.complete.insufficient : 0;
1021
1174
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "decision-analysis", role: "region", "aria-label": t("analysisTitle"), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "decision-analysis-inner", children: [
1022
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "decision-analysis-title", children: t("analysisTitle") }),
1023
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "decision-muted decision-analysis-intro", children: t("analysisIntro") }),
1024
- loaded && (!analysis || analysis.totalDecisions === 0) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "decision-empty", role: "status", children: t("logEmpty") }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1175
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "decision-analysis-head", children: [
1176
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "decision-analysis-heading", children: [
1177
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "decision-analysis-title", children: t("analysisTitle") }),
1178
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "decision-muted decision-analysis-intro", children: t("analysisIntro") })
1179
+ ] }),
1180
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1181
+ "button",
1182
+ {
1183
+ type: "button",
1184
+ className: "decision-analysis-switch",
1185
+ "aria-pressed": enabled === true,
1186
+ "aria-busy": busy || enabled === null && !sessionError,
1187
+ disabled: busy || enabled === null && !sessionError,
1188
+ title: sessionError ? t("analysisDecisionRetry") : enabled === false ? t("analysisDecisionHintOff") : enabled === true ? t("analysisDecisionHintOn") : void 0,
1189
+ onClick: () => void toggleEnabled(),
1190
+ children: [
1191
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "decision-analysis-switch-dot", "aria-hidden": "true" }),
1192
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("analysisDecisionSwitch") }),
1193
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "decision-analysis-switch-state", children: sessionError ? t("analysisDecisionUnavailable") : enabled === null ? t("loading") : enabled ? t("analysisDecisionOn") : t("analysisDecisionOff") })
1194
+ ]
1195
+ }
1196
+ )
1197
+ ] }),
1198
+ loaded && (!analysis || analysis.totalDecisions === 0) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "decision-empty", role: "status", children: enabled === false ? t("analysisDecisionDisabled") : t("logEmpty") }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1025
1199
  profile && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: "decision-analysis-section", children: [
1026
1200
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { children: t("analysisProfile") }),
1027
1201
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "decision-analysis-cards", children: [
@@ -1101,9 +1275,54 @@ async function request2(path, fetchFn, init) {
1101
1275
  if (!response.ok || !body.ok || body.value === void 0) throw new Error(body.error || "Request failed");
1102
1276
  return body.value;
1103
1277
  }
1104
- var DEFAULT_KEEP_PREFIXES = ["mcp__openviking", "team_task_"];
1278
+ var DEFAULT_KEEP_PREFIXES = ["mcp__openviking"];
1105
1279
  var DEFAULT_MAX_CANDIDATES = 20;
1106
- var DEFAULT_THRESHOLD = 0.3;
1280
+ var DEFAULT_THRESHOLD = 0.7;
1281
+ var DEFAULT_BATCH_MODE = "auto";
1282
+ var DEFAULT_RUBRIC = [
1283
+ "\u660E\u663E\u7B54\u975E\u6240\u95EE\uFF0C\u6216\u5B58\u5728\u4E25\u91CD\u9057\u6F0F / \u81EA\u76F8\u77DB\u76FE",
1284
+ "\u57FA\u672C\u7B54\u5230\u95EE\u9898\uFF0C\u4F46\u6709\u53EF\u5BDF\u89C9\u7684\u9057\u6F0F\u6216\u4E0D\u4E25\u8C28",
1285
+ "\u5B8C\u6574\u3001\u51C6\u786E\u3001\u65E0\u81EA\u76F8\u77DB\u76FE\u5730\u56DE\u5E94\u4E86\u8BF7\u6C42"
1286
+ ];
1287
+ var THRESHOLD_DEFAULTS = {
1288
+ gateMin: 0.6,
1289
+ checkMin: 0.4,
1290
+ lowScore: 1,
1291
+ trendMin: 0.6,
1292
+ trendRun: 3,
1293
+ trendSevere: 5,
1294
+ completeMin: 0.4,
1295
+ minConditions: 2
1296
+ };
1297
+ var defaultThresholds = () => Object.fromEntries(
1298
+ Object.entries(THRESHOLD_DEFAULTS).map(([name, value]) => [name, String(value)])
1299
+ );
1300
+ var RUBRIC_MAX_LEVELS = 10;
1301
+ var RUBRIC_MAX_LEVEL_LENGTH = 256;
1302
+ var thresholdsOf = (value) => {
1303
+ const trendRun = value.checkSettings?.trendRun ?? THRESHOLD_DEFAULTS.trendRun;
1304
+ return {
1305
+ gateMin: String(value.gateSettings?.minConfidence ?? THRESHOLD_DEFAULTS.gateMin),
1306
+ checkMin: String(value.checkSettings?.minConfidence ?? THRESHOLD_DEFAULTS.checkMin),
1307
+ lowScore: String(value.checkSettings?.lowScoreThreshold ?? THRESHOLD_DEFAULTS.lowScore),
1308
+ trendMin: String(value.checkSettings?.trendMinConfidence ?? THRESHOLD_DEFAULTS.trendMin),
1309
+ trendRun: String(trendRun),
1310
+ // The service derives an unset severe tier from the warn tier
1311
+ // (self-check.mjs: Math.max(trendRun + 1, 5)), so mirror that here or the box
1312
+ // reports a value the service is not using.
1313
+ trendSevere: String(value.checkSettings?.trendSevereRun ?? Math.max(trendRun + 1, THRESHOLD_DEFAULTS.trendSevere)),
1314
+ completeMin: String(value.completeSettings?.minConfidence ?? THRESHOLD_DEFAULTS.completeMin),
1315
+ minConditions: String(value.completeSettings?.minConditions ?? THRESHOLD_DEFAULTS.minConditions)
1316
+ };
1317
+ };
1318
+ var clampNumber = (raw, fallback, min, max, integer = false) => {
1319
+ const parsed = integer ? Number.parseInt(raw, 10) : Number.parseFloat(raw);
1320
+ if (!Number.isFinite(parsed)) return fallback;
1321
+ const clamped = Math.min(max, Math.max(min, parsed));
1322
+ return integer ? Math.round(clamped) : clamped;
1323
+ };
1324
+ var rubricLevels = (text) => text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
1325
+ var rubricOf = (settings) => (settings?.rubric ?? DEFAULT_RUBRIC).join("\n");
1107
1326
  var parsePrefixes = (text) => Array.from(new Set(text.split(/[,\r\n]+/).map((line) => line.trim()).filter(Boolean)));
1108
1327
  var prefixesText = (settings) => (settings?.keepPrefixes ?? DEFAULT_KEEP_PREFIXES).join("\n");
1109
1328
  var maxCandidatesOf = (settings) => settings?.maxCandidates ?? DEFAULT_MAX_CANDIDATES;
@@ -1155,6 +1374,9 @@ function ConfigForm({ t, fetchFn = fetch }) {
1155
1374
  const [keepPrefixes, setKeepPrefixes] = (0, import_react4.useState)(DEFAULT_KEEP_PREFIXES.join("\n"));
1156
1375
  const [maxCandidates, setMaxCandidates] = (0, import_react4.useState)(String(DEFAULT_MAX_CANDIDATES));
1157
1376
  const [threshold, setThreshold] = (0, import_react4.useState)(String(DEFAULT_THRESHOLD));
1377
+ const [batchMode, setBatchMode] = (0, import_react4.useState)(DEFAULT_BATCH_MODE);
1378
+ const [rubric, setRubric] = (0, import_react4.useState)(DEFAULT_RUBRIC.join("\n"));
1379
+ const [thresholds, setThresholds] = (0, import_react4.useState)(defaultThresholds);
1158
1380
  const [gateOn, setGateOn] = (0, import_react4.useState)(true);
1159
1381
  const [checkOn, setCheckOn] = (0, import_react4.useState)(true);
1160
1382
  const [narrowOn, setNarrowOn] = (0, import_react4.useState)(true);
@@ -1183,6 +1405,13 @@ function ConfigForm({ t, fetchFn = fetch }) {
1183
1405
  setKeepPrefixes(prefixesText(value.narrowSettings));
1184
1406
  setMaxCandidates(String(maxCandidatesOf(value.narrowSettings)));
1185
1407
  setThreshold(String(thresholdOf(value.narrowSettings)));
1408
+ setBatchMode(value.narrowSettings?.batchMode ?? DEFAULT_BATCH_MODE);
1409
+ setRubric(rubricOf(value.checkSettings));
1410
+ setThresholds(thresholdsOf(value));
1411
+ };
1412
+ const setThresholdField = (key2, next) => {
1413
+ setThresholds((previous) => ({ ...previous, [key2]: next }));
1414
+ setAdvancedDirty(true);
1186
1415
  };
1187
1416
  const applyConfig = (value) => {
1188
1417
  applyBackend(value);
@@ -1224,28 +1453,76 @@ function ConfigForm({ t, fetchFn = fetch }) {
1224
1453
  }
1225
1454
  };
1226
1455
  const featureState = () => ({ gate: gateOn, check: checkOn, narrow: narrowOn, complete: completeOn });
1456
+ const canEdit = ready && !busy;
1457
+ const rubricIssue = (() => {
1458
+ const levels = rubricLevels(rubric);
1459
+ if (levels.length < 2) return t("rubricTooFew");
1460
+ if (levels.length > RUBRIC_MAX_LEVELS) return t("rubricTooMany");
1461
+ const tooLong = levels.findIndex((level) => level.length > RUBRIC_MAX_LEVEL_LENGTH);
1462
+ return tooLong >= 0 ? t("rubricLevelTooLong", { line: tooLong + 1 }) : void 0;
1463
+ })();
1227
1464
  const saveAdvanced = async (event) => {
1228
1465
  event.preventDefault();
1229
- const parsedCap = Number.parseInt(maxCandidates, 10);
1230
- const cap = Number.isFinite(parsedCap) ? Math.min(200, Math.max(1, parsedCap)) : DEFAULT_MAX_CANDIDATES;
1231
- const parsedThreshold = Number.parseFloat(threshold);
1232
- const thresh = Number.isFinite(parsedThreshold) ? Math.min(1, Math.max(0, parsedThreshold)) : DEFAULT_THRESHOLD;
1466
+ if (rubricIssue) {
1467
+ setMessage({ text: rubricIssue, ok: false });
1468
+ return;
1469
+ }
1470
+ const cap = clampNumber(maxCandidates, DEFAULT_MAX_CANDIDATES, 1, 200, true);
1471
+ const thresh = clampNumber(threshold, DEFAULT_THRESHOLD, 0, 1);
1472
+ const trendRun = clampNumber(thresholds.trendRun, THRESHOLD_DEFAULTS.trendRun, 2, 10, true);
1473
+ const trendSevereRun = Math.max(
1474
+ trendRun + 1,
1475
+ clampNumber(thresholds.trendSevere, THRESHOLD_DEFAULTS.trendSevere, 2, 20, true)
1476
+ );
1233
1477
  setBusy(true);
1234
1478
  try {
1235
1479
  const value = await request2("config", fetchFn, {
1236
1480
  method: "PUT",
1237
1481
  headers: { "content-type": "application/json" },
1238
1482
  body: JSON.stringify({
1239
- checkSettings: { mode: checkMode },
1240
- narrowSettings: { mode: narrowMode, keepPrefixes: parsePrefixes(keepPrefixes), maxCandidates: cap, threshold: thresh },
1241
- completeSettings: { mode: completeMode }
1483
+ gateSettings: {
1484
+ ...config.gateSettings,
1485
+ minConfidence: clampNumber(thresholds.gateMin, THRESHOLD_DEFAULTS.gateMin, 0, 1)
1486
+ },
1487
+ checkSettings: {
1488
+ ...config.checkSettings,
1489
+ mode: checkMode,
1490
+ rubric: rubricLevels(rubric),
1491
+ lowScoreThreshold: clampNumber(thresholds.lowScore, THRESHOLD_DEFAULTS.lowScore, 0, 9, true),
1492
+ minConfidence: clampNumber(thresholds.checkMin, THRESHOLD_DEFAULTS.checkMin, 0, 1),
1493
+ trendMinConfidence: clampNumber(thresholds.trendMin, THRESHOLD_DEFAULTS.trendMin, 0, 1),
1494
+ trendRun,
1495
+ trendSevereRun
1496
+ },
1497
+ narrowSettings: {
1498
+ ...config.narrowSettings,
1499
+ mode: narrowMode,
1500
+ keepPrefixes: parsePrefixes(keepPrefixes),
1501
+ maxCandidates: cap,
1502
+ threshold: thresh,
1503
+ batchMode
1504
+ },
1505
+ completeSettings: {
1506
+ ...config.completeSettings,
1507
+ mode: completeMode,
1508
+ minConditions: clampNumber(thresholds.minConditions, THRESHOLD_DEFAULTS.minConditions, 2, 20, true),
1509
+ minConfidence: clampNumber(thresholds.completeMin, THRESHOLD_DEFAULTS.completeMin, 0, 1)
1510
+ }
1242
1511
  })
1243
1512
  });
1513
+ setConfig((previous) => ({
1514
+ ...previous,
1515
+ gateSettings: value.gateSettings ?? previous.gateSettings,
1516
+ checkSettings: value.checkSettings ?? previous.checkSettings,
1517
+ narrowSettings: value.narrowSettings ?? previous.narrowSettings,
1518
+ completeSettings: value.completeSettings ?? previous.completeSettings
1519
+ }));
1244
1520
  applyAdvanced(value);
1245
1521
  setAdvancedDirty(false);
1246
1522
  setMessage({ text: t("saved"), ok: true });
1247
- } catch {
1248
- setMessage({ text: t("error"), ok: false });
1523
+ } catch (error) {
1524
+ const reason = error instanceof Error && error.message && error.message !== "Request failed" ? error.message : "";
1525
+ setMessage({ text: reason ? `${t("error")} (${reason})` : t("error"), ok: false });
1249
1526
  } finally {
1250
1527
  setBusy(false);
1251
1528
  }
@@ -1323,7 +1600,7 @@ ${url}`)) return;
1323
1600
  {
1324
1601
  label: t("featureGate"),
1325
1602
  checked: gateOn,
1326
- disabled: !ready || busy,
1603
+ disabled: !canEdit,
1327
1604
  onChange: (next) => {
1328
1605
  setGateOn(next);
1329
1606
  void toggleFeature({ ...featureState(), gate: next }, () => setGateOn(!next));
@@ -1336,7 +1613,7 @@ ${url}`)) return;
1336
1613
  {
1337
1614
  label: t("featureCheck"),
1338
1615
  checked: checkOn,
1339
- disabled: !ready || busy,
1616
+ disabled: !canEdit,
1340
1617
  onChange: (next) => {
1341
1618
  setCheckOn(next);
1342
1619
  void toggleFeature({ ...featureState(), check: next }, () => setCheckOn(!next));
@@ -1349,7 +1626,7 @@ ${url}`)) return;
1349
1626
  {
1350
1627
  label: t("featureNarrow"),
1351
1628
  checked: narrowOn,
1352
- disabled: !ready || busy,
1629
+ disabled: !canEdit,
1353
1630
  onChange: (next) => {
1354
1631
  setNarrowOn(next);
1355
1632
  void toggleFeature({ ...featureState(), narrow: next }, () => setNarrowOn(!next));
@@ -1362,7 +1639,7 @@ ${url}`)) return;
1362
1639
  {
1363
1640
  label: t("featureComplete"),
1364
1641
  checked: completeOn,
1365
- disabled: !ready || busy,
1642
+ disabled: !canEdit,
1366
1643
  onChange: (next) => {
1367
1644
  setCompleteOn(next);
1368
1645
  void toggleFeature({ ...featureState(), complete: next }, () => setCompleteOn(!next));
@@ -1389,7 +1666,7 @@ ${url}`)) return;
1389
1666
  {
1390
1667
  label: t("selfCheckSteer"),
1391
1668
  checked: checkMode === "steer",
1392
- disabled: !ready || !checkOn,
1669
+ disabled: !canEdit || !checkOn,
1393
1670
  onChange: (next) => {
1394
1671
  setCheckMode(next ? "steer" : "observe");
1395
1672
  setAdvancedDirty(true);
@@ -1402,7 +1679,7 @@ ${url}`)) return;
1402
1679
  {
1403
1680
  label: t("narrowObserveLabel"),
1404
1681
  checked: narrowMode === "observe",
1405
- disabled: !ready || !narrowOn,
1682
+ disabled: !canEdit || !narrowOn,
1406
1683
  onChange: (next) => {
1407
1684
  setNarrowMode(next ? "observe" : "enforce");
1408
1685
  setAdvancedDirty(true);
@@ -1415,7 +1692,7 @@ ${url}`)) return;
1415
1692
  {
1416
1693
  label: t("completeSteer"),
1417
1694
  checked: completeMode === "steer",
1418
- disabled: !ready || !completeOn,
1695
+ disabled: !canEdit || !completeOn,
1419
1696
  onChange: (next) => {
1420
1697
  setCompleteMode(next ? "steer" : "observe");
1421
1698
  setAdvancedDirty(true);
@@ -1434,7 +1711,7 @@ ${url}`)) return;
1434
1711
  className: "decision-prefixes",
1435
1712
  rows: 3,
1436
1713
  value: keepPrefixes,
1437
- disabled: !ready || !narrowOn,
1714
+ disabled: !canEdit || !narrowOn,
1438
1715
  placeholder: "mcp__openviking",
1439
1716
  onChange: (event) => {
1440
1717
  setKeepPrefixes(event.target.value);
@@ -1455,7 +1732,7 @@ ${url}`)) return;
1455
1732
  max: 200,
1456
1733
  step: 1,
1457
1734
  value: maxCandidates,
1458
- disabled: !ready || !narrowOn,
1735
+ disabled: !canEdit || !narrowOn,
1459
1736
  placeholder: "20",
1460
1737
  onChange: (event) => {
1461
1738
  setMaxCandidates(event.target.value);
@@ -1474,10 +1751,10 @@ ${url}`)) return;
1474
1751
  type: "number",
1475
1752
  min: 0,
1476
1753
  max: 1,
1477
- step: 0.05,
1754
+ step: "any",
1478
1755
  value: threshold,
1479
- disabled: !ready || !narrowOn,
1480
- placeholder: "0.3",
1756
+ disabled: !canEdit || !narrowOn,
1757
+ placeholder: "0.7",
1481
1758
  onChange: (event) => {
1482
1759
  setThreshold(event.target.value);
1483
1760
  setAdvancedDirty(true);
@@ -1485,10 +1762,193 @@ ${url}`)) return;
1485
1762
  }
1486
1763
  ),
1487
1764
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("narrowThresholdHint") })
1765
+ ] }),
1766
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1767
+ t("batchModeLabel"),
1768
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1769
+ "select",
1770
+ {
1771
+ className: "decision-select",
1772
+ value: batchMode,
1773
+ disabled: !canEdit || !narrowOn,
1774
+ onChange: (event) => {
1775
+ setBatchMode(event.target.value);
1776
+ setAdvancedDirty(true);
1777
+ },
1778
+ children: [
1779
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "auto", children: t("batchModeAuto") }),
1780
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "single", children: t("batchModeSingle") }),
1781
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "split", children: t("batchModeSplit") })
1782
+ ]
1783
+ }
1784
+ ),
1785
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("batchModeHint") })
1488
1786
  ] })
1787
+ ] }),
1788
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "decision-field-block decision-field-block-wide", children: [
1789
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "decision-subhead", children: t("advancedThresholds") }),
1790
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "decision-threshold-grid", children: [
1791
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1792
+ t("gateMinConfidenceLabel"),
1793
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1794
+ "input",
1795
+ {
1796
+ className: "decision-narrow-cap",
1797
+ type: "number",
1798
+ min: 0,
1799
+ max: 1,
1800
+ step: "any",
1801
+ value: thresholds.gateMin,
1802
+ disabled: !canEdit || !gateOn,
1803
+ onChange: (event) => setThresholdField("gateMin", event.target.value)
1804
+ }
1805
+ ),
1806
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("gateMinConfidenceHint") })
1807
+ ] }),
1808
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1809
+ t("checkMinConfidenceLabel"),
1810
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1811
+ "input",
1812
+ {
1813
+ className: "decision-narrow-cap",
1814
+ type: "number",
1815
+ min: 0,
1816
+ max: 1,
1817
+ step: "any",
1818
+ value: thresholds.checkMin,
1819
+ disabled: !canEdit || !checkOn,
1820
+ onChange: (event) => setThresholdField("checkMin", event.target.value)
1821
+ }
1822
+ ),
1823
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("checkMinConfidenceHint") })
1824
+ ] }),
1825
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1826
+ t("lowScoreThresholdLabel"),
1827
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1828
+ "input",
1829
+ {
1830
+ className: "decision-narrow-cap",
1831
+ type: "number",
1832
+ min: 0,
1833
+ max: 9,
1834
+ step: 1,
1835
+ value: thresholds.lowScore,
1836
+ disabled: !canEdit || !checkOn,
1837
+ onChange: (event) => setThresholdField("lowScore", event.target.value)
1838
+ }
1839
+ ),
1840
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("lowScoreThresholdHint") })
1841
+ ] }),
1842
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1843
+ t("trendMinConfidenceLabel"),
1844
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1845
+ "input",
1846
+ {
1847
+ className: "decision-narrow-cap",
1848
+ type: "number",
1849
+ min: 0,
1850
+ max: 1,
1851
+ step: "any",
1852
+ value: thresholds.trendMin,
1853
+ disabled: !canEdit || !checkOn,
1854
+ onChange: (event) => setThresholdField("trendMin", event.target.value)
1855
+ }
1856
+ ),
1857
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("trendMinConfidenceHint") })
1858
+ ] }),
1859
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1860
+ t("trendRunLabel"),
1861
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1862
+ "input",
1863
+ {
1864
+ className: "decision-narrow-cap",
1865
+ type: "number",
1866
+ min: 2,
1867
+ max: 10,
1868
+ step: 1,
1869
+ value: thresholds.trendRun,
1870
+ disabled: !canEdit || !checkOn,
1871
+ onChange: (event) => setThresholdField("trendRun", event.target.value)
1872
+ }
1873
+ ),
1874
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("trendRunHint") })
1875
+ ] }),
1876
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1877
+ t("trendSevereRunLabel"),
1878
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1879
+ "input",
1880
+ {
1881
+ className: "decision-narrow-cap",
1882
+ type: "number",
1883
+ min: 2,
1884
+ max: 20,
1885
+ step: 1,
1886
+ value: thresholds.trendSevere,
1887
+ disabled: !canEdit || !checkOn,
1888
+ onChange: (event) => setThresholdField("trendSevere", event.target.value)
1889
+ }
1890
+ ),
1891
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("trendSevereRunHint") })
1892
+ ] }),
1893
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1894
+ t("completeMinConfidenceLabel"),
1895
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1896
+ "input",
1897
+ {
1898
+ className: "decision-narrow-cap",
1899
+ type: "number",
1900
+ min: 0,
1901
+ max: 1,
1902
+ step: "any",
1903
+ value: thresholds.completeMin,
1904
+ disabled: !canEdit || !completeOn,
1905
+ onChange: (event) => setThresholdField("completeMin", event.target.value)
1906
+ }
1907
+ ),
1908
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("completeMinConfidenceHint") })
1909
+ ] }),
1910
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1911
+ t("minConditionsLabel"),
1912
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1913
+ "input",
1914
+ {
1915
+ className: "decision-narrow-cap",
1916
+ type: "number",
1917
+ min: 2,
1918
+ max: 20,
1919
+ step: 1,
1920
+ value: thresholds.minConditions,
1921
+ disabled: !canEdit || !completeOn,
1922
+ onChange: (event) => setThresholdField("minConditions", event.target.value)
1923
+ }
1924
+ ),
1925
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("minConditionsHint") })
1926
+ ] })
1927
+ ] })
1928
+ ] }),
1929
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "decision-field-block decision-field-block-wide", children: [
1930
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "decision-subhead", children: t("advancedRubric") }),
1931
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field", children: [
1932
+ t("selfCheckRubricLabel"),
1933
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1934
+ "textarea",
1935
+ {
1936
+ className: "decision-prefixes",
1937
+ rows: 4,
1938
+ value: rubric,
1939
+ disabled: !canEdit || !checkOn,
1940
+ onChange: (event) => {
1941
+ setRubric(event.target.value);
1942
+ setAdvancedDirty(true);
1943
+ }
1944
+ }
1945
+ ),
1946
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("selfCheckRubricHint") })
1947
+ ] }),
1948
+ rubricIssue && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { role: "status", className: "decision-muted decision-message-warn", children: rubricIssue })
1489
1949
  ] })
1490
1950
  ] }),
1491
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "decision-actions", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { disabled: busy || !ready || !advancedDirty, type: "submit", children: t("saveAdvanced") }) })
1951
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "decision-actions", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { disabled: !canEdit || !advancedDirty || Boolean(rubricIssue), type: "submit", children: t("saveAdvanced") }) })
1492
1952
  ] })
1493
1953
  ] }),
1494
1954
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { children: [
@@ -1508,7 +1968,7 @@ ${url}`)) return;
1508
1968
  {
1509
1969
  type: "url",
1510
1970
  value: config.url,
1511
- disabled: !ready,
1971
+ disabled: !canEdit,
1512
1972
  placeholder: "https://api.typesafe.ai",
1513
1973
  onChange: (event) => {
1514
1974
  setConfig({ ...config, url: event.target.value });
@@ -1524,7 +1984,7 @@ ${url}`)) return;
1524
1984
  "input",
1525
1985
  {
1526
1986
  value: config.model,
1527
- disabled: !ready,
1987
+ disabled: !canEdit,
1528
1988
  placeholder: "jev-latest",
1529
1989
  onChange: (event) => {
1530
1990
  setConfig({ ...config, model: event.target.value });
@@ -1542,7 +2002,7 @@ ${url}`)) return;
1542
2002
  type: "password",
1543
2003
  autoComplete: "off",
1544
2004
  value: key,
1545
- disabled: !ready,
2005
+ disabled: !canEdit,
1546
2006
  placeholder: config.apiKeySet ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : "",
1547
2007
  onChange: (event) => {
1548
2008
  setKey(event.target.value);
@@ -1554,8 +2014,8 @@ ${url}`)) return;
1554
2014
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: config.apiKeySet ? t("keyHintSaved") : t("keyHintEmpty") })
1555
2015
  ] }),
1556
2016
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "decision-actions", children: [
1557
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { disabled: busy || !ready, type: "submit", children: t("save") }),
1558
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "decision-secondary", disabled: busy || !ready || backendDirty, type: "button", onClick: () => void probe(), children: t("probe") }),
2017
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { disabled: !canEdit, type: "submit", children: t("save") }),
2018
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "decision-secondary", disabled: !canEdit || backendDirty, type: "button", onClick: () => void probe(), children: t("probe") }),
1559
2019
  probeResult && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { role: "status", className: `decision-probe-result${probeResult.ok ? " decision-message-ok" : " decision-message-warn"}`, children: probeResult.text })
1560
2020
  ] })
1561
2021
  ] }),
@@ -1564,7 +2024,7 @@ ${url}`)) return;
1564
2024
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "decision-danger-title", children: t("removeKey") }),
1565
2025
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("removeKeyHint") })
1566
2026
  ] }),
1567
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "decision-danger-button", disabled: busy || !ready, onClick: () => void removeSavedKey(), children: t("removeKeyButton") })
2027
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "decision-danger-button", disabled: !canEdit, onClick: () => void removeSavedKey(), children: t("removeKeyButton") })
1568
2028
  ] })
1569
2029
  ] }),
1570
2030
  message && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { role: "status", className: `decision-message${message.ok ? " decision-message-ok" : " decision-message-warn"}`, children: message.text })
@@ -1700,13 +2160,14 @@ var css = `
1700
2160
  .decision-config form{display:grid;gap:1rem;margin-top:.8rem}
1701
2161
  .decision-field{display:grid;gap:.4rem;font-size:.82rem;font-weight:600}
1702
2162
  .decision-field .decision-muted{font-weight:400;margin:.1rem 0 0}
1703
- .decision-config input:not([type=checkbox]){box-sizing:border-box;width:100%;min-height:2.4rem;border:1px solid var(--dsw-alias-border-l2,#ccd3da);border-radius:8px;padding:.4rem .7rem;background:var(--dsw-alias-bg-layer-2,#fff);color:inherit;font:inherit;font-weight:400}
1704
- .decision-config input:not([type=checkbox]):disabled{background:var(--dsw-alias-bg-layer-1,#f6f8fa);opacity:.7}
2163
+ .decision-config :is(input:not([type=checkbox]),select){box-sizing:border-box;width:100%;min-height:2.4rem;border:1px solid var(--dsw-alias-border-l2,#ccd3da);border-radius:8px;padding:.4rem .7rem;background:var(--dsw-alias-bg-layer-2,#fff);color:inherit;font:inherit;font-weight:400}
2164
+ .decision-config :is(input:not([type=checkbox]),select):disabled{background:var(--dsw-alias-bg-layer-1,#f6f8fa);opacity:.7}
1705
2165
  .decision-config textarea{box-sizing:border-box;width:100%;border:1px solid var(--dsw-alias-border-l2,#ccd3da);border-radius:8px;padding:.4rem .7rem;background:var(--dsw-alias-bg-layer-2,#fff);color:inherit;font:inherit;font-weight:400;resize:vertical;min-height:3.4rem}
1706
2166
  .decision-config textarea:disabled{background:var(--dsw-alias-bg-layer-1,#f6f8fa);opacity:.7}
1707
2167
  .decision-field-textarea{margin-top:.7rem}
1708
2168
  .decision-field-inline{margin-top:.7rem}
1709
2169
  .decision-narrow-cap{width:6rem!important}
2170
+ .decision-select{width:11rem!important}
1710
2171
  .decision-prefixes{font-family:var(--dsw-alias-font-mono,ui-monospace,SFMono-Regular,Menlo,monospace)!important;line-height:1.5}
1711
2172
 
1712
2173
  .decision-field-block{display:grid;gap:.35rem}
@@ -1715,6 +2176,11 @@ var css = `
1715
2176
  .decision-advanced-grid{display:grid;grid-template-columns:1fr;gap:1.1rem;align-items:start;justify-content:start}
1716
2177
  .decision-advanced-grid .decision-field-block+.decision-field-block{margin-top:0}
1717
2178
  @container (min-width:34rem){.decision-advanced-grid{grid-template-columns:repeat(2,minmax(0,28rem));column-gap:2rem}}
2179
+ /* A block that needs the full row width (the threshold list, the rubric box);
2180
+ its own fields flow into as many columns as fit, so eight numeric fields do
2181
+ not stretch one grid cell to ~50rem of height beside a mostly empty one. */
2182
+ .decision-field-block-wide{grid-column:1/-1}
2183
+ .decision-threshold-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(13rem,1fr));gap:.9rem 1.6rem;align-items:start}
1718
2184
  .decision-subhead{font-size:.86rem;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e)}
1719
2185
  .decision-toggle{display:flex;align-items:center;justify-content:space-between;gap:1rem;font-size:.86rem;font-weight:600;cursor:pointer}
1720
2186
  .decision-toggle-text{flex:1 1 auto}
@@ -1748,10 +2214,22 @@ var css = `
1748
2214
  /* Conversation-view "Decision analysis" tab. It reuses the card / stat / log
1749
2215
  primitives above; this block only supplies the scroll container and section
1750
2216
  rhythm, since the tab is not inside the modal's .decision-body wrapper. */
1751
- .decision-analysis{height:100%;overflow:auto;color:var(--dsw-alias-label-primary,#202124);font:inherit}
2217
+ .decision-analysis{height:100%;overflow:auto;color:var(--dsw-alias-label-primary,#202124);font:inherit;--decision-analysis-accent:#1f5d50;--decision-analysis-accent-bg:rgba(31,93,80,.08);--decision-analysis-dot:#1f8a70;--decision-analysis-ring:rgba(31,138,112,.16)}
1752
2218
  .decision-analysis-inner{max-width:52rem;margin:0 auto;padding:1.4rem 1.5rem 3rem}
2219
+ .decision-analysis-head{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;flex-wrap:wrap}
2220
+ .decision-analysis-heading{flex:1 1 18rem;min-width:0}
1753
2221
  .decision-analysis-title{font-size:1.15rem;margin:0 0 .3rem}
1754
- .decision-analysis-intro{margin:0 0 .4rem}
2222
+ .decision-analysis-intro{margin:0}
2223
+ /* The session-level automatic-intervention switch, mirrored from the dock panel.
2224
+ A pill button with a status dot: pressed = decisions on for this session. */
2225
+ .decision-analysis-switch{display:inline-flex;align-items:center;gap:.45rem;flex:0 0 auto;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2,#ccd3da);border-radius:999px;background:transparent;color:var(--dsw-alias-label-secondary,#59636e);padding:.38rem .85rem;font:inherit;font-size:.8rem;font-weight:500;line-height:1.3;white-space:nowrap;cursor:pointer;transition:color .15s,border-color .15s,background .15s}
2226
+ .decision-analysis-switch:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#eef1f3);color:var(--dsw-alias-label-primary,#202124)}
2227
+ .decision-analysis-switch[aria-pressed="true"]{border-color:var(--decision-analysis-accent);color:var(--decision-analysis-accent);background:var(--decision-analysis-accent-bg)}
2228
+ .decision-analysis-switch-dot{flex:0 0 auto;width:.5rem;height:.5rem;border-radius:50%;background:var(--dsw-alias-label-tertiary,#9aa5b1);transition:background .15s,box-shadow .15s}
2229
+ .decision-analysis-switch[aria-pressed="true"] .decision-analysis-switch-dot{background:var(--decision-analysis-dot);box-shadow:0 0 0 2px var(--decision-analysis-ring)}
2230
+ .decision-analysis-switch:disabled{opacity:.55;cursor:default}
2231
+ .decision-analysis-switch-state{font-weight:400;opacity:.8}
2232
+ .decision-analysis-switch:focus-visible{outline:2px solid var(--decision-analysis-accent);outline-offset:2px}
1755
2233
  .decision-analysis-section{border-top:1px solid var(--dsw-alias-border-l2,#eceff1);margin-top:1.1rem;padding-top:1rem}
1756
2234
  .decision-analysis-section>h3{font-size:.92rem;margin:0 0 .6rem}
1757
2235
  .decision-analysis-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(14rem,1fr));gap:.7rem}
@@ -1777,7 +2255,7 @@ var css = `
1777
2255
  .decision-pager button:disabled{opacity:.45;cursor:default}
1778
2256
  .decision-pager-status{font-size:.8rem;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}
1779
2257
  @media (prefers-color-scheme:dark){
1780
- .decision-analysis{color:var(--dsw-alias-label-primary,#e6eaee)}
2258
+ .decision-analysis{color:var(--dsw-alias-label-primary,#e6eaee);--decision-analysis-accent:#8fdcc6;--decision-analysis-accent-bg:rgba(95,191,165,.14);--decision-analysis-dot:#3ecf9e;--decision-analysis-ring:rgba(62,207,158,.2)}
1781
2259
  }
1782
2260
  `;
1783
2261
  function installStyles() {