@max-null/dsh-plugin-center 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/client.js ADDED
@@ -0,0 +1,633 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@max-null/dsh-plugin-center",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+
7
+ "use strict";
8
+ var __defProp = Object.defineProperty;
9
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
10
+ var __getOwnPropNames = Object.getOwnPropertyNames;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
25
+
26
+ // client/index.tsx
27
+ var index_exports = {};
28
+ __export(index_exports, {
29
+ apply: () => apply,
30
+ inject: () => inject
31
+ });
32
+ module.exports = __toCommonJS(index_exports);
33
+ var import_react = require("react");
34
+ var import_jsx_runtime = require("react/jsx-runtime");
35
+ var CSS = `
36
+ .pc-title { font-size: 18px; font-weight: 600; line-height: 26px; color: var(--dsw-alias-label-primary); }
37
+ .pc-sub { font-size: 13px; line-height: 20px; margin-top: 4px; color: var(--dsw-alias-label-tertiary); }
38
+ .pc-head { display: flex; align-items: center; gap: 10px; }
39
+ .pc-head .pc-sub { margin-top: 0; }
40
+ .pc-head .pc-btn { flex: none; }
41
+ .pc-count { display: inline-block; min-width: 16px; padding: 0 5px; margin-left: 6px; border-radius: 8px; background: var(--dsw-alias-bg-module-platform); color: var(--dsw-alias-label-secondary); font-size: 12px; text-align: center; }
42
+ .pc-tab.active .pc-count { background: var(--dsw-alias-state-business-tertiary); color: var(--dsw-alias-state-business-primary); }
43
+ .pc-tabs { display: flex; gap: 4px; margin: 16px 0 12px; border-bottom: 1px solid var(--dsw-alias-border-l2); }
44
+ .pc-tab { padding: 8px 14px; font-size: 14px; cursor: pointer; background: none; border: none; font-family: inherit; color: var(--dsw-alias-label-tertiary); border-bottom: 2px solid transparent; margin-bottom: -1px; }
45
+ .pc-tab:hover { color: var(--dsw-alias-label-secondary); }
46
+ .pc-tab.active { color: var(--dsw-alias-label-primary); border-bottom-color: var(--dsw-alias-state-business-primary); }
47
+
48
+ .pc-card { border: 1px solid var(--dsw-alias-border-l2); border-radius: 10px; padding: 14px 16px; margin-bottom: 10px; background: var(--dsw-alias-bg-layer-1); min-width: 0; transition: border-color .15s; display: flex; flex-direction: column; }
49
+ .pc-card:hover { border-color: var(--dsw-alias-border-l3); }
50
+ .pc-name { font-weight: 500; color: var(--dsw-alias-label-primary); }
51
+ .pc-ver { color: var(--dsw-alias-label-caption); font-size: 12px; }
52
+ .pc-desc { color: var(--dsw-alias-label-secondary); font-size: 13px; margin-top: 6px; word-break: break-word; overflow-wrap: break-word; }
53
+ .pc-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
54
+ .pc-spacer { flex: 1; }
55
+ .pc-meta { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin-top: auto; padding-top: 10px; }
56
+
57
+ .pc-badge { display: inline-flex; align-items: center; height: 20px; padding: 0 8px; border-radius: 6px; font-size: 12px; line-height: 1; }
58
+ .pc-badge.official { background: var(--dsw-alias-state-business-tertiary); color: var(--dsw-alias-state-business-primary); }
59
+ .pc-badge.installed { background: var(--dsw-alias-state-warn-tertiary); color: var(--dsw-alias-state-warn-primary); }
60
+ .pc-badge.local, .pc-badge.builtin { background: var(--dsw-alias-bg-module-platform); color: var(--dsw-alias-label-tertiary); }
61
+ .pc-tag { display: inline-flex; align-items: center; height: 20px; padding: 0 8px; border-radius: 6px; font-size: 12px; line-height: 1; background: var(--dsw-alias-bg-module-platform); color: var(--dsw-alias-label-secondary); }
62
+ .pc-tag.danger { background: var(--dsw-alias-interactive-bg-hover-danger); color: var(--dsw-alias-state-error-primary); }
63
+ .pc-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--dsw-alias-state-success-primary); }
64
+ .pc-dot.failed { background: var(--dsw-alias-state-error-primary); }
65
+
66
+ .pc-toolbar { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding: 4px 0; }
67
+ .pc-chip { height: 28px; padding: 0 12px; border-radius: 18px; border: 1px solid var(--dsw-alias-border-l2); background: var(--dsw-alias-bg-base); color: var(--dsw-alias-label-secondary); font-size: 13px; cursor: pointer; font-family: inherit; }
68
+ .pc-chip:hover { background: var(--dsw-alias-interactive-bg-hover); }
69
+ .pc-chip.active { background: var(--dsw-alias-state-business-primary); border-color: var(--dsw-alias-state-business-primary); color: var(--dsw-alias-bg-base); }
70
+
71
+ .pc-btn { height: 26px; padding: 0 10px; border-radius: 8px; border: 1px solid var(--dsw-alias-border-l2); background: var(--dsw-alias-bg-module-platform); color: var(--dsw-alias-label-primary); font-size: 12px; cursor: pointer; font-family: inherit; }
72
+ .pc-btn:hover { background: var(--dsw-alias-interactive-bg-hover); }
73
+ .pc-btn.primary { border: none; background: var(--dsw-alias-button-primary-fill); color: var(--dsw-alias-bg-base); }
74
+ .pc-btn.primary:hover { background: var(--dsw-alias-button-primary-hover); }
75
+ .pc-btn:disabled { opacity: 0.5; cursor: default; }
76
+
77
+ .pc-search { height: 28px; padding: 0 12px; border-radius: 18px; border: 1px solid var(--dsw-alias-border-l2); background: var(--dsw-alias-bg-base); color: var(--dsw-alias-label-primary); font-size: 13px; outline: none; width: 200px; font-family: inherit; }
78
+ .pc-search:focus { border-color: var(--dsw-alias-state-business-primary); }
79
+ .pc-search::placeholder { color: var(--dsw-alias-label-caption); }
80
+ .pc-select { height: 28px; padding: 0 8px; border-radius: 18px; border: 1px solid var(--dsw-alias-border-l2); background: var(--dsw-alias-bg-base); color: var(--dsw-alias-label-secondary); font-size: 13px; cursor: pointer; font-family: inherit; }
81
+ .pc-iconbtn { width: 28px; height: 28px; padding: 0; border-radius: 18px; border: 1px solid var(--dsw-alias-border-l2); background: var(--dsw-alias-bg-base); color: var(--dsw-alias-label-secondary); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
82
+ .pc-iconbtn:hover { background: var(--dsw-alias-interactive-bg-hover); }
83
+
84
+ .pc-grid { display: grid; gap: 12px; }
85
+ .pc-grid.double { grid-template-columns: 1fr 1fr; }
86
+ .pc-grid.single { grid-template-columns: 1fr; }
87
+
88
+ .pc-overlay { position: fixed; inset: 0; background: var(--dsw-alias-bg-mask-1); display: flex; align-items: center; justify-content: center; z-index: 100; }
89
+ .pc-panel { width: 760px; max-width: 94vw; max-height: 86vh; background: var(--dsw-alias-bg-base); border-radius: 12px; box-shadow: 0 24px 64px rgba(0,0,0,.24); display: flex; flex-direction: column; overflow: hidden; }
90
+ .pc-panel-head { flex: none; display: flex; align-items: center; padding: 20px 28px 0; }
91
+ .pc-panel-body { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 8px 28px 20px; }
92
+ .pc-scroll { flex: 1; min-height: 0; overflow: auto; }
93
+ .pc-close { background: none; border: none; color: var(--dsw-alias-label-tertiary); font-size: 20px; cursor: pointer; padding: 4px 8px; border-radius: 6px; font-family: inherit; }
94
+ .pc-close:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
95
+ .pc-headerbtn { height: 28px; width: 28px; display: inline-flex; align-items: center; justify-content: center; border-radius: 6px; border: none; background: transparent; cursor: pointer; color: var(--dsw-alias-label-secondary); }
96
+ .pc-headerbtn:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
97
+ .pc-wn-item { border-bottom: 1px solid var(--dsw-alias-border-l1); padding: 14px 0; }
98
+ .pc-wn-item:last-child { border-bottom: none; }
99
+ .pc-wn-list { margin-top: 8px; padding-left: 20px; color: var(--dsw-alias-label-secondary); font-size: 13px; }
100
+ .pc-toast { position: fixed; bottom: 32px; left: 50%; transform: translateX(-50%); padding: 10px 18px; border-radius: 10px; background: var(--dsw-alias-bg-layer-1); border: 1px solid var(--dsw-alias-border-l2); color: var(--dsw-alias-label-primary); font-size: 13px; box-shadow: 0 8px 32px rgba(0,0,0,.18); z-index: 200; max-width: 80vw; }
101
+ .pc-toast.ok { border-color: var(--dsw-alias-state-success-primary); }
102
+ .pc-toast.error { border-color: var(--dsw-alias-state-error-primary); }
103
+ `;
104
+ var cssInjected = false;
105
+ function injectCss() {
106
+ if (cssInjected || typeof document === "undefined") return;
107
+ cssInjected = true;
108
+ const style = document.createElement("style");
109
+ style.setAttribute("data-plugin", "@max-null/dsh-plugin-center");
110
+ style.textContent = CSS;
111
+ document.head.append(style);
112
+ }
113
+ var rpc = async () => {
114
+ throw new Error("plugin-center: rpc not wired");
115
+ };
116
+ var overlayOpen = false;
117
+ var whatsNewOpen = false;
118
+ var whatsNewDigests = [];
119
+ var overlayListeners = /* @__PURE__ */ new Set();
120
+ var whatsNewListeners = /* @__PURE__ */ new Set();
121
+ function openOverlay() {
122
+ overlayOpen = true;
123
+ overlayListeners.forEach((l) => l());
124
+ }
125
+ function closeOverlay() {
126
+ overlayOpen = false;
127
+ overlayListeners.forEach((l) => l());
128
+ }
129
+ function closeWhatsNew() {
130
+ whatsNewOpen = false;
131
+ for (const d of whatsNewDigests) readCache[d.name] = d.toVersion;
132
+ void rpc("markRead", { versions: readCache });
133
+ whatsNewListeners.forEach((l) => l());
134
+ }
135
+ function useOverlayOpen() {
136
+ const [open, setOpen] = (0, import_react.useState)(overlayOpen);
137
+ (0, import_react.useEffect)(() => {
138
+ const l = () => {
139
+ setOpen(overlayOpen);
140
+ };
141
+ overlayListeners.add(l);
142
+ return () => {
143
+ overlayListeners.delete(l);
144
+ };
145
+ }, []);
146
+ return open;
147
+ }
148
+ function useWhatsNewOpen() {
149
+ const [open, setOpen] = (0, import_react.useState)(whatsNewOpen);
150
+ (0, import_react.useEffect)(() => {
151
+ const l = () => {
152
+ setOpen(whatsNewOpen);
153
+ };
154
+ whatsNewListeners.add(l);
155
+ return () => {
156
+ whatsNewListeners.delete(l);
157
+ };
158
+ }, []);
159
+ return open;
160
+ }
161
+ var readCache = {};
162
+ var installedCache = null;
163
+ var marketCache = {};
164
+ var toastState = null;
165
+ var toastListeners = /* @__PURE__ */ new Set();
166
+ function showToast(message, kind = "ok") {
167
+ toastState = { message, kind };
168
+ toastListeners.forEach((l) => l());
169
+ }
170
+ var pendingInstall = /* @__PURE__ */ new Set();
171
+ function useToast() {
172
+ const [t, setT] = (0, import_react.useState)(toastState);
173
+ (0, import_react.useEffect)(() => {
174
+ const l = () => {
175
+ setT(toastState);
176
+ };
177
+ toastListeners.add(l);
178
+ return () => {
179
+ toastListeners.delete(l);
180
+ };
181
+ }, []);
182
+ (0, import_react.useEffect)(() => {
183
+ if (t === null) return;
184
+ const id = setTimeout(() => {
185
+ toastState = null;
186
+ toastListeners.forEach((l) => l());
187
+ }, 3200);
188
+ return () => clearTimeout(id);
189
+ }, [t]);
190
+ return t;
191
+ }
192
+ async function checkWhatNew() {
193
+ try {
194
+ const since = new Date(Date.now() - 30 * 864e5).toISOString();
195
+ const digests = await rpc("checkUpdates", { since });
196
+ readCache = await rpc("readVersions");
197
+ const fresh = digests.filter((d) => readCache[d.name] !== d.toVersion);
198
+ if (fresh.length > 0) {
199
+ whatsNewDigests = fresh;
200
+ whatsNewOpen = true;
201
+ whatsNewListeners.forEach((l) => l());
202
+ }
203
+ } catch {
204
+ }
205
+ }
206
+ var SOURCE_LABEL = { official: "\u5B98\u65B9", installed: "\u7528\u6237\u5B89\u88C5", local: "\u672C\u5730\u5F00\u53D1", builtin: "\u5185\u7F6E" };
207
+ var CATEGORIES = ["ui", "usage", "theme", "model", "session", "memory", "tools", "vision", "skill", "workflow", "notify", "dev", "market", "fun"];
208
+ function InstalledView({ search, category, source }) {
209
+ const [items, setItems] = (0, import_react.useState)(installedCache);
210
+ const [error, setError] = (0, import_react.useState)(null);
211
+ (0, import_react.useEffect)(() => {
212
+ if (installedCache !== null) return;
213
+ let alive = true;
214
+ void rpc("listInstalled").then(
215
+ (v) => {
216
+ installedCache = v;
217
+ if (alive) setItems(installedCache);
218
+ },
219
+ (e) => {
220
+ if (alive) setError(e instanceof Error ? e.message : String(e));
221
+ }
222
+ );
223
+ return () => {
224
+ alive = false;
225
+ };
226
+ }, []);
227
+ if (error !== null) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "pc-sub", children: [
228
+ "\u52A0\u8F7D\u5931\u8D25\uFF1A",
229
+ error
230
+ ] });
231
+ if (items === null) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "pc-sub", children: "\u52A0\u8F7D\u4E2D\u2026" });
232
+ const q = search.trim().toLowerCase();
233
+ const filtered = items.filter((p) => {
234
+ const matchSearch = q === "" || p.displayName.toLowerCase().includes(q) || (p.description ?? "").toLowerCase().includes(q) || p.name.toLowerCase().includes(q);
235
+ const matchCategory = category === null || p.categories.includes(category);
236
+ const matchSource = source === null || p.source === source;
237
+ return matchSearch && matchCategory && matchSource;
238
+ });
239
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: filtered.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-card", children: [
240
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-row", children: [
241
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-name", children: p.displayName }),
242
+ p.version !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "pc-ver", children: [
243
+ "v",
244
+ p.version
245
+ ] }),
246
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `pc-badge ${p.source}`, children: SOURCE_LABEL[p.source] }),
247
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-spacer" }),
248
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `pc-dot${p.fiberPhase === "failed" ? " failed" : ""}` })
249
+ ] }),
250
+ p.description !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pc-desc", children: p.description }),
251
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-meta", children: [
252
+ p.categories.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-tag", children: c }, c)),
253
+ p.compatRange !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "pc-tag", children: [
254
+ "\u8981\u6C42 DSH ",
255
+ p.compatRange
256
+ ] }),
257
+ !p.enabled && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-tag", children: "\u5DF2\u7981\u7528" })
258
+ ] })
259
+ ] }, p.entryId)) });
260
+ }
261
+ function MarketView({ category, single, source, search, onCount }) {
262
+ const [items, setItems] = (0, import_react.useState)(marketCache[source]?.plugins ?? []);
263
+ const [done, setDone] = (0, import_react.useState)(marketCache[source]?.done ?? false);
264
+ const [error, setError] = (0, import_react.useState)(null);
265
+ const [busy, setBusy] = (0, import_react.useState)(null);
266
+ (0, import_react.useEffect)(() => {
267
+ let alive = true;
268
+ let timer;
269
+ const cached = marketCache[source];
270
+ if (cached !== void 0) {
271
+ setItems(cached.plugins);
272
+ setDone(cached.done);
273
+ onCount(cached.plugins.length);
274
+ if (cached.done) return;
275
+ } else {
276
+ setItems([]);
277
+ setDone(false);
278
+ onCount(0);
279
+ }
280
+ const poll = async () => {
281
+ try {
282
+ const r = await rpc("listMarket", { source });
283
+ if (!alive) return;
284
+ marketCache[source] = { plugins: r.plugins, done: r.done };
285
+ setItems(r.plugins);
286
+ setDone(r.done);
287
+ onCount(r.plugins.length);
288
+ if (!r.done) timer = setTimeout(poll, 1200);
289
+ } catch (e) {
290
+ if (alive) setError(e instanceof Error ? e.message : String(e));
291
+ }
292
+ };
293
+ void poll();
294
+ return () => {
295
+ alive = false;
296
+ if (timer !== void 0) clearTimeout(timer);
297
+ };
298
+ }, [source, onCount]);
299
+ if (error !== null) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "pc-sub", children: [
300
+ "\u52A0\u8F7D\u5931\u8D25\uFF1A",
301
+ error
302
+ ] });
303
+ if (items.length === 0 && !done) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "pc-sub", children: "\u52A0\u8F7D\u5E02\u573A\u76EE\u5F55\u4E2D\u2026" });
304
+ const q = search.trim().toLowerCase();
305
+ const filtered = items.filter((m) => {
306
+ const matchSearch = q === "" || m.name.toLowerCase().includes(q) || (m.description.zh || m.description.en).toLowerCase().includes(q);
307
+ return matchSearch && (category === null || m.categories.includes(category));
308
+ });
309
+ const install = (m) => {
310
+ setBusy(m.name);
311
+ void rpc("install", { spec: m.spec }).then(
312
+ () => {
313
+ setBusy(null);
314
+ pendingInstall.add(m.spec);
315
+ for (const key of Object.keys(marketCache)) {
316
+ const c = marketCache[key];
317
+ if (c !== void 0) c.plugins = c.plugins.map((p) => p.name === m.name ? { ...p, installed: true } : p);
318
+ }
319
+ setItems((prev) => prev.map((p) => p.name === m.name ? { ...p, installed: true } : p));
320
+ showToast(`\u5DF2\u53D1\u8D77\u5B89\u88C5 ${m.name}\uFF0C\u91CD\u542F dsh web \u540E\u751F\u6548`);
321
+ },
322
+ (e) => {
323
+ setBusy(null);
324
+ showToast(`\u5B89\u88C5\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`, "error");
325
+ }
326
+ );
327
+ };
328
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
329
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `pc-grid ${single ? "single" : "double"}`, children: filtered.map((m) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-card", children: [
330
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-row", children: [
331
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-name", children: m.name }),
332
+ m.stars !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "pc-ver", children: [
333
+ "\u2605 ",
334
+ m.stars
335
+ ] }),
336
+ m.version !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "pc-ver", children: [
337
+ "v",
338
+ m.version
339
+ ] })
340
+ ] }),
341
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pc-desc", children: m.description.zh || m.description.en }),
342
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-meta", children: [
343
+ m.categories.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-tag", children: c }, c)),
344
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-spacer" }),
345
+ m.installed || pendingInstall.has(m.spec) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-tag", children: pendingInstall.has(m.spec) ? "\u5F85\u91CD\u542F\u751F\u6548" : "\u5DF2\u5B89\u88C5" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "pc-btn primary", disabled: busy !== null, onClick: () => {
346
+ install(m);
347
+ }, children: busy === m.name ? "\u5B89\u88C5\u4E2D\u2026" : "\u5B89\u88C5" })
348
+ ] })
349
+ ] }, m.name)) }),
350
+ !done && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "pc-sub", children: [
351
+ "\u6B63\u5728\u52A0\u8F7D\u66F4\u591A\u2026\uFF08\u5DF2\u52A0\u8F7D ",
352
+ items.length,
353
+ " \u4E2A\uFF09"
354
+ ] })
355
+ ] });
356
+ }
357
+ function UpdatesView({ updates, refresh, updateOne, busy }) {
358
+ if (updates === null) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "pc-sub", children: "\u68C0\u67E5\u66F4\u65B0\u4E2D\u2026" });
359
+ if (updates.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
360
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "pc-sub", children: "\u6CA1\u6709\u53EF\u7528\u7684\u66F4\u65B0\u3002" }),
361
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "pc-btn", onClick: refresh, children: "\u91CD\u65B0\u68C0\u67E5" })
362
+ ] });
363
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: updates.map((u) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-card", children: [
364
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-row", children: [
365
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-name", children: u.name }),
366
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-ver", children: u.fromVersion }),
367
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-ver", children: "\u2192" }),
368
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--dsw-alias-state-business-primary)", fontWeight: 500 }, children: u.toVersion }),
369
+ u.compat === "incompatible" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-tag danger", children: "\u4E0D\u517C\u5BB9\u5F53\u524D DSH" }),
370
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-spacer" }),
371
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "pc-btn primary", disabled: busy !== null, onClick: () => {
372
+ updateOne(u.name);
373
+ }, children: busy === u.name ? "\u66F4\u65B0\u4E2D\u2026" : "\u66F4\u65B0" })
374
+ ] }),
375
+ u.changelog.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "pc-wn-list", children: u.changelog.slice(0, 5).map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: line }, i)) })
376
+ ] }, u.name)) });
377
+ }
378
+ function CenterPanel({ variant = "section" }) {
379
+ const [view, setView] = (0, import_react.useState)("installed");
380
+ const [category, setCategory] = (0, import_react.useState)(null);
381
+ const [single, setSingle] = (0, import_react.useState)(false);
382
+ const [source, setSource] = (0, import_react.useState)("awesome");
383
+ const [search, setSearch] = (0, import_react.useState)("");
384
+ const [installedCategory, setInstalledCategory] = (0, import_react.useState)(null);
385
+ const [marketSearch, setMarketSearch] = (0, import_react.useState)("");
386
+ const [installedSource, setInstalledSource] = (0, import_react.useState)(null);
387
+ const [installedCount, setInstalledCount] = (0, import_react.useState)(0);
388
+ const [failedCount, setFailedCount] = (0, import_react.useState)(0);
389
+ const [marketCount, setMarketCount] = (0, import_react.useState)(0);
390
+ const [updates, setUpdates] = (0, import_react.useState)(null);
391
+ const [busyUpdate, setBusyUpdate] = (0, import_react.useState)(null);
392
+ const refreshUpdates = (0, import_react.useCallback)(() => {
393
+ void rpc("checkUpdates", { since: new Date(Date.now() - 30 * 864e5).toISOString() }).then(
394
+ (v) => {
395
+ setUpdates(v);
396
+ },
397
+ () => {
398
+ }
399
+ );
400
+ }, []);
401
+ (0, import_react.useEffect)(() => {
402
+ void rpc("listInstalled").then(
403
+ (v) => {
404
+ const items = v;
405
+ setInstalledCount(items.length);
406
+ setFailedCount(items.filter((p) => p.fiberPhase === "failed").length);
407
+ },
408
+ () => {
409
+ }
410
+ );
411
+ refreshUpdates();
412
+ }, [refreshUpdates]);
413
+ const updateOne = (name) => {
414
+ setBusyUpdate(name);
415
+ void rpc("update", { name }).then(
416
+ () => {
417
+ setBusyUpdate(null);
418
+ showToast(`\u5DF2\u66F4\u65B0 ${name}\uFF0C\u91CD\u542F dsh web \u540E\u751F\u6548`);
419
+ },
420
+ (e) => {
421
+ setBusyUpdate(null);
422
+ showToast(`\u66F4\u65B0\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`, "error");
423
+ }
424
+ );
425
+ };
426
+ const updateAll = () => {
427
+ if (updates !== null) {
428
+ for (const u of updates) {
429
+ void updateOne(u.name);
430
+ }
431
+ }
432
+ };
433
+ const tab = (v, label, count) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: `pc-tab${view === v ? " active" : ""}`, onClick: () => {
434
+ setView(v);
435
+ }, children: [
436
+ label,
437
+ count !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-count", children: count })
438
+ ] }, v);
439
+ const tabs = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-tabs", children: [
440
+ tab("installed", "\u5DF2\u5B89\u88C5", installedCount),
441
+ tab("market", "\u5E02\u573A", marketCount),
442
+ tab("updates", "\u66F4\u65B0", updates?.length ?? 0)
443
+ ] });
444
+ const head = (showTitle) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-head", children: [
445
+ showTitle && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-title", children: "\u63D2\u4EF6\u4E2D\u5FC3" }),
446
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "pc-sub", children: [
447
+ "\u5DF2\u5B89\u88C5 ",
448
+ installedCount,
449
+ " \xB7 \u6709\u66F4\u65B0 ",
450
+ updates?.length ?? 0,
451
+ " \xB7 \u5931\u6548 ",
452
+ failedCount
453
+ ] }),
454
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-spacer" }),
455
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "pc-btn", onClick: refreshUpdates, children: "\u68C0\u67E5\u66F4\u65B0" }),
456
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { className: "pc-btn primary", disabled: !updates?.length, onClick: updateAll, children: [
457
+ "Update All\uFF08",
458
+ updates?.length ?? 0,
459
+ "\uFF09"
460
+ ] })
461
+ ] });
462
+ const installedToolbar = view === "installed" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-toolbar", children: [
463
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "pc-search", value: search, onChange: (e) => {
464
+ setSearch(e.target.value);
465
+ }, placeholder: "\u641C\u7D22\u5DF2\u5B89\u88C5\u63D2\u4EF6" }),
466
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { className: "pc-select", value: installedSource ?? "", onChange: (e) => {
467
+ setInstalledSource(e.target.value === "" ? null : e.target.value);
468
+ }, children: [
469
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "", children: "\u5168\u90E8\u6765\u6E90" }),
470
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "official", children: "\u5B98\u65B9" }),
471
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "installed", children: "\u7528\u6237\u5B89\u88C5" }),
472
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "local", children: "\u672C\u5730\u5F00\u53D1" }),
473
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "builtin", children: "\u5185\u7F6E" })
474
+ ] }),
475
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: `pc-chip${installedCategory === null ? " active" : ""}`, onClick: () => {
476
+ setInstalledCategory(null);
477
+ }, children: "\u5168\u90E8" }),
478
+ CATEGORIES.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: `pc-chip${installedCategory === c ? " active" : ""}`, onClick: () => {
479
+ setInstalledCategory(c);
480
+ }, children: c }, c))
481
+ ] }) : null;
482
+ const marketToolbar = view === "market" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-toolbar", children: [
483
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "pc-search", value: marketSearch, onChange: (e) => {
484
+ setMarketSearch(e.target.value);
485
+ }, placeholder: "\u641C\u7D22\u793E\u533A\u63D2\u4EF6" }),
486
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { className: "pc-select", value: source, onChange: (e) => {
487
+ setSource(e.target.value);
488
+ setCategory(null);
489
+ }, children: [
490
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "awesome", children: "awesome-dsh-plugin" }),
491
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "oh-my-dsh", children: "Oh-My-DSH" }),
492
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "all", children: "\u5168\u90E8\u6E90" })
493
+ ] }),
494
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: `pc-chip${category === null ? " active" : ""}`, onClick: () => {
495
+ setCategory(null);
496
+ }, children: "\u5168\u90E8" }),
497
+ CATEGORIES.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: `pc-chip${category === c ? " active" : ""}`, onClick: () => {
498
+ setCategory(c);
499
+ }, children: c }, c)),
500
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-spacer" }),
501
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", title: single ? "\u53CC\u5217\u7F51\u683C" : "\u5355\u5217\u5217\u8868", "aria-label": "\u5207\u6362\u5E03\u5C40", className: "pc-iconbtn", onClick: () => {
502
+ setSingle((v) => !v);
503
+ }, children: single ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
504
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "2", y: "2", width: "5", height: "5", rx: "1" }),
505
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "9", y: "2", width: "5", height: "5", rx: "1" }),
506
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "2", y: "9", width: "5", height: "5", rx: "1" }),
507
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "9", y: "9", width: "5", height: "5", rx: "1" })
508
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
509
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "2", y: "2", width: "12", height: "5", rx: "1" }),
510
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "2", y: "9", width: "12", height: "5", rx: "1" })
511
+ ] }) })
512
+ ] }) : null;
513
+ const body = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
514
+ view === "installed" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InstalledView, { search, category: installedCategory, source: installedSource }),
515
+ view === "market" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MarketView, { category, single, source, search: marketSearch, onCount: setMarketCount }),
516
+ view === "updates" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UpdatesView, { updates, refresh: refreshUpdates, updateOne, busy: busyUpdate })
517
+ ] });
518
+ if (variant === "overlay") {
519
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", flex: 1, minHeight: 0 }, children: [
520
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: "none" }, children: [
521
+ head(false),
522
+ tabs,
523
+ installedToolbar,
524
+ marketToolbar
525
+ ] }),
526
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pc-scroll", children: body })
527
+ ] });
528
+ }
529
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%", minHeight: 0 }, children: [
530
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: "none", paddingBottom: "4px" }, children: [
531
+ head(true),
532
+ tabs,
533
+ installedToolbar,
534
+ marketToolbar
535
+ ] }),
536
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pc-scroll", children: body })
537
+ ] });
538
+ }
539
+ function HeaderButton() {
540
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", title: "\u63D2\u4EF6\u4E2D\u5FC3", "aria-label": "\u63D2\u4EF6\u4E2D\u5FC3", className: "pc-headerbtn", onClick: openOverlay, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
541
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "2", y: "2", width: "5", height: "5", rx: "1" }),
542
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "9", y: "2", width: "5", height: "5", rx: "1" }),
543
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "2", y: "9", width: "5", height: "5", rx: "1" }),
544
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "9", y: "9", width: "5", height: "5", rx: "1" })
545
+ ] }) });
546
+ }
547
+ function OverlayPanel() {
548
+ const open = useOverlayOpen();
549
+ if (!open) return null;
550
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pc-overlay", role: "presentation", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-panel", role: "dialog", "aria-modal": "true", "aria-label": "\u63D2\u4EF6\u4E2D\u5FC3", children: [
551
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-panel-head", children: [
552
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-title", children: "\u63D2\u4EF6\u4E2D\u5FC3" }),
553
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-spacer" }),
554
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "pc-close", onClick: closeOverlay, "aria-label": "\u5173\u95ED", children: "\u2715" })
555
+ ] }),
556
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pc-panel-body", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CenterPanel, { variant: "overlay" }) })
557
+ ] }) });
558
+ }
559
+ function Toast() {
560
+ const t = useToast();
561
+ if (t === null) return null;
562
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `pc-toast ${t.kind}`, children: t.message });
563
+ }
564
+ function WhatsNewDialog() {
565
+ const open = useWhatsNewOpen();
566
+ if (!open || whatsNewDigests.length === 0) return null;
567
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pc-overlay", role: "presentation", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-panel", style: { width: "540px" }, role: "dialog", "aria-modal": "true", "aria-label": "\u63D2\u4EF6\u66F4\u65B0", children: [
568
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-panel-head", children: [
569
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-title", children: "\u63D2\u4EF6\u66F4\u65B0" }),
570
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "pc-sub", style: { marginTop: 0 }, children: [
571
+ whatsNewDigests.length,
572
+ " \u4E2A\u63D2\u4EF6\u6709\u65B0\u7248\u672C"
573
+ ] }),
574
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-spacer" }),
575
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "pc-close", onClick: closeWhatsNew, "aria-label": "\u5173\u95ED", children: "\u2715" })
576
+ ] }),
577
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-panel-body", style: { overflow: "auto" }, children: [
578
+ whatsNewDigests.map((u) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-wn-item", children: [
579
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-row", children: [
580
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-name", children: u.name }),
581
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-ver", children: u.fromVersion }),
582
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-ver", children: "\u2192" }),
583
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--dsw-alias-state-business-primary)", fontWeight: 500 }, children: u.toVersion })
584
+ ] }),
585
+ u.changelog.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "pc-wn-list", children: u.changelog.slice(0, 5).map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: line }, i)) })
586
+ ] }, u.name)),
587
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", justifyContent: "flex-end", gap: "8px", marginTop: "16px" }, children: [
588
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "pc-btn", onClick: closeWhatsNew, children: "\u7A0D\u540E" }),
589
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "pc-btn primary", onClick: closeWhatsNew, children: "\u5168\u90E8\u6807\u8BB0\u5DF2\u8BFB" })
590
+ ] })
591
+ ] })
592
+ ] }) });
593
+ }
594
+ var inject = ["slots", "connection"];
595
+ function apply(ctx) {
596
+ injectCss();
597
+ rpc = async (endpoint, payload = {}) => {
598
+ const result = await ctx.connection.rpc.call("/plugin-center", endpoint, payload);
599
+ if (result.ok) return result.value;
600
+ throw new Error(result.error?.message ?? `plugin-center: ${endpoint} failed`);
601
+ };
602
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
603
+ name: "settings.section",
604
+ id: "plugin-center",
605
+ order: 50,
606
+ label: () => "\u63D2\u4EF6\u4E2D\u5FC3"
607
+ }, CenterPanel));
608
+ ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
609
+ name: "conversation.session.header.utilities",
610
+ id: "plugin-center",
611
+ order: 50
612
+ }, HeaderButton));
613
+ ctx.slots.inject("shell.overlay", () => ctx.slots.register({
614
+ name: "shell.overlay",
615
+ id: "plugin-center-panel",
616
+ order: 50
617
+ }, OverlayPanel));
618
+ ctx.slots.inject("shell.overlay", () => ctx.slots.register({
619
+ name: "shell.overlay",
620
+ id: "plugin-center-whats-new",
621
+ order: 51
622
+ }, WhatsNewDialog));
623
+ ctx.slots.inject("shell.overlay", () => ctx.slots.register({
624
+ name: "shell.overlay",
625
+ id: "plugin-center-toast",
626
+ order: 52
627
+ }, Toast));
628
+ void checkWhatNew();
629
+ }
630
+ return module.exports;
631
+ },
632
+ });
633
+
@@ -0,0 +1,7 @@
1
+ # dsh-plugin-center bundle patch: one insert over the profile root.
2
+ # `loader`, `api-gateway`, and the client roster already live in the host; this
3
+ # adds only the plugin-center host half. The browser half is picked up through
4
+ # the package's dsh.client declaration, like the shipped ui-* packages.
5
+ - insert:
6
+ - id: plugin-center
7
+ name: '@max-null/dsh-plugin-center'