@lijian-ui/dsh-skill-manage 0.1.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/lib/client.js ADDED
@@ -0,0 +1,1494 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@lijian-ui/dsh-skill-manage",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react = require("react");
8
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
+ let react_jsx_runtime = require("react/jsx-runtime");
10
+ //#region src/client/SkillManageSection.tsx
11
+ const CSS_TEXT = `
12
+ .SKM_section{width:100%;max-width:760px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:14px;display:flex}
13
+ .SKM_status{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px;margin:0}
14
+ .SKM_failure{color:var(--dsw-alias-state-error-primary);align-items:center;gap:10px;display:flex}
15
+ .SKM_failure p{margin:0}
16
+ .SKM_failure button{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:4px 10px}
17
+ .SKM_catalog{flex-direction:column;gap:12px;display:flex}
18
+ .SKM_search{width:100%;color:var(--dsw-alias-label-tertiary);align-items:center;display:flex;position:relative}
19
+ .SKM_search>svg{pointer-events:none;position:absolute;left:12px}
20
+ .SKM_search input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;height:36px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:8px;outline:none;padding:0 34px 0 36px;font-size:13px}
21
+ .SKM_search input::placeholder{color:var(--dsw-alias-label-tertiary)}
22
+ .SKM_search input:focus-visible{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-business-primary) 18%, transparent)}
23
+ .SKM_catalogHeading{align-items:baseline;gap:7px;padding:0 2px;display:flex}
24
+ .SKM_catalogHeading h3{font-size:13px;font-weight:600;line-height:20px;margin:0}
25
+ .SKM_catalogHeading span{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:18px}
26
+ .SKM_cards{flex-direction:column;gap:8px;margin:0;padding:0;list-style:none;display:flex}
27
+ .SKM_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;min-width:0;overflow:hidden;transition:border-color .15s ease}
28
+ .SKM_card:hover{border-color:var(--dsw-alias-border-l1)}
29
+ .SKM_cardRow{box-sizing:border-box;width:100%;align-items:center;gap:10px;font:inherit;color:var(--dsw-alias-label-primary);background:0 0;border:none;padding:10px 12px;display:flex;text-align:left}
30
+ .SKM_cardInfo{min-width:0;flex:1;cursor:pointer;display:flex;align-items:center;gap:8px}
31
+ .SKM_cardLeading{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}
32
+ .SKM_cardText{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px}
33
+ .SKM_cardTitle{text-overflow:ellipsis;white-space:nowrap;overflow:hidden;font-size:13px;font-weight:500;line-height:20px;transition:color .2s ease;margin:0}
34
+ .SKM_cardTitle[data-disabled=true]{color:var(--dsw-alias-label-tertiary)}
35
+ .SKM_cardDesc{text-overflow:ellipsis;white-space:nowrap;overflow:hidden;font-size:12px;line-height:16px;color:var(--dsw-alias-label-tertiary);margin:0}
36
+ .SKM_cardActions{align-items:center;gap:8px;display:inline-flex;flex:none}
37
+ .SKM_switch{width:36px;height:21px;border-radius:999px;border:none;background:var(--dsw-alias-border-l2,#ccc);position:relative;cursor:pointer;flex:none;padding:0;transition:background-color .15s ease}
38
+ .SKM_switch[data-on=true]{background:var(--dsw-alias-state-business-primary,#185FA5)}
39
+ .SKM_switch:disabled{cursor:default;opacity:.6}
40
+ .SKM_switchThumb{position:absolute;left:2px;top:2px;width:17px;height:17px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:left .15s ease}
41
+ .SKM_switch[data-on=true] .SKM_switchThumb{left:17px}
42
+ .SKM_deleteBtn{font:inherit;color:var(--dsw-alias-state-error-primary);cursor:pointer;background:0 0;border:1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);border-radius:6px;padding:3px 8px;font-size:11px;line-height:16px}
43
+ .SKM_deleteBtn:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent)}
44
+ .SKM_deleteBtn:disabled{cursor:default;opacity:.6}
45
+ .SKM_opError{color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px}
46
+ .SKM_addActions{margin-left:auto;align-items:center;gap:6px;display:inline-flex;position:relative}
47
+ .SKM_addButton{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:14px;padding:0;display:inline-flex;align-items:center;justify-content:center}
48
+ .SKM_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}
49
+ .SKM_addButton:disabled{cursor:default;opacity:.6}
50
+ .SKM_addMenu{position:absolute;top:calc(100% + 4px);right:0;background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;box-shadow:var(--dsw-shadow-lv1);flex-direction:column;padding:4px;display:flex;z-index:10}
51
+ .SKM_addMenuItem{font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:6px 12px;font-size:13px;line-height:20px;text-align:left;white-space:nowrap}
52
+ .SKM_addMenuItem:hover{background:var(--dsw-alias-interactive-bg-hover)}
53
+ .SKM_addStatus{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0}
54
+ .SKM_addErrorBanner{border:1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);border-radius:8px;align-items:center;gap:10px;padding:8px 12px;display:flex}
55
+ .SKM_addErrorText{color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px;flex:1;min-width:0}
56
+ .SKM_addDismiss{font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:2px 10px;font-size:12px;line-height:18px;flex:none}
57
+ .SKM_addDismiss:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}
58
+ .SKM_fileInput{display:none}
59
+ .SKM_scopeBar{gap:6px;padding:2px;max-width:100%;overflow-x:auto;scrollbar-width:thin;display:flex;align-items:center}
60
+ .SKM_scopeChip{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:3px 12px;font-size:12px;line-height:18px;white-space:nowrap;flex:none;display:inline-flex;align-items:center;gap:6px}
61
+ .SKM_scopeChip:hover{background:var(--dsw-alias-interactive-bg-hover)}
62
+ .SKM_scopeChip[data-active=true]{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 12%, transparent);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}
63
+ .SKM_scopeChipCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px;line-height:16px}
64
+ .SKM_scopeChip[data-active=true] .SKM_scopeChipCount{color:var(--dsw-alias-state-business-primary)}
65
+ .SKM_migrateButton{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:14px;padding:0;display:inline-flex;align-items:center;justify-content:center}
66
+ .SKM_migrateButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}
67
+ .SKM_migrateButton:disabled{cursor:default;opacity:.6}
68
+ .SKM_visuallyHidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;clip:rect(0 0 0 0);overflow:hidden;white-space:nowrap}
69
+ .SKM_detailOverlay{position:fixed;inset:0;background:color-mix(in srgb, rgba(0,0,0,.5) 60%, transparent);align-items:center;justify-content:center;display:flex;z-index:1000}
70
+ .SKM_detailBox{background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;box-shadow:var(--dsw-shadow-lv2);width:640px;max-width:calc(100vw - 48px);max-height:85vh;flex-direction:column;display:flex}
71
+ .SKM_detailHeader{align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--dsw-alias-border-l3);display:flex}
72
+ .SKM_detailTitle{font-size:15px;font-weight:600;line-height:22px;margin:0;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
73
+ .SKM_detailClose{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:4px 12px;font-size:13px;line-height:20px;flex:none}
74
+ .SKM_detailClose:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}
75
+ .SKM_confirmBox{background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;box-shadow:var(--dsw-shadow-lv2);width:400px;max-width:calc(100vw - 48px);flex-direction:column;gap:16px;padding:20px;display:flex}
76
+ .SKM_confirmText{font-size:14px;line-height:22px;color:var(--dsw-alias-label-primary);margin:0}
77
+ .SKM_confirmActions{align-items:center;justify-content:flex-end;gap:8px;display:flex}
78
+ .SKM_confirmCancel{font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:6px 16px;font-size:13px;line-height:20px}
79
+ .SKM_confirmCancel:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}
80
+ .SKM_confirmDelete{font:inherit;color:var(--dsw-alias-state-error-primary);cursor:pointer;background:0 0;border:1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);border-radius:8px;padding:6px 16px;font-size:13px;line-height:20px}
81
+ .SKM_confirmDelete:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent)}
82
+ .SKM_confirmDelete:disabled{cursor:default;opacity:.6}
83
+ .SKM_detailBody{flex:1;overflow-y:auto;padding:16px;flex-direction:column;gap:16px;display:flex}
84
+ .SKM_detailMeta{border:1px solid var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:12px;flex-direction:column;gap:6px;display:flex}
85
+ .SKM_detailMetaTitle{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary);margin:0;text-transform:uppercase;letter-spacing:.5px}
86
+ .SKM_detailMetaRow{align-items:baseline;gap:8px;display:flex;font-size:13px;line-height:20px}
87
+ .SKM_detailMetaKey{color:var(--dsw-alias-label-tertiary);flex:none;font-weight:500;min-width:80px}
88
+ .SKM_detailMetaVal{color:var(--dsw-alias-label-primary);flex:1;min-width:0;word-break:break-word}
89
+ .SKM_detailMetaVal code{font-family:var(--dsw-alias-font-family-mono,ui-monospace,monospace);font-size:12px;background:var(--dsw-alias-bg-layer-2);border-radius:4px;padding:1px 4px}
90
+ .SKM_detailContent{flex:1;min-height:0;flex-direction:column;display:flex}
91
+ .SKM_detailMd{flex:1;min-height:0;overflow-y:auto}
92
+ .SKM_detailMd>div{font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary)}
93
+ .SKM_detailMd>div h1{font-size:18px;font-weight:600;margin:12px 0 8px}
94
+ .SKM_detailMd>div h2{font-size:16px;font-weight:600;margin:10px 0 6px}
95
+ .SKM_detailMd>div h3{font-size:14px;font-weight:600;margin:8px 0 4px}
96
+ .SKM_detailMd>div p{margin:0 0 8px}
97
+ .SKM_detailMd>div ul,.SKM_detailMd>div ol{margin:0 0 8px;padding-left:20px}
98
+ .SKM_detailMd>div li{margin:2px 0}
99
+ .SKM_detailMd>div pre{background:var(--dsw-alias-bg-layer-1);border-radius:6px;padding:8px 12px;overflow-x:auto;font-size:12px;line-height:18px;margin:0 0 8px}
100
+ .SKM_detailMd>div code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
101
+ .SKM_detailMd>div blockquote{border-left:3px solid var(--dsw-alias-border-l2);padding-left:12px;color:var(--dsw-alias-label-secondary);margin:0 0 8px}
102
+ .SKM_detailMd>div table{border-collapse:collapse;margin:0 0 8px}
103
+ .SKM_detailMd>div th,.SKM_detailMd>div td{border:1px solid var(--dsw-alias-border-l2);padding:4px 8px;font-size:12px}
104
+ .SKM_detailMd>div hr{border:none;border-top:1px solid var(--dsw-alias-border-l2);margin:8px 0}
105
+ .SKM_detailContentTitle{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary);margin:0;text-transform:uppercase;letter-spacing:.5px}
106
+ .SKM_md{font-size:13px;line-height:22px;color:var(--dsw-alias-label-primary)}
107
+ .SKM_md h1{font-size:18px;font-weight:600;line-height:26px;margin:8px 0 4px}
108
+ .SKM_md h2{font-size:16px;font-weight:600;line-height:24px;margin:8px 0 4px}
109
+ .SKM_md h3{font-size:14px;font-weight:600;line-height:22px;margin:6px 0 2px}
110
+ .SKM_md p{margin:0 0 8px}
111
+ .SKM_md ul,.SKM_md ol{margin:0 0 8px;padding-left:20px}
112
+ .SKM_md li{margin:2px 0}
113
+ .SKM_md code{font-family:var(--dsw-alias-font-family-mono,ui-monospace,monospace);font-size:12px;background:var(--dsw-alias-bg-layer-2);border-radius:4px;padding:1px 5px}
114
+ .SKM_md pre{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l3);border-radius:8px;padding:10px 12px;overflow-x:auto;margin:0 0 8px}
115
+ .SKM_md pre code{background:0 0;border:none;padding:0;font-size:12px;line-height:18px}
116
+ .SKM_md strong{font-weight:600}
117
+ .SKM_md em{font-style:italic}
118
+ .SKM_md blockquote{border-left:3px solid var(--dsw-alias-border-l2);margin:0 0 8px;padding:4px 12px;color:var(--dsw-alias-label-secondary)}
119
+ .SKM_md hr{border:none;border-top:1px solid var(--dsw-alias-border-l3);margin:8px 0}
120
+ .SKM_detailLoading{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px;margin:0;text-align:center;padding:20px}
121
+ .SKM_detailError{color:var(--dsw-alias-state-error-primary);font-size:13px;line-height:20px;margin:0;text-align:center;padding:20px}
122
+ .SKM_scopeOverlay{position:fixed;inset:0;background:color-mix(in srgb, rgba(0,0,0,.45) 55%, transparent);align-items:center;justify-content:center;display:flex;z-index:1000}
123
+ .SKM_scopeBox{background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;box-shadow:var(--dsw-shadow-lv2);width:440px;max-width:calc(100vw - 48px);max-height:80vh;flex-direction:column;padding:16px;gap:12px;display:flex}
124
+ .SKM_scopeBox h4{font-size:14px;font-weight:600;line-height:20px;margin:0}
125
+ .SKM_scopeOptions{flex-direction:column;gap:8px;display:flex}
126
+ .SKM_scopeOption{font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:8px 12px;font-size:13px;line-height:20px;text-align:left;display:flex;align-items:center;gap:8px}
127
+ .SKM_scopeOption[data-active=true]{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 1px color-mix(in srgb, var(--dsw-alias-state-business-primary) 30%, transparent)}
128
+ .SKM_scopeOption input{margin:0;accent-color:var(--dsw-alias-state-business-primary)}
129
+ .SKM_wsPath{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
130
+ .SKM_scopeHint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0}
131
+ .SKM_scopeActions{margin-top:auto;justify-content:flex-end;gap:8px;display:flex}
132
+ .SKM_scopeAction{font:inherit;cursor:pointer;border-radius:8px;padding:6px 14px;font-size:13px;line-height:20px}
133
+ .SKM_scopeCancel{color:var(--dsw-alias-label-primary);background:0 0;border:1px solid var(--dsw-alias-border-l2)}
134
+ .SKM_scopeCancel:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}
135
+ .SKM_scopeConfirm{color:#fff;background:var(--dsw-alias-state-business-primary);border:none}
136
+ .SKM_scopeConfirm:disabled{cursor:default;opacity:.6}
137
+ .SKM_migrateSection{flex-direction:column;gap:6px;display:flex}
138
+ .SKM_migrateLabel{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;margin:0}
139
+ .SKM_migrateList{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;max-height:220px;overflow-y:auto;margin:0;padding:4px;list-style:none;display:flex;flex-direction:column;gap:2px}
140
+ .SKM_migrateItem{font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:6px 10px;font-size:13px;line-height:20px;text-align:left;display:flex;align-items:center;gap:8px;width:100%}
141
+ .SKM_migrateItem:hover{background:var(--dsw-alias-interactive-bg-hover)}
142
+ .SKM_migrateItem input{margin:0;accent-color:var(--dsw-alias-state-business-primary)}
143
+ .SKM_migrateItemName{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
144
+ .SKM_migrateItemState{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;flex:none}
145
+ .SKM_migrateSelectAll{font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:2px 10px;font-size:12px;line-height:18px}
146
+ .SKM_migrateSelectAll:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}
147
+ .SKM_migrateResult{color:var(--dsw-alias-state-success-primary);font-size:13px;line-height:20px;margin:0}
148
+ .SKM_migrateResult[data-ok=false]{color:var(--dsw-alias-state-error-primary)}
149
+ .SKM_migrateResultList{border:1px solid var(--dsw-alias-border-l3);border-radius:8px;margin:6px 0 0;padding:4px 8px;list-style:none;display:flex;flex-direction:column;gap:2px;max-height:120px;overflow-y:auto}
150
+ .SKM_migrateResultList li{color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}
151
+ `;
152
+ const TAG_ID = "@lijian-ui/dsh-skill-manage/SkillManageSection.module.css";
153
+ function injectCss() {
154
+ if (typeof document !== "undefined" && document.querySelector(`style[data-plugin-css="${TAG_ID}"]`) === null) {
155
+ const tag = document.createElement("style");
156
+ tag.dataset.plugin = "@lijian-ui/dsh-skill-manage";
157
+ tag.dataset.pluginCss = TAG_ID;
158
+ tag.textContent = CSS_TEXT;
159
+ document.head.appendChild(tag);
160
+ }
161
+ }
162
+ function parseFrontmatter(raw) {
163
+ const trimmed = raw.trimStart();
164
+ if (!trimmed.startsWith("---")) return {
165
+ frontmatter: null,
166
+ body: raw
167
+ };
168
+ const end = trimmed.indexOf("\n---", 3);
169
+ if (end === -1) return {
170
+ frontmatter: null,
171
+ body: raw
172
+ };
173
+ const yamlText = trimmed.slice(3, end).trim();
174
+ const body = trimmed.slice(end + 4).replace(/^\s*\n/, "");
175
+ const frontmatter = {};
176
+ for (const line of yamlText.split("\n")) {
177
+ const m = line.match(/^(\w[\w-]*)\s*:\s*(.*)$/);
178
+ if (!m) continue;
179
+ const [, key, val] = m;
180
+ if (val === "true") frontmatter[key] = true;
181
+ else if (val === "false") frontmatter[key] = false;
182
+ else if (val === "") frontmatter[key] = "";
183
+ else if (/^-?\d+$/.test(val)) frontmatter[key] = parseInt(val, 10);
184
+ else frontmatter[key] = val.replace(/^["']|["']$/g, "");
185
+ }
186
+ return {
187
+ frontmatter,
188
+ body
189
+ };
190
+ }
191
+ function DetailContent({ raw }) {
192
+ const { frontmatter, body } = (0, react.useMemo)(() => parseFrontmatter(raw), [raw]);
193
+ const metaKeys = frontmatter !== null ? Object.keys(frontmatter) : [];
194
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [metaKeys.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
195
+ className: "SKM_detailMeta",
196
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
197
+ className: "SKM_detailMetaTitle",
198
+ children: "Frontmatter"
199
+ }), metaKeys.map((k) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
200
+ className: "SKM_detailMetaRow",
201
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
202
+ className: "SKM_detailMetaKey",
203
+ children: k
204
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
205
+ className: "SKM_detailMetaVal",
206
+ children: String(frontmatter[k])
207
+ })]
208
+ }, k))]
209
+ }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
210
+ className: "SKM_detailMd",
211
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, { text: body })
212
+ })] });
213
+ }
214
+ function MigrateDialog(props) {
215
+ const { t, options, from, setFrom, targets, toggleTarget, mode, setMode, skills, selected, toggle, selectAll, busy, result, error, onConfirm, onCancel, onClose } = props;
216
+ const known = Array.isArray(options) ? options : [];
217
+ const fromLabel = from === "" ? t("migratePickSource") : from === "global" ? t("scopeGlobal") : from;
218
+ const okCount = Array.isArray(result) ? result.filter((item) => item.ok === true).length : 0;
219
+ const failCount = Array.isArray(result) ? result.length - okCount : 0;
220
+ const targetLabelOf = (value) => value === null || value === void 0 ? t("scopeGlobal") : value === "global" ? t("scopeGlobal") : value;
221
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
222
+ className: "SKM_scopeOverlay",
223
+ role: "dialog",
224
+ "aria-modal": "true",
225
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
226
+ className: "SKM_scopeBox",
227
+ children: [
228
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: t("migrateTitle") }),
229
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
230
+ className: "SKM_migrateSection",
231
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
232
+ className: "SKM_migrateLabel",
233
+ children: t("migrateFrom")
234
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
235
+ className: "SKM_scopeOptions",
236
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
237
+ type: "button",
238
+ className: "SKM_scopeOption",
239
+ "data-active": from === "global" ? "true" : void 0,
240
+ onClick: () => setFrom("global"),
241
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
242
+ type: "radio",
243
+ name: "migrate-from",
244
+ checked: from === "global",
245
+ readOnly: true
246
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("scopeGlobal") })]
247
+ }), known.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
248
+ type: "button",
249
+ className: "SKM_scopeOption",
250
+ "data-active": from === option.path ? "true" : void 0,
251
+ onClick: () => setFrom(option.path),
252
+ children: [
253
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
254
+ type: "radio",
255
+ name: "migrate-from",
256
+ checked: from === option.path,
257
+ readOnly: true
258
+ }),
259
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: option.label }),
260
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
261
+ className: "SKM_wsPath",
262
+ title: option.path,
263
+ children: option.path
264
+ })
265
+ ]
266
+ }, option.path))]
267
+ })]
268
+ }),
269
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
270
+ className: "SKM_migrateSection",
271
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
272
+ className: "SKM_migrateLabel",
273
+ children: t("migrateTo")
274
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
275
+ className: "SKM_scopeOptions",
276
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
277
+ type: "button",
278
+ className: "SKM_scopeOption",
279
+ "data-active": targets.has("global") ? "true" : void 0,
280
+ onClick: () => toggleTarget("global"),
281
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
282
+ type: "checkbox",
283
+ checked: targets.has("global"),
284
+ readOnly: true
285
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("scopeGlobal") })]
286
+ }), known.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
287
+ type: "button",
288
+ className: "SKM_scopeOption",
289
+ "data-active": targets.has(option.path) ? "true" : void 0,
290
+ onClick: () => toggleTarget(option.path),
291
+ children: [
292
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
293
+ type: "checkbox",
294
+ checked: targets.has(option.path),
295
+ readOnly: true
296
+ }),
297
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: option.label }),
298
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
299
+ className: "SKM_wsPath",
300
+ title: option.path,
301
+ children: option.path
302
+ })
303
+ ]
304
+ }, option.path))]
305
+ })]
306
+ }),
307
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
308
+ className: "SKM_migrateSection",
309
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
310
+ className: "SKM_migrateLabel",
311
+ children: t("migrateMode")
312
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
313
+ className: "SKM_scopeOptions",
314
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
315
+ type: "button",
316
+ className: "SKM_scopeOption",
317
+ "data-active": mode === "move" ? "true" : void 0,
318
+ onClick: () => setMode("move"),
319
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
320
+ type: "radio",
321
+ name: "migrate-mode",
322
+ checked: mode === "move",
323
+ readOnly: true
324
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("migrateModeMove") })]
325
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
326
+ type: "button",
327
+ className: "SKM_scopeOption",
328
+ "data-active": mode === "copy" ? "true" : void 0,
329
+ onClick: () => setMode("copy"),
330
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
331
+ type: "radio",
332
+ name: "migrate-mode",
333
+ checked: mode === "copy",
334
+ readOnly: true
335
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("migrateModeCopy") })]
336
+ })]
337
+ })]
338
+ }),
339
+ from === "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
340
+ className: "SKM_scopeHint",
341
+ children: t("migratePickSource")
342
+ }) : result === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
343
+ className: "SKM_migrateSection",
344
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
345
+ style: {
346
+ display: "flex",
347
+ alignItems: "center",
348
+ justifyContent: "space-between"
349
+ },
350
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
351
+ className: "SKM_migrateLabel",
352
+ children: fromLabel + " · " + skills.length
353
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
354
+ type: "button",
355
+ className: "SKM_migrateSelectAll",
356
+ onClick: selectAll,
357
+ children: t("migrateSelectAll")
358
+ })]
359
+ }), skills.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
360
+ className: "SKM_scopeHint",
361
+ children: t("migrateNoSkills")
362
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
363
+ className: "SKM_migrateList",
364
+ children: skills.map((skill) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
365
+ type: "button",
366
+ className: "SKM_migrateItem",
367
+ onClick: () => toggle(skill.name),
368
+ children: [
369
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
370
+ type: "checkbox",
371
+ checked: selected.has(skill.name),
372
+ readOnly: true
373
+ }),
374
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
375
+ className: "SKM_migrateItemName",
376
+ children: skill.name
377
+ }),
378
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
379
+ className: "SKM_migrateItemState",
380
+ children: skill.enabled !== false ? t("enabledTag") : t("disabledTag")
381
+ })
382
+ ]
383
+ }) }, skill.name))
384
+ })]
385
+ }) : null,
386
+ error !== null && error !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
387
+ className: "SKM_scopeHint",
388
+ role: "alert",
389
+ children: error
390
+ }) : null,
391
+ result !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
392
+ className: "SKM_migrateSection",
393
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
394
+ className: "SKM_migrateResult",
395
+ "data-ok": failCount === 0 ? "true" : "false",
396
+ children: t("migrateDoneOk") + okCount + t("migrateDoneFail") + failCount + t("migrateDoneSuffix")
397
+ }), failCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
398
+ className: "SKM_migrateLabel",
399
+ children: t("migrateErrors")
400
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
401
+ className: "SKM_migrateResultList",
402
+ children: result.filter((item) => item.ok !== true).map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: item.name + (item.target === null || item.target === void 0 ? "" : " → " + targetLabelOf(item.target)) + ":" + (item.error ?? "") }, item.name + "-" + (item.target ?? "")))
403
+ })] }) : null]
404
+ }) : null,
405
+ mode === "move" && targets.size > 1 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
406
+ className: "SKM_scopeHint",
407
+ children: t("migrateMoveSingle")
408
+ }) : null,
409
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
410
+ className: "SKM_scopeActions",
411
+ children: result === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
412
+ type: "button",
413
+ className: "SKM_scopeAction SKM_scopeCancel",
414
+ disabled: busy,
415
+ onClick: onCancel,
416
+ children: t("migrateCancel")
417
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
418
+ type: "button",
419
+ className: "SKM_scopeAction SKM_scopeConfirm",
420
+ disabled: busy || from === "" || targets.size === 0 || selected.size === 0 || targets.has(from) || mode === "move" && targets.size > 1,
421
+ onClick: onConfirm,
422
+ children: busy ? t("migrateBusy") : t("migrateConfirm")
423
+ })] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
424
+ type: "button",
425
+ className: "SKM_scopeAction SKM_scopeConfirm",
426
+ onClick: onClose,
427
+ children: t("migrateClose")
428
+ })
429
+ })
430
+ ]
431
+ })
432
+ });
433
+ }
434
+ function SkillManageSection(props) {
435
+ const { t, currentSessionId, listSkills, loadContent, setSkillEnabled, removeSkill, addSkill, listWorkspaces, batchMigrateSkill, refreshSkillCache } = props;
436
+ const [query, setQuery] = (0, react.useState)("");
437
+ const [listState, setListState] = (0, react.useState)({ status: "loading" });
438
+ const [request, setRequest] = (0, react.useState)(0);
439
+ const [detail, setDetail] = (0, react.useState)(null);
440
+ const [ops, setOps] = (0, react.useState)({});
441
+ const [adding, setAdding] = (0, react.useState)({ status: "idle" });
442
+ const [addMenuOpen, setAddMenuOpen] = (0, react.useState)(false);
443
+ const [wsOptions, setWsOptions] = (0, react.useState)(null);
444
+ const [scopeFilter, setScopeFilter] = (0, react.useState)("global");
445
+ const [migrator, setMigrator] = (0, react.useState)(null);
446
+ const [deleteConfirm, setDeleteConfirm] = (0, react.useState)(null);
447
+ const inflight = (0, react.useRef)(/* @__PURE__ */ new Set());
448
+ const folderInput = (0, react.useRef)(null);
449
+ const fileInput = (0, react.useRef)(null);
450
+ (0, react.useEffect)(() => {
451
+ injectCss();
452
+ }, []);
453
+ (0, react.useEffect)(() => {
454
+ let current = true;
455
+ setListState((prev) => prev.status === "ready" ? prev : { status: "loading" });
456
+ Promise.resolve().then(() => listSkills()).then((snapshot) => {
457
+ if (!current) return;
458
+ const skills = snapshot !== null && typeof snapshot === "object" && Array.isArray(snapshot.skills) ? [...snapshot.skills].sort((a, b) => a.name.localeCompare(b.name)) : [];
459
+ setListState({
460
+ status: "ready",
461
+ skills
462
+ });
463
+ }, () => {
464
+ if (current) setListState({ status: "error" });
465
+ });
466
+ return () => {
467
+ current = false;
468
+ };
469
+ }, [listSkills, request]);
470
+ (0, react.useEffect)(() => {
471
+ let current = true;
472
+ Promise.resolve().then(() => listWorkspaces()).then((snapshot) => {
473
+ if (!current) return;
474
+ setWsOptions(snapshot !== null && typeof snapshot === "object" && Array.isArray(snapshot.workspaces) ? snapshot.workspaces : []);
475
+ }, () => {
476
+ if (current) setWsOptions([]);
477
+ });
478
+ return () => {
479
+ current = false;
480
+ };
481
+ }, [listWorkspaces]);
482
+ const refresh = () => {
483
+ setDetail(null);
484
+ setRequest((value) => value + 1);
485
+ };
486
+ const reloadAfterHot = () => {
487
+ setTimeout(() => {
488
+ refreshSkillCache();
489
+ setRequest((value) => value + 1);
490
+ }, 800);
491
+ };
492
+ const applySetEnabled = (skill) => {
493
+ const target = skill.enabled !== true;
494
+ setOps((prev) => ({
495
+ ...prev,
496
+ [skill.name]: { status: "busy" }
497
+ }));
498
+ Promise.resolve().then(() => setSkillEnabled(skill.name, target)).then(() => {
499
+ setListState((prev) => prev.status === "ready" ? {
500
+ status: "ready",
501
+ skills: prev.skills.map((s) => s.name === skill.name ? {
502
+ ...s,
503
+ enabled: target
504
+ } : s)
505
+ } : prev);
506
+ setOps((prev) => ({
507
+ ...prev,
508
+ [skill.name]: { status: "ok" }
509
+ }));
510
+ if (detail !== null && detail.skill.name === skill.name) setDetail((d) => d === null ? d : {
511
+ ...d,
512
+ skill: {
513
+ ...d.skill,
514
+ enabled: target
515
+ }
516
+ });
517
+ reloadAfterHot();
518
+ }, () => {
519
+ setOps((prev) => ({
520
+ ...prev,
521
+ [skill.name]: { status: "error" }
522
+ }));
523
+ });
524
+ };
525
+ const applyRemove = (skill) => {
526
+ setOps((prev) => ({
527
+ ...prev,
528
+ [skill.name]: { status: "busy" }
529
+ }));
530
+ Promise.resolve().then(() => removeSkill(skill.name)).then(() => {
531
+ setListState((prev) => prev.status === "ready" ? {
532
+ status: "ready",
533
+ skills: prev.skills.filter((s) => s.name !== skill.name)
534
+ } : prev);
535
+ setOps((prev) => ({
536
+ ...prev,
537
+ [skill.name]: { status: "ok" }
538
+ }));
539
+ if (detail !== null && detail.skill.name === skill.name) setDetail(null);
540
+ reloadAfterHot();
541
+ }, () => {
542
+ setOps((prev) => ({
543
+ ...prev,
544
+ [skill.name]: { status: "error" }
545
+ }));
546
+ });
547
+ };
548
+ const openDetail = (skill) => {
549
+ setDetail({
550
+ skill,
551
+ body: { status: "loading" }
552
+ });
553
+ if (inflight.current.has(skill.name)) return;
554
+ inflight.current.add(skill.name);
555
+ Promise.resolve().then(() => loadContent(skill.name)).then((content) => {
556
+ inflight.current.delete(skill.name);
557
+ setDetail((d) => d === null || d.skill.name !== skill.name ? d : {
558
+ ...d,
559
+ body: {
560
+ status: content === null ? "missing" : "ready",
561
+ content
562
+ }
563
+ });
564
+ }, () => {
565
+ inflight.current.delete(skill.name);
566
+ setDetail((d) => d === null || d.skill.name !== skill.name ? d : {
567
+ ...d,
568
+ body: { status: "error" }
569
+ });
570
+ });
571
+ };
572
+ const readFileAsBase64 = (file) => new Promise((resolve, reject) => {
573
+ const reader = new FileReader();
574
+ reader.onload = () => {
575
+ const bytes = new Uint8Array(reader.result);
576
+ let binary = "";
577
+ for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
578
+ resolve(btoa(binary));
579
+ };
580
+ reader.onerror = () => reject(/* @__PURE__ */ new Error("file read failed"));
581
+ reader.readAsArrayBuffer(file);
582
+ });
583
+ const cleanHostError = (error) => String(error?.message ?? error).replace(/^skillManage\.[a-zA-Z]+ failed: [a-z-]+: /, "");
584
+ const runAdd = (kind, files) => {
585
+ if (files.length === 0) return;
586
+ if (files.length > 200) {
587
+ setAdding({
588
+ status: "error",
589
+ message: t("addTooMany")
590
+ });
591
+ return;
592
+ }
593
+ if (kind === "bundle" && !files.some((file) => {
594
+ const parts = (file.webkitRelativePath ?? "").replaceAll("\\", "/").split("/");
595
+ return parts.length === 2 && parts[1] === "SKILL.md";
596
+ })) {
597
+ setAdding({
598
+ status: "error",
599
+ message: t("addNoSkillFile")
600
+ });
601
+ return;
602
+ }
603
+ setAdding({ status: "busy" });
604
+ const workspace = scopeFilter === "global" ? null : scopeFilter;
605
+ Promise.all(files.map(readFileAsBase64)).then((items) => {
606
+ const payloadFiles = items.map((base64, index) => ({
607
+ path: (files[index].webkitRelativePath || files[index].name).replaceAll("\\", "/"),
608
+ base64
609
+ }));
610
+ return addSkill({
611
+ kind,
612
+ files: payloadFiles,
613
+ workspace
614
+ });
615
+ }).then(() => {
616
+ setAdding({ status: "ok" });
617
+ setTimeout(() => setRequest((value) => value + 1), 700);
618
+ setTimeout(() => setAdding({ status: "idle" }), 2500);
619
+ }, (error) => {
620
+ setAdding({
621
+ status: "error",
622
+ message: cleanHostError(error)
623
+ });
624
+ });
625
+ };
626
+ const openMigrator = () => {
627
+ setMigrator({
628
+ from: "",
629
+ targets: /* @__PURE__ */ new Set(),
630
+ mode: "move",
631
+ selected: /* @__PURE__ */ new Set(),
632
+ busy: false,
633
+ result: null,
634
+ error: null
635
+ });
636
+ };
637
+ const applyBatchMigrate = () => {
638
+ const m = migrator;
639
+ if (m === null) return;
640
+ if (m.from === "") {
641
+ setMigrator({
642
+ ...m,
643
+ error: t("migratePickSource")
644
+ });
645
+ return;
646
+ }
647
+ if (m.targets.size === 0) {
648
+ setMigrator({
649
+ ...m,
650
+ error: t("migratePickTarget")
651
+ });
652
+ return;
653
+ }
654
+ if (m.targets.has(m.from)) {
655
+ setMigrator({
656
+ ...m,
657
+ error: t("migrateSameScope")
658
+ });
659
+ return;
660
+ }
661
+ if (m.mode === "move" && m.targets.size > 1) {
662
+ setMigrator({
663
+ ...m,
664
+ error: t("migrateMoveSingle")
665
+ });
666
+ return;
667
+ }
668
+ if (m.selected.size === 0) {
669
+ setMigrator({
670
+ ...m,
671
+ error: t("migratePickSkills")
672
+ });
673
+ return;
674
+ }
675
+ setMigrator({
676
+ ...m,
677
+ busy: true,
678
+ error: null
679
+ });
680
+ const payload = {
681
+ from: m.from === "global" ? null : m.from,
682
+ targets: [...m.targets].map((value) => value === "global" ? null : value),
683
+ mode: m.mode,
684
+ names: [...m.selected]
685
+ };
686
+ Promise.resolve().then(() => batchMigrateSkill(payload)).then((snapshot) => {
687
+ const results = snapshot !== null && typeof snapshot === "object" && Array.isArray(snapshot.results) ? snapshot.results : [];
688
+ setMigrator((prev) => prev === null ? prev : {
689
+ ...prev,
690
+ busy: false,
691
+ result: results
692
+ });
693
+ reloadAfterHot();
694
+ }, (error) => {
695
+ setMigrator((prev) => prev === null ? prev : {
696
+ ...prev,
697
+ busy: false,
698
+ error: cleanHostError(error)
699
+ });
700
+ });
701
+ };
702
+ const onPickFolder = (event) => {
703
+ const input = event.currentTarget;
704
+ const files = [...input.files];
705
+ input.value = "";
706
+ if (files.length === 0) return;
707
+ if (!files[0].webkitRelativePath) {
708
+ setAdding({
709
+ status: "error",
710
+ message: t("addFolderUnsupported")
711
+ });
712
+ return;
713
+ }
714
+ runAdd("bundle", files);
715
+ };
716
+ const onPickFile = (event) => {
717
+ const input = event.currentTarget;
718
+ const files = [...input.files];
719
+ input.value = "";
720
+ if (files.length !== 1) return;
721
+ runAdd("flat", files);
722
+ };
723
+ (0, react.useEffect)(() => {
724
+ if (!addMenuOpen || typeof document === "undefined") return;
725
+ const close = (event) => {
726
+ if (event.target instanceof Element && event.target.closest("[data-add-menu]")) return;
727
+ setAddMenuOpen(false);
728
+ };
729
+ document.addEventListener("click", close);
730
+ return () => document.removeEventListener("click", close);
731
+ }, [addMenuOpen]);
732
+ (0, react.useEffect)(() => {
733
+ if (detail === null || typeof document === "undefined") return;
734
+ const onKey = (e) => {
735
+ if (e.key === "Escape") setDetail(null);
736
+ };
737
+ document.addEventListener("keydown", onKey);
738
+ return () => document.removeEventListener("keydown", onKey);
739
+ }, [detail]);
740
+ const normalizedQuery = query.trim().toLocaleLowerCase();
741
+ const skills = listState.status === "ready" ? listState.skills : [];
742
+ const scopeOf = (skill) => skill.scope !== void 0 && skill.scope !== null && skill.scope.kind === "workspace" ? skill.scope.path ?? "global" : "global";
743
+ const labelOf = (path) => {
744
+ const parts = String(path).replaceAll("\\", "/").split("/").filter(Boolean);
745
+ return parts.length > 0 ? parts[parts.length - 1] : String(path);
746
+ };
747
+ const scopeKeys = ["global", ...(Array.isArray(wsOptions) ? wsOptions : []).map((workspace) => workspace.path).filter((path) => path !== "global")];
748
+ if (scopeFilter !== "global" && !scopeKeys.includes(scopeFilter)) scopeKeys.push(scopeFilter);
749
+ const scopeCount = (key) => skills.reduce((sum, skill) => sum + (scopeOf(skill) === key ? 1 : 0), 0);
750
+ const scoped = skills.filter((skill) => scopeOf(skill) === scopeFilter);
751
+ const filtered = scoped.filter((skill) => skill.name.toLocaleLowerCase().includes(normalizedQuery));
752
+ const migratorSkills = migrator !== null ? skills.filter((skill) => scopeOf(skill) === migrator.from) : [];
753
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
754
+ className: "SKM_section",
755
+ "aria-busy": listState.status === "loading",
756
+ children: listState.status === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
757
+ className: "SKM_status",
758
+ children: t("loading")
759
+ }) : listState.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
760
+ className: "SKM_failure",
761
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
762
+ role: "alert",
763
+ children: t("error")
764
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
765
+ type: "button",
766
+ onClick: refresh,
767
+ children: t("retry")
768
+ })]
769
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
770
+ className: "SKM_catalog",
771
+ children: [
772
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
773
+ className: "SKM_search",
774
+ children: [
775
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, { "aria-hidden": "true" }),
776
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
777
+ className: "SKM_visuallyHidden",
778
+ children: t("search")
779
+ }),
780
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
781
+ type: "search",
782
+ value: query,
783
+ placeholder: t("search"),
784
+ "aria-label": t("search"),
785
+ onChange: (event) => setQuery(event.currentTarget.value)
786
+ })
787
+ ]
788
+ }),
789
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
790
+ className: "SKM_catalogHeading",
791
+ children: [
792
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("catalog") }),
793
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
794
+ "data-skill-count": filtered.length,
795
+ children: filtered.length
796
+ }),
797
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
798
+ className: "SKM_addActions",
799
+ "data-add-menu": "1",
800
+ children: [
801
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
802
+ type: "button",
803
+ className: "SKM_migrateButton",
804
+ "aria-label": t("migrateButton"),
805
+ title: t("migrateButton"),
806
+ disabled: listState.status !== "ready" || skills.length === 0 || adding.status === "busy",
807
+ onClick: openMigrator,
808
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
809
+ width: "14",
810
+ height: "14",
811
+ viewBox: "0 0 16 16",
812
+ fill: "none",
813
+ "aria-hidden": "true",
814
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
815
+ d: "M2.5 5h11M11 2.5 13.5 5 11 7.5",
816
+ stroke: "currentColor",
817
+ strokeWidth: 1.6,
818
+ strokeLinecap: "round",
819
+ strokeLinejoin: "round"
820
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
821
+ d: "M13.5 11h-11M5 8.5 2.5 11 5 13.5",
822
+ stroke: "currentColor",
823
+ strokeWidth: 1.6,
824
+ strokeLinecap: "round",
825
+ strokeLinejoin: "round"
826
+ })]
827
+ })
828
+ }),
829
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
830
+ type: "button",
831
+ className: "SKM_addButton",
832
+ "aria-label": t("addButton"),
833
+ title: t("addButton"),
834
+ disabled: adding.status === "busy",
835
+ onClick: () => setAddMenuOpen((value) => !value),
836
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
837
+ width: "14",
838
+ height: "14",
839
+ viewBox: "0 0 16 16",
840
+ fill: "none",
841
+ "aria-hidden": "true",
842
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
843
+ d: "M8 3.5v9",
844
+ stroke: "currentColor",
845
+ strokeWidth: 1.6,
846
+ strokeLinecap: "round"
847
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
848
+ d: "M3.5 8h9",
849
+ stroke: "currentColor",
850
+ strokeWidth: 1.6,
851
+ strokeLinecap: "round"
852
+ })]
853
+ })
854
+ }),
855
+ addMenuOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
856
+ className: "SKM_addMenu",
857
+ role: "menu",
858
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
859
+ type: "button",
860
+ className: "SKM_addMenuItem",
861
+ role: "menuitem",
862
+ onClick: () => {
863
+ setAddMenuOpen(false);
864
+ folderInput.current?.click();
865
+ },
866
+ children: t("addMenuFolder")
867
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
868
+ type: "button",
869
+ className: "SKM_addMenuItem",
870
+ role: "menuitem",
871
+ onClick: () => {
872
+ setAddMenuOpen(false);
873
+ fileInput.current?.click();
874
+ },
875
+ children: t("addMenuFile")
876
+ })]
877
+ }) : null
878
+ ]
879
+ })
880
+ ]
881
+ }),
882
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
883
+ className: "SKM_scopeBar",
884
+ role: "tablist",
885
+ children: scopeKeys.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
886
+ type: "button",
887
+ role: "tab",
888
+ "aria-selected": scopeFilter === key,
889
+ className: "SKM_scopeChip",
890
+ "data-active": scopeFilter === key ? "true" : void 0,
891
+ onClick: () => setScopeFilter(key),
892
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
893
+ title: key === "global" ? t("scopeGlobal") : key,
894
+ children: key === "global" ? t("scopeGlobal") : labelOf(key)
895
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
896
+ className: "SKM_scopeChipCount",
897
+ children: scopeCount(key)
898
+ })]
899
+ }, key))
900
+ }),
901
+ adding.status === "busy" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
902
+ className: "SKM_addStatus",
903
+ children: t("addBusy")
904
+ }) : null,
905
+ adding.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
906
+ className: "SKM_addErrorBanner",
907
+ role: "alert",
908
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
909
+ className: "SKM_addErrorText",
910
+ children: adding.message
911
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
912
+ type: "button",
913
+ className: "SKM_addDismiss",
914
+ onClick: () => setAdding({ status: "idle" }),
915
+ children: t("addDismiss")
916
+ })]
917
+ }) : null,
918
+ currentSessionId() === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
919
+ className: "SKM_status",
920
+ children: t("noSession")
921
+ }) : null,
922
+ skills.length === 0 && currentSessionId() !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
923
+ className: "SKM_status",
924
+ children: t("empty")
925
+ }) : null,
926
+ skills.length > 0 && scoped.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
927
+ className: "SKM_status",
928
+ children: t("emptyScope")
929
+ }) : null,
930
+ scoped.length > 0 && filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
931
+ className: "SKM_status",
932
+ children: t("emptySearch")
933
+ }) : null,
934
+ filtered.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
935
+ className: "SKM_cards",
936
+ children: filtered.map((skill) => {
937
+ const enabled = skill.enabled !== false;
938
+ const editable = skill.source !== "bundled" && skill.source !== "runtime";
939
+ const op = ops[skill.name];
940
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
941
+ className: "SKM_card",
942
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
943
+ className: "SKM_cardRow",
944
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
945
+ className: "SKM_cardInfo",
946
+ onClick: () => openDetail(skill),
947
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
948
+ className: "SKM_cardLeading",
949
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSkillOutline16, { size: 14 })
950
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
951
+ className: "SKM_cardText",
952
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
953
+ className: "SKM_cardTitle",
954
+ "data-disabled": enabled ? void 0 : "true",
955
+ title: skill.name,
956
+ children: skill.name
957
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
958
+ className: "SKM_cardDesc",
959
+ children: skill.description
960
+ })]
961
+ })]
962
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
963
+ className: "SKM_cardActions",
964
+ children: [
965
+ editable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
966
+ type: "button",
967
+ role: "switch",
968
+ className: "SKM_switch",
969
+ "data-on": enabled ? "true" : void 0,
970
+ "aria-checked": enabled,
971
+ "aria-label": enabled ? t("switchDisable") : t("switchEnable"),
972
+ disabled: op?.status === "busy",
973
+ onClick: (e) => {
974
+ e.stopPropagation();
975
+ applySetEnabled(skill);
976
+ },
977
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "SKM_switchThumb" })
978
+ }) : null,
979
+ editable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
980
+ type: "button",
981
+ className: "SKM_deleteBtn",
982
+ disabled: op?.status === "busy",
983
+ onClick: (e) => {
984
+ e.stopPropagation();
985
+ setDeleteConfirm(skill);
986
+ },
987
+ children: t("deleteLabel")
988
+ }) : null,
989
+ op?.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
990
+ className: "SKM_opError",
991
+ children: "!"
992
+ }) : null
993
+ ]
994
+ })]
995
+ })
996
+ }, skill.name);
997
+ })
998
+ }) : null,
999
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1000
+ ref: folderInput,
1001
+ className: "SKM_fileInput",
1002
+ type: "file",
1003
+ webkitdirectory: "",
1004
+ onChange: onPickFolder
1005
+ }),
1006
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1007
+ ref: fileInput,
1008
+ className: "SKM_fileInput",
1009
+ type: "file",
1010
+ accept: ".md,text/markdown",
1011
+ onChange: onPickFile
1012
+ }),
1013
+ detail !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1014
+ className: "SKM_detailOverlay",
1015
+ role: "dialog",
1016
+ "aria-modal": "true",
1017
+ onClick: (e) => {
1018
+ if (e.target === e.currentTarget) setDetail(null);
1019
+ },
1020
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1021
+ className: "SKM_detailBox",
1022
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1023
+ className: "SKM_detailHeader",
1024
+ children: [
1025
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1026
+ className: "SKM_cardLeading",
1027
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSkillOutline16, { size: 16 })
1028
+ }),
1029
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
1030
+ className: "SKM_detailTitle",
1031
+ children: detail.skill.name
1032
+ }),
1033
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1034
+ type: "button",
1035
+ className: "SKM_detailClose",
1036
+ onClick: () => setDetail(null),
1037
+ children: t("retry") === "Retry" ? "Close" : "关闭"
1038
+ })
1039
+ ]
1040
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1041
+ className: "SKM_detailBody",
1042
+ children: [
1043
+ detail.body.status === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1044
+ className: "SKM_detailLoading",
1045
+ children: t("contentLoading")
1046
+ }) : null,
1047
+ detail.body.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1048
+ className: "SKM_detailError",
1049
+ children: t("contentError")
1050
+ }) : null,
1051
+ detail.body.status === "missing" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1052
+ className: "SKM_detailError",
1053
+ children: t("contentMissing")
1054
+ }) : null,
1055
+ detail.body.status === "ready" && detail.body.content ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailContent, { raw: detail.body.content.content }) : null
1056
+ ]
1057
+ })]
1058
+ })
1059
+ }) : null,
1060
+ deleteConfirm !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1061
+ className: "SKM_detailOverlay",
1062
+ role: "dialog",
1063
+ "aria-modal": "true",
1064
+ onClick: (e) => {
1065
+ if (e.target === e.currentTarget) setDeleteConfirm(null);
1066
+ },
1067
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1068
+ className: "SKM_confirmBox",
1069
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1070
+ className: "SKM_confirmText",
1071
+ children: t("deleteConfirm") + deleteConfirm.name + t("deleteConfirmSuffix")
1072
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1073
+ className: "SKM_confirmActions",
1074
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1075
+ type: "button",
1076
+ className: "SKM_confirmCancel",
1077
+ onClick: () => setDeleteConfirm(null),
1078
+ children: t("retry") === "Retry" ? "Cancel" : "取消"
1079
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1080
+ type: "button",
1081
+ className: "SKM_confirmDelete",
1082
+ disabled: ops[deleteConfirm.name]?.status === "busy",
1083
+ onClick: () => {
1084
+ const s = deleteConfirm;
1085
+ setDeleteConfirm(null);
1086
+ applyRemove(s);
1087
+ },
1088
+ children: t("deleteLabel")
1089
+ })]
1090
+ })]
1091
+ })
1092
+ }) : null,
1093
+ migrator !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MigrateDialog, {
1094
+ t,
1095
+ options: wsOptions,
1096
+ from: migrator.from,
1097
+ setFrom: (value) => setMigrator((prev) => prev === null ? prev : {
1098
+ ...prev,
1099
+ from: value,
1100
+ error: null
1101
+ }),
1102
+ targets: migrator.targets,
1103
+ toggleTarget: (value) => setMigrator((prev) => {
1104
+ if (prev === null) return prev;
1105
+ const next = new Set(prev.targets);
1106
+ if (next.has(value)) next.delete(value);
1107
+ else next.add(value);
1108
+ return {
1109
+ ...prev,
1110
+ targets: next,
1111
+ error: null,
1112
+ ...next.size > 1 && prev.mode === "move" ? { mode: "copy" } : {}
1113
+ };
1114
+ }),
1115
+ mode: migrator.mode,
1116
+ setMode: (value) => setMigrator((prev) => prev === null ? prev : {
1117
+ ...prev,
1118
+ mode: value
1119
+ }),
1120
+ skills: migratorSkills,
1121
+ selected: migrator.selected,
1122
+ toggle: (skillName) => setMigrator((prev) => {
1123
+ if (prev === null) return prev;
1124
+ const next = new Set(prev.selected);
1125
+ if (next.has(skillName)) next.delete(skillName);
1126
+ else next.add(skillName);
1127
+ return {
1128
+ ...prev,
1129
+ selected: next
1130
+ };
1131
+ }),
1132
+ selectAll: () => setMigrator((prev) => {
1133
+ if (prev === null) return prev;
1134
+ const all = new Set(migratorSkills.map((skill) => skill.name));
1135
+ return {
1136
+ ...prev,
1137
+ selected: prev.selected.size === all.size ? /* @__PURE__ */ new Set() : all
1138
+ };
1139
+ }),
1140
+ busy: migrator.busy,
1141
+ result: migrator.result,
1142
+ error: migrator.error,
1143
+ onConfirm: applyBatchMigrate,
1144
+ onCancel: () => setMigrator(null),
1145
+ onClose: () => setMigrator(null)
1146
+ }) : null
1147
+ ]
1148
+ })
1149
+ });
1150
+ }
1151
+ //#endregion
1152
+ //#region src/client/client-i18n.ts
1153
+ const zh = {
1154
+ nav: "技能管理",
1155
+ loading: "正在读取技能…",
1156
+ error: "暂时无法读取技能。",
1157
+ retry: "重试",
1158
+ search: "搜索技能",
1159
+ catalog: "技能列表",
1160
+ empty: "暂无技能。",
1161
+ emptySearch: "没有匹配的技能。",
1162
+ noSession: "打开一个会话后即可查看该会话的技能。",
1163
+ contentLoading: "正在加载技能内容…",
1164
+ contentError: "技能内容加载失败。",
1165
+ contentMissing: "技能内容不可用。",
1166
+ providerLabel: "来源",
1167
+ enabledTag: "已启用",
1168
+ disabledTag: "已停用",
1169
+ switchEnable: "启用",
1170
+ switchDisable: "停用",
1171
+ deleteLabel: "删除",
1172
+ deleteConfirm: "确定要删除技能 ",
1173
+ deleteConfirmSuffix: " 吗?此操作不可恢复。",
1174
+ opFailed: "操作失败",
1175
+ addButton: "添加技能",
1176
+ addMenuFolder: "选择目录束",
1177
+ addMenuFile: "选择单文件",
1178
+ addDismiss: "知道了",
1179
+ addBusy: "正在添加技能…",
1180
+ addTooMany: "所选内容文件数量过多。",
1181
+ addFolderUnsupported: "当前浏览器不支持选择文件夹,请改用\"选择技能文件\"。",
1182
+ addNoSkillFile: "所选文件夹不是有效的技能目录:缺少顶层的 SKILL.md 文件。",
1183
+ scopeGlobal: "全局",
1184
+ emptyScope: "该作用域下暂无技能。",
1185
+ migrateButton: "批量迁移",
1186
+ migrateTitle: "批量迁移技能",
1187
+ migrateFrom: "源作用域(手动选择)",
1188
+ migrateTo: "目标作用域(可多选)",
1189
+ migrateMode: "方式",
1190
+ migrateModeCopy: "复制(保留原技能)",
1191
+ migrateModeMove: "移动(删除原技能)",
1192
+ migrateSelectAll: "全选",
1193
+ migrateNoSkills: "该作用域下没有可迁移的技能。",
1194
+ migratePickSource: "请先选择源作用域",
1195
+ migratePickTarget: "请至少选择一个目标作用域",
1196
+ migrateSameScope: "目标作用域不能与源作用域相同",
1197
+ migrateMoveSingle: "移动模式只能选择一个目标作用域(多目标请改用复制)",
1198
+ migratePickSkills: "请至少选择一个技能",
1199
+ migrateConfirm: "开始迁移",
1200
+ migrateBusy: "正在迁移…",
1201
+ migrateCancel: "取消",
1202
+ migrateDoneOk: "迁移完成:成功 ",
1203
+ migrateDoneFail: ",失败 ",
1204
+ migrateDoneSuffix: "",
1205
+ migrateErrors: "失败明细",
1206
+ migrateSourceLabel: "源作用域",
1207
+ migrateTargetLabel: "目标作用域",
1208
+ migrateClose: "关闭"
1209
+ };
1210
+ const en = {
1211
+ nav: "Skill Manage",
1212
+ loading: "Reading skills…",
1213
+ error: "Skills are temporarily unavailable.",
1214
+ retry: "Retry",
1215
+ search: "Search skills",
1216
+ catalog: "Skills",
1217
+ empty: "No skills are available.",
1218
+ emptySearch: "No matching skills.",
1219
+ noSession: "Open a session to view its skills.",
1220
+ contentLoading: "Loading skill content…",
1221
+ contentError: "Skill content failed to load.",
1222
+ contentMissing: "Skill content is unavailable.",
1223
+ providerLabel: "Provider",
1224
+ enabledTag: "Enabled",
1225
+ disabledTag: "Disabled",
1226
+ switchEnable: "Enable",
1227
+ switchDisable: "Disable",
1228
+ deleteLabel: "Delete",
1229
+ deleteConfirm: "Delete skill ",
1230
+ deleteConfirmSuffix: "? This cannot be undone.",
1231
+ opFailed: "Operation failed",
1232
+ addButton: "Add skill",
1233
+ addMenuFolder: "Choose directory bundle",
1234
+ addMenuFile: "Choose single file",
1235
+ addDismiss: "Dismiss",
1236
+ addBusy: "Adding skill…",
1237
+ addTooMany: "Too many files in the selection.",
1238
+ addFolderUnsupported: "This browser cannot pick folders — use Choose skill file instead.",
1239
+ addNoSkillFile: "Not a valid skill folder: missing a top-level SKILL.md file.",
1240
+ scopeGlobal: "Global",
1241
+ emptyScope: "No skills in this scope yet.",
1242
+ migrateButton: "Batch migrate",
1243
+ migrateTitle: "Batch migrate skills",
1244
+ migrateFrom: "From (pick one)",
1245
+ migrateTo: "To (multiple allowed)",
1246
+ migrateMode: "Mode",
1247
+ migrateModeCopy: "Copy (keep the original)",
1248
+ migrateModeMove: "Move (delete the original)",
1249
+ migrateSelectAll: "Select all",
1250
+ migrateNoSkills: "No skills to migrate in this scope.",
1251
+ migratePickSource: "Pick a source scope first",
1252
+ migratePickTarget: "Pick at least one target scope",
1253
+ migrateSameScope: "A target scope must differ from the source",
1254
+ migrateMoveSingle: "Move mode allows exactly one target (use Copy for several)",
1255
+ migratePickSkills: "Pick at least one skill",
1256
+ migrateConfirm: "Start migration",
1257
+ migrateBusy: "Migrating…",
1258
+ migrateCancel: "Cancel",
1259
+ migrateDoneOk: "Migration finished: ",
1260
+ migrateDoneFail: " succeeded, ",
1261
+ migrateDoneSuffix: " failed",
1262
+ migrateErrors: "Failed items",
1263
+ migrateSourceLabel: "From",
1264
+ migrateTargetLabel: "To",
1265
+ migrateClose: "Close"
1266
+ };
1267
+ //#endregion
1268
+ //#region src/client/index.ts
1269
+ const SECTION_ID = "skill-manage";
1270
+ const SECTION_ORDER = 17;
1271
+ const I18N_NS = "settings.skills";
1272
+ const SERVICE = "skillManage";
1273
+ const PACKAGE = "@lijian-ui/dsh-skill-manage";
1274
+ const inject = [
1275
+ "slots",
1276
+ "locale",
1277
+ "remote",
1278
+ "sessions"
1279
+ ];
1280
+ const identity = (value) => value;
1281
+ const codec = (symbol) => ({
1282
+ mode: "strict",
1283
+ typeSymbol: symbol,
1284
+ schema: { parse: identity }
1285
+ });
1286
+ const CONTRIBUTION = {
1287
+ package: PACKAGE,
1288
+ descriptors: [
1289
+ {
1290
+ id: `${PACKAGE}#${SERVICE}/list`,
1291
+ service: SERVICE,
1292
+ namespace: SERVICE,
1293
+ method: "list",
1294
+ invocation: { kind: "direct" },
1295
+ parameters: [{
1296
+ name: "sessionId",
1297
+ wire: "sessionId",
1298
+ source: "json",
1299
+ acceptsUndefined: true,
1300
+ codec: codec(`${PACKAGE}#sessionId`)
1301
+ }],
1302
+ result: codec(`${PACKAGE}#SkillListResult`)
1303
+ },
1304
+ {
1305
+ id: `${PACKAGE}#${SERVICE}/workspaces`,
1306
+ service: SERVICE,
1307
+ namespace: SERVICE,
1308
+ method: "workspaces",
1309
+ invocation: { kind: "direct" },
1310
+ parameters: [],
1311
+ result: codec(`${PACKAGE}#WorkspacesResult`)
1312
+ },
1313
+ {
1314
+ id: `${PACKAGE}#${SERVICE}/migrate`,
1315
+ service: SERVICE,
1316
+ namespace: SERVICE,
1317
+ method: "migrate",
1318
+ invocation: { kind: "direct" },
1319
+ parameters: [
1320
+ {
1321
+ name: "name",
1322
+ wire: "name",
1323
+ source: "json",
1324
+ codec: codec(`${PACKAGE}#SkillName`)
1325
+ },
1326
+ {
1327
+ name: "sessionId",
1328
+ wire: "sessionId",
1329
+ source: "json",
1330
+ acceptsUndefined: true,
1331
+ codec: codec(`${PACKAGE}#sessionId`)
1332
+ },
1333
+ {
1334
+ name: "payload",
1335
+ wire: "payload",
1336
+ source: "json",
1337
+ codec: codec(`${PACKAGE}#MigratePayload`)
1338
+ }
1339
+ ],
1340
+ result: codec(`${PACKAGE}#MigrateResult`)
1341
+ },
1342
+ {
1343
+ id: `${PACKAGE}#${SERVICE}/batchMigrate`,
1344
+ service: SERVICE,
1345
+ namespace: SERVICE,
1346
+ method: "batchMigrate",
1347
+ invocation: { kind: "direct" },
1348
+ parameters: [{
1349
+ name: "sessionId",
1350
+ wire: "sessionId",
1351
+ source: "json",
1352
+ acceptsUndefined: true,
1353
+ codec: codec(`${PACKAGE}#sessionId`)
1354
+ }, {
1355
+ name: "payload",
1356
+ wire: "payload",
1357
+ source: "json",
1358
+ codec: codec(`${PACKAGE}#BatchMigratePayload`)
1359
+ }],
1360
+ result: codec(`${PACKAGE}#BatchMigrateResult`)
1361
+ },
1362
+ {
1363
+ id: `${PACKAGE}#${SERVICE}/content`,
1364
+ service: SERVICE,
1365
+ namespace: SERVICE,
1366
+ method: "content",
1367
+ invocation: { kind: "direct" },
1368
+ parameters: [{
1369
+ name: "name",
1370
+ wire: "name",
1371
+ source: "json",
1372
+ codec: codec(`${PACKAGE}#SkillName`)
1373
+ }, {
1374
+ name: "sessionId",
1375
+ wire: "sessionId",
1376
+ source: "json",
1377
+ acceptsUndefined: true,
1378
+ codec: codec(`${PACKAGE}#sessionId`)
1379
+ }],
1380
+ result: codec(`${PACKAGE}#SkillContent`)
1381
+ },
1382
+ {
1383
+ id: `${PACKAGE}#${SERVICE}/setEnabled`,
1384
+ service: SERVICE,
1385
+ namespace: SERVICE,
1386
+ method: "setEnabled",
1387
+ invocation: { kind: "direct" },
1388
+ parameters: [
1389
+ {
1390
+ name: "name",
1391
+ wire: "name",
1392
+ source: "json",
1393
+ codec: codec(`${PACKAGE}#SkillName`)
1394
+ },
1395
+ {
1396
+ name: "sessionId",
1397
+ wire: "sessionId",
1398
+ source: "json",
1399
+ acceptsUndefined: true,
1400
+ codec: codec(`${PACKAGE}#sessionId`)
1401
+ },
1402
+ {
1403
+ name: "enabled",
1404
+ wire: "enabled",
1405
+ source: "json",
1406
+ codec: codec(`${PACKAGE}#EnabledFlag`)
1407
+ }
1408
+ ],
1409
+ result: codec(`${PACKAGE}#SetEnabledResult`)
1410
+ },
1411
+ {
1412
+ id: `${PACKAGE}#${SERVICE}/deleteSkill`,
1413
+ service: SERVICE,
1414
+ namespace: SERVICE,
1415
+ method: "deleteSkill",
1416
+ invocation: { kind: "direct" },
1417
+ parameters: [{
1418
+ name: "name",
1419
+ wire: "name",
1420
+ source: "json",
1421
+ codec: codec(`${PACKAGE}#SkillName`)
1422
+ }, {
1423
+ name: "sessionId",
1424
+ wire: "sessionId",
1425
+ source: "json",
1426
+ acceptsUndefined: true,
1427
+ codec: codec(`${PACKAGE}#sessionId`)
1428
+ }],
1429
+ result: codec(`${PACKAGE}#DeleteSkillResult`)
1430
+ },
1431
+ {
1432
+ id: `${PACKAGE}#${SERVICE}/addSkill`,
1433
+ service: SERVICE,
1434
+ namespace: SERVICE,
1435
+ method: "addSkill",
1436
+ invocation: { kind: "direct" },
1437
+ parameters: [{
1438
+ name: "sessionId",
1439
+ wire: "sessionId",
1440
+ source: "json",
1441
+ acceptsUndefined: true,
1442
+ codec: codec(`${PACKAGE}#sessionId`)
1443
+ }, {
1444
+ name: "payload",
1445
+ wire: "payload",
1446
+ source: "json",
1447
+ codec: codec(`${PACKAGE}#AddPayload`)
1448
+ }],
1449
+ result: codec(`${PACKAGE}#AddResult`)
1450
+ }
1451
+ ]
1452
+ };
1453
+ function apply(ctx) {
1454
+ ctx.effect(() => ctx.locale.register(I18N_NS, {
1455
+ zh,
1456
+ en
1457
+ }), "skill-manage: client dictionaries");
1458
+ const t = ctx.locale.bind(I18N_NS);
1459
+ const mount = ctx.remote.$mount(CONTRIBUTION);
1460
+ const currentSessionId = () => ctx.get("sessions").currentProvideInfo.getSnapshot().sessionId;
1461
+ const callRemote = async (method, ...args) => {
1462
+ await mount;
1463
+ const result = await ctx.get(`remote.${SERVICE}`)[method](...args);
1464
+ if (!result.ok) throw new Error(`${SERVICE}.${method} failed: ${result.error?.code}: ${result.error?.message}`);
1465
+ return result.value;
1466
+ };
1467
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
1468
+ name: "settings.section",
1469
+ id: SECTION_ID,
1470
+ order: SECTION_ORDER,
1471
+ label: () => t("nav"),
1472
+ locale: I18N_NS,
1473
+ inject: () => ({
1474
+ t,
1475
+ currentSessionId,
1476
+ listSkills: () => callRemote("list", currentSessionId()),
1477
+ listWorkspaces: () => callRemote("workspaces"),
1478
+ loadContent: (name) => callRemote("content", name, currentSessionId()),
1479
+ setSkillEnabled: (name, enabled) => callRemote("setEnabled", name, currentSessionId(), enabled),
1480
+ batchMigrateSkill: (payload) => callRemote("batchMigrate", currentSessionId(), payload),
1481
+ removeSkill: (name) => callRemote("deleteSkill", name, currentSessionId()),
1482
+ addSkill: (payload) => callRemote("addSkill", currentSessionId(), payload),
1483
+ refreshSkillCache: () => ctx.emit("connection/reset")
1484
+ })
1485
+ }, SkillManageSection));
1486
+ }
1487
+ //#endregion
1488
+ exports.apply = apply;
1489
+ exports.inject = inject;
1490
+ return module.exports;
1491
+ }
1492
+ });
1493
+
1494
+ //# sourceMappingURL=client.js.map