dsh-skill-hub 0.1.0 → 0.2.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.
Files changed (79) hide show
  1. package/README.md +146 -33
  2. package/lib/client.js +3477 -436
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +2408 -366
  5. package/lib/types/client/SkillHubSettingsCard.d.ts +5 -0
  6. package/lib/types/client/api-config-scope.d.ts +6 -0
  7. package/lib/types/client/api.d.ts +44 -2
  8. package/lib/types/client/grouping.d.ts +64 -0
  9. package/lib/types/client/locales.d.ts +155 -18
  10. package/lib/types/client/market-catalog.d.ts +14 -0
  11. package/lib/types/client/panel/DisabledRow.d.ts +12 -0
  12. package/lib/types/client/panel/GroupSummary.d.ts +10 -0
  13. package/lib/types/client/panel/MarketView.d.ts +11 -0
  14. package/lib/types/client/panel/ScenesView.d.ts +11 -0
  15. package/lib/types/client/panel/SkillDetailView.d.ts +31 -0
  16. package/lib/types/client/panel/SkillHubPanel.d.ts +11 -3
  17. package/lib/types/client/panel/SkillRow.d.ts +11 -0
  18. package/lib/types/client/panel/SourceStatusBadge.d.ts +18 -0
  19. package/lib/types/client/panel/SourcesView.d.ts +10 -0
  20. package/lib/types/client/panel/TagEditorView.d.ts +29 -0
  21. package/lib/types/client/panel/dialogs.d.ts +73 -0
  22. package/lib/types/client/panel/format.d.ts +14 -0
  23. package/lib/types/client/panel/useSkillHub.d.ts +183 -0
  24. package/lib/types/client/settings-card.d.ts +21 -4
  25. package/lib/types/client/settings-form.d.ts +2 -0
  26. package/lib/types/client/settings-nav-icon.d.ts +8 -0
  27. package/lib/types/index.d.ts +6 -0
  28. package/lib/types/protocol.d.ts +428 -7
  29. package/lib/types/provider.d.ts +6 -1
  30. package/lib/types/repo.d.ts +133 -0
  31. package/lib/types/routes.d.ts +9 -4
  32. package/lib/types/skillfs.d.ts +19 -14
  33. package/lib/types/stats.d.ts +17 -4
  34. package/lib/types/store.d.ts +112 -6
  35. package/lib/types/update.d.ts +20 -0
  36. package/package.json +5 -3
  37. package/src/client/SkillHubSettingsCard.tsx +61 -8
  38. package/src/client/api-config-scope.test.ts +79 -0
  39. package/src/client/api-config-scope.ts +28 -4
  40. package/src/client/api.ts +239 -9
  41. package/src/client/grouping.test.ts +109 -0
  42. package/src/client/grouping.ts +120 -0
  43. package/src/client/index.tsx +5 -2
  44. package/src/client/locales.ts +314 -40
  45. package/src/client/market-catalog.ts +22 -0
  46. package/src/client/panel/DisabledRow.tsx +32 -0
  47. package/src/client/panel/GroupSummary.tsx +27 -0
  48. package/src/client/panel/MarketView.tsx +173 -0
  49. package/src/client/panel/ScenesView.tsx +75 -0
  50. package/src/client/panel/SkillDetailView.tsx +95 -0
  51. package/src/client/panel/SkillHubPanel.tsx +251 -257
  52. package/src/client/panel/SkillRow.tsx +54 -0
  53. package/src/client/panel/SourceStatusBadge.tsx +61 -0
  54. package/src/client/panel/SourcesView.tsx +104 -0
  55. package/src/client/panel/TagEditorView.tsx +89 -0
  56. package/src/client/panel/dialogs.tsx +185 -0
  57. package/src/client/panel/format.ts +31 -0
  58. package/src/client/panel/panel.module.css +209 -45
  59. package/src/client/panel/useSkillHub.ts +797 -0
  60. package/src/client/settings-card.module.css +44 -28
  61. package/src/client/settings-card.tsx +64 -8
  62. package/src/client/settings-form.ts +12 -0
  63. package/src/client/settings-nav-icon.ts +42 -0
  64. package/src/index.ts +19 -15
  65. package/src/protocol.ts +460 -7
  66. package/src/provider.test.ts +2 -4
  67. package/src/provider.ts +18 -14
  68. package/src/repo.test.ts +212 -0
  69. package/src/repo.ts +528 -0
  70. package/src/routes.test.ts +564 -52
  71. package/src/routes.ts +999 -153
  72. package/src/skillfs.test.ts +98 -16
  73. package/src/skillfs.ts +68 -33
  74. package/src/stats.test.ts +52 -17
  75. package/src/stats.ts +55 -18
  76. package/src/store.test.ts +205 -1
  77. package/src/store.ts +527 -24
  78. package/src/update.test.ts +73 -0
  79. package/src/update.ts +136 -0
