dsh-skill-hub 0.2.5 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -2303,6 +2303,7 @@ function makeRoutes(deps) {
2303
2303
  if (req.method === "GET") {
2304
2304
  writeJson(res, 200, {
2305
2305
  ok: true,
2306
+ pluginVersion: CURRENT_VERSION,
2306
2307
  config: configOf(deps),
2307
2308
  saved: savedOf(deps)
2308
2309
  });
@@ -2359,6 +2360,7 @@ function makeRoutes(deps) {
2359
2360
  } else config = await deps.updateConfig(patch);
2360
2361
  writeJson(res, 200, {
2361
2362
  ok: true,
2363
+ pluginVersion: CURRENT_VERSION,
2362
2364
  config,
2363
2365
  saved: savedOf(deps)
2364
2366
  });
@@ -5,7 +5,7 @@
5
5
  * Registered into the official `settings.plugin.item` slot keyed by that
6
6
  * namespace, so the plugin shows up in Settings → 插件 on dsh rc.7+.
7
7
  */
8
- import type { ReactElement } from 'react';
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';
@@ -180,7 +180,7 @@ export declare const zh: {
180
180
  readonly 'form.success': "已创建:";
181
181
  readonly 'form.error': "创建失败:";
182
182
  readonly 'err.dismiss': "知道了";
183
- readonly 'settings.title': "Skill Hub";
183
+ readonly 'settings.title': "技能中枢";
184
184
  readonly 'settings.description': "管理 dsh 本地技能目录:浏览、分组、来源同步与新建。";
185
185
  readonly 'settings.enabled': "启用插件";
186
186
  readonly 'settings.enabledHint': "关闭后技能中枢的路由、入口与公告全部下线。";
@@ -16,6 +16,8 @@ export interface PluginSettingsCardProps {
16
16
  titleKey: HubKey;
17
17
  /** Locale key of the card description. */
18
18
  descriptionKey: HubKey;
19
+ /** 插件自身版本(可选):显示在标题旁的小徽标;缺省不渲染。 */
20
+ version?: string;
19
21
  /** The form shell state. */
20
22
  state: CardShell;
21
23
  onSave: () => void;
@@ -278,6 +278,8 @@ export declare const HEX_COLOR_RE: RegExp;
278
278
  /** GET /api/skill-hub/config */
279
279
  export interface ConfigResponse {
280
280
  ok: true;
281
+ /** 已安装插件自身的版本号(package.json version),设置卡标题旁显示。 */
282
+ pluginVersion: string;
281
283
  /** Effective configuration (saved overrides merged over the defaults). */
282
284
  config: HubConfig;
283
285
  /** Raw user overrides persisted in the sidecar (absent fields inherit defaults). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-skill-hub",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
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": {
@@ -6,9 +6,10 @@
6
6
  * namespace, so the plugin shows up in Settings → 插件 on dsh rc.7+.
7
7
  */
8
8
 
9
- import type { ReactElement } from 'react'
9
+ import { useEffect, useState, type ReactElement } from 'react'
10
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
+ import { SkillHubApi } from './api.ts'
12
13
  import { ColorField, NumberField, PluginSettingsCard, SwitchField } from './settings-card.tsx'
13
14
  import { booleanField, CardForm, colorField, numberField, type CardShell, type FieldState, type FormScope } from './settings-form.ts'
14
15
  // Single source for the TS-side dot defaults (the panel CSS mirrors these).
@@ -91,6 +92,15 @@ export class SkillHubSettingsCardController {
91
92
  export function SkillHubSettingsCard(props: SkillHubSettingsCardProps): ReactElement {
92
93
  const { t } = props
93
94
  const state = props.useSkillHubSettingsCard((snapshot) => snapshot)
95
+ // 插件自身版本:挂载时从 config 路由取一次(与面板标题徽标同源),失败静默不显示。
96
+ const [version, setVersion] = useState<string | undefined>(undefined)
97
+ useEffect(() => {
98
+ let cancelled = false
99
+ void new SkillHubApi().config()
100
+ .then((res) => { if (!cancelled && res.ok) setVersion(res.pluginVersion) })
101
+ .catch(() => { /* 版本徽标是装饰性的,失败不提示 */ })
102
+ return () => { cancelled = true }
103
+ }, [])
94
104
  const disabled = !state.writable
95
105
  const fieldProps = {
96
106
  overriddenLabel: t('settings.overridden'),
@@ -102,6 +112,7 @@ export function SkillHubSettingsCard(props: SkillHubSettingsCardProps): ReactEle
102
112
  t={t}
103
113
  titleKey='settings.title'
104
114
  descriptionKey='settings.description'
115
+ version={version}
105
116
  state={state}
106
117
  onSave={props.save}
107
118
  onDiscard={props.discard}
@@ -181,7 +181,7 @@ export const zh = {
181
181
  'form.success': '已创建:',
182
182
  'form.error': '创建失败:',
183
183
  'err.dismiss': '知道了',
184
- 'settings.title': 'Skill Hub',
184
+ 'settings.title': '技能中枢',
185
185
  'settings.description': '管理 dsh 本地技能目录:浏览、分组、来源同步与新建。',
186
186
  'settings.enabled': '启用插件',
187
187
  'settings.enabledHint': '关闭后技能中枢的路由、入口与公告全部下线。',
@@ -8,6 +8,7 @@
8
8
  .headText { flex-direction: column; flex: 1; gap: 4px; min-width: 0; display: flex; }
9
9
  .name { color: var(--dsw-alias-label-primary); font-size: 15px; font-weight: 600; line-height: 1.4; }
10
10
  .description { color: var(--dsw-alias-label-tertiary); font-size: 13px; line-height: 1.5; }
11
+ .versionTag { font-size: 12px; font-weight: 500; opacity: .45; margin-left: 6px; white-space: nowrap; font-variant-numeric: tabular-nums; vertical-align: 1px; }
11
12
  .pending { white-space: nowrap; background: var(--dsw-alias-bg-module-platform); color: var(--dsw-alias-label-secondary); border-radius: 999px; flex: none; padding: 1px 8px; font-size: 11px; font-weight: 500; line-height: 17px; }
12
13
  .chevron, .chevronOpen { color: var(--dsw-alias-label-tertiary); flex: none; transition: transform .16s; }
13
14
  .chevronOpen { transform: rotate(180deg); }
@@ -20,6 +20,8 @@ export interface PluginSettingsCardProps {
20
20
  titleKey: HubKey
21
21
  /** Locale key of the card description. */
22
22
  descriptionKey: HubKey
23
+ /** 插件自身版本(可选):显示在标题旁的小徽标;缺省不渲染。 */
24
+ version?: string
23
25
  /** The form shell state. */
24
26
  state: CardShell
25
27
  onSave: () => void
@@ -48,7 +50,7 @@ export function PluginSettingsCard(props: PluginSettingsCardProps): ReactElement
48
50
  onClick={() => { setOpen(!open) }}
49
51
  >
50
52
  <span className={css.headText}>
51
- <span className={css.name}>{title}</span>
53
+ <span className={css.name}>{title}{props.version !== undefined ? <span className={css.versionTag}>v{props.version}</span> : null}</span>
52
54
  <span className={css.description}>{props.t(props.descriptionKey)}</span>
53
55
  </span>
54
56
  {state.dirty ? <span className={css.pending}>{props.t('settings.unsaved')}</span> : null}
package/src/protocol.ts CHANGED
@@ -318,6 +318,8 @@ export const HEX_COLOR_RE = /^#[0-9a-f]{6}$/i
318
318
  /** GET /api/skill-hub/config */
319
319
  export interface ConfigResponse {
320
320
  ok: true
321
+ /** 已安装插件自身的版本号(package.json version),设置卡标题旁显示。 */
322
+ pluginVersion: string
321
323
  /** Effective configuration (saved overrides merged over the defaults). */
322
324
  config: HubConfig
323
325
  /** Raw user overrides persisted in the sidecar (absent fields inherit defaults). */
@@ -396,6 +396,7 @@ describe('skill-hub routes', () => {
396
396
  expect(res.status).toBe(200)
397
397
  const body = res.json() as ConfigResponse
398
398
  expect(body.ok).toBe(true)
399
+ expect(body.pluginVersion).toMatch(/^\d+\.\d+\.\d+$/)
399
400
  expect(body.config).toEqual({ enabled: false, announceToAgent: true, showUseCount: true, showUseTime: true, showGroupSummary: true, statsWindowDays: 14, statsScanMinutes: 5 })
400
401
  expect(body.saved).toEqual({ enabled: false })
401
402
  })
package/src/routes.ts CHANGED
@@ -719,7 +719,7 @@ export function makeRoutes(deps: SkillHubRouteDeps): WebRoute[] {
719
719
  skipGate: true,
720
720
  handler: async ({ req, res, body }) => {
721
721
  if (req.method === 'GET') {
722
- writeJson(res, 200, { ok: true, config: configOf(deps), saved: savedOf(deps) } satisfies ConfigResponse)
722
+ writeJson(res, 200, { ok: true, pluginVersion: CURRENT_VERSION, config: configOf(deps), saved: savedOf(deps) } satisfies ConfigResponse)
723
723
  return
724
724
  }
725
725
  const raw = body
@@ -759,7 +759,7 @@ export function makeRoutes(deps: SkillHubRouteDeps): WebRoute[] {
759
759
  } else {
760
760
  config = await deps.updateConfig(patch)
761
761
  }
762
- writeJson(res, 200, { ok: true, config, saved: savedOf(deps) } satisfies ConfigResponse)
762
+ writeJson(res, 200, { ok: true, pluginVersion: CURRENT_VERSION, config, saved: savedOf(deps) } satisfies ConfigResponse)
763
763
  },
764
764
  }),
765
765
  // --------------------------------------------------------------- market