@dungsil/dsh-plugin-ui-setting-skills 0.3.1 → 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 +260 -150
- package/dist/index.js +23 -4
- package/locale/en.json +7 -1
- package/locale/ko.json +7 -1
- package/locale/zh.json +7 -1
- package/package.json +24 -22
package/dist/client.js
CHANGED
|
@@ -13,12 +13,13 @@ function installStyles(css) {
|
|
|
13
13
|
return () => style.remove();
|
|
14
14
|
}
|
|
15
15
|
// ../../tools/ui/src/settings.tsx
|
|
16
|
-
/**
|
|
16
|
+
/** Decorate matching navigation rows in both the rc.5 and 0.2.2 settings shells. */
|
|
17
17
|
function installSettingsIcon(id, labels, icon) {
|
|
18
18
|
const attribute = "data-dsh-settings-icon";
|
|
19
19
|
const selector = `[${attribute}="${id}"]`;
|
|
20
20
|
const removeStyles = installStyles(`
|
|
21
|
-
${selector} > svg
|
|
21
|
+
${selector} > svg,
|
|
22
|
+
${selector} > [aria-hidden="true"]:not([data-dsh-settings-icon-glyph]) { display: none; }
|
|
22
23
|
${typeof icon === "string" ? `${selector}::before { content: ''; display: block; flex: none; width: 16px; height: 16px; background: currentColor; mask: url("data:image/svg+xml,${encodeURIComponent(icon)}") center / contain no-repeat; }` : ""}
|
|
23
24
|
${selector} > [data-dsh-settings-icon-glyph] { display: inline-flex; flex: none; }
|
|
24
25
|
`);
|
|
@@ -76,6 +77,9 @@ var en_default = {
|
|
|
76
77
|
"dsh": "DSH skills",
|
|
77
78
|
"loading": "Loading skills…",
|
|
78
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.",
|
|
79
83
|
"error": "Could not load skills. Close and reopen this settings section to try again.",
|
|
80
84
|
"incomplete": "Some skill sources could not be loaded. This list may be incomplete.",
|
|
81
85
|
"use": "Use",
|
|
@@ -89,7 +93,10 @@ var en_default = {
|
|
|
89
93
|
"original": "View original",
|
|
90
94
|
"retry": "Retry",
|
|
91
95
|
"translating": "Translating…",
|
|
92
|
-
"
|
|
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.",
|
|
93
100
|
"translationError": "Could not translate. The original is shown. Paid services require a Session and are unavailable here.",
|
|
94
101
|
"saveError": "Could not save the setting. Close and reopen this section to check the saved state before trying again."
|
|
95
102
|
}
|
|
@@ -107,6 +114,9 @@ var ko_default = {
|
|
|
107
114
|
"dsh": "DSH 스킬",
|
|
108
115
|
"loading": "스킬을 불러오는 중입니다…",
|
|
109
116
|
"empty": "이 경로에서 로드된 스킬이 없습니다.",
|
|
117
|
+
"search": "스킬 검색",
|
|
118
|
+
"searchPlaceholder": "이름, 설명 또는 경로로 검색",
|
|
119
|
+
"noResults": "검색 조건에 맞는 스킬이 없습니다.",
|
|
110
120
|
"error": "스킬을 불러오지 못했습니다. 이 설정 항목을 닫았다가 다시 열어 주세요.",
|
|
111
121
|
"incomplete": "일부 스킬 소스를 불러오지 못해 목록이 완전하지 않을 수 있습니다.",
|
|
112
122
|
"use": "사용",
|
|
@@ -120,7 +130,10 @@ var ko_default = {
|
|
|
120
130
|
"original": "원문 보기",
|
|
121
131
|
"retry": "다시 시도",
|
|
122
132
|
"translating": "번역 중…",
|
|
123
|
-
"
|
|
133
|
+
"translateAll": "전체 스킬 번역",
|
|
134
|
+
"translatingAll": "전체 스킬 번역 중…",
|
|
135
|
+
"translationAllError": "일부 스킬 설명을 번역하지 못했습니다. 다시 시도하면 실패한 항목만 번역합니다.",
|
|
136
|
+
"translationNotice": "스킬을 펼치거나 전체 스킬 번역을 누르면 사고 과정 번역 설정에서 선택한 서비스로 설명을 전송합니다. 전체 번역에는 공용 스킬과 DSH 스킬이 모두 포함됩니다. 번역문은 해당 설정의 대상 언어에 따라 캐시에 저장합니다.",
|
|
124
137
|
"translationError": "번역하지 못해 원문을 표시합니다. 유료 서비스는 세션이 필요하므로 이 화면에서 사용할 수 없습니다.",
|
|
125
138
|
"saveError": "설정을 저장하지 못했습니다. 이 설정 항목을 닫았다가 다시 열어 저장 상태를 확인한 후 다시 시도해 주세요."
|
|
126
139
|
}
|
|
@@ -138,6 +151,9 @@ var zh_default = {
|
|
|
138
151
|
"dsh": "DSH 技能",
|
|
139
152
|
"loading": "正在加载技能…",
|
|
140
153
|
"empty": "未从此目录加载任何技能。",
|
|
154
|
+
"search": "搜索技能",
|
|
155
|
+
"searchPlaceholder": "按名称、描述或路径搜索",
|
|
156
|
+
"noResults": "没有符合搜索条件的技能。",
|
|
141
157
|
"error": "无法加载技能。请关闭并重新打开此设置项后重试。",
|
|
142
158
|
"incomplete": "部分技能源无法加载,列表可能不完整。",
|
|
143
159
|
"use": "使用",
|
|
@@ -151,7 +167,10 @@ var zh_default = {
|
|
|
151
167
|
"original": "查看原文",
|
|
152
168
|
"retry": "重试",
|
|
153
169
|
"translating": "正在翻译…",
|
|
154
|
-
"
|
|
170
|
+
"translateAll": "翻译全部技能",
|
|
171
|
+
"translatingAll": "正在翻译全部技能…",
|
|
172
|
+
"translationAllError": "部分技能描述翻译失败。重试时仅翻译失败的项目。",
|
|
173
|
+
"translationNotice": "展开技能或点击翻译全部技能时,会将描述发送至思考过程翻译设置中选择的服务。全部翻译包括共享技能和 DSH 技能。译文按该设置的目标语言缓存。",
|
|
155
174
|
"translationError": "翻译失败,已显示原文。付费服务需要会话,无法在此页面使用。",
|
|
156
175
|
"saveError": "无法保存设置。请关闭并重新打开此设置项,确认已保存的状态后重试。"
|
|
157
176
|
}
|
|
@@ -173,6 +192,7 @@ const styles = `
|
|
|
173
192
|
.dsh-skills-settings { container-type: inline-size; color: var(--dsw-alias-label-primary); font: 14px/22px var(--dsw-font-family, system-ui); }
|
|
174
193
|
.dsh-skills-settings p { margin: 4px 0; }
|
|
175
194
|
.dsh-skills-settings-tabs { margin: 20px 0 12px; }
|
|
195
|
+
.dsh-skills-search { width: 100%; box-sizing: border-box; margin-bottom: 12px; }
|
|
176
196
|
.dsh-skills-settings .dsh-skills-muted { color: var(--dsw-alias-label-secondary); }
|
|
177
197
|
.dsh-skills-settings ul { list-style: none; margin: 0; padding: 0; }
|
|
178
198
|
.dsh-skills-settings code { font-size: 12px; overflow-wrap: anywhere; }
|
|
@@ -196,52 +216,29 @@ const styles = `
|
|
|
196
216
|
.dsh-skills-open-error { grid-column: 1 / -1; padding: 0 0 16px 28px; }
|
|
197
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); }
|
|
198
218
|
`;
|
|
199
|
-
|
|
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 }) {
|
|
200
225
|
const text = localizedCopy(language);
|
|
201
|
-
const [translated, setTranslated] = (0, react.useState)();
|
|
202
226
|
const [original, setOriginal] = (0, react.useState)(false);
|
|
203
|
-
const
|
|
204
|
-
const [failed, setFailed] = (0, react.useState)(false);
|
|
205
|
-
const [retry, setRetry] = (0, react.useState)(0);
|
|
227
|
+
const { value: translated, pending, failed } = translation ?? {};
|
|
206
228
|
(0, react.useEffect)(() => {
|
|
207
|
-
|
|
208
|
-
setOriginal(false);
|
|
209
|
-
setPending(false);
|
|
210
|
-
setFailed(false);
|
|
211
|
-
if (!expanded || !available || !skill.path || !skill.description) return;
|
|
212
|
-
const request = new AbortController();
|
|
213
|
-
setPending(true);
|
|
214
|
-
(async () => {
|
|
215
|
-
try {
|
|
216
|
-
const result = await connection.rpc.call(channel, translateMethod, {
|
|
217
|
-
path: skill.path,
|
|
218
|
-
language
|
|
219
|
-
}, request.signal);
|
|
220
|
-
if (request.signal.aborted) return;
|
|
221
|
-
if (!result.ok || typeof result.value !== "string") throw new Error("Could not translate description");
|
|
222
|
-
setTranslated(result.value);
|
|
223
|
-
} catch {
|
|
224
|
-
if (!request.signal.aborted) setFailed(true);
|
|
225
|
-
} finally {
|
|
226
|
-
if (!request.signal.aborted) setPending(false);
|
|
227
|
-
}
|
|
228
|
-
})();
|
|
229
|
-
return () => request.abort();
|
|
229
|
+
if (expanded && available) translate(skill);
|
|
230
230
|
}, [
|
|
231
231
|
expanded,
|
|
232
|
-
skill.description,
|
|
233
|
-
skill.path,
|
|
234
|
-
language,
|
|
235
232
|
available,
|
|
236
|
-
|
|
237
|
-
|
|
233
|
+
skill,
|
|
234
|
+
translate
|
|
238
235
|
]);
|
|
239
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: [
|
|
240
237
|
pending && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
241
238
|
role: "status",
|
|
242
239
|
children: text.translating
|
|
243
240
|
}),
|
|
244
|
-
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, {
|
|
245
242
|
variant: "ghost",
|
|
246
243
|
size: "sm",
|
|
247
244
|
onClick: () => setOriginal((value) => !value),
|
|
@@ -253,7 +250,7 @@ function SkillDescription({ skill, connection, language, available, expanded })
|
|
|
253
250
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
254
251
|
variant: "ghost",
|
|
255
252
|
size: "sm",
|
|
256
|
-
onClick: () =>
|
|
253
|
+
onClick: () => void translate(skill),
|
|
257
254
|
children: text.retry
|
|
258
255
|
})] })
|
|
259
256
|
] })] });
|
|
@@ -273,11 +270,89 @@ function SkillsSettings({ ctx }) {
|
|
|
273
270
|
const mounted = (0, react.useRef)(false);
|
|
274
271
|
const [expanded, setExpanded] = (0, react.useState)({});
|
|
275
272
|
const [source, setSource] = (0, react.useState)("user-agents");
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
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}`;
|
|
281
356
|
(0, react.useEffect)(() => {
|
|
282
357
|
const controller = new AbortController();
|
|
283
358
|
mounted.current = true;
|
|
@@ -356,9 +431,30 @@ function SkillsSettings({ ctx }) {
|
|
|
356
431
|
className: "dsh-skills-muted",
|
|
357
432
|
children: text.openFolderUnavailable
|
|
358
433
|
}),
|
|
359
|
-
view?.translationAvailable && /* @__PURE__ */ (0, react_jsx_runtime.
|
|
360
|
-
className: "dsh-skills-
|
|
361
|
-
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
|
+
]
|
|
362
458
|
}),
|
|
363
459
|
!view && !error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
364
460
|
role: "status",
|
|
@@ -376,112 +472,126 @@ function SkillsSettings({ ctx }) {
|
|
|
376
472
|
role: "alert",
|
|
377
473
|
children: text.incomplete
|
|
378
474
|
}),
|
|
379
|
-
view && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
380
|
-
|
|
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
|
-
|
|
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
|
|
427
540
|
})]
|
|
428
|
-
})
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
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 })
|
|
432
554
|
})]
|
|
433
555
|
})]
|
|
434
|
-
}),
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
size: "sm",
|
|
458
|
-
"aria-label": `${folderStatus[skill.path] === "opening" ? text.openingFolder : text.openFolder}: ${skill.name}`,
|
|
459
|
-
"aria-busy": folderStatus[skill.path] === "opening",
|
|
460
|
-
disabled: !view.folderOpenAvailable || folderStatus[skill.path] === "opening",
|
|
461
|
-
"aria-description": view.folderOpenAvailable ? text.openFolderHint : text.openFolderUnavailable,
|
|
462
|
-
onClick: () => void openFolder(skill.path),
|
|
463
|
-
icon: folderStatus[skill.path] === "opening" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconLoadingOutlineRegular, {
|
|
464
|
-
size: 16,
|
|
465
|
-
"aria-hidden": "true"
|
|
466
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutlineRegular, {
|
|
467
|
-
size: 16,
|
|
468
|
-
"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
|
+
})
|
|
469
579
|
})
|
|
470
|
-
})
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
})
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
})
|
|
483
|
-
|
|
484
|
-
|
|
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
|
+
] })
|
|
485
595
|
]
|
|
486
596
|
});
|
|
487
597
|
}
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,9 @@ 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
|
-
|
|
10
|
+
import { francAll } from "franc-min";
|
|
11
|
+
import { iso6393 } from "iso-639-3";
|
|
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) {
|
|
13
15
|
return value === null || value === void 0;
|
|
@@ -260,7 +262,7 @@ var Time;
|
|
|
260
262
|
}
|
|
261
263
|
Time.template = template;
|
|
262
264
|
})(Time || (Time = {}));
|
|
263
|
-
// ../../node_modules/.pnpm/@deepseek-ai+schemastery@3.
|
|
265
|
+
// ../../node_modules/.pnpm/@deepseek-ai+schemastery@3.19.0/node_modules/@deepseek-ai/schemastery/lib/index.mjs
|
|
264
266
|
const kSchema = Symbol.for("schemastery");
|
|
265
267
|
const kValidationError = Symbol.for("ValidationError");
|
|
266
268
|
globalThis.__schemastery_index__ ??= 0;
|
|
@@ -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": {
|
|
@@ -25,23 +25,25 @@
|
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.
|
|
29
|
-
"@deepseek-ai/dsh-home-paths": "0.2.
|
|
30
|
-
"@deepseek-ai/dsh-native-command": "0.2.
|
|
28
|
+
"@deepseek-ai/dsh-atomic-write": "0.2.2-rc.1",
|
|
29
|
+
"@deepseek-ai/dsh-home-paths": "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
|
-
"@deepseek-ai/cordis": "4.0
|
|
34
|
-
"@deepseek-ai/dsh-app-boot": "0.2.
|
|
35
|
-
"@deepseek-ai/dsh-client-connection": "0.2.
|
|
36
|
-
"@deepseek-ai/dsh-client-locale": "0.2.
|
|
37
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.2.
|
|
38
|
-
"@deepseek-ai/dsh-client-ui-settings": "0.2.
|
|
39
|
-
"@deepseek-ai/dsh-config-editor": "0.2.
|
|
40
|
-
"@deepseek-ai/dsh-credentials-local": "0.2.
|
|
41
|
-
"@deepseek-ai/dsh-experimental-client-ui-cot-translation": "0.2.
|
|
42
|
-
"@deepseek-ai/dsh-skill": "0.2.
|
|
43
|
-
"@deepseek-ai/dsh-skill-filesystem": "0.2.
|
|
44
|
-
"@deepseek-ai/schemastery": "3.
|
|
35
|
+
"@deepseek-ai/cordis": "4.1.0",
|
|
36
|
+
"@deepseek-ai/dsh-app-boot": "0.2.2-rc.1",
|
|
37
|
+
"@deepseek-ai/dsh-client-connection": "0.2.2-rc.1",
|
|
38
|
+
"@deepseek-ai/dsh-client-locale": "0.2.2-rc.1",
|
|
39
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.2-rc.1",
|
|
40
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.2.2-rc.1",
|
|
41
|
+
"@deepseek-ai/dsh-config-editor": "0.2.2-rc.1",
|
|
42
|
+
"@deepseek-ai/dsh-credentials-local": "0.2.2-rc.1",
|
|
43
|
+
"@deepseek-ai/dsh-experimental-client-ui-cot-translation": "0.2.2-rc.1",
|
|
44
|
+
"@deepseek-ai/dsh-skill": "0.2.2-rc.1",
|
|
45
|
+
"@deepseek-ai/dsh-skill-filesystem": "0.2.2-rc.1",
|
|
46
|
+
"@deepseek-ai/schemastery": "3.19.0",
|
|
45
47
|
"@dungsil/dsh-tsconfig": "0.0.0",
|
|
46
48
|
"@dungsil/dsh-tsdown": "0.0.0",
|
|
47
49
|
"@dungsil/dsh-ui": "0.0.0",
|
|
@@ -54,14 +56,14 @@
|
|
|
54
56
|
},
|
|
55
57
|
"peerDependencies": {
|
|
56
58
|
"@deepseek-ai/cordis": "^4.0.5",
|
|
57
|
-
"@deepseek-ai/dsh-client-connection": "^0.2.1-rc.5",
|
|
58
|
-
"@deepseek-ai/dsh-client-ui-primitives": "^0.2.1-rc.5",
|
|
59
|
-
"@deepseek-ai/dsh-config-editor": "^0.2.1-rc.5",
|
|
60
|
-
"@deepseek-ai/dsh-skill": "^0.2.1-rc.5",
|
|
61
|
-
"@deepseek-ai/dsh-skill-filesystem": "^0.2.1-rc.5"
|
|
59
|
+
"@deepseek-ai/dsh-client-connection": "^0.2.1-rc.5 || ^0.2.2-rc.1",
|
|
60
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.2.1-rc.5 || ^0.2.2-rc.1",
|
|
61
|
+
"@deepseek-ai/dsh-config-editor": "^0.2.1-rc.5 || ^0.2.2-rc.1",
|
|
62
|
+
"@deepseek-ai/dsh-skill": "^0.2.1-rc.5 || ^0.2.2-rc.1",
|
|
63
|
+
"@deepseek-ai/dsh-skill-filesystem": "^0.2.1-rc.5 || ^0.2.2-rc.1"
|
|
62
64
|
},
|
|
63
65
|
"engines": {
|
|
64
|
-
"dsh": "^0.2.1-rc.5",
|
|
66
|
+
"dsh": "^0.2.1-rc.5 || ^0.2.2-rc.1",
|
|
65
67
|
"node": ">=24.9.0"
|
|
66
68
|
},
|
|
67
69
|
"dsh": {
|