dsh-skill-hub 0.2.2 → 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 +10 -14
- package/README.zh.md +9 -12
- package/lib/client.js +367 -173
- package/lib/client.js.map +1 -1
- package/lib/types/client/SkillHubSettingsCard.d.ts +2 -6
- package/lib/types/client/icons.d.ts +25 -0
- package/lib/types/client/locales.d.ts +3 -3
- package/lib/types/client/panel/format.d.ts +10 -0
- package/lib/types/client/slash-dots.d.ts +57 -0
- package/package.json +68 -26
- package/src/client/SkillHubSettingsCard.tsx +4 -7
- package/src/client/icons.tsx +61 -0
- package/src/client/index.tsx +13 -1
- package/src/client/locales.ts +6 -6
- package/src/client/panel/SkillDetailView.tsx +6 -2
- package/src/client/panel/SkillHubPanel.tsx +1 -1
- package/src/client/panel/SkillRow.tsx +8 -3
- package/src/client/panel/format.ts +11 -0
- package/src/client/settings-card.tsx +1 -1
- package/src/client/slash-dots.test.ts +145 -0
- package/src/client/slash-dots.tsx +190 -0
|
@@ -9,12 +9,8 @@ import type { ReactElement } from 'react';
|
|
|
9
9
|
import type { SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';
|
|
10
10
|
import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
11
11
|
import { type CardShell, type FieldState, type FormScope } from './settings-form.ts';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export declare const DEFAULT_DOT_MODEL_COLOR = "#2f81f7";
|
|
15
|
-
/** User-invocable dot color default. Single source for the TS side; the
|
|
16
|
-
* panel's CSS mirrors it via --hub-user (panel.module.css). */
|
|
17
|
-
export declare const DEFAULT_DOT_USER_COLOR = "#3fb950";
|
|
12
|
+
import { DEFAULT_DOT_MODEL_COLOR, DEFAULT_DOT_USER_COLOR } from './panel/format.ts';
|
|
13
|
+
export { DEFAULT_DOT_MODEL_COLOR, DEFAULT_DOT_USER_COLOR };
|
|
18
14
|
/** The card's projected state. */
|
|
19
15
|
export interface SkillHubSettingsState extends CardShell {
|
|
20
16
|
enabled: FieldState;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vendored UI icons for dsh-skill-hub.
|
|
3
|
+
*
|
|
4
|
+
* These were originally imported from `@deepseek-ai/dsh-client-ui-primitives`.
|
|
5
|
+
* That package is still published for the rc.7/rc.2 SDK families, but newer dsh
|
|
6
|
+
* web builds no longer expose it as a standalone plugin module — they keep a
|
|
7
|
+
* static compatibility module instead. Vendoring the few tiny outline icons the
|
|
8
|
+
* hub uses makes the browser half self-contained and equally compatible with
|
|
9
|
+
* older and newer dsh hosts.
|
|
10
|
+
*
|
|
11
|
+
* SVG paths are copied verbatim from dsh-client-ui-primitives (MIT licensed)
|
|
12
|
+
* so the visuals remain pixel-identical to the dsh icon family.
|
|
13
|
+
*/
|
|
14
|
+
import type { JSX } from 'react';
|
|
15
|
+
/** Props understood by the dsh icon family: size + optional className. */
|
|
16
|
+
export interface IconProps {
|
|
17
|
+
size?: number;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
/** ic_ds_chevron_down_outline_14 */
|
|
21
|
+
export declare function IconChevronDownOutline14({ size, className }: IconProps): JSX.Element;
|
|
22
|
+
/** ic_ds_trash_outline_16 */
|
|
23
|
+
export declare function IconTrashOutline16({ size, className }: IconProps): JSX.Element;
|
|
24
|
+
/** ic_ds_skill_outline_16 */
|
|
25
|
+
export declare function IconSkillOutline16({ size, className }: IconProps): JSX.Element;
|
|
@@ -18,7 +18,7 @@ export declare const zh: {
|
|
|
18
18
|
readonly 'panel.search': "搜索技能…";
|
|
19
19
|
readonly 'legend.model': "模型可调 — Agent 可自动调用";
|
|
20
20
|
readonly 'legend.user': "用户可调 — 仅显式点名时触发";
|
|
21
|
-
readonly 'legend.hint': "
|
|
21
|
+
readonly 'legend.hint': "每个技能最多一个圆点;无圆点 = 不可被调用。";
|
|
22
22
|
readonly 'panel.enabled': "已启用";
|
|
23
23
|
readonly 'panel.disabled': "已禁用";
|
|
24
24
|
readonly 'panel.diagnostics': "发现诊断";
|
|
@@ -187,9 +187,9 @@ export declare const zh: {
|
|
|
187
187
|
readonly 'settings.announceToAgent': "向 Agent 公告";
|
|
188
188
|
readonly 'settings.announceToAgentHint': "在系统提示中加入本插件说明,用户提到技能管理时 Agent 知道如何协作。";
|
|
189
189
|
readonly 'settings.dotModelColor': "模型可调圆点颜色";
|
|
190
|
-
readonly 'settings.dotModelColorHint': "
|
|
190
|
+
readonly 'settings.dotModelColorHint': "技能行/聊天 / 菜单中「模型可调」蓝色圆点的颜色(#rrggbb)。";
|
|
191
191
|
readonly 'settings.dotUserColor': "用户可调圆点颜色";
|
|
192
|
-
readonly 'settings.dotUserColorHint': "
|
|
192
|
+
readonly 'settings.dotUserColorHint': "技能行/聊天 / 菜单中「仅用户可调」绿色圆点的颜色(#rrggbb)。";
|
|
193
193
|
readonly 'settings.showUseCount': "显示调用次数";
|
|
194
194
|
readonly 'settings.showUseCountHint': "在技能名旁显示琥珀色调用次数。";
|
|
195
195
|
readonly 'settings.showUseTime': "显示最近调用时间";
|
|
@@ -2,8 +2,18 @@
|
|
|
2
2
|
* Shared display helpers for the panel views (skill rows, detail view, and
|
|
3
3
|
* dialogs): dot color styling, relative/absolute time text, and commit-SHA
|
|
4
4
|
* shortening. Kept in one place so the views render identically.
|
|
5
|
+
*
|
|
6
|
+
* The invocation-status dot defaults live here (not in the settings card) so
|
|
7
|
+
* both the panel legend and the chat `/` skill menu draw from one source and
|
|
8
|
+
* so this primitives-free module stays unit-testable.
|
|
5
9
|
*/
|
|
6
10
|
import type { CSSProperties } from 'react';
|
|
11
|
+
/** Model-invocable dot color default. Single source for the TS side; the
|
|
12
|
+
* panel's CSS mirrors it via --hub-model (panel.module.css). */
|
|
13
|
+
export declare const DEFAULT_DOT_MODEL_COLOR = "#2f81f7";
|
|
14
|
+
/** User-invocable dot color default. Single source for the TS side; the
|
|
15
|
+
* panel's CSS mirrors it via --hub-user (panel.module.css). */
|
|
16
|
+
export declare const DEFAULT_DOT_USER_COLOR = "#3fb950";
|
|
7
17
|
/** Dot inline style from the user-chosen color (undefined keeps the CSS default). */
|
|
8
18
|
export declare function dotStyle(color: string | undefined): CSSProperties | undefined;
|
|
9
19
|
/** Localized relative-time text for a Unix-ms timestamp. */
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slash-menu skill dots: puts the invocation-status dot (model-callable blue /
|
|
3
|
+
* user-only green) in front of every skill candidate in the chat `/` menu.
|
|
4
|
+
*
|
|
5
|
+
* Mechanism (mirrors how dsh-at-file fills the menu icon slot): the candidate
|
|
6
|
+
* menu's rows already render an optional `icon` slot (`MenuView` renders
|
|
7
|
+
* `item.icon` in a 16×16 leading span when it's defined), but the core `/skill`
|
|
8
|
+
* source (`dsh-client-ui-skill`) returns candidates without `icon`. This module
|
|
9
|
+
* wraps that source's `candidates` and stamps each row with a colored dot,
|
|
10
|
+
* reusing the same settings (dotModelColor / dotUserColor) and the same
|
|
11
|
+
* `modelInvocable` classification the panel legend uses — so the chat menu and
|
|
12
|
+
* the Settings → 技能 panel stay in sync, and editing the color updates both.
|
|
13
|
+
*
|
|
14
|
+
* The skill source is registered by the core plugin under the `name` "skill"
|
|
15
|
+
* on the `/` trigger; re-registering the same name would throw, so this wraps
|
|
16
|
+
* the already-registered source object instead (found through the runtime
|
|
17
|
+
* source registry, which the frozen contract exposes only as `registerSource`
|
|
18
|
+
* / `sessionOf` — the lookup below is defensive: it never throws).
|
|
19
|
+
*/
|
|
20
|
+
import type { ClientContext, SettingsScope } from '@deepseek-ai/dsh-client-runtime/client';
|
|
21
|
+
import type { InputTriggerServiceContract, InputTriggerSource } from '@deepseek-ai/dsh-client-ui-input-trigger/client';
|
|
22
|
+
import type { HubSettingsValue } from '../protocol.ts';
|
|
23
|
+
import type { SkillHubApi } from './api.ts';
|
|
24
|
+
/**
|
|
25
|
+
* Find the core `/skill` source through the runtime registry, or undefined.
|
|
26
|
+
* The lookup never throws: a missing/reshaped registry just means no dots. Exported
|
|
27
|
+
* for unit tests; the apply path only calls it indirectly through setupSkillSlashDots.
|
|
28
|
+
* @param service - the ctx.inputTriggers service face.
|
|
29
|
+
* @returns the registered skill source, or undefined.
|
|
30
|
+
*/
|
|
31
|
+
export declare function findSkillSource(service: InputTriggerServiceContract): InputTriggerSource | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Clear the modelInvocable cache. Called on connection/reset so a fresh
|
|
34
|
+
* catalog wins after reconnect; exported for deterministic unit tests.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resetModelCache(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Wrap the core skill source so every menu row carries the invocation dot.
|
|
39
|
+
* Exported for unit tests; production wiring goes through setupSkillSlashDots.
|
|
40
|
+
* @param source - the registered `/skill` source.
|
|
41
|
+
* @param api - hub browser API for the modelInvocable lookup.
|
|
42
|
+
* @param scope - hub settings scope for the dot colors.
|
|
43
|
+
* @returns a disposer restoring the original candidates.
|
|
44
|
+
*/
|
|
45
|
+
export declare function wrapSkillSource(source: InputTriggerSource, api: SkillHubApi, scope: SettingsScope<HubSettingsValue>): () => void;
|
|
46
|
+
/**
|
|
47
|
+
* Mount the slash-menu dots on the registered `/skill` source. Idempotent and
|
|
48
|
+
* defensive: if the core source isn't registered yet (or the registry shape
|
|
49
|
+
* changes), it retries briefly and then gives up silently — the chat keeps
|
|
50
|
+
* working, it simply shows no dots. The returned disposer restores the
|
|
51
|
+
* original candidates and clears the model cache.
|
|
52
|
+
* @param ctx - the client root context (inputTriggers + events).
|
|
53
|
+
* @param api - hub browser API.
|
|
54
|
+
* @param scope - hub settings scope for dot colors.
|
|
55
|
+
* @returns a cleanup function for `ctx.effect`.
|
|
56
|
+
*/
|
|
57
|
+
export declare function setupSkillSlashDots(ctx: ClientContext, api: SkillHubApi, scope: SettingsScope<HubSettingsValue>): () => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-skill-hub",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "In-GUI skill hub for DeepSeek Harness (dsh): browse the full local skill catalog from the official ctx.skills registry (every root + third-party providers), toggle skills on/off, inspect bodies, surface frontmatter diagnostics, and scaffold new skills — plus a codex-style skill market (built-in catalog, upstream update checks, one-click update-all) with tracked source sync. The full manager beyond the read-only dsh-skill-manager browser.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -37,42 +37,84 @@
|
|
|
37
37
|
"platform": "web"
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
|
+
"dshWorkshop": {
|
|
41
|
+
"schema": "omdsh-workshop-package/v1",
|
|
42
|
+
"type": "plugin",
|
|
43
|
+
"integration": {
|
|
44
|
+
"protocol": "harness-cordis",
|
|
45
|
+
"artifact": "cordis.patch.yml"
|
|
46
|
+
},
|
|
47
|
+
"install": {
|
|
48
|
+
"mode": "guided",
|
|
49
|
+
"adapter": "third-party",
|
|
50
|
+
"failurePolicy": "manual",
|
|
51
|
+
"touchesCurrentBeforeActivation": false
|
|
52
|
+
},
|
|
53
|
+
"lifecycle": {
|
|
54
|
+
"activation": "hot-reload",
|
|
55
|
+
"dispose": "supported"
|
|
56
|
+
},
|
|
57
|
+
"permissions": [
|
|
58
|
+
"fs:read",
|
|
59
|
+
"fs:write",
|
|
60
|
+
"net:https",
|
|
61
|
+
"net:loopback"
|
|
62
|
+
],
|
|
63
|
+
"compatibility": {
|
|
64
|
+
"dshVersions": [
|
|
65
|
+
"0.1.0-rc.7",
|
|
66
|
+
"0.1.1-rc.2"
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
"capability": {
|
|
70
|
+
"id": "skill-hub-settings-panel",
|
|
71
|
+
"kind": "ui",
|
|
72
|
+
"invocation": "Open Settings → Skills panel; GET /api/skill-hub/catalog",
|
|
73
|
+
"expected": "The full local skill catalog (all roots) renders as groups and toggles persist an enabled/disabled row without a restart."
|
|
74
|
+
},
|
|
75
|
+
"evidence": {
|
|
76
|
+
"install": null,
|
|
77
|
+
"failureIsolation": null,
|
|
78
|
+
"hotReload": null,
|
|
79
|
+
"remove": null
|
|
80
|
+
}
|
|
81
|
+
},
|
|
40
82
|
"dependencies": {
|
|
41
83
|
"js-yaml": "^4.1.0",
|
|
42
84
|
"schemastery": "^3.18.0"
|
|
43
85
|
},
|
|
44
86
|
"peerDependencies": {
|
|
45
87
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
46
|
-
"@deepseek-ai/dsh-client-connection": "
|
|
47
|
-
"@deepseek-ai/dsh-client-locale": "
|
|
48
|
-
"@deepseek-ai/dsh-client-runtime": "
|
|
49
|
-
"@deepseek-ai/dsh-client-ui-
|
|
50
|
-
"@deepseek-ai/dsh-client-ui-settings": "
|
|
51
|
-
"@deepseek-ai/dsh-client-ui-slots": "
|
|
52
|
-
"@deepseek-ai/dsh-host-webserver": "
|
|
53
|
-
"@deepseek-ai/dsh-session": "
|
|
54
|
-
"@deepseek-ai/dsh-session-query": "
|
|
55
|
-
"@deepseek-ai/dsh-settings": "
|
|
56
|
-
"@deepseek-ai/dsh-skill": "
|
|
57
|
-
"@deepseek-ai/dsh-system-prompt": "
|
|
88
|
+
"@deepseek-ai/dsh-client-connection": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
89
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
90
|
+
"@deepseek-ai/dsh-client-runtime": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
91
|
+
"@deepseek-ai/dsh-client-ui-input-trigger": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
92
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
93
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
94
|
+
"@deepseek-ai/dsh-host-webserver": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
95
|
+
"@deepseek-ai/dsh-session": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
96
|
+
"@deepseek-ai/dsh-session-query": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
97
|
+
"@deepseek-ai/dsh-settings": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
98
|
+
"@deepseek-ai/dsh-skill": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
99
|
+
"@deepseek-ai/dsh-system-prompt": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
58
100
|
"react": "^18.2.0",
|
|
59
101
|
"react-dom": "^18.2.0"
|
|
60
102
|
},
|
|
61
103
|
"devDependencies": {
|
|
62
104
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
63
|
-
"@deepseek-ai/dsh-client-connection": "
|
|
64
|
-
"@deepseek-ai/dsh-client-locale": "
|
|
65
|
-
"@deepseek-ai/dsh-client-runtime": "
|
|
66
|
-
"@deepseek-ai/dsh-client-ui-
|
|
67
|
-
"@deepseek-ai/dsh-client-ui-settings": "
|
|
68
|
-
"@deepseek-ai/dsh-client-ui-settings-plugins": "
|
|
69
|
-
"@deepseek-ai/dsh-client-ui-slots": "
|
|
70
|
-
"@deepseek-ai/dsh-host-webserver": "
|
|
71
|
-
"@deepseek-ai/dsh-session": "
|
|
72
|
-
"@deepseek-ai/dsh-session-query": "
|
|
73
|
-
"@deepseek-ai/dsh-settings": "
|
|
74
|
-
"@deepseek-ai/dsh-skill": "
|
|
75
|
-
"@deepseek-ai/dsh-system-prompt": "
|
|
105
|
+
"@deepseek-ai/dsh-client-connection": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
106
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
107
|
+
"@deepseek-ai/dsh-client-runtime": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
108
|
+
"@deepseek-ai/dsh-client-ui-input-trigger": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
109
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
110
|
+
"@deepseek-ai/dsh-client-ui-settings-plugins": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
111
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
112
|
+
"@deepseek-ai/dsh-host-webserver": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
113
|
+
"@deepseek-ai/dsh-session": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
114
|
+
"@deepseek-ai/dsh-session-query": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
115
|
+
"@deepseek-ai/dsh-settings": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
116
|
+
"@deepseek-ai/dsh-skill": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
117
|
+
"@deepseek-ai/dsh-system-prompt": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0",
|
|
76
118
|
"@types/js-yaml": "^4.0.9",
|
|
77
119
|
"@types/node": "^22.20.0",
|
|
78
120
|
"@types/react": "~18.3.1",
|
|
@@ -11,13 +11,10 @@ import type { SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'
|
|
|
11
11
|
import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
|
|
12
12
|
import { ColorField, PluginSettingsCard, SwitchField } from './settings-card.tsx'
|
|
13
13
|
import { booleanField, CardForm, colorField, type CardShell, type FieldState, type FormScope } from './settings-form.ts'
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export
|
|
18
|
-
/** User-invocable dot color default. Single source for the TS side; the
|
|
19
|
-
* panel's CSS mirrors it via --hub-user (panel.module.css). */
|
|
20
|
-
export const DEFAULT_DOT_USER_COLOR = '#3fb950'
|
|
14
|
+
// Single source for the TS-side dot defaults (the panel CSS mirrors these).
|
|
15
|
+
import { DEFAULT_DOT_MODEL_COLOR, DEFAULT_DOT_USER_COLOR } from './panel/format.ts'
|
|
16
|
+
// Re-export for any consumer that imported them from the card before the move.
|
|
17
|
+
export { DEFAULT_DOT_MODEL_COLOR, DEFAULT_DOT_USER_COLOR }
|
|
21
18
|
|
|
22
19
|
/** The card's projected state. */
|
|
23
20
|
export interface SkillHubSettingsState extends CardShell {
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vendored UI icons for dsh-skill-hub.
|
|
3
|
+
*
|
|
4
|
+
* These were originally imported from `@deepseek-ai/dsh-client-ui-primitives`.
|
|
5
|
+
* That package is still published for the rc.7/rc.2 SDK families, but newer dsh
|
|
6
|
+
* web builds no longer expose it as a standalone plugin module — they keep a
|
|
7
|
+
* static compatibility module instead. Vendoring the few tiny outline icons the
|
|
8
|
+
* hub uses makes the browser half self-contained and equally compatible with
|
|
9
|
+
* older and newer dsh hosts.
|
|
10
|
+
*
|
|
11
|
+
* SVG paths are copied verbatim from dsh-client-ui-primitives (MIT licensed)
|
|
12
|
+
* so the visuals remain pixel-identical to the dsh icon family.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { JSX } from 'react'
|
|
16
|
+
|
|
17
|
+
/** Props understood by the dsh icon family: size + optional className. */
|
|
18
|
+
export interface IconProps {
|
|
19
|
+
size?: number
|
|
20
|
+
className?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** ic_ds_chevron_down_outline_14 */
|
|
24
|
+
export function IconChevronDownOutline14({ size = 14, className }: IconProps): JSX.Element {
|
|
25
|
+
return (
|
|
26
|
+
<svg width={size} height={size} className={className} viewBox='0 0 14 14' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
|
27
|
+
<path
|
|
28
|
+
d='M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z'
|
|
29
|
+
fill='currentColor'
|
|
30
|
+
/>
|
|
31
|
+
</svg>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** ic_ds_trash_outline_16 */
|
|
36
|
+
export function IconTrashOutline16({ size = 16, className }: IconProps): JSX.Element {
|
|
37
|
+
return (
|
|
38
|
+
<svg width={size} height={size} className={className} viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
|
39
|
+
<path
|
|
40
|
+
d='M14.4782 4.84067L14.2138 10.1152C14.1102 12.1872 14.067 13.0115 13.3866 13.9607C13.1044 14.3546 12.7498 14.6912 12.3424 14.9535C11.8239 15.2872 11.2415 15.4316 10.5585 15.4998C9.88727 15.5668 9.04946 15.5656 7.99998 15.5656C6.95051 15.5656 6.1127 15.5668 5.44142 15.4998C4.75851 15.4316 4.17602 15.2872 3.65753 14.9535C3.25012 14.6912 2.89559 14.3546 2.61332 13.9607C1.93296 13.0115 1.88979 12.1872 1.78619 10.1152L1.52179 4.84067L2.89006 4.77277L3.15343 10.0463C3.26221 12.2218 3.32452 12.6015 3.72646 13.1624C3.90825 13.4161 4.13686 13.6334 4.39927 13.8023C4.66204 13.9714 5.00263 14.0792 5.57825 14.1367C6.16562 14.1953 6.92298 14.1963 7.99998 14.1963C9.07699 14.1963 9.83434 14.1953 10.4217 14.1367C10.9973 14.0792 11.3379 13.9714 11.6007 13.8023C11.8631 13.6334 12.0917 13.4161 12.2735 13.1624C12.6755 12.6015 12.7378 12.2218 12.8465 10.0463L13.1099 4.77277L14.4782 4.84067ZM5.43011 6.22849H6.7994V11.3909H5.43011V6.22849ZM9.20056 6.22849H10.5699V11.3909H9.20056V6.22849ZM8.53597 0.434431C9.17976 0.434431 9.6522 0.426926 10.0966 0.571258C10.2357 0.616451 10.3717 0.672554 10.502 0.738948C10.9182 0.951107 11.2464 1.29099 11.7015 1.74612L12.4978 2.54136H15.3742V3.91169H0.625732V2.54136H3.50218L4.29845 1.74612C4.75358 1.29099 5.08174 0.951107 5.49801 0.738948C5.62831 0.672554 5.76425 0.616451 5.90334 0.571258C6.34776 0.426926 6.82021 0.434431 7.46399 0.434431H8.53597ZM7.46399 1.80476C6.73208 1.80476 6.51641 1.81187 6.32617 1.87369C6.25545 1.89667 6.18668 1.92533 6.12041 1.95907C5.96398 2.03878 5.82348 2.16253 5.44142 2.54136H10.5585C10.1765 2.16253 10.036 2.03878 9.87955 1.95907C9.81329 1.92533 9.74452 1.89667 9.6738 1.87369C9.48356 1.81187 9.26789 1.80476 8.53597 1.80476H7.46399Z'
|
|
41
|
+
fill='currentColor'
|
|
42
|
+
/>
|
|
43
|
+
</svg>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** ic_ds_skill_outline_16 */
|
|
48
|
+
export function IconSkillOutline16({ size = 16, className }: IconProps): JSX.Element {
|
|
49
|
+
return (
|
|
50
|
+
<svg width={size} height={size} className={className} viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
|
51
|
+
<path
|
|
52
|
+
d='M12.5113 15.4067C12.4395 15.6249 12.1308 15.6249 12.059 15.4067L11.643 14.1416C11.454 13.567 11.0033 13.1164 10.4288 12.9274L9.16369 12.5113C8.94544 12.4395 8.94544 12.1308 9.16369 12.059L10.4288 11.643C11.0033 11.454 11.454 11.0033 11.643 10.4288L12.059 9.16369C12.1308 8.94544 12.4395 8.94544 12.5113 9.16369L12.9274 10.4288C13.1164 11.0033 13.567 11.454 14.1416 11.643L15.4067 12.059C15.6249 12.1308 15.6249 12.4395 15.4067 12.5113L14.1416 12.9274C13.567 13.1164 13.1164 13.567 12.9274 14.1416L12.5113 15.4067Z'
|
|
53
|
+
fill='currentColor'
|
|
54
|
+
/>
|
|
55
|
+
<path
|
|
56
|
+
d='M9.02246 0.546878C9.9822 0.546878 10.7564 0.545403 11.374 0.612307C12.0042 0.680586 12.5515 0.826244 13.0273 1.17188C13.3052 1.37376 13.5501 1.61868 13.752 1.89649C14.0975 2.37225 14.2432 2.91984 14.3115 3.54981C14.3784 4.16727 14.377 4.94206 14.377 5.90137V8.51367C13.9611 8.29533 13.5071 8.13985 13.0273 8.06055V5.90137C13.0273 4.9121 13.0259 4.22322 12.9688 3.69532C12.9129 3.18044 12.8098 2.89782 12.6592 2.69043C12.5406 2.52724 12.3966 2.38326 12.2334 2.26465C12.026 2.11404 11.7437 2.0109 11.2285 1.95508C10.7005 1.89789 10.0122 1.89649 9.02246 1.89649H6.55371C5.56395 1.89649 4.87569 1.89787 4.34766 1.95508C3.83242 2.01092 3.55022 2.11398 3.34278 2.26465C3.17953 2.38329 3.03564 2.52719 2.91699 2.69043C2.76642 2.89782 2.66325 3.18042 2.60742 3.69532C2.55027 4.22322 2.54883 4.9121 2.54883 5.90137V10.0986C2.54883 11.0878 2.55031 11.7768 2.60742 12.3047C2.66326 12.8196 2.76642 13.1032 2.91699 13.3105C3.03558 13.4736 3.17966 13.6178 3.34278 13.7363C3.5502 13.8869 3.83265 13.9901 4.34766 14.0459C4.87568 14.1031 5.56398 14.1035 6.55371 14.1035H8.08399C8.27443 14.6025 8.55077 15.0585 8.89551 15.4541H6.55371C5.59402 15.4541 4.81976 15.4546 4.20215 15.3877C3.57204 15.3194 3.02468 15.1738 2.54883 14.8281C2.27111 14.6263 2.02606 14.3813 1.82422 14.1035C1.47883 13.6278 1.33293 13.08 1.26465 12.4502C1.19783 11.8327 1.19922 11.0579 1.19922 10.0986V5.90137C1.19922 4.94206 1.1978 4.16727 1.26465 3.54981C1.33295 2.91984 1.47867 2.37225 1.82422 1.89649C2.02613 1.61864 2.27098 1.37379 2.54883 1.17188C3.02472 0.826181 3.57197 0.6806 4.20215 0.612307C4.81976 0.545393 5.594 0.546877 6.55371 0.546878H9.02246ZM9.19629 9.14649H4.5459V7.84571H9.19629V9.14649ZM11.0303 6.10645H4.5459V4.80567H11.0303V6.10645Z'
|
|
57
|
+
fill='currentColor'
|
|
58
|
+
/>
|
|
59
|
+
</svg>
|
|
60
|
+
)
|
|
61
|
+
}
|
package/src/client/index.tsx
CHANGED
|
@@ -31,10 +31,13 @@ import type {} from '@deepseek-ai/dsh-client-ui-settings/client'
|
|
|
31
31
|
import type {} from '@deepseek-ai/dsh-client-ui-slots'
|
|
32
32
|
// Type-only: pulls the settings-plugins SlotMap merge (settings.plugin.item).
|
|
33
33
|
import type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client'
|
|
34
|
+
// Type-only: pulls the Context merge for ctx.inputTriggers (slash-dots wiring).
|
|
35
|
+
import type {} from '@deepseek-ai/dsh-client-ui-input-trigger/client'
|
|
34
36
|
import type { HubSettingsValue } from '../protocol.ts'
|
|
35
37
|
import { SkillHubApi } from './api.ts'
|
|
36
38
|
import { en, zh, type HubKey } from './locales.ts'
|
|
37
39
|
import { applySettingsNavIcon } from './settings-nav-icon.ts'
|
|
40
|
+
import { setupSkillSlashDots } from './slash-dots.tsx'
|
|
38
41
|
import { SkillHubSettingsCard, SkillHubSettingsCardController } from './SkillHubSettingsCard.tsx'
|
|
39
42
|
import { SkillHubPanel } from './panel/SkillHubPanel.tsx'
|
|
40
43
|
|
|
@@ -55,7 +58,7 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
|
55
58
|
* `settingsScope` is the namespace-scope binder itself; mirror the official
|
|
56
59
|
* settings-plugins inject list.
|
|
57
60
|
*/
|
|
58
|
-
export const inject = ['slots', 'locale', 'connection', 'remote', 'settingsScope']
|
|
61
|
+
export const inject = ['slots', 'locale', 'connection', 'remote', 'settingsScope', 'inputTriggers']
|
|
59
62
|
|
|
60
63
|
/** Type-only surface (export discipline: no value exports beyond the plugin contract). */
|
|
61
64
|
export type { SkillHubPanelProps } from './panel/SkillHubPanel.tsx'
|
|
@@ -79,6 +82,15 @@ export function apply(ctx: ClientContext): void {
|
|
|
79
82
|
ctx.settingsScope.bind<HubSettingsValue>({ namespace: NS }),
|
|
80
83
|
)
|
|
81
84
|
|
|
85
|
+
// Chat `/` menu skill dots: wrap the core skill source so every candidate
|
|
86
|
+
// row carries the invocation dot, colored from the same settings the panel
|
|
87
|
+
// legend uses (dotModelColor / dotUserColor). Own scope = independent reader;
|
|
88
|
+
// fails silent, never takes the GUI down.
|
|
89
|
+
ctx.effect(
|
|
90
|
+
() => setupSkillSlashDots(ctx, api, ctx.settingsScope.bind<HubSettingsValue>({ namespace: NS })),
|
|
91
|
+
'dsh-skill-hub: slash dots',
|
|
92
|
+
)
|
|
93
|
+
|
|
82
94
|
// Plugin-management card: Settings → 插件 → 可配置插件列表.
|
|
83
95
|
// rc.7's slot contract declares this keyed slot with options `key`
|
|
84
96
|
// (the settings namespace the card edits), so registration is fully typed.
|
package/src/client/locales.ts
CHANGED
|
@@ -19,7 +19,7 @@ export const zh = {
|
|
|
19
19
|
'panel.search': '搜索技能…',
|
|
20
20
|
'legend.model': '模型可调 — Agent 可自动调用',
|
|
21
21
|
'legend.user': '用户可调 — 仅显式点名时触发',
|
|
22
|
-
'legend.hint': '
|
|
22
|
+
'legend.hint': '每个技能最多一个圆点;无圆点 = 不可被调用。',
|
|
23
23
|
'panel.enabled': '已启用',
|
|
24
24
|
'panel.disabled': '已禁用',
|
|
25
25
|
'panel.diagnostics': '发现诊断',
|
|
@@ -188,9 +188,9 @@ export const zh = {
|
|
|
188
188
|
'settings.announceToAgent': '向 Agent 公告',
|
|
189
189
|
'settings.announceToAgentHint': '在系统提示中加入本插件说明,用户提到技能管理时 Agent 知道如何协作。',
|
|
190
190
|
'settings.dotModelColor': '模型可调圆点颜色',
|
|
191
|
-
'settings.dotModelColorHint': '
|
|
191
|
+
'settings.dotModelColorHint': '技能行/聊天 / 菜单中「模型可调」蓝色圆点的颜色(#rrggbb)。',
|
|
192
192
|
'settings.dotUserColor': '用户可调圆点颜色',
|
|
193
|
-
'settings.dotUserColorHint': '
|
|
193
|
+
'settings.dotUserColorHint': '技能行/聊天 / 菜单中「仅用户可调」绿色圆点的颜色(#rrggbb)。',
|
|
194
194
|
'settings.showUseCount': '显示调用次数',
|
|
195
195
|
'settings.showUseCountHint': '在技能名旁显示琥珀色调用次数。',
|
|
196
196
|
'settings.showUseTime': '显示最近调用时间',
|
|
@@ -228,7 +228,7 @@ export const en: Record<HubKey, string> = {
|
|
|
228
228
|
'panel.search': 'Search skills…',
|
|
229
229
|
'legend.model': 'Model-invocable — agents may call automatically',
|
|
230
230
|
'legend.user': 'User-invocable — explicit invocation only',
|
|
231
|
-
'legend.hint': '
|
|
231
|
+
'legend.hint': 'At most one dot per skill; no dot = not invocable.',
|
|
232
232
|
'panel.enabled': 'Enabled',
|
|
233
233
|
'panel.disabled': 'Disabled',
|
|
234
234
|
'panel.diagnostics': 'Discovery diagnostics',
|
|
@@ -397,9 +397,9 @@ export const en: Record<HubKey, string> = {
|
|
|
397
397
|
'settings.announceToAgent': 'Announce to agent',
|
|
398
398
|
'settings.announceToAgentHint': 'Adds a system-prompt section so agents know how to collaborate when users mention skill management.',
|
|
399
399
|
'settings.dotModelColor': 'Model-invocable dot color',
|
|
400
|
-
'settings.dotModelColorHint': 'Color of the blue dot
|
|
400
|
+
'settings.dotModelColorHint': 'Color of the blue "model-callable" dot in the skill panel and the chat / menu (#rrggbb).',
|
|
401
401
|
'settings.dotUserColor': 'User-invocable dot color',
|
|
402
|
-
'settings.dotUserColorHint': 'Color of the green dot
|
|
402
|
+
'settings.dotUserColorHint': 'Color of the green "user-only" dot in the skill panel and the chat / menu (#rrggbb).',
|
|
403
403
|
'settings.showUseCount': 'Show invocation count',
|
|
404
404
|
'settings.showUseCountHint': 'Show the amber invocation count beside each skill name.',
|
|
405
405
|
'settings.showUseTime': 'Show last-used time',
|
|
@@ -42,8 +42,12 @@ export function SkillDetailView(props: SkillDetailViewProps): JSX.Element {
|
|
|
42
42
|
<button type='button' className={css.back} onClick={onBack}>{tt('detail.back')}</button>
|
|
43
43
|
<span className={css.detailName}>
|
|
44
44
|
{detail.name}
|
|
45
|
-
{
|
|
46
|
-
{detail.invocation.
|
|
45
|
+
{/* 单一状态圆点:模型可调 → 蓝;否则用户可调 → 绿。与聊天 / 菜单同规则。 */}
|
|
46
|
+
{detail.invocation.modelInvocable
|
|
47
|
+
? <span className={css.dot + ' ' + css.dotModel} style={dotStyle(hubConfig?.dotModelColor)} title={tt('legend.model')} />
|
|
48
|
+
: detail.invocation.userInvocable
|
|
49
|
+
? <span className={css.dot + ' ' + css.dotUser} style={dotStyle(hubConfig?.dotUserColor)} title={tt('legend.user')} />
|
|
50
|
+
: null}
|
|
47
51
|
</span>
|
|
48
52
|
</div>
|
|
49
53
|
<div className={css.detailMeta}>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import { useState } from 'react'
|
|
16
16
|
import type { WritableRoot } from '../../protocol.ts'
|
|
17
|
-
import { IconSkillOutline16 } from '
|
|
17
|
+
import { IconSkillOutline16 } from '../icons.tsx'
|
|
18
18
|
import type { SkillHubApi } from '../api.ts'
|
|
19
19
|
import { tt } from '../helpers.ts'
|
|
20
20
|
import { PRIVATE_SOURCE, type SortKey } from '../grouping.ts'
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { JSX, KeyboardEvent } from 'react'
|
|
7
7
|
import type { CatalogSkill } from '../../protocol.ts'
|
|
8
|
-
import { IconTrashOutline16 } from '
|
|
8
|
+
import { IconTrashOutline16 } from '../icons.tsx'
|
|
9
9
|
import { tt } from '../helpers.ts'
|
|
10
10
|
import { dotStyle, relativeTimeText } from './format.ts'
|
|
11
11
|
import type { SkillHubState } from './useSkillHub.ts'
|
|
@@ -16,6 +16,12 @@ export function SkillRow(props: { skill: CatalogSkill; hub: SkillHubState }): JS
|
|
|
16
16
|
const stat = hub.uses.get(skill.name)
|
|
17
17
|
const count = stat?.count ?? 0
|
|
18
18
|
const lastUsed = stat?.lastUsed
|
|
19
|
+
/** 单一状态圆点:模型可调 → 蓝;否则用户可调 → 绿。与聊天 / 菜单同规则。 */
|
|
20
|
+
const dot = skill.invocation.modelInvocable
|
|
21
|
+
? <span className={css.dot + ' ' + css.dotModel} style={dotStyle(hub.hubConfig?.dotModelColor)} title={tt('legend.model')} />
|
|
22
|
+
: skill.invocation.userInvocable
|
|
23
|
+
? <span className={css.dot + ' ' + css.dotUser} style={dotStyle(hub.hubConfig?.dotUserColor)} title={tt('legend.user')} />
|
|
24
|
+
: null
|
|
19
25
|
/** 键盘打开详情:Enter 或空格。仅当焦点在行本身(而非行内按钮)时生效。 */
|
|
20
26
|
const onKeyDown = (event: KeyboardEvent<HTMLDivElement>): void => {
|
|
21
27
|
if (event.target !== event.currentTarget) return
|
|
@@ -37,8 +43,7 @@ export function SkillRow(props: { skill: CatalogSkill; hub: SkillHubState }): JS
|
|
|
37
43
|
<div className={css.rowName}>
|
|
38
44
|
<span className={css.rowNameText}>{skill.name}</span>
|
|
39
45
|
{count > 0 && hub.hubConfig?.showUseCount !== false ? <span className={css.useCount}>{count}</span> : null}
|
|
40
|
-
{
|
|
41
|
-
{skill.invocation.userInvocable ? <span className={css.dot + ' ' + css.dotUser} style={dotStyle(hub.hubConfig?.dotUserColor)} title={tt('legend.user')} /> : null}
|
|
46
|
+
{dot}
|
|
42
47
|
{lastUsed !== undefined && hub.hubConfig?.showUseTime !== false ? <span className={css.useTime}>{relativeTimeText(lastUsed)}</span> : null}
|
|
43
48
|
</div>
|
|
44
49
|
<div className={css.rowDesc}>{skill.description}</div>
|
|
@@ -2,12 +2,23 @@
|
|
|
2
2
|
* Shared display helpers for the panel views (skill rows, detail view, and
|
|
3
3
|
* dialogs): dot color styling, relative/absolute time text, and commit-SHA
|
|
4
4
|
* shortening. Kept in one place so the views render identically.
|
|
5
|
+
*
|
|
6
|
+
* The invocation-status dot defaults live here (not in the settings card) so
|
|
7
|
+
* both the panel legend and the chat `/` skill menu draw from one source and
|
|
8
|
+
* so this primitives-free module stays unit-testable.
|
|
5
9
|
*/
|
|
6
10
|
|
|
7
11
|
import type { CSSProperties } from 'react'
|
|
8
12
|
import { formatRelativeTime } from '../grouping.ts'
|
|
9
13
|
import { tt } from '../helpers.ts'
|
|
10
14
|
|
|
15
|
+
/** Model-invocable dot color default. Single source for the TS side; the
|
|
16
|
+
* panel's CSS mirrors it via --hub-model (panel.module.css). */
|
|
17
|
+
export const DEFAULT_DOT_MODEL_COLOR = '#2f81f7'
|
|
18
|
+
/** User-invocable dot color default. Single source for the TS side; the
|
|
19
|
+
* panel's CSS mirrors it via --hub-user (panel.module.css). */
|
|
20
|
+
export const DEFAULT_DOT_USER_COLOR = '#3fb950'
|
|
21
|
+
|
|
11
22
|
/** Dot inline style from the user-chosen color (undefined keeps the CSS default). */
|
|
12
23
|
export function dotStyle(color: string | undefined): CSSProperties | undefined {
|
|
13
24
|
if (color === undefined) return undefined
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { useState, type ReactElement } from 'react'
|
|
10
|
-
import { IconChevronDownOutline14 } from '
|
|
10
|
+
import { IconChevronDownOutline14 } from './icons.tsx'
|
|
11
11
|
import type { HubKey } from './locales.ts'
|
|
12
12
|
import type { CardShell } from './settings-form.ts'
|
|
13
13
|
import css from './settings-card.module.css'
|