dsh-auto-review 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +91 -0
- package/LICENSE +201 -0
- package/README.es.md +226 -0
- package/README.hi.md +226 -0
- package/README.md +226 -0
- package/README.pt.md +226 -0
- package/README.zh.md +226 -0
- package/cordis.patch.yml +27 -0
- package/lib/client.js +494 -0
- package/lib/client.js.map +1 -0
- package/lib/events-CFl6CHZi.js +344 -0
- package/lib/index.js +5305 -0
- package/lib/invariant.js +223 -0
- package/lib/types/client/ReviewPanel.d.ts +29 -0
- package/lib/types/client/ReviewPanel.d.ts.map +1 -0
- package/lib/types/client/ReviewPanel.js +63 -0
- package/lib/types/client/ReviewPanel.js.map +1 -0
- package/lib/types/client/index.d.ts +31 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/lib/types/client/index.js +51 -0
- package/lib/types/client/index.js.map +1 -0
- package/lib/types/client/locales.d.ts +49 -0
- package/lib/types/client/locales.d.ts.map +1 -0
- package/lib/types/client/locales.js +82 -0
- package/lib/types/client/locales.js.map +1 -0
- package/lib/types/client/present.d.ts +25 -0
- package/lib/types/client/present.d.ts.map +1 -0
- package/lib/types/client/present.js +36 -0
- package/lib/types/client/present.js.map +1 -0
- package/lib/types/client/styles.d.ts +9 -0
- package/lib/types/client/styles.d.ts.map +1 -0
- package/lib/types/client/styles.js +130 -0
- package/lib/types/client/styles.js.map +1 -0
- package/lib/types/config.d.ts +200 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/config.js +154 -0
- package/lib/types/config.js.map +1 -0
- package/lib/types/events.d.ts +347 -0
- package/lib/types/events.d.ts.map +1 -0
- package/lib/types/events.js +369 -0
- package/lib/types/events.js.map +1 -0
- package/lib/types/index.d.ts +26 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +26 -0
- package/lib/types/index.js.map +1 -0
- package/lib/types/invariant.d.ts +28 -0
- package/lib/types/invariant.d.ts.map +1 -0
- package/lib/types/invariant.js +306 -0
- package/lib/types/invariant.js.map +1 -0
- package/lib/types/messages.d.ts +38 -0
- package/lib/types/messages.d.ts.map +1 -0
- package/lib/types/messages.js +65 -0
- package/lib/types/messages.js.map +1 -0
- package/lib/types/projection-types.d.ts +61 -0
- package/lib/types/projection-types.d.ts.map +1 -0
- package/lib/types/projection-types.js +8 -0
- package/lib/types/projection-types.js.map +1 -0
- package/lib/types/projection.d.ts +93 -0
- package/lib/types/projection.d.ts.map +1 -0
- package/lib/types/projection.js +197 -0
- package/lib/types/projection.js.map +1 -0
- package/lib/types/review.d.ts +141 -0
- package/lib/types/review.d.ts.map +1 -0
- package/lib/types/review.js +389 -0
- package/lib/types/review.js.map +1 -0
- package/lib/types/runtime.d.ts +160 -0
- package/lib/types/runtime.d.ts.map +1 -0
- package/lib/types/runtime.js +486 -0
- package/lib/types/runtime.js.map +1 -0
- package/package.json +132 -0
- package/src/client/ReviewPanel.tsx +164 -0
- package/src/client/index.ts +72 -0
- package/src/client/locales.ts +87 -0
- package/src/client/present.ts +58 -0
- package/src/client/styles.ts +131 -0
- package/src/config.ts +346 -0
- package/src/events.ts +553 -0
- package/src/index.ts +28 -0
- package/src/invariant.ts +326 -0
- package/src/messages.ts +91 -0
- package/src/projection-types.ts +61 -0
- package/src/projection.ts +224 -0
- package/src/review.ts +428 -0
- package/src/runtime.ts +562 -0
package/lib/client.js
ADDED
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "dsh-auto-review",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react = require("react");
|
|
8
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
|
+
//#region src/client/present.ts
|
|
10
|
+
/** Present one verdict row (the component supplies the localized label texts). */
|
|
11
|
+
function presentVerdict(verdict, labels) {
|
|
12
|
+
if (verdict.fallback !== void 0) return {
|
|
13
|
+
reviewId: verdict.reviewId,
|
|
14
|
+
toolName: verdict.toolName,
|
|
15
|
+
label: labels.fallback(verdict.fallback),
|
|
16
|
+
detail: `${verdict.durationMs} ms`,
|
|
17
|
+
tone: "fallback"
|
|
18
|
+
};
|
|
19
|
+
if (verdict.escalation === "risk-policy") return {
|
|
20
|
+
reviewId: verdict.reviewId,
|
|
21
|
+
toolName: verdict.toolName,
|
|
22
|
+
label: labels.escalation,
|
|
23
|
+
detail: verdict.reason ?? "",
|
|
24
|
+
tone: "escalation"
|
|
25
|
+
};
|
|
26
|
+
const label = verdict.decision === "deny" ? labels.deny : labels.allow;
|
|
27
|
+
return {
|
|
28
|
+
reviewId: verdict.reviewId,
|
|
29
|
+
toolName: verdict.toolName,
|
|
30
|
+
label,
|
|
31
|
+
detail: verdict.reason ?? `${verdict.durationMs} ms`,
|
|
32
|
+
tone: verdict.decision === "deny" ? "deny" : "allow"
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/client/ReviewPanel.tsx
|
|
37
|
+
/**
|
|
38
|
+
* The session-header review panel: a button in the conversation header that
|
|
39
|
+
* opens a popover with this session's auto-review state — the on/off switch,
|
|
40
|
+
* budgets, cumulative statistics (including hard-disable rejections), the
|
|
41
|
+
* circuit trip, recent verdicts, and one-shot approve buttons for recent
|
|
42
|
+
* denials. Data arrives through the `autoReview` session projection;
|
|
43
|
+
* switches and approves execute the `/auto-review` command through the
|
|
44
|
+
* commands Remote.
|
|
45
|
+
* @module dsh-auto-review/client/ReviewPanel
|
|
46
|
+
*/
|
|
47
|
+
/** Compact verdict-row badge label for the panel. */
|
|
48
|
+
function verdictBadge(value, t) {
|
|
49
|
+
if (value === void 0) return t("unavailable");
|
|
50
|
+
const fallback = (kind) => t("fallbackLabel").replace("{kind}", kind);
|
|
51
|
+
const labels = {
|
|
52
|
+
allow: t("decisionAllow"),
|
|
53
|
+
deny: t("decisionDeny"),
|
|
54
|
+
fallback,
|
|
55
|
+
escalation: t("escalationLabel")
|
|
56
|
+
};
|
|
57
|
+
return value.recent.map((verdict) => presentVerdict(verdict, labels)).map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58
|
+
"data-dsh-auto-review-verdict": true,
|
|
59
|
+
children: [
|
|
60
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
61
|
+
"data-dsh-auto-review-muted": true,
|
|
62
|
+
children: row.toolName
|
|
63
|
+
}),
|
|
64
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
65
|
+
"data-dsh-auto-review": `tone-${row.tone}`,
|
|
66
|
+
children: row.label
|
|
67
|
+
}),
|
|
68
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
69
|
+
"data-dsh-auto-review-muted": true,
|
|
70
|
+
children: row.detail
|
|
71
|
+
})
|
|
72
|
+
]
|
|
73
|
+
}, row.reviewId));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Render the review panel action.
|
|
77
|
+
* @param props - framework kit (sessionId, useProjection), locale, and the approve face.
|
|
78
|
+
* @returns the header button with its popover.
|
|
79
|
+
*/
|
|
80
|
+
function ReviewPanel({ useProjection, approve, setEnabled, t }) {
|
|
81
|
+
const value = useProjection("autoReview");
|
|
82
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
83
|
+
const [notice, setNotice] = (0, react.useState)(null);
|
|
84
|
+
const anchor = (0, react.useRef)(null);
|
|
85
|
+
const toggle = () => setOpen((previous) => !previous);
|
|
86
|
+
const runApprove = async (n) => {
|
|
87
|
+
try {
|
|
88
|
+
const text = await approve(n);
|
|
89
|
+
setNotice(t("approveResult").replace("{text}", text));
|
|
90
|
+
} catch (error) {
|
|
91
|
+
setNotice(t("approveFailed").replace("{text}", error instanceof Error ? error.message : String(error)));
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const runSwitch = async (enabled) => {
|
|
95
|
+
try {
|
|
96
|
+
const text = await setEnabled(enabled);
|
|
97
|
+
setNotice(t("switchedResult").replace("{text}", text));
|
|
98
|
+
} catch (error) {
|
|
99
|
+
setNotice(t("switchFailed").replace("{text}", error instanceof Error ? error.message : String(error)));
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
103
|
+
"data-dsh-auto-review": true,
|
|
104
|
+
ref: anchor,
|
|
105
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
106
|
+
type: "button",
|
|
107
|
+
"data-dsh-auto-review-button": true,
|
|
108
|
+
onClick: toggle,
|
|
109
|
+
children: t("label")
|
|
110
|
+
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
111
|
+
"data-dsh-auto-review-panel": true,
|
|
112
|
+
children: [
|
|
113
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
114
|
+
"data-dsh-auto-review-title": true,
|
|
115
|
+
children: t("title")
|
|
116
|
+
}),
|
|
117
|
+
value === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
118
|
+
"data-dsh-auto-review-muted": true,
|
|
119
|
+
children: t("unavailable")
|
|
120
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
121
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
122
|
+
"data-dsh-auto-review-row": true,
|
|
123
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("state") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: value.enabled ? t("stateOn") : t("stateOff") })]
|
|
124
|
+
}),
|
|
125
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
126
|
+
"data-dsh-auto-review-row": true,
|
|
127
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
128
|
+
t("enable"),
|
|
129
|
+
" / ",
|
|
130
|
+
t("disable")
|
|
131
|
+
] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
132
|
+
type: "button",
|
|
133
|
+
"data-dsh-auto-review-switch": true,
|
|
134
|
+
disabled: value.enabled,
|
|
135
|
+
onClick: () => void runSwitch(true),
|
|
136
|
+
children: t("enable")
|
|
137
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
138
|
+
type: "button",
|
|
139
|
+
"data-dsh-auto-review-switch": true,
|
|
140
|
+
disabled: !value.enabled,
|
|
141
|
+
onClick: () => void runSwitch(false),
|
|
142
|
+
children: t("disable")
|
|
143
|
+
})] })]
|
|
144
|
+
}),
|
|
145
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
146
|
+
"data-dsh-auto-review-row": true,
|
|
147
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("verdicts") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: value.verdictsUsed })]
|
|
148
|
+
}),
|
|
149
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
150
|
+
"data-dsh-auto-review-row": true,
|
|
151
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("failures") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: value.failuresUsed })]
|
|
152
|
+
}),
|
|
153
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
154
|
+
"data-dsh-auto-review-row": true,
|
|
155
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("allTime") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
156
|
+
value.allows,
|
|
157
|
+
" ",
|
|
158
|
+
t("allows"),
|
|
159
|
+
" · ",
|
|
160
|
+
value.denies,
|
|
161
|
+
" ",
|
|
162
|
+
t("denies"),
|
|
163
|
+
" · ",
|
|
164
|
+
value.fallbacks,
|
|
165
|
+
" ",
|
|
166
|
+
t("fallbacks"),
|
|
167
|
+
" · ",
|
|
168
|
+
value.neverRejects,
|
|
169
|
+
" ",
|
|
170
|
+
t("neverRejects"),
|
|
171
|
+
" · ",
|
|
172
|
+
t("avg"),
|
|
173
|
+
" ",
|
|
174
|
+
value.avgDurationMs,
|
|
175
|
+
" ",
|
|
176
|
+
t("ms")
|
|
177
|
+
] })]
|
|
178
|
+
}),
|
|
179
|
+
value.circuit !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
180
|
+
"data-dsh-auto-review-circuit": true,
|
|
181
|
+
children: [
|
|
182
|
+
t("circuit"),
|
|
183
|
+
" — ",
|
|
184
|
+
t("circuitDetail").replace("{kind}", value.circuit.trip.kind).replace("{count}", String(value.circuit.trip.count)).replace("{action}", value.circuit.action)
|
|
185
|
+
]
|
|
186
|
+
}),
|
|
187
|
+
value.recentDenies.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
188
|
+
"data-dsh-auto-review-section": true,
|
|
189
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
190
|
+
"data-dsh-auto-review-title": true,
|
|
191
|
+
children: t("denyList")
|
|
192
|
+
}), value.recentDenies.map((deny, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
193
|
+
"data-dsh-auto-review-row": true,
|
|
194
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
195
|
+
"data-dsh-auto-review-muted": true,
|
|
196
|
+
children: deny.toolName
|
|
197
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
198
|
+
type: "button",
|
|
199
|
+
"data-dsh-auto-review-approve": true,
|
|
200
|
+
onClick: () => void runApprove(index + 1),
|
|
201
|
+
children: [
|
|
202
|
+
t("approve"),
|
|
203
|
+
" #",
|
|
204
|
+
index + 1
|
|
205
|
+
]
|
|
206
|
+
})]
|
|
207
|
+
}, deny.reviewId))]
|
|
208
|
+
}),
|
|
209
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
210
|
+
"data-dsh-auto-review-section": true,
|
|
211
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
212
|
+
"data-dsh-auto-review-title": true,
|
|
213
|
+
children: t("recent")
|
|
214
|
+
}), value.recent.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
215
|
+
"data-dsh-auto-review-muted": true,
|
|
216
|
+
children: t("empty")
|
|
217
|
+
}) : verdictBadge(value, t)]
|
|
218
|
+
})
|
|
219
|
+
] }),
|
|
220
|
+
notice !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
221
|
+
"data-dsh-auto-review-muted": true,
|
|
222
|
+
children: notice
|
|
223
|
+
})
|
|
224
|
+
]
|
|
225
|
+
})]
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
//#endregion
|
|
229
|
+
//#region src/client/locales.ts
|
|
230
|
+
/**
|
|
231
|
+
* Copy dictionaries for the auto-review session-header panel (en/zh — the
|
|
232
|
+
* harness locale registry accepts these two UI language codes today).
|
|
233
|
+
* @module dsh-auto-review/client/locales
|
|
234
|
+
*/
|
|
235
|
+
/** Simplified Chinese dictionary and key source of truth. */
|
|
236
|
+
const zh = {
|
|
237
|
+
label: "AI 审查",
|
|
238
|
+
title: "AI 自动审查",
|
|
239
|
+
state: "状态",
|
|
240
|
+
stateOn: "已开启",
|
|
241
|
+
stateOff: "已关闭",
|
|
242
|
+
enable: "开启",
|
|
243
|
+
disable: "关闭",
|
|
244
|
+
verdicts: "本回合 AI 裁决",
|
|
245
|
+
failures: "本回合失败",
|
|
246
|
+
allTime: "累计",
|
|
247
|
+
allows: "放行",
|
|
248
|
+
denies: "拒绝",
|
|
249
|
+
fallbacks: "失败",
|
|
250
|
+
neverRejects: "硬禁用拒绝",
|
|
251
|
+
avg: "平均耗时",
|
|
252
|
+
circuit: "拒绝熔断器已触发",
|
|
253
|
+
circuitDetail: "触发类型:{kind},计数 {count},动作 {action}",
|
|
254
|
+
empty: "本会话暂无 AI 审查裁决。",
|
|
255
|
+
recent: "最近裁决",
|
|
256
|
+
denyList: "可批准的重试",
|
|
257
|
+
approve: "批准重试",
|
|
258
|
+
approveResult: "已授权:{text}",
|
|
259
|
+
approveFailed: "批准失败:{text}",
|
|
260
|
+
switchedResult: "已切换:{text}",
|
|
261
|
+
switchFailed: "切换失败:{text}",
|
|
262
|
+
unavailable: "审查面板不可用(宿主未提供会话投影能力)。",
|
|
263
|
+
decisionAllow: "放行",
|
|
264
|
+
decisionDeny: "拒绝",
|
|
265
|
+
fallbackLabel: "失败({kind})",
|
|
266
|
+
escalationLabel: "风险策略升级",
|
|
267
|
+
riskLow: "低风险",
|
|
268
|
+
riskMedium: "中风险",
|
|
269
|
+
riskHigh: "高风险",
|
|
270
|
+
ms: "ms"
|
|
271
|
+
};
|
|
272
|
+
/** English dictionary checked against the Chinese key set. */
|
|
273
|
+
const en = {
|
|
274
|
+
label: "AI Review",
|
|
275
|
+
title: "AI Auto-Review",
|
|
276
|
+
state: "State",
|
|
277
|
+
stateOn: "ON",
|
|
278
|
+
stateOff: "OFF",
|
|
279
|
+
enable: "Enable",
|
|
280
|
+
disable: "Disable",
|
|
281
|
+
verdicts: "AI verdicts this turn",
|
|
282
|
+
failures: "Failures this turn",
|
|
283
|
+
allTime: "All-time",
|
|
284
|
+
allows: "allows",
|
|
285
|
+
denies: "denies",
|
|
286
|
+
fallbacks: "fallbacks",
|
|
287
|
+
neverRejects: "never rejects",
|
|
288
|
+
avg: "avg",
|
|
289
|
+
circuit: "Rejection circuit breaker tripped",
|
|
290
|
+
circuitDetail: "{kind}: {count} denials, action {action}",
|
|
291
|
+
empty: "No AI review verdicts in this session yet.",
|
|
292
|
+
recent: "Recent verdicts",
|
|
293
|
+
denyList: "Approvable retries",
|
|
294
|
+
approve: "Approve retry",
|
|
295
|
+
approveResult: "Authorized: {text}",
|
|
296
|
+
approveFailed: "Approve failed: {text}",
|
|
297
|
+
switchedResult: "Switched: {text}",
|
|
298
|
+
switchFailed: "Switch failed: {text}",
|
|
299
|
+
unavailable: "The review panel is unavailable (the host does not provide the session-projection capability).",
|
|
300
|
+
decisionAllow: "allow",
|
|
301
|
+
decisionDeny: "deny",
|
|
302
|
+
fallbackLabel: "fallback ({kind})",
|
|
303
|
+
escalationLabel: "risk-policy escalation",
|
|
304
|
+
riskLow: "low risk",
|
|
305
|
+
riskMedium: "medium risk",
|
|
306
|
+
riskHigh: "high risk",
|
|
307
|
+
ms: "ms"
|
|
308
|
+
};
|
|
309
|
+
/** Dictionary namespace owned by this plugin. */
|
|
310
|
+
const NS = "autoReviewPanel";
|
|
311
|
+
//#endregion
|
|
312
|
+
//#region src/client/styles.ts
|
|
313
|
+
/**
|
|
314
|
+
* Scoped stylesheet for the review panel. Standalone bundles cannot use the
|
|
315
|
+
* in-repo CSS-module pipeline, so the panel injects one `<style>` element
|
|
316
|
+
* whose selectors are all scoped under `[data-dsh-auto-review]`.
|
|
317
|
+
* @module dsh-auto-review/client/styles
|
|
318
|
+
*/
|
|
319
|
+
const STYLE_ID = "dsh-auto-review-panel-styles";
|
|
320
|
+
const CSS = `
|
|
321
|
+
[data-dsh-auto-review] {
|
|
322
|
+
--ar-allow: var(--dsw-color-success, #16a34a);
|
|
323
|
+
--ar-deny: var(--dsw-color-danger, #dc2626);
|
|
324
|
+
--ar-fallback: var(--dsw-color-warning, #d97706);
|
|
325
|
+
--ar-escalation: var(--dsw-color-warning, #d97706);
|
|
326
|
+
--ar-border: var(--dsw-color-border, rgba(128, 128, 128, 0.3));
|
|
327
|
+
--ar-bg: var(--dsw-color-surface, #ffffff);
|
|
328
|
+
--ar-fg: var(--dsw-color-text, #1f2328);
|
|
329
|
+
--ar-muted: var(--dsw-color-text-muted, #6b7280);
|
|
330
|
+
font-family: inherit;
|
|
331
|
+
color: var(--ar-fg);
|
|
332
|
+
}
|
|
333
|
+
[data-dsh-auto-review-panel] {
|
|
334
|
+
position: absolute;
|
|
335
|
+
z-index: 40;
|
|
336
|
+
min-width: 320px;
|
|
337
|
+
max-width: 420px;
|
|
338
|
+
max-height: 70vh;
|
|
339
|
+
overflow-y: auto;
|
|
340
|
+
background: var(--ar-bg);
|
|
341
|
+
border: 1px solid var(--ar-border);
|
|
342
|
+
border-radius: 8px;
|
|
343
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
|
|
344
|
+
padding: 12px;
|
|
345
|
+
font-size: 12px;
|
|
346
|
+
line-height: 1.5;
|
|
347
|
+
}
|
|
348
|
+
[data-dsh-auto-review-button] {
|
|
349
|
+
display: inline-flex;
|
|
350
|
+
align-items: center;
|
|
351
|
+
gap: 4px;
|
|
352
|
+
cursor: pointer;
|
|
353
|
+
background: transparent;
|
|
354
|
+
border: 1px solid var(--ar-border);
|
|
355
|
+
border-radius: 6px;
|
|
356
|
+
padding: 3px 8px;
|
|
357
|
+
font-size: 12px;
|
|
358
|
+
color: var(--ar-fg);
|
|
359
|
+
}
|
|
360
|
+
[data-dsh-auto-review-button]:hover {
|
|
361
|
+
background: rgba(128, 128, 128, 0.12);
|
|
362
|
+
}
|
|
363
|
+
[data-dsh-auto-review-section] {
|
|
364
|
+
margin: 8px 0;
|
|
365
|
+
border-top: 1px solid var(--ar-border);
|
|
366
|
+
padding-top: 8px;
|
|
367
|
+
}
|
|
368
|
+
[data-dsh-auto-review-title] {
|
|
369
|
+
font-weight: 600;
|
|
370
|
+
margin-bottom: 6px;
|
|
371
|
+
}
|
|
372
|
+
[data-dsh-auto-review-row] {
|
|
373
|
+
display: flex;
|
|
374
|
+
justify-content: space-between;
|
|
375
|
+
gap: 8px;
|
|
376
|
+
padding: 2px 0;
|
|
377
|
+
align-items: baseline;
|
|
378
|
+
}
|
|
379
|
+
[data-dsh-auto-review-muted] {
|
|
380
|
+
color: var(--ar-muted);
|
|
381
|
+
}
|
|
382
|
+
[data-dsh-auto-review-verdict] {
|
|
383
|
+
display: flex;
|
|
384
|
+
justify-content: space-between;
|
|
385
|
+
gap: 8px;
|
|
386
|
+
padding: 3px 0;
|
|
387
|
+
border-bottom: 1px dashed var(--ar-border);
|
|
388
|
+
}
|
|
389
|
+
[data-dsh-auto-review-tone-allow] { color: var(--ar-allow); }
|
|
390
|
+
[data-dsh-auto-review-tone-deny] { color: var(--ar-deny); }
|
|
391
|
+
[data-dsh-auto-review-tone-fallback] { color: var(--ar-fallback); }
|
|
392
|
+
[data-dsh-auto-review-tone-escalation] { color: var(--ar-escalation); }
|
|
393
|
+
[data-dsh-auto-review-approve] {
|
|
394
|
+
cursor: pointer;
|
|
395
|
+
border: 1px solid var(--ar-border);
|
|
396
|
+
border-radius: 4px;
|
|
397
|
+
background: transparent;
|
|
398
|
+
color: var(--ar-fg);
|
|
399
|
+
padding: 1px 6px;
|
|
400
|
+
font-size: 11px;
|
|
401
|
+
}
|
|
402
|
+
[data-dsh-auto-review-approve]:hover {
|
|
403
|
+
background: rgba(128, 128, 128, 0.12);
|
|
404
|
+
}
|
|
405
|
+
[data-dsh-auto-review-switch] {
|
|
406
|
+
cursor: pointer;
|
|
407
|
+
border: 1px solid var(--ar-border);
|
|
408
|
+
border-radius: 4px;
|
|
409
|
+
background: transparent;
|
|
410
|
+
color: var(--ar-fg);
|
|
411
|
+
padding: 1px 6px;
|
|
412
|
+
font-size: 11px;
|
|
413
|
+
}
|
|
414
|
+
[data-dsh-auto-review-switch] + [data-dsh-auto-review-switch] {
|
|
415
|
+
margin-left: 4px;
|
|
416
|
+
}
|
|
417
|
+
[data-dsh-auto-review-switch]:hover:not(:disabled) {
|
|
418
|
+
background: rgba(128, 128, 128, 0.12);
|
|
419
|
+
}
|
|
420
|
+
[data-dsh-auto-review-approve]:disabled,
|
|
421
|
+
[data-dsh-auto-review-switch]:disabled {
|
|
422
|
+
opacity: 0.45;
|
|
423
|
+
cursor: default;
|
|
424
|
+
}
|
|
425
|
+
[data-dsh-auto-review-circuit] {
|
|
426
|
+
color: var(--ar-deny);
|
|
427
|
+
font-weight: 600;
|
|
428
|
+
}
|
|
429
|
+
`;
|
|
430
|
+
/** Install the scoped stylesheet once per plugin fiber. */
|
|
431
|
+
function installPanelStyles() {
|
|
432
|
+
if (document.getElementById(STYLE_ID) !== null) return () => void 0;
|
|
433
|
+
const element = document.createElement("style");
|
|
434
|
+
element.id = STYLE_ID;
|
|
435
|
+
element.textContent = CSS;
|
|
436
|
+
document.head.appendChild(element);
|
|
437
|
+
return () => {
|
|
438
|
+
element.remove();
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region src/client/index.ts
|
|
443
|
+
/** Plugin name: matches the package name, the graph row id, and the bundle id. */
|
|
444
|
+
const name = "dsh-auto-review";
|
|
445
|
+
/** Services the panel reads; `remote.commands` is mounted by the api-remotes client. */
|
|
446
|
+
const inject = [
|
|
447
|
+
"slots",
|
|
448
|
+
"locale",
|
|
449
|
+
"remote",
|
|
450
|
+
"remote.commands"
|
|
451
|
+
];
|
|
452
|
+
/**
|
|
453
|
+
* Browser plugin body: dictionaries, the scoped stylesheet, and the
|
|
454
|
+
* session-header action registration.
|
|
455
|
+
* @param ctx - client root context.
|
|
456
|
+
*/
|
|
457
|
+
function apply(ctx) {
|
|
458
|
+
ctx.effect(() => ctx.locale.register(NS, {
|
|
459
|
+
zh,
|
|
460
|
+
en
|
|
461
|
+
}), "dsh-auto-review: dictionaries");
|
|
462
|
+
ctx.effect(() => installPanelStyles(), "dsh-auto-review: stylesheet");
|
|
463
|
+
ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
|
|
464
|
+
name: "conversation.session.header.actions",
|
|
465
|
+
id: "auto-review",
|
|
466
|
+
order: 40,
|
|
467
|
+
locale: NS,
|
|
468
|
+
inject: (sessionId) => {
|
|
469
|
+
const executeCommand = async (line) => {
|
|
470
|
+
const result = await ctx.remote.commands.execute(sessionId, line);
|
|
471
|
+
if (!result.ok) throw new Error(`${result.error.code}: ${result.error.message}`);
|
|
472
|
+
if (result.value === void 0) throw new Error("unknown command: /auto-review");
|
|
473
|
+
const command = result.value.result;
|
|
474
|
+
if (command === void 0) throw new Error("/auto-review produced no command result");
|
|
475
|
+
const text = command.text ?? "";
|
|
476
|
+
return command.kind === "success" ? text : `${command.kind}: ${text}`;
|
|
477
|
+
};
|
|
478
|
+
return {
|
|
479
|
+
approve: async (n) => executeCommand(`/auto-review approve ${n}`),
|
|
480
|
+
setEnabled: async (enabled) => executeCommand(`/auto-review ${enabled ? "on" : "off"}`)
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
}, ReviewPanel));
|
|
484
|
+
}
|
|
485
|
+
//#endregion
|
|
486
|
+
exports.apply = apply;
|
|
487
|
+
exports.inject = inject;
|
|
488
|
+
exports.name = name;
|
|
489
|
+
exports.presentVerdict = presentVerdict;
|
|
490
|
+
return module.exports;
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","names":["useState","useRef"],"sources":["../src/client/present.ts","../src/client/ReviewPanel.tsx","../src/client/locales.ts","../src/client/styles.ts","../src/client/index.ts"],"sourcesContent":["/**\n * Pure presentation for the review panel: verdict rows and badges as plain\n * strings and tone codes — no I/O, clock, or randomness. The component\n * owns layout and interaction; this module owns the text.\n * @module dsh-auto-review/client/present\n */\n\nimport type { AutoReviewVerdictView } from '../projection-types.ts'\n\n/** Badge tones the component maps to scoped styles. */\nexport type VerdictTone = 'allow' | 'deny' | 'fallback' | 'escalation'\n\n/** One presented verdict row. */\nexport interface PresentedVerdict {\n readonly reviewId: string\n readonly toolName: string\n readonly label: string\n readonly detail: string\n readonly tone: VerdictTone\n}\n\n/** Present one verdict row (the component supplies the localized label texts). */\nexport function presentVerdict(\n verdict: AutoReviewVerdictView,\n labels: {\n readonly allow: string\n readonly deny: string\n readonly fallback: (kind: string) => string\n readonly escalation: string\n },\n): PresentedVerdict {\n if (verdict.fallback !== undefined) {\n return {\n reviewId: verdict.reviewId,\n toolName: verdict.toolName,\n label: labels.fallback(verdict.fallback),\n detail: `${verdict.durationMs} ms`,\n tone: 'fallback',\n }\n }\n if (verdict.escalation === 'risk-policy') {\n return {\n reviewId: verdict.reviewId,\n toolName: verdict.toolName,\n label: labels.escalation,\n detail: verdict.reason ?? '',\n tone: 'escalation',\n }\n }\n const label = verdict.decision === 'deny' ? labels.deny : labels.allow\n return {\n reviewId: verdict.reviewId,\n toolName: verdict.toolName,\n label,\n detail: verdict.reason ?? `${verdict.durationMs} ms`,\n tone: verdict.decision === 'deny' ? 'deny' : 'allow',\n }\n}\n","/**\n * The session-header review panel: a button in the conversation header that\n * opens a popover with this session's auto-review state — the on/off switch,\n * budgets, cumulative statistics (including hard-disable rejections), the\n * circuit trip, recent verdicts, and one-shot approve buttons for recent\n * denials. Data arrives through the `autoReview` session projection;\n * switches and approves execute the `/auto-review` command through the\n * commands Remote.\n * @module dsh-auto-review/client/ReviewPanel\n */\n\nimport { useRef, useState, type ReactNode } from 'react'\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { AutoReviewProjection } from '../projection-types.ts'\nimport { presentVerdict } from './present.ts'\nimport { NS } from './locales.ts'\n\n/** Registration-side injected face: the approve action for one recent denial. */\nexport interface ReviewPanelInjected {\n /** Approve the n-th most recent denial (1 = most recent); resolves with the command result text. */\n approve: (n: number) => Promise<string>\n /** Switch the session's auto-review on/off (`/auto-review on|off`); resolves with the command result text. */\n setEnabled: (enabled: boolean) => Promise<string>\n}\n\n/** Full component props assembled by the session-header slot renderer. */\nexport type ReviewPanelProps =\n PropsRuntime<'conversation.session.header.actions'>\n & PropsLocale<typeof NS>\n & InjectFace<ReviewPanelInjected>\n\n/** Compact verdict-row badge label for the panel. */\nfunction verdictBadge(\n value: AutoReviewProjection | undefined,\n t: ReviewPanelProps['t'],\n): ReactNode {\n if (value === undefined) return t('unavailable')\n const fallback = (kind: string): string => t('fallbackLabel').replace('{kind}', kind)\n const labels = {\n allow: t('decisionAllow'),\n deny: t('decisionDeny'),\n fallback,\n escalation: t('escalationLabel'),\n }\n return value.recent.map(verdict => presentVerdict(verdict, labels)).map(row => (\n <div key={row.reviewId} data-dsh-auto-review-verdict>\n <span data-dsh-auto-review-muted>{row.toolName}</span>\n <span data-dsh-auto-review={`tone-${row.tone}`}>{row.label}</span>\n <span data-dsh-auto-review-muted>{row.detail}</span>\n </div>\n ))\n}\n\n/**\n * Render the review panel action.\n * @param props - framework kit (sessionId, useProjection), locale, and the approve face.\n * @returns the header button with its popover.\n */\nexport function ReviewPanel({ useProjection, approve, setEnabled, t }: ReviewPanelProps): ReactNode {\n const value = useProjection('autoReview')\n const [open, setOpen] = useState(false)\n const [notice, setNotice] = useState<string | null>(null)\n const anchor = useRef<HTMLDivElement | null>(null)\n const toggle = (): void => setOpen(previous => !previous)\n const runApprove = async (n: number): Promise<void> => {\n try {\n const text = await approve(n)\n setNotice(t('approveResult').replace('{text}', text))\n } catch (error: unknown) {\n setNotice(t('approveFailed').replace('{text}', error instanceof Error ? error.message : String(error)))\n }\n }\n const runSwitch = async (enabled: boolean): Promise<void> => {\n try {\n const text = await setEnabled(enabled)\n setNotice(t('switchedResult').replace('{text}', text))\n } catch (error: unknown) {\n setNotice(t('switchFailed').replace('{text}', error instanceof Error ? error.message : String(error)))\n }\n }\n return (\n <div data-dsh-auto-review ref={anchor}>\n <button type=\"button\" data-dsh-auto-review-button onClick={toggle}>\n {t('label')}\n </button>\n {open && (\n <div data-dsh-auto-review-panel>\n <div data-dsh-auto-review-title>{t('title')}</div>\n {value === undefined\n ? <div data-dsh-auto-review-muted>{t('unavailable')}</div>\n : (\n <div>\n <div data-dsh-auto-review-row>\n <span>{t('state')}</span>\n <span>{value.enabled ? t('stateOn') : t('stateOff')}</span>\n </div>\n <div data-dsh-auto-review-row>\n <span>{t('enable')} / {t('disable')}</span>\n <span>\n <button\n type=\"button\"\n data-dsh-auto-review-switch\n disabled={value.enabled}\n onClick={() => void runSwitch(true)}\n >\n {t('enable')}\n </button>\n <button\n type=\"button\"\n data-dsh-auto-review-switch\n disabled={!value.enabled}\n onClick={() => void runSwitch(false)}\n >\n {t('disable')}\n </button>\n </span>\n </div>\n <div data-dsh-auto-review-row>\n <span>{t('verdicts')}</span>\n <span>{value.verdictsUsed}</span>\n </div>\n <div data-dsh-auto-review-row>\n <span>{t('failures')}</span>\n <span>{value.failuresUsed}</span>\n </div>\n <div data-dsh-auto-review-row>\n <span>{t('allTime')}</span>\n <span>\n {value.allows} {t('allows')} · {value.denies} {t('denies')} · {value.fallbacks} {t('fallbacks')} · {value.neverRejects} {t('neverRejects')} · {t('avg')} {value.avgDurationMs} {t('ms')}\n </span>\n </div>\n {value.circuit !== null && (\n <div data-dsh-auto-review-circuit>\n {t('circuit')} — {t('circuitDetail')\n .replace('{kind}', value.circuit.trip.kind)\n .replace('{count}', String(value.circuit.trip.count))\n .replace('{action}', value.circuit.action)}\n </div>\n )}\n {value.recentDenies.length > 0 && (\n <div data-dsh-auto-review-section>\n <div data-dsh-auto-review-title>{t('denyList')}</div>\n {value.recentDenies.map((deny, index) => (\n <div key={deny.reviewId} data-dsh-auto-review-row>\n <span data-dsh-auto-review-muted>{deny.toolName}</span>\n <button type=\"button\" data-dsh-auto-review-approve onClick={() => void runApprove(index + 1)}>\n {t('approve')} #{index + 1}\n </button>\n </div>\n ))}\n </div>\n )}\n <div data-dsh-auto-review-section>\n <div data-dsh-auto-review-title>{t('recent')}</div>\n {value.recent.length === 0 ? <div data-dsh-auto-review-muted>{t('empty')}</div> : verdictBadge(value, t)}\n </div>\n </div>\n )}\n {notice !== null && <div data-dsh-auto-review-muted>{notice}</div>}\n </div>\n )}\n </div>\n )\n}\n","/**\n * Copy dictionaries for the auto-review session-header panel (en/zh — the\n * harness locale registry accepts these two UI language codes today).\n * @module dsh-auto-review/client/locales\n */\n\n/** Simplified Chinese dictionary and key source of truth. */\nexport const zh = {\n label: 'AI 审查',\n title: 'AI 自动审查',\n state: '状态',\n stateOn: '已开启',\n stateOff: '已关闭',\n enable: '开启',\n disable: '关闭',\n verdicts: '本回合 AI 裁决',\n failures: '本回合失败',\n allTime: '累计',\n allows: '放行',\n denies: '拒绝',\n fallbacks: '失败',\n neverRejects: '硬禁用拒绝',\n avg: '平均耗时',\n circuit: '拒绝熔断器已触发',\n circuitDetail: '触发类型:{kind},计数 {count},动作 {action}',\n empty: '本会话暂无 AI 审查裁决。',\n recent: '最近裁决',\n denyList: '可批准的重试',\n approve: '批准重试',\n approveResult: '已授权:{text}',\n approveFailed: '批准失败:{text}',\n switchedResult: '已切换:{text}',\n switchFailed: '切换失败:{text}',\n unavailable: '审查面板不可用(宿主未提供会话投影能力)。',\n decisionAllow: '放行',\n decisionDeny: '拒绝',\n fallbackLabel: '失败({kind})',\n escalationLabel: '风险策略升级',\n riskLow: '低风险',\n riskMedium: '中风险',\n riskHigh: '高风险',\n ms: 'ms',\n} satisfies Record<string, string>\n\n/** Auto-review panel locale key union. */\nexport type ReviewPanelLocaleKey = keyof typeof zh\n\n/** English dictionary checked against the Chinese key set. */\nexport const en: Record<ReviewPanelLocaleKey, string> = {\n label: 'AI Review',\n title: 'AI Auto-Review',\n state: 'State',\n stateOn: 'ON',\n stateOff: 'OFF',\n enable: 'Enable',\n disable: 'Disable',\n verdicts: 'AI verdicts this turn',\n failures: 'Failures this turn',\n allTime: 'All-time',\n allows: 'allows',\n denies: 'denies',\n fallbacks: 'fallbacks',\n neverRejects: 'never rejects',\n avg: 'avg',\n circuit: 'Rejection circuit breaker tripped',\n circuitDetail: '{kind}: {count} denials, action {action}',\n empty: 'No AI review verdicts in this session yet.',\n recent: 'Recent verdicts',\n denyList: 'Approvable retries',\n approve: 'Approve retry',\n approveResult: 'Authorized: {text}',\n approveFailed: 'Approve failed: {text}',\n switchedResult: 'Switched: {text}',\n switchFailed: 'Switch failed: {text}',\n unavailable: 'The review panel is unavailable (the host does not provide the session-projection capability).',\n decisionAllow: 'allow',\n decisionDeny: 'deny',\n fallbackLabel: 'fallback ({kind})',\n escalationLabel: 'risk-policy escalation',\n riskLow: 'low risk',\n riskMedium: 'medium risk',\n riskHigh: 'high risk',\n ms: 'ms',\n}\n\n/** Dictionary namespace owned by this plugin. */\nexport const NS = 'autoReviewPanel'\n","/**\n * Scoped stylesheet for the review panel. Standalone bundles cannot use the\n * in-repo CSS-module pipeline, so the panel injects one `<style>` element\n * whose selectors are all scoped under `[data-dsh-auto-review]`.\n * @module dsh-auto-review/client/styles\n */\n\nconst STYLE_ID = 'dsh-auto-review-panel-styles'\n\nconst CSS = `\n[data-dsh-auto-review] {\n --ar-allow: var(--dsw-color-success, #16a34a);\n --ar-deny: var(--dsw-color-danger, #dc2626);\n --ar-fallback: var(--dsw-color-warning, #d97706);\n --ar-escalation: var(--dsw-color-warning, #d97706);\n --ar-border: var(--dsw-color-border, rgba(128, 128, 128, 0.3));\n --ar-bg: var(--dsw-color-surface, #ffffff);\n --ar-fg: var(--dsw-color-text, #1f2328);\n --ar-muted: var(--dsw-color-text-muted, #6b7280);\n font-family: inherit;\n color: var(--ar-fg);\n}\n[data-dsh-auto-review-panel] {\n position: absolute;\n z-index: 40;\n min-width: 320px;\n max-width: 420px;\n max-height: 70vh;\n overflow-y: auto;\n background: var(--ar-bg);\n border: 1px solid var(--ar-border);\n border-radius: 8px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);\n padding: 12px;\n font-size: 12px;\n line-height: 1.5;\n}\n[data-dsh-auto-review-button] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n cursor: pointer;\n background: transparent;\n border: 1px solid var(--ar-border);\n border-radius: 6px;\n padding: 3px 8px;\n font-size: 12px;\n color: var(--ar-fg);\n}\n[data-dsh-auto-review-button]:hover {\n background: rgba(128, 128, 128, 0.12);\n}\n[data-dsh-auto-review-section] {\n margin: 8px 0;\n border-top: 1px solid var(--ar-border);\n padding-top: 8px;\n}\n[data-dsh-auto-review-title] {\n font-weight: 600;\n margin-bottom: 6px;\n}\n[data-dsh-auto-review-row] {\n display: flex;\n justify-content: space-between;\n gap: 8px;\n padding: 2px 0;\n align-items: baseline;\n}\n[data-dsh-auto-review-muted] {\n color: var(--ar-muted);\n}\n[data-dsh-auto-review-verdict] {\n display: flex;\n justify-content: space-between;\n gap: 8px;\n padding: 3px 0;\n border-bottom: 1px dashed var(--ar-border);\n}\n[data-dsh-auto-review-tone-allow] { color: var(--ar-allow); }\n[data-dsh-auto-review-tone-deny] { color: var(--ar-deny); }\n[data-dsh-auto-review-tone-fallback] { color: var(--ar-fallback); }\n[data-dsh-auto-review-tone-escalation] { color: var(--ar-escalation); }\n[data-dsh-auto-review-approve] {\n cursor: pointer;\n border: 1px solid var(--ar-border);\n border-radius: 4px;\n background: transparent;\n color: var(--ar-fg);\n padding: 1px 6px;\n font-size: 11px;\n}\n[data-dsh-auto-review-approve]:hover {\n background: rgba(128, 128, 128, 0.12);\n}\n[data-dsh-auto-review-switch] {\n cursor: pointer;\n border: 1px solid var(--ar-border);\n border-radius: 4px;\n background: transparent;\n color: var(--ar-fg);\n padding: 1px 6px;\n font-size: 11px;\n}\n[data-dsh-auto-review-switch] + [data-dsh-auto-review-switch] {\n margin-left: 4px;\n}\n[data-dsh-auto-review-switch]:hover:not(:disabled) {\n background: rgba(128, 128, 128, 0.12);\n}\n[data-dsh-auto-review-approve]:disabled,\n[data-dsh-auto-review-switch]:disabled {\n opacity: 0.45;\n cursor: default;\n}\n[data-dsh-auto-review-circuit] {\n color: var(--ar-deny);\n font-weight: 600;\n}\n`\n\n/** Install the scoped stylesheet once per plugin fiber. */\nexport function installPanelStyles(): () => void {\n if (document.getElementById(STYLE_ID) !== null) return () => undefined\n const element = document.createElement('style')\n element.id = STYLE_ID\n element.textContent = CSS\n document.head.appendChild(element)\n return () => {\n element.remove()\n }\n}\n","/**\n * `dsh-auto-review`, browser half: registers the locale dictionaries, the\n * scoped stylesheet, and the session-header review panel action. All data\n * arrives through the `autoReview` session projection; the approve buttons\n * execute the `/auto-review approve [n]` command through the commands\n * Remote namespace.\n *\n * @module dsh-auto-review/client\n */\n\nimport type { ClientContext, SessionId } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// Type-only: pulls the 'conversation.session.header.actions' SlotMap\n// declaration into this program so the registration typechecks.\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\n// Type-only: merges the commands namespace onto ctx.remote.\nimport type {} from '@deepseek-ai/dsh-api-remotes/client'\nimport type {} from '../projection-types.ts'\nimport { ReviewPanel, type ReviewPanelInjected } from './ReviewPanel.tsx'\nimport { en, NS, zh, type ReviewPanelLocaleKey } from './locales.ts'\nimport { installPanelStyles } from './styles.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Review panel copy. */\n 'autoReviewPanel': ReviewPanelLocaleKey\n }\n}\n\nexport type { ReviewPanelProps, ReviewPanelInjected } from './ReviewPanel.tsx'\nexport type { ReviewPanelLocaleKey } from './locales.ts'\nexport { presentVerdict, type PresentedVerdict, type VerdictTone } from './present.ts'\n\n/** Plugin name: matches the package name, the graph row id, and the bundle id. */\nexport const name = 'dsh-auto-review'\n\n/** Services the panel reads; `remote.commands` is mounted by the api-remotes client. */\nexport const inject = ['slots', 'locale', 'remote', 'remote.commands']\n\n/**\n * Browser plugin body: dictionaries, the scoped stylesheet, and the\n * session-header action registration.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-auto-review: dictionaries')\n ctx.effect(() => installPanelStyles(), 'dsh-auto-review: stylesheet')\n ctx.slots.inject(\n 'conversation.session.header.actions',\n () => ctx.slots.register({\n name: 'conversation.session.header.actions',\n id: 'auto-review',\n order: 40,\n locale: NS,\n inject: (sessionId: SessionId): ReviewPanelInjected => {\n const executeCommand = async (line: string): Promise<string> => {\n const result = await ctx.remote.commands.execute(sessionId, line)\n if (!result.ok) throw new Error(`${result.error.code}: ${result.error.message}`)\n if (result.value === undefined) throw new Error('unknown command: /auto-review')\n const command = result.value.result\n if (command === undefined) throw new Error('/auto-review produced no command result')\n const text = command.text ?? ''\n return command.kind === 'success' ? text : `${command.kind}: ${text}`\n }\n return {\n approve: async (n: number): Promise<string> => executeCommand(`/auto-review approve ${n}`),\n setEnabled: async (enabled: boolean): Promise<string> => executeCommand(`/auto-review ${enabled ? 'on' : 'off'}`),\n }\n },\n }, ReviewPanel),\n )\n}\n"],"mappings":"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"}
|