@ran-sh/dsh-crew 1.2.0-rc.4 → 1.2.0-rc.6

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.
@@ -1,567 +1,567 @@
1
- window.__ModuleLoader__.load({ id: "@ran-sh/dsh-crew-web-bridge", factory: (require) => {
2
- var module = { exports: {} }; var exports = module.exports;
3
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
- let react = require("react");
5
- let react_jsx_runtime = require("react/jsx-runtime");
6
- //#region src/client/panel-chrome.tsx
7
- function PanelStyles() {
8
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `
9
- .dsh-crew-ui { --crew-line: rgba(128,128,128,.24); --crew-soft: rgba(128,128,128,.045); --crew-accent: #2563eb; font-size: 13px; line-height: 1.55; min-width: 0; }
10
- .dsh-crew-ui *, .dsh-crew-ui *::before, .dsh-crew-ui *::after { box-sizing: border-box; }
11
- .dsh-crew-ui .crew-panel-header { border: 1px solid var(--crew-line); border-radius: 12px; padding: 16px; background: var(--crew-soft); display: flex; flex-wrap: wrap; align-items: flex-start; gap: 12px 16px; }
12
- .dsh-crew-ui .crew-panel-heading { flex: 1 1 260px; min-width: 0; }
13
- .dsh-crew-ui .crew-eyebrow { font-size: 10.5px; letter-spacing: .055em; opacity: .65; margin-bottom: 4px; }
14
- .dsh-crew-ui .crew-panel-title { margin: 0; font-size: 19px; font-weight: 680; line-height: 1.3; letter-spacing: -.025em; }
15
- .dsh-crew-ui .crew-panel-description { margin: 5px 0 0; font-size: 12px; opacity: .72; overflow-wrap: anywhere; }
16
- .dsh-crew-ui .crew-panel-badges { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
17
- .dsh-crew-ui .crew-nav-link { display: inline-flex; align-items: center; justify-content: center; color: var(--crew-accent); background: transparent; border: 1px solid var(--crew-line); border-radius: 8px; padding: 7px 10px; font-size: 12px; font-weight: 600; text-decoration: none; flex-shrink: 0; }
18
- .dsh-crew-ui button:focus-visible, .dsh-crew-ui a:focus-visible, .dsh-crew-ui input:focus-visible, .dsh-crew-ui summary:focus-visible { outline: 2px solid var(--crew-accent); outline-offset: 3px; }
19
- .dsh-crew-ui button:disabled { cursor: not-allowed; opacity: .4; }
20
- .dsh-crew-ui .crew-nav-link:hover, .dsh-crew-ui .crew-section-trigger:hover, .dsh-crew-ui summary:hover { background: rgba(128,128,128,.09); }
21
- .dsh-crew-ui .crew-section-heading { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
22
- .dsh-crew-ui .crew-section-title { font-weight: 650; font-size: 13px; }
23
- .dsh-crew-ui .crew-section-summary { font-size: 11.5px; opacity: .65; overflow-wrap: anywhere; }
24
- .dsh-crew-ui .crew-config-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; margin: 6px 0 2px; }
25
- @media (prefers-color-scheme: dark) { .dsh-crew-ui { --crew-accent: #8ab4ff; } }
26
- @media (prefers-reduced-motion: reduce) { .dsh-crew-ui * { transition: none !important; } }
27
- ` });
28
- }
29
- function PanelHeader({ title, eyebrow, description, href, linkText, children }) {
30
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
31
- className: "crew-panel-header",
32
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
33
- className: "crew-panel-heading",
34
- children: [
35
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
36
- className: "crew-eyebrow",
37
- children: eyebrow
38
- }),
39
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
40
- className: "crew-panel-title",
41
- children: title
42
- }),
43
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
44
- className: "crew-panel-description",
45
- children: description
46
- }),
47
- children && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
48
- className: "crew-panel-badges",
49
- children
50
- })
51
- ]
52
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
53
- className: "crew-nav-link",
54
- href,
55
- target: "_blank",
56
- rel: "noopener noreferrer",
57
- children: linkText
58
- })]
59
- });
60
- }
61
- //#endregion
62
- //#region src/client/quick-panel.tsx
63
- const API = "/_dsh/dsh-crew";
64
- const FULL = "http://127.0.0.1:3210/";
65
- const RESTART_KEYS = /* @__PURE__ */ new Set([
66
- "vision_enabled",
67
- "imagegen_enabled",
68
- "vision_provider",
69
- "imagegen_provider"
70
- ]);
71
- const T = {
72
- zh: {
73
- title: "DSH Crew 快捷控制",
74
- openFull: "打开 3210 后台 →",
75
- running: "后台已连接",
76
- surface: "3080 / 日常控制",
77
- description: "常用开关与模型顺序在这里调整,更多设置进入后台。",
78
- priorityHint: "从上到下按优先级排列;从列表移除不会删除 Provider。",
79
- empty: "未配置优先模型,按现有后备策略选择。",
80
- models: (n) => `${n} 个模型`,
81
- moveUp: "上移",
82
- moveDown: "下移",
83
- remove: "从优先级移除",
84
- unavailable: "Crew 后端不可用",
85
- openDiag: "打开诊断",
86
- crew: "Crew",
87
- enabled: "启用子 Agent",
88
- flash: "Worker / Flash",
89
- pro: "Reviewer / Pro",
90
- addModel: "+ 添加模型",
91
- multimodal: "多模态",
92
- vision: "视觉",
93
- imagegen: "生图",
94
- provider: "Provider",
95
- applyRestart: "应用并重启 Crew",
96
- savedNeedsRestart: "配置已保存 · 需要重启 Crew 才会生效",
97
- saved: "已保存",
98
- working: "处理中…",
99
- providerPlaceholder: "provider",
100
- modelPlaceholder: "model"
101
- },
102
- en: {
103
- title: "DSH Crew Quick Controls",
104
- openFull: "Open Crew backend (3210) →",
105
- running: "Backend connected",
106
- surface: "3080 / DAILY CONTROLS",
107
- description: "Manage everyday switches and model order here. Open the backend for advanced settings.",
108
- priorityHint: "Ordered by priority. Removing a model here does not delete its provider.",
109
- empty: "No priority models. The existing fallback policy applies.",
110
- models: (n) => `${n} models`,
111
- moveUp: "Move up",
112
- moveDown: "Move down",
113
- remove: "Remove from priority",
114
- unavailable: "Crew backend unavailable",
115
- openDiag: "Open diagnostics",
116
- crew: "Crew",
117
- enabled: "Enable sub-agents",
118
- flash: "Worker / Flash",
119
- pro: "Reviewer / Pro",
120
- addModel: "+ Add model",
121
- multimodal: "Multimodal",
122
- vision: "Vision",
123
- imagegen: "Imagegen",
124
- provider: "Provider",
125
- applyRestart: "Apply & restart Crew",
126
- savedNeedsRestart: "Saved · restart Crew to take effect",
127
- saved: "Saved",
128
- working: "Working…",
129
- providerPlaceholder: "provider",
130
- modelPlaceholder: "Model"
131
- }
132
- };
133
- function LocalStyles() {
134
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `
135
- .dsh-crew-ui.crew-quick-card { display: flex; flex-direction: column; gap: 12px; }
136
- .crew-quick-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
137
- .crew-quick-title { font-size: 16px; font-weight: 680; }
138
- .crew-quick-section { font-weight: 650; opacity: 0.85; }
139
- .crew-quick-chip { border: 1px solid rgba(128,128,128,0.35); border-radius: 999px; padding: 1px 10px; font-size: 12px; }
140
- .crew-quick-card .crew-quick-btn { border: 1px solid var(--crew-line); border-radius: 7px; min-height: 30px; padding: 3px 9px; cursor: pointer; background: transparent; color: inherit; font-size: 12px; }
141
- .crew-quick-btn.primary { border-color: #4a9eff; color: #4a9eff; font-weight: 650; }
142
- .crew-quick-card .crew-quick-input { border: 1px solid var(--crew-line); border-radius: 6px; padding: 6px 9px; font-size: 12px; min-width: 0; width: 100%; background: transparent; color: inherit; }
143
- .crew-quick-notice { opacity: 0.75; font-size: 12.5px; }
144
- .crew-quick-card .crew-quick-master { padding: 11px 14px; border: 1px solid var(--crew-line); border-radius: 10px; justify-content: space-between; }
145
- .crew-quick-card input[type=checkbox] { accent-color: var(--crew-accent); width: 15px; height: 15px; }
146
- .crew-quick-card label { display: inline-flex; gap: 7px; align-items: center; }
147
- .crew-quick-card .crew-quick-group { border: 1px solid var(--crew-line); border-radius: 10px; overflow: hidden; }
148
- .crew-quick-card .crew-quick-group > summary { cursor: pointer; padding: 12px 14px; }
149
- .crew-quick-card .crew-quick-count { margin-left: 10px; font-size: 11px; opacity: .65; font-weight: 400; }
150
- .crew-quick-card .crew-quick-content { padding: 0 14px 14px; }
151
- .crew-quick-card .crew-quick-list { padding: 0; margin: 10px 0; list-style: none; }
152
- .crew-quick-card .crew-quick-model { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; gap: 9px; align-items: center; border-top: 1px solid var(--crew-line); padding: 10px 0; }
153
- .crew-quick-card .crew-quick-rank { opacity: .5; font-size: 11px; font-variant-numeric: tabular-nums; }
154
- .crew-quick-card .crew-quick-model-name { font-size: 12.5px; font-weight: 600; overflow-wrap: anywhere; }
155
- .crew-quick-card .crew-quick-provider { font-size: 11px; opacity: .65; overflow-wrap: anywhere; }
156
- .crew-quick-card .crew-quick-actions { display: flex; gap: 4px; }
157
- .crew-quick-card .crew-quick-add > summary { color: var(--crew-accent); cursor: pointer; font-size: 12px; padding: 4px 0; }
158
- .crew-quick-card .crew-quick-form { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; gap: 7px; margin-top: 9px; }
159
- .crew-quick-card .crew-quick-media { display: grid; grid-template-columns: 100px minmax(0, 1fr); gap: 10px; align-items: center; margin-top: 10px; }
160
- @media (max-width: 640px) { .crew-quick-card .crew-quick-form { grid-template-columns: minmax(0, 1fr); } .crew-quick-card .crew-quick-model { grid-template-columns: 18px minmax(0, 1fr); } .crew-quick-card .crew-quick-actions { grid-column: 2; justify-content: flex-end; } }
161
- ` });
162
- }
163
- async function readJson(res) {
164
- if (!res.ok) return {
165
- ok: false,
166
- status: res.status
167
- };
168
- try {
169
- return await res.json();
170
- } catch {
171
- return { ok: false };
172
- }
173
- }
174
- function QuickPanel({ ctx }) {
175
- const locale = ctx?.locale?.getLocale?.().active === "zh" ? "zh" : "en";
176
- const t = T[locale] ?? T.zh;
177
- const [config, setConfig] = (0, react.useState)(null);
178
- const [ready, setReady] = (0, react.useState)(null);
179
- const [notice, setNotice] = (0, react.useState)("");
180
- const [busy, setBusy] = (0, react.useState)(false);
181
- const [restartPending, setRestartPending] = (0, react.useState)(false);
182
- const [drafts, setDrafts] = (0, react.useState)({});
183
- const load = (0, react.useCallback)(async () => {
184
- try {
185
- const status = await readJson(await fetch(`${API}/quick-status`, { cache: "no-store" }));
186
- if (!status.ok) {
187
- setReady(false);
188
- return;
189
- }
190
- setReady(true);
191
- setConfig(status.config ?? {});
192
- } catch {
193
- setReady(false);
194
- }
195
- }, []);
196
- (0, react.useEffect)(() => {
197
- load();
198
- }, [load]);
199
- const patch = (0, react.useCallback)(async (next) => {
200
- setBusy(true);
201
- setNotice(t.working);
202
- try {
203
- const res = await readJson(await fetch(`${API}/quick-config`, {
204
- method: "POST",
205
- headers: { "content-type": "application/json" },
206
- body: JSON.stringify(next)
207
- }));
208
- if (!res.ok) throw new Error(res.code ?? res.error ?? "save failed");
209
- setConfig(res.config ?? {});
210
- if (Object.keys(next).some((k) => RESTART_KEYS.has(k))) {
211
- setRestartPending(true);
212
- setNotice(t.savedNeedsRestart);
213
- } else {
214
- setNotice(t.saved);
215
- setTimeout(() => setNotice(""), 1500);
216
- }
217
- return true;
218
- } catch (e) {
219
- setNotice(String(e?.message ?? e));
220
- return false;
221
- } finally {
222
- setBusy(false);
223
- }
224
- }, [t]);
225
- const toggle = (key, value) => {
226
- setConfig((c) => ({
227
- ...c ?? {},
228
- [key]: value
229
- }));
230
- patch({ [key]: value });
231
- };
232
- const setProvider = (key, value) => {
233
- setConfig((c) => ({
234
- ...c ?? {},
235
- [key]: value
236
- }));
237
- patch({ [key]: value });
238
- };
239
- const moveModel = (listKey, index, dir) => {
240
- const list = [...config?.[listKey] ?? []];
241
- const to = index + dir;
242
- if (to < 0 || to >= list.length) return;
243
- [list[index], list[to]] = [list[to], list[index]];
244
- setConfig((c) => ({
245
- ...c ?? {},
246
- [listKey]: list
247
- }));
248
- patch({ [listKey]: list });
249
- };
250
- const removeModel = (listKey, index) => {
251
- const list = [...config?.[listKey] ?? []];
252
- list.splice(index, 1);
253
- setConfig((c) => ({
254
- ...c ?? {},
255
- [listKey]: list
256
- }));
257
- patch({ [listKey]: list });
258
- };
259
- const addModel = (listKey) => {
260
- const draft = drafts[listKey] ?? {
261
- provider: "",
262
- model: ""
263
- };
264
- if (!draft.provider.trim() || !draft.model.trim()) return;
265
- const list = [...config?.[listKey] ?? [], {
266
- provider: draft.provider.trim(),
267
- model: draft.model.trim()
268
- }];
269
- setConfig((c) => ({
270
- ...c ?? {},
271
- [listKey]: list
272
- }));
273
- setDrafts((d) => ({
274
- ...d,
275
- [listKey]: {
276
- provider: "",
277
- model: ""
278
- }
279
- }));
280
- patch({ [listKey]: list });
281
- };
282
- const modelList = (listKey, label) => {
283
- const list = config?.[listKey] ?? [];
284
- const draft = drafts[listKey] ?? {
285
- provider: "",
286
- model: ""
287
- };
288
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
289
- className: "crew-quick-group",
290
- open: listKey === "flash_model_priority",
291
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
292
- className: "crew-quick-count",
293
- children: t.models(list.length)
294
- })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
295
- className: "crew-quick-content",
296
- children: [
297
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
298
- className: "crew-quick-notice",
299
- children: t.priorityHint
300
- }),
301
- list.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
302
- className: "crew-quick-notice",
303
- children: t.empty
304
- }),
305
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
306
- className: "crew-quick-list",
307
- "aria-label": label,
308
- children: list.map((entry, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
309
- className: "crew-quick-model",
310
- children: [
311
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
312
- className: "crew-quick-rank",
313
- "aria-hidden": "true",
314
- children: [i + 1, "."]
315
- }),
316
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
317
- className: "crew-quick-model-name",
318
- children: entry.model
319
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
320
- className: "crew-quick-provider",
321
- children: entry.provider
322
- })] }),
323
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
324
- className: "crew-quick-actions",
325
- children: [
326
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
327
- type: "button",
328
- className: "crew-quick-btn",
329
- "aria-label": `${t.moveUp} ${entry.model}`,
330
- title: t.moveUp,
331
- disabled: busy || i === 0,
332
- onClick: () => moveModel(listKey, i, -1),
333
- children: "↑"
334
- }),
335
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
336
- type: "button",
337
- className: "crew-quick-btn",
338
- "aria-label": `${t.moveDown} ${entry.model}`,
339
- title: t.moveDown,
340
- disabled: busy || i === list.length - 1,
341
- onClick: () => moveModel(listKey, i, 1),
342
- children: "↓"
343
- }),
344
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
345
- type: "button",
346
- className: "crew-quick-btn",
347
- "aria-label": `${t.remove} ${entry.model}`,
348
- title: t.remove,
349
- disabled: busy,
350
- onClick: () => removeModel(listKey, i),
351
- children: "×"
352
- })
353
- ]
354
- })
355
- ]
356
- }, `${entry.provider}/${entry.model}/${i}`))
357
- }),
358
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
359
- className: "crew-quick-add",
360
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t.addModel }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
361
- className: "crew-quick-form",
362
- children: [
363
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
364
- className: "crew-quick-input",
365
- "aria-label": `${label} Provider`,
366
- placeholder: t.providerPlaceholder,
367
- disabled: busy,
368
- value: draft.provider,
369
- onChange: (e) => setDrafts((d) => ({
370
- ...d,
371
- [listKey]: {
372
- ...draft,
373
- provider: e.target.value
374
- }
375
- }))
376
- }),
377
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
378
- className: "crew-quick-input",
379
- "aria-label": `${label} ${locale === "zh" ? "模型" : "Model"}`,
380
- placeholder: t.modelPlaceholder,
381
- disabled: busy,
382
- value: draft.model,
383
- onChange: (e) => setDrafts((d) => ({
384
- ...d,
385
- [listKey]: {
386
- ...draft,
387
- model: e.target.value
388
- }
389
- }))
390
- }),
391
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
392
- type: "button",
393
- className: "crew-quick-btn",
394
- disabled: busy || !draft.provider.trim() || !draft.model.trim(),
395
- onClick: () => addModel(listKey),
396
- children: t.addModel
397
- })
398
- ]
399
- })]
400
- })
401
- ]
402
- })]
403
- });
404
- };
405
- if (ready === false) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
406
- className: "dsh-crew-ui crew-quick-card",
407
- children: [
408
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelStyles, {}),
409
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LocalStyles, {}),
410
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
411
- className: "crew-quick-title",
412
- children: t.title
413
- }),
414
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
415
- className: "crew-quick-notice",
416
- children: t.unavailable
417
- }),
418
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
419
- className: "crew-quick-row",
420
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
421
- className: "crew-nav-link",
422
- href: FULL,
423
- target: "_blank",
424
- rel: "noopener noreferrer",
425
- children: t.openDiag
426
- })
427
- })
428
- ]
429
- });
430
- if (config === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
431
- className: "dsh-crew-ui crew-quick-card",
432
- children: [
433
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelStyles, {}),
434
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LocalStyles, {}),
435
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
436
- className: "crew-quick-notice",
437
- role: "status",
438
- children: t.working
439
- })
440
- ]
441
- });
442
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
443
- className: "dsh-crew-ui crew-quick-card",
444
- children: [
445
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelStyles, {}),
446
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LocalStyles, {}),
447
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelHeader, {
448
- title: t.title,
449
- eyebrow: t.surface,
450
- description: t.description,
451
- href: FULL,
452
- linkText: t.openFull,
453
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
454
- className: "crew-quick-chip",
455
- children: [t.running, " · 3210"]
456
- })
457
- }),
458
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
459
- className: "crew-quick-row crew-quick-master",
460
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
461
- className: "crew-quick-section",
462
- children: t.crew
463
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
464
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
465
- type: "checkbox",
466
- disabled: busy,
467
- checked: config.subagents_enabled !== false,
468
- onChange: (e) => toggle("subagents_enabled", e.target.checked)
469
- }),
470
- " ",
471
- t.enabled
472
- ] })]
473
- }),
474
- modelList("flash_model_priority", t.flash),
475
- modelList("pro_model_priority", t.pro),
476
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
477
- className: "crew-quick-group",
478
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.multimodal }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
479
- className: "crew-quick-count",
480
- children: [
481
- t.vision,
482
- " / ",
483
- t.imagegen
484
- ]
485
- })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
486
- className: "crew-quick-content",
487
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
488
- className: "crew-quick-media",
489
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
490
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
491
- type: "checkbox",
492
- disabled: busy,
493
- checked: config.vision_enabled === true,
494
- onChange: (e) => toggle("vision_enabled", e.target.checked)
495
- }),
496
- " ",
497
- t.vision
498
- ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
499
- className: "crew-quick-input",
500
- "aria-label": `${t.vision} Provider`,
501
- placeholder: t.provider,
502
- disabled: busy,
503
- defaultValue: config.vision_provider ?? "",
504
- onBlur: (e) => setProvider("vision_provider", e.target.value)
505
- }, `vision-${config.vision_provider ?? ""}`)]
506
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
507
- className: "crew-quick-media",
508
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
509
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
510
- type: "checkbox",
511
- disabled: busy,
512
- checked: config.imagegen_enabled === true,
513
- onChange: (e) => toggle("imagegen_enabled", e.target.checked)
514
- }),
515
- " ",
516
- t.imagegen
517
- ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
518
- className: "crew-quick-input",
519
- "aria-label": `${t.imagegen} Provider`,
520
- placeholder: t.provider,
521
- disabled: busy,
522
- defaultValue: config.imagegen_provider ?? "",
523
- onBlur: (e) => setProvider("imagegen_provider", e.target.value)
524
- })]
525
- })]
526
- })]
527
- }),
528
- restartPending && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
529
- className: "crew-quick-row",
530
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
531
- className: "crew-quick-btn primary",
532
- href: FULL,
533
- target: "_blank",
534
- rel: "noopener noreferrer",
535
- children: t.openFull
536
- })
537
- }),
538
- notice && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
539
- className: "crew-quick-notice",
540
- role: "status",
541
- "aria-live": "polite",
542
- children: notice
543
- })
544
- ]
545
- });
546
- }
547
- function applyQuick(ctx) {
548
- ctx.slots.inject("settings.section", () => {
549
- return ctx.slots.register({
550
- name: "settings.section",
551
- id: "dsh-crew-quick",
552
- order: 65,
553
- label: () => "DSH Crew"
554
- }, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuickPanel, { ctx }));
555
- });
556
- }
557
- //#endregion
558
- //#region src/client/quick-entry.tsx
559
- const inject = ["slots", "locale"];
560
- function apply(ctx) {
561
- applyQuick(ctx);
562
- }
563
- //#endregion
564
- exports.apply = apply;
565
- exports.inject = inject;
566
-
567
- return module.exports; } });
1
+ window.__ModuleLoader__.load({ id: "@ran-sh/dsh-crew-web-bridge", factory: (require) => {
2
+ var module = { exports: {} }; var exports = module.exports;
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
+ let react = require("react");
5
+ let react_jsx_runtime = require("react/jsx-runtime");
6
+ //#region src/client/panel-chrome.tsx
7
+ function PanelStyles() {
8
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `
9
+ .dsh-crew-ui { --crew-line: rgba(128,128,128,.24); --crew-soft: rgba(128,128,128,.045); --crew-accent: #2563eb; font-size: 13px; line-height: 1.55; min-width: 0; }
10
+ .dsh-crew-ui *, .dsh-crew-ui *::before, .dsh-crew-ui *::after { box-sizing: border-box; }
11
+ .dsh-crew-ui .crew-panel-header { border: 1px solid var(--crew-line); border-radius: 12px; padding: 16px; background: var(--crew-soft); display: flex; flex-wrap: wrap; align-items: flex-start; gap: 12px 16px; }
12
+ .dsh-crew-ui .crew-panel-heading { flex: 1 1 260px; min-width: 0; }
13
+ .dsh-crew-ui .crew-eyebrow { font-size: 10.5px; letter-spacing: .055em; opacity: .65; margin-bottom: 4px; }
14
+ .dsh-crew-ui .crew-panel-title { margin: 0; font-size: 19px; font-weight: 680; line-height: 1.3; letter-spacing: -.025em; }
15
+ .dsh-crew-ui .crew-panel-description { margin: 5px 0 0; font-size: 12px; opacity: .72; overflow-wrap: anywhere; }
16
+ .dsh-crew-ui .crew-panel-badges { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
17
+ .dsh-crew-ui .crew-nav-link { display: inline-flex; align-items: center; justify-content: center; color: var(--crew-accent); background: transparent; border: 1px solid var(--crew-line); border-radius: 8px; padding: 7px 10px; font-size: 12px; font-weight: 600; text-decoration: none; flex-shrink: 0; }
18
+ .dsh-crew-ui button:focus-visible, .dsh-crew-ui a:focus-visible, .dsh-crew-ui input:focus-visible, .dsh-crew-ui summary:focus-visible { outline: 2px solid var(--crew-accent); outline-offset: 3px; }
19
+ .dsh-crew-ui button:disabled { cursor: not-allowed; opacity: .4; }
20
+ .dsh-crew-ui .crew-nav-link:hover, .dsh-crew-ui .crew-section-trigger:hover, .dsh-crew-ui summary:hover { background: rgba(128,128,128,.09); }
21
+ .dsh-crew-ui .crew-section-heading { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
22
+ .dsh-crew-ui .crew-section-title { font-weight: 650; font-size: 13px; }
23
+ .dsh-crew-ui .crew-section-summary { font-size: 11.5px; opacity: .65; overflow-wrap: anywhere; }
24
+ .dsh-crew-ui .crew-config-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; margin: 6px 0 2px; }
25
+ @media (prefers-color-scheme: dark) { .dsh-crew-ui { --crew-accent: #8ab4ff; } }
26
+ @media (prefers-reduced-motion: reduce) { .dsh-crew-ui * { transition: none !important; } }
27
+ ` });
28
+ }
29
+ function PanelHeader({ title, eyebrow, description, href, linkText, children }) {
30
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
31
+ className: "crew-panel-header",
32
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
33
+ className: "crew-panel-heading",
34
+ children: [
35
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
36
+ className: "crew-eyebrow",
37
+ children: eyebrow
38
+ }),
39
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
40
+ className: "crew-panel-title",
41
+ children: title
42
+ }),
43
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
44
+ className: "crew-panel-description",
45
+ children: description
46
+ }),
47
+ children && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
48
+ className: "crew-panel-badges",
49
+ children
50
+ })
51
+ ]
52
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
53
+ className: "crew-nav-link",
54
+ href,
55
+ target: "_blank",
56
+ rel: "noopener noreferrer",
57
+ children: linkText
58
+ })]
59
+ });
60
+ }
61
+ //#endregion
62
+ //#region src/client/quick-panel.tsx
63
+ const API = "/_dsh/dsh-crew";
64
+ const FULL = "http://127.0.0.1:3210/";
65
+ const RESTART_KEYS = /* @__PURE__ */ new Set([
66
+ "vision_enabled",
67
+ "imagegen_enabled",
68
+ "vision_provider",
69
+ "imagegen_provider"
70
+ ]);
71
+ const T = {
72
+ zh: {
73
+ title: "DSH Crew 快捷控制",
74
+ openFull: "打开 3210 后台 →",
75
+ running: "后台已连接",
76
+ surface: "3080 / 日常控制",
77
+ description: "常用开关与模型顺序在这里调整,更多设置进入后台。",
78
+ priorityHint: "从上到下按优先级排列;从列表移除不会删除 Provider。",
79
+ empty: "未配置优先模型,按现有后备策略选择。",
80
+ models: (n) => `${n} 个模型`,
81
+ moveUp: "上移",
82
+ moveDown: "下移",
83
+ remove: "从优先级移除",
84
+ unavailable: "Crew 后端不可用",
85
+ openDiag: "打开诊断",
86
+ crew: "Crew",
87
+ enabled: "启用子 Agent",
88
+ flash: "Worker / Flash",
89
+ pro: "Reviewer / Pro",
90
+ addModel: "+ 添加模型",
91
+ multimodal: "多模态",
92
+ vision: "视觉",
93
+ imagegen: "生图",
94
+ provider: "Provider",
95
+ applyRestart: "应用并重启 Crew",
96
+ savedNeedsRestart: "配置已保存 · 需要重启 Crew 才会生效",
97
+ saved: "已保存",
98
+ working: "处理中…",
99
+ providerPlaceholder: "provider",
100
+ modelPlaceholder: "model"
101
+ },
102
+ en: {
103
+ title: "DSH Crew Quick Controls",
104
+ openFull: "Open Crew backend (3210) →",
105
+ running: "Backend connected",
106
+ surface: "3080 / DAILY CONTROLS",
107
+ description: "Manage everyday switches and model order here. Open the backend for advanced settings.",
108
+ priorityHint: "Ordered by priority. Removing a model here does not delete its provider.",
109
+ empty: "No priority models. The existing fallback policy applies.",
110
+ models: (n) => `${n} models`,
111
+ moveUp: "Move up",
112
+ moveDown: "Move down",
113
+ remove: "Remove from priority",
114
+ unavailable: "Crew backend unavailable",
115
+ openDiag: "Open diagnostics",
116
+ crew: "Crew",
117
+ enabled: "Enable sub-agents",
118
+ flash: "Worker / Flash",
119
+ pro: "Reviewer / Pro",
120
+ addModel: "+ Add model",
121
+ multimodal: "Multimodal",
122
+ vision: "Vision",
123
+ imagegen: "Imagegen",
124
+ provider: "Provider",
125
+ applyRestart: "Apply & restart Crew",
126
+ savedNeedsRestart: "Saved · restart Crew to take effect",
127
+ saved: "Saved",
128
+ working: "Working…",
129
+ providerPlaceholder: "provider",
130
+ modelPlaceholder: "Model"
131
+ }
132
+ };
133
+ function LocalStyles() {
134
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `
135
+ .dsh-crew-ui.crew-quick-card { display: flex; flex-direction: column; gap: 12px; }
136
+ .crew-quick-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
137
+ .crew-quick-title { font-size: 16px; font-weight: 680; }
138
+ .crew-quick-section { font-weight: 650; opacity: 0.85; }
139
+ .crew-quick-chip { border: 1px solid rgba(128,128,128,0.35); border-radius: 999px; padding: 1px 10px; font-size: 12px; }
140
+ .crew-quick-card .crew-quick-btn { border: 1px solid var(--crew-line); border-radius: 7px; min-height: 30px; padding: 3px 9px; cursor: pointer; background: transparent; color: inherit; font-size: 12px; }
141
+ .crew-quick-btn.primary { border-color: #4a9eff; color: #4a9eff; font-weight: 650; }
142
+ .crew-quick-card .crew-quick-input { border: 1px solid var(--crew-line); border-radius: 6px; padding: 6px 9px; font-size: 12px; min-width: 0; width: 100%; background: transparent; color: inherit; }
143
+ .crew-quick-notice { opacity: 0.75; font-size: 12.5px; }
144
+ .crew-quick-card .crew-quick-master { padding: 11px 14px; border: 1px solid var(--crew-line); border-radius: 10px; justify-content: space-between; }
145
+ .crew-quick-card input[type=checkbox] { accent-color: var(--crew-accent); width: 15px; height: 15px; }
146
+ .crew-quick-card label { display: inline-flex; gap: 7px; align-items: center; }
147
+ .crew-quick-card .crew-quick-group { border: 1px solid var(--crew-line); border-radius: 10px; overflow: hidden; }
148
+ .crew-quick-card .crew-quick-group > summary { cursor: pointer; padding: 12px 14px; }
149
+ .crew-quick-card .crew-quick-count { margin-left: 10px; font-size: 11px; opacity: .65; font-weight: 400; }
150
+ .crew-quick-card .crew-quick-content { padding: 0 14px 14px; }
151
+ .crew-quick-card .crew-quick-list { padding: 0; margin: 10px 0; list-style: none; }
152
+ .crew-quick-card .crew-quick-model { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; gap: 9px; align-items: center; border-top: 1px solid var(--crew-line); padding: 10px 0; }
153
+ .crew-quick-card .crew-quick-rank { opacity: .5; font-size: 11px; font-variant-numeric: tabular-nums; }
154
+ .crew-quick-card .crew-quick-model-name { font-size: 12.5px; font-weight: 600; overflow-wrap: anywhere; }
155
+ .crew-quick-card .crew-quick-provider { font-size: 11px; opacity: .65; overflow-wrap: anywhere; }
156
+ .crew-quick-card .crew-quick-actions { display: flex; gap: 4px; }
157
+ .crew-quick-card .crew-quick-add > summary { color: var(--crew-accent); cursor: pointer; font-size: 12px; padding: 4px 0; }
158
+ .crew-quick-card .crew-quick-form { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; gap: 7px; margin-top: 9px; }
159
+ .crew-quick-card .crew-quick-media { display: grid; grid-template-columns: 100px minmax(0, 1fr); gap: 10px; align-items: center; margin-top: 10px; }
160
+ @media (max-width: 640px) { .crew-quick-card .crew-quick-form { grid-template-columns: minmax(0, 1fr); } .crew-quick-card .crew-quick-model { grid-template-columns: 18px minmax(0, 1fr); } .crew-quick-card .crew-quick-actions { grid-column: 2; justify-content: flex-end; } }
161
+ ` });
162
+ }
163
+ async function readJson(res) {
164
+ if (!res.ok) return {
165
+ ok: false,
166
+ status: res.status
167
+ };
168
+ try {
169
+ return await res.json();
170
+ } catch {
171
+ return { ok: false };
172
+ }
173
+ }
174
+ function QuickPanel({ ctx }) {
175
+ const locale = ctx?.locale?.getLocale?.().active === "zh" ? "zh" : "en";
176
+ const t = T[locale] ?? T.zh;
177
+ const [config, setConfig] = (0, react.useState)(null);
178
+ const [ready, setReady] = (0, react.useState)(null);
179
+ const [notice, setNotice] = (0, react.useState)("");
180
+ const [busy, setBusy] = (0, react.useState)(false);
181
+ const [restartPending, setRestartPending] = (0, react.useState)(false);
182
+ const [drafts, setDrafts] = (0, react.useState)({});
183
+ const load = (0, react.useCallback)(async () => {
184
+ try {
185
+ const status = await readJson(await fetch(`${API}/quick-status`, { cache: "no-store" }));
186
+ if (!status.ok) {
187
+ setReady(false);
188
+ return;
189
+ }
190
+ setReady(true);
191
+ setConfig(status.config ?? {});
192
+ } catch {
193
+ setReady(false);
194
+ }
195
+ }, []);
196
+ (0, react.useEffect)(() => {
197
+ load();
198
+ }, [load]);
199
+ const patch = (0, react.useCallback)(async (next) => {
200
+ setBusy(true);
201
+ setNotice(t.working);
202
+ try {
203
+ const res = await readJson(await fetch(`${API}/quick-config`, {
204
+ method: "POST",
205
+ headers: { "content-type": "application/json" },
206
+ body: JSON.stringify(next)
207
+ }));
208
+ if (!res.ok) throw new Error(res.code ?? res.error ?? "save failed");
209
+ setConfig(res.config ?? {});
210
+ if (Object.keys(next).some((k) => RESTART_KEYS.has(k))) {
211
+ setRestartPending(true);
212
+ setNotice(t.savedNeedsRestart);
213
+ } else {
214
+ setNotice(t.saved);
215
+ setTimeout(() => setNotice(""), 1500);
216
+ }
217
+ return true;
218
+ } catch (e) {
219
+ setNotice(String(e?.message ?? e));
220
+ return false;
221
+ } finally {
222
+ setBusy(false);
223
+ }
224
+ }, [t]);
225
+ const toggle = (key, value) => {
226
+ setConfig((c) => ({
227
+ ...c ?? {},
228
+ [key]: value
229
+ }));
230
+ patch({ [key]: value });
231
+ };
232
+ const setProvider = (key, value) => {
233
+ setConfig((c) => ({
234
+ ...c ?? {},
235
+ [key]: value
236
+ }));
237
+ patch({ [key]: value });
238
+ };
239
+ const moveModel = (listKey, index, dir) => {
240
+ const list = [...config?.[listKey] ?? []];
241
+ const to = index + dir;
242
+ if (to < 0 || to >= list.length) return;
243
+ [list[index], list[to]] = [list[to], list[index]];
244
+ setConfig((c) => ({
245
+ ...c ?? {},
246
+ [listKey]: list
247
+ }));
248
+ patch({ [listKey]: list });
249
+ };
250
+ const removeModel = (listKey, index) => {
251
+ const list = [...config?.[listKey] ?? []];
252
+ list.splice(index, 1);
253
+ setConfig((c) => ({
254
+ ...c ?? {},
255
+ [listKey]: list
256
+ }));
257
+ patch({ [listKey]: list });
258
+ };
259
+ const addModel = (listKey) => {
260
+ const draft = drafts[listKey] ?? {
261
+ provider: "",
262
+ model: ""
263
+ };
264
+ if (!draft.provider.trim() || !draft.model.trim()) return;
265
+ const list = [...config?.[listKey] ?? [], {
266
+ provider: draft.provider.trim(),
267
+ model: draft.model.trim()
268
+ }];
269
+ setConfig((c) => ({
270
+ ...c ?? {},
271
+ [listKey]: list
272
+ }));
273
+ setDrafts((d) => ({
274
+ ...d,
275
+ [listKey]: {
276
+ provider: "",
277
+ model: ""
278
+ }
279
+ }));
280
+ patch({ [listKey]: list });
281
+ };
282
+ const modelList = (listKey, label) => {
283
+ const list = config?.[listKey] ?? [];
284
+ const draft = drafts[listKey] ?? {
285
+ provider: "",
286
+ model: ""
287
+ };
288
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
289
+ className: "crew-quick-group",
290
+ open: listKey === "flash_model_priority",
291
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
292
+ className: "crew-quick-count",
293
+ children: t.models(list.length)
294
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
295
+ className: "crew-quick-content",
296
+ children: [
297
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
298
+ className: "crew-quick-notice",
299
+ children: t.priorityHint
300
+ }),
301
+ list.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
302
+ className: "crew-quick-notice",
303
+ children: t.empty
304
+ }),
305
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
306
+ className: "crew-quick-list",
307
+ "aria-label": label,
308
+ children: list.map((entry, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
309
+ className: "crew-quick-model",
310
+ children: [
311
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
312
+ className: "crew-quick-rank",
313
+ "aria-hidden": "true",
314
+ children: [i + 1, "."]
315
+ }),
316
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
317
+ className: "crew-quick-model-name",
318
+ children: entry.model
319
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
320
+ className: "crew-quick-provider",
321
+ children: entry.provider
322
+ })] }),
323
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
324
+ className: "crew-quick-actions",
325
+ children: [
326
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
327
+ type: "button",
328
+ className: "crew-quick-btn",
329
+ "aria-label": `${t.moveUp} ${entry.model}`,
330
+ title: t.moveUp,
331
+ disabled: busy || i === 0,
332
+ onClick: () => moveModel(listKey, i, -1),
333
+ children: "↑"
334
+ }),
335
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
336
+ type: "button",
337
+ className: "crew-quick-btn",
338
+ "aria-label": `${t.moveDown} ${entry.model}`,
339
+ title: t.moveDown,
340
+ disabled: busy || i === list.length - 1,
341
+ onClick: () => moveModel(listKey, i, 1),
342
+ children: "↓"
343
+ }),
344
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
345
+ type: "button",
346
+ className: "crew-quick-btn",
347
+ "aria-label": `${t.remove} ${entry.model}`,
348
+ title: t.remove,
349
+ disabled: busy,
350
+ onClick: () => removeModel(listKey, i),
351
+ children: "×"
352
+ })
353
+ ]
354
+ })
355
+ ]
356
+ }, `${entry.provider}/${entry.model}/${i}`))
357
+ }),
358
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
359
+ className: "crew-quick-add",
360
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t.addModel }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
361
+ className: "crew-quick-form",
362
+ children: [
363
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
364
+ className: "crew-quick-input",
365
+ "aria-label": `${label} Provider`,
366
+ placeholder: t.providerPlaceholder,
367
+ disabled: busy,
368
+ value: draft.provider,
369
+ onChange: (e) => setDrafts((d) => ({
370
+ ...d,
371
+ [listKey]: {
372
+ ...draft,
373
+ provider: e.target.value
374
+ }
375
+ }))
376
+ }),
377
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
378
+ className: "crew-quick-input",
379
+ "aria-label": `${label} ${locale === "zh" ? "模型" : "Model"}`,
380
+ placeholder: t.modelPlaceholder,
381
+ disabled: busy,
382
+ value: draft.model,
383
+ onChange: (e) => setDrafts((d) => ({
384
+ ...d,
385
+ [listKey]: {
386
+ ...draft,
387
+ model: e.target.value
388
+ }
389
+ }))
390
+ }),
391
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
392
+ type: "button",
393
+ className: "crew-quick-btn",
394
+ disabled: busy || !draft.provider.trim() || !draft.model.trim(),
395
+ onClick: () => addModel(listKey),
396
+ children: t.addModel
397
+ })
398
+ ]
399
+ })]
400
+ })
401
+ ]
402
+ })]
403
+ });
404
+ };
405
+ if (ready === false) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
406
+ className: "dsh-crew-ui crew-quick-card",
407
+ children: [
408
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelStyles, {}),
409
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LocalStyles, {}),
410
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
411
+ className: "crew-quick-title",
412
+ children: t.title
413
+ }),
414
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
415
+ className: "crew-quick-notice",
416
+ children: t.unavailable
417
+ }),
418
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
419
+ className: "crew-quick-row",
420
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
421
+ className: "crew-nav-link",
422
+ href: FULL,
423
+ target: "_blank",
424
+ rel: "noopener noreferrer",
425
+ children: t.openDiag
426
+ })
427
+ })
428
+ ]
429
+ });
430
+ if (config === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
431
+ className: "dsh-crew-ui crew-quick-card",
432
+ children: [
433
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelStyles, {}),
434
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LocalStyles, {}),
435
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
436
+ className: "crew-quick-notice",
437
+ role: "status",
438
+ children: t.working
439
+ })
440
+ ]
441
+ });
442
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
443
+ className: "dsh-crew-ui crew-quick-card",
444
+ children: [
445
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelStyles, {}),
446
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LocalStyles, {}),
447
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelHeader, {
448
+ title: t.title,
449
+ eyebrow: t.surface,
450
+ description: t.description,
451
+ href: FULL,
452
+ linkText: t.openFull,
453
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
454
+ className: "crew-quick-chip",
455
+ children: [t.running, " · 3210"]
456
+ })
457
+ }),
458
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
459
+ className: "crew-quick-row crew-quick-master",
460
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
461
+ className: "crew-quick-section",
462
+ children: t.crew
463
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
464
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
465
+ type: "checkbox",
466
+ disabled: busy,
467
+ checked: config.subagents_enabled !== false,
468
+ onChange: (e) => toggle("subagents_enabled", e.target.checked)
469
+ }),
470
+ " ",
471
+ t.enabled
472
+ ] })]
473
+ }),
474
+ modelList("flash_model_priority", t.flash),
475
+ modelList("pro_model_priority", t.pro),
476
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
477
+ className: "crew-quick-group",
478
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.multimodal }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
479
+ className: "crew-quick-count",
480
+ children: [
481
+ t.vision,
482
+ " / ",
483
+ t.imagegen
484
+ ]
485
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
486
+ className: "crew-quick-content",
487
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
488
+ className: "crew-quick-media",
489
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
490
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
491
+ type: "checkbox",
492
+ disabled: busy,
493
+ checked: config.vision_enabled === true,
494
+ onChange: (e) => toggle("vision_enabled", e.target.checked)
495
+ }),
496
+ " ",
497
+ t.vision
498
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
499
+ className: "crew-quick-input",
500
+ "aria-label": `${t.vision} Provider`,
501
+ placeholder: t.provider,
502
+ disabled: busy,
503
+ defaultValue: config.vision_provider ?? "",
504
+ onBlur: (e) => setProvider("vision_provider", e.target.value)
505
+ }, `vision-${config.vision_provider ?? ""}`)]
506
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
507
+ className: "crew-quick-media",
508
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
509
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
510
+ type: "checkbox",
511
+ disabled: busy,
512
+ checked: config.imagegen_enabled === true,
513
+ onChange: (e) => toggle("imagegen_enabled", e.target.checked)
514
+ }),
515
+ " ",
516
+ t.imagegen
517
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
518
+ className: "crew-quick-input",
519
+ "aria-label": `${t.imagegen} Provider`,
520
+ placeholder: t.provider,
521
+ disabled: busy,
522
+ defaultValue: config.imagegen_provider ?? "",
523
+ onBlur: (e) => setProvider("imagegen_provider", e.target.value)
524
+ })]
525
+ })]
526
+ })]
527
+ }),
528
+ restartPending && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
529
+ className: "crew-quick-row",
530
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
531
+ className: "crew-quick-btn primary",
532
+ href: FULL,
533
+ target: "_blank",
534
+ rel: "noopener noreferrer",
535
+ children: t.openFull
536
+ })
537
+ }),
538
+ notice && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
539
+ className: "crew-quick-notice",
540
+ role: "status",
541
+ "aria-live": "polite",
542
+ children: notice
543
+ })
544
+ ]
545
+ });
546
+ }
547
+ function applyQuick(ctx) {
548
+ ctx.slots.inject("settings.section", () => {
549
+ return ctx.slots.register({
550
+ name: "settings.section",
551
+ id: "dsh-crew-quick",
552
+ order: 65,
553
+ label: () => "DSH Crew"
554
+ }, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuickPanel, { ctx }));
555
+ });
556
+ }
557
+ //#endregion
558
+ //#region src/client/quick-entry.tsx
559
+ const inject = ["slots", "locale"];
560
+ function apply(ctx) {
561
+ applyQuick(ctx);
562
+ }
563
+ //#endregion
564
+ exports.apply = apply;
565
+ exports.inject = inject;
566
+
567
+ return module.exports; } });