@@ -13,6 +13,11 @@ import { CardForm, type CardShell, type FieldState, type FormScope } from './set
13
13
  export interface SkillHubSettingsState extends CardShell {
14
14
  enabled: FieldState;
15
15
  announceToAgent: FieldState;
16
+ dotModelColor: FieldState;
17
+ dotUserColor: FieldState;
18
+ showUseCount: FieldState;
19
+ showUseTime: FieldState;
20
+ showGroupSummary: FieldState;
16
21
  }
17
22
  /** Props the slot renderer receives (locale copy + injected form actions). */
18
23
  export interface SkillHubSettingsCardProps {
@@ -14,6 +14,12 @@
14
14
  */
15
15
  import type { SkillHubApi } from './api.ts';
16
16
  import type { FormScope } from './settings-form.ts';
17
+ /** Model-invocable dot color default. Single source for the TS side; the
18
+ * panel's CSS mirrors it via --hub-model (panel.module.css). */
19
+ export declare const DEFAULT_DOT_MODEL_COLOR = "#2f81f7";
20
+ /** User-invocable dot color default. Single source for the TS side; the
21
+ * panel's CSS mirrors it via --hub-user (panel.module.css). */
22
+ export declare const DEFAULT_DOT_USER_COLOR = "#3fb950";
17
23
  /** FormScope-compatible reactive config handle (see module doc). */
18
24
  export declare class ApiConfigScope implements FormScope {
19
25
  private readonly api;
@@ -2,7 +2,7 @@
2
2
  * Browser-side API client for the /api/skill-hub route family. The only
3
3
  * data access path the panel uses — plain fetch, same origin.
4
4
  */
5
- import { type CatalogResponse, type ConfigRequest, type ConfigResponse, type CreateRequest, type CreateResponse, type SkillDetail, type StatsResponse } from '../protocol.ts';
5
+ import { type CatalogResponse, type ConfigRequest, type ConfigResponse, type CreateRequest, type CreateResponse, type MarketCheckResponse, type MarketSourcesResponse, type MarketSyncResponse, type RepoDiscoverResponse, type RepoImportResponse, type SkillDetail, type SkillDeleteResponse, type SourceCheckResponse, type SourceDeleteResponse, type SourceRestoreResponse, type SourceTrashClearResponse, type SourcesResponse, type SourceSyncResponse, type StatsResponse, type ToggleBatchResponse, type UpdateCheckResponse } from '../protocol.ts';
6
6
  /** Error carrying the route's JSON error message. */
7
7
  export declare class SkillHubApiError extends Error {
8
8
  constructor(message: string);
@@ -11,12 +11,54 @@ export declare class SkillHubApiError extends Error {
11
11
  export declare class SkillHubApi {
12
12
  catalog(): Promise<CatalogResponse>;
13
13
  skill(name: string): Promise<SkillDetail>;
14
- /** Toggle a skill; resolves with the fresh catalog from the route. */
14
+ /** Move one writable skill into the restorable trash. */
15
+ deleteSkill(name: string): Promise<SkillDeleteResponse>;
16
+ /** Toggle one skill; resolves with the fresh catalog from the route. */
15
17
  toggle(name: string, enabled: boolean): Promise<CatalogResponse>;
16
18
  create(payload: CreateRequest): Promise<CreateResponse>;
17
19
  stats(): Promise<StatsResponse>;
20
+ /** Toggle a whole group in one write; resolves with the fresh catalog + failures. */
21
+ toggleBatch(names: string[], enabled: boolean): Promise<ToggleBatchResponse>;
22
+ /** The user's added market sources (codex-style repo slugs). */
23
+ market(): Promise<MarketSourcesResponse>;
24
+ /** Add a market source repo; resolves with the fresh list. */
25
+ addMarketSource(repo: string): Promise<MarketSourcesResponse>;
26
+ /** Remove a market source repo; resolves with the fresh list. */
27
+ removeMarketSource(repo: string): Promise<MarketSourcesResponse>;
28
+ /** Check every market source for updates (throttled server-side). */
29
+ marketCheck(): Promise<MarketCheckResponse>;
30
+ /** Align a market source to its pinned ref; resolves with tracked skills. */
31
+ marketSync(repo: string): Promise<MarketSyncResponse>;
32
+ /** Pin a market source to an explicit ref (branch picker). */
33
+ setMarketSourceRef(repo: string, ref: string): Promise<MarketSourcesResponse>;
34
+ /** Check the hub's own latest GitHub release. */
35
+ updateCheck(): Promise<UpdateCheckResponse>;
36
+ /** Discover importable skills in a GitHub repo. */
37
+ repoDiscover(repo: string): Promise<RepoDiscoverResponse>;
38
+ /** Install selected repo skills into the user-dsh root (records the source). */
39
+ repoImport(repo: string, paths: string[], ref?: string): Promise<RepoImportResponse>;
18
40
  /** Read the hub's runtime config (effective values + saved overrides). */
19
41
  config(): Promise<ConfigResponse>;
20
42
  /** Patch the hub's runtime config (null clears a saved override). */
21
43
  saveConfig(patch: ConfigRequest): Promise<ConfigResponse>;
44
+ /** 用户 tag 分组 + 系统集合组 + origin 映射。 */
45
+ groups(): Promise<import('../protocol.ts').GroupsResponse>;
46
+ /** 新建(无 id)或重命名(带 id)一个 tag 分组;返回全部 tag。 */
47
+ saveTag(payload: import('../protocol.ts').TagSaveRequest): Promise<import('../protocol.ts').SkillTag[]>;
48
+ /** 删除一个 tag 分组;返回全部 tag。 */
49
+ deleteTag(id: string): Promise<import('../protocol.ts').SkillTag[]>;
50
+ /** 直接设置某 tag 的完整成员列表;返回全部 tag。 */
51
+ setTagMembers(id: string, skillNames: string[]): Promise<import('../protocol.ts').SkillTag[]>;
52
+ /** 来源列表 + 派生 origin 映射 + 集合组 + 回收站。 */
53
+ sources(): Promise<SourcesResponse>;
54
+ /** 检查指定(或全部)来源的上游更新。 */
55
+ checkSources(repo?: string): Promise<SourceCheckResponse>;
56
+ /** 同步一个来源的所选(或全部)技能到上游最新版本。 */
57
+ syncSource(repo: string, skills?: string[]): Promise<SourceSyncResponse>;
58
+ /** 跟进上游删除:把所选技能移入回收站。 */
59
+ confirmDeleteSource(repo: string, skills: string[]): Promise<SourceDeleteResponse>;
60
+ /** 从回收站恢复一个技能。 */
61
+ restoreSource(name: string): Promise<SourceRestoreResponse>;
62
+ /** Permanently delete every skill currently in the trash. */
63
+ clearTrash(): Promise<SourceTrashClearResponse>;
22
64
  }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Pure grouping helpers for the skill-hub panel (no React/DOM deps, so the
3
+ * merge/classify/filter logic stays unit-testable).
4
+ *
5
+ * The "分组" view unifies two ways a skill can belong to a group:
6
+ * - user tags (sidecar SkillTag)
7
+ * - origin collections (sidecar sources → backend-aggregated CollectionGroup)
8
+ *
9
+ * Switch semantics: a skill's enabled state is global (the file is renamed
10
+ * once), so a group switch is derived from its members' actual states:
11
+ * all members enabled → 'on', all disabled → 'off', otherwise 'mixed'.
12
+ * Closing a group whose member is enabled in another group is a conflict the
13
+ * GUI resolves with a dialog; the helpers below compute both sides.
14
+ */
15
+ import type { CatalogSkill, CollectionGroup, SkillTag } from '../protocol.ts';
16
+ /** Grouped switch state derived from member enablement. */
17
+ export type GroupSwitchState = 'on' | 'off' | 'mixed';
18
+ /** The derived switch view of one group. */
19
+ export interface GroupSwitchView {
20
+ state: GroupSwitchState;
21
+ /** Writable members currently enabled. */
22
+ enabled: string[];
23
+ /** Writable members currently disabled. */
24
+ disabled: string[];
25
+ }
26
+ /**
27
+ * Derive a group switch view from its member names and the set of currently
28
+ * enabled skill names (catalog.skills). Members not in the enabled set count
29
+ * as disabled (catalog.disabled or absent read-only rows).
30
+ */
31
+ export declare function groupSwitchView(members: readonly string[], enabledNames: ReadonlySet<string>): GroupSwitchView;
32
+ /** Names of every group a skill belongs to (tags + collections). */
33
+ export declare function groupNamesOf(name: string, tags: readonly SkillTag[], collections: readonly CollectionGroup[]): string[];
34
+ /**
35
+ * Members of a group that are currently enabled AND also belong to at least
36
+ * one other group — the set a "close" action must ask about.
37
+ */
38
+ export declare function conflictsOnClose(members: readonly string[], enabledNames: ReadonlySet<string>, otherGroups: ReadonlyArray<{
39
+ members: readonly string[];
40
+ }>): string[];
41
+ /** Origin-repo filter value: skills with no source record (private skills). */
42
+ export declare const PRIVATE_SOURCE = "private";
43
+ /**
44
+ * Apply the origin filter ('all' or a specific origin repo; skills without a
45
+ * source record count as PRIVATE_SOURCE). The origins map is the store's
46
+ * skillName → repo derivation, so filtering follows the tracked source
47
+ * records instead of the filesystem root a skill happens to live under.
48
+ */
49
+ export declare function filterBySource(skills: readonly CatalogSkill[], source: string, origins: Readonly<Record<string, string>>): CatalogSkill[];
50
+ /** Catalog sort keys offered by the filter bar. */
51
+ export type SortKey = 'name' | 'added' | 'uses';
52
+ /**
53
+ * Sort a skill list in place-safe copy order: name ascending, added
54
+ * descending (newest first, unknown addedAt last), or uses descending
55
+ * (most-called first). Unknown values always trail.
56
+ */
57
+ export declare function sortSkills(skills: readonly CatalogSkill[], key: SortKey, getUses?: (name: string) => number | undefined): CatalogSkill[];
58
+ /** Localized relative-time tuple; the caller resolves it via tt(). */
59
+ export interface RelativeTime {
60
+ key: 'time.justNow' | 'time.minutesAgo' | 'time.hoursAgo' | 'time.daysAgo' | 'time.weeksAgo';
61
+ value?: number;
62
+ }
63
+ /** Format an epoch-ms timestamp as a short relative time bucket. */
64
+ export declare function formatRelativeTime(ms: number, now?: number): RelativeTime;
@@ -5,13 +5,20 @@
5
5
  */
6
6
  export declare const zh: {
7
7
  readonly 'entry.label': "技能";
8
- readonly 'entry.tooltip': "技能中枢:浏览与管理本地技能";
9
- readonly 'view.source': "按来源";
10
- readonly 'view.sets': "按 Sets";
8
+ readonly 'entry.tooltip': "技能中枢:浏览、分组与同步管理本地技能";
9
+ readonly 'view.sources': "来源";
10
+ readonly 'view.scenes': "场景";
11
+ readonly 'view.market': "市场";
12
+ readonly 'view.flat': "平铺";
13
+ readonly 'view.grouped': "分组";
11
14
  readonly 'panel.title': "技能中枢";
12
- readonly 'panel.refresh': "刷新";
15
+ readonly 'panel.count': "共 {count} 个技能";
16
+ readonly 'panel.disabledCount': "已禁用 {count}";
13
17
  readonly 'panel.new': "新建技能";
14
18
  readonly 'panel.search': "搜索技能…";
19
+ readonly 'legend.model': "模型可调 — Agent 可自动调用";
20
+ readonly 'legend.user': "用户可调 — 仅显式点名时触发";
21
+ readonly 'legend.hint': "圆点标在技能名旁;无圆点表示该技能不可被调用。";
15
22
  readonly 'panel.enabled': "已启用";
16
23
  readonly 'panel.disabled': "已禁用";
17
24
  readonly 'panel.diagnostics': "发现诊断";
@@ -19,6 +26,65 @@ export declare const zh: {
19
26
  readonly 'panel.emptyAll': "本地还没有技能。点击「新建技能」创建第一个。";
20
27
  readonly 'panel.loading': "读取中…";
21
28
  readonly 'panel.incomplete': "(目录可能不完整)";
29
+ readonly 'market.addHint': "像 codex 一样添加仓库源:输入 owner/repo 或 GitHub 链接,扫描其中的技能并一键导入;导入后自动跟踪上游更新。";
30
+ readonly 'market.addPlaceholder': "owner/repo 或 https://github.com/…";
31
+ readonly 'market.addSource': "添加源";
32
+ readonly 'market.noSources': "还没有市场源。从下方内置市场添加,或输入一个 GitHub 仓库。";
33
+ readonly 'market.catalogTitle': "内置市场";
34
+ readonly 'market.catalogHint': "精选技能仓库,添加后即可扫描安装,并持续检查更新。";
35
+ readonly 'market.catalog.anthropics': "Anthropic 官方技能合集(Claude Skills)";
36
+ readonly 'market.catalog.superpowers': "Superpowers 社区技能合集";
37
+ readonly 'market.catalog.mattpocock': "Matt Pocock 技能集";
38
+ readonly 'market.catalog.openDesign': "设计技能合集(design-templates)";
39
+ readonly 'market.added': "已添加";
40
+ readonly 'market.add': "添加";
41
+ readonly 'market.mySources': "我的市场源";
42
+ readonly 'market.installed': "已装 {count}";
43
+ readonly 'market.updatable': "可更新 {count}";
44
+ readonly 'market.deletedUpstream': "上游已删 {count}";
45
+ readonly 'market.checkAll': "检查全部";
46
+ readonly 'market.updateAll': "全部更新";
47
+ readonly 'market.updateAllConfirmTitle': "批量更新全部技能?";
48
+ readonly 'market.updateAllConfirmText': "将把以下来源的可更新技能更新到上游最新版本(覆盖本地修改):";
49
+ readonly 'market.updateAllItem': "{repo}({count} 个技能)";
50
+ readonly 'market.updateAllDone': "已更新 {count} 个来源";
51
+ readonly 'market.deleteSource': "移除源";
52
+ readonly 'market.scan': "扫描";
53
+ readonly 'market.scanning': "扫描中…";
54
+ readonly 'market.check': "检查";
55
+ readonly 'market.sync': "同步";
56
+ readonly 'market.syncing': "同步中…";
57
+ readonly 'market.updated': "有更新";
58
+ readonly 'market.newRelease': "新版本 v{version}";
59
+ readonly 'market.branchTitle': "选择分支";
60
+ readonly 'market.branchHint': "该仓库没有正式发布,选择要跟踪的分支(默认为 main):";
61
+ readonly 'market.branchConfirm': "确定";
62
+ readonly 'market.syncTitle': "同步本地技能";
63
+ readonly 'market.syncText': "市场源已对齐到 {ref},要同步更新以下本地技能吗?";
64
+ readonly 'market.syncNone': "该来源还没有导入本地技能。";
65
+ readonly 'market.syncCancel': "跳过";
66
+ readonly 'market.removeHint': "移除源不影响已安装的技能。";
67
+ readonly 'repo.ready': "发现 {count} 个可导入技能";
68
+ readonly 'repo.empty': "没有找到可导入技能。";
69
+ readonly 'repo.selectAll': "全选";
70
+ readonly 'repo.clearAll': "清空";
71
+ readonly 'repo.import': "导入所选 ({count})";
72
+ readonly 'repo.importing': "导入中…";
73
+ readonly 'repo.existing': "已存在";
74
+ readonly 'repo.files': "{count} 个文件 · {size}";
75
+ readonly 'repo.imported': "导入成功 {count} 个";
76
+ readonly 'repo.skippedExisting': "跳过已存在 {count} 个";
77
+ readonly 'repo.failed': "失败 {count} 个";
78
+ readonly 'repo.root.skills': "技能 skills";
79
+ readonly 'repo.root.designTemplates': "模板 design-templates";
80
+ readonly 'update.check': "检查更新";
81
+ readonly 'update.checking': "检查中…";
82
+ readonly 'update.upToDate': "已是最新版本 v{version}";
83
+ readonly 'update.available': "发现新版本 v{version}(当前 v{current})";
84
+ readonly 'update.newVersion': "新版本 v{version}";
85
+ readonly 'update.viewRelease': "查看发布";
86
+ readonly 'update.error': "检查更新失败:{error}";
87
+ readonly 'update.unavailable': "暂无可用的发布版本";
22
88
  readonly 'group.project-dsh': "项目 .dsh/skills";
23
89
  readonly 'group.project-agents': "项目 .agents/skills";
24
90
  readonly 'group.custom': "自定义目录";
@@ -27,19 +93,80 @@ export declare const zh: {
27
93
  readonly 'group.user-agents': "用户 ~/.agents/skills";
28
94
  readonly 'group.bundled': "内置";
29
95
  readonly 'group.other': "其他来源";
30
- readonly 'group.uncategorized': "未归类";
31
- readonly 'badge.model': "模型可调";
32
- readonly 'badge.user': "用户可调";
33
- readonly 'badge.uses': "{count} 次调用";
96
+ readonly 'groups.new': "新建场景";
97
+ readonly 'groups.namePlaceholder': "场景名";
98
+ readonly 'groups.edit': "编辑";
99
+ readonly 'groups.rename': "保存名称";
100
+ readonly 'groups.delete': "删除场景";
101
+ readonly 'groups.saveMembers': "保存成员";
102
+ readonly 'groups.membersHint': "勾选技能加入此场景(含已禁用)。";
103
+ readonly 'groups.empty': "还没有场景。先新建一个,再把技能归类。";
104
+ readonly 'groups.noCollections': "暂无来源组。从市场导入技能后自动按来源聚合。";
105
+ readonly 'groups.personal': "个人";
106
+ readonly 'groups.noWritable': "该组没有可写技能(只读技能无法由中枢开关)";
107
+ readonly 'groups.closeAll': "全部关闭";
108
+ readonly 'groups.keepOn': "保留开启";
109
+ readonly 'groups.conflictTitle': "关闭此组?";
110
+ readonly 'groups.conflictText': "以下技能也在其他组中开启,关闭它们会影响那些组:";
111
+ readonly 'filter.allSources': "全部来源";
112
+ readonly 'filter.private': "个人";
113
+ readonly 'sort.name': "按名称";
114
+ readonly 'sort.added': "按添加时间";
115
+ readonly 'sort.uses': "按调用次数";
116
+ readonly 'time.justNow': "刚刚";
117
+ readonly 'time.minutesAgo': "{value} 分钟前";
118
+ readonly 'time.hoursAgo': "{value} 小时前";
119
+ readonly 'time.daysAgo': "{value} 天前";
120
+ readonly 'time.weeksAgo': "{value} 周前";
121
+ readonly 'badge.source.project-dsh': "项目 .dsh";
122
+ readonly 'badge.source.project-agents': "项目 .agents";
123
+ readonly 'badge.source.custom': "自定义";
124
+ readonly 'badge.source.runtime': "运行时";
125
+ readonly 'badge.source.user-dsh': "用户 .dsh";
126
+ readonly 'badge.source.user-agents': "用户 .agents";
127
+ readonly 'badge.source.bundled': "内置";
34
128
  readonly 'row.readonly': "只读";
35
129
  readonly 'row.disable': "禁用";
36
130
  readonly 'row.enable': "启用";
131
+ readonly 'row.delete': "移入回收站";
132
+ readonly 'delete.confirmTitle': "移入回收站?";
133
+ readonly 'delete.confirmText': "确定把「{name}」移入回收站吗?可随时恢复。";
134
+ readonly 'delete.confirm': "移入回收站";
37
135
  readonly 'detail.back': "返回列表";
38
136
  readonly 'detail.provider': "提供者";
39
- readonly 'detail.source': "来源";
137
+ readonly 'detail.addedAt': "添加时间";
138
+ readonly 'detail.updatedAt': "更新时间";
40
139
  readonly 'detail.path': "路径";
140
+ readonly 'detail.whenToUse': "适用场景";
141
+ readonly 'detail.uses': "调用次数";
142
+ readonly 'detail.groups': "所属场景";
41
143
  readonly 'detail.loading': "读取技能正文…";
42
- readonly 'form.title': "新建技能";
144
+ readonly 'source.private': "个人技能(未绑定上游,不检查更新)";
145
+ readonly 'source.commit': "已同步版本";
146
+ readonly 'source.unverified': "尚未核对上游";
147
+ readonly 'source.check': "检查更新";
148
+ readonly 'source.checkHint': "点击检查上游更新";
149
+ readonly 'source.checking': "检查中…";
150
+ readonly 'source.upToDate': "已是最新";
151
+ readonly 'source.updated': "有更新 {count} 个";
152
+ readonly 'source.deleted': "上游已删除 {count} 个";
153
+ readonly 'source.error': "检查失败";
154
+ readonly 'source.throttled': "刚刚检查过";
155
+ readonly 'source.sync': "同步";
156
+ readonly 'source.syncing': "同步中…";
157
+ readonly 'source.syncConfirmTitle': "同步技能?";
158
+ readonly 'source.syncConfirmText': "将用上游最新版本覆盖本地对以下技能的所有修改:";
159
+ readonly 'source.followDelete': "跟进删除";
160
+ readonly 'source.deleteConfirmTitle': "跟进上游删除?";
161
+ readonly 'source.deleteConfirmText': "以下技能已从上游仓库移除,本地目录将移入回收站(可恢复):";
162
+ readonly 'source.trash': "回收站";
163
+ readonly 'source.restore': "恢复";
164
+ readonly 'source.clearTrash': "清空回收站";
165
+ readonly 'source.clearTrashConfirmTitle': "清空回收站?";
166
+ readonly 'source.clearTrashConfirmText': "回收站里的技能会被永久删除,无法恢复。此操作不可撤销。";
167
+ readonly 'source.clearTrashConfirm': "永久删除";
168
+ readonly 'form.capabilityHint': "能力怎么选:重复方法 → 技能;外部系统 → MCP;长期资料 → 知识库。";
169
+ readonly 'form.descPlaceholder': "一句话说明用途(含触发词),Agent 靠它自动激活技能";
43
170
  readonly 'form.name': "技能名(kebab-case,如 code-review)";
44
171
  readonly 'form.desc': "描述(一句话路由说明)";
45
172
  readonly 'form.root': "目标目录";
@@ -50,25 +177,35 @@ export declare const zh: {
50
177
  readonly 'form.error': "创建失败:";
51
178
  readonly 'err.dismiss': "知道了";
52
179
  readonly 'settings.title': "Skill Hub";
53
- readonly 'settings.description': "管理 dsh 本地技能目录:浏览、启用/禁用、诊断与新建。";
180
+ readonly 'settings.description': "管理 dsh 本地技能目录:浏览、分组、来源同步与新建。";
54
181
  readonly 'settings.enabled': "启用插件";
55
182
  readonly 'settings.enabledHint': "关闭后技能中枢的路由、入口与公告全部下线。";
56
183
  readonly 'settings.announceToAgent': "向 Agent 公告";
57
184
  readonly 'settings.announceToAgentHint': "在系统提示中加入本插件说明,用户提到技能管理时 Agent 知道如何协作。";
185
+ readonly 'settings.dotModelColor': "模型可调圆点颜色";
186
+ readonly 'settings.dotModelColorHint': "技能名旁蓝色圆点的颜色(#rrggbb)。";
187
+ readonly 'settings.dotUserColor': "用户可调圆点颜色";
188
+ readonly 'settings.dotUserColorHint': "技能名旁绿色圆点的颜色(#rrggbb)。";
189
+ readonly 'settings.showUseCount': "显示调用次数";
190
+ readonly 'settings.showUseCountHint': "在技能名旁显示琥珀色调用次数。";
191
+ readonly 'settings.showUseTime': "显示最近调用时间";
192
+ readonly 'settings.showUseTimeHint': "在技能名行右侧显示相对时间(如「3 天前」)。";
193
+ readonly 'settings.showGroupSummary': "显示分组汇总";
194
+ readonly 'settings.showGroupSummaryHint': "在分组标题后汇总调用次数与最近调用时间。";
58
195
  readonly 'settings.inherit': "继承";
59
196
  readonly 'settings.on': "开";
60
197
  readonly 'settings.off': "关";
61
198
  readonly 'settings.overridden': "已覆盖";
62
- readonly 'settings.reset': "重置";
199
+ readonly 'settings.reset': "恢复默认";
63
200
  readonly 'settings.unsaved': "未保存";
64
201
  readonly 'settings.save': "保存";
65
202
  readonly 'settings.saving': "保存中…";
66
- readonly 'settings.discard': "放弃更改";
67
- readonly 'settings.saveFailed': "保存失败";
68
- readonly 'settings.readOnly': "当前部署只读,无法编辑。";
69
- readonly 'settings.notExposed': "命名空间未挂载。";
70
- readonly 'settings.collapse': "折叠";
71
- readonly 'settings.expand': "展开";
203
+ readonly 'settings.discard': "放弃修改";
204
+ readonly 'settings.saveFailed': "本部署没有接受这些值,已保留供你修改。";
205
+ readonly 'settings.readOnly': "本部署的设置为只读。";
206
+ readonly 'settings.notExposed': "本部署没有挂载该设置命名空间。";
207
+ readonly 'settings.collapse': "收起设置";
208
+ readonly 'settings.expand': "展开设置";
72
209
  };
73
210
  export declare const en: Record<HubKey, string>;
74
211
  /** Union of every translatable key (the namespace's registered dictionary type). */
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Built-in market catalog: well-known skill repos shown on the market tab so
3
+ * users can browse and install without knowing repo URLs (cc-switch-style).
4
+ * Only the repo slug lives here; adding goes through the normal
5
+ * market-source route and records upstream tracking like any manual source.
6
+ */
7
+ import type { HubKey } from './locales.ts';
8
+ export interface MarketCatalogEntry {
9
+ repo: string;
10
+ /** locales.ts key for the one-line description. */
11
+ descriptionKey: HubKey;
12
+ }
13
+ /** 默认市场目录:精选技能仓库(顺序即展示顺序)。 */
14
+ export declare const MARKET_CATALOG: readonly MarketCatalogEntry[];
@@ -0,0 +1,12 @@
1
+ /**
2
+ * One disabled skill row (name + description + root badge + enable switch).
3
+ * Shared by the source-group lists, the scene-group lists, and the bottom
4
+ * disabled section.
5
+ */
6
+ import type { JSX } from 'react';
7
+ import type { DisabledSkill } from '../../protocol.ts';
8
+ export declare function DisabledRow(props: {
9
+ record: DisabledSkill;
10
+ busy: boolean;
11
+ onEnable: () => void;
12
+ }): JSX.Element;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Group-header usage summary: total invocation count chip + the group's most
3
+ * recent last-used time. Honours the showGroupSummary config switch.
4
+ */
5
+ import type { JSX } from 'react';
6
+ import type { SkillHubState } from './useSkillHub.ts';
7
+ export declare function GroupSummary(props: {
8
+ members: readonly string[];
9
+ hub: SkillHubState;
10
+ }): JSX.Element;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Market tab: the built-in market catalog (one-click add), the user's market
3
+ * sources with aggregated per-repo state (installed / updatable / deleted
4
+ * upstream), check-all and update-all actions, and the repo scan result with
5
+ * the importable skill checklist.
6
+ */
7
+ import type { JSX } from 'react';
8
+ import type { SkillHubState } from './useSkillHub.ts';
9
+ export declare function MarketView(props: {
10
+ hub: SkillHubState;
11
+ }): JSX.Element;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Scenes tab: user tag groups (one card per scene with the tri-state switch
3
+ * and edit entry) plus the new-scene form. Scenes are the user's own
4
+ * enable/disable units (e.g. a Godot scene vs a Java scene); upstream repos
5
+ * are managed in the sources tab.
6
+ */
7
+ import type { JSX } from 'react';
8
+ import type { SkillHubState } from './useSkillHub.ts';
9
+ export declare function ScenesView(props: {
10
+ hub: SkillHubState;
11
+ }): JSX.Element;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Full-page skill detail view: metadata, upstream source card with
3
+ * check/sync/follow-delete actions, and the raw SKILL.md body. Pure
4
+ * presentation — every state value and action arrives as a prop, so the
5
+ * panel stays the single owner of state.
6
+ */
7
+ import type { JSX } from 'react';
8
+ import type { GroupsResponse, HubConfig, SkillDetail, SourceCheckResult, SourcesResponse } from '../../protocol.ts';
9
+ export interface SkillDetailViewProps {
10
+ detail: SkillDetail;
11
+ hubConfig: HubConfig | null;
12
+ /** skillName → usage stat (count + last used). */
13
+ uses: ReadonlyMap<string, {
14
+ count: number;
15
+ lastUsed?: number;
16
+ }>;
17
+ groupsState: GroupsResponse | null;
18
+ sourcesState: SourcesResponse | null;
19
+ sourceCheck: Readonly<Record<string, SourceCheckResult>>;
20
+ checkingSource: string | null;
21
+ syncingSource: string | null;
22
+ loading: boolean;
23
+ onBack: () => void;
24
+ /** Check one source repo for upstream updates. */
25
+ onCheck: (repo: string) => void;
26
+ /** Request syncing the skill (overwrites local edits; opens a confirm). */
27
+ onSync: (repo: string, skills: string[]) => void;
28
+ /** Request following the upstream deletion (moves into the trash). */
29
+ onFollowDelete: (repo: string, skills: string[]) => void;
30
+ }
31
+ export declare function SkillDetailView(props: SkillDetailViewProps): JSX.Element;
@@ -1,7 +1,15 @@
1
1
  /**
2
- * The skill hub panel: full catalog grouped by source, search, enable/
3
- * disable toggles, discovery diagnostics, disabled-skill re-enable, skill
4
- * body inspection, and the new-skill scaffold form.
2
+ * The skill hub panel: catalog grouped by tags + source collections, search
3
+ * and filter in one row, per-group tri-state switches with conflict dialogs,
4
+ * upstream source tracking (check / sync / follow upstream deletion into a
5
+ * restorable trash), codex-style market sources, disabled re-enable,
6
+ * detail inspection, and the new-skill scaffold form.
7
+ *
8
+ * Thin shell: state and flows live in useSkillHub, the tab contents live in
9
+ * SourcesView / ScenesView / MarketView, and the dialog family lives in
10
+ * dialogs.tsx. This component owns only the shared chrome (header, banners,
11
+ * filter bar, shared sections) and the view routing — and holds no hooks,
12
+ * so the detail / tag-editor early returns are safe.
5
13
  */
6
14
  import type { SkillHubApi } from '../api.ts';
7
15
  export interface SkillHubPanelProps {
@@ -0,0 +1,11 @@
1
+ /**
2
+ * One enabled skill row: name + invocation dots + usage meta, delete and
3
+ * disable actions. Shared by the flat list and both grouped views.
4
+ */
5
+ import type { JSX } from 'react';
6
+ import type { CatalogSkill } from '../../protocol.ts';
7
+ import type { SkillHubState } from './useSkillHub.ts';
8
+ export declare function SkillRow(props: {
9
+ skill: CatalogSkill;
10
+ hub: SkillHubState;
11
+ }): JSX.Element;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Source check-status badges (up-to-date / updated / deleted / error /
3
+ * throttled / unverified). Shared by the panel's source-group headers and
4
+ * the skill detail view.
5
+ *
6
+ * In the group headers the badge doubles as the re-check affordance: it
7
+ * shows a clickable "检查更新" badge before the first check, "检查中…" while
8
+ * checking, and the status badge (clickable again to re-check) afterwards.
9
+ */
10
+ import type { JSX } from 'react';
11
+ import type { SourceCheckResult } from '../../protocol.ts';
12
+ export declare function SourceStatusBadge(props: {
13
+ check: SourceCheckResult | undefined;
14
+ /** 正在检查该来源(显示「检查中…」)。 */
15
+ checking?: boolean;
16
+ /** 提供后徽章区域可点击触发检查(组头用;详情页有自己的检查按钮)。 */
17
+ onCheck?: () => void;
18
+ }): JSX.Element | null;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Sources tab: the flat skill list or the grouped view (one card per
3
+ * upstream collection with check/sync/follow-delete actions and the
4
+ * tri-state switch, plus the uncategorized "personal" card).
5
+ */
6
+ import type { JSX } from 'react';
7
+ import type { SkillHubState } from './useSkillHub.ts';
8
+ export declare function SourcesView(props: {
9
+ hub: SkillHubState;
10
+ }): JSX.Element;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Full-page tag (scene) editor: rename / delete header, member checkbox
3
+ * lists (enabled + disabled skills), and the save-members action. Pure
4
+ * presentation — the draft state lives in the panel and arrives as props.
5
+ */
6
+ import type { JSX } from 'react';
7
+ import type { CatalogResponse, SkillTag } from '../../protocol.ts';
8
+ export interface TagEditorViewProps {
9
+ tag: SkillTag;
10
+ /** Current name draft (panel-owned). */
11
+ editName: string;
12
+ /** Current member-checkbox draft (panel-owned). */
13
+ membersDraft: ReadonlySet<string>;
14
+ /** Current member-list search text (panel-owned). */
15
+ editSearch: string;
16
+ catalog: CatalogResponse | null;
17
+ tagBusy: boolean;
18
+ onBack: () => void;
19
+ onEditName: (value: string) => void;
20
+ onEditSearch: (value: string) => void;
21
+ onToggleMember: (name: string, checked: boolean) => void;
22
+ /** Rename with the current draft (disabled while blank). */
23
+ onRename: () => void;
24
+ /** Delete this tag (hidden for the default scene). */
25
+ onDelete: () => void;
26
+ /** Persist the current member draft and leave the editor. */
27
+ onSaveMembers: () => void;
28
+ }
29
+ export declare function TagEditorView(props: TagEditorViewProps): JSX.Element;