dsh-skill-hub 0.3.6 → 0.3.7
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/client.js +890 -356
- package/lib/client.js.map +1 -1
- package/lib/index.js +401 -47
- package/lib/types/client/SkillHubSettingsCard.d.ts +0 -2
- package/lib/types/client/api.d.ts +5 -1
- package/lib/types/client/helpers.d.ts +10 -0
- package/lib/types/client/locales.d.ts +30 -0
- package/lib/types/client/panel/DisabledRow.d.ts +2 -0
- package/lib/types/client/panel/SkillDetailView.d.ts +5 -1
- package/lib/types/client/panel/dialogs.d.ts +19 -0
- package/lib/types/client/panel/useSkillHub.d.ts +12 -1
- package/lib/types/client/settings-card.d.ts +0 -17
- package/lib/types/client/settings-form.d.ts +0 -1
- package/lib/types/protocol.d.ts +40 -17
- package/lib/types/repo.d.ts +4 -6
- package/lib/types/skillfs.d.ts +13 -0
- package/package.json +29 -28
- package/src/client/SkillHubSettingsCard.tsx +0 -2
- package/src/client/api.ts +18 -0
- package/src/client/helpers.ts +40 -0
- package/src/client/locales.ts +60 -0
- package/src/client/panel/DisabledRow.tsx +22 -7
- package/src/client/panel/MarketView.tsx +8 -1
- package/src/client/panel/ScenesView.tsx +1 -1
- package/src/client/panel/SkillDetailView.tsx +35 -11
- package/src/client/panel/SkillHubPanel.tsx +42 -4
- package/src/client/panel/SkillRow.tsx +5 -2
- package/src/client/panel/SourcesView.tsx +2 -17
- package/src/client/panel/dialogs.tsx +61 -0
- package/src/client/panel/panel.module.css +1 -8
- package/src/client/panel/useSkillHub.ts +97 -12
- package/src/client/settings-card.tsx +0 -42
- package/src/client/settings-form.ts +1 -5
- package/src/protocol.ts +42 -8
- package/src/repo.ts +71 -29
- package/src/routes.test.ts +22 -0
- package/src/routes.ts +181 -10
- package/src/skillfs.ts +188 -3
|
@@ -64,12 +64,22 @@ export declare const zh: {
|
|
|
64
64
|
readonly 'market.branchTitle': "选择分支";
|
|
65
65
|
readonly 'market.branchHint': "该仓库没有正式发布,选择要跟踪的分支(默认为 main):";
|
|
66
66
|
readonly 'market.branchConfirm': "确定";
|
|
67
|
+
readonly 'market.versionTitle': "切换跟踪版本";
|
|
68
|
+
readonly 'market.versionText': "选择 {repo} 要跟踪的版本,切换后建议重新扫描并同步已装技能";
|
|
69
|
+
readonly 'market.versionCurrent': "当前 {ref}";
|
|
70
|
+
readonly 'market.versionReleases': "发布版";
|
|
71
|
+
readonly 'market.versionBranches': "分支";
|
|
72
|
+
readonly 'market.versionCustom': "自定义(tag / 分支 / commit)";
|
|
73
|
+
readonly 'market.versionConfirm': "切换到 {ref}";
|
|
74
|
+
readonly 'market.versionHint': "点击切换跟踪版本";
|
|
75
|
+
readonly 'market.unpinned': "未定版";
|
|
67
76
|
readonly 'market.syncTitle': "同步本地技能";
|
|
68
77
|
readonly 'market.syncText': "市场源已对齐到 {ref},要同步更新以下本地技能吗?";
|
|
69
78
|
readonly 'market.syncNone': "该来源还没有导入本地技能。";
|
|
70
79
|
readonly 'market.syncCancel': "跳过";
|
|
71
80
|
readonly 'market.removeHint': "移除源不影响已安装的技能。";
|
|
72
81
|
readonly 'repo.ready': "发现 {count} 个可导入技能";
|
|
82
|
+
readonly 'repo.truncated': "⚠ 仓库过大,仅展示部分技能(GitHub 截断),可缩小仓库或指定子目录";
|
|
73
83
|
readonly 'repo.empty': "没有找到可导入技能。";
|
|
74
84
|
readonly 'repo.selectAll': "全选";
|
|
75
85
|
readonly 'repo.clearAll': "清空";
|
|
@@ -142,6 +152,26 @@ export declare const zh: {
|
|
|
142
152
|
readonly 'row.enable': "启用";
|
|
143
153
|
readonly 'row.delete': "移入回收站";
|
|
144
154
|
readonly 'row.open': "查看 {name} 详情(回车)";
|
|
155
|
+
readonly 'row.duplicate': "重名";
|
|
156
|
+
readonly 'row.duplicateHint': "同名技能存在多个来源,当前显示为优先级最高的版本";
|
|
157
|
+
readonly 'row.copy': "复制";
|
|
158
|
+
readonly 'row.copyMention': "复制 $mention";
|
|
159
|
+
readonly 'row.copied': "已复制";
|
|
160
|
+
readonly 'row.copyPath': "复制路径";
|
|
161
|
+
readonly 'detail.copyMention': "复制 $mention";
|
|
162
|
+
readonly 'detail.copyPath': "复制路径";
|
|
163
|
+
readonly 'detail.copied': "已复制";
|
|
164
|
+
readonly 'diag.fix': "修复";
|
|
165
|
+
readonly 'diag.fixing': "修复中…";
|
|
166
|
+
readonly 'diag.fixed': "已修复";
|
|
167
|
+
readonly 'diag.fixConfirm': "用自动修复重写以下文件的 frontmatter?建议先备份:{path}";
|
|
168
|
+
readonly 'filter.invocation': "调用";
|
|
169
|
+
readonly 'filter.invocationAll': "全部调用";
|
|
170
|
+
readonly 'filter.modelOnly': "模型可调";
|
|
171
|
+
readonly 'filter.userOnly': "用户可调";
|
|
172
|
+
readonly 'filter.showing': "显示 {shown}/{total}(已启用){filtered}";
|
|
173
|
+
readonly 'filter.filteredSuffix': " · 已筛选";
|
|
174
|
+
readonly 'filter.shortened': "短描述 {count} 条,悬浮看全文";
|
|
145
175
|
readonly 'delete.confirmTitle': "移入回收站?";
|
|
146
176
|
readonly 'delete.confirmText': "确定把「{name}」移入回收站吗?可随时恢复。";
|
|
147
177
|
readonly 'delete.confirm': "移入回收站";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* presentation — every state value and action arrives as a prop, so the
|
|
5
5
|
* panel stays the single owner of state.
|
|
6
6
|
*/
|
|
7
|
-
import type
|
|
7
|
+
import { type JSX } from 'react';
|
|
8
8
|
import type { GroupsResponse, HubConfig, SkillDetail, SourceCheckResult, SourcesResponse } from '../../protocol.ts';
|
|
9
9
|
export interface SkillDetailViewProps {
|
|
10
10
|
detail: SkillDetail;
|
|
@@ -20,6 +20,10 @@ export interface SkillDetailViewProps {
|
|
|
20
20
|
checkingSource: string | null;
|
|
21
21
|
syncingSource: string | null;
|
|
22
22
|
loading: boolean;
|
|
23
|
+
/** Whether the skill is currently hub-disabled (served from the .disabled file). */
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
/** Re-enable a hub-disabled skill. */
|
|
26
|
+
onEnable?: () => void;
|
|
23
27
|
onBack: () => void;
|
|
24
28
|
/** Check one source repo for upstream updates. */
|
|
25
29
|
onCheck: (repo: string) => void;
|
|
@@ -27,6 +27,16 @@ export interface BranchChoiceState {
|
|
|
27
27
|
branches: string[];
|
|
28
28
|
selected: string;
|
|
29
29
|
}
|
|
30
|
+
/** Version picker for a market source: releases + branches + custom ref. */
|
|
31
|
+
export interface VersionChoiceState {
|
|
32
|
+
repo: string;
|
|
33
|
+
current?: string;
|
|
34
|
+
releases: string[];
|
|
35
|
+
branches: string[];
|
|
36
|
+
selected: string;
|
|
37
|
+
custom: string;
|
|
38
|
+
loading: boolean;
|
|
39
|
+
}
|
|
30
40
|
/** Post-sync skill update dialog: which tracked skills to refresh. */
|
|
31
41
|
export interface MarketSyncDialogState {
|
|
32
42
|
repo: string;
|
|
@@ -63,6 +73,15 @@ export declare function BranchChoiceDialog(props: {
|
|
|
63
73
|
onCancel: () => void;
|
|
64
74
|
onConfirm: () => void;
|
|
65
75
|
}): JSX.Element;
|
|
76
|
+
/** Version picker: switch a market source's tracked ref (release / branch / custom). */
|
|
77
|
+
export declare function VersionChoiceDialog(props: {
|
|
78
|
+
choice: VersionChoiceState;
|
|
79
|
+
busy: boolean;
|
|
80
|
+
onSelect: (ref: string) => void;
|
|
81
|
+
onCustom: (custom: string) => void;
|
|
82
|
+
onCancel: () => void;
|
|
83
|
+
onConfirm: () => void;
|
|
84
|
+
}): JSX.Element;
|
|
66
85
|
/** Post-sync selection: which tracked skills to batch-update to the new version. */
|
|
67
86
|
export declare function MarketSyncDialog(props: {
|
|
68
87
|
dialog: MarketSyncDialogState;
|
|
@@ -9,7 +9,7 @@ import { type FormEvent } from 'react';
|
|
|
9
9
|
import type { CatalogResponse, CatalogSkill, DisabledSkill, GroupsResponse, HubConfig, MarketSourceRecord, RepoDiscoverResponse, RepoImportProgressResponse, SkillDetail, SkillTag, SourceCheckResult, SourcesResponse, UpdateCheckResponse, WritableRoot } from '../../protocol.ts';
|
|
10
10
|
import type { SkillHubApi } from '../api.ts';
|
|
11
11
|
import { type SortKey, type GroupSwitchState } from '../grouping.ts';
|
|
12
|
-
import type { BranchChoiceState, ConfirmDialogState, ConflictDialogState, MarketSyncDialogState } from './dialogs.tsx';
|
|
12
|
+
import type { BranchChoiceState, ConfirmDialogState, ConflictDialogState, MarketSyncDialogState, VersionChoiceState } from './dialogs.tsx';
|
|
13
13
|
/** One-shot self-update check state. */
|
|
14
14
|
type UpdateState = {
|
|
15
15
|
status: 'idle';
|
|
@@ -76,6 +76,7 @@ export declare function useSkillHub(api: SkillHubApi): {
|
|
|
76
76
|
tab: "sources" | "scenes" | "market";
|
|
77
77
|
skillView: "flat" | "groups";
|
|
78
78
|
sourceFilter: string;
|
|
79
|
+
invocationFilter: "user" | "model" | "all";
|
|
79
80
|
sortKey: SortKey;
|
|
80
81
|
marketState: MarketState;
|
|
81
82
|
marketCheck: Readonly<Record<string, {
|
|
@@ -117,6 +118,8 @@ export declare function useSkillHub(api: SkillHubApi): {
|
|
|
117
118
|
subdividedProjects: ReadonlySet<string>;
|
|
118
119
|
showLegend: boolean;
|
|
119
120
|
editMode: boolean;
|
|
121
|
+
versionDialog: VersionChoiceState | null;
|
|
122
|
+
versionBusy: boolean;
|
|
120
123
|
actionNames: Set<string>;
|
|
121
124
|
viewNames: Set<string>;
|
|
122
125
|
normalized: string;
|
|
@@ -124,6 +127,7 @@ export declare function useSkillHub(api: SkillHubApi): {
|
|
|
124
127
|
sourceOptions: string[];
|
|
125
128
|
filtered: CatalogSkill[];
|
|
126
129
|
sorted: CatalogSkill[];
|
|
130
|
+
shortenedCount: number;
|
|
127
131
|
setLoadError: import("react").Dispatch<import("react").SetStateAction<string | null>>;
|
|
128
132
|
setSuccessBanner: import("react").Dispatch<import("react").SetStateAction<string | null>>;
|
|
129
133
|
setSearch: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
@@ -141,6 +145,7 @@ export declare function useSkillHub(api: SkillHubApi): {
|
|
|
141
145
|
setTab: import("react").Dispatch<import("react").SetStateAction<"sources" | "scenes" | "market">>;
|
|
142
146
|
setSkillView: import("react").Dispatch<import("react").SetStateAction<"flat" | "groups">>;
|
|
143
147
|
setSourceFilter: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
148
|
+
setInvocationFilter: import("react").Dispatch<import("react").SetStateAction<"user" | "model" | "all">>;
|
|
144
149
|
setSortKey: import("react").Dispatch<import("react").SetStateAction<SortKey>>;
|
|
145
150
|
setBranchChoice: import("react").Dispatch<import("react").SetStateAction<BranchChoiceState | null>>;
|
|
146
151
|
setMarketSyncDialog: import("react").Dispatch<import("react").SetStateAction<MarketSyncDialogState | null>>;
|
|
@@ -161,6 +166,7 @@ export declare function useSkillHub(api: SkillHubApi): {
|
|
|
161
166
|
setEditSearch: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
162
167
|
setShowLegend: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
163
168
|
setEditMode: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
169
|
+
setVersionDialog: import("react").Dispatch<import("react").SetStateAction<VersionChoiceState | null>>;
|
|
164
170
|
toggleGroupCollapse: (key: string) => void;
|
|
165
171
|
toggleSubdivide: (key: string) => void;
|
|
166
172
|
checkUpdate: () => Promise<void>;
|
|
@@ -177,6 +183,11 @@ export declare function useSkillHub(api: SkillHubApi): {
|
|
|
177
183
|
requestDelete: (repo: string, skills: string[]) => void;
|
|
178
184
|
restoreTrash: (name: string) => Promise<void>;
|
|
179
185
|
clearTrash: () => Promise<void>;
|
|
186
|
+
fixingPaths: ReadonlySet<string>;
|
|
187
|
+
fixDiagnostic: (path: string) => Promise<void>;
|
|
188
|
+
clearListFilters: () => void;
|
|
189
|
+
openVersionDialog: (repo: string) => Promise<void>;
|
|
190
|
+
confirmVersionDialog: () => Promise<void>;
|
|
180
191
|
requestDeleteSkill: (name: string) => void;
|
|
181
192
|
runDeleteSkill: () => Promise<void>;
|
|
182
193
|
requestDeleteGroup: (name: string, skillNames: string[]) => void;
|
|
@@ -30,23 +30,6 @@ export interface PluginSettingsCardProps {
|
|
|
30
30
|
* @returns the card, or nothing while the namespace is still loading.
|
|
31
31
|
*/
|
|
32
32
|
export declare function PluginSettingsCard(props: PluginSettingsCardProps): ReactElement | null;
|
|
33
|
-
/** One staged boolean field: 继承 / 开 / 关. */
|
|
34
|
-
export interface BooleanFieldProps {
|
|
35
|
-
id: string;
|
|
36
|
-
label: string;
|
|
37
|
-
hint: string;
|
|
38
|
-
inheritLabel: string;
|
|
39
|
-
onLabel: string;
|
|
40
|
-
offLabel: string;
|
|
41
|
-
overriddenLabel: string;
|
|
42
|
-
resetLabel: string;
|
|
43
|
-
disabled: boolean;
|
|
44
|
-
text: string;
|
|
45
|
-
overridden: boolean;
|
|
46
|
-
onEdit: (text: string) => void;
|
|
47
|
-
onReset: () => void;
|
|
48
|
-
}
|
|
49
|
-
export declare function BooleanField(props: BooleanFieldProps): ReactElement;
|
|
50
33
|
/**
|
|
51
34
|
* A compact sliding switch for the card's master enable/disable control.
|
|
52
35
|
* An empty text value means the field inherits its default; the switch still
|
package/lib/types/protocol.d.ts
CHANGED
|
@@ -38,6 +38,8 @@ export declare const SKILL_HUB_API: {
|
|
|
38
38
|
readonly sourceDelete: "/api/skill-hub/sources/delete";
|
|
39
39
|
readonly sourceRestore: "/api/skill-hub/sources/restore";
|
|
40
40
|
readonly sourceTrashClear: "/api/skill-hub/sources/trash/clear";
|
|
41
|
+
readonly diagnosticFix: "/api/skill-hub/diagnostic/fix";
|
|
42
|
+
readonly marketSourceVersions: "/api/skill-hub/market/source/versions";
|
|
41
43
|
};
|
|
42
44
|
/** User-level roots the hub may write to (matches dsh-skill-filesystem ranks 400/500). */
|
|
43
45
|
export type WritableRoot = 'user-dsh' | 'user-agents';
|
|
@@ -67,6 +69,13 @@ export interface CatalogSkill {
|
|
|
67
69
|
workspace?: string;
|
|
68
70
|
/** 工作区显示标题(来自 workspace.json;无则回退为路径)。 */
|
|
69
71
|
workspaceTitle?: string;
|
|
72
|
+
/** UI metadata from agents/openai.yaml (mirrors codex SkillInterface). */
|
|
73
|
+
displayName?: string;
|
|
74
|
+
shortDescription?: string;
|
|
75
|
+
brandColor?: string;
|
|
76
|
+
iconSmall?: string;
|
|
77
|
+
iconLarge?: string;
|
|
78
|
+
defaultPrompt?: string;
|
|
70
79
|
}
|
|
71
80
|
/** One disabled skill tracked by the hub sidecar (SKILL.md renamed away). */
|
|
72
81
|
export interface DisabledSkill {
|
|
@@ -82,6 +91,16 @@ export interface DiagnosticEntry {
|
|
|
82
91
|
path: string;
|
|
83
92
|
root: string;
|
|
84
93
|
reason: string;
|
|
94
|
+
/** Whether this diagnostic can be auto-fixed (e.g. unquoted colon). */
|
|
95
|
+
fixable?: boolean;
|
|
96
|
+
}
|
|
97
|
+
/** POST /api/skill-hub/diagnostic/fix — repair a fixable diagnostic in place. */
|
|
98
|
+
export interface DiagnosticFixRequest {
|
|
99
|
+
path: string;
|
|
100
|
+
}
|
|
101
|
+
export interface DiagnosticFixResponse {
|
|
102
|
+
ok: true;
|
|
103
|
+
path: string;
|
|
85
104
|
}
|
|
86
105
|
/** GET /api/skill-hub/catalog */
|
|
87
106
|
export interface CatalogResponse {
|
|
@@ -96,6 +115,8 @@ export interface CatalogResponse {
|
|
|
96
115
|
disabled: DisabledSkill[];
|
|
97
116
|
/** Files in the writable roots the provider ignores, with reasons. */
|
|
98
117
|
diagnostics: DiagnosticEntry[];
|
|
118
|
+
/** Skill names that appeared in multiple roots (first wins, others hidden). Mirrors codex name_counts. */
|
|
119
|
+
duplicateNames?: string[];
|
|
99
120
|
}
|
|
100
121
|
/** GET /api/skill-hub/skill */
|
|
101
122
|
export interface SkillDetail {
|
|
@@ -112,6 +133,12 @@ export interface SkillDetail {
|
|
|
112
133
|
updatedAt?: number;
|
|
113
134
|
/** Markdown instruction body. */
|
|
114
135
|
content: string;
|
|
136
|
+
displayName?: string;
|
|
137
|
+
shortDescription?: string;
|
|
138
|
+
brandColor?: string;
|
|
139
|
+
iconSmall?: string;
|
|
140
|
+
iconLarge?: string;
|
|
141
|
+
defaultPrompt?: string;
|
|
115
142
|
}
|
|
116
143
|
export interface SkillDetailResponse {
|
|
117
144
|
ok: true;
|
|
@@ -342,6 +369,17 @@ export interface MarketSourceRefRequest {
|
|
|
342
369
|
/** Release tag or branch name chosen for the repo. */
|
|
343
370
|
ref: string;
|
|
344
371
|
}
|
|
372
|
+
/** GET /api/skill-hub/market/source/versions?repo= — releases + branches for the version picker. */
|
|
373
|
+
export interface MarketSourceVersionsResponse {
|
|
374
|
+
ok: true;
|
|
375
|
+
repo: string;
|
|
376
|
+
/** Currently pinned ref, when one is recorded. */
|
|
377
|
+
current?: string;
|
|
378
|
+
/** Release tags, newest first (drafts excluded). */
|
|
379
|
+
releases: string[];
|
|
380
|
+
/** Branch names, default branch first. */
|
|
381
|
+
branches: string[];
|
|
382
|
+
}
|
|
345
383
|
/** GET /api/skill-hub/market/check — update check over market sources. */
|
|
346
384
|
export interface MarketCheckResponse {
|
|
347
385
|
ok: true;
|
|
@@ -404,6 +442,8 @@ export interface RepoDiscoverResponse {
|
|
|
404
442
|
/** Branch names to choose from when ref is null (default branch first). */
|
|
405
443
|
branches?: string[];
|
|
406
444
|
entries: RepoSkillEntry[];
|
|
445
|
+
/** GitHub truncated the tree; discovery is partial (mirrors codex walk_truncated). */
|
|
446
|
+
truncated?: boolean;
|
|
407
447
|
}
|
|
408
448
|
/** POST /api/skill-hub/repo/import — install selected repo skills. */
|
|
409
449
|
export interface RepoImportRequest {
|
|
@@ -461,23 +501,6 @@ export interface RepoImportCancelResponse {
|
|
|
461
501
|
jobId: string;
|
|
462
502
|
status: 'cancelled' | 'done';
|
|
463
503
|
}
|
|
464
|
-
/** @deprecated 旧同步响应,保留供类型兼容,实际已由 Progress 代替 */
|
|
465
|
-
export interface RepoImportLegacyResponse {
|
|
466
|
-
ok: true;
|
|
467
|
-
imported: Array<{
|
|
468
|
-
name: string;
|
|
469
|
-
origin: string;
|
|
470
|
-
path: string;
|
|
471
|
-
}>;
|
|
472
|
-
skipped: Array<{
|
|
473
|
-
name: string;
|
|
474
|
-
reason: 'exists';
|
|
475
|
-
}>;
|
|
476
|
-
failed: Array<{
|
|
477
|
-
name: string;
|
|
478
|
-
error: string;
|
|
479
|
-
}>;
|
|
480
|
-
}
|
|
481
504
|
/** GET /api/skill-hub/update — check the plugin's own latest GitHub release. */
|
|
482
505
|
export interface UpdateCheckResponse {
|
|
483
506
|
ok: true;
|
package/lib/types/repo.d.ts
CHANGED
|
@@ -36,6 +36,7 @@ export declare class RepoFetchError extends Error {
|
|
|
36
36
|
export declare function setGithubToken(token: string | undefined): void;
|
|
37
37
|
/** Authorization header for api.github.com / raw.githubusercontent.com calls. */
|
|
38
38
|
export declare function githubAuthHeaders(): Record<string, string>;
|
|
39
|
+
export declare function clearEtagCache(): void;
|
|
39
40
|
/**
|
|
40
41
|
* Build a RepoFetchError; when the response shows an exhausted rate limit,
|
|
41
42
|
* report the reset time instead of a bare HTTP status.
|
|
@@ -48,15 +49,10 @@ export declare function repoSlug(ref: RepoRef): string;
|
|
|
48
49
|
* Only github.com URLs are accepted in v1.
|
|
49
50
|
*/
|
|
50
51
|
export declare function normalizeRepoInput(input: string): RepoRef | null;
|
|
51
|
-
/**
|
|
52
|
-
* Load repo metadata and the recursive git tree at the given ref. The meta
|
|
53
|
-
* request always resolves the default branch (used when ref is absent); the
|
|
54
|
-
* tree is fetched at `ref ?? default_branch` so an explicit branch/tag scans
|
|
55
|
-
* the exact same content a later download would fetch.
|
|
56
|
-
*/
|
|
57
52
|
export declare function loadRepoTree(repo: string, ref?: string, fetchImpl?: typeof fetch): Promise<{
|
|
58
53
|
ref: string;
|
|
59
54
|
tree: RepoTreeItem[];
|
|
55
|
+
truncated: boolean;
|
|
60
56
|
}>;
|
|
61
57
|
/** Collect every file inside a skill directory, including SKILL.md itself. */
|
|
62
58
|
export declare function collectRepoSkillFiles(tree: readonly RepoTreeItem[], dir: string): RepoFile[];
|
|
@@ -94,6 +90,8 @@ export declare function cleanupLeftoverImportDirs(targetRoot: string): Promise<n
|
|
|
94
90
|
* repo has no releases (GitHub's /releases/latest skips prereleases/drafts).
|
|
95
91
|
*/
|
|
96
92
|
export declare function getLatestReleaseTag(repo: string, fetchImpl?: typeof fetch): Promise<string | undefined>;
|
|
93
|
+
/** Release tags of a repo, newest first (skips drafts, keeps prereleases). */
|
|
94
|
+
export declare function listRepoReleases(repo: string, fetchImpl?: typeof fetch): Promise<string[]>;
|
|
97
95
|
/** Branch names of a repo, default branch first (one GitHub API request). */
|
|
98
96
|
export declare function listRepoBranches(repo: string, fetchImpl?: typeof fetch): Promise<string[]>;
|
|
99
97
|
/**
|
package/lib/types/skillfs.d.ts
CHANGED
|
@@ -65,6 +65,10 @@ export declare function parseFrontmatter(text: string): {
|
|
|
65
65
|
} | {
|
|
66
66
|
error: string;
|
|
67
67
|
};
|
|
68
|
+
/** Try to repair a SKILL.md's frontmatter in place (unquoted colon etc.). Returns the new file text or null when not fixable. */
|
|
69
|
+
export declare function repairFrontmatterFileText(text: string): string | null;
|
|
70
|
+
/** Repair one file on disk when its frontmatter is auto-fixable. Returns the new text. */
|
|
71
|
+
export declare function fixDiagnosticFile(path: string, home?: string): Promise<string>;
|
|
68
72
|
/** One discoverable skill file in a scanned root. */
|
|
69
73
|
export interface SkillEntry {
|
|
70
74
|
/** Absolute path of the discovery file (SKILL.md or the flat .md). */
|
|
@@ -81,6 +85,15 @@ export interface SkillEntry {
|
|
|
81
85
|
export declare function scanRoot(base: string): Promise<SkillEntry[]>;
|
|
82
86
|
/** Scan one writable root. */
|
|
83
87
|
export declare function listSkillEntries(root: WritableRoot, home?: string): Promise<SkillEntry[]>;
|
|
88
|
+
/** Read UI metadata from `agents/openai.yaml` beside a directory skill (mirrors codex SkillInterface). */
|
|
89
|
+
export declare function readSkillInterface(directory: string): Promise<{
|
|
90
|
+
displayName?: string;
|
|
91
|
+
shortDescription?: string;
|
|
92
|
+
brandColor?: string;
|
|
93
|
+
iconSmall?: string;
|
|
94
|
+
iconLarge?: string;
|
|
95
|
+
defaultPrompt?: string;
|
|
96
|
+
} | undefined>;
|
|
84
97
|
/**
|
|
85
98
|
* Walk up from cwd (max 32 levels) for a project marker (.dsh or .git);
|
|
86
99
|
* falls back to cwd itself. The provider roots project skills here.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-skill-hub",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
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": {
|
|
@@ -65,7 +65,8 @@
|
|
|
65
65
|
"0.1.1-rc.2",
|
|
66
66
|
"0.1.2-alpha.2",
|
|
67
67
|
"0.1.2-alpha.3",
|
|
68
|
-
"0.1.2-alpha.4"
|
|
68
|
+
"0.1.2-alpha.4",
|
|
69
|
+
"0.1.2-alpha.5"
|
|
69
70
|
]
|
|
70
71
|
},
|
|
71
72
|
"capability": {
|
|
@@ -87,19 +88,19 @@
|
|
|
87
88
|
},
|
|
88
89
|
"peerDependencies": {
|
|
89
90
|
"@deepseek-ai/cordis": "^4.0.1 || ^4.0.2",
|
|
90
|
-
"@deepseek-ai/dsh-client-connection": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
91
|
-
"@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
92
|
-
"@deepseek-ai/dsh-client-runtime": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
93
|
-
"@deepseek-ai/dsh-client-store": ">=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
94
|
-
"@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 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
95
|
-
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
96
|
-
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
97
|
-
"@deepseek-ai/dsh-host-webserver": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
98
|
-
"@deepseek-ai/dsh-session": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
99
|
-
"@deepseek-ai/dsh-session-query": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
100
|
-
"@deepseek-ai/dsh-settings": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
101
|
-
"@deepseek-ai/dsh-skill": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
102
|
-
"@deepseek-ai/dsh-system-prompt": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0",
|
|
91
|
+
"@deepseek-ai/dsh-client-connection": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
92
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
93
|
+
"@deepseek-ai/dsh-client-runtime": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
94
|
+
"@deepseek-ai/dsh-client-store": ">=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
95
|
+
"@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 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
96
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
97
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
98
|
+
"@deepseek-ai/dsh-host-webserver": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
99
|
+
"@deepseek-ai/dsh-session": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
100
|
+
"@deepseek-ai/dsh-session-query": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
101
|
+
"@deepseek-ai/dsh-settings": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
102
|
+
"@deepseek-ai/dsh-skill": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
103
|
+
"@deepseek-ai/dsh-system-prompt": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.2 <0.2.0-0 || >=0.1.2-alpha.2 <0.2.0-0 || >=0.1.2-alpha.3 <0.2.0-0 || >=0.1.2-alpha.4 <0.2.0-0 || >=0.1.2-alpha.5 <0.2.0-0",
|
|
103
104
|
"react": "^18.2.0",
|
|
104
105
|
"react-dom": "^18.2.0"
|
|
105
106
|
},
|
|
@@ -113,19 +114,19 @@
|
|
|
113
114
|
},
|
|
114
115
|
"devDependencies": {
|
|
115
116
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
116
|
-
"@deepseek-ai/dsh-client-connection": "^0.1.2-alpha.
|
|
117
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.2-alpha.
|
|
118
|
-
"@deepseek-ai/dsh-client-store": "^0.1.2-alpha.
|
|
119
|
-
"@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.2-alpha.
|
|
120
|
-
"@deepseek-ai/dsh-client-ui-settings": "^0.1.2-alpha.
|
|
121
|
-
"@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.2-alpha.
|
|
122
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.2-alpha.
|
|
123
|
-
"@deepseek-ai/dsh-host-webserver": "^0.1.2-alpha.
|
|
124
|
-
"@deepseek-ai/dsh-session": "^0.1.2-alpha.
|
|
125
|
-
"@deepseek-ai/dsh-session-query": "^0.1.2-alpha.
|
|
126
|
-
"@deepseek-ai/dsh-settings": "^0.1.2-alpha.
|
|
127
|
-
"@deepseek-ai/dsh-skill": "^0.1.2-alpha.
|
|
128
|
-
"@deepseek-ai/dsh-system-prompt": "^0.1.2-alpha.
|
|
117
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.2-alpha.5",
|
|
118
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.2-alpha.5",
|
|
119
|
+
"@deepseek-ai/dsh-client-store": "^0.1.2-alpha.5",
|
|
120
|
+
"@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.2-alpha.5",
|
|
121
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.2-alpha.5",
|
|
122
|
+
"@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.2-alpha.5",
|
|
123
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.2-alpha.5",
|
|
124
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.2-alpha.5",
|
|
125
|
+
"@deepseek-ai/dsh-session": "^0.1.2-alpha.5",
|
|
126
|
+
"@deepseek-ai/dsh-session-query": "^0.1.2-alpha.5",
|
|
127
|
+
"@deepseek-ai/dsh-settings": "^0.1.2-alpha.5",
|
|
128
|
+
"@deepseek-ai/dsh-skill": "^0.1.2-alpha.5",
|
|
129
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.2-alpha.5",
|
|
129
130
|
"@types/js-yaml": "^4.0.9",
|
|
130
131
|
"@types/node": "^22.20.0",
|
|
131
132
|
"@types/react": "~18.3.1",
|
|
@@ -14,8 +14,6 @@ import { ColorField, NumberField, PluginSettingsCard, SwitchField } from './sett
|
|
|
14
14
|
import { booleanField, CardForm, colorField, numberField, type CardShell, type FieldState, type FormScope } from './settings-form.ts'
|
|
15
15
|
// Single source for the TS-side dot defaults (the panel CSS mirrors these).
|
|
16
16
|
import { DEFAULT_DOT_MODEL_COLOR, DEFAULT_DOT_USER_COLOR } from './panel/format.ts'
|
|
17
|
-
// Re-export for any consumer that imported them from the card before the move.
|
|
18
|
-
export { DEFAULT_DOT_MODEL_COLOR, DEFAULT_DOT_USER_COLOR }
|
|
19
17
|
|
|
20
18
|
/** The card's projected state. */
|
|
21
19
|
export interface SkillHubSettingsState extends CardShell {
|
package/src/client/api.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
type MarketSourceRequest,
|
|
20
20
|
type MarketSourceResponse,
|
|
21
21
|
type MarketSourcesResponse,
|
|
22
|
+
type MarketSourceVersionsResponse,
|
|
22
23
|
type MarketSyncResponse,
|
|
23
24
|
type RepoDiscoverResponse,
|
|
24
25
|
type RepoImportCancelResponse,
|
|
@@ -193,6 +194,13 @@ export class SkillHubApi {
|
|
|
193
194
|
return readJson<MarketSyncResponse>(response)
|
|
194
195
|
}
|
|
195
196
|
|
|
197
|
+
/** Releases + branches of a market source for the version picker. */
|
|
198
|
+
async marketSourceVersions(repo: string): Promise<MarketSourceVersionsResponse> {
|
|
199
|
+
const url = SKILL_HUB_API.marketSourceVersions + '?repo=' + encodeURIComponent(repo)
|
|
200
|
+
const response = await fetchWithTimeout(url)
|
|
201
|
+
return readJson<MarketSourceVersionsResponse>(response)
|
|
202
|
+
}
|
|
203
|
+
|
|
196
204
|
/** Pin a market source to an explicit ref (branch picker). */
|
|
197
205
|
async setMarketSourceRef(repo: string, ref: string): Promise<MarketSourcesResponse> {
|
|
198
206
|
const response = await fetchWithTimeout(SKILL_HUB_API.marketSourceRef, {
|
|
@@ -387,4 +395,14 @@ export class SkillHubApi {
|
|
|
387
395
|
const response = await fetchWithTimeout(SKILL_HUB_API.sourceTrashClear, { method: 'POST' })
|
|
388
396
|
return readJson<SourceTrashClearResponse>(response)
|
|
389
397
|
}
|
|
398
|
+
|
|
399
|
+
/** Auto-fix a fixable diagnostic (e.g. unquoted colon). */
|
|
400
|
+
async fixDiagnostic(path: string): Promise<import('../protocol.ts').DiagnosticFixResponse> {
|
|
401
|
+
const response = await fetchWithTimeout(SKILL_HUB_API.diagnosticFix, {
|
|
402
|
+
method: 'POST',
|
|
403
|
+
headers: { 'content-type': 'application/json' },
|
|
404
|
+
body: JSON.stringify({ path } satisfies import('../protocol.ts').DiagnosticFixRequest),
|
|
405
|
+
})
|
|
406
|
+
return readJson<import('../protocol.ts').DiagnosticFixResponse>(response)
|
|
407
|
+
}
|
|
390
408
|
}
|
package/src/client/helpers.ts
CHANGED
|
@@ -21,3 +21,43 @@ export function errorMessage(error: unknown): string {
|
|
|
21
21
|
return String(error)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Whether a displayName is worth showing beside the kebab-case name.
|
|
26
|
+
* Pure case/punctuation variants (e.g. "Code Review" vs "code-review") are redundant.
|
|
27
|
+
*/
|
|
28
|
+
export function isDisplayNameDistinct(name: string, displayName: string | undefined): displayName is string {
|
|
29
|
+
if (displayName === undefined) return false
|
|
30
|
+
const normalize = (s: string): string => s.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff]+/g, '')
|
|
31
|
+
return normalize(displayName) !== normalize(name)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Copy text to the clipboard. Uses the async API with a positioned-textarea
|
|
36
|
+
* fallback for insecure contexts. Resolves true only when the copy succeeded.
|
|
37
|
+
*/
|
|
38
|
+
export async function copyTextToClipboard(text: string): Promise<boolean> {
|
|
39
|
+
if (navigator.clipboard?.writeText !== undefined) {
|
|
40
|
+
try {
|
|
41
|
+
await navigator.clipboard.writeText(text)
|
|
42
|
+
return true
|
|
43
|
+
} catch {
|
|
44
|
+
// Fall through to the legacy path below.
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const ta = document.createElement('textarea')
|
|
49
|
+
ta.value = text
|
|
50
|
+
ta.setAttribute('readonly', '')
|
|
51
|
+
ta.style.position = 'fixed'
|
|
52
|
+
ta.style.top = '0'
|
|
53
|
+
ta.style.opacity = '0'
|
|
54
|
+
document.body.appendChild(ta)
|
|
55
|
+
ta.select()
|
|
56
|
+
const ok = document.execCommand('copy')
|
|
57
|
+
ta.remove()
|
|
58
|
+
return ok
|
|
59
|
+
} catch {
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|