dsh-skill-hub 0.0.1 → 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.
- package/CONTRIBUTING.md +56 -0
- package/README.md +355 -20
- package/cordis.patch.yml +12 -0
- package/lib/client.js +4514 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +3119 -0
- package/lib/invariant.js +6 -0
- package/lib/types/client/SkillHubSettingsCard.d.ts +53 -0
- package/lib/types/client/api-config-scope.d.ts +48 -0
- package/lib/types/client/api.d.ts +64 -0
- package/lib/types/client/grouping.d.ts +64 -0
- package/lib/types/client/helpers.d.ts +11 -0
- package/lib/types/client/index.d.ts +42 -0
- package/lib/types/client/locales.d.ts +216 -0
- package/lib/types/client/market-catalog.d.ts +14 -0
- package/lib/types/client/panel/DisabledRow.d.ts +12 -0
- package/lib/types/client/panel/GroupSummary.d.ts +10 -0
- package/lib/types/client/panel/MarketView.d.ts +11 -0
- package/lib/types/client/panel/ScenesView.d.ts +11 -0
- package/lib/types/client/panel/SkillDetailView.d.ts +31 -0
- package/lib/types/client/panel/SkillHubPanel.d.ts +18 -0
- package/lib/types/client/panel/SkillRow.d.ts +11 -0
- package/lib/types/client/panel/SourceStatusBadge.d.ts +18 -0
- package/lib/types/client/panel/SourcesView.d.ts +10 -0
- package/lib/types/client/panel/TagEditorView.d.ts +29 -0
- package/lib/types/client/panel/dialogs.d.ts +73 -0
- package/lib/types/client/panel/format.d.ts +14 -0
- package/lib/types/client/panel/useSkillHub.d.ts +183 -0
- package/lib/types/client/settings-card.d.ts +81 -0
- package/lib/types/client/settings-form.d.ts +95 -0
- package/lib/types/client/settings-nav-icon.d.ts +8 -0
- package/lib/types/index.d.ts +36 -0
- package/lib/types/invariant.d.ts +3 -0
- package/lib/types/protocol.d.ts +571 -0
- package/lib/types/provider.d.ts +47 -0
- package/lib/types/repo.d.ts +133 -0
- package/lib/types/routes.d.ts +51 -0
- package/lib/types/skillfs.d.ts +95 -0
- package/lib/types/stats.d.ts +49 -0
- package/lib/types/store.d.ts +142 -0
- package/lib/types/update.d.ts +20 -0
- package/package.json +115 -11
- package/src/client/SkillHubSettingsCard.tsx +161 -0
- package/src/client/api-config-scope.test.ts +79 -0
- package/src/client/api-config-scope.ts +119 -0
- package/src/client/api.ts +327 -0
- package/src/client/css-modules.d.ts +5 -0
- package/src/client/grouping.test.ts +109 -0
- package/src/client/grouping.ts +120 -0
- package/src/client/helpers.ts +23 -0
- package/src/client/index.tsx +104 -0
- package/src/client/locales.ts +432 -0
- package/src/client/market-catalog.ts +22 -0
- package/src/client/panel/DisabledRow.tsx +32 -0
- package/src/client/panel/GroupSummary.tsx +27 -0
- package/src/client/panel/MarketView.tsx +173 -0
- package/src/client/panel/ScenesView.tsx +75 -0
- package/src/client/panel/SkillDetailView.tsx +95 -0
- package/src/client/panel/SkillHubPanel.tsx +347 -0
- package/src/client/panel/SkillRow.tsx +54 -0
- package/src/client/panel/SourceStatusBadge.tsx +61 -0
- package/src/client/panel/SourcesView.tsx +104 -0
- package/src/client/panel/TagEditorView.tsx +89 -0
- package/src/client/panel/dialogs.tsx +185 -0
- package/src/client/panel/format.ts +31 -0
- package/src/client/panel/panel.module.css +219 -0
- package/src/client/panel/useSkillHub.ts +797 -0
- package/src/client/settings-card.module.css +52 -0
- package/src/client/settings-card.tsx +237 -0
- package/src/client/settings-form.ts +227 -0
- package/src/client/settings-nav-icon.ts +42 -0
- package/src/index.ts +181 -0
- package/src/invariant.ts +4 -0
- package/src/protocol.ts +622 -0
- package/src/provider.test.ts +112 -0
- package/src/provider.ts +168 -0
- package/src/repo.test.ts +212 -0
- package/src/repo.ts +528 -0
- package/src/routes.test.ts +786 -0
- package/src/routes.ts +1252 -0
- package/src/skillfs.test.ts +290 -0
- package/src/skillfs.ts +306 -0
- package/src/stats.test.ts +168 -0
- package/src/stats.ts +124 -0
- package/src/store.test.ts +253 -0
- package/src/store.ts +628 -0
- package/src/update.test.ts +73 -0
- package/src/update.ts +136 -0
|
@@ -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;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared dialog family for the panel: one overlay shell plus the specific
|
|
3
|
+
* dialogs (group-close conflict, sync/delete confirm, branch picker, and
|
|
4
|
+
* market sync selection). Every dialog closes on outside click and keeps
|
|
5
|
+
* the same role/aria shell; the panel owns all dialog state.
|
|
6
|
+
*/
|
|
7
|
+
import { type JSX } from 'react';
|
|
8
|
+
import type { CollectionGroup, SkillTag } from '../../protocol.ts';
|
|
9
|
+
/** A group-close conflict waiting for the user's decision. */
|
|
10
|
+
export interface ConflictDialogState {
|
|
11
|
+
/** Group key: 'tag:<id>' or 'col:<name>'. */
|
|
12
|
+
key: string;
|
|
13
|
+
name: string;
|
|
14
|
+
/** Conflicting skill names (enabled here and in other groups). */
|
|
15
|
+
conflicts: string[];
|
|
16
|
+
}
|
|
17
|
+
/** A destructive/sync confirmation waiting for the user's decision. */
|
|
18
|
+
export interface ConfirmDialogState {
|
|
19
|
+
kind: 'sync' | 'delete';
|
|
20
|
+
repo: string;
|
|
21
|
+
/** Skills the action applies to. */
|
|
22
|
+
skills: string[];
|
|
23
|
+
}
|
|
24
|
+
/** Branch picker shown when a repo has no release and no pinned ref. */
|
|
25
|
+
export interface BranchChoiceState {
|
|
26
|
+
repo: string;
|
|
27
|
+
branches: string[];
|
|
28
|
+
selected: string;
|
|
29
|
+
}
|
|
30
|
+
/** Post-sync skill update dialog: which tracked skills to refresh. */
|
|
31
|
+
export interface MarketSyncDialogState {
|
|
32
|
+
repo: string;
|
|
33
|
+
ref: string;
|
|
34
|
+
skills: string[];
|
|
35
|
+
selected: ReadonlySet<string>;
|
|
36
|
+
}
|
|
37
|
+
/** Simple confirm dialog: title + text + optional skill list + cancel/confirm. */
|
|
38
|
+
export declare function ConfirmDialog(props: {
|
|
39
|
+
title: string;
|
|
40
|
+
text: string;
|
|
41
|
+
/** Optional skill names listed between the text and the buttons. */
|
|
42
|
+
items?: readonly string[];
|
|
43
|
+
confirmLabel: string;
|
|
44
|
+
/** Danger-styled confirm button (destructive actions). */
|
|
45
|
+
danger?: boolean;
|
|
46
|
+
onCancel: () => void;
|
|
47
|
+
onConfirm: () => void;
|
|
48
|
+
}): JSX.Element;
|
|
49
|
+
/** Group-close conflict: which skills stay on, and which other groups also enable them. */
|
|
50
|
+
export declare function ConflictDialog(props: {
|
|
51
|
+
dialog: ConflictDialogState;
|
|
52
|
+
tags: readonly SkillTag[];
|
|
53
|
+
collections: readonly CollectionGroup[];
|
|
54
|
+
onClose: () => void;
|
|
55
|
+
onKeepOn: () => void;
|
|
56
|
+
onCloseAll: () => void;
|
|
57
|
+
}): JSX.Element;
|
|
58
|
+
/** Branch picker for a repo without releases (pins the ref, then rescans). */
|
|
59
|
+
export declare function BranchChoiceDialog(props: {
|
|
60
|
+
choice: BranchChoiceState;
|
|
61
|
+
busy: boolean;
|
|
62
|
+
onSelect: (branch: string) => void;
|
|
63
|
+
onCancel: () => void;
|
|
64
|
+
onConfirm: () => void;
|
|
65
|
+
}): JSX.Element;
|
|
66
|
+
/** Post-sync selection: which tracked skills to batch-update to the new version. */
|
|
67
|
+
export declare function MarketSyncDialog(props: {
|
|
68
|
+
dialog: MarketSyncDialogState;
|
|
69
|
+
busy: boolean;
|
|
70
|
+
onToggle: (name: string, checked: boolean) => void;
|
|
71
|
+
onCancel: () => void;
|
|
72
|
+
onConfirm: () => void;
|
|
73
|
+
}): JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared display helpers for the panel views (skill rows, detail view, and
|
|
3
|
+
* dialogs): dot color styling, relative/absolute time text, and commit-SHA
|
|
4
|
+
* shortening. Kept in one place so the views render identically.
|
|
5
|
+
*/
|
|
6
|
+
import type { CSSProperties } from 'react';
|
|
7
|
+
/** Dot inline style from the user-chosen color (undefined keeps the CSS default). */
|
|
8
|
+
export declare function dotStyle(color: string | undefined): CSSProperties | undefined;
|
|
9
|
+
/** Localized relative-time text for a Unix-ms timestamp. */
|
|
10
|
+
export declare function relativeTimeText(ms: number): string;
|
|
11
|
+
/** Localized absolute time for the detail meta (e.g. "2026/8/16 11:00:00"). */
|
|
12
|
+
export declare function formatDateTime(ms: number): string;
|
|
13
|
+
/** Short form of a commit SHA for display. */
|
|
14
|
+
export declare function shortSha(sha: string): string;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useSkillHub — the panel's state owner. Everything the skill hub panel
|
|
3
|
+
* knows (catalog, groups, sources, market, dialogs, drafts) plus every
|
|
4
|
+
* async flow lives here; the panel itself only renders. All hooks run
|
|
5
|
+
* unconditionally at the top, so the panel may early-return for the detail
|
|
6
|
+
* and tag-editor views without violating the rules of hooks.
|
|
7
|
+
*/
|
|
8
|
+
import { type FormEvent } from 'react';
|
|
9
|
+
import type { CatalogResponse, CatalogSkill, DisabledSkill, GroupsResponse, HubConfig, MarketSourceRecord, RepoDiscoverResponse, RepoImportResponse, SkillDetail, SkillTag, SourceCheckResult, SourcesResponse, UpdateCheckResponse, WritableRoot } from '../../protocol.ts';
|
|
10
|
+
import type { SkillHubApi } from '../api.ts';
|
|
11
|
+
import { type SortKey, type GroupSwitchState } from '../grouping.ts';
|
|
12
|
+
import type { BranchChoiceState, ConfirmDialogState, ConflictDialogState, MarketSyncDialogState } from './dialogs.tsx';
|
|
13
|
+
/** One-shot self-update check state. */
|
|
14
|
+
type UpdateState = {
|
|
15
|
+
status: 'idle';
|
|
16
|
+
} | {
|
|
17
|
+
status: 'checking';
|
|
18
|
+
} | {
|
|
19
|
+
status: 'ready';
|
|
20
|
+
data: UpdateCheckResponse;
|
|
21
|
+
} | {
|
|
22
|
+
status: 'error';
|
|
23
|
+
message: string;
|
|
24
|
+
};
|
|
25
|
+
/** Repo scanner/import state (drives the market source preview). */
|
|
26
|
+
type RepoDiscoverState = {
|
|
27
|
+
status: 'idle';
|
|
28
|
+
} | {
|
|
29
|
+
status: 'scanning';
|
|
30
|
+
} | {
|
|
31
|
+
status: 'ready';
|
|
32
|
+
data: RepoDiscoverResponse;
|
|
33
|
+
} | {
|
|
34
|
+
status: 'error';
|
|
35
|
+
message: string;
|
|
36
|
+
};
|
|
37
|
+
/** Market sources list state. */
|
|
38
|
+
type MarketState = {
|
|
39
|
+
status: 'loading' | 'ready' | 'error';
|
|
40
|
+
repos: MarketSourceRecord[];
|
|
41
|
+
};
|
|
42
|
+
/** The hook's result: the panel's complete state + action surface. */
|
|
43
|
+
export type SkillHubState = ReturnType<typeof useSkillHub>;
|
|
44
|
+
export declare function useSkillHub(api: SkillHubApi): {
|
|
45
|
+
catalog: CatalogResponse | null;
|
|
46
|
+
loading: boolean;
|
|
47
|
+
loadError: string | null;
|
|
48
|
+
successBanner: string | null;
|
|
49
|
+
updateState: UpdateState;
|
|
50
|
+
repoDiscoverState: RepoDiscoverState;
|
|
51
|
+
scanningRepo: string | null;
|
|
52
|
+
repoSelected: ReadonlySet<string>;
|
|
53
|
+
repoImporting: boolean;
|
|
54
|
+
repoResult: RepoImportResponse | null;
|
|
55
|
+
search: string;
|
|
56
|
+
detail: SkillDetail | null;
|
|
57
|
+
detailLoading: boolean;
|
|
58
|
+
busyNames: ReadonlySet<string>;
|
|
59
|
+
batchBusy: boolean;
|
|
60
|
+
showForm: boolean;
|
|
61
|
+
formName: string;
|
|
62
|
+
formDesc: string;
|
|
63
|
+
formRoot: WritableRoot;
|
|
64
|
+
formBusy: boolean;
|
|
65
|
+
formMessage: {
|
|
66
|
+
kind: "error" | "success";
|
|
67
|
+
text: string;
|
|
68
|
+
} | null;
|
|
69
|
+
uses: ReadonlyMap<string, {
|
|
70
|
+
count: number;
|
|
71
|
+
lastUsed?: number;
|
|
72
|
+
}>;
|
|
73
|
+
hubConfig: HubConfig | null;
|
|
74
|
+
tab: "sources" | "scenes" | "market";
|
|
75
|
+
skillView: "flat" | "groups";
|
|
76
|
+
sourceFilter: string;
|
|
77
|
+
sortKey: SortKey;
|
|
78
|
+
marketState: MarketState;
|
|
79
|
+
marketCheck: Readonly<Record<string, {
|
|
80
|
+
repo: string;
|
|
81
|
+
ref?: string;
|
|
82
|
+
latestTag?: string;
|
|
83
|
+
updateAvailable: boolean;
|
|
84
|
+
commitSha: string;
|
|
85
|
+
throttled?: boolean;
|
|
86
|
+
error?: string;
|
|
87
|
+
}>>;
|
|
88
|
+
branchChoice: BranchChoiceState | null;
|
|
89
|
+
branchBusy: boolean;
|
|
90
|
+
marketSyncDialog: MarketSyncDialogState | null;
|
|
91
|
+
syncingMarket: string | null;
|
|
92
|
+
syncBusy: boolean;
|
|
93
|
+
newSourceName: string;
|
|
94
|
+
groupsState: GroupsResponse | null;
|
|
95
|
+
sourcesState: SourcesResponse | null;
|
|
96
|
+
sourceCheck: Readonly<Record<string, SourceCheckResult>>;
|
|
97
|
+
checkingSource: string | null;
|
|
98
|
+
syncingSource: string | null;
|
|
99
|
+
conflictDialog: ConflictDialogState | null;
|
|
100
|
+
confirmDialog: ConfirmDialogState | null;
|
|
101
|
+
deleteSkillDialog: string | null;
|
|
102
|
+
confirmClearTrash: boolean;
|
|
103
|
+
updateAllDialog: boolean;
|
|
104
|
+
editingTag: SkillTag | null;
|
|
105
|
+
editName: string;
|
|
106
|
+
membersDraft: ReadonlySet<string>;
|
|
107
|
+
newTagName: string;
|
|
108
|
+
tagBusy: boolean;
|
|
109
|
+
editSearch: string;
|
|
110
|
+
collapsedGroups: ReadonlySet<string>;
|
|
111
|
+
showLegend: boolean;
|
|
112
|
+
actionNames: Set<string>;
|
|
113
|
+
viewNames: Set<string>;
|
|
114
|
+
normalized: string;
|
|
115
|
+
origins: Record<string, string>;
|
|
116
|
+
sourceOptions: string[];
|
|
117
|
+
filtered: CatalogSkill[];
|
|
118
|
+
sorted: CatalogSkill[];
|
|
119
|
+
setLoadError: import("react").Dispatch<import("react").SetStateAction<string | null>>;
|
|
120
|
+
setSuccessBanner: import("react").Dispatch<import("react").SetStateAction<string | null>>;
|
|
121
|
+
setSearch: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
122
|
+
setDetail: import("react").Dispatch<import("react").SetStateAction<SkillDetail | null>>;
|
|
123
|
+
setShowForm: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
124
|
+
setFormName: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
125
|
+
setFormDesc: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
126
|
+
setFormRoot: import("react").Dispatch<import("react").SetStateAction<WritableRoot>>;
|
|
127
|
+
setFormMessage: import("react").Dispatch<import("react").SetStateAction<{
|
|
128
|
+
kind: "error" | "success";
|
|
129
|
+
text: string;
|
|
130
|
+
} | null>>;
|
|
131
|
+
setRepoSelected: import("react").Dispatch<import("react").SetStateAction<ReadonlySet<string>>>;
|
|
132
|
+
setTab: import("react").Dispatch<import("react").SetStateAction<"sources" | "scenes" | "market">>;
|
|
133
|
+
setSkillView: import("react").Dispatch<import("react").SetStateAction<"flat" | "groups">>;
|
|
134
|
+
setSourceFilter: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
135
|
+
setSortKey: import("react").Dispatch<import("react").SetStateAction<SortKey>>;
|
|
136
|
+
setBranchChoice: import("react").Dispatch<import("react").SetStateAction<BranchChoiceState | null>>;
|
|
137
|
+
setMarketSyncDialog: import("react").Dispatch<import("react").SetStateAction<MarketSyncDialogState | null>>;
|
|
138
|
+
setNewSourceName: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
139
|
+
setConflictDialog: import("react").Dispatch<import("react").SetStateAction<ConflictDialogState | null>>;
|
|
140
|
+
setConfirmDialog: import("react").Dispatch<import("react").SetStateAction<ConfirmDialogState | null>>;
|
|
141
|
+
setDeleteSkillDialog: import("react").Dispatch<import("react").SetStateAction<string | null>>;
|
|
142
|
+
setConfirmClearTrash: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
143
|
+
setUpdateAllDialog: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
144
|
+
setEditingTag: import("react").Dispatch<import("react").SetStateAction<SkillTag | null>>;
|
|
145
|
+
setEditName: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
146
|
+
setMembersDraft: import("react").Dispatch<import("react").SetStateAction<ReadonlySet<string>>>;
|
|
147
|
+
setNewTagName: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
148
|
+
setEditSearch: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
149
|
+
setShowLegend: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
150
|
+
toggleGroupCollapse: (key: string) => void;
|
|
151
|
+
checkUpdate: () => Promise<void>;
|
|
152
|
+
loadMarket: () => Promise<void>;
|
|
153
|
+
openDetail: (name: string) => Promise<void>;
|
|
154
|
+
toggle: (skill: CatalogSkill, enabled: boolean) => Promise<void>;
|
|
155
|
+
enableDisabled: (record: DisabledSkill) => Promise<void>;
|
|
156
|
+
batchToggleNames: (names: string[], enabled: boolean) => Promise<void>;
|
|
157
|
+
toggleGroup: (key: string, name: string, view: GroupSwitchState) => void;
|
|
158
|
+
resolveConflict: (closeAll: boolean) => Promise<void>;
|
|
159
|
+
runConfirmed: () => Promise<void>;
|
|
160
|
+
checkSources: (repo?: string) => Promise<void>;
|
|
161
|
+
requestSync: (repo: string, skills: string[]) => void;
|
|
162
|
+
requestDelete: (repo: string, skills: string[]) => void;
|
|
163
|
+
restoreTrash: (name: string) => Promise<void>;
|
|
164
|
+
clearTrash: () => Promise<void>;
|
|
165
|
+
requestDeleteSkill: (name: string) => void;
|
|
166
|
+
runDeleteSkill: () => Promise<void>;
|
|
167
|
+
createTag: (event: FormEvent) => Promise<void>;
|
|
168
|
+
deleteTag: (id: string) => Promise<void>;
|
|
169
|
+
saveTag: (id: string, name: string, memberNames: string[] | null) => Promise<void>;
|
|
170
|
+
addSource: (input: string) => Promise<void>;
|
|
171
|
+
addMarketSource: () => Promise<void>;
|
|
172
|
+
removeMarketSource: (repo: string) => Promise<void>;
|
|
173
|
+
scanRepo: (input: string) => Promise<void>;
|
|
174
|
+
confirmBranchChoice: () => Promise<void>;
|
|
175
|
+
toggleRepoSelected: (path: string, checked: boolean) => void;
|
|
176
|
+
importRepo: () => Promise<void>;
|
|
177
|
+
checkMarket: () => Promise<void>;
|
|
178
|
+
syncMarketSource: (repo: string) => Promise<void>;
|
|
179
|
+
confirmMarketSync: () => Promise<void>;
|
|
180
|
+
updateAll: () => Promise<void>;
|
|
181
|
+
create: (event: FormEvent) => Promise<void>;
|
|
182
|
+
};
|
|
183
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared chrome for the plugin settings card, aligned with the official
|
|
3
|
+
* dsh-client-ui-settings-plugins PluginCard design language: the same tokens,
|
|
4
|
+
* disclosure header, field rhythm, and copy. Renders nothing while the
|
|
5
|
+
* namespace is unavailable — a deployment that does not compose the owning
|
|
6
|
+
* plugin should show no trace of it.
|
|
7
|
+
*/
|
|
8
|
+
import { type ReactElement } from 'react';
|
|
9
|
+
import type { CardShell } from './settings-form.ts';
|
|
10
|
+
/** Card-level chrome props. */
|
|
11
|
+
export interface PluginSettingsCardProps {
|
|
12
|
+
/** Locale translator for the owning plugin's namespace. */
|
|
13
|
+
t: (key: string) => string;
|
|
14
|
+
/** Locale key of the card title. */
|
|
15
|
+
titleKey: string;
|
|
16
|
+
/** Locale key of the card description. */
|
|
17
|
+
descriptionKey: string;
|
|
18
|
+
/** The form shell state. */
|
|
19
|
+
state: CardShell;
|
|
20
|
+
onSave: () => void;
|
|
21
|
+
onDiscard: () => void;
|
|
22
|
+
children?: ReactElement | ReactElement[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Render one plugin settings card.
|
|
26
|
+
* @param props - the plugin's copy keys, its form state, and its controls.
|
|
27
|
+
* @returns the card, or nothing while the namespace is still loading.
|
|
28
|
+
*/
|
|
29
|
+
export declare function PluginSettingsCard(props: PluginSettingsCardProps): ReactElement | null;
|
|
30
|
+
/** One staged boolean field: 继承 / 开 / 关. */
|
|
31
|
+
export interface BooleanFieldProps {
|
|
32
|
+
id: string;
|
|
33
|
+
label: string;
|
|
34
|
+
hint: string;
|
|
35
|
+
inheritLabel: string;
|
|
36
|
+
onLabel: string;
|
|
37
|
+
offLabel: string;
|
|
38
|
+
overriddenLabel: string;
|
|
39
|
+
resetLabel: string;
|
|
40
|
+
disabled: boolean;
|
|
41
|
+
text: string;
|
|
42
|
+
overridden: boolean;
|
|
43
|
+
onEdit: (text: string) => void;
|
|
44
|
+
onReset: () => void;
|
|
45
|
+
}
|
|
46
|
+
export declare function BooleanField(props: BooleanFieldProps): ReactElement;
|
|
47
|
+
/**
|
|
48
|
+
* A compact sliding switch for the card's master enable/disable control.
|
|
49
|
+
* An empty text value means the field inherits its default; the switch still
|
|
50
|
+
* reflects the effective default and becomes an explicit override on click.
|
|
51
|
+
*/
|
|
52
|
+
export interface SwitchFieldProps {
|
|
53
|
+
label: string;
|
|
54
|
+
hint: string;
|
|
55
|
+
disabled: boolean;
|
|
56
|
+
text: string;
|
|
57
|
+
overridden: boolean;
|
|
58
|
+
overriddenLabel: string;
|
|
59
|
+
resetLabel: string;
|
|
60
|
+
onEdit: (text: string) => void;
|
|
61
|
+
onReset: () => void;
|
|
62
|
+
}
|
|
63
|
+
export declare function SwitchField(props: SwitchFieldProps): ReactElement;
|
|
64
|
+
/** One staged color field: a native color picker plus the hex draft text. */
|
|
65
|
+
export interface ColorFieldProps {
|
|
66
|
+
id: string;
|
|
67
|
+
label: string;
|
|
68
|
+
hint: string;
|
|
69
|
+
inheritLabel: string;
|
|
70
|
+
overriddenLabel: string;
|
|
71
|
+
resetLabel: string;
|
|
72
|
+
disabled: boolean;
|
|
73
|
+
/** Effective hex (#rrggbb) when overridden; empty string means inherit. */
|
|
74
|
+
text: string;
|
|
75
|
+
/** The default color the picker shows while inheriting (per-field). */
|
|
76
|
+
defaultColor: string;
|
|
77
|
+
overridden: boolean;
|
|
78
|
+
onEdit: (text: string) => void;
|
|
79
|
+
onReset: () => void;
|
|
80
|
+
}
|
|
81
|
+
export declare function ColorField(props: ColorFieldProps): ReactElement;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings-card form machinery, vendored from the dsh-web-ui family bucket
|
|
3
|
+
* (packages/dsh-task-board/src/client/settings-form.ts) and re-typed. Stages
|
|
4
|
+
* one card's edits over one settings namespace and writes them on save.
|
|
5
|
+
*
|
|
6
|
+
* The Host is the only authority on whether a value was accepted — its
|
|
7
|
+
* validators own the constraints no schema can express — so the outcome is
|
|
8
|
+
* read back from the section rather than predicted here. A save that did not
|
|
9
|
+
* land keeps its drafts, so the user can correct them instead of retyping.
|
|
10
|
+
*/
|
|
11
|
+
/** One editable field spec: formatting plus text parsing. */
|
|
12
|
+
export interface FieldSpec {
|
|
13
|
+
field: string;
|
|
14
|
+
format: (value: unknown) => string;
|
|
15
|
+
parse: (text: string) => {
|
|
16
|
+
kind: 'set';
|
|
17
|
+
value: unknown;
|
|
18
|
+
} | {
|
|
19
|
+
kind: 'clear';
|
|
20
|
+
} | undefined;
|
|
21
|
+
}
|
|
22
|
+
/** A boolean field, edited through true/false draft text. */
|
|
23
|
+
export declare function booleanField(field: string): FieldSpec;
|
|
24
|
+
/** A #rrggbb color field, edited through hex draft text. */
|
|
25
|
+
export declare function colorField(field: string): FieldSpec;
|
|
26
|
+
/** Card-level state the chrome renders. */
|
|
27
|
+
export interface CardShell {
|
|
28
|
+
available: boolean;
|
|
29
|
+
exposed: boolean;
|
|
30
|
+
writable: boolean;
|
|
31
|
+
dirty: boolean;
|
|
32
|
+
invalid: boolean;
|
|
33
|
+
saving: boolean;
|
|
34
|
+
failed: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** One field's state from the effective section and its staged draft. */
|
|
37
|
+
export interface FieldState {
|
|
38
|
+
text: string;
|
|
39
|
+
overridden: boolean;
|
|
40
|
+
invalid: boolean;
|
|
41
|
+
}
|
|
42
|
+
/** The settings scope face the form consumes (subset of SettingsScope<T>). */
|
|
43
|
+
export interface FormScope {
|
|
44
|
+
subscribe(listener: () => void): () => void;
|
|
45
|
+
getSnapshot(): {
|
|
46
|
+
status: string;
|
|
47
|
+
writable: boolean;
|
|
48
|
+
value?: Record<string, unknown>;
|
|
49
|
+
base?: unknown;
|
|
50
|
+
user?: unknown;
|
|
51
|
+
};
|
|
52
|
+
set(field: string, value: unknown): Promise<void>;
|
|
53
|
+
unset(field: string): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
/** Stages one card's edits and writes them through the settings transport. */
|
|
56
|
+
export declare class CardForm {
|
|
57
|
+
private readonly scope;
|
|
58
|
+
private readonly specs;
|
|
59
|
+
private readonly staged;
|
|
60
|
+
private readonly listeners;
|
|
61
|
+
private saving;
|
|
62
|
+
private failed;
|
|
63
|
+
/** @param scope - the bound settings scope for this card's namespace. */
|
|
64
|
+
constructor(scope: FormScope, specs: FieldSpec[]);
|
|
65
|
+
/** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */
|
|
66
|
+
bind<T>(project: () => T): import("@deepseek-ai/dsh-client-runtime/client").SnapshotStore<T>;
|
|
67
|
+
/** Read the card-level state: what the Host serves, and what a save would do. */
|
|
68
|
+
shell(): CardShell;
|
|
69
|
+
/** Read one field's state from the effective section and its staged draft. */
|
|
70
|
+
field(field: string): FieldState;
|
|
71
|
+
/** The actions the card's slot registration injects. */
|
|
72
|
+
actions(): {
|
|
73
|
+
edit: (field: string, text: string) => void;
|
|
74
|
+
resetField: (field: string) => void;
|
|
75
|
+
save: () => void;
|
|
76
|
+
discard: () => void;
|
|
77
|
+
};
|
|
78
|
+
/** Write every staged edit, then re-seed from what the Host accepted. */
|
|
79
|
+
save(): Promise<void>;
|
|
80
|
+
/** Every staged edit a save would write, in staging order. */
|
|
81
|
+
plan(): Array<{
|
|
82
|
+
field: string;
|
|
83
|
+
run: (() => Promise<boolean>) | undefined;
|
|
84
|
+
}>;
|
|
85
|
+
private clear;
|
|
86
|
+
private store;
|
|
87
|
+
private userRecord;
|
|
88
|
+
private stage;
|
|
89
|
+
private specOf;
|
|
90
|
+
private sectionValue;
|
|
91
|
+
private baseValue;
|
|
92
|
+
private userLayer;
|
|
93
|
+
private stored;
|
|
94
|
+
private publish;
|
|
95
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The settings shell renders section nav icons from a hard-coded id map and
|
|
3
|
+
* exposes no registrant icon option, so the skill-hub section falls back to
|
|
4
|
+
* the generic gear. This scoped DOM patch swaps in the official skill icon
|
|
5
|
+
* whenever the settings dialog re-renders.
|
|
6
|
+
*/
|
|
7
|
+
/** Swap the settings nav gear for the skill icon and keep it in sync. */
|
|
8
|
+
export declare function applySettingsNavIcon(): () => void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-skill-hub — host half. Mounts the /api/skill-hub route family (full
|
|
3
|
+
* skill catalog from the official ctx.skills registry, skill detail,
|
|
4
|
+
* enable/disable toggle, new-skill scaffold) plus a system-prompt
|
|
5
|
+
* announcement. The browser half (./client) renders the sidebar entry and
|
|
6
|
+
* the skill hub panel. Everything rides official NPM SDK packages — no dsh
|
|
7
|
+
* source changes.
|
|
8
|
+
*/
|
|
9
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
10
|
+
import z from 'schemastery';
|
|
11
|
+
/** Stable cordis plugin name (matches cordis.patch.yml insert id). */
|
|
12
|
+
export declare const name = "skill-hub";
|
|
13
|
+
/** Services required before the skill-hub surfaces can mount. */
|
|
14
|
+
export declare const inject: string[];
|
|
15
|
+
/** Plugin config, validated by the same-named schemastery schema. */
|
|
16
|
+
export interface Config {
|
|
17
|
+
/** When true (default), a system-prompt section announces the hub to every agent. */
|
|
18
|
+
announceToAgent?: boolean;
|
|
19
|
+
/** Master switch for the plugin (routes, prompt section). */
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
/** Show per-skill invocation count chip. Default true. */
|
|
22
|
+
showUseCount?: boolean;
|
|
23
|
+
/** Show per-skill last-used relative time. Default true. */
|
|
24
|
+
showUseTime?: boolean;
|
|
25
|
+
/** Show group-header usage summaries (count + last used). Default true. */
|
|
26
|
+
showGroupSummary?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare const Config: z<Config>;
|
|
29
|
+
/** Model-facing announcement: plugin presence, capabilities, and limits. */
|
|
30
|
+
export declare const SKILL_HUB_GUIDANCE: string;
|
|
31
|
+
/**
|
|
32
|
+
* Mount the skill hub routes and announcement.
|
|
33
|
+
* @param ctx - host plugin context carrying webServer/skills/systemPrompt.
|
|
34
|
+
* @param config - resolved plugin config (schema defaults applied by the loader).
|
|
35
|
+
*/
|
|
36
|
+
export declare function apply(ctx: Context, config?: Config): void;
|