@dungsil/dsh-plugin-ui-model-picker 0.2.3 → 0.2.4
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/README.md +4 -4
- package/dist/client.js +104 -45
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
DSH Web 입력창에서 모델과 추론 강도를 선택합니다. 하나의 선택 버튼을 누르면 추론 강도 팝오버가 먼저 열리며, 팝오버 안의 모델명을 눌러 모델 목록으로 이동합니다.
|
|
5
|
+
DSH Web 입력창에서 모델과 추론 강도를 선택합니다. 하나의 선택 버튼을 누르면 추론 강도 팝오버가 먼저 열리며, 팝오버 안의 모델명을 눌러 모델 목록으로 이동합니다. 모델을 고르면 실제 모델은 바로 바뀌지 않고 추론 강도 슬라이더가 이어서 표시되며, 강도를 설정할 때 모델이 함께 적용됩니다.
|
|
6
6
|
|
|
7
7
|
위 이미지는 플러그인 컴포넌트에 예시 모델 목록과 테마 색상을 제공한 검증 화면을 각각 캡처해 합성했습니다. 표시된 모델명과 추론 단계는 예시이며, 실제 목록은 연결한 제공자가 결정합니다.
|
|
8
8
|
|
|
@@ -10,14 +10,14 @@ DSH Web 입력창에서 모델과 추론 강도를 선택합니다. 하나의
|
|
|
10
10
|
|
|
11
11
|
1. DSH 플러그인 설치 화면에서 `@dungsil/dsh-plugin-ui-model-picker`를 설치하고 활성화합니다.
|
|
12
12
|
2. 입력창 오른쪽 선택 버튼을 눌러 추론 강도 슬라이더를 엽니다. 방향키와 Home/End 키도 사용할 수 있습니다.
|
|
13
|
-
3. 모델을 바꾸려면 팝오버 상단의 모델명 부분을 누르고 제공자별 모델을 선택합니다. 오른쪽 위 재설정 아이콘은 기본 추론 강도를 복원합니다.
|
|
13
|
+
3. 모델을 바꾸려면 팝오버 상단의 모델명 부분을 누르고 제공자별 모델을 선택합니다. 추론 강도를 지원하는 모델을 고르면 슬라이더가 이어서 나타나며, 강도를 설정해야 모델이 적용됩니다. 오른쪽 위 재설정 아이콘은 기본 추론 강도를 복원합니다.
|
|
14
14
|
|
|
15
15
|
## 동작과 호환성
|
|
16
16
|
|
|
17
17
|
- DSH `0.2.1-rc.5` 이상 `0.3.0` 미만의 Web UI를 지원합니다. 기본 `ui-model-selection` 기능이 활성화되어 있어야 합니다.
|
|
18
18
|
- 공용 모델 디렉터리와 선택 API를 그대로 사용하므로 `/model` 명령과 선택 상태를 공유합니다. 별도 모델 설정을 저장하거나 API 키를 다루지 않습니다.
|
|
19
|
-
- 실제 제공자 목록과 모델별 추론 메타데이터만 사용합니다. 별도 모델 목록, Fast 모드, 고정 추론 단계는 추가하지 않습니다. 추론을 지원하지 않는 모델에는 슬라이더를 표시하지 않으며,
|
|
20
|
-
- 다른 모델로 바꾸면
|
|
19
|
+
- 실제 제공자 목록과 모델별 추론 메타데이터만 사용합니다. 별도 모델 목록, Fast 모드, 고정 추론 단계는 추가하지 않습니다. 추론을 지원하지 않는 모델에는 슬라이더를 표시하지 않으며, 그런 모델은 목록에서 고르는 즉시 적용됩니다.
|
|
20
|
+
- 다른 모델로 바꾸면 그 모델이 지원하는 추론 강도에서 슬라이더가 시작되고, 강도를 설정해야 모델 선택이 적용됩니다. 슬라이더를 건드리지 않고 팝오버를 닫으면 모델은 바뀌지 않습니다. 기본값 재설정은 별도 강도 지정을 해제합니다.
|
|
21
21
|
- Escape, 바깥 클릭, 스크롤, 창 크기 변경으로 메뉴를 닫습니다. 메뉴의 방향키와 Tab 탐색을 지원합니다. 한국어·영어·중국어(간체)와 DSH 테마 색상을 따릅니다.
|
|
22
22
|
- 기본 모델 슬롯만 우선순위로 대체합니다. 제거하면 기본 선택 UI가 돌아오며 모델 선택은 유지됩니다. 같은 슬롯을 대체하는 다른 플러그인과는 함께 사용하지 마세요.
|
|
23
23
|
|
package/dist/client.js
CHANGED
|
@@ -108,6 +108,7 @@ const styles = `${composerStyles}
|
|
|
108
108
|
.dsh-codex-slider input::-moz-range-track { height: 28px; background: transparent; }
|
|
109
109
|
.dsh-codex-slider input::-moz-range-thumb { width: 26px; height: 26px; border: 1px solid #0000000a; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px #0002; }
|
|
110
110
|
.dsh-codex-notice { padding: 6px 10px; margin: 0; font-size: 12px; overflow-wrap: anywhere; }
|
|
111
|
+
.dsh-codex-status { position: absolute; width: 1px; height: 1px; padding: 0; margin: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
|
|
111
112
|
.dsh-codex-popover [role=alert] { color: var(--dsw-alias-state-error-primary, #b54424); }
|
|
112
113
|
.dsh-codex-popover :focus-visible { outline: 2px solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); outline-offset: -2px; }
|
|
113
114
|
.dsh-codex-popover :disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }
|
|
@@ -127,7 +128,6 @@ const copy = {
|
|
|
127
128
|
model: "모델 선택",
|
|
128
129
|
effort: "추론 강도",
|
|
129
130
|
choose: "추론 수준 선택",
|
|
130
|
-
default: "제공자 기본값",
|
|
131
131
|
reset: "기본값으로 재설정",
|
|
132
132
|
loading: "모델을 불러오는 중입니다…",
|
|
133
133
|
empty: "사용할 수 있는 모델이 없습니다.",
|
|
@@ -141,7 +141,6 @@ const copy = {
|
|
|
141
141
|
model: "Select model",
|
|
142
142
|
effort: "Reasoning effort",
|
|
143
143
|
choose: "Select reasoning effort",
|
|
144
|
-
default: "Provider default",
|
|
145
144
|
reset: "Reset to default",
|
|
146
145
|
loading: "Loading models…",
|
|
147
146
|
empty: "No models available.",
|
|
@@ -155,7 +154,6 @@ const copy = {
|
|
|
155
154
|
model: "选择模型",
|
|
156
155
|
effort: "推理强度",
|
|
157
156
|
choose: "选择推理级别",
|
|
158
|
-
default: "提供商默认值",
|
|
159
157
|
reset: "重置为默认值",
|
|
160
158
|
loading: "正在加载模型…",
|
|
161
159
|
empty: "没有可用的模型。",
|
|
@@ -174,25 +172,28 @@ function apply(ctx) {
|
|
|
174
172
|
const { active: locale } = useLocaleSnapshot(ctx.locale);
|
|
175
173
|
const text = copy[locale.startsWith("ko") ? "ko" : locale.startsWith("zh") ? "zh" : "en"];
|
|
176
174
|
const [requestedPanel, setPanel] = (0, react.useState)(null);
|
|
175
|
+
const [staged, setStaged] = (0, react.useState)(null);
|
|
177
176
|
const [draft, setDraft] = (0, react.useState)(0);
|
|
178
177
|
const [failed, setFailed] = (0, react.useState)(false);
|
|
179
178
|
const trigger = (0, react.useRef)(null);
|
|
180
179
|
const anchor = (0, react.useRef)(null);
|
|
181
180
|
const popup = (0, react.useRef)(null);
|
|
182
181
|
const pending = (0, react.useRef)(false);
|
|
182
|
+
const sliderSelection = (0, react.useRef)(null);
|
|
183
183
|
const mounted = (0, react.useRef)(true);
|
|
184
184
|
const id = (0, react.useId)();
|
|
185
185
|
const current = state.current;
|
|
186
186
|
const model = state.groups.find((item) => item.id === current?.provider)?.models.find((item) => item.id === current?.model);
|
|
187
187
|
const reasoning = model?.reasoning;
|
|
188
|
-
const efforts = reasoning?.efforts
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const panel = requestedPanel === "effort" && !
|
|
188
|
+
const efforts = reasoning?.efforts ?? [];
|
|
189
|
+
const stagedGroup = staged ? state.groups.find((item) => item.id === staged.provider) : void 0;
|
|
190
|
+
const stagedModel = staged ? stagedGroup?.models.find((item) => item.id === staged.model) : model;
|
|
191
|
+
const stagedEfforts = (stagedModel?.reasoning)?.efforts ?? [];
|
|
192
|
+
const panel = requestedPanel === "effort" && !stagedEfforts.length ? "model" : requestedPanel;
|
|
193
193
|
const effective = current?.reasoningEffort ?? reasoning?.defaultEffort;
|
|
194
194
|
const effortIndex = efforts.findIndex((item) => item.id === effective);
|
|
195
195
|
const effortLabel = efforts.length ? efforts[effortIndex]?.name ?? state.retainedEffort : void 0;
|
|
196
|
+
const stagedName = stagedModel?.name ?? (staged ? staged.model : current?.model) ?? text.model;
|
|
196
197
|
const busy = state.status === "selecting";
|
|
197
198
|
const disabled = locked || busy;
|
|
198
199
|
(0, react.useEffect)(() => {
|
|
@@ -203,10 +204,16 @@ function apply(ctx) {
|
|
|
203
204
|
};
|
|
204
205
|
}, [directory]);
|
|
205
206
|
const close = () => {
|
|
207
|
+
sliderSelection.current = null;
|
|
206
208
|
setPanel(null);
|
|
209
|
+
setStaged(null);
|
|
207
210
|
if (trigger.current) (0, _deepseek_ai_dsh_client_ui_primitives.focusWithoutRing)(trigger.current);
|
|
208
211
|
};
|
|
209
|
-
(0, _deepseek_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer)(anchor, panel !== null, () =>
|
|
212
|
+
(0, _deepseek_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer)(anchor, panel !== null, () => {
|
|
213
|
+
sliderSelection.current = null;
|
|
214
|
+
setPanel(null);
|
|
215
|
+
setStaged(null);
|
|
216
|
+
}, popup);
|
|
210
217
|
(0, react.useLayoutEffect)(() => {
|
|
211
218
|
if (!panel || !popup.current || !anchor.current) return;
|
|
212
219
|
const element = popup.current;
|
|
@@ -252,25 +259,42 @@ function apply(ctx) {
|
|
|
252
259
|
};
|
|
253
260
|
}, [panel]);
|
|
254
261
|
(0, react.useEffect)(() => {
|
|
255
|
-
if (locked)
|
|
262
|
+
if (locked) {
|
|
263
|
+
sliderSelection.current = null;
|
|
264
|
+
setPanel(null);
|
|
265
|
+
setStaged(null);
|
|
266
|
+
}
|
|
256
267
|
}, [locked]);
|
|
257
268
|
(0, react.useEffect)(() => {
|
|
269
|
+
const selection = sliderSelection.current;
|
|
270
|
+
sliderSelection.current = null;
|
|
271
|
+
if (selection && current?.provider === selection.provider && current?.model === selection.model && current?.reasoningEffort === selection.reasoningEffort) {
|
|
272
|
+
setStaged(null);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
258
275
|
setPanel(null);
|
|
276
|
+
setStaged(null);
|
|
259
277
|
}, [
|
|
260
278
|
current?.provider,
|
|
261
279
|
current?.model,
|
|
262
280
|
current?.reasoningEffort
|
|
263
281
|
]);
|
|
264
|
-
const select = async (selection) => {
|
|
282
|
+
const select = async (selection, keepSlider = false) => {
|
|
265
283
|
if (disabled || pending.current) return;
|
|
266
284
|
pending.current = true;
|
|
285
|
+
sliderSelection.current = keepSlider ? selection : null;
|
|
267
286
|
setFailed(false);
|
|
268
287
|
try {
|
|
269
288
|
const result = await directory.select(selection);
|
|
270
289
|
if (!mounted.current) return;
|
|
271
|
-
if (result.ok)
|
|
272
|
-
|
|
290
|
+
if (result.ok) {
|
|
291
|
+
if (!keepSlider) close();
|
|
292
|
+
} else {
|
|
293
|
+
sliderSelection.current = null;
|
|
294
|
+
setFailed(true);
|
|
295
|
+
}
|
|
273
296
|
} catch {
|
|
297
|
+
sliderSelection.current = null;
|
|
274
298
|
if (mounted.current) setFailed(true);
|
|
275
299
|
} finally {
|
|
276
300
|
pending.current = false;
|
|
@@ -282,19 +306,50 @@ function apply(ctx) {
|
|
|
282
306
|
close();
|
|
283
307
|
return;
|
|
284
308
|
}
|
|
309
|
+
setStaged(null);
|
|
285
310
|
setDraft(Math.max(0, effortIndex));
|
|
286
311
|
setFailed(false);
|
|
287
312
|
setPanel("effort");
|
|
288
313
|
directory.load().catch(() => {});
|
|
289
314
|
};
|
|
290
315
|
const selectEffort = (index) => {
|
|
291
|
-
|
|
292
|
-
const effort = efforts[index].id;
|
|
293
|
-
select({
|
|
316
|
+
const target = staged ?? (current ? {
|
|
294
317
|
provider: current.provider,
|
|
295
|
-
model: current.model
|
|
296
|
-
|
|
318
|
+
model: current.model
|
|
319
|
+
} : null);
|
|
320
|
+
const effort = stagedEfforts[index];
|
|
321
|
+
if (!target || !effort) return;
|
|
322
|
+
select({
|
|
323
|
+
provider: target.provider,
|
|
324
|
+
model: target.model,
|
|
325
|
+
reasoningEffort: effort.id
|
|
326
|
+
}, true);
|
|
327
|
+
};
|
|
328
|
+
const stageModel = (provider, option) => {
|
|
329
|
+
const same = provider === current?.provider && option.id === current?.model;
|
|
330
|
+
const optionReasoning = option.reasoning;
|
|
331
|
+
const optionEfforts = optionReasoning?.efforts ?? [];
|
|
332
|
+
if (optionEfforts.length < 2) {
|
|
333
|
+
if (same) {
|
|
334
|
+
close();
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const effort = optionReasoning?.defaultEffort;
|
|
338
|
+
select({
|
|
339
|
+
provider,
|
|
340
|
+
model: option.id,
|
|
341
|
+
...effort === void 0 ? {} : { reasoningEffort: effort }
|
|
342
|
+
});
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const preferredEffort = same ? current?.reasoningEffort ?? optionReasoning?.defaultEffort : optionReasoning?.defaultEffort ?? current?.reasoningEffort;
|
|
346
|
+
setStaged({
|
|
347
|
+
provider,
|
|
348
|
+
model: option.id
|
|
297
349
|
});
|
|
350
|
+
setDraft(Math.max(0, optionEfforts.findIndex((item) => item.id === preferredEffort)));
|
|
351
|
+
setFailed(false);
|
|
352
|
+
setPanel("effort");
|
|
298
353
|
};
|
|
299
354
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
300
355
|
className: "dsh-codex-picker",
|
|
@@ -305,13 +360,16 @@ function apply(ctx) {
|
|
|
305
360
|
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDataOutlineRegular, { size: 16 }),
|
|
306
361
|
label: model?.name ?? current?.model ?? text.model,
|
|
307
362
|
detail: effortLabel,
|
|
308
|
-
disabled,
|
|
363
|
+
disabled: locked,
|
|
364
|
+
"aria-disabled": disabled,
|
|
309
365
|
"aria-label": `${efforts.length ? text.choose : text.model}: ${model?.name ?? current?.model ?? text.model}${effortLabel ? `, ${effortLabel}` : ""}`,
|
|
310
366
|
title: `${model?.name ?? current?.model ?? text.model}${effortLabel ? ` ${effortLabel}` : ""}`,
|
|
311
367
|
"aria-haspopup": "dialog",
|
|
312
368
|
"aria-expanded": panel !== null,
|
|
313
369
|
"aria-controls": panel ? id : void 0,
|
|
314
|
-
onClick: (event) =>
|
|
370
|
+
onClick: (event) => {
|
|
371
|
+
if (!disabled) show(event.currentTarget);
|
|
372
|
+
}
|
|
315
373
|
})
|
|
316
374
|
}), panel && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.MenuSurface, {
|
|
317
375
|
id,
|
|
@@ -320,7 +378,7 @@ function apply(ctx) {
|
|
|
320
378
|
"aria-label": panel === "model" ? text.model : text.effort,
|
|
321
379
|
className: "dsh-codex-popover",
|
|
322
380
|
children: [
|
|
323
|
-
panel === "model" ?
|
|
381
|
+
panel === "model" ? stagedEfforts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
324
382
|
type: "button",
|
|
325
383
|
className: "dsh-codex-back",
|
|
326
384
|
onClick: () => setPanel("effort"),
|
|
@@ -334,25 +392,30 @@ function apply(ctx) {
|
|
|
334
392
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
335
393
|
type: "button",
|
|
336
394
|
className: "dsh-codex-model",
|
|
337
|
-
disabled,
|
|
338
|
-
"aria-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
395
|
+
disabled: locked,
|
|
396
|
+
"aria-disabled": disabled,
|
|
397
|
+
"aria-label": `${text.model}: ${stagedName}`,
|
|
398
|
+
onClick: () => {
|
|
399
|
+
if (!disabled) setPanel("model");
|
|
400
|
+
},
|
|
401
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: stagedEfforts[draft]?.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
402
|
+
stagedName,
|
|
342
403
|
" ",
|
|
343
404
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, { size: 14 })
|
|
344
405
|
] })]
|
|
345
406
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
346
407
|
type: "button",
|
|
347
408
|
className: "dsh-codex-reset",
|
|
348
|
-
disabled:
|
|
409
|
+
disabled: locked || !(staged ?? current),
|
|
410
|
+
"aria-disabled": disabled || !(staged ?? current),
|
|
349
411
|
"aria-label": text.reset,
|
|
350
412
|
title: text.reset,
|
|
351
413
|
onClick: () => {
|
|
352
|
-
|
|
414
|
+
const target = staged ?? (current ? {
|
|
353
415
|
provider: current.provider,
|
|
354
416
|
model: current.model
|
|
355
|
-
});
|
|
417
|
+
} : null);
|
|
418
|
+
if (target) select(target);
|
|
356
419
|
},
|
|
357
420
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconResetOutlineRegular, {})
|
|
358
421
|
})]
|
|
@@ -363,7 +426,7 @@ function apply(ctx) {
|
|
|
363
426
|
children: text.loading
|
|
364
427
|
}),
|
|
365
428
|
busy && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
366
|
-
className: "dsh-codex-notice",
|
|
429
|
+
className: panel === "effort" ? "dsh-codex-status" : "dsh-codex-notice",
|
|
367
430
|
role: "status",
|
|
368
431
|
children: text.busy
|
|
369
432
|
}),
|
|
@@ -397,14 +460,7 @@ function apply(ctx) {
|
|
|
397
460
|
"aria-checked": provider.id === current?.provider && option.id === current?.model,
|
|
398
461
|
className: "dsh-codex-option",
|
|
399
462
|
disabled,
|
|
400
|
-
onClick: () =>
|
|
401
|
-
const effort = provider.id === current?.provider && option.id === current?.model ? current.reasoningEffort : option.reasoning?.defaultEffort;
|
|
402
|
-
select({
|
|
403
|
-
provider: provider.id,
|
|
404
|
-
model: option.id,
|
|
405
|
-
...effort === void 0 ? {} : { reasoningEffort: effort }
|
|
406
|
-
});
|
|
407
|
-
},
|
|
463
|
+
onClick: () => stageModel(provider.id, option),
|
|
408
464
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [option.name, option.description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: option.description })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
409
465
|
className: "dsh-codex-check",
|
|
410
466
|
"aria-hidden": "true",
|
|
@@ -428,26 +484,29 @@ function apply(ctx) {
|
|
|
428
484
|
},
|
|
429
485
|
children: text.retry
|
|
430
486
|
})
|
|
431
|
-
] }) :
|
|
487
|
+
] }) : stagedEfforts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
432
488
|
className: "dsh-codex-slider",
|
|
433
489
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
434
490
|
className: "dsh-codex-rail",
|
|
435
|
-
style: { "--dsh-codex-progress": `${
|
|
491
|
+
style: { "--dsh-codex-progress": `${stagedEfforts.length > 1 ? draft / (stagedEfforts.length - 1) * 100 : 0}%` },
|
|
436
492
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
437
493
|
className: "dsh-codex-track",
|
|
438
494
|
"aria-hidden": "true",
|
|
439
|
-
children:
|
|
495
|
+
children: stagedEfforts.map((effort, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { "data-filled": index <= draft }, effort.id))
|
|
440
496
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
441
497
|
id: `${id}-effort`,
|
|
442
498
|
type: "range",
|
|
443
499
|
min: 0,
|
|
444
|
-
max:
|
|
500
|
+
max: stagedEfforts.length - 1,
|
|
445
501
|
step: 1,
|
|
446
502
|
value: draft,
|
|
447
|
-
disabled:
|
|
503
|
+
disabled: locked || stagedEfforts.length < 2,
|
|
504
|
+
"aria-disabled": disabled || stagedEfforts.length < 2,
|
|
448
505
|
"aria-label": text.effort,
|
|
449
|
-
"aria-valuetext":
|
|
450
|
-
onChange: (event) =>
|
|
506
|
+
"aria-valuetext": stagedEfforts[draft]?.name,
|
|
507
|
+
onChange: (event) => {
|
|
508
|
+
if (!disabled) setDraft(Number(event.target.value));
|
|
509
|
+
},
|
|
451
510
|
onPointerUp: (event) => selectEffort(Number(event.currentTarget.value)),
|
|
452
511
|
onKeyUp: (event) => {
|
|
453
512
|
if ([
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dungsil/dsh-plugin-ui-model-picker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Model and reasoning effort picker for the DeepSeek Harness composer.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"@dungsil/dsh-ui": "0.0.0",
|
|
41
41
|
"@types/react": "18.3.31",
|
|
42
42
|
"@types/react-dom": "18.3.7",
|
|
43
|
+
"happy-dom": "21.0.4",
|
|
43
44
|
"react": "18.3.1",
|
|
44
45
|
"react-dom": "18.3.1",
|
|
45
46
|
"tsdown": "0.23.4"
|
|
@@ -88,6 +89,7 @@
|
|
|
88
89
|
},
|
|
89
90
|
"scripts": {
|
|
90
91
|
"build": "tsdown",
|
|
91
|
-
"typecheck": "tsc --noEmit"
|
|
92
|
+
"typecheck": "tsc --noEmit",
|
|
93
|
+
"test": "node --test test/*.test.mjs"
|
|
92
94
|
}
|
|
93
95
|
}
|