dsh-plugin-experts 0.1.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/dist/client.js ADDED
@@ -0,0 +1,3072 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "dsh-plugin-experts",
3
+ factory: function (require) {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __export = (target, all) => {
11
+ for (var name2 in all)
12
+ __defProp(target, name2, { get: all[name2], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
23
+
24
+ // packages/experts/client.tsx
25
+ var client_exports = {};
26
+ __export(client_exports, {
27
+ apply: () => apply,
28
+ expertManagerGuide: () => expertManagerGuide,
29
+ expertTeamManagerGuide: () => expertTeamManagerGuide,
30
+ inject: () => inject,
31
+ name: () => name
32
+ });
33
+ module.exports = __toCommonJS(client_exports);
34
+
35
+ // packages/experts/src/panel.tsx
36
+ var import_react6 = require("react");
37
+
38
+ // shared/ui/primitives.tsx
39
+ var import_react = require("react");
40
+
41
+ // shared/ui/icons.tsx
42
+ var import_jsx_runtime = require("react/jsx-runtime");
43
+ function Svg({ size = 16, className, children }) {
44
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
45
+ "svg",
46
+ {
47
+ width: size,
48
+ height: size,
49
+ viewBox: "0 0 24 24",
50
+ fill: "none",
51
+ stroke: "currentColor",
52
+ strokeWidth: 1.8,
53
+ strokeLinecap: "round",
54
+ strokeLinejoin: "round",
55
+ "aria-hidden": "true",
56
+ focusable: "false",
57
+ className,
58
+ style: { display: "block", flex: "none" },
59
+ children
60
+ }
61
+ );
62
+ }
63
+ var IconClose = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Svg, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 6l12 12M18 6 6 18" }) });
64
+
65
+ // shared/ui/tokens.ts
66
+ var baseCss = `
67
+ .dshs-root {
68
+ height: 100%;
69
+ min-height: 0;
70
+ overflow: auto;
71
+ color: var(--dsw-alias-label-primary);
72
+ background: var(--dsw-alias-bg-base);
73
+ font-size: 14px;
74
+ line-height: 1.55;
75
+ -webkit-font-smoothing: antialiased;
76
+ --dshs-muted: var(--dsw-alias-label-secondary);
77
+ }
78
+ .dshs-page { max-width: 1180px; margin: 0 auto; padding: 24px 32px 72px; }
79
+ .dshs-page--wide { max-width: 1320px; }
80
+
81
+ .dshs-title { margin: 0; font-size: 24px; line-height: 1.25; font-weight: 700; letter-spacing: -0.01em; }
82
+ .dshs-subtitle { margin: 6px 0 0; color: var(--dshs-muted); font-size: 13.5px; }
83
+ .dshs-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; margin: 18px 0 22px; }
84
+ .dshs-section { margin-top: 28px; }
85
+ .dshs-section__title { margin: 0 0 12px; font-size: 14px; font-weight: 650; }
86
+
87
+ .dshs-card {
88
+ border: 1px solid var(--dsw-alias-border-l1);
89
+ border-radius: 12px;
90
+ background: var(--dsw-alias-bg-layer-1);
91
+ overflow: hidden;
92
+ }
93
+ .dshs-row {
94
+ display: flex; align-items: center; gap: 12px;
95
+ padding: 12px 16px;
96
+ border-top: 1px solid var(--dsw-alias-border-l1);
97
+ }
98
+ .dshs-row:first-child { border-top: 0; }
99
+ .dshs-row__main { flex: 1; min-width: 0; }
100
+ .dshs-row__name { font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
101
+ .dshs-row__meta { color: var(--dshs-muted); font-size: 12.5px; overflow-wrap: anywhere; }
102
+
103
+ .dshs-muted { color: var(--dshs-muted); }
104
+ .dshs-idle { color: var(--dsw-alias-state-idle-primary); }
105
+ .dshs-error { color: var(--dsw-alias-state-error-primary); }
106
+ .dshs-warn { color: var(--dsw-alias-state-warn-primary); }
107
+ .dshs-ok { color: var(--dsw-alias-state-success-primary); }
108
+ .dshs-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; overflow-wrap: anywhere; }
109
+ .dshs-empty { padding: 40px 16px; text-align: center; color: var(--dshs-muted); }
110
+ .dshs-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
111
+ .dshs-stack { display: flex; flex-direction: column; gap: 12px; }
112
+ .dshs-inline { display: flex; align-items: center; gap: 8px; }
113
+ .dshs-grow { flex: 1; min-width: 0; }
114
+ `;
115
+ var layoutCss = `
116
+ /* ---- capability switcher: the tabs across the top of every panel ---- */
117
+ .dshs-caps { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
118
+ .dshs-cap {
119
+ display: inline-flex; align-items: center; gap: 7px;
120
+ height: 34px; padding: 0 13px;
121
+ border: 1px solid transparent; border-radius: 9px;
122
+ background: transparent; color: var(--dshs-muted);
123
+ font: inherit; font-size: 13.5px; cursor: pointer;
124
+ }
125
+ .dshs-cap:hover:not(:disabled) { background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-primary); }
126
+ .dshs-cap[aria-current="page"] {
127
+ background: var(--dsw-alias-bg-layer-2);
128
+ border-color: var(--dsw-alias-border-l1);
129
+ color: var(--dsw-alias-label-primary);
130
+ font-weight: 600;
131
+ }
132
+ .dshs-cap:disabled { opacity: 0.45; cursor: default; }
133
+ .dshs-cap:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }
134
+
135
+ /* ---- toolbar: search plus actions, under the switcher ---- */
136
+ .dshs-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 18px; }
137
+ .dshs-toolbar .dshs-search { flex: 1; min-width: 200px; max-width: 380px; }
138
+
139
+ /* ---- filter chips (\u5168\u90E8 / \u9ED8\u8BA4 / \u6211\u7684) ---- */
140
+ .dshs-segmented {
141
+ display: inline-flex; align-items: center; gap: 4px;
142
+ padding: 3px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 10px;
143
+ background: var(--dsw-alias-bg-layer-1);
144
+ }
145
+ .dshs-segmented button {
146
+ height: 28px; padding: 0 14px;
147
+ border: 0; border-radius: 7px; background: transparent;
148
+ color: var(--dshs-muted); font: inherit; font-size: 13px; cursor: pointer;
149
+ }
150
+ .dshs-segmented button:hover:not([aria-pressed="true"]) { color: var(--dsw-alias-label-primary); }
151
+ .dshs-segmented button[aria-pressed="true"] {
152
+ background: var(--dsw-alias-bg-layer-2);
153
+ color: var(--dsw-alias-label-primary);
154
+ font-weight: 600;
155
+ }
156
+ .dshs-segmented button:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }
157
+
158
+ /* ---- count line ---- */
159
+ .dshs-count { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 22px 0 12px; color: var(--dshs-muted); font-size: 13px; }
160
+
161
+ /* ---- card grid ---- */
162
+ .dshs-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(276px, 1fr)); gap: 16px; }
163
+ .dshs-grid--wide { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
164
+
165
+ .dshs-tilecard {
166
+ display: flex; flex-direction: column; gap: 10px;
167
+ padding: 16px;
168
+ border: 1px solid var(--dsw-alias-border-l1); border-radius: 12px;
169
+ background: var(--dsw-alias-bg-layer-1);
170
+ color: inherit; text-align: left; font: inherit;
171
+ }
172
+ .dshs-tilecard--interactive { cursor: pointer; transition: border-color 120ms ease, background 120ms ease; }
173
+ .dshs-tilecard--interactive:hover { border-color: var(--dsw-alias-border-l2); background: var(--dsw-alias-bg-layer-2); }
174
+ .dshs-tilecard--muted { opacity: 0.62; }
175
+ .dshs-tilecard__head { display: flex; align-items: flex-start; gap: 12px; }
176
+ .dshs-tilecard__title { font-size: 15px; font-weight: 650; overflow-wrap: anywhere; }
177
+ .dshs-tilecard__sub { margin-top: 3px; color: var(--dshs-muted); font-size: 12.5px; overflow-wrap: anywhere; }
178
+ .dshs-tilecard__body { color: var(--dshs-muted); font-size: 13px; }
179
+ .dshs-tilecard__foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: auto; padding-top: 2px; color: var(--dshs-muted); font-size: 12.5px; }
180
+
181
+ /* ---- icon tile: the coloured square every card leads with ---- */
182
+ .dshs-tile {
183
+ display: grid; place-items: center;
184
+ width: 42px; height: 42px; flex: none;
185
+ border-radius: 11px;
186
+ background: var(--dsw-alias-bg-layer-2);
187
+ color: var(--dsw-alias-label-primary);
188
+ font-size: 16px; font-weight: 700; line-height: 1;
189
+ user-select: none;
190
+ }
191
+ .dshs-tile--lg { width: 52px; height: 52px; border-radius: 14px; font-size: 19px; }
192
+ .dshs-tile--sm { width: 32px; height: 32px; border-radius: 9px; font-size: 13px; }
193
+ /* Hues are mixed into the theme surface so they survive both themes. */
194
+ .dshs-tile[data-hue="0"] { background: color-mix(in srgb, #14b8a6 22%, var(--dsw-alias-bg-layer-2)); color: #14b8a6; }
195
+ .dshs-tile[data-hue="1"] { background: color-mix(in srgb, #6366f1 22%, var(--dsw-alias-bg-layer-2)); color: #818cf8; }
196
+ .dshs-tile[data-hue="2"] { background: color-mix(in srgb, #f97316 22%, var(--dsw-alias-bg-layer-2)); color: #fb923c; }
197
+ .dshs-tile[data-hue="3"] { background: color-mix(in srgb, #a855f7 22%, var(--dsw-alias-bg-layer-2)); color: #c084fc; }
198
+ .dshs-tile[data-hue="4"] { background: color-mix(in srgb, #0ea5e9 22%, var(--dsw-alias-bg-layer-2)); color: #38bdf8; }
199
+ .dshs-tile[data-hue="5"] { background: color-mix(in srgb, #ec4899 22%, var(--dsw-alias-bg-layer-2)); color: #f472b6; }
200
+ .dshs-tile[data-hue="6"] { background: color-mix(in srgb, #22c55e 22%, var(--dsw-alias-bg-layer-2)); color: #4ade80; }
201
+ .dshs-tile[data-hue="7"] { background: color-mix(in srgb, #eab308 22%, var(--dsw-alias-bg-layer-2)); color: #facc15; }
202
+
203
+ /* ---- tag chips and status pills ---- */
204
+ .dshs-tags { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
205
+ .dshs-tag {
206
+ padding: 2px 9px;
207
+ border: 1px solid var(--dsw-alias-border-l1); border-radius: 999px;
208
+ color: var(--dshs-muted); font-size: 11.5px; line-height: 1.7; white-space: nowrap;
209
+ }
210
+ .dshs-pill {
211
+ display: inline-flex; align-items: center; gap: 5px;
212
+ padding: 2px 9px;
213
+ border: 1px solid var(--dsw-alias-border-l1); border-radius: 999px;
214
+ font-size: 11.5px; line-height: 1.7; white-space: nowrap;
215
+ color: var(--dshs-muted);
216
+ }
217
+ .dshs-pill--ok { color: var(--dsw-alias-state-success-primary); border-color: color-mix(in srgb, var(--dsw-alias-state-success-primary) 45%, transparent); }
218
+ .dshs-pill--warn { color: var(--dsw-alias-state-warn-primary); border-color: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 45%, transparent); }
219
+ .dshs-pill--error { color: var(--dsw-alias-state-error-primary); border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent); }
220
+ .dshs-pill--idle { color: var(--dsw-alias-state-idle-primary); }
221
+ .dshs-pill__dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
222
+
223
+ /* ---- two-pane layout used by the library ---- */
224
+ .dshs-split { display: grid; grid-template-columns: minmax(220px, 280px) minmax(0, 1fr); gap: 20px; align-items: start; }
225
+ @media (max-width: 860px) { .dshs-split { grid-template-columns: minmax(0, 1fr); } }
226
+
227
+ /* ---- empty state with a leading icon tile ---- */
228
+ .dshs-blank { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 56px 20px; text-align: center; }
229
+ .dshs-blank__title { font-size: 17px; font-weight: 650; }
230
+ .dshs-blank__text { color: var(--dshs-muted); max-width: 420px; }
231
+ `;
232
+ var controlsCss = `
233
+ .dshs-btn {
234
+ display: inline-flex; align-items: center; justify-content: center; gap: 6px;
235
+ height: 34px; padding: 0 14px;
236
+ border: 1px solid var(--dsw-alias-border-l1);
237
+ border-radius: 9px;
238
+ background: var(--dsw-alias-bg-layer-1);
239
+ color: var(--dsw-alias-label-primary);
240
+ font: inherit; font-size: 13.5px; cursor: pointer;
241
+ white-space: nowrap;
242
+ }
243
+ .dshs-btn:hover:not(:disabled) { border-color: var(--dsw-alias-border-l2); background: var(--dsw-alias-bg-layer-2); }
244
+ .dshs-btn:disabled { opacity: 0.5; cursor: not-allowed; }
245
+ .dshs-btn:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }
246
+ /* The reference's primary action is a filled, high-contrast button. */
247
+ .dshs-btn--primary {
248
+ background: var(--dsw-alias-label-primary);
249
+ border-color: var(--dsw-alias-label-primary);
250
+ color: var(--dsw-alias-bg-base);
251
+ font-weight: 600;
252
+ }
253
+ .dshs-btn--primary:hover:not(:disabled) { opacity: 0.88; background: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-label-primary); }
254
+ .dshs-btn--ghost { background: transparent; border-color: transparent; color: var(--dshs-muted); }
255
+ .dshs-btn--ghost:hover:not(:disabled) { background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-primary); }
256
+ .dshs-btn--danger { color: var(--dsw-alias-state-error-primary); }
257
+ .dshs-btn--danger:hover:not(:disabled) { border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent); }
258
+ .dshs-btn--sm { height: 28px; padding: 0 10px; font-size: 12.5px; border-radius: 8px; }
259
+ .dshs-iconbtn {
260
+ display: inline-flex; align-items: center; justify-content: center;
261
+ width: 30px; height: 30px; padding: 0;
262
+ border: 1px solid transparent; border-radius: 8px;
263
+ background: transparent; color: var(--dshs-muted); cursor: pointer;
264
+ }
265
+ .dshs-iconbtn:hover:not(:disabled) { background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-primary); }
266
+ .dshs-iconbtn:disabled { opacity: 0.45; cursor: not-allowed; }
267
+ .dshs-iconbtn:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }
268
+
269
+ .dshs-input, .dshs-textarea, .dshs-select {
270
+ width: 100%; box-sizing: border-box;
271
+ min-height: 34px; padding: 7px 11px;
272
+ border: 1px solid var(--dsw-alias-border-l1); border-radius: 9px;
273
+ background: var(--dsw-alias-bg-layer-1);
274
+ color: var(--dsw-alias-label-primary);
275
+ font: inherit; font-size: 13.5px;
276
+ }
277
+ .dshs-textarea { min-height: 96px; resize: vertical; line-height: 1.6; }
278
+ .dshs-select { appearance: auto; }
279
+ .dshs-input:focus-visible, .dshs-textarea:focus-visible, .dshs-select:focus-visible {
280
+ outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: -1px; border-color: var(--dsw-alias-brand-primary);
281
+ }
282
+ .dshs-input::placeholder, .dshs-textarea::placeholder { color: var(--dsw-alias-state-idle-primary); }
283
+ .dshs-field { display: flex; flex-direction: column; gap: 6px; }
284
+ .dshs-field__label { font-size: 12.5px; font-weight: 550; color: var(--dshs-muted); }
285
+ .dshs-field__hint { font-size: 12px; color: var(--dshs-muted); }
286
+ .dshs-field__error { font-size: 12px; color: var(--dsw-alias-state-error-primary); }
287
+
288
+ .dshs-badge {
289
+ display: inline-flex; align-items: center; gap: 4px;
290
+ padding: 1px 8px; border-radius: 999px;
291
+ border: 1px solid var(--dsw-alias-border-l1);
292
+ font-size: 11.5px; color: var(--dshs-muted); white-space: nowrap;
293
+ }
294
+ .dshs-badge--ok { color: var(--dsw-alias-state-success-primary); border-color: color-mix(in srgb, var(--dsw-alias-state-success-primary) 45%, transparent); }
295
+ .dshs-badge--warn { color: var(--dsw-alias-state-warn-primary); border-color: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 45%, transparent); }
296
+ .dshs-badge--error { color: var(--dsw-alias-state-error-primary); border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent); }
297
+ .dshs-badge--idle { color: var(--dsw-alias-state-idle-primary); }
298
+
299
+ .dshs-switch {
300
+ position: relative; flex: none;
301
+ width: 34px; height: 20px; padding: 0;
302
+ border: 1px solid var(--dsw-alias-border-l2); border-radius: 999px;
303
+ background: var(--dsw-alias-bg-layer-2); cursor: pointer; transition: background 120ms ease;
304
+ }
305
+ .dshs-switch[aria-checked="true"] { background: var(--dsw-alias-brand-primary); border-color: var(--dsw-alias-brand-primary); }
306
+ .dshs-switch:disabled { opacity: 0.5; cursor: not-allowed; }
307
+ .dshs-switch:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 2px; }
308
+ .dshs-switch__knob {
309
+ position: absolute; top: 1px; left: 1px;
310
+ width: 16px; height: 16px; border-radius: 50%;
311
+ background: var(--dsw-alias-bg-base); transition: transform 120ms ease;
312
+ }
313
+ .dshs-switch[aria-checked="true"] .dshs-switch__knob { transform: translateX(14px); }
314
+
315
+ .dshs-spinner {
316
+ width: 14px; height: 14px; flex: none;
317
+ border: 2px solid var(--dsw-alias-border-l2); border-top-color: var(--dsw-alias-brand-primary);
318
+ border-radius: 50%; animation: dshs-spin 700ms linear infinite;
319
+ }
320
+ @keyframes dshs-spin { to { transform: rotate(360deg); } }
321
+ @media (prefers-reduced-motion: reduce) { .dshs-spinner { animation-duration: 2s; } }
322
+ `;
323
+ var modalCss = `
324
+ .dshs-overlay {
325
+ position: fixed; inset: 0; z-index: 60;
326
+ display: flex; align-items: center; justify-content: center;
327
+ padding: 24px;
328
+ background: color-mix(in srgb, var(--dsw-alias-bg-base) 62%, transparent);
329
+ }
330
+ .dshs-modal {
331
+ display: flex; flex-direction: column;
332
+ width: min(600px, 100%); max-height: min(84vh, 760px);
333
+ border: 1px solid var(--dsw-alias-border-l1); border-radius: 14px;
334
+ background: var(--dsw-alias-bg-overlay);
335
+ box-shadow: 0 16px 48px rgb(0 0 0 / 26%);
336
+ }
337
+ .dshs-modal__head { display: flex; align-items: center; gap: 12px; padding: 18px 20px 12px; }
338
+ .dshs-modal__title { margin: 0; font-size: 16px; font-weight: 650; flex: 1; }
339
+ .dshs-modal__body { padding: 4px 20px 18px; overflow: auto; }
340
+ .dshs-modal__foot { display: flex; justify-content: flex-end; gap: 8px; padding: 14px 20px 18px; border-top: 1px solid var(--dsw-alias-border-l1); }
341
+ `;
342
+ var allCss = `${baseCss}
343
+ ${layoutCss}
344
+ ${controlsCss}
345
+ ${modalCss}`;
346
+
347
+ // shared/ui/primitives.tsx
348
+ var import_jsx_runtime2 = require("react/jsx-runtime");
349
+ function Styles() {
350
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { "data-dsh-plugin-ui": "1", children: allCss });
351
+ }
352
+ function IconButton({
353
+ label,
354
+ disabled = false,
355
+ onClick,
356
+ children
357
+ }) {
358
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "dshs-iconbtn", "aria-label": label, title: label, disabled, onClick, children });
359
+ }
360
+ function Modal({
361
+ open = false,
362
+ title,
363
+ closeLabel = "\u5173\u95ED",
364
+ onClose,
365
+ footer,
366
+ className,
367
+ children
368
+ }) {
369
+ const panelRef = (0, import_react.useRef)(null);
370
+ const restoreRef = (0, import_react.useRef)(null);
371
+ (0, import_react.useEffect)(() => {
372
+ if (!open) return;
373
+ restoreRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
374
+ const panel = panelRef.current;
375
+ const first = panel?.querySelector('input, textarea, select, button, [tabindex]:not([tabindex="-1"])');
376
+ (first ?? panel)?.focus();
377
+ return () => restoreRef.current?.focus?.();
378
+ }, [open]);
379
+ (0, import_react.useEffect)(() => {
380
+ if (!open) return void 0;
381
+ const onKeyDown = (event) => {
382
+ if (event.key === "Escape") {
383
+ event.preventDefault();
384
+ event.stopPropagation();
385
+ onClose();
386
+ return;
387
+ }
388
+ if (event.key !== "Tab") return;
389
+ const panel = panelRef.current;
390
+ if (panel === null) return;
391
+ const focusable = [...panel.querySelectorAll('input, textarea, select, button, [tabindex]:not([tabindex="-1"])')].filter((node) => !node.hasAttribute("disabled"));
392
+ if (focusable.length === 0) return;
393
+ const first = focusable[0];
394
+ const last = focusable[focusable.length - 1];
395
+ const active = document.activeElement;
396
+ if (event.shiftKey && (active === first || !panel.contains(active))) {
397
+ event.preventDefault();
398
+ last.focus();
399
+ } else if (!event.shiftKey && active === last) {
400
+ event.preventDefault();
401
+ first.focus();
402
+ }
403
+ };
404
+ document.addEventListener("keydown", onKeyDown, true);
405
+ return () => document.removeEventListener("keydown", onKeyDown, true);
406
+ }, [open, onClose]);
407
+ if (!open) return null;
408
+ if (className !== void 0) {
409
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
410
+ "div",
411
+ {
412
+ className: "dshs-overlay",
413
+ onMouseDown: (event) => {
414
+ if (event.target === event.currentTarget) onClose();
415
+ },
416
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className, role: "dialog", "aria-modal": "true", "aria-label": title, tabIndex: -1, ref: panelRef, children: [
417
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Styles, {}),
418
+ children
419
+ ] })
420
+ }
421
+ );
422
+ }
423
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
424
+ "div",
425
+ {
426
+ className: "dshs-overlay",
427
+ onMouseDown: (event) => {
428
+ if (event.target === event.currentTarget) onClose();
429
+ },
430
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dshs-modal", role: "dialog", "aria-modal": "true", "aria-label": title, tabIndex: -1, ref: panelRef, children: [
431
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Styles, {}),
432
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dshs-modal__head", children: [
433
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: "dshs-modal__title", children: title }),
434
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IconButton, { label: closeLabel, onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IconClose, {}) })
435
+ ] }),
436
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dshs-modal__body", children }),
437
+ footer !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dshs-modal__foot", children: footer })
438
+ ] })
439
+ }
440
+ );
441
+ }
442
+
443
+ // shared/ui/capabilities.tsx
444
+ var import_jsx_runtime3 = require("react/jsx-runtime");
445
+ function glyph(paths) {
446
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
447
+ "svg",
448
+ {
449
+ width: 15,
450
+ height: 15,
451
+ viewBox: "0 0 24 24",
452
+ fill: "none",
453
+ stroke: "currentColor",
454
+ strokeWidth: 1.8,
455
+ strokeLinecap: "round",
456
+ strokeLinejoin: "round",
457
+ "aria-hidden": "true",
458
+ style: { display: "block" },
459
+ children: paths.map((path) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: path }, path))
460
+ }
461
+ );
462
+ }
463
+ var CAPABILITIES = [
464
+ { key: "dsh-plugin-experts", label: "\u4E13\u5BB6", icon: glyph(["M9 8a3 3 0 1 0 0 .01", "M3 19a6 6 0 0 1 12 0", "M16 5.5a3 3 0 0 1 0 5.9", "M17.5 19a6 6 0 0 0-2-4.5"]) },
465
+ { key: "dsh-plugin-skills", label: "\u6280\u80FD", icon: glyph(["m9 8-4 4 4 4", "m15 8 4 4-4 4"]) },
466
+ { key: "dsh-plugin-connectors", label: "\u8FDE\u63A5\u5668", icon: glyph(["M9 3v6", "M15 3v6", "M6 9h12v3a6 6 0 0 1-12 0z", "M12 18v3"]) },
467
+ { key: "dsh-plugin-projects", label: "\u9879\u76EE", icon: glyph(["M4 6h9", "M4 12h9", "M4 18h6", "M17.5 4v4", "M17.5 12v4"]) },
468
+ { key: "dsh-plugin-library", label: "\u8D44\u6599\u5E93", icon: glyph(["M5 4h9a2 2 0 0 1 2 2v14H7a2 2 0 0 1-2-2z", "M8 4v16", "M16 8h3v12"]) }
469
+ ];
470
+
471
+ // shared/ui/navigation.ts
472
+ function createNavFace(ctx, current2) {
473
+ const available = () => {
474
+ const keys = /* @__PURE__ */ new Set();
475
+ const entries = ctx.slots?.entriesOfSlot("main") ?? [];
476
+ for (const entry of entries) {
477
+ const key = entry?.options?.key;
478
+ if (typeof key === "string") keys.add(key);
479
+ }
480
+ keys.add(current2);
481
+ return keys;
482
+ };
483
+ return {
484
+ current: current2,
485
+ available,
486
+ open: (key) => {
487
+ if (key === current2) return;
488
+ ctx.layout?.selectPanel(key);
489
+ }
490
+ };
491
+ }
492
+
493
+ // shared/ui/host.ts
494
+ var import_react2 = require("react");
495
+ var HostCallFailure = class extends Error {
496
+ code;
497
+ constructor(error) {
498
+ super(error.message);
499
+ this.name = "HostCallFailure";
500
+ this.code = error.code;
501
+ }
502
+ };
503
+ async function hostCall(feature, endpoint, payload, signal, timeoutMs = 15e3) {
504
+ const deadline = AbortSignal.timeout(timeoutMs);
505
+ const combined = signal === void 0 ? deadline : AbortSignal.any([signal, deadline]);
506
+ let response;
507
+ try {
508
+ response = await fetch(`/api/dsh-skills/${feature}`, {
509
+ method: "POST",
510
+ credentials: "same-origin",
511
+ headers: { "content-type": "application/json", accept: "application/json" },
512
+ body: JSON.stringify({ endpoint, payload }),
513
+ signal: combined
514
+ });
515
+ } catch (cause) {
516
+ if (deadline.aborted) {
517
+ throw new HostCallFailure({ code: "host/timeout", message: `${feature}.${endpoint} \u8D85\u8FC7 ${Math.round(timeoutMs / 1e3)} \u79D2\u6CA1\u6709\u54CD\u5E94\u3002` });
518
+ }
519
+ throw cause;
520
+ }
521
+ if (!response.ok) {
522
+ throw new HostCallFailure({ code: `http/${response.status}`, message: `Host \u8DEF\u7531\u8FD4\u56DE ${response.status}` });
523
+ }
524
+ const body = await response.json();
525
+ if (body.ok !== true) {
526
+ throw new HostCallFailure(body.error ?? { code: "unknown", message: "Host \u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94" });
527
+ }
528
+ return body.value;
529
+ }
530
+
531
+ // packages/experts/src/management.ts
532
+ var FEATURE = "experts";
533
+ var experts = {
534
+ list: (query = "") => hostCall(FEATURE, "list", { query }),
535
+ get: (expertId) => hostCall(FEATURE, "get", { expertId }),
536
+ create: (input) => hostCall(FEATURE, "create", input),
537
+ updateDraft: (expertId, patch, expectedRevision) => hostCall(FEATURE, "update-draft", { expertId, patch, expectedRevision }),
538
+ publish: (expertId, expectedRevision) => hostCall(FEATURE, "publish", {
539
+ expertId,
540
+ ...expectedRevision === void 0 ? {} : { expectedRevision }
541
+ }),
542
+ copy: (expertId, revisionId) => hostCall(FEATURE, "copy", { expertId, ...revisionId === void 0 ? {} : { revisionId } }),
543
+ remove: (expertId) => hostCall(FEATURE, "delete", { expertId }),
544
+ adoption: (sessionId) => hostCall(FEATURE, "adoption", { sessionId }),
545
+ setAdoption: (sessionId, expertId) => hostCall(FEATURE, "set-adoption", { sessionId, expertId }),
546
+ listTeams: (query = "") => hostCall(FEATURE, "list-teams", { query }),
547
+ getTeam: (teamId) => hostCall(FEATURE, "get-team", { teamId }),
548
+ createTeam: (input) => hostCall(FEATURE, "create-team", input),
549
+ updateTeam: (teamId, patch, expectedRevision) => hostCall(FEATURE, "update-team", {
550
+ teamId,
551
+ patch,
552
+ ...expectedRevision === void 0 ? {} : { expectedRevision }
553
+ }),
554
+ removeTeam: (teamId) => hostCall(FEATURE, "delete-team", { teamId })
555
+ };
556
+ var EXPERT_LIMITS = {
557
+ nameMax: 120,
558
+ descriptionMax: 2e3,
559
+ roleMax: 6e4,
560
+ skillsMax: 12
561
+ };
562
+ var TEAM_LIMITS = {
563
+ nameMax: EXPERT_LIMITS.nameMax,
564
+ descriptionMax: EXPERT_LIMITS.descriptionMax,
565
+ mandateMax: EXPERT_LIMITS.roleMax,
566
+ membersMin: 2,
567
+ membersMax: 16
568
+ };
569
+ var MEMBER_KEY_PATTERN = /^[a-z][a-z0-9-]{0,39}$/u;
570
+ function memberKeyFor(name2, taken) {
571
+ const slug = name2.toLowerCase().replace(/[^a-z0-9-]+/gu, "-").replace(/^-+|-+$/gu, "").slice(0, 40);
572
+ const base = MEMBER_KEY_PATTERN.test(slug) && slug !== "lead" ? slug : "member";
573
+ if (!taken.includes(base)) return base;
574
+ for (let index = 2; index < 1e4; index += 1) {
575
+ const candidate = `${base}-${index}`;
576
+ if (!taken.includes(candidate)) return candidate;
577
+ }
578
+ return base;
579
+ }
580
+ function reasonOf(error) {
581
+ return error instanceof Error ? error.message : String(error);
582
+ }
583
+ function codeOf(error) {
584
+ const code = error?.code;
585
+ return typeof code === "string" ? code : "";
586
+ }
587
+
588
+ // packages/experts/src/session-bus.ts
589
+ var current;
590
+ var listeners = /* @__PURE__ */ new Set();
591
+ function setCurrentSessionId(sessionId) {
592
+ if (sessionId === current) return;
593
+ current = sessionId;
594
+ for (const listener of listeners) {
595
+ try {
596
+ listener();
597
+ } catch {
598
+ }
599
+ }
600
+ }
601
+ function getCurrentSessionId() {
602
+ return current;
603
+ }
604
+ function subscribeCurrentSession(listener) {
605
+ listeners.add(listener);
606
+ return () => {
607
+ listeners.delete(listener);
608
+ };
609
+ }
610
+
611
+ // packages/experts/src/icons.tsx
612
+ var import_jsx_runtime4 = require("react/jsx-runtime");
613
+ var PATHS = {
614
+ experts: "M5 4h12a4 4 0 014 4v6a7 7 0 01-14 0v-3H5a3 3 0 010-6M13 11a2 2 0 11-4 0 2 2 0 014 0M19 11a2 2 0 11-4 0 2 2 0 014 0M11 17h5",
615
+ skills: "M8 5L2 12l6 7M16 5l6 7-6 7M14 3l-4 18",
616
+ connectors: "M9 15l6-6M9 6l2-2a4 4 0 016 6l-2 2M15 18l-2 2a4 4 0 01-6-6l2-2",
617
+ close: "M6 6l12 12M18 6L6 18"
618
+ };
619
+ function CapabilityIcon({ name: name2 }) {
620
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.7, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, focusable: false, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: PATHS[name2] }) });
621
+ }
622
+ function CloseIcon() {
623
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: PATHS.close }) });
624
+ }
625
+
626
+ // packages/experts/src/dialog-css.ts
627
+ var dialogCss = `
628
+ .wd-dialog-backdrop{position:fixed;inset:0;z-index:1200;display:grid;place-items:center;padding:24px;background:var(--dsw-alias-bg-mask-2)}
629
+ .wd-dialog{position:relative;box-sizing:border-box;width:min(720px,calc(100vw - 48px));max-height:calc(100dvh - 48px);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;border:0;border-radius:16px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-elevation-prominent);outline:none;font:14px/22px "PingFang SC","Microsoft YaHei",sans-serif;animation:wd-dialog-enter .16s ease-out}
630
+ .wd-dialog *{box-sizing:border-box}
631
+ .wd-dialog button{font:inherit;white-space:nowrap}
632
+ .wd-dialog>.wd-dialog-close{position:absolute;z-index:2;right:16px;top:16px;width:32px;height:32px;min-height:32px;padding:0;display:grid;place-items:center;border:0;border-radius:6px;background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer}
633
+ .wd-dialog-close svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round}
634
+ .wd-dialog-close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.wd-dialog-close:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
635
+ @keyframes wd-dialog-enter{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}
636
+ @media(prefers-reduced-motion:reduce){.wd-dialog{animation:none}}
637
+ @media(max-width:640px){.wd-dialog-backdrop{padding:12px}.wd-dialog{width:calc(100vw - 24px);max-height:calc(100dvh - 24px);height:auto;border-radius:12px}.wd-dialog>.wd-dialog-close{right:8px;top:8px;width:44px;height:44px;min-height:44px}}
638
+ `;
639
+
640
+ // packages/experts/src/styles.ts
641
+ var expertsCss = `${dialogCss}
642
+ @layer workdsh-business {
643
+
644
+ .wd-experts{overflow:auto;box-sizing:border-box}
645
+ .wd-experts{height:100%;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);font:14px/22px "PingFang SC","Microsoft YaHei",sans-serif;padding:24px}
646
+ .wd-experts *{box-sizing:border-box}
647
+ .wd-experts .nav-toggle{display:none}
648
+ .wd-experts button,.wd-experts input,.wd-experts select,.wd-experts textarea{font:inherit;color:inherit}
649
+ .wd-experts button{cursor:pointer}
650
+ .wd-experts button{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2);min-height:36px;padding:6px 12px}
651
+ .wd-experts button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
652
+ .wd-experts button:disabled{cursor:not-allowed}
653
+ .wd-experts button:disabled{color:var(--dsw-alias-label-dimmed)}
654
+ .wd-experts input,.wd-experts select,.wd-experts textarea{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-1);min-height:36px;padding:6px 12px}
655
+ .wd-experts :focus-visible{outline-offset:3px}
656
+ .wd-experts :focus-visible{outline:2px solid var(--dsw-alias-brand-primary)}
657
+ .wd-experts .muted{color:var(--dsw-alias-label-tertiary)}
658
+ .wd-experts .cap-header{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:24px}
659
+ .wd-experts .cap-tab{display:flex;align-items:center;gap:7px;white-space:nowrap}
660
+ .wd-experts .cap-tab{border:0;background:transparent;min-height:38px;padding:6px 14px;border-radius:8px}
661
+ .wd-experts .cap-tab.active{background:var(--dsw-alias-interactive-bg-hover)}
662
+ .wd-experts .cap-tab:disabled{cursor:default}
663
+ .wd-experts .cap-tab:disabled{color:var(--dsw-alias-label-tertiary)}
664
+ .wd-experts .search{margin-left:auto;width:250px;min-width:150px}
665
+ .wd-experts .mine-toggle,.wd-experts .create-expert{white-space:nowrap}
666
+ .wd-experts .mine-toggle.active{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l2)}
667
+ .wd-experts .create-expert{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-inverted);border-color:var(--dsw-alias-border-l2);font-weight:600}
668
+ .wd-experts .section-head{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:16px;border-bottom:1px solid var(--dsw-alias-border-l2)}
669
+ .wd-experts .section-head{padding-bottom:16px}
670
+ .wd-experts .section-head h1{margin:0}
671
+ .wd-experts .section-head h1{font-size:25px;line-height:34px;font-weight:600}
672
+ .wd-experts .section-actions{display:flex;gap:8px;align-items:center}
673
+ .wd-experts .back-center{margin:0 0 20px}
674
+ .wd-experts .back-center{border:0;background:transparent;color:var(--dsw-alias-label-tertiary);padding-left:0}
675
+ .wd-experts .work-types{display:flex;gap:24px}
676
+ .wd-experts .work-types button{background:transparent;border:0;padding:0;color:var(--dsw-alias-label-tertiary);font-size:22px;font-weight:600}
677
+ .wd-experts .work-types button.active{color:var(--dsw-alias-label-primary)}
678
+ .wd-experts .work-types span{margin-left:10px}
679
+ .wd-experts .work-types span{font-size:12px;color:var(--dsw-alias-label-tertiary);font-weight:400}
680
+ .wd-experts .create-menu{position:relative}
681
+ .wd-experts .create-menu summary{list-style:none;cursor:pointer}
682
+ .wd-experts .create-menu summary{border-radius:8px;padding:9px 14px}
683
+ .wd-experts .create-menu summary::-webkit-details-marker{display:none}
684
+ .wd-experts .create-menu>div{position:absolute;right:0;top:calc(100% + 8px);width:180px;z-index:20}
685
+ .wd-experts .create-menu>div{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:8px;box-shadow:0 12px 28px var(--dsw-alias-bg-mask-2)}
686
+ .wd-experts .create-menu button{display:block;width:100%;text-align:left}
687
+ .wd-experts .create-menu button{border:0;background:transparent}
688
+ .wd-experts .domain-tags{display:flex;gap:6px;flex-wrap:wrap}
689
+ .wd-experts .domain-tags span{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);font-size:11px;border-radius:4px;padding:3px 7px}
690
+ .wd-experts .create-card{display:flex;align-items:center;justify-content:center;gap:12px}
691
+ .wd-experts .create-card{min-height:220px;color:var(--dsw-alias-label-tertiary);font-size:14px}
692
+ .wd-experts .create-card>span{font-size:46px;font-weight:400;line-height:1}
693
+ .wd-experts .filter-tabs{display:flex;gap:7px;align-items:center;overflow:auto;margin:0 0 18px}
694
+ .wd-experts .filter-tabs{padding:0 0 2px}
695
+ .wd-experts .filter-tabs button{white-space:nowrap}
696
+ .wd-experts .filter-tabs button{border:0;background:transparent}
697
+ .wd-experts .filter-tabs button.active{background:var(--dsw-alias-interactive-bg-hover)}
698
+ .wd-experts .filter-tabs button:disabled{color:var(--dsw-alias-label-dimmed)}
699
+ .wd-experts .counts{margin:0 0 16px}
700
+ .wd-experts .counts{font-size:12px;color:var(--dsw-alias-label-tertiary)}
701
+ .wd-experts .counts.error{color:var(--dsw-alias-state-error-primary)}
702
+ .wd-experts .grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px}
703
+ .wd-experts .card{position:relative;min-width:0;display:flex;flex-direction:column;gap:12px}
704
+ .wd-experts .card{border-radius:17px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);min-height:150px;padding:24px}
705
+ .wd-experts .card:hover{border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2)}
706
+ .wd-experts .card.draft{border-style:dashed}
707
+ .wd-experts .card.unavailable{opacity:.62}
708
+ .wd-experts .card-top{display:flex;align-items:flex-start;gap:12px;min-width:0}
709
+ .wd-experts .card-open{display:flex;align-items:flex-start;gap:12px;min-width:0;flex:1;text-align:left}
710
+ .wd-experts .card-open{padding:0;border:0;background:transparent}
711
+ .wd-experts .card-open:hover:not(:disabled){background:transparent}
712
+ .wd-experts .avatar{display:inline-grid;place-items:center;width:46px;flex:none;overflow:hidden}
713
+ .wd-experts .avatar{height:46px;border-radius:50%;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font-weight:700;font-size:18px}
714
+ .wd-experts .avatar img{width:100%;object-fit:cover}
715
+ .wd-experts .avatar img{height:100%}
716
+ .wd-experts .card-title{min-width:0;flex:1}
717
+ .wd-experts .card-title strong{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
718
+ .wd-experts .card-title strong{font-weight:600;font-size:15px}
719
+ .wd-experts .card-meta{display:block;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
720
+ .wd-experts .card-meta{font-size:12px;color:var(--dsw-alias-label-tertiary)}
721
+ .wd-experts .card p.desc{margin:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
722
+ .wd-experts .card p.desc{font-size:12px;line-height:20px;color:var(--dsw-alias-label-secondary)}
723
+ .wd-experts .card-foot{display:flex;align-items:center;gap:8px;margin-top:auto;flex-wrap:wrap}
724
+ .wd-experts .badge{white-space:nowrap}
725
+ .wd-experts .badge{font-size:11px;padding:2px 8px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary)}
726
+ .wd-experts .badge.ready{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}
727
+ .wd-experts .badge.warn{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}
728
+ .wd-experts .badge.bad{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-warn-primary)}
729
+ .wd-experts .pin{margin-left:auto}
730
+ .wd-experts .pin{background:transparent;border:0;min-height:28px;padding:2px 6px;font-size:15px;color:var(--dsw-alias-label-dimmed)}
731
+ .wd-experts .pin.on{color:var(--dsw-alias-state-warn-primary)}
732
+ .wd-experts .more-button{width:34px}
733
+ .wd-experts .more-button{min-height:30px;padding:0;border:0;font-size:18px;background:transparent;color:var(--dsw-alias-label-secondary)}
734
+ .wd-experts .card-actions{position:relative}
735
+ .wd-experts .card-menu{position:absolute;z-index:20;right:0;top:calc(100% + 6px);width:172px}
736
+ .wd-experts .card-menu{padding:8px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:14px;box-shadow:0 14px 36px var(--dsw-alias-bg-mask-2)}
737
+ .wd-experts .card-menu button{display:block;width:100%;text-align:left}
738
+ .wd-experts .card-menu button{border:0;background:transparent;min-height:40px;padding:8px 12px;border-radius:8px}
739
+ .wd-experts .card-menu button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
740
+ .wd-experts .card-menu .danger{color:var(--dsw-alias-state-error-primary)}
741
+ .wd-experts .card.menu-open{z-index:25}
742
+ .wd-experts .empty{text-align:center}
743
+ .wd-experts .empty{padding:64px 20px}
744
+ .wd-experts .empty strong{display:block;margin-bottom:8px}
745
+ .wd-experts .empty strong{font-size:16px}
746
+ .wd-experts .empty .empty-actions{display:flex;gap:10px;justify-content:center;margin-top:18px}
747
+ .wd-experts .skeleton{background-size:200% 100%;animation:wd-shimmer 1.3s infinite}
748
+ .wd-experts .skeleton{border-radius:17px;border:1px solid var(--dsw-alias-border-l2);background:linear-gradient(100deg,var(--dsw-alias-bg-layer-1) 30%,var(--dsw-alias-bg-layer-2) 50%,var(--dsw-alias-bg-layer-1) 70%);min-height:150px}
749
+ @keyframes wd-shimmer{to{background-position:-200% 0}}
750
+ .wd-experts .notice{display:flex;gap:10px;align-items:flex-start;margin:0 0 16px}
751
+ .wd-experts .notice{padding:12px 14px;border-radius:12px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1)}
752
+ .wd-experts .notice.error{border-color:var(--dsw-alias-state-warn-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,var(--dsw-alias-bg-layer-1))}
753
+ .wd-experts .notice.warn{border-color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-state-warn-tertiary)}
754
+ .wd-experts .notice.info{border-color:var(--dsw-alias-state-success-primary);background:var(--dsw-alias-state-success-tertiary)}
755
+ .wd-experts .notice .notice-body{flex:1;min-width:0}
756
+ .wd-experts .notice .notice-body strong{display:block;margin-bottom:2px}
757
+ .wd-experts .notice button{min-height:30px;padding:2px 10px}
758
+ .expert-dialog{width:min(800px,calc(100vw - 56px));display:flex;flex-direction:column;overflow:hidden}
759
+ .expert-dialog{max-height:min(820px,calc(100dvh - 80px));padding:0}
760
+ .wd-dialog.expert-dialog,.wd-dialog.editor-dialog{box-sizing:border-box}
761
+ .wd-dialog.editor-dialog>.wd-dialog-close{top:16px;right:16px}
762
+ .expert-dialog :focus-visible{outline-offset:3px}
763
+ .expert-dialog :focus-visible{outline:2px solid var(--dsw-alias-brand-text)}
764
+ .expert-dialog .notice.info{border:0;padding:0;background:transparent;font-size:12px;color:var(--dsw-alias-label-tertiary)}
765
+ .expert-dialog .notice.info strong{display:none}
766
+ .expert-dialog .dialog-scroll{overflow:auto}
767
+ .expert-dialog .dialog-scroll{padding:24px}
768
+ .expert-dialog .detail-header{display:grid;grid-template-columns:48px minmax(0,1fr);gap:16px;align-items:start}
769
+ .expert-dialog .detail-header{padding-right:52px}
770
+ .wd-dialog.expert-dialog .detail-avatar{width:48px;display:grid;place-items:center;overflow:hidden}
771
+ .wd-dialog.expert-dialog .detail-avatar{height:48px;border-radius:50%;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font-size:22px;font-weight:600}
772
+ .expert-dialog .detail-avatar img{width:100%;object-fit:cover}
773
+ .expert-dialog .detail-avatar img{height:100%}
774
+ .expert-dialog .detail-title h1{margin:0;overflow-wrap:anywhere}
775
+ .expert-dialog .detail-title h1{font-size:20px;line-height:28px}
776
+ .expert-dialog .detail-subtitle{margin:6px 0 0}
777
+ .expert-dialog .detail-subtitle{color:var(--dsw-alias-label-tertiary);font-size:13px}
778
+ .expert-dialog .detail-title>.detail-head-actions{margin-top:14px;justify-content:flex-start}
779
+ .expert-dialog .detail-head-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap;justify-content:flex-end}
780
+ .expert-dialog .summon{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-inverted);border-color:var(--dsw-alias-border-l2);font-weight:600}
781
+ .expert-dialog button{cursor:pointer}
782
+ .expert-dialog button{font:inherit;min-height:38px;padding:7px 15px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}
783
+ .expert-dialog button:disabled{cursor:not-allowed}
784
+ .expert-dialog button:disabled{opacity:.5}
785
+ .expert-dialog .detail-section-title{display:flex;align-items:center;gap:9px;margin:30px 0 12px}
786
+ .expert-dialog .detail-section-title{font-size:17px;font-weight:600}
787
+ .expert-dialog .detail-desc{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}
788
+ .expert-dialog .detail-desc{color:var(--dsw-alias-label-primary);line-height:1.7}
789
+ .expert-dialog .tag-row{display:flex;flex-wrap:wrap;gap:8px;margin:16px 0 0}
790
+ .expert-dialog .tag{font-size:12px;padding:3px 10px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary)}
791
+ .expert-dialog .example-list{display:grid;gap:10px}
792
+ .expert-dialog .example{display:flex;align-items:center;gap:12px;width:100%;text-align:left}
793
+ .expert-dialog .example{padding:14px 16px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-1)}
794
+ .expert-dialog .example:disabled{color:var(--dsw-alias-label-secondary);opacity:.7}
795
+ .expert-dialog .example:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l2)}
796
+ .expert-dialog .example .example-text{flex:1;min-width:0}
797
+ .expert-dialog .example .example-text strong{display:block;margin-bottom:2px}
798
+ .expert-dialog .example .example-text span{white-space:pre-wrap;overflow-wrap:anywhere}
799
+ .expert-dialog .example .example-text span{color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:1.65}
800
+ .expert-dialog .cap-list{display:grid;gap:8px}
801
+ .expert-dialog .cap-row{display:flex;align-items:center;gap:10px}
802
+ .expert-dialog .cap-row{padding:10px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-1)}
803
+ .expert-dialog .cap-row .cap-state{margin-left:auto;white-space:nowrap}
804
+ .expert-dialog .cap-row .cap-state{font-size:12px}
805
+ .expert-dialog .cap-row.ok .cap-state{color:var(--dsw-alias-state-success-primary)}
806
+ .expert-dialog .cap-row.missing{border-color:var(--dsw-alias-state-warn-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,var(--dsw-alias-bg-layer-1))}
807
+ .expert-dialog .cap-row.missing .cap-state{color:var(--dsw-alias-state-error-primary)}
808
+ .expert-dialog .team-member-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px 16px;margin:16px 0 24px}
809
+ .expert-dialog .team-person{min-width:0}
810
+ .expert-dialog .team-person summary{display:flex;align-items:center;gap:10px;cursor:pointer;list-style:none}
811
+ .expert-dialog .team-person summary::-webkit-details-marker{display:none}
812
+ .expert-dialog .member-avatar{width:38px;flex-shrink:0;display:grid;place-items:center;overflow:hidden}
813
+ .expert-dialog .member-avatar{height:38px;border-radius:50%;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
814
+ .expert-dialog .member-avatar img{width:100%;object-fit:cover}
815
+ .expert-dialog .member-avatar img{height:100%}
816
+ .expert-dialog .member-identity{display:grid;gap:4px;min-width:0}
817
+ .expert-dialog .member-identity{font-size:12px;color:var(--dsw-alias-label-tertiary)}
818
+ .expert-dialog .member-identity strong{overflow-wrap:anywhere}
819
+ .expert-dialog .member-identity strong{font-size:14px;font-weight:500;color:var(--dsw-alias-label-primary)}
820
+ .expert-dialog .member-lead{margin-left:6px;white-space:nowrap}
821
+ .expert-dialog .member-lead{font-size:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover);border-radius:4px;padding:2px 5px}
822
+ .expert-dialog .team-person p{overflow-wrap:anywhere}
823
+ .expert-dialog .team-person p{font-size:12px;line-height:1.7}
824
+ .expert-dialog .member-responsibility{white-space:pre-wrap;overflow:auto}
825
+ .expert-dialog .member-responsibility{max-height:300px}
826
+ .expert-dialog .team-workflows article{border-bottom:1px solid var(--dsw-alias-border-l2)}
827
+ .expert-dialog .team-workflows article{padding:12px 0}
828
+ @media(max-width:900px){.expert-dialog .team-member-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
829
+ @media(max-width:560px){.expert-dialog .team-member-grid{grid-template-columns:1fr}}
830
+ .expert-dialog .expert-settings summary{cursor:pointer;list-style-position:inside;margin:24px 0 12px}
831
+ .expert-dialog .expert-settings summary{font-size:16px;font-weight:600}
832
+ .expert-work-summary{display:grid;gap:12px;margin:20px 0}
833
+ .expert-work-summary>section{border-left:3px solid var(--dsw-alias-brand-text);min-width:0}
834
+ .expert-work-summary>section{padding:2px 0 2px 14px}
835
+ .expert-dialog .expert-work-summary h3{margin:0 0 6px}
836
+ .expert-dialog .expert-work-summary h3{font-size:15px;color:var(--dsw-alias-label-primary)}
837
+ .expert-work-summary p{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}
838
+ .expert-work-summary p{line-height:1.7;color:var(--dsw-alias-label-secondary)}
839
+ .expert-dialog .prose-block{white-space:pre-wrap;overflow-wrap:anywhere;margin:0 0 12px}
840
+ .expert-dialog .prose-block{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:16px 18px;color:var(--dsw-alias-label-primary);line-height:1.7}
841
+ .expert-dialog .prose-block h4{margin:0 0 6px}
842
+ .expert-dialog .prose-block h4{font-size:13px;color:var(--dsw-alias-label-tertiary);font-weight:600}
843
+ .confirm-dialog{width:min(560px,calc(100vw - 40px))}
844
+ .confirm-dialog{padding:24px}
845
+ .confirm-dialog h2{margin:0 52px 14px 0}
846
+ .confirm-dialog h2{font-size:21px}
847
+ .confirm-dialog p{margin:0 0 14px}
848
+ .confirm-dialog p{color:var(--dsw-alias-label-tertiary);line-height:1.7}
849
+ .confirm-dialog button{cursor:pointer}
850
+ .confirm-dialog button{min-height:40px;padding:8px 16px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}
851
+ .confirm-dialog .confirm-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:20px}
852
+ .confirm-dialog .primary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-inverted);border-color:var(--dsw-alias-border-l2);font-weight:600}
853
+ .confirm-dialog .danger.solid{background:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary-foreground)}
854
+ .confirm-dialog .danger.solid:disabled{cursor:not-allowed}
855
+ .confirm-dialog .danger.solid:disabled{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,var(--dsw-alias-bg-layer-1));border-color:var(--dsw-alias-state-error-secondary);color:var(--dsw-alias-label-tertiary)}
856
+ .confirm-dialog .digest{word-break:break-all}
857
+ .confirm-dialog .digest{font:12px/18px ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--dsw-alias-label-tertiary)}
858
+ .confirm-dialog .diff-list{margin:0}
859
+ .confirm-dialog .diff-list{padding-left:20px;color:var(--dsw-alias-label-secondary);line-height:1.9}
860
+ .wd-dialog.publish-dialog{width:min(760px,calc(100vw - 40px));display:flex;flex-direction:column;overflow:hidden}
861
+ .wd-dialog.publish-dialog{max-height:min(820px,calc(100vh - 56px));padding:28px}
862
+ .publish-dialog .publish-scroll{overflow:auto;overflow-wrap:anywhere}
863
+ .publish-dialog .publish-scroll{min-height:0;padding-right:4px}
864
+ .publish-dialog .confirm-actions{flex-shrink:0;border-top:1px solid var(--dsw-alias-border-l2)}
865
+ .publish-dialog .confirm-actions{padding-top:16px}
866
+ .publish-dialog .confirm-actions .primary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-inverted);border-color:var(--dsw-alias-border-l2)}
867
+ .publish-dialog .confirm-actions .primary:hover:not(:disabled){background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-inverted)}
868
+ .publish-dialog .usage-preview{font-size:14px;line-height:1.7}
869
+ .publish-dialog .usage-preview header{display:flex;align-items:flex-start;gap:16px}
870
+ .publish-dialog .usage-preview header>div{min-width:0}
871
+ .publish-dialog .preview-avatar{flex-shrink:0;display:grid;place-items:center;width:56px}
872
+ .publish-dialog .preview-avatar{height:56px;border-radius:50%;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-brand-text);font-size:24px}
873
+ .publish-dialog .usage-preview h3{margin:20px 0 8px}
874
+ .publish-dialog .usage-preview h3{font-size:15px;color:var(--dsw-alias-label-primary)}
875
+ .publish-dialog .usage-preview header h3{margin:0 0 8px}
876
+ .publish-dialog .usage-preview header h3{font-size:20px}
877
+ .publish-dialog .usage-preview p{white-space:pre-wrap;overflow-wrap:anywhere}
878
+ .publish-dialog .preview-tags{display:flex;flex-wrap:wrap;gap:8px}
879
+ .publish-dialog .preview-tags span{border:1px solid var(--dsw-alias-border-l2);border-radius:16px;padding:3px 10px;color:var(--dsw-alias-label-tertiary);font-size:12px}
880
+ .publish-dialog .preview-example{margin:10px 0}
881
+ .publish-dialog .preview-example{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:12px 14px;background:var(--dsw-alias-bg-layer-2)}
882
+ .publish-dialog .preview-example p{margin:4px 0 0}
883
+ .publish-dialog .usage-preview ul{margin:8px 0}
884
+ .publish-dialog .usage-preview ul{padding-left:20px;color:var(--dsw-alias-label-secondary)}
885
+ .publish-dialog .usage-preview li{margin:8px 0}
886
+ .publish-dialog .usage-preview small{display:block;overflow-wrap:anywhere}
887
+ .publish-dialog .usage-preview small{color:var(--dsw-alias-label-tertiary);font-size:12px}
888
+ .publish-dialog .preview-settings,.publish-dialog .preview-digests{margin:20px 0 12px;border-top:1px solid var(--dsw-alias-border-l2)}
889
+ .publish-dialog .preview-settings,.publish-dialog .preview-digests{padding-top:12px}
890
+ .publish-dialog summary{cursor:pointer}
891
+ .publish-dialog summary{color:var(--dsw-alias-label-primary)}
892
+ @media(max-width:640px){.wd-dialog.publish-dialog{width:calc(100vw - 24px)}.wd-dialog.publish-dialog{max-height:calc(100dvh - 24px);height:auto;padding:20px 16px}.publish-dialog h2{font-size:18px}.publish-dialog .confirm-actions button{min-height:44px}}
893
+
894
+ .editor-dialog{width:min(760px,calc(100vw - 56px));display:flex;flex-direction:column;overflow:hidden}
895
+
896
+ .editor-dialog{max-height:min(820px,calc(100dvh - 80px));padding:0}
897
+ .editor-dialog .editor-head{display:flex;align-items:center;gap:14px;flex-shrink:0;border-bottom:1px solid var(--dsw-alias-border-l2)}
898
+ .editor-dialog .editor-head{padding:24px 84px 24px 28px}
899
+ .editor-dialog .editor-head h2{margin:0;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
900
+ .editor-dialog .editor-head h2{font-size:20px}
901
+ .editor-dialog .editor-scroll{overflow:auto}
902
+ .editor-dialog .editor-scroll{min-height:0;padding:22px 28px 28px}
903
+ .editor-dialog .editor-foot{display:flex;align-items:center;gap:12px;flex-shrink:0;border-top:1px solid var(--dsw-alias-border-l2)}
904
+ .editor-dialog .editor-foot{padding:16px 28px;background:var(--dsw-alias-bg-layer-1)}
905
+ .editor-dialog .editor-foot .saved-at{margin-right:auto}
906
+ .editor-dialog .editor-foot .saved-at{color:var(--dsw-alias-label-tertiary);font-size:12px}
907
+ .editor-dialog .group{margin-bottom:18px}
908
+ .editor-dialog .group{border:1px solid var(--dsw-alias-border-l2);border-radius:14px;padding:20px 22px;background:var(--dsw-alias-bg-layer-1)}
909
+ .editor-dialog .group>h3{margin:0 0 16px;display:flex;align-items:center;gap:8px}
910
+ .editor-dialog .group>h3{font-size:15px}
911
+ .editor-dialog .field{margin-bottom:16px}
912
+ .editor-dialog .field:last-child{margin-bottom:0}
913
+ .editor-dialog .field label{display:block;margin-bottom:6px}
914
+ .editor-dialog .field label{font-weight:600;font-size:13px}
915
+ .editor-dialog .field .hint{margin-top:4px}
916
+ .editor-dialog .field .hint{color:var(--dsw-alias-label-dimmed);font-size:12px}
917
+ .editor-dialog .field .field-error{margin-top:4px}
918
+ .editor-dialog .field .field-error{color:var(--dsw-alias-state-error-primary);font-size:12px}
919
+ .editor-dialog :is(input,.wd-form-input),.editor-dialog textarea{box-sizing:border-box;width:100%;min-width:0}
920
+ .editor-dialog input,.editor-dialog textarea{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);border-radius:9px;padding:10px 12px;font:inherit}
921
+ .editor-dialog :is(input,.wd-form-input):focus-visible,.editor-dialog textarea:focus-visible{outline-offset:2px}
922
+ .editor-dialog input:focus-visible,.editor-dialog textarea:focus-visible{outline:2px solid var(--dsw-alias-brand-text)}
923
+ .editor-dialog .tag-editor{grid-template-columns:repeat(2,minmax(0,1fr))}
924
+ .editor-dialog .example-editor-row{display:grid;gap:10px}
925
+ .editor-dialog .example-editor-row{padding:16px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-1)}
926
+ .editor-dialog .example-editor-row textarea{resize:vertical}
927
+ .editor-dialog .example-editor-row textarea{min-height:100px;line-height:1.65}
928
+ .editor-dialog .example-editor-row .remove{justify-self:end}
929
+ .editor-dialog .example-editor-row .remove{color:var(--dsw-alias-state-error-primary)}
930
+
931
+ .editor-dialog .field textarea{resize:vertical}
932
+
933
+ .editor-dialog .field textarea{min-height:88px;line-height:1.7;font:13px/22px "PingFang SC","Microsoft YaHei",sans-serif}
934
+ .editor-dialog .field textarea.prose{min-height:120px}
935
+ .editor-dialog .field .counter{float:right}
936
+ .editor-dialog .field .counter{color:var(--dsw-alias-label-dimmed);font-size:12px;font-weight:400}
937
+ .editor-dialog .field.invalid input,.editor-dialog .field.invalid textarea{border-color:var(--dsw-alias-state-error-primary)}
938
+ .editor-dialog .list-editor{display:grid;gap:10px}
939
+ .editor-dialog .list-row{display:flex;gap:8px;align-items:flex-start}
940
+ .editor-dialog .list-row input,.editor-dialog .list-row textarea{flex:1;min-width:0}
941
+ .editor-dialog .list-row .remove{flex:none}
942
+ .editor-dialog .list-row .remove{min-height:36px;padding:0 12px;color:var(--dsw-alias-state-error-primary)}
943
+ .editor-dialog .add-row{justify-self:start}
944
+ .editor-dialog .add-row{background:transparent;border:1px dashed var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary)}
945
+ .editor-dialog button{cursor:pointer}
946
+ .editor-dialog button{font:inherit;min-height:38px;padding:7px 15px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}
947
+ .editor-dialog button:disabled{cursor:not-allowed}
948
+ .editor-dialog button:disabled{opacity:.5}
949
+ .editor-dialog .primary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-inverted);border-color:var(--dsw-alias-border-l2);font-weight:600}
950
+ .editor-dialog .conflict{margin-bottom:18px}
951
+ .editor-dialog .conflict{border:1px solid var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-state-warn-tertiary);border-radius:12px;padding:16px 18px}
952
+ .editor-dialog .conflict h4{margin:0 0 8px}
953
+ .editor-dialog .conflict h4{color:var(--dsw-alias-state-warn-primary)}
954
+ .editor-dialog .conflict .conflict-actions{display:flex;gap:10px;margin-top:12px}
955
+ .editor-dialog .issues{margin-bottom:18px}
956
+ .editor-dialog .issues{border:1px solid var(--dsw-alias-state-warn-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,var(--dsw-alias-bg-layer-1));border-radius:12px;padding:14px 18px}
957
+ .editor-dialog .issues h4{margin:0 0 8px}
958
+ .editor-dialog .issues h4{color:var(--dsw-alias-state-error-primary)}
959
+ .editor-dialog .issues ul{margin:0}
960
+ .editor-dialog .issues ul{padding-left:20px;color:var(--dsw-alias-label-primary);line-height:1.9}
961
+ .editor-dialog .equipped-row{display:flex;align-items:center;gap:12px}
962
+ .editor-dialog .equipped-row{padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-2)}
963
+ .editor-dialog .equipped-row strong{flex:1;min-width:0;overflow-wrap:anywhere}
964
+ .editor-dialog .equipped-row .remove{color:var(--dsw-alias-state-error-primary)}
965
+ .editor-dialog .skill-picker{margin-top:16px}
966
+ .editor-dialog .skill-picker{padding:16px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-2)}
967
+ .editor-dialog .skill-picker h4{margin:0 0 12px}
968
+ .editor-dialog .skill-picker-list{overflow:auto;margin-top:12px;display:grid;gap:8px}
969
+ .editor-dialog .skill-picker-list{max-height:300px}
970
+ .editor-dialog .skill-choice{display:flex;align-items:flex-start;gap:12px;cursor:pointer}
971
+ .editor-dialog .skill-choice{padding:12px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px}
972
+ .editor-dialog .skill-choice :is(input,.wd-form-input){width:18px;flex:none;margin:3px 0;accent-color:var(--dsw-alias-state-success-primary)}
973
+ .editor-dialog .skill-choice input{height:18px;padding:0}
974
+ .editor-dialog .skill-choice>span{flex:1;min-width:0;overflow-wrap:anywhere}
975
+ .editor-dialog .skill-choice small,.expert-dialog .skill-copy small{display:block;margin-top:4px}
976
+ .editor-dialog .skill-choice small,.expert-dialog .skill-copy small{color:var(--dsw-alias-label-tertiary);line-height:1.6}
977
+ .editor-dialog .skill-choice>small{flex:none}
978
+ .editor-dialog .skill-choice>small{font-size:12px}
979
+ .editor-dialog .picker-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:12px}
980
+ .expert-dialog .skill-copy{flex:1;min-width:0;overflow-wrap:anywhere}
981
+ .import-dialog{width:min(720px,calc(100vw - 40px))}
982
+ .import-dialog{padding:24px}
983
+ .import-dialog h2{margin:0 56px 20px 0}
984
+ .import-dialog h2{font-size:23px}
985
+ .import-dialog button,.import-dialog select{font:inherit;color:inherit}
986
+ .import-dialog .dropzone{width:100%;display:grid;place-content:center;justify-items:center;gap:10px;cursor:pointer}
987
+ .import-dialog .dropzone{min-height:200px;border:1px dashed var(--dsw-alias-border-l2);border-radius:18px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}
988
+ .import-dialog .dropzone:hover,.import-dialog .dropzone.dragging{border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2)}
989
+ .import-dialog .dropzone:disabled{cursor:wait}
990
+ .import-dialog .dropzone:disabled{opacity:.7}
991
+ .import-dialog .upload-glyph{width:50px;display:grid;place-items:center}
992
+ .import-dialog .upload-glyph{height:42px;border:2px solid var(--dsw-alias-border-l2);border-radius:8px;font-size:24px;color:var(--dsw-alias-label-tertiary)}
993
+ .import-dialog .dropzone strong{font-size:17px;font-weight:500}
994
+ .import-dialog .dropzone small{color:var(--dsw-alias-label-tertiary)}
995
+ .import-dialog .visually-hidden{position:absolute;width:1px;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}
996
+ .import-dialog .visually-hidden{height:1px;padding:0;border:0}
997
+ .import-dialog .review{margin-top:24px}
998
+ .import-dialog .review h3{margin:0 0 12px}
999
+ .import-dialog .review h3{font-size:17px}
1000
+ .import-dialog dl{display:grid;grid-template-columns:110px 1fr;gap:10px;margin:16px 0}
1001
+ .import-dialog dt{color:var(--dsw-alias-label-tertiary)}
1002
+ .import-dialog dd{margin:0;overflow-wrap:anywhere}
1003
+ .import-dialog .issue-list{margin:8px 0 0}
1004
+ .import-dialog .issue-list{padding-left:20px;color:var(--dsw-alias-state-error-primary);line-height:1.9}
1005
+ .import-dialog .import-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:22px}
1006
+ .import-dialog .import-actions button{cursor:pointer}
1007
+ .import-dialog .import-actions button{min-height:42px;padding:8px 18px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-bg-layer-2)}
1008
+ .import-dialog .import-actions .install{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-inverted);border-color:var(--dsw-alias-border-l2);font-weight:600}
1009
+ .import-dialog .error{margin:16px 0 0}
1010
+ .import-dialog .error{color:var(--dsw-alias-state-error-primary)}
1011
+ .wd-experts svg,.expert-dialog svg,.editor-dialog svg,.confirm-dialog svg,.import-dialog svg{width:20px;stroke:currentColor;stroke-width:1.7;fill:none;stroke-linecap:round}
1012
+ .wd-experts svg,.expert-dialog svg,.editor-dialog svg,.confirm-dialog svg,.import-dialog svg{height:20px}
1013
+ .wd-experts .error-text{color:var(--dsw-alias-state-error-primary)}
1014
+ @media(max-width:1400px){.wd-experts .grid{grid-template-columns:repeat(3,minmax(0,1fr))}}
1015
+ @media(max-width:1100px){.wd-experts .grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
1016
+ @media(max-width:900px){.wd-experts .search{order:2;margin-left:0;flex:1}.expert-dialog .detail-header{grid-template-columns:48px minmax(0,1fr)}.wd-dialog.expert-dialog .detail-avatar{width:48px}.wd-dialog.expert-dialog .detail-avatar{height:48px;font-size:22px}.expert-dialog .detail-title>.detail-head-actions{justify-content:flex-start}}
1017
+ @media(max-width:600px){.wd-experts{padding:16px}.wd-experts .nav-toggle{display:block}.wd-experts .grid{grid-template-columns:1fr}.wd-experts .card-menu{right:auto;left:0}.expert-dialog{width:calc(100vw - 24px)}.expert-dialog{max-height:calc(100dvh - 24px);height:auto;border-radius:12px}.wd-dialog.expert-dialog,.wd-dialog.editor-dialog{box-sizing:border-box}
1018
+ .wd-dialog.editor-dialog>.wd-dialog-close{top:16px;right:16px}
1019
+ .expert-dialog :focus-visible{outline-offset:3px}
1020
+ .expert-dialog :focus-visible{outline:2px solid var(--dsw-alias-brand-text)}
1021
+ .expert-dialog .notice.info{border:0;padding:0;background:transparent;font-size:12px;color:var(--dsw-alias-label-tertiary)}
1022
+ .expert-dialog .notice.info strong{display:none}
1023
+ .expert-dialog .dialog-scroll{padding:24px 18px}.editor-dialog{width:calc(100vw - 24px)}.editor-dialog{max-height:calc(100dvh - 24px);height:auto;border-radius:12px}.editor-dialog .editor-scroll{padding:18px}.editor-dialog .editor-head{padding-left:18px;padding-right:72px}.editor-dialog .editor-foot{gap:8px;flex-wrap:wrap}.editor-dialog .editor-foot{padding:12px 18px}.editor-dialog .editor-foot .saved-at{flex-basis:100%}.editor-dialog .tag-editor{grid-template-columns:1fr}.import-dialog{padding:24px 18px}.import-dialog dl{grid-template-columns:1fr;gap:4px}.import-dialog dd{margin-bottom:8px}}
1024
+ @media(prefers-reduced-motion:reduce){.wd-experts .skeleton{animation:none}}
1025
+
1026
+
1027
+ }
1028
+ /* The shared Modal rules are unlayered; sizing must use the same cascade layer. */
1029
+ .wd-dialog.editor-dialog{width:min(760px,calc(100vw - 56px));max-height:min(820px,calc(100dvh - 80px))}
1030
+ @media(max-width:640px){.wd-dialog.editor-dialog{width:calc(100vw - 24px);max-height:calc(100dvh - 24px)}}
1031
+
1032
+ `;
1033
+
1034
+ // packages/experts/src/detail.tsx
1035
+ var import_react3 = require("react");
1036
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1037
+ function draftAhead(detail) {
1038
+ const published = detail.publishedRevision;
1039
+ const draft = detail.draft;
1040
+ if (published === null || draft === null) return false;
1041
+ return draft.name !== published.name || draft.description !== published.description || draft.role !== published.role || draft.preferredSkills.join("\n") !== published.preferredSkills.join("\n");
1042
+ }
1043
+ function ExpertDetailModal({
1044
+ expertId,
1045
+ management,
1046
+ sessionId,
1047
+ acting,
1048
+ onClose,
1049
+ onChanged,
1050
+ onEdit,
1051
+ onCopy,
1052
+ onRemove
1053
+ }) {
1054
+ const [detail, setDetail] = (0, import_react3.useState)();
1055
+ const [phase, setPhase] = (0, import_react3.useState)("loading");
1056
+ const [error, setError] = (0, import_react3.useState)("");
1057
+ const [menuOpen, setMenuOpen] = (0, import_react3.useState)(false);
1058
+ const [adoption, setAdoption] = (0, import_react3.useState)(null);
1059
+ const [saving, setSaving] = (0, import_react3.useState)(false);
1060
+ const menu = (0, import_react3.useRef)(null);
1061
+ const load = (0, import_react3.useCallback)(async () => {
1062
+ setPhase("loading");
1063
+ setError("");
1064
+ try {
1065
+ setDetail(await management.get(expertId));
1066
+ setPhase("ready");
1067
+ } catch (cause) {
1068
+ setError(reasonOf(cause));
1069
+ setPhase("error");
1070
+ }
1071
+ }, [expertId, management]);
1072
+ (0, import_react3.useEffect)(() => {
1073
+ void load();
1074
+ }, [load]);
1075
+ (0, import_react3.useEffect)(() => {
1076
+ if (sessionId === void 0) {
1077
+ setAdoption(null);
1078
+ return;
1079
+ }
1080
+ let cancelled = false;
1081
+ void management.adoption(sessionId).then(
1082
+ (value) => {
1083
+ if (!cancelled) setAdoption(value);
1084
+ },
1085
+ () => {
1086
+ if (!cancelled) setAdoption(null);
1087
+ }
1088
+ );
1089
+ return () => {
1090
+ cancelled = true;
1091
+ };
1092
+ }, [management, sessionId, detail]);
1093
+ (0, import_react3.useEffect)(() => {
1094
+ if (!menuOpen) return;
1095
+ const outside = (event) => {
1096
+ if (!(event.target instanceof Element) || !menu.current?.contains(event.target)) setMenuOpen(false);
1097
+ };
1098
+ document.addEventListener("pointerdown", outside);
1099
+ return () => document.removeEventListener("pointerdown", outside);
1100
+ }, [menuOpen]);
1101
+ if (phase === "loading") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dialog-scroll", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "muted", children: "\u6B63\u5728\u8BFB\u53D6\u4E13\u5BB6\u8BE6\u60C5\u2026" }) });
1102
+ if (phase === "error" || detail === void 0) {
1103
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dialog-scroll", children: [
1104
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "error-text", role: "alert", children: error || "\u65E0\u6CD5\u8BFB\u53D6\u4E13\u5BB6\u8BE6\u60C5\u3002" }),
1105
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "detail-head-actions", style: { marginTop: 16 }, children: [
1106
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { onClick: () => void load(), children: "\u91CD\u8BD5" }),
1107
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { onClick: onClose, children: "\u5173\u95ED" })
1108
+ ] })
1109
+ ] });
1110
+ }
1111
+ const draft = detail.draft;
1112
+ const published = detail.publishedRevision;
1113
+ const name2 = draft?.name ?? published?.name ?? "";
1114
+ const description = draft?.description ?? published?.description ?? "";
1115
+ const role = draft?.role ?? published?.role ?? "";
1116
+ const skills = draft?.preferredSkills ?? published?.preferredSkills ?? [];
1117
+ const adoptedHere = adoption !== null && adoption.expertId === detail.expert.id;
1118
+ const unlocked = sessionId !== void 0 && published !== null;
1119
+ const adoptHint = sessionId === void 0 ? "\u6253\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u540E\uFF0C\u8F93\u5165\u6846\u5DE6\u4FA7\u7684\u4E13\u5BB6\u9009\u62E9\u5668\u4F1A\u7ED1\u5B9A\u5F53\u524D\u4F1A\u8BDD\uFF0C\u8FD9\u91CC\u5C31\u80FD\u76F4\u63A5\u91C7\u7528\u3002" : published === null ? "\u8BE5\u4E13\u5BB6\u8FD8\u6CA1\u6709\u53D1\u5E03\u4FEE\u8BA2\uFF0C\u5148\u53D1\u5E03\u518D\u91C7\u7528\u3002" : `\u91C7\u7528\u540E\u4F1A\u628A\u4FEE\u8BA2 ${published.number} \u7684\u89D2\u8272\u8BF4\u660E\u5199\u8FDB\u672C\u4F1A\u8BDD\u7684\u4E0A\u4E0B\u6587\u3002`;
1120
+ const setAdoptionHere = async (next) => {
1121
+ if (sessionId === void 0) return;
1122
+ setSaving(true);
1123
+ setError("");
1124
+ try {
1125
+ setAdoption(await management.setAdoption(sessionId, next ? detail.expert.id : null));
1126
+ onChanged();
1127
+ } catch (cause) {
1128
+ setError(reasonOf(cause));
1129
+ } finally {
1130
+ setSaving(false);
1131
+ }
1132
+ };
1133
+ const busy = acting || saving;
1134
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dialog-scroll", children: [
1135
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("header", { className: "detail-header", children: [
1136
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "detail-avatar", "aria-hidden": true, children: name2.trim().charAt(0) || "\u4E13" }),
1137
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "detail-title", children: [
1138
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h1", { children: name2 || "\uFF08\u672A\u547D\u540D\u4E13\u5BB6\uFF09" }),
1139
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "detail-subtitle", children: [
1140
+ "\u6211\u7684\u4E13\u5BB6 \xB7 \u4E13\u5BB6 \xB7 ",
1141
+ published === null ? "\u8349\u7A3F" : `\u5DF2\u53D1\u5E03\u4FEE\u8BA2 ${published.number}`
1142
+ ] }),
1143
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "detail-head-actions", children: [
1144
+ published === null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "summon", disabled: busy, onClick: () => onEdit(expertId), children: "\u7EE7\u7EED\u7F16\u8F91" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1145
+ "button",
1146
+ {
1147
+ className: "summon",
1148
+ disabled: busy || !unlocked,
1149
+ title: adoptHint,
1150
+ onClick: () => void setAdoptionHere(!adoptedHere),
1151
+ children: adoptedHere ? "\u53D6\u6D88\u91C7\u7528" : "\u4E3A\u672C\u6B21\u5BF9\u8BDD\u91C7\u7528"
1152
+ }
1153
+ ),
1154
+ published !== null && !unlocked && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "muted", children: adoptHint }),
1155
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "card-actions", ref: menu, children: [
1156
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1157
+ "button",
1158
+ {
1159
+ className: "more-button",
1160
+ "aria-label": "\u7BA1\u7406\u4E13\u5BB6",
1161
+ "aria-haspopup": "menu",
1162
+ "aria-expanded": menuOpen,
1163
+ disabled: busy,
1164
+ onClick: () => setMenuOpen((open) => !open),
1165
+ children: "\u2022\u2022\u2022"
1166
+ }
1167
+ ),
1168
+ menuOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "card-menu", role: "menu", style: { right: 0, left: "auto" }, children: [
1169
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { role: "menuitem", onClick: () => {
1170
+ setMenuOpen(false);
1171
+ onEdit(expertId);
1172
+ }, children: "\u7F16\u8F91" }),
1173
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { role: "menuitem", onClick: () => {
1174
+ setMenuOpen(false);
1175
+ onClose();
1176
+ onEdit(expertId);
1177
+ }, children: "\u7F16\u8F91\u5236\u4F5C\u6587\u4EF6" }),
1178
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { role: "menuitem", disabled: busy, onClick: () => {
1179
+ setMenuOpen(false);
1180
+ onCopy(expertId);
1181
+ }, children: "\u590D\u5236\u5230\u6211\u7684\u4E13\u5BB6" }),
1182
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1183
+ "button",
1184
+ {
1185
+ className: "danger",
1186
+ role: "menuitem",
1187
+ disabled: busy,
1188
+ onClick: () => {
1189
+ setMenuOpen(false);
1190
+ onRemove({ id: expertId, name: name2 });
1191
+ },
1192
+ children: "\u5220\u9664"
1193
+ }
1194
+ )
1195
+ ] })
1196
+ ] })
1197
+ ] })
1198
+ ] })
1199
+ ] }),
1200
+ draftAhead(detail) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "notice", role: "status", children: [
1201
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "notice-body", children: [
1202
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "\u8349\u7A3F\u6709\u4FEE\u6539\uFF0C\u5C1A\u672A\u53D1\u5E03" }),
1203
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
1204
+ "\u5F53\u524D\u8BE6\u60C5\u4E0E\u91C7\u7528\u4F7F\u7528\u5DF2\u53D1\u5E03\u7248\u672C\uFF1B\u7F16\u8F91\u8349\u7A3F\u4E0D\u4F1A\u66F4\u65B0\u5B83\u3002\u5DF2\u53D1\u5E03\u4FEE\u8BA2 ",
1205
+ published?.number,
1206
+ "\uFF0C\u8349\u7A3F\u91CC\u5DF2\u6709\u672A\u53D1\u5E03\u7684\u6539\u52A8\u3002"
1207
+ ] })
1208
+ ] }),
1209
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { disabled: busy, onClick: () => {
1210
+ onClose();
1211
+ onEdit(expertId);
1212
+ }, children: "\u5BA1\u9605\u8349\u7A3F" })
1213
+ ] }),
1214
+ description.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "detail-desc", style: { marginTop: 20 }, children: description }),
1215
+ skills.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "tag-row", children: skills.map((skill) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "tag", children: skill }, skill)) }),
1216
+ error.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "notice error", role: "alert", style: { marginTop: 20 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "notice-body", children: [
1217
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "\u65E0\u6CD5\u5B8C\u6210\u64CD\u4F5C" }),
1218
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: error })
1219
+ ] }) }),
1220
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("details", { className: "expert-settings", children: [
1221
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("summary", { children: [
1222
+ "\u914D\u5907\u6280\u80FD \xB7 ",
1223
+ skills.length
1224
+ ] }),
1225
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h2", { className: "detail-section-title", children: [
1226
+ "\u9996\u9009\u6280\u80FD \xB7 ",
1227
+ skills.length
1228
+ ] }),
1229
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "detail-subtitle", children: "\u8FD9\u4E9B\u662F\u4E13\u5BB6\u58F0\u660E\u7684\u9996\u9009\u6280\u80FD\u540D\u3002Host \u53EA\u4FDD\u5B58\u540D\u79F0\uFF0C\u4E0D\u4FDD\u5B58\u7248\u672C\u6216\u53EF\u7528\u6027\u72B6\u6001\uFF1B\u91C7\u7528\u540E\u5B83\u4EEC\u53EA\u4F5C\u4E3A\u63D0\u793A\u8FDB\u5165\u4F1A\u8BDD\u3002" }),
1230
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "cap-list", children: [
1231
+ skills.map((skill) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "cap-row", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "skill-copy", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: skill }) }) }, skill)),
1232
+ skills.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "cap-row", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "muted", children: "\u672A\u663E\u5F0F\u914D\u5907\u6280\u80FD\uFF0C\u4ECD\u53D7\u539F\u751F\u4EFB\u52A1\u80FD\u529B\u4E0E\u6743\u9650\u9650\u5236\u3002" }) })
1233
+ ] })
1234
+ ] }),
1235
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("details", { className: "expert-settings", children: [
1236
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("summary", { children: "\u5B8C\u6574\u4E13\u4E1A\u8BBE\u5B9A" }),
1237
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "detail-subtitle", children: published === null ? "\u8349\u7A3F" : `\u5DF2\u53D1\u5E03\u4FEE\u8BA2 ${published.number}` }),
1238
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "prose-block", children: role || "\uFF08\u6682\u65E0\u89D2\u8272\u8BF4\u660E\uFF09" })
1239
+ ] }),
1240
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "detail-head-actions", style: { marginTop: 28, justifyContent: "flex-end" }, children: [
1241
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { onClick: onClose, children: "\u5173\u95ED" }),
1242
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { onClick: () => {
1243
+ void load();
1244
+ onChanged();
1245
+ }, disabled: busy, children: "\u5237\u65B0" })
1246
+ ] })
1247
+ ] });
1248
+ }
1249
+
1250
+ // packages/experts/src/editor.tsx
1251
+ var import_react4 = require("react");
1252
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1253
+ function fromDetail(detail) {
1254
+ const draft = detail.draft;
1255
+ const published = detail.publishedRevision;
1256
+ return {
1257
+ name: draft?.name ?? published?.name ?? "",
1258
+ description: draft?.description ?? published?.description ?? "",
1259
+ role: draft?.role ?? published?.role ?? "",
1260
+ skills: [...draft?.preferredSkills ?? published?.preferredSkills ?? []]
1261
+ };
1262
+ }
1263
+ function parseSkills(value) {
1264
+ return [...new Set(value.split(/[\n,,、]/u).map((part) => part.trim()).filter((part) => part.length > 0))];
1265
+ }
1266
+ function UsagePreview({ form }) {
1267
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "usage-preview", "aria-label": "\u4E13\u5BB6\u4F7F\u7528\u9884\u89C8", children: [
1268
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("header", { children: [
1269
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "preview-avatar", "aria-hidden": true, children: form.name.trim().charAt(0) || "\u4E13" }),
1270
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
1271
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: form.name.trim() || "\uFF08\u672A\u547D\u540D\u4E13\u5BB6\uFF09" }),
1272
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: form.description })
1273
+ ] })
1274
+ ] }),
1275
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "prose-block", style: { whiteSpace: "pre-wrap" }, children: form.role }),
1276
+ form.skills.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1277
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: "\u9996\u9009\u6280\u80FD" }),
1278
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { children: form.skills.map((skill) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: skill }) }, skill)) })
1279
+ ] }),
1280
+ form.skills.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1281
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: "\u9996\u9009\u6280\u80FD" }),
1282
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: "\u672A\u663E\u5F0F\u914D\u5907\u6280\u80FD\uFF0C\u4ECD\u53D7\u539F\u751F\u4EFB\u52A1\u80FD\u529B\u4E0E\u6743\u9650\u9650\u5236\u3002" })
1283
+ ] })
1284
+ ] });
1285
+ }
1286
+ function PublishConfirmDialog({
1287
+ expertId,
1288
+ revision,
1289
+ form,
1290
+ management,
1291
+ onCancel,
1292
+ onPublished
1293
+ }) {
1294
+ const [busy, setBusy] = (0, import_react4.useState)(false);
1295
+ const [error, setError] = (0, import_react4.useState)("");
1296
+ const [receipt, setReceipt] = (0, import_react4.useState)();
1297
+ const confirm = async () => {
1298
+ setBusy(true);
1299
+ setError("");
1300
+ try {
1301
+ const result = await management.publish(expertId, revision);
1302
+ setReceipt(result.revision);
1303
+ } catch (cause) {
1304
+ setError(reasonOf(cause));
1305
+ } finally {
1306
+ setBusy(false);
1307
+ }
1308
+ };
1309
+ if (receipt !== void 0) {
1310
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Modal, { open: true, title: "\u53D1\u5E03\u6210\u529F", className: "wd-dialog confirm-dialog", onClose: onPublished, children: [
1311
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "wd-dialog-close", "aria-label": "\u5173\u95ED", onClick: onPublished, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CloseIcon, {}) }),
1312
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u53D1\u5E03\u6210\u529F" }),
1313
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { children: [
1314
+ "\u5DF2\u53D1\u5E03\u300C",
1315
+ form.name.trim() || "\u8BE5\u4E13\u5BB6",
1316
+ "\u300D\u7684\u4FEE\u8BA2 ",
1317
+ receipt.number,
1318
+ "\u3002\u5DF2\u7ECF\u91C7\u7528\u8FC7\u5B83\u7684\u4F1A\u8BDD\u4FDD\u6301\u539F\u6765\u7684\u4FEE\u8BA2\uFF1B\u4E4B\u540E\u91C7\u7528\u5B83\u7684\u4F1A\u8BDD\u4F7F\u7528\u8FD9\u4E00\u7248\u3002"
1319
+ ] }),
1320
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "digest", children: [
1321
+ "\u4FEE\u8BA2 ",
1322
+ receipt.id
1323
+ ] }),
1324
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "confirm-actions", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "primary", onClick: onPublished, children: "\u8FD4\u56DE\u6211\u7684\u4E13\u5BB6" }) })
1325
+ ] });
1326
+ }
1327
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Modal, { open: true, title: "\u786E\u8BA4\u53D1\u5E03\u4E13\u5BB6", className: "wd-dialog confirm-dialog publish-dialog", onClose: () => {
1328
+ if (!busy) onCancel();
1329
+ }, children: [
1330
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "wd-dialog-close", "aria-label": "\u5173\u95ED", onClick: onCancel, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CloseIcon, {}) }),
1331
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u786E\u8BA4\u53D1\u5E03\u6B64\u7248\u672C" }),
1332
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: "\u8BF7\u5BA1\u9605\u4E0B\u65B9\u4E13\u5BB6\u5185\u5BB9\u3002\u786E\u8BA4\u540E\uFF0C\u4E4B\u540E\u91C7\u7528\u5B83\u7684\u4F1A\u8BDD\u4F7F\u7528\u6B64\u7248\u672C\uFF1B\u4EE5\u540E\u7F16\u8F91\u9700\u91CD\u65B0\u53D1\u5E03\uFF0C\u5DF2\u6709\u4F1A\u8BDD\u4FDD\u6301\u539F\u4FEE\u8BA2\u3002" }),
1333
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "publish-scroll", children: [
1334
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(UsagePreview, { form }),
1335
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("details", { className: "preview-digests", children: [
1336
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("summary", { children: "\u7248\u672C\u4FE1\u606F" }),
1337
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "digest", children: [
1338
+ "\u8349\u7A3F\u4FEE\u8BA2 ",
1339
+ revision
1340
+ ] })
1341
+ ] })
1342
+ ] }),
1343
+ error.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "error-text", role: "alert", style: { marginTop: 12 }, children: error }),
1344
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "confirm-actions", children: [
1345
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: onCancel, disabled: busy, children: "\u53D6\u6D88" }),
1346
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "primary", onClick: () => void confirm(), disabled: busy, children: busy ? "\u6B63\u5728\u53D1\u5E03\u2026" : "\u786E\u8BA4\u53D1\u5E03\u6B64\u7248\u672C" })
1347
+ ] })
1348
+ ] });
1349
+ }
1350
+ function ExpertDraftEditor({ expertId, management, onClose, onSaved, onPublished }) {
1351
+ const [detail, setDetail] = (0, import_react4.useState)();
1352
+ const [form, setForm] = (0, import_react4.useState)();
1353
+ const [baseline, setBaseline] = (0, import_react4.useState)("");
1354
+ const [phase, setPhase] = (0, import_react4.useState)("loading");
1355
+ const [error, setError] = (0, import_react4.useState)("");
1356
+ const [saving, setSaving] = (0, import_react4.useState)(false);
1357
+ const [savedAt, setSavedAt] = (0, import_react4.useState)();
1358
+ const [conflict, setConflict] = (0, import_react4.useState)();
1359
+ const [skillInput, setSkillInput] = (0, import_react4.useState)("");
1360
+ const [publish, setPublish] = (0, import_react4.useState)();
1361
+ const load = (0, import_react4.useCallback)(async () => {
1362
+ setPhase("loading");
1363
+ setError("");
1364
+ try {
1365
+ const next = await management.get(expertId);
1366
+ const initial = fromDetail(next);
1367
+ setDetail(next);
1368
+ setForm(initial);
1369
+ setBaseline(JSON.stringify(initial));
1370
+ setPhase("ready");
1371
+ } catch (cause) {
1372
+ setError(reasonOf(cause));
1373
+ setPhase("error");
1374
+ }
1375
+ }, [expertId, management]);
1376
+ (0, import_react4.useEffect)(() => {
1377
+ void load();
1378
+ }, [load]);
1379
+ const dirty = (0, import_react4.useMemo)(() => form !== void 0 && JSON.stringify(form) !== baseline, [form, baseline]);
1380
+ const save = (0, import_react4.useCallback)(async (current2, expectedRevision) => {
1381
+ setSaving(true);
1382
+ setError("");
1383
+ try {
1384
+ const next = await management.updateDraft(expertId, {
1385
+ name: current2.name.trim(),
1386
+ description: current2.description.trim(),
1387
+ role: current2.role,
1388
+ preferredSkills: current2.skills
1389
+ }, expectedRevision);
1390
+ const refreshed = fromDetail(next);
1391
+ setDetail(next);
1392
+ setForm(refreshed);
1393
+ setBaseline(JSON.stringify(refreshed));
1394
+ setConflict(void 0);
1395
+ setSavedAt(/* @__PURE__ */ new Date());
1396
+ onSaved();
1397
+ return next.draft?.revision;
1398
+ } catch (cause) {
1399
+ if (codeOf(cause) === "experts/draft-conflict") {
1400
+ try {
1401
+ const fresh = await management.get(expertId);
1402
+ setConflict({ latest: fromDetail(fresh), latestRevision: fresh.draft?.revision ?? "" });
1403
+ setError("\u8349\u7A3F\u5DF2\u5728\u522B\u5904\u66F4\u65B0\uFF0C\u8BF7\u9009\u62E9\u4FDD\u7559\u4F60\u7684\u4FEE\u6539\u6216\u52A0\u8F7D\u6700\u65B0\u7248\u672C\u3002");
1404
+ } catch {
1405
+ setError(reasonOf(cause));
1406
+ }
1407
+ } else setError(reasonOf(cause));
1408
+ return void 0;
1409
+ } finally {
1410
+ setSaving(false);
1411
+ }
1412
+ }, [expertId, management, onSaved]);
1413
+ const onPublish = (0, import_react4.useCallback)(async () => {
1414
+ if (form === void 0 || detail?.draft == null) return;
1415
+ const current2 = form;
1416
+ let revision = detail.draft.revision;
1417
+ if (dirty) {
1418
+ const saved = await save(current2, revision);
1419
+ if (saved === void 0) return;
1420
+ revision = saved;
1421
+ }
1422
+ setError("");
1423
+ setPublish({ revision, form: current2 });
1424
+ }, [detail, dirty, form, save]);
1425
+ if (publish !== void 0) {
1426
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1427
+ PublishConfirmDialog,
1428
+ {
1429
+ expertId,
1430
+ revision: publish.revision,
1431
+ form: publish.form,
1432
+ management,
1433
+ onCancel: () => setPublish(void 0),
1434
+ onPublished: () => {
1435
+ setPublish(void 0);
1436
+ onPublished();
1437
+ }
1438
+ }
1439
+ );
1440
+ }
1441
+ if (phase !== "ready" || form === void 0) {
1442
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Modal, { open: true, title: "\u7F16\u8F91\u4E13\u5BB6\u8349\u7A3F", className: "wd-dialog editor-dialog", onClose, children: [
1443
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "wd-dialog-close", "aria-label": "\u5173\u95ED", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CloseIcon, {}) }),
1444
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "editor-head", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u7F16\u8F91\u4E13\u5BB6\u8349\u7A3F" }) }),
1445
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "editor-scroll", children: [
1446
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "muted", children: error || "\u6B63\u5728\u52A0\u8F7D\u8349\u7A3F\u2026" }),
1447
+ phase === "error" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "detail-head-actions", style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: () => void load(), children: "\u91CD\u8BD5" }) })
1448
+ ] })
1449
+ ] });
1450
+ }
1451
+ const nameInvalid = form.name.trim().length === 0 || form.name.length > EXPERT_LIMITS.nameMax;
1452
+ const descInvalid = form.description.length > EXPERT_LIMITS.descriptionMax;
1453
+ const roleInvalid = form.role.trim().length === 0 || form.role.length > EXPERT_LIMITS.roleMax;
1454
+ const hasPublished = detail?.publishedRevision != null;
1455
+ const noDraft = detail?.draft == null;
1456
+ const set = (key, value) => setForm((prev) => prev === void 0 ? prev : { ...prev, [key]: value });
1457
+ const addSkill = () => {
1458
+ const next = parseSkills(skillInput);
1459
+ if (next.length === 0) return;
1460
+ set("skills", [...form.skills, ...next.filter((skill) => !form.skills.includes(skill))].slice(0, EXPERT_LIMITS.skillsMax));
1461
+ setSkillInput("");
1462
+ };
1463
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Modal, { open: true, title: "\u7F16\u8F91\u4E13\u5BB6\u8349\u7A3F", className: "wd-dialog editor-dialog", onClose, children: [
1464
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "wd-dialog-close", "aria-label": "\u5173\u95ED", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CloseIcon, {}) }),
1465
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "editor-head", children: [
1466
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: form.name.trim() || "\u7F16\u8F91\u4E13\u5BB6\u8349\u7A3F" }),
1467
+ savedAt !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "saved-at", children: [
1468
+ "\u5DF2\u4FDD\u5B58 ",
1469
+ savedAt.toLocaleTimeString()
1470
+ ] })
1471
+ ] }),
1472
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "editor-scroll", children: [
1473
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "notice", role: "status", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "notice-body", children: [
1474
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: hasPublished ? dirty ? "\u8349\u7A3F\u6709\u4FEE\u6539\uFF0C\u5C1A\u672A\u53D1\u5E03" : "\u6B63\u5728\u7F16\u8F91\u8349\u7A3F" : "\u6B63\u5728\u7F16\u8F91\u672A\u53D1\u5E03\u8349\u7A3F" }),
1475
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\u4FDD\u5B58\u8349\u7A3F\u4EC5\u4FDD\u5B58\u7F16\u8F91\u5185\u5BB9\uFF1B\u660E\u786E\u786E\u8BA4\u53D1\u5E03\u540E\uFF0C\u4E13\u5BB6\u8BE6\u60C5\u4E0E\u4E4B\u540E\u91C7\u7528\u5B83\u7684\u4F1A\u8BDD\u624D\u4F1A\u4F7F\u7528\u6B64\u7248\u672C\u3002\u5DF2\u6709\u4F1A\u8BDD\u4FDD\u6301\u5B83\u91C7\u7528\u7684\u4FEE\u8BA2\u3002" })
1476
+ ] }) }),
1477
+ conflict !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "conflict", children: [
1478
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h4", { children: "\u8349\u7A3F\u51B2\u7A81" }),
1479
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "muted", children: "Host \u5DF2\u6709\u66F4\u65B0\u7684\u8349\u7A3F\u3002\u4F60\u53EF\u4EE5\u4FDD\u7559\u5F53\u524D\u4FEE\u6539\u5E76\u8986\u76D6\uFF0C\u6216\u52A0\u8F7D\u6700\u65B0\u7248\u672C\uFF08\u5C06\u4E22\u5F03\u672A\u4FDD\u5B58\u7684\u672C\u5730\u4FEE\u6539\uFF09\u3002" }),
1480
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "conflict-actions", children: [
1481
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: () => {
1482
+ setConflict(void 0);
1483
+ void save(form, conflict.latestRevision);
1484
+ }, children: "\u4FDD\u7559\u6211\u7684\u5E76\u8986\u76D6" }),
1485
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: () => {
1486
+ setForm(conflict.latest);
1487
+ setBaseline(JSON.stringify(conflict.latest));
1488
+ setConflict(void 0);
1489
+ setError("");
1490
+ }, children: "\u52A0\u8F7D\u6700\u65B0\u7248\u672C" })
1491
+ ] })
1492
+ ] }),
1493
+ error.length > 0 && conflict === void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "issues", children: [
1494
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h4", { children: "\u65E0\u6CD5\u5B8C\u6210\u64CD\u4F5C" }),
1495
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: error }) })
1496
+ ] }),
1497
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "group", children: [
1498
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: "\u57FA\u672C\u4FE1\u606F" }),
1499
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `field ${nameInvalid ? "invalid" : ""}`, children: [
1500
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { htmlFor: "ex-name", children: [
1501
+ "\u540D\u79F0 ",
1502
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "counter", children: [
1503
+ form.name.length,
1504
+ "/",
1505
+ EXPERT_LIMITS.nameMax
1506
+ ] })
1507
+ ] }),
1508
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { id: "ex-name", value: form.name, maxLength: EXPERT_LIMITS.nameMax + 20, placeholder: "\u4F8B\u5982\uFF1A\u5408\u540C\u5BA1\u67E5\u4E13\u5BB6", onChange: (event) => set("name", event.currentTarget.value) }),
1509
+ nameInvalid && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "field-error", children: [
1510
+ "\u540D\u79F0\u4E3A\u5FC5\u586B\uFF0C\u4E14\u4E0D\u8D85\u8FC7 ",
1511
+ EXPERT_LIMITS.nameMax,
1512
+ " \u4E2A\u5B57\u7B26\u3002"
1513
+ ] })
1514
+ ] }),
1515
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `field ${descInvalid ? "invalid" : ""}`, children: [
1516
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { htmlFor: "ex-desc", children: [
1517
+ "\u7B80\u4ECB ",
1518
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "counter", children: [
1519
+ form.description.length,
1520
+ "/",
1521
+ EXPERT_LIMITS.descriptionMax
1522
+ ] })
1523
+ ] }),
1524
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("textarea", { id: "ex-desc", value: form.description, placeholder: "\u4E00\u53E5\u8BDD\u8BF4\u660E\u8FD9\u4E2A\u4E13\u5BB6\u80FD\u5E2E\u4F60\u505A\u4EC0\u4E48", onChange: (event) => set("description", event.currentTarget.value) }),
1525
+ descInvalid && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "field-error", children: [
1526
+ "\u7B80\u4ECB\u4E0D\u8D85\u8FC7 ",
1527
+ EXPERT_LIMITS.descriptionMax,
1528
+ " \u4E2A\u5B57\u7B26\u3002"
1529
+ ] })
1530
+ ] })
1531
+ ] }),
1532
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "group", children: [
1533
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { children: "\u4E13\u4E1A\u89D2\u8272" }),
1534
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `field ${roleInvalid ? "invalid" : ""}`, children: [
1535
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { htmlFor: "ex-role", children: [
1536
+ "\u89D2\u8272\u8BF4\u660E ",
1537
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "counter", children: [
1538
+ form.role.length,
1539
+ "/",
1540
+ EXPERT_LIMITS.roleMax
1541
+ ] })
1542
+ ] }),
1543
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("textarea", { id: "ex-role", className: "prose", value: form.role, placeholder: "\u8FD9\u4E2A\u4E13\u5BB6\u662F\u8C01\u3001\u5177\u5907\u54EA\u4E9B\u4E13\u4E1A\u80CC\u666F\u4E0E\u5224\u65AD\u6807\u51C6\u3002\u53D1\u5E03\u540E\uFF0C\u8FD9\u6BB5\u6587\u5B57\u4F1A\u8FDB\u5165\u91C7\u7528\u5B83\u7684\u4F1A\u8BDD\u7684\u6A21\u578B\u4E0A\u4E0B\u6587\u3002", onChange: (event) => set("role", event.currentTarget.value) }),
1544
+ roleInvalid && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "field-error", children: [
1545
+ "\u89D2\u8272\u8BF4\u660E\u4E3A\u5FC5\u586B\uFF0C\u4E14\u4E0D\u8D85\u8FC7 ",
1546
+ EXPERT_LIMITS.roleMax,
1547
+ " \u4E2A\u5B57\u7B26\u3002"
1548
+ ] })
1549
+ ] })
1550
+ ] }),
1551
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "group", children: [
1552
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("h3", { children: [
1553
+ "\u9996\u9009\u6280\u80FD \xB7 ",
1554
+ form.skills.length
1555
+ ] }),
1556
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "hint", children: [
1557
+ "\u6700\u591A ",
1558
+ EXPERT_LIMITS.skillsMax,
1559
+ " \u4E2A\uFF0C\u53EA\u662F\u7ED9\u6A21\u578B\u7684\u63D0\u793A\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u8C03\u7528\u6216\u5B89\u88C5\u4EFB\u4F55\u6280\u80FD\u3002"
1560
+ ] }),
1561
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "list-editor", children: [
1562
+ form.skills.map((skill, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "equipped-row", children: [
1563
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: skill }),
1564
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1565
+ "button",
1566
+ {
1567
+ className: "remove",
1568
+ "aria-label": `\u5220\u9664\u6280\u80FD ${index + 1}`,
1569
+ onClick: () => set("skills", form.skills.filter((_, position) => position !== index)),
1570
+ children: "\u79FB\u9664"
1571
+ }
1572
+ )
1573
+ ] }, `${skill}-${index}`)),
1574
+ form.skills.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "hint", children: "\u5C1A\u672A\u914D\u5907\u6280\u80FD\u3002" }),
1575
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "list-row", children: [
1576
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { value: skillInput, "aria-label": "\u6DFB\u52A0\u9996\u9009\u6280\u80FD", placeholder: "\u6280\u80FD\u540D", onChange: (event) => setSkillInput(event.currentTarget.value) }),
1577
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { disabled: skillInput.trim().length === 0 || form.skills.length >= EXPERT_LIMITS.skillsMax, onClick: addSkill, children: "+ \u6DFB\u52A0\u6280\u80FD" })
1578
+ ] })
1579
+ ] })
1580
+ ] })
1581
+ ] }),
1582
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "editor-foot", children: [
1583
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "saved-at", children: dirty ? "\u6709\u672A\u4FDD\u5B58\u7684\u4FEE\u6539" : savedAt !== void 0 ? "\u5168\u90E8\u5DF2\u4FDD\u5B58" : "\u5C1A\u672A\u4FEE\u6539" }),
1584
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: onClose, disabled: saving, children: "\u53D6\u6D88" }),
1585
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: () => void save(form, detail?.draft?.revision ?? ""), disabled: saving || !dirty || noDraft, children: saving ? "\u6B63\u5728\u4FDD\u5B58\u2026" : "\u4FDD\u5B58\u8349\u7A3F" }),
1586
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "primary", onClick: () => void onPublish(), disabled: saving || nameInvalid || roleInvalid || noDraft, children: saving ? "\u6B63\u5728\u5904\u7406\u2026" : "\u53D1\u5E03" })
1587
+ ] })
1588
+ ] });
1589
+ }
1590
+
1591
+ // packages/experts/src/team.tsx
1592
+ var import_react5 = require("react");
1593
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1594
+ var RESPONSIBILITY_MAX = 6e4;
1595
+ function identity(member) {
1596
+ return { name: member.name, profession: member.description };
1597
+ }
1598
+ function rosterOf(team) {
1599
+ return team.members;
1600
+ }
1601
+ function TeamOverview({ team, roles }) {
1602
+ const members = rosterOf(team);
1603
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { "aria-label": "\u56E2\u961F\u6210\u5458\u4E0E\u534F\u4F5C", children: [
1604
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { className: "detail-section-title", children: "\u56E2\u961F\u6210\u5458" }),
1605
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "team-member-grid", children: members.map((member) => {
1606
+ const person = identity(member);
1607
+ const responsibility = roles[member.expertId] ?? "";
1608
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("details", { className: "team-person", children: [
1609
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("summary", { children: [
1610
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "member-avatar", "aria-hidden": true, children: person.name.trim().charAt(0) || "\u4E13" }),
1611
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "member-identity", children: [
1612
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("strong", { children: [
1613
+ person.profession || person.name,
1614
+ member.lead && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "member-lead", children: "\u4E3B\u7406\u4EBA" })
1615
+ ] }),
1616
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: person.profession ? person.name : member.lead ? "\u7EDF\u7B79\u9700\u6C42\u4E0E\u6574\u5408\u4EA4\u4ED8" : "\u56E2\u961F\u6210\u5458" })
1617
+ ] })
1618
+ ] }),
1619
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: member.description || "\uFF08\u6682\u65E0\u7B80\u4ECB\uFF09" }),
1620
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "member-responsibility", children: responsibility.slice(0, RESPONSIBILITY_MAX) || "\uFF08\u6682\u65E0\u89D2\u8272\u8BF4\u660E\uFF09" })
1621
+ ] }, member.key);
1622
+ }) })
1623
+ ] });
1624
+ }
1625
+ function TeamContent({ team, roles, skills, onChange }) {
1626
+ if (!team) return null;
1627
+ const fields = { role: "\u4E13\u4E1A\u804C\u8D23" };
1628
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "team-content", "aria-label": "\u4E13\u5BB6\u56E2\u5185\u5BB9", children: [
1629
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("h3", { children: [
1630
+ "\u56E2\u961F\u6210\u5458 \xB7 ",
1631
+ team.members.length
1632
+ ] }),
1633
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: "\u4E3B\u7406\u4EBA\u8D1F\u8D23\u7406\u89E3\u9700\u6C42\u4E0E\u6574\u5408\u4EA4\u4ED8\uFF1B\u4EE5\u4E0B\u6210\u5458\u627F\u62C5\u72EC\u7ACB\u4E13\u4E1A\u5DE5\u4F5C\u3002\u6574\u5957\u5185\u5BB9\u7EDF\u4E00\u4FDD\u5B58\u3001\u53D1\u5E03\u3002" }),
1634
+ team.members.map((member) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("details", { className: "preview-settings", children: [
1635
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("summary", { children: [
1636
+ member.name || "\uFF08\u5DF2\u5220\u9664\u7684\u4E13\u5BB6\uFF09",
1637
+ " \xB7 ",
1638
+ member.description
1639
+ ] }),
1640
+ Object.entries(fields).map(([key, title]) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "prose-block", children: [
1641
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h4", { children: title }),
1642
+ onChange ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1643
+ "textarea",
1644
+ {
1645
+ "aria-label": `${member.name} ${title}`,
1646
+ className: "prose",
1647
+ style: { width: "100%", minHeight: 120 },
1648
+ value: roles[member.expertId] ?? "",
1649
+ onChange: (event) => onChange(member.expertId, event.currentTarget.value)
1650
+ }
1651
+ ) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: { whiteSpace: "pre-wrap" }, children: roles[member.expertId] ?? "" })
1652
+ ] }, key)),
1653
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { children: [
1654
+ "\u914D\u5907\u6280\u80FD\uFF1A",
1655
+ (skills[member.expertId] ?? []).join("\u3001") || "\u672A\u5355\u72EC\u914D\u5907"
1656
+ ] })
1657
+ ] }, member.key))
1658
+ ] });
1659
+ }
1660
+ function TeamCard({
1661
+ row,
1662
+ busy,
1663
+ menuOpen,
1664
+ mine,
1665
+ onOpenMenu,
1666
+ onCloseMenu,
1667
+ onOpen,
1668
+ onEdit,
1669
+ onRemove
1670
+ }) {
1671
+ const lead = row.members.find((member) => member.lead);
1672
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("article", { className: `card ${menuOpen ? "menu-open" : ""}`, children: [
1673
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "card-top", children: [
1674
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { className: "card-open", "aria-label": `\u67E5\u770B\u4E13\u5BB6\u56E2 ${row.name}`, onClick: onOpen, children: [
1675
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "avatar", "aria-hidden": true, children: row.name.trim().charAt(0) || "\u56E2" }),
1676
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "card-title", children: [
1677
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { title: row.name, children: row.name }),
1678
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "card-meta", children: [
1679
+ row.description.split(/[\n。]/u)[0]?.trim() || "\u4E13\u5BB6\u56E2",
1680
+ mine && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
1681
+ " \xB7 ",
1682
+ row.members.length,
1683
+ " \u4F4D\u6210\u5458"
1684
+ ] })
1685
+ ] })
1686
+ ] })
1687
+ ] }),
1688
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "card-actions", children: [
1689
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1690
+ "button",
1691
+ {
1692
+ className: "more-button",
1693
+ "aria-label": `\u7BA1\u7406\u4E13\u5BB6\u56E2 ${row.name}`,
1694
+ "aria-haspopup": "menu",
1695
+ "aria-expanded": menuOpen,
1696
+ onClick: () => {
1697
+ if (menuOpen) onCloseMenu();
1698
+ else onOpenMenu();
1699
+ },
1700
+ children: "\u2022\u2022\u2022"
1701
+ }
1702
+ ),
1703
+ menuOpen && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "card-menu", role: "menu", children: [
1704
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { role: "menuitem", onClick: onEdit, children: "\u7F16\u8F91" }),
1705
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "danger", role: "menuitem", disabled: busy, onClick: onRemove, children: "\u5220\u9664" })
1706
+ ] })
1707
+ ] })
1708
+ ] }),
1709
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "desc", children: row.description || /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "muted", children: "\uFF08\u6682\u65E0\u7B80\u4ECB\uFF09" }) }),
1710
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "domain-tags", children: row.members.slice(0, 3).map((member) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: member.name || member.key }, member.key)) }),
1711
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "card-foot", children: [
1712
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "badge", children: "\u4E13\u5BB6\u56E2" }),
1713
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "badge", children: [
1714
+ row.members.length,
1715
+ " \u4F4D\u6210\u5458"
1716
+ ] }),
1717
+ lead === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "badge", children: "\u672A\u6307\u5B9A\u4E3B\u7406\u4EBA" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "badge ready", children: [
1718
+ "\u4E3B\u7406\u4EBA ",
1719
+ lead.name || lead.key
1720
+ ] })
1721
+ ] })
1722
+ ] });
1723
+ }
1724
+ function fromTeam(team) {
1725
+ if (team === void 0) return { name: "", description: "", mandate: "", members: [] };
1726
+ return {
1727
+ name: team.name,
1728
+ description: team.description,
1729
+ mandate: team.mandate,
1730
+ members: team.members.map((member) => ({ key: member.key, expertId: member.expertId, lead: member.lead }))
1731
+ };
1732
+ }
1733
+ function TeamFields({
1734
+ form,
1735
+ experts: experts2,
1736
+ set
1737
+ }) {
1738
+ const [pick, setPick] = (0, import_react5.useState)("");
1739
+ const nameInvalid = form.name.trim().length === 0 || form.name.length > TEAM_LIMITS.nameMax;
1740
+ const descInvalid = form.description.length > TEAM_LIMITS.descriptionMax;
1741
+ const mandateInvalid = form.mandate.length > TEAM_LIMITS.mandateMax;
1742
+ const rosterInvalid = form.members.length < TEAM_LIMITS.membersMin || form.members.length > TEAM_LIMITS.membersMax;
1743
+ const chosen = new Set(form.members.map((member) => member.expertId));
1744
+ const add = () => {
1745
+ if (pick.length === 0 || chosen.has(pick)) return;
1746
+ const expert = experts2.find((row) => row.id === pick);
1747
+ const members = [...form.members, {
1748
+ key: memberKeyFor(expert?.name ?? "member", form.members.map((member) => member.key)),
1749
+ expertId: pick,
1750
+ // Upstream's roster always has exactly one lead; the first pick becomes it.
1751
+ lead: form.members.length === 0
1752
+ }];
1753
+ set("members", members);
1754
+ setPick("");
1755
+ };
1756
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1757
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "group", children: [
1758
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { children: "\u57FA\u672C\u4FE1\u606F" }),
1759
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `field ${nameInvalid ? "invalid" : ""}`, children: [
1760
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { htmlFor: "tm-name", children: [
1761
+ "\u540D\u79F0 ",
1762
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "counter", children: [
1763
+ form.name.length,
1764
+ "/",
1765
+ TEAM_LIMITS.nameMax
1766
+ ] })
1767
+ ] }),
1768
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { id: "tm-name", value: form.name, placeholder: "\u4F8B\u5982\uFF1A\u5408\u540C\u5BA1\u67E5\u4E13\u5BB6\u56E2", onChange: (event) => set("name", event.currentTarget.value) }),
1769
+ nameInvalid && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "field-error", children: [
1770
+ "\u540D\u79F0\u4E3A\u5FC5\u586B\uFF0C\u4E14\u4E0D\u8D85\u8FC7 ",
1771
+ TEAM_LIMITS.nameMax,
1772
+ " \u4E2A\u5B57\u7B26\u3002"
1773
+ ] })
1774
+ ] }),
1775
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `field ${descInvalid ? "invalid" : ""}`, children: [
1776
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { htmlFor: "tm-desc", children: [
1777
+ "\u7B80\u4ECB ",
1778
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "counter", children: [
1779
+ form.description.length,
1780
+ "/",
1781
+ TEAM_LIMITS.descriptionMax
1782
+ ] })
1783
+ ] }),
1784
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("textarea", { id: "tm-desc", value: form.description, placeholder: "\u4E00\u53E5\u8BDD\u8BF4\u660E\u8FD9\u4E2A\u4E13\u5BB6\u56E2\u80FD\u5E2E\u4F60\u505A\u4EC0\u4E48", onChange: (event) => set("description", event.currentTarget.value) }),
1785
+ descInvalid && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "field-error", children: [
1786
+ "\u7B80\u4ECB\u4E0D\u8D85\u8FC7 ",
1787
+ TEAM_LIMITS.descriptionMax,
1788
+ " \u4E2A\u5B57\u7B26\u3002"
1789
+ ] })
1790
+ ] })
1791
+ ] }),
1792
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "group", children: [
1793
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { children: "\u4E3B\u7406\u4EBA\u804C\u8D23" }),
1794
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `field ${mandateInvalid ? "invalid" : ""}`, children: [
1795
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { htmlFor: "tm-mandate", children: [
1796
+ "\u89D2\u8272\u8BF4\u660E ",
1797
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "counter", children: [
1798
+ form.mandate.length,
1799
+ "/",
1800
+ TEAM_LIMITS.mandateMax
1801
+ ] })
1802
+ ] }),
1803
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("textarea", { id: "tm-mandate", className: "prose", value: form.mandate, placeholder: "\u4E3B\u7406\u4EBA\u662F\u8C01\u3001\u5982\u4F55\u7406\u89E3\u9700\u6C42\u4E0E\u6574\u5408\u4EA4\u4ED8\u3002", onChange: (event) => set("mandate", event.currentTarget.value) })
1804
+ ] })
1805
+ ] }),
1806
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "group", children: [
1807
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("h3", { children: [
1808
+ "\u56E2\u961F\u6210\u5458 \xB7 ",
1809
+ form.members.length
1810
+ ] }),
1811
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "hint", children: [
1812
+ "\u9700\u8981 ",
1813
+ TEAM_LIMITS.membersMin,
1814
+ " \u81F3 ",
1815
+ TEAM_LIMITS.membersMax,
1816
+ " \u4F4D\u6210\u5458\uFF0C\u53EA\u80FD\u4ECE\u5DF2\u6709\u4E13\u5BB6\u91CC\u9009\uFF1B\u540D\u518C\u6309\u987A\u5E8F\u4FDD\u5B58\u3002"
1817
+ ] }),
1818
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "list-editor", children: [
1819
+ form.members.map((member, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "equipped-row", children: [
1820
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: experts2.find((row) => row.id === member.expertId)?.name ?? member.expertId }),
1821
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "muted", children: [
1822
+ member.key,
1823
+ member.lead ? " \xB7 \u4E3B\u7406\u4EBA" : ""
1824
+ ] }),
1825
+ !member.lead && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1826
+ "button",
1827
+ {
1828
+ className: "remove",
1829
+ "aria-label": `\u8BBE\u4E3A\u4E3B\u7406\u4EBA ${member.key}`,
1830
+ onClick: () => set("members", form.members.map((item, position) => ({ ...item, lead: position === index }))),
1831
+ children: "\u8BBE\u4E3A\u4E3B\u7406\u4EBA"
1832
+ }
1833
+ ),
1834
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1835
+ "button",
1836
+ {
1837
+ className: "remove",
1838
+ "aria-label": `\u79FB\u9664\u6210\u5458 ${member.key}`,
1839
+ onClick: () => {
1840
+ const members = form.members.filter((_, position) => position !== index);
1841
+ set("members", members.some((item) => item.lead) ? members : members.map((item, position) => ({ ...item, lead: position === 0 })));
1842
+ },
1843
+ children: "\u79FB\u9664"
1844
+ }
1845
+ )
1846
+ ] }, `${member.key}-${index}`)),
1847
+ form.members.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "hint", children: "\u5C1A\u672A\u9009\u62E9\u6210\u5458\u3002" }),
1848
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "list-row", children: [
1849
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("select", { value: pick, "aria-label": "\u9009\u62E9\u6210\u5458\u4E13\u5BB6", onChange: (event) => setPick(event.currentTarget.value), children: [
1850
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "", children: "\u9009\u62E9\u4E00\u4F4D\u4E13\u5BB6\u2026" }),
1851
+ experts2.filter((row) => !chosen.has(row.id)).map((row) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: row.id, children: row.name }, row.id))
1852
+ ] }),
1853
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { disabled: pick.length === 0 || form.members.length >= TEAM_LIMITS.membersMax, onClick: add, children: "+ \u6DFB\u52A0\u6210\u5458" })
1854
+ ] }),
1855
+ rosterInvalid && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "field-error", children: [
1856
+ "\u6210\u5458\u9700\u8981 ",
1857
+ TEAM_LIMITS.membersMin,
1858
+ " \u81F3 ",
1859
+ TEAM_LIMITS.membersMax,
1860
+ " \u4F4D\u3002"
1861
+ ] }),
1862
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "hint", children: [
1863
+ "\u6210\u5458\u6807\u8BC6\u7531\u4E13\u5BB6\u540D\u751F\u6210\uFF08",
1864
+ MEMBER_KEY_PATTERN.source,
1865
+ "\uFF09\uFF0C\u7528\u4E8E\u533A\u5206\u540C\u56E2\u6210\u5458\u3002"
1866
+ ] })
1867
+ ] })
1868
+ ] })
1869
+ ] });
1870
+ }
1871
+ function formReady(form) {
1872
+ return form.name.trim().length > 0 && form.name.length <= TEAM_LIMITS.nameMax && form.description.length <= TEAM_LIMITS.descriptionMax && form.mandate.length <= TEAM_LIMITS.mandateMax && form.members.length >= TEAM_LIMITS.membersMin && form.members.length <= TEAM_LIMITS.membersMax;
1873
+ }
1874
+ function CreateTeamDialog({
1875
+ busy,
1876
+ experts: experts2,
1877
+ onClose,
1878
+ onCreate
1879
+ }) {
1880
+ const [form, setForm] = (0, import_react5.useState)(() => fromTeam());
1881
+ const set = (key, value) => setForm((prev) => ({ ...prev, [key]: value }));
1882
+ const ready = formReady(form) && !busy;
1883
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Modal, { open: true, title: "\u65B0\u5EFA\u4E13\u5BB6\u56E2", className: "wd-dialog editor-dialog", onClose, children: [
1884
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "wd-dialog-close", "aria-label": "\u5173\u95ED", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {}) }),
1885
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "editor-head", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { children: "\u65B0\u5EFA\u4E13\u5BB6\u56E2" }) }),
1886
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "editor-scroll", children: [
1887
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "notice", role: "status", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "notice-body", children: [
1888
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "\u4E13\u5BB6\u56E2\u7531\u5DF2\u6709\u4E13\u5BB6\u7EC4\u6210" }),
1889
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "\u6210\u5458\u5FC5\u987B\u662F\u672C\u673A\u5DF2\u6709\u7684\u4E13\u5BB6\uFF1B\u4E3B\u7406\u4EBA\u8D1F\u8D23\u7406\u89E3\u9700\u6C42\u4E0E\u6574\u5408\u4EA4\u4ED8\uFF0C\u5176\u4F59\u6210\u5458\u627F\u62C5\u72EC\u7ACB\u4E13\u4E1A\u5DE5\u4F5C\u3002\u4FDD\u5B58\u540E\u56E2\u961F\u7ACB\u5373\u53EF\u7528\u3002" })
1890
+ ] }) }),
1891
+ experts2.length < TEAM_LIMITS.membersMin && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "notice warn", role: "status", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "notice-body", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
1892
+ "\u81F3\u5C11\u9700\u8981 ",
1893
+ TEAM_LIMITS.membersMin,
1894
+ " \u4F4D\u4E13\u5BB6\u624D\u80FD\u7EC4\u6210\u4E13\u5BB6\u56E2\u3002\u5148\u5236\u4F5C\u4E13\u5BB6\uFF0C\u518D\u56DE\u6765\u521B\u5EFA\u3002"
1895
+ ] }) }) }),
1896
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TeamFields, { form, experts: experts2, set })
1897
+ ] }),
1898
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "editor-foot", children: [
1899
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "saved-at", children: [
1900
+ "\u540D\u79F0\u4E0E ",
1901
+ TEAM_LIMITS.membersMin,
1902
+ "\u2013",
1903
+ TEAM_LIMITS.membersMax,
1904
+ " \u4F4D\u6210\u5458\u4E3A\u5FC5\u586B"
1905
+ ] }),
1906
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { onClick: onClose, disabled: busy, children: "\u53D6\u6D88" }),
1907
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "primary", disabled: !ready, onClick: () => onCreate({
1908
+ name: form.name.trim(),
1909
+ description: form.description.trim(),
1910
+ mandate: form.mandate.trim(),
1911
+ members: form.members
1912
+ }), children: busy ? "\u6B63\u5728\u521B\u5EFA\u2026" : "\u521B\u5EFA\u4E13\u5BB6\u56E2" })
1913
+ ] })
1914
+ ] });
1915
+ }
1916
+ function EditTeamDialog({
1917
+ team,
1918
+ busy,
1919
+ experts: experts2,
1920
+ management,
1921
+ onClose,
1922
+ onSaved
1923
+ }) {
1924
+ const [form, setForm] = (0, import_react5.useState)(() => fromTeam(team));
1925
+ const [revision, setRevision] = (0, import_react5.useState)(team.revision);
1926
+ const [saving, setSaving] = (0, import_react5.useState)(false);
1927
+ const [error, setError] = (0, import_react5.useState)("");
1928
+ const set = (key, value) => setForm((prev) => ({ ...prev, [key]: value }));
1929
+ const ready = formReady(form) && !saving && !busy;
1930
+ const save = async () => {
1931
+ setSaving(true);
1932
+ setError("");
1933
+ try {
1934
+ const next = await management.updateTeam(team.id, {
1935
+ name: form.name.trim(),
1936
+ description: form.description.trim(),
1937
+ mandate: form.mandate.trim(),
1938
+ members: form.members
1939
+ }, revision);
1940
+ setRevision(next.revision);
1941
+ onSaved();
1942
+ } catch (cause) {
1943
+ setError(reasonOf(cause));
1944
+ } finally {
1945
+ setSaving(false);
1946
+ }
1947
+ };
1948
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Modal, { open: true, title: "\u7F16\u8F91\u4E13\u5BB6\u56E2", className: "wd-dialog editor-dialog", onClose, children: [
1949
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "wd-dialog-close", "aria-label": "\u5173\u95ED", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {}) }),
1950
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "editor-head", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { children: form.name.trim() || "\u7F16\u8F91\u4E13\u5BB6\u56E2" }) }),
1951
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "editor-scroll", children: [
1952
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "notice", role: "info", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "notice-body", children: [
1953
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "\u6B63\u5728\u7F16\u8F91\u4E13\u5BB6\u56E2" }),
1954
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "\u6210\u5458\u5F15\u7528\u7684\u662F\u4E13\u5BB6\u672C\u8EAB\uFF0C\u4E0D\u590D\u5236\u5185\u5BB9\uFF1B\u4EE5\u540E\u7F16\u8F91\u67D0\u4F4D\u4E13\u5BB6\uFF0C\u8FD9\u91CC\u770B\u5230\u7684\u5C31\u662F\u6700\u65B0\u5185\u5BB9\u3002" })
1955
+ ] }) }),
1956
+ error.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "issues", role: "alert", children: [
1957
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h4", { children: "\u65E0\u6CD5\u5B8C\u6210\u64CD\u4F5C" }),
1958
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("li", { children: error }) })
1959
+ ] }),
1960
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TeamFields, { form, experts: experts2, set })
1961
+ ] }),
1962
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "editor-foot", children: [
1963
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "saved-at", children: [
1964
+ "\u4FEE\u8BA2 ",
1965
+ revision.slice(0, 12),
1966
+ "\u2026"
1967
+ ] }),
1968
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { onClick: onClose, disabled: saving, children: "\u53D6\u6D88" }),
1969
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "primary", disabled: !ready, onClick: () => void save(), children: saving ? "\u6B63\u5728\u4FDD\u5B58\u2026" : "\u4FDD\u5B58\u4E13\u5BB6\u56E2" })
1970
+ ] })
1971
+ ] });
1972
+ }
1973
+ function DeleteTeamDialog({
1974
+ name: name2,
1975
+ busy,
1976
+ onClose,
1977
+ onConfirm
1978
+ }) {
1979
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Modal, { open: true, title: "\u5220\u9664\u4E13\u5BB6\u56E2", className: "wd-dialog confirm-dialog", onClose, children: [
1980
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "wd-dialog-close", "aria-label": "\u5173\u95ED", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseIcon, {}) }),
1981
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("h2", { children: [
1982
+ "\u5220\u9664\u300C",
1983
+ name2,
1984
+ "\u300D\uFF1F"
1985
+ ] }),
1986
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: "\u53EA\u5220\u9664\u8FD9\u4E2A\u4E13\u5BB6\u56E2\u672C\u8EAB\uFF1B\u5B83\u5217\u51FA\u7684\u4E13\u5BB6\u4E0D\u4F1A\u88AB\u5220\u9664\uFF0C\u5176\u4ED6\u4E13\u5BB6\u56E2\u4E5F\u4E0D\u53D7\u5F71\u54CD\u3002" }),
1987
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "confirm-actions", children: [
1988
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { onClick: onClose, disabled: busy, children: "\u53D6\u6D88" }),
1989
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "danger solid", onClick: onConfirm, disabled: busy, children: busy ? "\u6B63\u5728\u5220\u9664\u2026" : "\u5220\u9664" })
1990
+ ] })
1991
+ ] });
1992
+ }
1993
+ function TeamDetailModal({
1994
+ teamId,
1995
+ management,
1996
+ acting,
1997
+ onClose,
1998
+ onChanged,
1999
+ onEdit,
2000
+ onRemove
2001
+ }) {
2002
+ const [team, setTeam] = (0, import_react5.useState)();
2003
+ const [roles, setRoles] = (0, import_react5.useState)({});
2004
+ const [memberSkills, setMemberSkills] = (0, import_react5.useState)({});
2005
+ const [phase, setPhase] = (0, import_react5.useState)("loading");
2006
+ const [error, setError] = (0, import_react5.useState)("");
2007
+ const load = (0, import_react5.useCallback)(async () => {
2008
+ setPhase("loading");
2009
+ setError("");
2010
+ try {
2011
+ const next = await management.getTeam(teamId);
2012
+ setTeam(next);
2013
+ setPhase("ready");
2014
+ const found = {};
2015
+ const foundSkills = {};
2016
+ await Promise.all(next.members.map(async (member) => {
2017
+ if (member.missing) return;
2018
+ try {
2019
+ const detail = await management.get(member.expertId);
2020
+ found[member.expertId] = detail.draft?.role ?? "";
2021
+ foundSkills[member.expertId] = detail.draft?.preferredSkills ?? [];
2022
+ } catch {
2023
+ }
2024
+ }));
2025
+ setRoles(found);
2026
+ setMemberSkills(foundSkills);
2027
+ } catch (cause) {
2028
+ setError(reasonOf(cause));
2029
+ setPhase("error");
2030
+ }
2031
+ }, [teamId, management]);
2032
+ (0, import_react5.useEffect)(() => {
2033
+ void load();
2034
+ }, [load]);
2035
+ if (phase === "loading") return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dialog-scroll", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "muted", children: "\u6B63\u5728\u8BFB\u53D6\u4E13\u5BB6\u56E2\u2026" }) });
2036
+ if (phase === "error" || team === void 0) {
2037
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dialog-scroll", children: [
2038
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "error-text", role: "alert", children: error || "\u65E0\u6CD5\u8BFB\u53D6\u4E13\u5BB6\u56E2\u3002" }),
2039
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "detail-head-actions", style: { marginTop: 16 }, children: [
2040
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { onClick: () => void load(), children: "\u91CD\u8BD5" }),
2041
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { onClick: onClose, children: "\u5173\u95ED" })
2042
+ ] })
2043
+ ] });
2044
+ }
2045
+ const lead = team.members.find((member) => member.lead);
2046
+ const leadUnpublished = team.members.some((member) => member.lead && !member.published);
2047
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dialog-scroll", children: [
2048
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("header", { className: "detail-header", children: [
2049
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "detail-avatar", "aria-hidden": true, children: team.name.trim().charAt(0) || "\u56E2" }),
2050
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "detail-title", children: [
2051
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { children: team.name || "\uFF08\u672A\u547D\u540D\u4E13\u5BB6\u56E2\uFF09" }),
2052
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "detail-subtitle", children: [
2053
+ "\u4E13\u5BB6\u56E2 \xB7 ",
2054
+ team.members.length,
2055
+ " \u4F4D\u6210\u5458",
2056
+ lead === void 0 ? " \xB7 \u672A\u6307\u5B9A\u4E3B\u7406\u4EBA" : ` \xB7 \u4E3B\u7406\u4EBA ${lead.name || lead.key}`
2057
+ ] }),
2058
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "detail-head-actions", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "summon", disabled: acting, onClick: () => {
2059
+ onChanged();
2060
+ onEdit(teamId);
2061
+ }, children: "\u7F16\u8F91\u4E13\u5BB6\u56E2" }) })
2062
+ ] })
2063
+ ] }),
2064
+ team.description.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "detail-desc", style: { marginTop: 20 }, children: team.description }),
2065
+ leadUnpublished && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "notice warn", role: "status", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "notice-body", children: [
2066
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "\u4E3B\u7406\u4EBA\u8FD8\u6CA1\u6709\u53D1\u5E03\u4FEE\u8BA2" }),
2067
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "\u8FD9\u91CC\u5F15\u7528\u7684\u662F\u4E13\u5BB6\u672C\u8EAB\uFF0C\u672A\u53D1\u5E03\u7684\u6210\u5458\u4ECD\u7136\u4F1A\u88AB\u5217\u51FA\u3002\u8981\u8BA9\u6574\u4E2A\u4E13\u5BB6\u56E2\u90FD\u6307\u5411\u53EF\u7528\u7684\u89D2\u8272\uFF0C\u5148\u4E3A\u8FD9\u4E9B\u6210\u5458\u53D1\u5E03\u4FEE\u8BA2\u3002" })
2068
+ ] }) }),
2069
+ team.mandate.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("details", { className: "expert-settings", open: true, children: [
2070
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("summary", { children: "\u4E3B\u7406\u4EBA\u804C\u8D23" }),
2071
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "prose-block", children: team.mandate })
2072
+ ] }),
2073
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TeamOverview, { team, roles }),
2074
+ team.members.some((member) => member.missing) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "notice warn", role: "status", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "notice-body", children: [
2075
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "\u6709\u6210\u5458\u5DF2\u88AB\u5220\u9664" }),
2076
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "\u88AB\u5F15\u7528\u7684\u4E13\u5BB6\u4E0D\u5728\u4E86\u3002\u7F16\u8F91\u8FD9\u4E2A\u4E13\u5BB6\u56E2\u5E76\u66FF\u6362\u8BE5\u6210\u5458\uFF0C\u6216\u5220\u9664\u5B83\u3002" })
2077
+ ] }) }),
2078
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("details", { className: "expert-settings", children: [
2079
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("summary", { children: "\u56E2\u961F\u5185\u5BB9" }),
2080
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TeamContent, { team, roles, skills: memberSkills })
2081
+ ] }),
2082
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "detail-head-actions", style: { marginTop: 28, justifyContent: "flex-end" }, children: [
2083
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { disabled: acting, onClick: () => onRemove(team), children: "\u5220\u9664" }),
2084
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { onClick: onClose, children: "\u5173\u95ED" }),
2085
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { onClick: () => void load(), disabled: acting, children: "\u5237\u65B0" })
2086
+ ] })
2087
+ ] });
2088
+ }
2089
+
2090
+ // packages/experts/src/panel.tsx
2091
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2092
+ var CAPABILITY_TABS = [["experts", "\u4E13\u5BB6"], ["skills", "\u6280\u80FD"], ["connectors", "\u8FDE\u63A5\u5668"]];
2093
+ var CAPABILITY_KEY = {
2094
+ experts: "dsh-plugin-experts",
2095
+ skills: "dsh-plugin-skills",
2096
+ connectors: "dsh-plugin-connectors"
2097
+ };
2098
+ var ORIGIN_FILTERS = [["all", "\u5168\u90E8"], ["default", "\u9ED8\u8BA4"], ["personal", "\u6211\u7684"]];
2099
+ var STATE_FILTERS = [["all", "\u5168\u90E8"], ["draft", "\u8349\u7A3F"], ["published", "\u5DF2\u53D1\u5E03"]];
2100
+ function useCurrentSessionId() {
2101
+ const [value, setValue] = (0, import_react6.useState)(getCurrentSessionId);
2102
+ (0, import_react6.useEffect)(() => subscribeCurrentSession(() => setValue(getCurrentSessionId())), []);
2103
+ return value;
2104
+ }
2105
+ function Avatar({ summary }) {
2106
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "avatar", "aria-hidden": true, children: summary.name.trim().charAt(0) || "\u4E13" });
2107
+ }
2108
+ function metaLine(summary) {
2109
+ const first = summary.description.split(/[\n。]/u)[0]?.trim() ?? "";
2110
+ return first.length > 0 ? first : "\u4E13\u5BB6";
2111
+ }
2112
+ function stateLabel(summary) {
2113
+ return summary.published ? "\u5DF2\u53D1\u5E03" : "\u8349\u7A3F";
2114
+ }
2115
+ function CreateExpertDialog({
2116
+ busy,
2117
+ onClose,
2118
+ onCreate
2119
+ }) {
2120
+ const [name2, setName] = (0, import_react6.useState)("");
2121
+ const [description, setDescription] = (0, import_react6.useState)("");
2122
+ const [role, setRole] = (0, import_react6.useState)("");
2123
+ const [skills, setSkills] = (0, import_react6.useState)("");
2124
+ const nameInvalid = name2.trim().length === 0 || name2.length > EXPERT_LIMITS.nameMax;
2125
+ const descInvalid = description.length > EXPERT_LIMITS.descriptionMax;
2126
+ const roleInvalid = role.trim().length === 0 || role.length > EXPERT_LIMITS.roleMax;
2127
+ const skillCount = skills.split(/[\n,,、]/u).map((part) => part.trim()).filter((part) => part.length > 0).length;
2128
+ const ready = !nameInvalid && !descInvalid && !roleInvalid && skillCount <= EXPERT_LIMITS.skillsMax;
2129
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Modal, { open: true, title: "\u65B0\u5EFA\u4E13\u5BB6", className: "wd-dialog editor-dialog", onClose, children: [
2130
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "wd-dialog-close", "aria-label": "\u5173\u95ED", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CloseIcon, {}) }),
2131
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "editor-head", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { children: "\u65B0\u5EFA\u4E13\u5BB6" }) }),
2132
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "editor-scroll", children: [
2133
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "notice", role: "status", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "notice-body", children: [
2134
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { children: "\u521B\u5EFA\u540E\u5148\u5F97\u5230\u4E00\u4EFD\u8349\u7A3F" }),
2135
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "\u8349\u7A3F\u53EA\u4FDD\u5B58\u5728\u672C\u673A\uFF1B\u70B9\u300C\u53D1\u5E03\u300D\u624D\u4F1A\u51BB\u7ED3\u6210\u4E0D\u53EF\u53D8\u4FEE\u8BA2\uFF0C\u4E4B\u540E\u624D\u80FD\u88AB\u67D0\u4E2A\u4F1A\u8BDD\u91C7\u7528\u3002" })
2136
+ ] }) }),
2137
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "group", children: [
2138
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: "\u57FA\u672C\u4FE1\u606F" }),
2139
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `field ${nameInvalid ? "invalid" : ""}`, children: [
2140
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { htmlFor: "ex-new-name", children: [
2141
+ "\u540D\u79F0 ",
2142
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "counter", children: [
2143
+ name2.length,
2144
+ "/",
2145
+ EXPERT_LIMITS.nameMax
2146
+ ] })
2147
+ ] }),
2148
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { id: "ex-new-name", value: name2, placeholder: "\u4F8B\u5982\uFF1A\u5408\u540C\u5BA1\u67E5\u4E13\u5BB6", onChange: (event) => setName(event.currentTarget.value) }),
2149
+ nameInvalid && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { className: "field-error", children: [
2150
+ "\u540D\u79F0\u4E3A\u5FC5\u586B\uFF0C\u4E14\u4E0D\u8D85\u8FC7 ",
2151
+ EXPERT_LIMITS.nameMax,
2152
+ " \u4E2A\u5B57\u7B26\u3002"
2153
+ ] })
2154
+ ] }),
2155
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `field ${descInvalid ? "invalid" : ""}`, children: [
2156
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { htmlFor: "ex-new-desc", children: [
2157
+ "\u7B80\u4ECB ",
2158
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "counter", children: [
2159
+ description.length,
2160
+ "/",
2161
+ EXPERT_LIMITS.descriptionMax
2162
+ ] })
2163
+ ] }),
2164
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("textarea", { id: "ex-new-desc", value: description, placeholder: "\u4E00\u53E5\u8BDD\u8BF4\u660E\u8FD9\u4E2A\u4E13\u5BB6\u80FD\u5E2E\u4F60\u505A\u4EC0\u4E48", onChange: (event) => setDescription(event.currentTarget.value) }),
2165
+ descInvalid && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { className: "field-error", children: [
2166
+ "\u7B80\u4ECB\u4E0D\u8D85\u8FC7 ",
2167
+ EXPERT_LIMITS.descriptionMax,
2168
+ " \u4E2A\u5B57\u7B26\u3002"
2169
+ ] })
2170
+ ] })
2171
+ ] }),
2172
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "group", children: [
2173
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: "\u4E13\u4E1A\u89D2\u8272" }),
2174
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `field ${roleInvalid ? "invalid" : ""}`, children: [
2175
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { htmlFor: "ex-new-role", children: [
2176
+ "\u89D2\u8272\u8BF4\u660E ",
2177
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "counter", children: [
2178
+ role.length,
2179
+ "/",
2180
+ EXPERT_LIMITS.roleMax
2181
+ ] })
2182
+ ] }),
2183
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("textarea", { id: "ex-new-role", className: "prose", value: role, placeholder: "\u8FD9\u4E2A\u4E13\u5BB6\u662F\u8C01\u3001\u5177\u5907\u54EA\u4E9B\u4E13\u4E1A\u80CC\u666F\u4E0E\u5224\u65AD\u6807\u51C6\u3002\u8FD9\u6BB5\u6587\u5B57\u4F1A\u8FDB\u5165\u91C7\u7528\u5B83\u7684\u4F1A\u8BDD\u7684\u6A21\u578B\u4E0A\u4E0B\u6587\u3002", onChange: (event) => setRole(event.currentTarget.value) }),
2184
+ roleInvalid && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { className: "field-error", children: [
2185
+ "\u89D2\u8272\u8BF4\u660E\u4E3A\u5FC5\u586B\uFF0C\u4E14\u4E0D\u8D85\u8FC7 ",
2186
+ EXPERT_LIMITS.roleMax,
2187
+ " \u4E2A\u5B57\u7B26\u3002"
2188
+ ] })
2189
+ ] })
2190
+ ] }),
2191
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "group", children: [
2192
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: "\u9996\u9009\u6280\u80FD" }),
2193
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "field", children: [
2194
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { htmlFor: "ex-new-skills", children: [
2195
+ "\u6BCF\u884C\u4E00\u4E2A\uFF0C\u6700\u591A ",
2196
+ EXPERT_LIMITS.skillsMax,
2197
+ " \u4E2A"
2198
+ ] }),
2199
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("textarea", { id: "ex-new-skills", value: skills, placeholder: "\u6BCF\u884C\u4E00\u4E2A\u6280\u80FD\u540D", onChange: (event) => setSkills(event.currentTarget.value) }),
2200
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "hint", children: "\u53EA\u662F\u7ED9\u6A21\u578B\u7684\u63D0\u793A\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u8C03\u7528\u6216\u5B89\u88C5\u4EFB\u4F55\u6280\u80FD\u3002" })
2201
+ ] })
2202
+ ] })
2203
+ ] }),
2204
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "editor-foot", children: [
2205
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "saved-at", children: "\u540D\u79F0\u3001\u7B80\u4ECB\u4E0E\u89D2\u8272\u8BF4\u660E\u4E3A\u5FC5\u586B" }),
2206
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: onClose, disabled: busy, children: "\u53D6\u6D88" }),
2207
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { className: "primary", disabled: busy || !ready, onClick: () => onCreate({
2208
+ name: name2.trim(),
2209
+ description: description.trim(),
2210
+ role: role.trim(),
2211
+ preferredSkills: [...new Set(skills.split(/[\n,,、]/u).map((part) => part.trim()).filter((part) => part.length > 0))]
2212
+ }), children: busy ? "\u6B63\u5728\u521B\u5EFA\u2026" : "\u521B\u5EFA\u8349\u7A3F" })
2213
+ ] })
2214
+ ] });
2215
+ }
2216
+ function DeleteExpertDialog({
2217
+ name: name2,
2218
+ busy,
2219
+ onClose,
2220
+ onConfirm
2221
+ }) {
2222
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Modal, { open: true, title: "\u5220\u9664\u4E13\u5BB6", className: "wd-dialog confirm-dialog", onClose, children: [
2223
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "wd-dialog-close", "aria-label": "\u5173\u95ED", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CloseIcon, {}) }),
2224
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("h2", { children: [
2225
+ "\u5220\u9664\u300C",
2226
+ name2,
2227
+ "\u300D\uFF1F"
2228
+ ] }),
2229
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "\u5B83\u7684\u8349\u7A3F\u548C\u5168\u90E8\u53D1\u5E03\u4FEE\u8BA2\u90FD\u4F1A\u88AB\u79FB\u9664\uFF1B\u91C7\u7528\u8FC7\u5B83\u7684\u4F1A\u8BDD\u4F1A\u7ACB\u5373\u53D6\u6D88\u91C7\u7528\u3002" }),
2230
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "confirm-actions", children: [
2231
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: onClose, disabled: busy, children: "\u53D6\u6D88" }),
2232
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { className: "danger solid", onClick: onConfirm, disabled: busy, children: busy ? "\u6B63\u5728\u5220\u9664\u2026" : "\u5220\u9664" })
2233
+ ] })
2234
+ ] });
2235
+ }
2236
+ function ExpertCard({
2237
+ row,
2238
+ busy,
2239
+ menuOpen,
2240
+ mine,
2241
+ onOpenMenu,
2242
+ onCloseMenu,
2243
+ onOpen,
2244
+ onEdit,
2245
+ onCopy,
2246
+ onRemove
2247
+ }) {
2248
+ const draft = !row.published;
2249
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("article", { className: `card ${draft ? "draft" : ""} ${menuOpen ? "menu-open" : ""}`, children: [
2250
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "card-top", children: [
2251
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("button", { className: "card-open", "aria-label": `\u67E5\u770B\u4E13\u5BB6 ${row.name}`, onClick: onOpen, children: [
2252
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Avatar, { summary: row }),
2253
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "card-title", children: [
2254
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { title: row.name, children: row.name }),
2255
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "card-meta", children: [
2256
+ metaLine(row),
2257
+ mine && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
2258
+ " \xB7 ",
2259
+ stateLabel(row)
2260
+ ] })
2261
+ ] })
2262
+ ] })
2263
+ ] }),
2264
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "card-actions", children: [
2265
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2266
+ "button",
2267
+ {
2268
+ className: "more-button",
2269
+ "aria-label": `\u7BA1\u7406\u4E13\u5BB6 ${row.name}`,
2270
+ "aria-haspopup": "menu",
2271
+ "aria-expanded": menuOpen,
2272
+ onClick: () => {
2273
+ if (menuOpen) onCloseMenu();
2274
+ else onOpenMenu();
2275
+ },
2276
+ children: "\u2022\u2022\u2022"
2277
+ }
2278
+ ),
2279
+ menuOpen && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "card-menu", role: "menu", children: [
2280
+ draft ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { role: "menuitem", onClick: onEdit, children: "\u7EE7\u7EED\u7F16\u8F91" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { role: "menuitem", onClick: onEdit, children: "\u7F16\u8F91" }),
2281
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { role: "menuitem", disabled: busy, onClick: onCopy, children: "\u590D\u5236\u5230\u6211\u7684\u4E13\u5BB6" }),
2282
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { className: "danger", role: "menuitem", disabled: busy, onClick: onRemove, children: "\u5220\u9664" })
2283
+ ] })
2284
+ ] })
2285
+ ] }),
2286
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "desc", children: row.description || /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "muted", children: "\uFF08\u6682\u65E0\u7B80\u4ECB\uFF09" }) }),
2287
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "domain-tags", children: row.preferredSkills.slice(0, 3).map((skill) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: skill }, skill)) }),
2288
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "card-foot", children: [
2289
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "badge", children: "\u4E13\u5BB6" }),
2290
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: `badge ${draft ? "" : "ready"}`, children: draft ? "\u672A\u53D1\u5E03" : "\u53EF\u7528" }),
2291
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "badge", children: draft ? "\u8349\u7A3F" : `\u9ED8\u8BA4\u4FEE\u8BA2 ${row.revisionNumber}` })
2292
+ ] })
2293
+ ] });
2294
+ }
2295
+ function ExpertsPanel({
2296
+ management = experts,
2297
+ nav,
2298
+ toggleNavigation,
2299
+ createExpertTask: createExpertTask2,
2300
+ editExpertTask: editExpertTask2
2301
+ }) {
2302
+ const sessionId = useCurrentSessionId();
2303
+ const [view, setView] = (0, import_react6.useState)(() => new URLSearchParams(window.location.search).get("expert-library") === "mine" ? "mine" : "center");
2304
+ const [kind, setKind] = (0, import_react6.useState)(() => new URLSearchParams(window.location.search).get("expert-kind") === "team" ? "team" : "agent");
2305
+ const [filter, setFilter] = (0, import_react6.useState)("all");
2306
+ const [stateFilter, setStateFilter] = (0, import_react6.useState)("all");
2307
+ const [query, setQuery] = (0, import_react6.useState)("");
2308
+ const [debounced, setDebounced] = (0, import_react6.useState)("");
2309
+ const [rows, setRows] = (0, import_react6.useState)([]);
2310
+ const [teams, setTeams] = (0, import_react6.useState)([]);
2311
+ const [busy, setBusy] = (0, import_react6.useState)(true);
2312
+ const [acting, setActing] = (0, import_react6.useState)(false);
2313
+ const [error, setError] = (0, import_react6.useState)("");
2314
+ const [notice, setNotice] = (0, import_react6.useState)();
2315
+ const [actionMenu, setActionMenu] = (0, import_react6.useState)();
2316
+ const [detailId, setDetailId] = (0, import_react6.useState)();
2317
+ const [editorId, setEditorId] = (0, import_react6.useState)(() => new URLSearchParams(window.location.search).get("expert-draft") ?? void 0);
2318
+ const [createOpen, setCreateOpen] = (0, import_react6.useState)(false);
2319
+ const [deleteTarget, setDeleteTarget] = (0, import_react6.useState)();
2320
+ const [teamDetailId, setTeamDetailId] = (0, import_react6.useState)();
2321
+ const [teamEditor, setTeamEditor] = (0, import_react6.useState)();
2322
+ const [teamCreateOpen, setTeamCreateOpen] = (0, import_react6.useState)(false);
2323
+ const [teamDeleteTarget, setTeamDeleteTarget] = (0, import_react6.useState)();
2324
+ const search = (0, import_react6.useRef)(null);
2325
+ (0, import_react6.useEffect)(() => {
2326
+ const url = new URL(window.location.href);
2327
+ if (view === "mine") url.searchParams.set("expert-library", "mine");
2328
+ else url.searchParams.delete("expert-library");
2329
+ url.searchParams.set("expert-kind", kind);
2330
+ window.history.replaceState(window.history.state, "", url);
2331
+ }, [view, kind]);
2332
+ (0, import_react6.useEffect)(() => {
2333
+ const timer = window.setTimeout(() => setDebounced(query.trim()), 300);
2334
+ return () => window.clearTimeout(timer);
2335
+ }, [query]);
2336
+ const load = (0, import_react6.useCallback)(async () => {
2337
+ setBusy(true);
2338
+ setError("");
2339
+ try {
2340
+ const [nextExperts, nextTeams] = await Promise.all([
2341
+ management.list(debounced),
2342
+ management.listTeams(debounced)
2343
+ ]);
2344
+ setRows(nextExperts);
2345
+ setTeams(nextTeams);
2346
+ } catch (cause) {
2347
+ setError(reasonOf(cause));
2348
+ } finally {
2349
+ setBusy(false);
2350
+ }
2351
+ }, [management, debounced]);
2352
+ (0, import_react6.useEffect)(() => {
2353
+ void load();
2354
+ }, [load]);
2355
+ (0, import_react6.useEffect)(() => {
2356
+ const revalidate = () => {
2357
+ if (document.visibilityState === "visible") void load();
2358
+ };
2359
+ window.addEventListener("focus", revalidate);
2360
+ document.addEventListener("visibilitychange", revalidate);
2361
+ return () => {
2362
+ window.removeEventListener("focus", revalidate);
2363
+ document.removeEventListener("visibilitychange", revalidate);
2364
+ };
2365
+ }, [load]);
2366
+ (0, import_react6.useEffect)(() => {
2367
+ if (!actionMenu) return;
2368
+ const outside = (event) => {
2369
+ if (!(event.target instanceof Element) || !event.target.closest(".card-actions")) setActionMenu(void 0);
2370
+ };
2371
+ document.addEventListener("pointerdown", outside);
2372
+ return () => document.removeEventListener("pointerdown", outside);
2373
+ }, [actionMenu]);
2374
+ const mineCount = (0, import_react6.useMemo)(() => rows.length + teams.length, [rows, teams]);
2375
+ const typeCounts = (0, import_react6.useMemo)(() => ({ agent: rows.length, team: teams.length }), [rows, teams]);
2376
+ const visible = (0, import_react6.useMemo)(() => {
2377
+ if (view === "center") {
2378
+ if (filter === "personal") return rows.filter((row) => !row.published);
2379
+ return rows.filter((row) => row.published);
2380
+ }
2381
+ if (stateFilter === "draft") return rows.filter((row) => !row.published);
2382
+ if (stateFilter === "published") return rows.filter((row) => row.published);
2383
+ return rows;
2384
+ }, [rows, view, filter, stateFilter]);
2385
+ const closeEditor = (0, import_react6.useCallback)(() => {
2386
+ setEditorId(void 0);
2387
+ const url = new URL(window.location.href);
2388
+ url.searchParams.delete("expert-draft");
2389
+ window.history.replaceState(window.history.state, "", url);
2390
+ }, []);
2391
+ const act = (0, import_react6.useCallback)(async (operation, after) => {
2392
+ setActing(true);
2393
+ setError("");
2394
+ try {
2395
+ await operation();
2396
+ after?.();
2397
+ await load();
2398
+ } catch (cause) {
2399
+ setError(reasonOf(cause));
2400
+ } finally {
2401
+ setActing(false);
2402
+ }
2403
+ }, [load]);
2404
+ const createExpert = (0, import_react6.useCallback)(async (kind2) => {
2405
+ if (createExpertTask2 === void 0) {
2406
+ setError("\u5236\u4F5C\u4E13\u5BB6\u9700\u8981\u5148\u5B89\u88C5\u5E76\u542F\u7528\u672C\u63D2\u4EF6\u7684 Client \u4E00\u534A\u3002");
2407
+ return;
2408
+ }
2409
+ setActing(true);
2410
+ setError("");
2411
+ try {
2412
+ await createExpertTask2(kind2);
2413
+ } catch (cause) {
2414
+ setError(reasonOf(cause));
2415
+ } finally {
2416
+ setActing(false);
2417
+ }
2418
+ }, [createExpertTask2]);
2419
+ const editInConversation = (0, import_react6.useCallback)(async (expertId) => {
2420
+ setActionMenu(void 0);
2421
+ if (editExpertTask2 === void 0) {
2422
+ setError("\u7F16\u8F91\u4E13\u5BB6\u9700\u8981\u5148\u5B89\u88C5\u5E76\u542F\u7528\u672C\u63D2\u4EF6\u7684 Client \u4E00\u534A\u3002");
2423
+ return;
2424
+ }
2425
+ setActing(true);
2426
+ setError("");
2427
+ try {
2428
+ await editExpertTask2(expertId);
2429
+ setDetailId(void 0);
2430
+ } catch (cause) {
2431
+ setError(reasonOf(cause));
2432
+ } finally {
2433
+ setActing(false);
2434
+ }
2435
+ }, [editExpertTask2]);
2436
+ const copyToMine = (row) => act(async () => {
2437
+ const draft = await management.copy(row.id);
2438
+ setActionMenu(void 0);
2439
+ setEditorId(draft.expert.id);
2440
+ });
2441
+ const removeExpert = (row) => act(async () => {
2442
+ const result = await management.remove(row.id);
2443
+ setDeleteTarget(void 0);
2444
+ setActionMenu(void 0);
2445
+ if (detailId === row.id) setDetailId(void 0);
2446
+ const impact = [...result.updatedTeams ?? [], ...result.removedTeams ?? []].map((team) => team.name);
2447
+ if (impact.length > 0) {
2448
+ const removed = (result.removedTeams ?? []).map((team) => team.name);
2449
+ setNotice({
2450
+ kind: "warn",
2451
+ text: `\u5DF2\u5220\u9664\u300C${row.name}\u300D\uFF0C\u5E76\u66F4\u65B0\u4E86\u4E13\u5BB6\u56E2\uFF1A${impact.join("\u3001")}${removed.length > 0 ? `\uFF08\u5176\u4E2D ${removed.join("\u3001")} \u4E0D\u8DB3 ${TEAM_LIMITS.membersMin} \u4F4D\u6210\u5458\uFF0C\u5DF2\u4E00\u5E76\u5220\u9664\uFF09` : ""}\u3002`
2452
+ });
2453
+ } else setNotice({ kind: "info", text: `\u5DF2\u5220\u9664\u300C${row.name}\u300D\u3002` });
2454
+ });
2455
+ const removeTeam = (team) => act(async () => {
2456
+ await management.removeTeam(team.id);
2457
+ setTeamDeleteTarget(void 0);
2458
+ setActionMenu(void 0);
2459
+ if (teamDetailId === team.id) setTeamDetailId(void 0);
2460
+ }, () => setNotice({ kind: "info", text: `\u5DF2\u5220\u9664\u4E13\u5BB6\u56E2\u300C${team.name}\u300D\u3002` }));
2461
+ const available = nav?.available() ?? /* @__PURE__ */ new Set();
2462
+ const kindLabel = kind === "team" ? "\u4E13\u5BB6\u56E2" : "\u4E13\u5BB6";
2463
+ const shownTeams = view === "mine" ? teams : filter === "personal" ? [] : teams;
2464
+ const count = kind === "team" ? shownTeams.length : visible.length;
2465
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "wd-experts wd-scope", "data-testid": "workdsh-experts", children: [
2466
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("style", { children: expertsCss }),
2467
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("header", { className: "cap-header", children: [
2468
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { className: "nav-toggle", onClick: () => toggleNavigation?.(), "aria-label": "\u5207\u6362\u5BFC\u822A", children: "\u5BFC\u822A" }),
2469
+ CAPABILITY_TABS.map(([key, label]) => {
2470
+ const active = key === "experts";
2471
+ const target = CAPABILITY_KEY[key];
2472
+ const enabled = active || target !== void 0 && available.has(target);
2473
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2474
+ "button",
2475
+ {
2476
+ className: `cap-tab ${active ? "active" : ""}`,
2477
+ disabled: !enabled,
2478
+ "aria-current": active ? "page" : void 0,
2479
+ title: enabled ? label : `${label}\uFF08\u672A\u5B89\u88C5\uFF09`,
2480
+ onClick: () => {
2481
+ if (!active && target !== void 0) nav?.open(target);
2482
+ },
2483
+ children: [
2484
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CapabilityIcon, { name: key }),
2485
+ label
2486
+ ]
2487
+ },
2488
+ key
2489
+ );
2490
+ }),
2491
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2492
+ "input",
2493
+ {
2494
+ className: "search",
2495
+ "aria-label": "\u641C\u7D22\u4E13\u5BB6",
2496
+ placeholder: view === "mine" ? `\u641C\u7D22\u6211\u521B\u5EFA\u7684${kindLabel}` : `\u641C\u7D22${kindLabel}`,
2497
+ ref: search,
2498
+ value: query,
2499
+ onChange: (event) => setQuery(event.currentTarget.value)
2500
+ }
2501
+ ),
2502
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2503
+ "button",
2504
+ {
2505
+ className: `mine-toggle ${view === "mine" ? "active" : ""}`,
2506
+ "aria-pressed": view === "mine",
2507
+ onClick: () => {
2508
+ setView("mine");
2509
+ setQuery("");
2510
+ },
2511
+ children: [
2512
+ "\u6211\u7684\u4E13\u5BB6 ",
2513
+ mineCount
2514
+ ]
2515
+ }
2516
+ ),
2517
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("details", { className: "create-menu", children: [
2518
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("summary", { className: "create-expert", children: "\u5236\u4F5C\u4E13\u5BB6" }),
2519
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { role: "menu", children: [
2520
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { role: "menuitem", disabled: acting, onClick: (event) => {
2521
+ event.currentTarget.closest("details")?.removeAttribute("open");
2522
+ void createExpert("agent");
2523
+ }, children: "\u521B\u5EFA\u4E13\u5BB6" }),
2524
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { role: "menuitem", disabled: acting, onClick: (event) => {
2525
+ event.currentTarget.closest("details")?.removeAttribute("open");
2526
+ void createExpert("team");
2527
+ }, children: "\u521B\u5EFA\u4E13\u5BB6\u56E2" })
2528
+ ] })
2529
+ ] })
2530
+ ] }),
2531
+ view === "mine" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { className: "back-center", onClick: () => {
2532
+ setView("center");
2533
+ setQuery("");
2534
+ setFilter("all");
2535
+ setStateFilter("all");
2536
+ }, children: "\u2039 \u5168\u90E8\u4E13\u5BB6" }),
2537
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "section-head", children: [
2538
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("nav", { className: "work-types", "aria-label": view === "mine" ? "\u6211\u7684\u4F5C\u54C1\u7C7B\u578B" : "\u4E13\u5BB6\u4E2D\u5FC3\u7C7B\u578B", children: [["agent", "\u4E13\u5BB6"], ["team", "\u4E13\u5BB6\u56E2"]].map(([type, label]) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2539
+ "button",
2540
+ {
2541
+ className: kind === type ? "active" : "",
2542
+ "aria-pressed": kind === type,
2543
+ onClick: () => {
2544
+ setKind(type);
2545
+ setQuery("");
2546
+ },
2547
+ children: [
2548
+ label,
2549
+ view === "mine" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: typeCounts[type] })
2550
+ ]
2551
+ },
2552
+ type
2553
+ )) }),
2554
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "section-actions", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: () => void load(), disabled: busy, children: "\u5237\u65B0" }) })
2555
+ ] }),
2556
+ view === "center" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("nav", { className: "filter-tabs", "aria-label": "\u6765\u6E90\u8FC7\u6EE4", children: ORIGIN_FILTERS.map(([key, label]) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2557
+ "button",
2558
+ {
2559
+ className: filter === key ? "active" : "",
2560
+ "aria-current": filter === key ? "page" : void 0,
2561
+ onClick: () => setFilter(key),
2562
+ children: label
2563
+ },
2564
+ key
2565
+ )) }),
2566
+ view === "mine" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("nav", { className: "filter-tabs", "aria-label": "\u72B6\u6001\u8FC7\u6EE4", children: STATE_FILTERS.map(([key, label]) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2567
+ "button",
2568
+ {
2569
+ className: stateFilter === key ? "active" : "",
2570
+ "aria-current": stateFilter === key ? "page" : void 0,
2571
+ onClick: () => setStateFilter(key),
2572
+ children: label
2573
+ },
2574
+ key
2575
+ )) }),
2576
+ notice && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `notice ${notice.kind}`, role: "status", children: [
2577
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "notice-body", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: notice.text }) }),
2578
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: () => setNotice(void 0), "aria-label": "\u5173\u95ED\u63D0\u793A", children: "\xD7" })
2579
+ ] }),
2580
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { role: "status", "aria-live": "polite", className: error ? "error counts" : "counts", children: busy ? "\u6B63\u5728\u8BFB\u53D6\u4E13\u5BB6\u76EE\u5F55\u2026" : error || `\u76EE\u5F55\u5171 ${kind === "team" ? teams.length : rows.length} \u4E2A${kindLabel} \xB7 \u5F53\u524D\u663E\u793A ${count} \u4E2A${debounced ? `\uFF08\u641C\u7D22\u201C${debounced}\u201D\uFF09` : ""}` }),
2581
+ kind === "team" ? busy ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "grid", "aria-hidden": true, children: Array.from({ length: 8 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "skeleton" }, index)) }) : !error && !shownTeams.length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "empty", children: [
2582
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { children: debounced ? "\u6CA1\u6709\u5339\u914D\u7684\u4E13\u5BB6\u56E2" : view === "mine" ? "\u8FD8\u6CA1\u6709\u81EA\u5DF1\u7684\u4E13\u5BB6\u56E2" : "\u6682\u65E0\u53EF\u7528\u4E13\u5BB6\u56E2" }),
2583
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "muted", children: debounced ? "\u4FDD\u7559\u641C\u7D22\u8BCD\uFF0C\u53EF\u6E05\u9664\u540E\u91CD\u8BD5\u3002" : view === "mine" ? "\u4ECE\u5DF2\u6709\u4E13\u5BB6\u91CC\u7EC4\u4E00\u4E2A\u5C5E\u4E8E\u4F60\u7684\u4E13\u5BB6\u56E2\u3002" : "\u9ED8\u8BA4\u6A21\u677F\u5C1A\u672A\u5C31\u7EEA\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u6216\u5236\u4F5C\u4E13\u5BB6\u56E2\u3002" }),
2584
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "empty-actions", children: [
2585
+ debounced && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: () => {
2586
+ setQuery("");
2587
+ setDebounced("");
2588
+ search.current?.focus();
2589
+ }, children: "\u6E05\u9664\u641C\u7D22" }),
2590
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { className: "create-expert", disabled: acting, onClick: () => setTeamCreateOpen(true), children: "\u521B\u5EFA\u4E13\u5BB6\u56E2" }),
2591
+ view === "mine" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: () => setView("center"), children: "\u6D4F\u89C8\u4E13\u5BB6\u4E2D\u5FC3" })
2592
+ ] })
2593
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "grid", children: [
2594
+ shownTeams.map((team) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2595
+ TeamCard,
2596
+ {
2597
+ row: team,
2598
+ busy: acting,
2599
+ mine: view === "mine",
2600
+ menuOpen: actionMenu === team.id,
2601
+ onOpenMenu: () => setActionMenu(team.id),
2602
+ onCloseMenu: () => setActionMenu(void 0),
2603
+ onOpen: () => {
2604
+ setActionMenu(void 0);
2605
+ setTeamDetailId(team.id);
2606
+ },
2607
+ onEdit: () => {
2608
+ setActionMenu(void 0);
2609
+ setTeamEditor(team);
2610
+ },
2611
+ onRemove: () => {
2612
+ setActionMenu(void 0);
2613
+ setTeamDeleteTarget(team);
2614
+ }
2615
+ },
2616
+ team.id
2617
+ )),
2618
+ view === "mine" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("button", { className: "card create-card", disabled: acting, onClick: () => setTeamCreateOpen(true), children: [
2619
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-hidden": true, children: "\uFF0B" }),
2620
+ "\u521B\u5EFA\u4E13\u5BB6\u56E2"
2621
+ ] })
2622
+ ] }) : busy ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "grid", "aria-hidden": true, children: Array.from({ length: 8 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "skeleton" }, index)) }) : !error && !visible.length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "empty", children: [
2623
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { children: debounced ? "\u6CA1\u6709\u5339\u914D\u7684\u4E13\u5BB6" : view === "mine" ? "\u8FD8\u6CA1\u6709\u81EA\u5DF1\u7684\u4E13\u5BB6" : "\u6682\u65E0\u53EF\u7528\u4E13\u5BB6" }),
2624
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "muted", children: debounced ? "\u4FDD\u7559\u641C\u7D22\u8BCD\uFF0C\u53EF\u6E05\u9664\u540E\u91CD\u8BD5\u3002" : view === "mine" ? "\u4ECE\u9ED8\u8BA4\u6A21\u677F\u590D\u5236\uFF0C\u6216\u76F4\u63A5\u5236\u4F5C\u4E00\u4E2A\u5C5E\u4E8E\u4F60\u7684\u4E13\u5BB6\u3002" : "\u9ED8\u8BA4\u6A21\u677F\u5C1A\u672A\u5C31\u7EEA\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u6216\u5236\u4F5C\u4E13\u5BB6\u3002" }),
2625
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "empty-actions", children: [
2626
+ debounced && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: () => {
2627
+ setQuery("");
2628
+ setDebounced("");
2629
+ search.current?.focus();
2630
+ }, children: "\u6E05\u9664\u641C\u7D22" }),
2631
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { className: "create-expert", disabled: acting, onClick: () => setCreateOpen(true), children: "\u521B\u5EFA\u4E13\u5BB6" }),
2632
+ view === "mine" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { onClick: () => setView("center"), children: "\u6D4F\u89C8\u4E13\u5BB6\u4E2D\u5FC3" })
2633
+ ] })
2634
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "grid", children: [
2635
+ visible.map((row) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2636
+ ExpertCard,
2637
+ {
2638
+ row,
2639
+ busy: acting,
2640
+ mine: view === "mine",
2641
+ menuOpen: actionMenu === row.id,
2642
+ onOpenMenu: () => setActionMenu(row.id),
2643
+ onCloseMenu: () => setActionMenu(void 0),
2644
+ onOpen: () => {
2645
+ setActionMenu(void 0);
2646
+ setDetailId(row.id);
2647
+ },
2648
+ onEdit: () => void editInConversation(row.id),
2649
+ onCopy: () => void copyToMine(row),
2650
+ onRemove: () => {
2651
+ setActionMenu(void 0);
2652
+ setDeleteTarget(row);
2653
+ }
2654
+ },
2655
+ row.id
2656
+ )),
2657
+ view === "mine" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("button", { className: "card create-card", disabled: acting, onClick: () => setCreateOpen(true), children: [
2658
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-hidden": true, children: "\uFF0B" }),
2659
+ "\u521B\u5EFA\u4E13\u5BB6"
2660
+ ] })
2661
+ ] }),
2662
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Modal, { open: Boolean(detailId), title: "\u4E13\u5BB6\u8BE6\u60C5", className: "wd-dialog expert-dialog", onClose: () => setDetailId(void 0), children: [
2663
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "wd-dialog-close", "aria-label": "\u5173\u95ED", onClick: () => setDetailId(void 0), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CloseIcon, {}) }),
2664
+ detailId && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2665
+ ExpertDetailModal,
2666
+ {
2667
+ expertId: detailId,
2668
+ management,
2669
+ sessionId,
2670
+ acting,
2671
+ onClose: () => setDetailId(void 0),
2672
+ onChanged: () => void load(),
2673
+ onEdit: (id) => void editInConversation(id),
2674
+ onCopy: (id) => {
2675
+ setDetailId(void 0);
2676
+ void act(async () => {
2677
+ const draft = await management.copy(id);
2678
+ setEditorId(draft.expert.id);
2679
+ });
2680
+ },
2681
+ onRemove: (row) => {
2682
+ setDetailId(void 0);
2683
+ setDeleteTarget(row);
2684
+ }
2685
+ }
2686
+ )
2687
+ ] }),
2688
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Modal, { open: Boolean(teamDetailId), title: "\u4E13\u5BB6\u56E2\u8BE6\u60C5", className: "wd-dialog expert-dialog", onClose: () => setTeamDetailId(void 0), children: [
2689
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "wd-dialog-close", "aria-label": "\u5173\u95ED", onClick: () => setTeamDetailId(void 0), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CloseIcon, {}) }),
2690
+ teamDetailId && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2691
+ TeamDetailModal,
2692
+ {
2693
+ teamId: teamDetailId,
2694
+ management,
2695
+ acting,
2696
+ onClose: () => setTeamDetailId(void 0),
2697
+ onChanged: () => void load(),
2698
+ onEdit: (id) => {
2699
+ const team = teams.find((row) => row.id === id);
2700
+ setTeamDetailId(void 0);
2701
+ if (team !== void 0) setTeamEditor(team);
2702
+ },
2703
+ onRemove: (team) => {
2704
+ setTeamDetailId(void 0);
2705
+ setTeamDeleteTarget(team);
2706
+ }
2707
+ }
2708
+ )
2709
+ ] }),
2710
+ editorId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2711
+ ExpertDraftEditor,
2712
+ {
2713
+ expertId: editorId,
2714
+ management,
2715
+ onClose: closeEditor,
2716
+ onSaved: () => void load(),
2717
+ onPublished: () => {
2718
+ closeEditor();
2719
+ void load();
2720
+ }
2721
+ }
2722
+ ),
2723
+ createOpen && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2724
+ CreateExpertDialog,
2725
+ {
2726
+ busy: acting,
2727
+ onClose: () => setCreateOpen(false),
2728
+ onCreate: (input) => void act(async () => {
2729
+ const draft = await management.create(input);
2730
+ setCreateOpen(false);
2731
+ setEditorId(draft.expert.id);
2732
+ })
2733
+ }
2734
+ ),
2735
+ deleteTarget !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2736
+ DeleteExpertDialog,
2737
+ {
2738
+ name: deleteTarget.name,
2739
+ busy: acting,
2740
+ onClose: () => setDeleteTarget(void 0),
2741
+ onConfirm: () => void removeExpert(deleteTarget)
2742
+ }
2743
+ ),
2744
+ teamCreateOpen && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2745
+ CreateTeamDialog,
2746
+ {
2747
+ busy: acting,
2748
+ experts: rows,
2749
+ onClose: () => setTeamCreateOpen(false),
2750
+ onCreate: (input) => void act(async () => {
2751
+ const team = await management.createTeam(input);
2752
+ setTeamCreateOpen(false);
2753
+ setKind("team");
2754
+ setTeamDetailId(team.id);
2755
+ })
2756
+ }
2757
+ ),
2758
+ teamEditor !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2759
+ EditTeamDialog,
2760
+ {
2761
+ team: teamEditor,
2762
+ busy: acting,
2763
+ experts: rows,
2764
+ management,
2765
+ onClose: () => setTeamEditor(void 0),
2766
+ onSaved: () => void load()
2767
+ }
2768
+ ),
2769
+ teamDeleteTarget !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2770
+ DeleteTeamDialog,
2771
+ {
2772
+ name: teamDeleteTarget.name,
2773
+ busy: acting,
2774
+ onClose: () => setTeamDeleteTarget(void 0),
2775
+ onConfirm: () => void removeTeam(teamDeleteTarget)
2776
+ }
2777
+ )
2778
+ ] });
2779
+ }
2780
+
2781
+ // packages/experts/src/picker.tsx
2782
+ var import_react7 = require("react");
2783
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2784
+ var css = `${dialogCss}
2785
+ .wd-expert-picker{position:relative;display:flex;align-items:center}.wd-expert-trigger{display:flex;align-items:center;gap:7px;max-width:190px;height:36px;padding:0 9px;border:0;border-radius:10px;background:transparent;color:var(--dsw-alias-label-secondary);font-size:13px;cursor:pointer}.wd-expert-trigger:hover,.wd-expert-trigger[aria-expanded="true"]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.wd-expert-trigger .trigger-icon{display:grid;place-items:center;width:22px;height:22px;flex:none;border-radius:7px;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.wd-expert-trigger.adopted .trigger-icon{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-inverted);font-weight:700}.wd-expert-trigger .trigger-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}
2786
+ .wd-expert-popover{position:absolute;z-index:90;left:0;bottom:calc(100% + 10px);width:336px;max-height:min(430px,60vh);overflow:auto;padding:8px;border:0;border-radius:15px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-elevation-panel);font:14px/20px "PingFang SC","Microsoft YaHei",sans-serif}.wd-expert-popover *{box-sizing:border-box}.wd-expert-popover .picker-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:8px;width:100%;min-height:54px;padding:5px;border-radius:10px}.wd-expert-popover .picker-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.wd-expert-popover .picker-main{display:grid;grid-template-columns:38px minmax(0,1fr);align-items:center;gap:10px;min-width:0;padding:3px;border:0;background:transparent;color:inherit;text-align:left;cursor:pointer}.wd-expert-popover .picker-mark{display:grid;place-items:center;width:38px;height:38px;border-radius:10px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-brand-text);font-weight:700}.wd-expert-popover .picker-copy{min-width:0}.wd-expert-popover .picker-copy strong,.wd-expert-popover .picker-copy small{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wd-expert-popover .picker-copy strong{font-size:14px;font-weight:600}.wd-expert-popover .picker-copy small{margin-top:2px;color:var(--dsw-alias-label-secondary);font-size:11px}.wd-expert-popover .picker-action{min-width:52px;padding:6px 8px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer}.wd-expert-popover .picker-action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.wd-expert-popover .picker-action.adopted{color:var(--dsw-alias-state-success-primary)}.wd-expert-popover .picker-action:disabled{color:var(--dsw-alias-label-dimmed);cursor:not-allowed}.wd-expert-popover .picker-empty{padding:18px 10px;text-align:center;color:var(--dsw-alias-label-secondary);font-size:12px}.wd-expert-popover .manage{display:flex;align-items:center;justify-content:center;gap:6px;width:100%;margin-top:4px;padding:9px;border:0;border-radius:10px;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer}.wd-expert-popover .manage:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
2787
+ @media(max-width:560px){.wd-expert-popover{position:fixed;left:12px;right:12px;bottom:86px;width:auto}.wd-expert-trigger .trigger-name{display:none}}
2788
+ `;
2789
+ function ExpertPicker({ sessionId, management = experts, openManagement }) {
2790
+ const root = (0, import_react7.useRef)(null);
2791
+ const [open, setOpen] = (0, import_react7.useState)(false);
2792
+ const [rows, setRows] = (0, import_react7.useState)([]);
2793
+ const [adoption, setAdoption] = (0, import_react7.useState)(null);
2794
+ const [pending, setPending] = (0, import_react7.useState)(false);
2795
+ (0, import_react7.useEffect)(() => {
2796
+ if (sessionId !== void 0) setCurrentSessionId(sessionId);
2797
+ }, [sessionId]);
2798
+ const refresh = (0, import_react7.useCallback)(async () => {
2799
+ if (sessionId === void 0) return;
2800
+ const [nextRows, nextAdoption] = await Promise.all([
2801
+ management.list().catch(() => []),
2802
+ management.adoption(sessionId).catch(() => null)
2803
+ ]);
2804
+ setRows(nextRows);
2805
+ setAdoption(nextAdoption);
2806
+ }, [management, sessionId]);
2807
+ (0, import_react7.useEffect)(() => {
2808
+ void refresh();
2809
+ }, [refresh]);
2810
+ (0, import_react7.useEffect)(() => {
2811
+ const timer = window.setInterval(() => {
2812
+ if (!document.hidden) void refresh();
2813
+ }, 5e3);
2814
+ const onVisible = () => {
2815
+ if (!document.hidden) void refresh();
2816
+ };
2817
+ document.addEventListener("visibilitychange", onVisible);
2818
+ return () => {
2819
+ window.clearInterval(timer);
2820
+ document.removeEventListener("visibilitychange", onVisible);
2821
+ };
2822
+ }, [refresh]);
2823
+ (0, import_react7.useEffect)(() => {
2824
+ if (!open) return;
2825
+ const onPointerDown = (event) => {
2826
+ if (!root.current?.contains(event.target)) setOpen(false);
2827
+ };
2828
+ document.addEventListener("pointerdown", onPointerDown);
2829
+ return () => document.removeEventListener("pointerdown", onPointerDown);
2830
+ }, [open]);
2831
+ const choose = (0, import_react7.useCallback)(async (row) => {
2832
+ if (sessionId === void 0 || !row.published) return;
2833
+ setPending(true);
2834
+ try {
2835
+ const next = adoption?.expertId === row.id ? await management.setAdoption(sessionId, null) : await management.setAdoption(sessionId, row.id);
2836
+ setAdoption(next);
2837
+ } catch {
2838
+ await refresh();
2839
+ } finally {
2840
+ setPending(false);
2841
+ }
2842
+ }, [adoption, management, refresh, sessionId]);
2843
+ if (sessionId === void 0) return null;
2844
+ const adoptedRow = rows.find((row) => row.id === adoption?.expertId);
2845
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2846
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("style", { children: css }),
2847
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "wd-expert-picker wd-scope", ref: root, children: [
2848
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2849
+ "button",
2850
+ {
2851
+ className: `wd-expert-trigger${adoptedRow !== void 0 ? " adopted" : ""}`,
2852
+ type: "button",
2853
+ "aria-label": adoptedRow !== void 0 ? `\u4E13\u5BB6\uFF1A${adoptedRow.name}` : "\u4E13\u5BB6",
2854
+ title: "\u672C\u6B21\u5BF9\u8BDD\u91C7\u7528\u7684\u4E13\u5BB6\u89D2\u8272",
2855
+ "aria-haspopup": "menu",
2856
+ "aria-expanded": open,
2857
+ onClick: () => setOpen((value) => !value),
2858
+ children: [
2859
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "trigger-icon", children: adoptedRow !== void 0 ? adoptedRow.name.trim().charAt(0) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CapabilityIcon, { name: "experts" }) }),
2860
+ adoptedRow !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "trigger-name", children: adoptedRow.name })
2861
+ ]
2862
+ }
2863
+ ),
2864
+ open && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "wd-expert-popover", role: "menu", "aria-label": "\u4E13\u5BB6", children: [
2865
+ rows.map((row) => {
2866
+ const adopted = adoption?.expertId === row.id;
2867
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "picker-row", role: "none", children: [
2868
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2869
+ "button",
2870
+ {
2871
+ className: "picker-main",
2872
+ type: "button",
2873
+ role: "menuitem",
2874
+ disabled: !row.published,
2875
+ onClick: () => {
2876
+ if (row.published) {
2877
+ setOpen(false);
2878
+ openManagement?.();
2879
+ }
2880
+ },
2881
+ children: [
2882
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "picker-mark", "aria-hidden": true, children: row.name.trim().charAt(0) || "\u4E13" }),
2883
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "picker-copy", children: [
2884
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: row.name }),
2885
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("small", { children: row.published ? `\u4FEE\u8BA2 ${row.revisionNumber} \xB7 ${row.description || "\u4E13\u5BB6"}` : "\u672A\u53D1\u5E03\uFF0C\u4E0D\u80FD\u91C7\u7528" })
2886
+ ] })
2887
+ ]
2888
+ }
2889
+ ),
2890
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2891
+ "button",
2892
+ {
2893
+ className: `picker-action${adopted ? " adopted" : ""}`,
2894
+ type: "button",
2895
+ role: "menuitemradio",
2896
+ "aria-checked": adopted,
2897
+ disabled: pending || !row.published,
2898
+ "aria-label": `${adopted ? "\u53D6\u6D88\u91C7\u7528" : "\u91C7\u7528"} ${row.name}`,
2899
+ onClick: () => void choose(row),
2900
+ children: adopted ? "\u5DF2\u91C7\u7528" : row.published ? "\u91C7\u7528" : "\u672A\u53D1\u5E03"
2901
+ }
2902
+ )
2903
+ ] }, row.id);
2904
+ }),
2905
+ rows.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "picker-empty", children: "\u8FD8\u6CA1\u6709\u4E13\u5BB6" }),
2906
+ openManagement !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("button", { className: "manage", type: "button", onClick: () => {
2907
+ setOpen(false);
2908
+ openManagement();
2909
+ }, children: [
2910
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "aria-hidden": "true", children: "\u2197" }),
2911
+ " \u7BA1\u7406\u4E13\u5BB6"
2912
+ ] })
2913
+ ] })
2914
+ ] })
2915
+ ] });
2916
+ }
2917
+
2918
+ // packages/experts/src/drafts.tsx
2919
+ var import_react8 = require("react");
2920
+ var pendingExpertDraftKey = "workdsh.pending-expert-task-draft";
2921
+ var pendingExpertDraftEvent = "workdsh:expert-draft-staged";
2922
+ var expertManagerGuide = "/expert-manager \u5E2E\u6211\u521B\u5EFA\u4E00\u4E2A XXX \u4E13\u5BB6\uFF0C\u64C5\u957F XXXXX\u3002\u6211\u7684\u7ECF\u9A8C\u662F\uFF1A[\u8BF7\u8865\u5145\u4F60\u7684\u884C\u4E1A\u80CC\u666F\u3001\u76F8\u5173\u7ECF\u9A8C]";
2923
+ var expertTeamManagerGuide = "/expert-manager \u5E2E\u6211\u521B\u5EFA\u4E00\u4E2A XXX \u4E13\u5BB6\u56E2\uFF0C\u56E2\u961F\u6210\u5458\u5305\u62EC[\u8BF7\u8865\u5145\u6210\u5458\u89D2\u8272]\uFF0C\u5171\u540C\u64C5\u957F XXXXX\u3002\u6211\u7684\u7ECF\u9A8C\u662F\uFF1A[\u8BF7\u8865\u5145\u4F60\u7684\u884C\u4E1A\u80CC\u666F\u3001\u76F8\u5173\u7ECF\u9A8C]";
2924
+ function PendingExpertDraft({ useSession, useInput, inputActions }) {
2925
+ const sessionId = typeof useSession === "function" ? useSession((session) => session?.sessionId) : void 0;
2926
+ const input = typeof useInput === "function" ? useInput((state) => state) : void 0;
2927
+ const [generation, setGeneration] = (0, import_react8.useState)(0);
2928
+ (0, import_react8.useEffect)(() => {
2929
+ const staged = () => setGeneration((value) => value + 1);
2930
+ window.addEventListener(pendingExpertDraftEvent, staged);
2931
+ return () => window.removeEventListener(pendingExpertDraftEvent, staged);
2932
+ }, []);
2933
+ (0, import_react8.useEffect)(() => {
2934
+ if (inputActions === void 0 || input === void 0) return;
2935
+ const serialized = window.sessionStorage.getItem(pendingExpertDraftKey);
2936
+ if (!serialized) return;
2937
+ let pending;
2938
+ try {
2939
+ pending = JSON.parse(serialized);
2940
+ } catch {
2941
+ window.sessionStorage.removeItem(pendingExpertDraftKey);
2942
+ return;
2943
+ }
2944
+ if (!pending || typeof pending.text !== "string" || typeof pending.expiresAt !== "number" || pending.expiresAt <= Date.now()) {
2945
+ window.sessionStorage.removeItem(pendingExpertDraftKey);
2946
+ return;
2947
+ }
2948
+ if (pending.sessionId !== sessionId) return;
2949
+ window.sessionStorage.removeItem(pendingExpertDraftKey);
2950
+ if (input.draft.length === 0 && input.attachmentIds.length === 0 && input.phase === "plain") {
2951
+ inputActions.setDraft(pending.text);
2952
+ }
2953
+ }, [sessionId, input, inputActions, generation]);
2954
+ return null;
2955
+ }
2956
+
2957
+ // packages/experts/src/session-launch.ts
2958
+ var DRAFT_TTL_MS = 6e4;
2959
+ function resolveWorkspace(sessions, workspaces) {
2960
+ const items = workspaces?.list?.getSnapshot().items ?? [];
2961
+ if (items.length === 0) return void 0;
2962
+ const byId = sessions.list?.getSnapshot().byId ?? {};
2963
+ const currentId = Object.values(byId).find((row) => (row.retainedBy?.mainView ?? 0) > 0)?.id;
2964
+ return (currentId === void 0 ? void 0 : items.find((row) => row.sessionIds.includes(currentId))) ?? items.find((row) => row.path !== void 0 && row.path === (currentId === void 0 ? void 0 : byId[currentId]?.cwd)) ?? items[0];
2965
+ }
2966
+ function stageDraft(faces, sessionId, text) {
2967
+ const storage = faces.storage ?? window.sessionStorage;
2968
+ const staged = { sessionId, text, expiresAt: Date.now() + DRAFT_TTL_MS };
2969
+ storage.setItem(pendingExpertDraftKey, JSON.stringify(staged));
2970
+ faces.uiWorkspace.openSession(sessionId);
2971
+ window.dispatchEvent(new Event(pendingExpertDraftEvent));
2972
+ }
2973
+ async function createExpertTask(faces, text) {
2974
+ faces.signal?.throwIfAborted();
2975
+ const workspace = resolveWorkspace(faces.sessions, faces.workspaces);
2976
+ if (workspace === void 0) throw new Error("\u9700\u8981\u5148\u9009\u62E9\u4E00\u4E2A\u5DE5\u4F5C\u533A\u518D\u5236\u4F5C\u4E13\u5BB6\u3002");
2977
+ const sessionId = await faces.sessions.create({ workspaceId: workspace.workspaceId, cwd: workspace.path });
2978
+ faces.signal?.throwIfAborted();
2979
+ faces.layout.selectPanel(null);
2980
+ faces.uiWorkspace.openSession(sessionId);
2981
+ stageDraft(faces, sessionId, text);
2982
+ return sessionId;
2983
+ }
2984
+ async function editExpertTask(faces, text) {
2985
+ faces.signal?.throwIfAborted();
2986
+ const workspace = resolveWorkspace(faces.sessions, faces.workspaces);
2987
+ if (workspace === void 0) throw new Error("\u9700\u8981\u5148\u9009\u62E9\u4E00\u4E2A\u5DE5\u4F5C\u533A\u518D\u4FEE\u6539\u4E13\u5BB6\u3002");
2988
+ const sessionId = await faces.sessions.create({ workspaceId: workspace.workspaceId, cwd: workspace.path });
2989
+ faces.signal?.throwIfAborted();
2990
+ faces.layout.selectPanel(null);
2991
+ faces.uiWorkspace.openSession(sessionId);
2992
+ stageDraft(faces, sessionId, text);
2993
+ return sessionId;
2994
+ }
2995
+ function expertEditGuide(name2) {
2996
+ return `/expert-manager \u5E2E\u6211\u4FEE\u6539\u4E13\u5BB6\uFF1A[${name2}]\uFF0C\u589E\u52A0/\u4F18\u5316[\u8BF7\u8865\u5145\u4F60\u5E0C\u671B\u65B0\u589E/\u4F18\u5316\u7684\u6280\u80FD\u6216\u77E5\u8BC6\u9886\u57DF\u7B49]\u65B9\u9762\u7684\u80FD\u529B`;
2997
+ }
2998
+
2999
+ // packages/experts/client.tsx
3000
+ var import_jsx_runtime10 = require("react/jsx-runtime");
3001
+ var PANEL_ID = "dsh-plugin-experts";
3002
+ var name = "dsh-plugin-experts-client";
3003
+ var inject = ["slots", "layout", "sessions", "workspaces", "uiWorkspace"];
3004
+ function ExpertsIcon({ size = 16 }) {
3005
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", style: { display: "block" }, children: [
3006
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("circle", { cx: "10", cy: "8", r: "3.2", stroke: "currentColor", strokeWidth: 1.8 }),
3007
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M4 19.5a6.2 6.2 0 0 1 12 0", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round" }),
3008
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M18.5 4.5 19.4 7l2.5.9-2.5.9-.9 2.5-.9-2.5-2.5-.9 2.5-.9z", stroke: "currentColor", strokeWidth: 1.4, strokeLinejoin: "round" })
3009
+ ] });
3010
+ }
3011
+ function apply(ctx) {
3012
+ const openManagement = () => ctx.layout?.selectPanel(PANEL_ID);
3013
+ const nav = createNavFace(ctx, PANEL_ID);
3014
+ const lifetime = new AbortController();
3015
+ ctx.effect?.(() => () => lifetime.abort(), "dsh-plugin-experts.client");
3016
+ const launchFaces = () => {
3017
+ const sessions = ctx.sessions;
3018
+ const uiWorkspace = ctx.uiWorkspace;
3019
+ if (sessions === void 0 || uiWorkspace === void 0 || ctx.layout === void 0) return void 0;
3020
+ return {
3021
+ sessions,
3022
+ ...ctx.workspaces === void 0 ? {} : { workspaces: ctx.workspaces },
3023
+ uiWorkspace,
3024
+ layout: ctx.layout,
3025
+ signal: lifetime.signal
3026
+ };
3027
+ };
3028
+ const createExpertTask2 = async (kind) => {
3029
+ const faces = launchFaces();
3030
+ if (faces === void 0) throw new Error("\u5236\u4F5C\u4E13\u5BB6\u9700\u8981\u4F1A\u8BDD\u4E0E\u5DE5\u4F5C\u533A\u670D\u52A1\uFF0C\u5F53\u524D\u73AF\u5883\u672A\u63D0\u4F9B\u3002");
3031
+ await createExpertTask(faces, kind === "team" ? expertTeamManagerGuide : expertManagerGuide);
3032
+ };
3033
+ const editExpertTask2 = async (expertId) => {
3034
+ const faces = launchFaces();
3035
+ if (faces === void 0) throw new Error("\u7F16\u8F91\u4E13\u5BB6\u9700\u8981\u4F1A\u8BDD\u4E0E\u5DE5\u4F5C\u533A\u670D\u52A1\uFF0C\u5F53\u524D\u73AF\u5883\u672A\u63D0\u4F9B\u3002");
3036
+ const name2 = await experts.list("").then((rows) => rows.find((item) => item.id === expertId)?.name).catch(() => void 0);
3037
+ await editExpertTask(faces, expertEditGuide(name2 ?? expertId));
3038
+ };
3039
+ ctx.slots.inject("main", () => ctx.slots.register({
3040
+ name: "main",
3041
+ key: PANEL_ID,
3042
+ inject: () => ({
3043
+ management: experts,
3044
+ nav,
3045
+ // Upstream's `.nav-toggle` is the narrow-screen sidebar control.
3046
+ toggleNavigation: () => ctx.layout?.toggleSidebar?.(),
3047
+ createExpertTask: createExpertTask2,
3048
+ editExpertTask: editExpertTask2
3049
+ })
3050
+ }, ExpertsPanel));
3051
+ ctx.slots.inject("conversation.input.left", () => ctx.slots.register({
3052
+ name: "conversation.input.left",
3053
+ id: PANEL_ID,
3054
+ order: 32,
3055
+ inject: () => ({ management: experts, openManagement })
3056
+ }, ExpertPicker));
3057
+ ctx.slots.inject("conversation.input.overlay", () => ctx.slots.register({
3058
+ name: "conversation.input.overlay",
3059
+ id: PANEL_ID,
3060
+ order: 32
3061
+ }, PendingExpertDraft));
3062
+ ctx.slots.inject("sidebar.panellist", () => ctx.slots.register({
3063
+ name: "sidebar.panellist",
3064
+ id: PANEL_ID,
3065
+ order: 40,
3066
+ label: "\u4E13\u5BB6 \xB7 \u6280\u80FD \xB7 \u8FDE\u63A5\u5668"
3067
+ }, ExpertsIcon));
3068
+ }
3069
+
3070
+ return module.exports;
3071
+ },
3072
+ });