@dungsil/dsh-plugin-ui-setting-skills 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.js +257 -148
- package/dist/index.js +21 -2
- package/locale/en.json +7 -1
- package/locale/ko.json +7 -1
- package/locale/zh.json +7 -1
- package/package.json +4 -2
package/dist/client.js
CHANGED
|
@@ -77,6 +77,9 @@ var en_default = {
|
|
|
77
77
|
"dsh": "DSH skills",
|
|
78
78
|
"loading": "Loading skills…",
|
|
79
79
|
"empty": "No loaded skills from this source.",
|
|
80
|
+
"search": "Search skills",
|
|
81
|
+
"searchPlaceholder": "Search by name, description, or path",
|
|
82
|
+
"noResults": "No skills match your search.",
|
|
80
83
|
"error": "Could not load skills. Close and reopen this settings section to try again.",
|
|
81
84
|
"incomplete": "Some skill sources could not be loaded. This list may be incomplete.",
|
|
82
85
|
"use": "Use",
|
|
@@ -90,7 +93,10 @@ var en_default = {
|
|
|
90
93
|
"original": "View original",
|
|
91
94
|
"retry": "Retry",
|
|
92
95
|
"translating": "Translating…",
|
|
93
|
-
"
|
|
96
|
+
"translateAll": "Translate all skills",
|
|
97
|
+
"translatingAll": "Translating all skills…",
|
|
98
|
+
"translationAllError": "Some skill descriptions could not be translated. Try again to translate only the failed items.",
|
|
99
|
+
"translationNotice": "Expanding a skill or translating all skills sends descriptions to the service selected in reasoning translation settings. Translate all includes both shared and DSH skills. Translations are cached using its target language.",
|
|
94
100
|
"translationError": "Could not translate. The original is shown. Paid services require a Session and are unavailable here.",
|
|
95
101
|
"saveError": "Could not save the setting. Close and reopen this section to check the saved state before trying again."
|
|
96
102
|
}
|
|
@@ -108,6 +114,9 @@ var ko_default = {
|
|
|
108
114
|
"dsh": "DSH 스킬",
|
|
109
115
|
"loading": "스킬을 불러오는 중입니다…",
|
|
110
116
|
"empty": "이 경로에서 로드된 스킬이 없습니다.",
|
|
117
|
+
"search": "스킬 검색",
|
|
118
|
+
"searchPlaceholder": "이름, 설명 또는 경로로 검색",
|
|
119
|
+
"noResults": "검색 조건에 맞는 스킬이 없습니다.",
|
|
111
120
|
"error": "스킬을 불러오지 못했습니다. 이 설정 항목을 닫았다가 다시 열어 주세요.",
|
|
112
121
|
"incomplete": "일부 스킬 소스를 불러오지 못해 목록이 완전하지 않을 수 있습니다.",
|
|
113
122
|
"use": "사용",
|
|
@@ -121,7 +130,10 @@ var ko_default = {
|
|
|
121
130
|
"original": "원문 보기",
|
|
122
131
|
"retry": "다시 시도",
|
|
123
132
|
"translating": "번역 중…",
|
|
124
|
-
"
|
|
133
|
+
"translateAll": "전체 스킬 번역",
|
|
134
|
+
"translatingAll": "전체 스킬 번역 중…",
|
|
135
|
+
"translationAllError": "일부 스킬 설명을 번역하지 못했습니다. 다시 시도하면 실패한 항목만 번역합니다.",
|
|
136
|
+
"translationNotice": "스킬을 펼치거나 전체 스킬 번역을 누르면 사고 과정 번역 설정에서 선택한 서비스로 설명을 전송합니다. 전체 번역에는 공용 스킬과 DSH 스킬이 모두 포함됩니다. 번역문은 해당 설정의 대상 언어에 따라 캐시에 저장합니다.",
|
|
125
137
|
"translationError": "번역하지 못해 원문을 표시합니다. 유료 서비스는 세션이 필요하므로 이 화면에서 사용할 수 없습니다.",
|
|
126
138
|
"saveError": "설정을 저장하지 못했습니다. 이 설정 항목을 닫았다가 다시 열어 저장 상태를 확인한 후 다시 시도해 주세요."
|
|
127
139
|
}
|
|
@@ -139,6 +151,9 @@ var zh_default = {
|
|
|
139
151
|
"dsh": "DSH 技能",
|
|
140
152
|
"loading": "正在加载技能…",
|
|
141
153
|
"empty": "未从此目录加载任何技能。",
|
|
154
|
+
"search": "搜索技能",
|
|
155
|
+
"searchPlaceholder": "按名称、描述或路径搜索",
|
|
156
|
+
"noResults": "没有符合搜索条件的技能。",
|
|
142
157
|
"error": "无法加载技能。请关闭并重新打开此设置项后重试。",
|
|
143
158
|
"incomplete": "部分技能源无法加载,列表可能不完整。",
|
|
144
159
|
"use": "使用",
|
|
@@ -152,7 +167,10 @@ var zh_default = {
|
|
|
152
167
|
"original": "查看原文",
|
|
153
168
|
"retry": "重试",
|
|
154
169
|
"translating": "正在翻译…",
|
|
155
|
-
"
|
|
170
|
+
"translateAll": "翻译全部技能",
|
|
171
|
+
"translatingAll": "正在翻译全部技能…",
|
|
172
|
+
"translationAllError": "部分技能描述翻译失败。重试时仅翻译失败的项目。",
|
|
173
|
+
"translationNotice": "展开技能或点击翻译全部技能时,会将描述发送至思考过程翻译设置中选择的服务。全部翻译包括共享技能和 DSH 技能。译文按该设置的目标语言缓存。",
|
|
156
174
|
"translationError": "翻译失败,已显示原文。付费服务需要会话,无法在此页面使用。",
|
|
157
175
|
"saveError": "无法保存设置。请关闭并重新打开此设置项,确认已保存的状态后重试。"
|
|
158
176
|
}
|
|
@@ -174,6 +192,7 @@ const styles = `
|
|
|
174
192
|
.dsh-skills-settings { container-type: inline-size; color: var(--dsw-alias-label-primary); font: 14px/22px var(--dsw-font-family, system-ui); }
|
|
175
193
|
.dsh-skills-settings p { margin: 4px 0; }
|
|
176
194
|
.dsh-skills-settings-tabs { margin: 20px 0 12px; }
|
|
195
|
+
.dsh-skills-search { width: 100%; box-sizing: border-box; margin-bottom: 12px; }
|
|
177
196
|
.dsh-skills-settings .dsh-skills-muted { color: var(--dsw-alias-label-secondary); }
|
|
178
197
|
.dsh-skills-settings ul { list-style: none; margin: 0; padding: 0; }
|
|
179
198
|
.dsh-skills-settings code { font-size: 12px; overflow-wrap: anywhere; }
|
|
@@ -197,52 +216,29 @@ const styles = `
|
|
|
197
216
|
.dsh-skills-open-error { grid-column: 1 / -1; padding: 0 0 16px 28px; }
|
|
198
217
|
.dsh-skills-list-header { display: flex; justify-content: space-between; gap: 16px; padding: 8px 0; border-bottom: .5px solid var(--dsw-alias-border-l2); }
|
|
199
218
|
`;
|
|
200
|
-
|
|
219
|
+
const translationKey = (skill, language) => JSON.stringify([
|
|
220
|
+
language,
|
|
221
|
+
skill.path,
|
|
222
|
+
skill.description
|
|
223
|
+
]);
|
|
224
|
+
function SkillDescription({ skill, language, available, expanded, translation, translate }) {
|
|
201
225
|
const text = localizedCopy(language);
|
|
202
|
-
const [translated, setTranslated] = (0, react.useState)();
|
|
203
226
|
const [original, setOriginal] = (0, react.useState)(false);
|
|
204
|
-
const
|
|
205
|
-
const [failed, setFailed] = (0, react.useState)(false);
|
|
206
|
-
const [retry, setRetry] = (0, react.useState)(0);
|
|
227
|
+
const { value: translated, pending, failed } = translation ?? {};
|
|
207
228
|
(0, react.useEffect)(() => {
|
|
208
|
-
|
|
209
|
-
setOriginal(false);
|
|
210
|
-
setPending(false);
|
|
211
|
-
setFailed(false);
|
|
212
|
-
if (!expanded || !available || !skill.path || !skill.description) return;
|
|
213
|
-
const request = new AbortController();
|
|
214
|
-
setPending(true);
|
|
215
|
-
(async () => {
|
|
216
|
-
try {
|
|
217
|
-
const result = await connection.rpc.call(channel, translateMethod, {
|
|
218
|
-
path: skill.path,
|
|
219
|
-
language
|
|
220
|
-
}, request.signal);
|
|
221
|
-
if (request.signal.aborted) return;
|
|
222
|
-
if (!result.ok || typeof result.value !== "string") throw new Error("Could not translate description");
|
|
223
|
-
setTranslated(result.value);
|
|
224
|
-
} catch {
|
|
225
|
-
if (!request.signal.aborted) setFailed(true);
|
|
226
|
-
} finally {
|
|
227
|
-
if (!request.signal.aborted) setPending(false);
|
|
228
|
-
}
|
|
229
|
-
})();
|
|
230
|
-
return () => request.abort();
|
|
229
|
+
if (expanded && available) translate(skill);
|
|
231
230
|
}, [
|
|
232
231
|
expanded,
|
|
233
|
-
skill.description,
|
|
234
|
-
skill.path,
|
|
235
|
-
language,
|
|
236
232
|
available,
|
|
237
|
-
|
|
238
|
-
|
|
233
|
+
skill,
|
|
234
|
+
translate
|
|
239
235
|
]);
|
|
240
236
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: original || translated === void 0 ? skill.description : translated }), available && skill.path && skill.description && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
241
237
|
pending && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
242
238
|
role: "status",
|
|
243
239
|
children: text.translating
|
|
244
240
|
}),
|
|
245
|
-
translated !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
241
|
+
translated !== void 0 && translated !== skill.description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
246
242
|
variant: "ghost",
|
|
247
243
|
size: "sm",
|
|
248
244
|
onClick: () => setOriginal((value) => !value),
|
|
@@ -254,7 +250,7 @@ function SkillDescription({ skill, connection, language, available, expanded })
|
|
|
254
250
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
255
251
|
variant: "ghost",
|
|
256
252
|
size: "sm",
|
|
257
|
-
onClick: () =>
|
|
253
|
+
onClick: () => void translate(skill),
|
|
258
254
|
children: text.retry
|
|
259
255
|
})] })
|
|
260
256
|
] })] });
|
|
@@ -274,11 +270,89 @@ function SkillsSettings({ ctx }) {
|
|
|
274
270
|
const mounted = (0, react.useRef)(false);
|
|
275
271
|
const [expanded, setExpanded] = (0, react.useState)({});
|
|
276
272
|
const [source, setSource] = (0, react.useState)("user-agents");
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
273
|
+
const [query, setQuery] = (0, react.useState)("");
|
|
274
|
+
const [, refreshTranslations] = (0, react.useState)(0);
|
|
275
|
+
const translations = (0, react.useMemo)(() => ({
|
|
276
|
+
entries: /* @__PURE__ */ new Map(),
|
|
277
|
+
requests: /* @__PURE__ */ new Map(),
|
|
278
|
+
controllers: /* @__PURE__ */ new Set(),
|
|
279
|
+
bulk: false,
|
|
280
|
+
active: true
|
|
281
|
+
}), [connection, locale.active]);
|
|
282
|
+
(0, react.useEffect)(() => {
|
|
283
|
+
translations.active = true;
|
|
284
|
+
return () => {
|
|
285
|
+
translations.active = false;
|
|
286
|
+
for (const controller of translations.controllers) controller.abort();
|
|
287
|
+
};
|
|
288
|
+
}, [translations]);
|
|
289
|
+
const translate = (0, react.useCallback)((skill) => {
|
|
290
|
+
if (!skill.path || !skill.description) return Promise.resolve();
|
|
291
|
+
const key = translationKey(skill, locale.active);
|
|
292
|
+
const existing = translations.requests.get(key);
|
|
293
|
+
if (existing) return existing;
|
|
294
|
+
if (translations.entries.get(key)?.value !== void 0) return Promise.resolve();
|
|
295
|
+
const controller = new AbortController();
|
|
296
|
+
translations.controllers.add(controller);
|
|
297
|
+
translations.entries.set(key, { pending: true });
|
|
298
|
+
refreshTranslations((value) => value + 1);
|
|
299
|
+
const request = (async () => {
|
|
300
|
+
try {
|
|
301
|
+
const result = await connection.rpc.call(channel, translateMethod, {
|
|
302
|
+
path: skill.path,
|
|
303
|
+
language: locale.active
|
|
304
|
+
}, controller.signal);
|
|
305
|
+
if (!result.ok || typeof result.value !== "string") throw new Error("Could not translate description");
|
|
306
|
+
if (!controller.signal.aborted) translations.entries.set(key, { value: result.value });
|
|
307
|
+
} catch {
|
|
308
|
+
if (!controller.signal.aborted) translations.entries.set(key, { failed: true });
|
|
309
|
+
} finally {
|
|
310
|
+
translations.requests.delete(key);
|
|
311
|
+
translations.controllers.delete(controller);
|
|
312
|
+
if (translations.active && !controller.signal.aborted) refreshTranslations((value) => value + 1);
|
|
313
|
+
}
|
|
314
|
+
})();
|
|
315
|
+
translations.requests.set(key, request);
|
|
316
|
+
return request;
|
|
317
|
+
}, [
|
|
318
|
+
connection,
|
|
319
|
+
locale.active,
|
|
320
|
+
translations
|
|
321
|
+
]);
|
|
322
|
+
async function translateAll() {
|
|
323
|
+
if (translations.bulk || !view?.translationAvailable) return;
|
|
324
|
+
translations.bulk = true;
|
|
325
|
+
refreshTranslations((value) => value + 1);
|
|
326
|
+
try {
|
|
327
|
+
for (const skill of view.skills) {
|
|
328
|
+
if (!translations.active) break;
|
|
329
|
+
await translate(skill);
|
|
330
|
+
}
|
|
331
|
+
} finally {
|
|
332
|
+
translations.bulk = false;
|
|
333
|
+
if (translations.active) refreshTranslations((value) => value + 1);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const normalizeSearch = (value) => value.normalize("NFKC").toLowerCase();
|
|
337
|
+
const searchTerms = normalizeSearch(query).trim().split(/\s+/u).filter(Boolean);
|
|
338
|
+
const groups = ["user-agents", "user-dsh"].map((value) => {
|
|
339
|
+
const skills = view?.skills.filter((skill) => skill.source === value) ?? [];
|
|
340
|
+
return {
|
|
341
|
+
value,
|
|
342
|
+
label: value === "user-agents" ? text.agents : text.dsh,
|
|
343
|
+
total: skills.length,
|
|
344
|
+
skills: skills.filter((skill) => {
|
|
345
|
+
const fields = [
|
|
346
|
+
skill.name,
|
|
347
|
+
skill.description,
|
|
348
|
+
skill.path ?? "",
|
|
349
|
+
translations.entries.get(translationKey(skill, locale.active))?.value ?? ""
|
|
350
|
+
].map(normalizeSearch);
|
|
351
|
+
return searchTerms.every((term) => fields.some((field) => field.includes(term)));
|
|
352
|
+
})
|
|
353
|
+
};
|
|
354
|
+
});
|
|
355
|
+
const groupCount = (group) => searchTerms.length ? `${group.skills.length}/${group.total}` : `${group.total}`;
|
|
282
356
|
(0, react.useEffect)(() => {
|
|
283
357
|
const controller = new AbortController();
|
|
284
358
|
mounted.current = true;
|
|
@@ -357,9 +431,30 @@ function SkillsSettings({ ctx }) {
|
|
|
357
431
|
className: "dsh-skills-muted",
|
|
358
432
|
children: text.openFolderUnavailable
|
|
359
433
|
}),
|
|
360
|
-
view?.translationAvailable && /* @__PURE__ */ (0, react_jsx_runtime.
|
|
361
|
-
className: "dsh-skills-
|
|
362
|
-
children:
|
|
434
|
+
view?.translationAvailable && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
435
|
+
className: "dsh-skills-translation-toolbar",
|
|
436
|
+
children: [
|
|
437
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
438
|
+
className: "dsh-skills-muted",
|
|
439
|
+
children: text.translationNotice
|
|
440
|
+
}),
|
|
441
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
442
|
+
variant: "ghost",
|
|
443
|
+
size: "sm",
|
|
444
|
+
disabled: translations.bulk || !view.skills.some((skill) => skill.path && skill.description),
|
|
445
|
+
"aria-busy": translations.bulk,
|
|
446
|
+
onClick: () => void translateAll(),
|
|
447
|
+
children: translations.bulk ? text.translatingAll : text.translateAll
|
|
448
|
+
}),
|
|
449
|
+
translations.bulk && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
450
|
+
role: "status",
|
|
451
|
+
children: text.translatingAll
|
|
452
|
+
}),
|
|
453
|
+
!translations.bulk && [...translations.entries.values()].some((entry) => entry.failed) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
454
|
+
role: "alert",
|
|
455
|
+
children: text.translationAllError
|
|
456
|
+
})
|
|
457
|
+
]
|
|
363
458
|
}),
|
|
364
459
|
!view && !error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
365
460
|
role: "status",
|
|
@@ -377,112 +472,126 @@ function SkillsSettings({ ctx }) {
|
|
|
377
472
|
role: "alert",
|
|
378
473
|
children: text.incomplete
|
|
379
474
|
}),
|
|
380
|
-
view && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
475
|
+
view && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
476
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedControl, {
|
|
477
|
+
id,
|
|
478
|
+
className: "dsh-skills-settings-tabs",
|
|
479
|
+
value: source,
|
|
480
|
+
options: groups.map((group) => ({
|
|
481
|
+
value: group.value,
|
|
482
|
+
label: `${group.label} ${groupCount(group)}`
|
|
483
|
+
})),
|
|
484
|
+
onChange: setSource,
|
|
485
|
+
label: text.nav
|
|
486
|
+
}),
|
|
487
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
488
|
+
className: "dsh-skills-search",
|
|
489
|
+
type: "search",
|
|
490
|
+
value: query,
|
|
491
|
+
"aria-label": text.search,
|
|
492
|
+
placeholder: text.searchPlaceholder,
|
|
493
|
+
autoComplete: "off",
|
|
494
|
+
onChange: (event) => setQuery(event.target.value)
|
|
495
|
+
}),
|
|
496
|
+
groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
497
|
+
id: `${id}-${group.value}-panel`,
|
|
498
|
+
role: "tabpanel",
|
|
499
|
+
"aria-labelledby": `${id}-${group.value}`,
|
|
500
|
+
hidden: source !== group.value,
|
|
501
|
+
tabIndex: 0,
|
|
502
|
+
children: group.skills.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
503
|
+
className: "dsh-skills-muted",
|
|
504
|
+
children: group.total > 0 && searchTerms.length ? text.noResults : text.empty
|
|
505
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
506
|
+
className: "dsh-skills-list-header dsh-skills-muted",
|
|
507
|
+
"aria-hidden": "true",
|
|
508
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
509
|
+
text.nav,
|
|
510
|
+
" ",
|
|
511
|
+
groupCount(group)
|
|
512
|
+
] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text.use })]
|
|
513
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", { children: group.skills.map((skill) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
|
|
514
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
515
|
+
open: expanded[skill.path ?? skill.name] ?? false,
|
|
516
|
+
onToggle: (event) => {
|
|
517
|
+
const open = event.currentTarget.open;
|
|
518
|
+
setExpanded((current) => ({
|
|
519
|
+
...current,
|
|
520
|
+
[skill.path ?? skill.name]: open
|
|
521
|
+
}));
|
|
522
|
+
},
|
|
523
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
524
|
+
"aria-label": skill.name,
|
|
525
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, {
|
|
526
|
+
size: 16,
|
|
527
|
+
"aria-hidden": "true"
|
|
528
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
529
|
+
className: "dsh-skills-summary-text",
|
|
530
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
531
|
+
className: "dsh-skills-title",
|
|
532
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: skill.name }), view.disabled.includes(skill.name) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
533
|
+
className: "dsh-skills-muted",
|
|
534
|
+
children: text.disabled
|
|
535
|
+
})]
|
|
536
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
537
|
+
className: "dsh-skills-preview dsh-skills-muted",
|
|
538
|
+
"aria-hidden": "true",
|
|
539
|
+
children: translations.entries.get(translationKey(skill, locale.active))?.value ?? skill.description
|
|
428
540
|
})]
|
|
429
|
-
})
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
541
|
+
})]
|
|
542
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
543
|
+
className: "dsh-skills-detail",
|
|
544
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SkillDescription, {
|
|
545
|
+
skill,
|
|
546
|
+
translation: translations.entries.get(translationKey(skill, locale.active)),
|
|
547
|
+
translate,
|
|
548
|
+
language: locale.active,
|
|
549
|
+
available: view.translationAvailable && source === group.value,
|
|
550
|
+
expanded: expanded[skill.path ?? skill.name] ?? false
|
|
551
|
+
}, translationKey(skill, locale.active)), skill.path && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
552
|
+
className: "dsh-skills-muted",
|
|
553
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: skill.path })
|
|
433
554
|
})]
|
|
434
555
|
})]
|
|
435
|
-
}),
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
size: "sm",
|
|
459
|
-
"aria-label": `${folderStatus[skill.path] === "opening" ? text.openingFolder : text.openFolder}: ${skill.name}`,
|
|
460
|
-
"aria-busy": folderStatus[skill.path] === "opening",
|
|
461
|
-
disabled: !view.folderOpenAvailable || folderStatus[skill.path] === "opening",
|
|
462
|
-
"aria-description": view.folderOpenAvailable ? text.openFolderHint : text.openFolderUnavailable,
|
|
463
|
-
onClick: () => void openFolder(skill.path),
|
|
464
|
-
icon: folderStatus[skill.path] === "opening" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutlineRegular, {
|
|
465
|
-
size: 16,
|
|
466
|
-
"aria-hidden": "true"
|
|
467
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutlineRegular, {
|
|
468
|
-
size: 16,
|
|
469
|
-
"aria-hidden": "true"
|
|
556
|
+
}),
|
|
557
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
558
|
+
className: "dsh-skills-actions",
|
|
559
|
+
children: [skill.path && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
560
|
+
label: folderStatus[skill.path] === "opening" ? text.openingFolder : text.openFolder,
|
|
561
|
+
side: "top",
|
|
562
|
+
portal: true,
|
|
563
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
564
|
+
className: "dsh-skills-folder",
|
|
565
|
+
variant: "ghost",
|
|
566
|
+
size: "sm",
|
|
567
|
+
"aria-label": `${folderStatus[skill.path] === "opening" ? text.openingFolder : text.openFolder}: ${skill.name}`,
|
|
568
|
+
"aria-busy": folderStatus[skill.path] === "opening",
|
|
569
|
+
disabled: !view.folderOpenAvailable || folderStatus[skill.path] === "opening",
|
|
570
|
+
"aria-description": view.folderOpenAvailable ? text.openFolderHint : text.openFolderUnavailable,
|
|
571
|
+
onClick: () => void openFolder(skill.path),
|
|
572
|
+
icon: folderStatus[skill.path] === "opening" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutlineRegular, {
|
|
573
|
+
size: 16,
|
|
574
|
+
"aria-hidden": "true"
|
|
575
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutlineRegular, {
|
|
576
|
+
size: 16,
|
|
577
|
+
"aria-hidden": "true"
|
|
578
|
+
})
|
|
470
579
|
})
|
|
471
|
-
})
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
})
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
})
|
|
484
|
-
|
|
485
|
-
|
|
580
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
581
|
+
label: `${text.use}: ${skill.name}`,
|
|
582
|
+
checked: !view.disabled.includes(skill.name),
|
|
583
|
+
disabled: busy || saveError,
|
|
584
|
+
onChange: (enabled) => void save(skill.name, !enabled)
|
|
585
|
+
})]
|
|
586
|
+
}),
|
|
587
|
+
skill.path && folderStatus[skill.path] === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
588
|
+
className: "dsh-skills-open-error",
|
|
589
|
+
role: "alert",
|
|
590
|
+
children: text.openFolderError
|
|
591
|
+
})
|
|
592
|
+
] }, skill.path ?? skill.name)) })] })
|
|
593
|
+
}, group.value))
|
|
594
|
+
] })
|
|
486
595
|
]
|
|
487
596
|
});
|
|
488
597
|
}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,8 @@ import { dshCachePath } from "@deepseek-ai/dsh-home-paths";
|
|
|
7
7
|
import { canOpenNativePath, openNativePath } from "@deepseek-ai/dsh-native-command";
|
|
8
8
|
import { SkillRegistry } from "@deepseek-ai/dsh-skill";
|
|
9
9
|
import { FileSystemSkillProvider } from "@deepseek-ai/dsh-skill-filesystem";
|
|
10
|
+
import { francAll } from "franc-min";
|
|
11
|
+
import { iso6393 } from "iso-639-3";
|
|
10
12
|
// ../../node_modules/.pnpm/@deepseek-ai+cosmokit@1.9.0/node_modules/@deepseek-ai/cosmokit/lib/index.js
|
|
11
13
|
/** Return true when a value is `null` or `undefined`. */
|
|
12
14
|
function isNullable(value) {
|
|
@@ -898,6 +900,23 @@ const method = "dungsil-ui-setting-skills/list";
|
|
|
898
900
|
const saveMethod = "dungsil-ui-setting-skills/save";
|
|
899
901
|
const translateMethod = "dungsil-ui-setting-skills/translate";
|
|
900
902
|
const openFolderMethod = "dungsil-ui-setting-skills/open-folder";
|
|
903
|
+
// src/language.ts
|
|
904
|
+
const languageCodes = new Map(iso6393.map((entry) => [entry.iso6393, entry.iso6391 ?? entry.iso6393]));
|
|
905
|
+
languageCodes.set("cmn", "zh");
|
|
906
|
+
/** Only skip a provider request when local detection has a clear winner. */
|
|
907
|
+
function matchesTargetLanguage(text, targetLanguage) {
|
|
908
|
+
let target;
|
|
909
|
+
try {
|
|
910
|
+
target = new Intl.Locale(targetLanguage.replaceAll("_", "-"));
|
|
911
|
+
} catch {
|
|
912
|
+
return false;
|
|
913
|
+
}
|
|
914
|
+
if (target.script || target.language === "zh" && target.region) return false;
|
|
915
|
+
if ((text.match(/\p{L}/gu)?.length ?? 0) < 10) return false;
|
|
916
|
+
const [first, second] = francAll(text);
|
|
917
|
+
if (!first || first[0] === "und" || second && first[1] - second[1] < .2) return false;
|
|
918
|
+
return languageCodes.get(first[0]) === target.language;
|
|
919
|
+
}
|
|
901
920
|
// src/index.ts
|
|
902
921
|
const name = "dungsil-ui-setting-skills";
|
|
903
922
|
const inject = ["connection", "configEditor"];
|
|
@@ -1010,8 +1029,8 @@ function apply(ctx, config = {}) {
|
|
|
1010
1029
|
skill.description
|
|
1011
1030
|
])).digest("hex");
|
|
1012
1031
|
const cachePath = join(cacheDir, `${key}.json`);
|
|
1013
|
-
let value;
|
|
1014
|
-
try {
|
|
1032
|
+
let value = matchesTargetLanguage(skill.description, targetLanguage) ? skill.description : void 0;
|
|
1033
|
+
if (value === void 0) try {
|
|
1015
1034
|
const cached = JSON.parse(await readFile(cachePath, "utf8"));
|
|
1016
1035
|
if (typeof cached === "string") value = cached;
|
|
1017
1036
|
} catch {}
|
package/locale/en.json
CHANGED
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
"dsh": "DSH skills",
|
|
11
11
|
"loading": "Loading skills…",
|
|
12
12
|
"empty": "No loaded skills from this source.",
|
|
13
|
+
"search": "Search skills",
|
|
14
|
+
"searchPlaceholder": "Search by name, description, or path",
|
|
15
|
+
"noResults": "No skills match your search.",
|
|
13
16
|
"error": "Could not load skills. Close and reopen this settings section to try again.",
|
|
14
17
|
"incomplete": "Some skill sources could not be loaded. This list may be incomplete.",
|
|
15
18
|
"use": "Use",
|
|
@@ -23,7 +26,10 @@
|
|
|
23
26
|
"original": "View original",
|
|
24
27
|
"retry": "Retry",
|
|
25
28
|
"translating": "Translating…",
|
|
26
|
-
"
|
|
29
|
+
"translateAll": "Translate all skills",
|
|
30
|
+
"translatingAll": "Translating all skills…",
|
|
31
|
+
"translationAllError": "Some skill descriptions could not be translated. Try again to translate only the failed items.",
|
|
32
|
+
"translationNotice": "Expanding a skill or translating all skills sends descriptions to the service selected in reasoning translation settings. Translate all includes both shared and DSH skills. Translations are cached using its target language.",
|
|
27
33
|
"translationError": "Could not translate. The original is shown. Paid services require a Session and are unavailable here.",
|
|
28
34
|
"saveError": "Could not save the setting. Close and reopen this section to check the saved state before trying again."
|
|
29
35
|
}
|
package/locale/ko.json
CHANGED
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
"dsh": "DSH 스킬",
|
|
11
11
|
"loading": "스킬을 불러오는 중입니다…",
|
|
12
12
|
"empty": "이 경로에서 로드된 스킬이 없습니다.",
|
|
13
|
+
"search": "스킬 검색",
|
|
14
|
+
"searchPlaceholder": "이름, 설명 또는 경로로 검색",
|
|
15
|
+
"noResults": "검색 조건에 맞는 스킬이 없습니다.",
|
|
13
16
|
"error": "스킬을 불러오지 못했습니다. 이 설정 항목을 닫았다가 다시 열어 주세요.",
|
|
14
17
|
"incomplete": "일부 스킬 소스를 불러오지 못해 목록이 완전하지 않을 수 있습니다.",
|
|
15
18
|
"use": "사용",
|
|
@@ -23,7 +26,10 @@
|
|
|
23
26
|
"original": "원문 보기",
|
|
24
27
|
"retry": "다시 시도",
|
|
25
28
|
"translating": "번역 중…",
|
|
26
|
-
"
|
|
29
|
+
"translateAll": "전체 스킬 번역",
|
|
30
|
+
"translatingAll": "전체 스킬 번역 중…",
|
|
31
|
+
"translationAllError": "일부 스킬 설명을 번역하지 못했습니다. 다시 시도하면 실패한 항목만 번역합니다.",
|
|
32
|
+
"translationNotice": "스킬을 펼치거나 전체 스킬 번역을 누르면 사고 과정 번역 설정에서 선택한 서비스로 설명을 전송합니다. 전체 번역에는 공용 스킬과 DSH 스킬이 모두 포함됩니다. 번역문은 해당 설정의 대상 언어에 따라 캐시에 저장합니다.",
|
|
27
33
|
"translationError": "번역하지 못해 원문을 표시합니다. 유료 서비스는 세션이 필요하므로 이 화면에서 사용할 수 없습니다.",
|
|
28
34
|
"saveError": "설정을 저장하지 못했습니다. 이 설정 항목을 닫았다가 다시 열어 저장 상태를 확인한 후 다시 시도해 주세요."
|
|
29
35
|
}
|
package/locale/zh.json
CHANGED
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
"dsh": "DSH 技能",
|
|
11
11
|
"loading": "正在加载技能…",
|
|
12
12
|
"empty": "未从此目录加载任何技能。",
|
|
13
|
+
"search": "搜索技能",
|
|
14
|
+
"searchPlaceholder": "按名称、描述或路径搜索",
|
|
15
|
+
"noResults": "没有符合搜索条件的技能。",
|
|
13
16
|
"error": "无法加载技能。请关闭并重新打开此设置项后重试。",
|
|
14
17
|
"incomplete": "部分技能源无法加载,列表可能不完整。",
|
|
15
18
|
"use": "使用",
|
|
@@ -23,7 +26,10 @@
|
|
|
23
26
|
"original": "查看原文",
|
|
24
27
|
"retry": "重试",
|
|
25
28
|
"translating": "正在翻译…",
|
|
26
|
-
"
|
|
29
|
+
"translateAll": "翻译全部技能",
|
|
30
|
+
"translatingAll": "正在翻译全部技能…",
|
|
31
|
+
"translationAllError": "部分技能描述翻译失败。重试时仅翻译失败的项目。",
|
|
32
|
+
"translationNotice": "展开技能或点击翻译全部技能时,会将描述发送至思考过程翻译设置中选择的服务。全部翻译包括共享技能和 DSH 技能。译文按该设置的目标语言缓存。",
|
|
27
33
|
"translationError": "翻译失败,已显示原文。付费服务需要会话,无法在此页面使用。",
|
|
28
34
|
"saveError": "无法保存设置。请关闭并重新打开此设置项,确认已保存的状态后重试。"
|
|
29
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dungsil/dsh-plugin-ui-setting-skills",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "View loaded user skills in DeepSeek Harness settings.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -27,7 +27,9 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@deepseek-ai/dsh-atomic-write": "0.2.2-rc.1",
|
|
29
29
|
"@deepseek-ai/dsh-home-paths": "0.2.2-rc.1",
|
|
30
|
-
"@deepseek-ai/dsh-native-command": "0.2.2-rc.1"
|
|
30
|
+
"@deepseek-ai/dsh-native-command": "0.2.2-rc.1",
|
|
31
|
+
"franc-min": "6.2.0",
|
|
32
|
+
"iso-639-3": "3.0.1"
|
|
31
33
|
},
|
|
32
34
|
"devDependencies": {
|
|
33
35
|
"@deepseek-ai/cordis": "4.1.0",
|