@zaimokuza/dsh-plugin-hub 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -30,7 +30,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/client/index.jsx
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- Market: () => Market,
34
33
  apply: () => apply,
35
34
  inject: () => inject,
36
35
  name: () => name
@@ -41,460 +40,524 @@ module.exports = __toCommonJS(index_exports);
41
40
  var define_HUB_BRAND_default = { title: "Plugin Hub", subTitle: "DSH EXTENSIONS", primaryColor: "#596579", navTitle: "Plugin Hub" };
42
41
 
43
42
  // src/client/index.jsx
43
+ var import_react2 = __toESM(require("react"), 1);
44
+
45
+ // src/client/resources.jsx
44
46
  var import_react = __toESM(require("react"), 1);
45
47
  var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
46
48
 
47
- // src/client/api.js
48
- var RequestError = class extends Error {
49
- constructor(key, detail = "") {
50
- super(key);
51
- this.detail = detail;
52
- }
53
- };
54
- async function request(path, data, { signal, fetcher = fetch, base = "/dsh-plugin-hub/hub/api/" } = {}) {
55
- let response;
56
- try {
57
- response = await fetcher(base + path, {
58
- signal: signal ? AbortSignal.any([signal, AbortSignal.timeout(2e4)]) : AbortSignal.timeout(2e4),
59
- ...data === void 0 ? {} : { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(data) }
60
- });
61
- } catch (error) {
62
- if (signal?.aborted) throw error;
63
- throw new RequestError(error.name === "TimeoutError" ? "\u8BF7\u6C42\u8D85\u65F6\uFF0C\u6B63\u5728\u7B49\u5F85 DSH \u54CD\u5E94\u3002" : "\u8FDE\u63A5\u5DF2\u65AD\u5F00\uFF0C\u8BF7\u786E\u8BA4\u672C\u5730 DSH \u5B9E\u4F8B\u6B63\u5728\u8FD0\u884C\u3002\u6062\u590D\u540E\u9875\u9762\u4F1A\u81EA\u52A8\u91CD\u8FDE\u3002");
64
- }
65
- if (response.status === 401) throw new RequestError("\u8BF7\u5148\u767B\u5F55\u5F53\u524D DSH \u5B9E\u4F8B");
66
- let value;
67
- try {
68
- value = await response.json();
69
- } catch {
70
- throw new RequestError("\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6548\u54CD\u5E94\uFF0C\u8BF7\u5237\u65B0 DSH \u9875\u9762\u3002");
71
- }
72
- if (!response.ok) throw new RequestError(value.error ?? `HTTP ${response.status}`);
73
- return value;
74
- }
49
+ // src/client/resources.css
50
+ var resources_default = `/* Reuse marketplace layout and DSH controls; only adapt the main-panel container. */
51
+ .hub-resource-page { box-sizing: border-box; width: 100%; height: 100%; overflow: auto; padding: 32px 40px; color: var(--dsw-alias-label-primary); font: 14px/22px var(--dsw-font-family); }
52
+ .hub-resource-content { max-width: 1080px; margin: 0 auto; }
53
+ .hub-resource-profile { display: flex; align-items: center; gap: 12px; padding: 14px 0; margin-bottom: 18px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
54
+ .hub-resource-profile > :first-child { flex-shrink: 0; }
55
+ .hub-resource-profile .hub-resource-path { margin: 0; }
56
+ .hub-resource-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
57
+ .hub-resource-grid { align-items: stretch; }
58
+ .hub-resource-card-name { min-width: 0; margin: 0; font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: normal; overflow-wrap: anywhere; }
59
+ .hub-resource-path { color: var(--dsw-alias-label-tertiary); font-size: 11px; line-height: 1.7; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
60
+ .hub-resource-meta { color: var(--dsw-alias-label-secondary); font-size: 11px; line-height: 1.7; }
61
+ .hub-resource-card-footer { margin-top: auto; padding-top: 12px; }
62
+ .hub-resource-page .hub-resource-card-footer .hub-resource-source { margin: 18px 0 0; padding-top: 12px; border-top: 1px solid var(--line); font-size: 11px; line-height: 18px; }
63
+ .hub-resource-empty { text-align: center; padding: 48px 16px; color: var(--dsw-alias-label-secondary); }
64
+ .hub-resource-form { display: grid; align-content: start; min-width: 0; width: 100%; gap: 12px; }
65
+ .hub-resource-field { display: grid; gap: 6px; min-width: 0; }
66
+ @container (max-width: 600px) { .hub-resource-profile { align-items: flex-start; flex-direction: column; gap: 6px; } .hub-resource-profile .hub-resource-path { max-width: 100%; } .hub-resource-scope-note { display: none; } }
67
+ @media (max-width: 800px) { .hub-resource-page { padding: 24px; } }
68
+ @media (max-width: 600px) { .hub-resource-page { padding: 16px; } }
69
+ /* Native Modal portals do not inherit panel typography. */
70
+ .hub-resource-dialog { box-sizing: border-box; font: 14px/22px var(--dsw-font-family); color: var(--dsw-alias-label-primary); max-height: calc(100dvh - 48px); }
71
+ .hub-resource-dialog *, .hub-resource-dialog *::before, .hub-resource-dialog *::after { box-sizing: border-box; }
72
+ .hub-resource-dialog-scroll { overflow: auto; min-height: 0; }
73
+ .hub-resource-editor-dialog { width: min(680px, 100%); }
74
+ .hub-resource-editor-note { color: var(--dsw-alias-label-secondary); margin: 0; font-size: 12px; line-height: 1.7; }
75
+ /* No editable code primitive is exported by DSH; use its code-font and input tokens. */
76
+ .hub-resource-code { display: block; width: 100%; min-width: 0; height: clamp(180px, 38vh, 360px); resize: vertical; padding: 12px; border: 1px solid var(--dsw-alias-border-l3); border-radius: 8px; background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-primary); font: 13px/1.6 var(--ds-font-family-code); tab-size: 2; }
77
+ .hub-resource-code:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }
78
+ .hub-resource-card-heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 28px; }
79
+ .hub-resource-card-heading > :last-child { flex-shrink: 0; }
80
+ .hub-resource-tab[aria-selected="true"], .hub-resource-tab[aria-pressed="true"] { background: var(--dsw-alias-interactive-bg-active); }
81
+ /* The sidebar exports a slot, not its Settings trigger; match that trigger's geometry. */
82
+ .hub-sidebar-button { box-sizing: border-box; flex: 1; min-width: 0; height: 42px; margin: 4px -2px; padding: 0 10px 0 8px; gap: 8px; justify-content: flex-start; border-radius: 12px; font-family: var(--dsw-font-family); }
83
+ .hub-sidebar-button[aria-pressed="true"] { background: var(--dsw-alias-interactive-bg-active); }
84
+ .hub-sidebar-button > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
85
+ .hub-sidebar-button.is-rail { flex: none; width: 36px; height: 36px; margin: 8px 0 10px; padding: 0; justify-content: center; border-radius: 50%; }
75
86
 
76
- // src/client/scope.js
77
- function inScope(plugin, scope) {
78
- if (scope === "all") return true;
79
- if (scope === "installed") return Boolean(plugin.installedVersion);
80
- return scope.startsWith("source:") && (plugin.catalogSourceIds ?? [plugin.catalogSource?.id]).includes(scope.slice(7));
81
- }
82
- function resolveScope(scope, sources) {
83
- return scope === "all" || scope === "installed" || sources.some((source) => scope === "source:" + source.id) ? scope : "all";
84
- }
87
+ .hub-resource-page .hub-search-input input::placeholder { color: var(--dsw-alias-label-tertiary); opacity: 1; }
88
+ /* Typography matches DSH's 14px controls; secondary metadata uses 12px. */
89
+ .hub-resource-page .hub-market { font: inherit; }
90
+ .hub-resource-page .hub-description { font-size: 14px; line-height: 22px; }
91
+ .hub-resource-page .hub-resource-path, .hub-resource-page .hub-results { font-size: 12px; line-height: 20px; }
92
+ .hub-resource-page .hub-search-input { height: 36px; }
93
+ .hub-resource-identity { display: flex; align-items: center; gap: 10px; min-width: 0; }
94
+ .hub-item-icon { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 32px; width: 32px; height: 32px; border-radius: 8px; background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-secondary); font-size: 14px; font-weight: 600; overflow: hidden; }
95
+ .hub-item-icon img { width: 100%; height: 100%; object-fit: contain; }
96
+ .hub-resource-version { font: 12px/20px var(--ds-font-family-code); display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; color: var(--dsw-alias-label-tertiary); font-weight: 400; margin-left: 4px; }
97
+ .hub-resource-card-heading > .hub-resource-identity { flex-shrink: 1; }
98
+ .hub-resource-editor-dialog.with-help { width: min(1100px, 100%); }
99
+ .hub-editor-columns { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; align-items: start; }
100
+ .with-help .hub-editor-columns { grid-template-columns: minmax(0, 1fr) minmax(260px, .8fr); }
101
+ .hub-editor-help { border-left: 1px solid var(--dsw-alias-border-l4); padding-left: 20px; max-height: min(600px, 65dvh); overflow: auto; min-width: 0; }
102
+ .hub-editor-help h3 { font: inherit; font-weight: 600; margin: 0 0 12px; }
103
+ .hub-editor-help p, .hub-editor-help dd { font-size: 12px; line-height: 20px; color: var(--dsw-alias-label-secondary); }
104
+ .hub-editor-help dl { margin: 0; }
105
+ .hub-editor-help dt { overflow-wrap: anywhere; }
106
+ .hub-editor-help dd { margin: 4px 0 16px; }
107
+ .hub-editor-help dd span { display: block; }
108
+ .hub-resource-editor-note code { overflow-wrap: anywhere; }
109
+ .hub-resource-page.with-file { display: grid; grid-template-columns: minmax(0, 1fr) minmax(320px, 40%); gap: 24px; align-items: start; }
110
+ .hub-skill-view { min-width: 0; border-left: 1px solid var(--dsw-alias-border-l4); padding-left: 20px; overflow: auto; }
111
+ .hub-skill-view h2 { font: inherit; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
112
+ @media (max-width: 850px) { .with-help .hub-editor-columns, .hub-resource-page.with-file { grid-template-columns: minmax(0, 1fr); } .hub-editor-help, .hub-skill-view { border-left: 0; border-top: 1px solid var(--dsw-alias-border-l4); padding: 16px 0 0; } }
113
+ @container (max-width: 680px) { .hub-resource-grid { grid-template-columns: minmax(0, 1fr); } }
114
+ .hub-skill-markdown { min-width: 0; padding: 10px 12px; white-space: normal; }
85
115
 
86
- // src/client/locale.js
87
- var pairs = [
88
- ["\u51B7\u9759\u671F\uFF1A{minutes} \u5206\u949F \xB7 {source}", "Release age: {minutes} minutes \xB7 {source}"],
89
- ["\u672C\u673A pnpm \u914D\u7F6E", "Local pnpm configuration"],
90
- ["\u9ED8\u8BA4 48 \u5C0F\u65F6", "Default 48 hours"],
91
- ["\u672A\u6EE1 {minutes} \u5206\u949F", "Under {minutes} minutes"],
92
- ["\u9884\u8BA1\u6EE1 {minutes} \u5206\u949F\uFF1A{date}", "Eligible after {minutes} minutes: {date}"],
93
- ["\u4E0D\u6309\u7248\u672C\u9650\u5236\uFF0C\u8FD0\u884C\u65F6\u68C0\u67E5\u63A5\u53E3", "No version gate; runtime API checks"],
94
- ["\u76EE\u5F55\u683C\u5F0F\u4E0D\u53D7\u652F\u6301\uFF1A\u9700\u8981 schemaVersion: 1 \u548C plugins \u6570\u7EC4", "Unsupported catalog: expected schemaVersion: 1 and a plugins array"],
95
- ["\u76EE\u5F55\u6700\u591A\u652F\u6301 25000 \u4E2A\u63D2\u4EF6", "A catalog supports at most 25000 plugins"],
96
- ["\u63D2\u4EF6\u8BB0\u5F55\u5FC5\u987B\u4E3A\u5BF9\u8C61", "Plugin entry must be an object"],
97
- ["npm \u5305\u540D\u65E0\u6548", "Invalid npm package name"],
98
- ["npm \u5305\u540D\u91CD\u590D", "Duplicate npm package name"],
99
- ["\u76EE\u5F55\u5305 plugins.json \u91CD\u590D\u6216\u8FC7\u5927", "Catalog plugins.json is duplicated or too large"],
100
- ["\u76EE\u5F55\u8FC7\u5927", "Catalog is too large"],
101
- ["\u76EE\u5F55\u5305\u7F3A\u5C11 plugins.json", "Catalog package is missing plugins.json"],
102
- ["\u4ED3\u5E93\u8BF7\u6C42\u5730\u5740\u4E0D\u5C5E\u4E8E\u914D\u7F6E\u7684 Nexus", "Registry request does not belong to the configured Nexus"],
103
- ["Invalid release request", "Invalid release request", "\u65E0\u6548\u7684\u7248\u672C\u67E5\u8BE2\u8BF7\u6C42"],
104
- ["Invalid catalog source id", "Invalid catalog source ID", "\u65E0\u6548\u7684\u6570\u636E\u6E90 ID"],
105
- ["Invalid catalog package name", "Invalid catalog package name", "\u65E0\u6548\u7684\u76EE\u5F55\u6570\u636E\u5305\u540D"],
106
- ["At most 20 catalog sources are supported", "At most 20 catalog sources are supported", "\u6700\u591A\u652F\u6301 20 \u4E2A\u6570\u636E\u6E90"],
107
- ["Catalog source kind must be npm or json", "Catalog source kind must be npm or json", "\u6570\u636E\u6E90\u7C7B\u578B\u5FC5\u987B\u662F npm \u6216 json"],
108
- ["JSON source requires getCatalog({ signal })", "JSON source requires getCatalog({ signal })", "JSON \u6570\u636E\u6E90\u9700\u8981 getCatalog({ signal })"],
109
- ["Source priority must be an integer between -1000 and 1000", "Source priority must be an integer between -1000 and 1000", "\u6570\u636E\u6E90\u4F18\u5148\u7EA7\u5FC5\u987B\u4E3A -1000 \u5230 1000 \u7684\u6574\u6570"],
110
- ["Invalid source displayName", "Invalid source displayName", "\u65E0\u6548\u7684\u6570\u636E\u6E90\u663E\u793A\u540D\u79F0"],
111
- ["Invalid source cacheVersion", "Invalid source cacheVersion", "\u65E0\u6548\u7684\u6570\u636E\u6E90\u7F13\u5B58\u7248\u672C"],
112
- ["\u517C\u5BB9\u58F0\u660E\u5B58\u5728\u51B2\u7A81\uFF0C\u9700\u8981\u7EF4\u62A4\u8005\u786E\u8BA4", "Compatibility declarations conflict; the maintainer must clarify"],
113
- ["\u58F0\u660E\u4E0D\u652F\u6301\u5F53\u524D DSH profile", "This DSH profile is not covered by the declaration"],
114
- ["\u4F5C\u8005\u9010\u7248\u672C\u58F0\u660E", "Author release declaration"],
115
- ["\u4E0D\u652F\u6301\u7684\u8BF7\u6C42\u65B9\u6CD5", "Unsupported request method"],
116
- ["\u63A5\u53E3\u4E0D\u5B58\u5728", "Endpoint not found"],
117
- ["\u8BF7\u6C42\u8FC7\u5927", "Request body is too large"],
118
- ["\u76EE\u5F55 npm \u5305\u7F3A\u5C11\u6709\u6548\u7684 integrity \u6216 shasum\uFF0C\u65E0\u6CD5\u6821\u9A8C", "Catalog package has no valid integrity or shasum for verification"],
119
- ["\u76EE\u5F55 npm \u5305\u5B8C\u6574\u6027\u6821\u9A8C\u5931\u8D25", "Catalog package integrity check failed"],
120
- ["\u76EE\u5F55\u6765\u6E90\u5FC5\u987B\u662F npm \u6570\u636E\u5305", "Catalog source must be an npm data package"],
121
- ["\u76EE\u5F55 npm \u5305\u6CA1\u6709\u53EF\u4E0B\u8F7D\u7684 latest \u7248\u672C", "Catalog package has no downloadable latest release"],
122
- ["\u76EE\u5F55 tarball \u5730\u5740\u4E0D\u5C5E\u4E8E\u914D\u7F6E\u7684\u4ED3\u5E93", "Catalog tarball does not belong to the configured registry"],
123
- ["\u63D2\u4EF6\u547D\u4EE4\u5931\u8D25", "Plugin command failed"],
124
- ["\u5B89\u88C5\u547D\u4EE4\u7ED3\u675F\uFF0C\u4F46\u5B9E\u9645\u7248\u672C\u4E0D\u5339\u914D", "Installation finished but the installed version does not match"],
125
- ["\u5305\u5DF2\u4E0B\u8F7D\uFF0C\u4F46\u5C1A\u672A\u6CE8\u518C\u4E3A DSH bundle", "Package downloaded but not registered as a DSH bundle"],
126
- ["\u5378\u8F7D\u547D\u4EE4\u7ED3\u675F\uFF0C\u4F46\u63D2\u4EF6\u4ECD\u5728 profile \u4E2D", "Uninstall finished but the plugin is still in the profile"],
127
- ["\u63D2\u4EF6\u64CD\u4F5C\u8D85\u65F6\uFF0C\u8BF7\u68C0\u67E5 profile \u540E\u91CD\u8BD5", "Plugin operation timed out; check the profile and retry"],
128
- ["\u6765\u6E90\u672A\u6838\u5B9E", "Source unverified"],
129
- ["\u5BBF\u4E3B\u4F9D\u8D56\u58F0\u660E", "Host peer declarations"],
130
- ["\u517C\u5BB9\u4F9D\u636E\uFF1A{basis}", "Compatibility evidence: {basis}"],
131
- ["\u5DF2\u786E\u8BA4\u53EF\u5B89\u88C5", "Confirmed installable"],
132
- ["\u5F53\u524D npm \u4ED3\u5E93\u672A\u627E\u5230\u6B64\u5305\uFF08404\uFF09", "Package not found in this npm registry (404)"],
133
- ["\u5F53\u524D\u4ED3\u5E93\u672A\u627E\u5230", "Not found in this registry"],
134
- ["\u6765\u6E90\u4E0D\u5339\u914D", "Source mismatch"],
135
- ["npm \u5305\u672A\u58F0\u660E\u53EF\u6838\u5BF9\u7684 GitHub \u6765\u6E90", "The npm package does not declare a verifiable GitHub repository"],
136
- ["npm \u5305\u5BF9\u5E94\u7684 GitHub \u4ED3\u5E93\u4E0E\u76EE\u5F55\u4E0D\u4E00\u81F4", "The npm package points to a different GitHub repository"],
137
- ["\u8BE5\u7248\u672C\u7684 npm \u6765\u6E90\u65E0\u6CD5\u4E0E\u76EE\u5F55\u4ED3\u5E93\u6838\u5BF9", "This npm version cannot be matched to the catalog repository"],
138
- ["\u6B63\u5728\u67E5\u8BE2\u7248\u672C", "Loading releases"],
139
- ["\u52A0\u8F7D\u66F4\u591A", "Load more"],
140
- ["\u5DF2\u67E5\u8BE2 {done} / {total} \u4E2A\u63D2\u4EF6\u7684\u7248\u672C", "Loaded releases for {done} / {total} plugins"],
141
- ["\u63D2\u4EF6\u76EE\u5F55", "Plugin directory"],
142
- ["\u6570\u636E\u6E90", "Data sources"],
143
- ["\u5173\u95ED\u6570\u636E\u6E90", "Close data sources"],
144
- ["\u6765\u6E90", "Source"],
145
- ["Company catalog", "Company catalog", "\u516C\u53F8\u76EE\u5F55"],
146
- ["Demo catalog", "Demo catalog", "\u6F14\u793A\u76EE\u5F55"],
147
- ["Team handbook", "Team handbook", "\u56E2\u961F\u624B\u518C\u76EE\u5F55"],
148
- ["npm \u6570\u636E\u5305", "npm data package"],
149
- ["\u6269\u5C55\u63D2\u4EF6 JSON", "Provider plugin JSON"],
150
- ["\u5DF2\u52A0\u8F7D", "Loaded"],
151
- ["\u4F7F\u7528\u7F13\u5B58", "Using cache"],
152
- ["\u76EE\u5F55\u6765\u6E90\u8BFB\u53D6\u8D85\u65F6", "Catalog source timed out"],
153
- ["\u76EE\u5F55\u6765\u6E90\u8BFB\u53D6\u5DF2\u53D6\u6D88", "Catalog source read cancelled"],
154
- ["\u4F18\u5148\u7EA7 {priority} \xB7 {count} \u4E2A\u63D2\u4EF6", "Priority {priority} \xB7 {count} plugins"],
155
- ["\u5DF2\u5408\u5E76 {count} \u6761\u91CD\u590D\u8BB0\u5F55", "Merged {count} duplicate entries"],
156
- ["\u540C\u540D\u63D2\u4EF6\u6309\u6765\u6E90\u4F18\u5148\u7EA7\u4FDD\u7559\u4E00\u6761\uFF1B\u4F18\u5148\u7EA7\u76F8\u540C\u65F6\u6309\u6765\u6E90 ID \u6392\u5E8F\u3002", "Duplicate package names use the highest-priority source; equal priorities are ordered by source ID."],
157
- ["\u4ECB\u7ECD\u6587\u6863", "Documentation"],
158
- ["\u6A21\u62DF\u5378\u8F7D", "Simulate uninstall"],
159
- ["\u5378\u8F7D\u63D2\u4EF6", "Uninstall plugin"],
160
- ["\u6B63\u5728\u5378\u8F7D\u2026", "Uninstalling\u2026"],
161
- ["\u5378\u8F7D\u4E2D", "Uninstalling"],
162
- ["\u5378\u8F7D\u5931\u8D25", "Uninstall failed"],
163
- ["\u5378\u8F7D", "Uninstall"],
164
- ["\u5B89\u88C5", "Install"],
165
- ["\u6A21\u62DF\u64CD\u4F5C\u5DF2\u5B8C\u6210", "Simulated operations finished"],
166
- ["\u63D2\u4EF6\u64CD\u4F5C\u5DF2\u5B8C\u6210", "Plugin operations finished"],
167
- ["{count} \u4E2A\u63D2\u4EF6\u64CD\u4F5C\u6B63\u5728\u6267\u884C", "{count} plugin operations in progress"],
168
- ["\u8BE5\u63D2\u4EF6\u5C1A\u672A\u5B89\u88C5", "This plugin is not installed"],
169
- ["\u8BE5\u63D2\u4EF6\u5DF2\u6709\u5176\u5B83\u64CD\u4F5C\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210", "Wait for the other operation on this plugin to finish"],
170
- ["\u8BF7\u901A\u8FC7 DSH CLI \u7BA1\u7406\u5E02\u573A\u63D2\u4EF6\u81EA\u8EAB", "Manage the marketplace itself through the DSH CLI"],
171
- ["\u65E0\u6548\u7684\u63D2\u4EF6\u64CD\u4F5C", "Invalid plugin operation"],
172
- ["nav", "Plugin Hub", "Plugin Hub"],
173
- ["\u63D2\u4EF6\u5E02\u573A", "Marketplace"],
174
- ["\u3002", "."],
175
- ["\u627E\u5230\u9002\u5408\u5F53\u524D DSH \u7684\u5DE5\u5177\u3002", "Find the right tools for your current DSH."],
176
- ["\u6536\u5F55\u63D2\u4EF6", "Plugins"],
177
- ["\u6709\u53EF\u5B89\u88C5\u7248\u672C", "Installable"],
178
- ["\u4F7F\u7528\u4E0E\u6545\u969C\u6392\u67E5", "Help & troubleshooting"],
179
- ["\u672C\u5730\u6F14\u793A", "Local demo"],
180
- ["Nexus npm \u8BF7\u6C42\u5DF2\u62E6\u622A\uFF0C\u76EE\u5F55\u5305\u3001\u7248\u672C\u4E0E\u5B89\u88C5\u7ED3\u679C\u5747\u4E3A\u6A21\u62DF\u3002", "Nexus npm requests are mocked, including the catalog package, versions and installs."],
181
- ["\u5207\u6362\u573A\u666F", "Demo scenarios"],
182
- ["\u6B63\u5E38\u76EE\u5F55", "Normal catalog"],
183
- ["\u65B0\u63D2\u4EF6\u767B\u8BB0", "New plugin registered"],
184
- ["\u76EE\u5F55\u683C\u5F0F\u635F\u574F", "Invalid catalog JSON"],
185
- ["\u76EE\u5F55\u6E90\u4E0D\u53EF\u7528", "Catalog unavailable"],
186
- ["\u67E5\u770B\u62E6\u622A\u8BF7\u6C42", "View intercepted requests"],
187
- ["\u91CD\u7F6E\u6A21\u62DF\u5B89\u88C5", "Reset simulated installs"],
188
- ["\u76EE\u5F55\u66F4\u65B0\u5931\u8D25\uFF0C\u7EE7\u7EED\u4F7F\u7528\u4E0A\u4E00\u4EFD\u6709\u6548\u6570\u636E", "Catalog update failed. Using the last valid catalog."],
189
- ["\u76EE\u5F55\u6682\u4E0D\u53EF\u7528", "Catalog is currently unavailable"],
190
- ["\u91CD\u8BD5", "Retry"],
191
- ["\u5173\u95ED\u9519\u8BEF", "Dismiss error"],
192
- ["\u5173\u95ED\u8BF7\u6C42\u8BB0\u5F55", "Close request log"],
193
- ["\u8BF7\u6C42\u62E6\u622A\u8BB0\u5F55", "Intercepted requests"],
194
- ["\u72EC\u7ACB MockAgent \u8FD4\u56DE npm \u5143\u6570\u636E\u548C\u76EE\u5F55\u538B\u7F29\u5305\uFF0C\u4E0D\u8FDE\u63A5\u771F\u5B9E Nexus\u3002", "An isolated MockAgent returns npm metadata and catalog tarballs without contacting a real Nexus."],
195
- ["\u63D2\u4EF6\u8303\u56F4", "Plugin scope"],
196
- ["\u5168\u90E8\u63D2\u4EF6", "All plugins"],
197
- ["\u5185\u90E8\u63D2\u4EF6", "Internal"],
198
- ["\u793E\u533A\u7CBE\u9009", "Community"],
199
- ["\u5DF2\u5B89\u88C5", "Installed"],
200
- ["\u641C\u7D22\u63D2\u4EF6", "Search plugins"],
201
- ["\u641C\u7D22\u63D2\u4EF6\u3001\u7528\u9014\u6216\u7EF4\u62A4\u56E2\u961F", "Search plugins, purpose or owner"],
202
- ["\u6E05\u7A7A\u641C\u7D22", "Clear search"],
203
- ["\u6309\u6807\u7B7E\u7B5B\u9009", "Filter by tag"],
204
- ["\u6240\u6709\u6807\u7B7E", "All tags"],
205
- ["\u5237\u65B0", "Refresh"],
206
- ["\u5237\u65B0\u76EE\u5F55\u4E0E\u7248\u672C", "Refresh catalog and versions"],
207
- ["\u201C{query}\u201D \u7684\u641C\u7D22\u7ED3\u679C", "Results for \u201C{query}\u201D"],
208
- ["\u4F60\u7684\u5DE5\u4F5C\u5DE5\u5177", "Your tools"],
209
- ["\u4E3A\u56E2\u961F\u7CBE\u9009", "Curated tools"],
210
- ["\u7248\u672C\u4FE1\u606F\u6765\u81EA npm \xB7 \u6309\u5F53\u524D DSH \u68C0\u67E5\u58F0\u660E", "npm versions \xB7 checked against this DSH"],
211
- ["\u5185\u90E8", "Internal"],
212
- ["\u7CBE\u9009", "Curated"],
213
- ["\u9009\u62E9\u7248\u672C", "Version"],
214
- ["{name}\u7248\u672C", "{name} version"],
215
- ["\u6682\u4E0D\u53EF\u7528", "Unavailable"],
216
- ["\u63A8\u8350", "Recommended"],
217
- ["\u53D1\u5E03\u4E8E {date}", "Published {date}"],
218
- ["\u6CA1\u6709\u53EF\u7528\u7248\u672C", "No releases available"],
219
- ["\u6392\u67E5\u6307\u5357", "Troubleshooting"],
220
- ["\u67E5\u8BE2\u5931\u8D25", "Query failed"],
221
- ["\u517C\u5BB9\u6027\u672A\u77E5", "Compatibility unknown"],
222
- ["\u7248\u672C\u4E0D\u517C\u5BB9", "Incompatible"],
223
- ["\u672A\u6EE1 {hours} \u5C0F\u65F6", "Under {hours} hours"],
224
- ["\u53D1\u5E03\u65F6\u95F4\u672A\u77E5", "Release date unknown"],
225
- ["\u7B26\u5408\u5B89\u88C5\u6761\u4EF6", "Eligible to install"],
226
- ["\u6682\u4E0D\u53EF\u5B89\u88C5", "Not installable"],
227
- ["\u5DF2\u52A0\u5165\u961F\u5217", "Queued"],
228
- ["\u6B63\u5728\u5B89\u88C5\u2026", "Installing\u2026"],
229
- ["\u6F14\u793A\u5DF2\u5B89\u88C5", "Demo installed"],
230
- ["\u6A21\u62DF\u5B89\u88C5", "Simulate install"],
231
- ["\u5B89\u88C5\u63D2\u4EF6", "Install plugin"],
232
- ["\u6B63\u5728\u8BFB\u53D6\u63D2\u4EF6\u76EE\u5F55\u2026", "Loading plugin catalog\u2026"],
233
- ["\u91CD\u65B0\u83B7\u53D6", "Try again"],
234
- ["\u65F6\u95F4\u672A\u77E5", "Unknown time"],
235
- ["\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u63D2\u4EF6", "No matching plugins"],
236
- ["\u8BD5\u8BD5\u5176\u5B83\u5173\u952E\u8BCD\uFF0C\u6216\u6E05\u9664\u5F53\u524D\u7B5B\u9009\u6761\u4EF6\u3002", "Try another keyword or clear your filters."],
237
- ["\u67E5\u770B\u5168\u90E8\u63D2\u4EF6", "View all plugins"],
238
- ["\u672A\u52A0\u8F7D", "Not loaded"],
239
- ["\u76EE\u5F55 {version} \xB7 \u66F4\u65B0\u4E8E {date}", "Catalog {version} \xB7 updated {date}"],
240
- ["\u5E02\u573A v{version}", "Marketplace v{version}"],
241
- ["\u201C\u7B26\u5408\u5B89\u88C5\u6761\u4EF6\u201D\u4F9D\u636E\u7248\u672C\u58F0\u660E\u4E0E\u53D1\u5E03\u65F6\u95F4\uFF0C\u5B9E\u9645\u4E0B\u8F7D\u4ECD\u4EE5 Nexus \u4E3A\u51C6\u3002", "Eligibility is based on version declarations and release dates. Nexus determines actual download availability."],
242
- ["\u672C\u9875\u5305\u542B\u6A21\u62DF\u7248\u672C\u58F0\u660E\uFF0C\u4E0D\u4EE3\u8868\u8FD9\u4E9B\u63D2\u4EF6\u7684\u771F\u5B9E\u517C\u5BB9\u8303\u56F4\u3002", "Version declarations on this page are simulated and do not represent actual plugin compatibility."],
243
- ["{count} \u4E2A\u63D2\u4EF6\u6B63\u5728\u6392\u961F\u6216\u5B89\u88C5", "{count} plugins queued or installing"],
244
- ["\u6A21\u62DF\u5B89\u88C5\u5DF2\u5B8C\u6210", "Simulated installs finished"],
245
- ["\u5B89\u88C5\u4EFB\u52A1\u5DF2\u5B8C\u6210", "Install tasks finished"],
246
- ["{count} \u9879\u6A21\u62DF\u5B8C\u6210 \xB7 \u4E0D\u4FEE\u6539\u771F\u5B9E\u63D2\u4EF6", "{count} simulated operations completed \xB7 no real plugins changed"],
247
- ["{count} \u9879\u5F85\u624B\u52A8\u91CD\u542F\u751F\u6548", "{count} installs awaiting a manual restart"],
248
- ["\u6536\u8D77", "Collapse"],
249
- ["\u67E5\u770B\u4EFB\u52A1", "View tasks"],
250
- ["\u6392\u961F\u4E2D", "Queued"],
251
- ["\u5B89\u88C5\u4E2D", "Installing"],
252
- ["\u6A21\u62DF\u5B8C\u6210", "Simulated"],
253
- ["\u5F85\u91CD\u542F", "Restart required"],
254
- ["\u5B89\u88C5\u5931\u8D25", "Install failed"],
255
- ["\u5173\u95ED\u8BE6\u60C5", "Close details"],
256
- ["\u7EF4\u62A4\u56E2\u961F", "Maintainer"],
257
- ["\u5F53\u524D\u5BBF\u4E3B", "Current host"],
258
- ["\u53D1\u884C\u7248\u672C", "Releases"],
259
- ["\u53D1\u5E03\u65F6\u95F4 {date} \xB7 DSH {range}", "Published {date} \xB7 DSH {range}"],
260
- ["\u672A\u58F0\u660E", "Not declared"],
261
- ["\u9884\u8BA1\u6EE1 {hours} \u5C0F\u65F6\uFF1A{date}", "Eligible after {hours} hours: {date}"],
262
- ["\u6253\u5F00 troubleshooting", "Open troubleshooting"],
263
- ["Agent \u63A5\u5165", "Agent access"],
264
- ["\u5F00\u53D1\u5DE5\u5177", "Developer tools"],
265
- ["\u77E5\u8BC6\u6587\u6863", "Knowledge"],
266
- ["\u6548\u7387\u5DE5\u5177", "Productivity"],
267
- ["\u7CFB\u7EDF\u96C6\u6210", "Integrations"],
268
- ["\u754C\u9762", "Interface"],
269
- ["\u8FDE\u63A5\u5DF2\u65AD\u5F00\uFF0C\u8BF7\u786E\u8BA4\u672C\u5730 DSH \u5B9E\u4F8B\u6B63\u5728\u8FD0\u884C\u3002\u6062\u590D\u540E\u9875\u9762\u4F1A\u81EA\u52A8\u91CD\u8FDE\u3002", "Disconnected. Check that the local DSH instance is running. This page will reconnect automatically."],
270
- ["\u8BF7\u6C42\u8D85\u65F6\uFF0C\u6B63\u5728\u7B49\u5F85 DSH \u54CD\u5E94\u3002", "Request timed out while waiting for DSH."],
271
- ["\u8BF7\u5148\u767B\u5F55\u5F53\u524D DSH \u5B9E\u4F8B", "Please authenticate with this DSH instance"],
272
- ["\u8BF7\u6C42\u6765\u6E90\u4E0D\u5339\u914D", "Request origin does not match this DSH instance"],
273
- ["\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6548\u54CD\u5E94\uFF0C\u8BF7\u5237\u65B0 DSH \u9875\u9762\u3002", "The server returned an invalid response. Reload the DSH page."],
274
- ["\u672A\u63D0\u4F9B\u6709\u6548\u7684 DSH \u517C\u5BB9\u58F0\u660E", "No valid DSH compatibility declaration"],
275
- ["\u4ED3\u5E93\u672A\u8FD4\u56DE\u6709\u6548\u53D1\u5E03\u65F6\u95F4", "The registry did not provide a valid release date"],
276
- ["\u8FD4\u56DE\u5185\u5BB9\u4E0D\u662F\u6709\u6548 JSON\uFF0C\u5DF2\u4FDD\u7559\u4E0A\u4E00\u4EFD\u53EF\u7528\u6570\u636E", "Invalid JSON received. The last valid catalog has been retained."],
277
- ["\u4ED3\u5E93\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u53D1\u884C\u7248\u672C", "The registry returned no valid releases"],
278
- ["\u4E0A\u6B21\u8FDB\u7A0B\u4E2D\u65AD\uFF0C\u8BF7\u91CD\u65B0\u5B89\u88C5", "The previous process was interrupted. Please install again."],
279
- ["\u5E02\u573A\u6B63\u5728\u5173\u95ED", "Marketplace is shutting down"],
280
- ["\u63D2\u4EF6\u4E0D\u5728\u5F53\u524D\u76EE\u5F55\u4E2D", "Plugin is not in the current catalog"],
281
- ["\u8BE5\u7248\u672C\u4E0D\u53EF\u5B89\u88C5", "This version cannot be installed"],
282
- ["\u5B89\u88C5\u961F\u5217\u5DF2\u6EE1", "Install queue is full"],
283
- ["\u65E0\u6548\u7684\u6F14\u793A\u573A\u666F", "Invalid demo scenario"],
284
- ["\u53EA\u5728\u6F14\u793A\u6A21\u5F0F\u53EF\u7528", "Only available in demo mode"],
285
- ["\u54CD\u5E94\u8D85\u8FC7\u5927\u5C0F\u9650\u5236", "Response exceeds the size limit"]
116
+ .hub-mcp-summary { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 16px; margin: 12px 0 0; }
117
+ .hub-mcp-statuses { display: flex; align-items: center; gap: 6px; }
118
+ .hub-mcp-endpoint { display: inline-flex; align-items: center; gap: 8px; min-width: 0; max-width: 100%; color: var(--dsw-alias-label-tertiary); }
119
+ .hub-mcp-endpoint code { font: 11px/18px var(--ds-font-family-code); max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
120
+ `;
121
+
122
+ // src/client/mcp-help.js
123
+ var mcpFields = [
124
+ ["serverName", "\u5DE5\u5177\u547D\u540D\u7A7A\u95F4\uFF0C1\u201332 \u4F4D\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\u6216\u8FDE\u5B57\u7B26\u3002", "\u5FC5\u586B"],
125
+ ["transport", "stdio \u4E3A\u672C\u5730\u8FDB\u7A0B\uFF1Bstreamable-http \u4E3A HTTP \u670D\u52A1\u3002", "\u5FC5\u586B"],
126
+ ["command", "stdio \u53EF\u6267\u884C\u6587\u4EF6\uFF1BWindows \u53EF\u4F7F\u7528 node.exe \u7684\u5B8C\u6574\u8DEF\u5F84\u3002", "stdio \u5FC5\u586B"],
127
+ ["args", "\u4F20\u7ED9\u53EF\u6267\u884C\u6587\u4EF6\u7684\u5B57\u7B26\u4E32\u6570\u7EC4\uFF0C\u4E0D\u7ECF\u8FC7 shell\u3002", "[]"],
128
+ ["env", "\u663E\u5F0F\u4F20\u7ED9\u670D\u52A1\u7684\u73AF\u5883\u53D8\u91CF\uFF0C\u53EF\u7528 !!js process.env.NAME \u5F15\u7528\u3002", "{}"],
129
+ ["cwd", "stdio \u5DE5\u4F5C\u76EE\u5F55\uFF0C\u7559\u7A7A\u4F7F\u7528\u5BBF\u4E3B\u5DE5\u4F5C\u76EE\u5F55\u3002", '""'],
130
+ ["url", "Streamable HTTP \u5730\u5740\u3002", "HTTP \u5FC5\u586B"],
131
+ ["headers", "HTTP \u8BF7\u6C42\u5934\uFF0C\u53EF\u5F15\u7528\u73AF\u5883\u53D8\u91CF\u3002", "{}"],
132
+ ["toolCallTimeoutMs", "\u5355\u6B21\u5DE5\u5177\u8C03\u7528\u8D85\u65F6\uFF0C\u5355\u4F4D\u6BEB\u79D2\u3002", "60000"],
133
+ ["failOnStartupError", "\u521D\u59CB\u5316\u5931\u8D25\u65F6\u662F\u5426\u8BA9\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25\u3002", "false"],
134
+ ["reconnect.enabled", "\u8FDE\u63A5\u4E22\u5931\u540E\u81EA\u52A8\u91CD\u8FDE\u3002", "true"],
135
+ ["reconnect.initialDelayMs", "\u9996\u6B21\u91CD\u8FDE\u7B49\u5F85\u6BEB\u79D2\u6570\uFF0C\u4E4B\u540E\u6307\u6570\u9012\u589E\u3002", "500"],
136
+ ["reconnect.maxDelayMs", "\u91CD\u8FDE\u7B49\u5F85\u4E0A\u9650\uFF0C\u5355\u4F4D\u6BEB\u79D2\u3002", "30000"],
137
+ ["reconnect.maxAttempts", "\u4E00\u6B21\u8FDE\u63A5\u6545\u969C\u7684\u8FDE\u7EED\u91CD\u8BD5\u6B21\u6570\u4E0A\u9650\u3002", "10"]
286
138
  ];
287
- var words = { zh: {}, en: {} };
288
- for (const [key, en, zh = key] of pairs) {
289
- words.zh[key] = zh;
290
- words.en[key] = en;
291
- }
292
- var tagKeys = { agent: "Agent \u63A5\u5165", "developer-tools": "\u5F00\u53D1\u5DE5\u5177", knowledge: "\u77E5\u8BC6\u6587\u6863", productivity: "\u6548\u7387\u5DE5\u5177", integration: "\u7CFB\u7EDF\u96C6\u6210", ui: "\u754C\u9762" };
293
- function diagnostic(value, t, language) {
294
- if (!value) return "";
295
- if (words.en[value]) return t(value);
296
- if (value.includes("\uFF1B") || value.includes("; ")) return value.split(/;|; /).map((part) => diagnostic(part, t, language)).join(language.startsWith("zh") ? "\uFF1B" : "; ");
297
- const entry = value.match(/^目录第 (\d+) 条:(.*)$/);
298
- if (entry && !language.startsWith("zh")) return `Catalog entry ${entry[1]}: ${diagnostic(entry[2], t, language)}`;
299
- if (language.startsWith("zh")) return value.replace(/^Duplicate catalog source id: (.+)$/, "\u6570\u636E\u6E90 ID \u91CD\u590D\uFF1A$1");
300
- return value.replace(/(\S+) 无效/g, "Invalid $1").replace(/(\S+) 不是有效 URL/g, "$1 is not a valid URL").replace(/(\S+) 必须是无凭据的 HTTPS 链接/g, "$1 must be an HTTPS URL without credentials").replace(/请求失败[( ]HTTP (\d+)[)]?/g, "Request failed (HTTP $1)").replace(/作者声明不兼容 DSH (.+)/g, "The author declares DSH $1 incompatible").replace(/插件命令失败(退出码 (\d+))/g, "Plugin command failed (exit code $1)").replace(/要求 DSH (.+),当前为 (.+)/g, "Requires DSH $1; current version is $2").replace(/要求 Node (.+)/g, "Requires Node $1").replace(/无法确认宿主接口 (.+)/g, "Cannot verify host interface $1").replace(/(.+) 要求 (.+),当前为 (.+)/g, "$1 requires $2; current version is $3").replace(/不支持当前 (os|cpu): (.+)/g, "Unsupported $1: $2").replace(/发布未满 (\d+) 小时/g, "Published less than $1 hours ago").replace(/发布未满 (\d+) 分钟/g, "Published less than $1 minutes ago").replace(/已弃用:(.*)/g, "Deprecated: $1");
301
- }
302
- function localizePlugin(plugin, language) {
303
- const locale = plugin.locales?.[language] ?? plugin.locales?.[language.split("-")[0]];
304
- return locale ? { ...plugin, ...locale } : plugin;
305
- }
306
139
 
307
140
  // src/client/market.css
308
- var market_default = "/* Brand and page layout only. Interactive controls use DSH primitives unchanged. */\n.hub-market {\n box-sizing: border-box;\n --red: #596579;\n --ink: var(--dsw-alias-label-primary, #25272b);\n --muted: var(--dsw-alias-label-tertiary, #7b7e86);\n --line: var(--dsw-alias-border-l4, #e9e9ed);\n color: var(--ink);\n font: var(--dsw-font-xs-13);\n padding: 5px 3px 20px;\n width: 100%;\n position: relative;\n isolation: isolate;\n container-type: inline-size;\n}\n.hub-market *, .hub-detail-body * { box-sizing: border-box; }\n.hub-market a:focus-visible, .hub-help-link:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 3px; }\n.hub-market svg { flex-shrink: 0; }\n.hub-topline { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 20px; }\n.hub-brand { display: flex; align-items: center; gap: 8px; font-size: 10px; letter-spacing: 1px; font-weight: 700; color: var(--muted); }\n.hub-brandmark { display: grid; place-items: center; width: 25px; height: 25px; color: white; background: var(--red); border-radius: 50%; font: 700 20px Georgia; letter-spacing: 0; }\n.hub-divider { width: 1px; height: 13px; background: var(--line); margin: 0 3px; }\n.hub-runtime { display: flex; align-items: center; gap: 5px; font: 10px ui-monospace, monospace; color: var(--muted); white-space: nowrap; }\n.hub-runtime i, .hub-footer i { width: 5px; height: 5px; border-radius: 50%; background: var(--dsw-alias-state-success-primary); display: inline-block; }\n.hub-header { display: flex; justify-content: space-between; align-items: center; gap: 18px; margin-bottom: 18px; }\n.hub-eyebrow { font-size: 9px; letter-spacing: 1.9px; color: var(--red); font-weight: 700; }\n.hub-header h1 { font-size: 30px; letter-spacing: -1px; margin: 4px 0 5px; font-weight: 650; line-height: 1.4; }\n.hub-header h1 span { color: var(--red); }\n.hub-header p { margin: 0; color: var(--muted); font-size: 12px; }\n.hub-header-art { position: relative; display: grid; place-items: center; color: var(--red); background: linear-gradient(145deg, color-mix(in srgb, var(--red) 5%, white), color-mix(in srgb, var(--red) 14%, white)); width: 80px; height: 74px; border-radius: 20px; transform: rotate(-8deg); flex-shrink: 0; border: 1px solid color-mix(in srgb, var(--red) 15%, transparent); }\n.hub-art-plus { position: absolute; right: -5px; bottom: 6px; background: white; box-shadow: 0 3px 9px #47172515; border-radius: 9px; width: 28px; height: 28px; text-align: center; font-size: 21px; line-height: 26px; transform: rotate(8deg); }\n.hub-art-dot { position: absolute; width: 8px; height: 8px; background: color-mix(in srgb, var(--red) 40%, white); border-radius: 50%; top: 9px; left: -6px; }\n.hub-stats { display: flex; flex-wrap: wrap; align-items: center; gap: 25px; padding: 12px 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); margin-bottom: 14px; }\n.hub-stats > div { display: flex; align-items: baseline; gap: 7px; }\n.hub-stats strong { font-size: 23px; font-weight: 600; letter-spacing: -.6px; font-variant-numeric: tabular-nums; }\n.hub-stats span { font-size: 11px; color: var(--muted); }\n.hub-tabs { display: flex; flex-wrap: wrap; gap: 8px; padding-bottom: 12px; border-bottom: 1px solid var(--line); margin-bottom: 14px; }\n.hub-tab-count { font-size: 10px; color: var(--muted); margin-left: 5px; }\n.hub-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }\n.hub-search-input { flex: 1; min-width: 180px; }\n.hub-results { display: flex; justify-content: space-between; align-items: center; gap: 10px; color: var(--muted); font-size: 11px; margin: 20px 0 12px; }\n.hub-results b { margin-left: 4px; font-weight: 500; }\n.hub-results small { font-size: 9px; }\n.hub-pagination { display: flex; justify-content: center; padding: 20px 0 0; }\n.hub-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 13px; }\n.hub-card { border: 1px solid var(--line); border-radius: 11px; padding: 16px; background: var(--dsw-alias-bg-layer-2, #fff); display: flex; flex-direction: column; min-width: 0; }\n.hub-card-top { display: flex; align-items: center; justify-content: space-between; gap: 6px; margin-bottom: 10px; flex-wrap: wrap; }\n.hub-plugin-icon { display: grid; place-items: center; border-radius: 10px; width: 40px; height: 40px; background: #f4f0ea; color: #9c754f; }\n.hub-plugin-icon.icon-knowledge { background: #eaf3f2; color: #4c8b80; }\n.hub-plugin-icon.icon-developer-tools { background: #edf0fa; color: #6278ac; }\n.hub-plugin-icon.icon-agent { background: #f8e9ed; color: #b94b63; }\n.hub-plugin-icon.icon-integration { background: #f1eefa; color: #8c6db2; }\n.hub-card-heading { font-size: 14px; margin: 0 -8px; }\n.hub-description { font-size: 12px; color: var(--muted); line-height: 1.85; min-height: 44px; margin: 13px 0 12px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }\n.hub-tags { display: flex; gap: 5px; flex-wrap: wrap; margin: 0 0 14px; }\n.hub-version-row { border-top: 1px solid var(--line); padding-top: 12px; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 6px; font-size: 11px; color: var(--muted); margin-top: auto; }\n.hub-version-note { font-size: 10px; color: var(--muted); overflow-wrap: anywhere; margin: 7px 0 13px; min-height: 16px; }\n.hub-card-actions { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 9px; }\n.hub-footer { display: flex; justify-content: space-between; flex-wrap: wrap; font-size: 9px; color: var(--muted); margin-top: 21px; gap: 8px; }\n.hub-footer i { margin-right: 5px; }\n.hub-footnote { font-size: 9px; color: var(--muted); margin: 7px 0 0; line-height: 1.7; }\n.hub-empty { padding: 50px 10px; text-align: center; color: var(--muted); }\n.hub-empty svg { margin: auto; }\n.hub-empty h2, .hub-empty h3 { color: var(--ink); font-weight: 500; }\n.hub-notice { display: flex; gap: 8px; align-items: center; font-size: 11px; padding: 12px; border-radius: 7px; margin: 10px 0; }\n.hub-notice.amber { background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 10%, var(--dsw-alias-bg-layer-2)); color: var(--dsw-alias-label-primary); }\n.hub-notice.red { background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, var(--dsw-alias-bg-layer-2)); color: var(--dsw-alias-label-primary); }\n.hub-notice > div, .hub-notice > span { flex: 1; }\n.hub-notice b, .hub-notice div > span { display: block; }\n.hub-notice b { font-weight: 500; }\n.hub-notice div > span { font-size: 10px; }\n.hub-queue { position: sticky; bottom: 0; z-index: 4; margin-top: 16px; background: var(--dsw-alias-bg-layer-2, #fff); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--dsw-elevation-prominent); overflow: hidden; }\n.hub-queue-summary { display: flex; align-items: center; width: 100%; gap: 10px; padding: 12px 15px; color: var(--ink); }\n.hub-queue-summary > span:nth-child(2) { flex: 1; }\n.hub-queue-icon { display: grid; place-items: center; border-radius: 8px; width: 33px; height: 33px; background: color-mix(in srgb, var(--red) 9%, white); color: var(--red); }\n.hub-queue-summary b { font-size: 11px; font-weight: 500; display: block; }\n.hub-queue-summary small { font-size: 9px; color: var(--muted); display: block; }\n.hub-jobs { border-top: 1px solid var(--line); max-height: 170px; overflow: auto; padding: 0 15px; }\n.hub-jobs > div { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--line); flex-wrap: wrap; }\n.hub-jobs > div > span:first-child { flex: 1; }\n.hub-jobs b { font-weight: 500; font-size: 10px; }\n.hub-jobs small { font-size: 9px; margin-left: 7px; color: var(--muted); }\n.hub-jobs p { font-size: 10px; width: 100%; color: var(--red); margin: 0; }\n.hub-detail-dialog { width: min(500px, 100%); max-height: 85vh; }\n.hub-detail-scroll { overflow: auto; }\n.hub-detail-body { color: var(--dsw-alias-label-primary); font: var(--dsw-font-xs-13); }\n.hub-package-name { font-size: 11px; color: var(--dsw-alias-label-tertiary); overflow-wrap: anywhere; }\n.hub-detail-info { display: flex; flex-wrap: wrap; gap: 25px; font-size: 11px; color: var(--dsw-alias-label-tertiary); padding: 16px 0; }\n.hub-detail-info b { display: block; color: var(--dsw-alias-label-secondary); font-weight: 500; margin-top: 3px; }\n.hub-detail-body h3 { font-size: 13px; margin: 10px 0; }\n.hub-releases { display: grid; gap: 12px; }\n.hub-release { border-bottom: 1px solid var(--dsw-alias-border-l4); padding-bottom: 12px; }\n.hub-release > div { display: flex; justify-content: space-between; align-items: center; }\n.hub-release small, .hub-release p { font-size: 11px; color: var(--dsw-alias-label-tertiary); margin: 6px 0 0; display: block; }\n.hub-help-link:hover { color: var(--dsw-alias-brand-primary); text-decoration: underline; }\n.hub-help-link { color: var(--dsw-alias-label-secondary); font-size: 11px; display: inline-flex; align-items: center; gap: 4px; text-decoration: none; }\n.spinning { animation: hub-spin .9s linear infinite; }\n@keyframes hub-spin { to { transform: rotate(360deg); } }\n@container (max-width: 470px) {\n .hub-grid { grid-template-columns: 1fr; }\n .hub-topline { flex-wrap: wrap; }\n .hub-header-art { display: none; }\n .hub-results small { display: none; }\n .hub-stats { gap: 15px; }\n}\n@media (prefers-reduced-motion: reduce) { .spinning { animation: none; } }\n\n.hub-card-package { font-size: 10px; color: var(--dsw-alias-label-tertiary); overflow-wrap: anywhere; margin-top: 5px; }\n.hub-document-links { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 12px; }\n.hub-detail-actions { width: 100%; }\n.hub-detail-actions > div:first-child { display: flex; flex-wrap: wrap; gap: 8px; }\n\n.hub-source-label { display: block; margin-top: 8px; color: var(--dsw-alias-label-tertiary); font-size: 11px; }\n";
141
+ var market_default = "/* Shared page layout; interactive controls remain DSH primitives. */\n.hub-market {\n box-sizing: border-box;\n --red: #596579;\n --ink: var(--dsw-alias-label-primary, #25272b);\n --muted: var(--dsw-alias-label-tertiary, #7b7e86);\n --line: var(--dsw-alias-border-l4, #e9e9ed);\n color: var(--ink);\n font: var(--dsw-font-xs-13);\n padding: 5px 3px 20px;\n width: 100%;\n position: relative;\n isolation: isolate;\n container-type: inline-size;\n}\n.hub-topline { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 20px; }\n.hub-brand { display: flex; align-items: center; gap: 8px; font-size: 10px; letter-spacing: 1px; font-weight: 700; color: var(--muted); }\n.hub-brandmark { display: grid; place-items: center; width: 25px; height: 25px; color: white; background: var(--red); border-radius: 50%; letter-spacing: 0; }\n.hub-divider { width: 1px; height: 13px; background: var(--line); margin: 0 3px; }\n.hub-header { display: flex; justify-content: space-between; align-items: center; gap: 18px; margin-bottom: 18px; }\n.hub-eyebrow { font-size: 9px; letter-spacing: 1.9px; color: var(--red); font-weight: 700; }\n.hub-header h1 { font-size: 30px; letter-spacing: -1px; margin: 4px 0 5px; font-weight: 650; line-height: 1.4; }\n.hub-header h1 span { color: var(--red); }\n.hub-header p { margin: 0; color: var(--muted); font-size: 12px; }\n.hub-header-art { position: relative; display: grid; place-items: center; color: var(--red); background: linear-gradient(145deg, color-mix(in srgb, var(--red) 5%, var(--dsw-alias-bg-layer-2)), color-mix(in srgb, var(--red) 14%, var(--dsw-alias-bg-layer-2))); width: 80px; height: 74px; border-radius: 20px; transform: rotate(-8deg); flex-shrink: 0; border: 1px solid color-mix(in srgb, var(--red) 15%, transparent); }\n.hub-art-plus { position: absolute; right: -5px; bottom: 6px; background: var(--dsw-alias-bg-layer-3); box-shadow: 0 3px 9px #47172515; border-radius: 9px; width: 28px; height: 28px; text-align: center; font-size: 21px; line-height: 26px; transform: rotate(8deg); }\n.hub-art-dot { position: absolute; width: 8px; height: 8px; background: color-mix(in srgb, var(--red) 40%, var(--dsw-alias-bg-layer-3)); border-radius: 50%; top: 9px; left: -6px; }\n.hub-tabs { display: flex; flex-wrap: wrap; gap: 8px; padding-bottom: 12px; border-bottom: 1px solid var(--line); margin-bottom: 14px; }\n.hub-tab-count { font-size: 10px; color: var(--muted); margin-left: 5px; }\n.hub-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }\n.hub-search-input { flex: 1; min-width: 180px; }\n.hub-results { display: flex; justify-content: space-between; align-items: center; gap: 10px; color: var(--muted); font-size: 11px; margin: 20px 0 12px; }\n.hub-results b { margin-left: 4px; font-weight: 500; }\n.hub-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 13px; }\n.hub-card { border: 1px solid var(--line); border-radius: 11px; padding: 16px; background: var(--dsw-alias-bg-layer-2, #fff); display: flex; flex-direction: column; min-width: 0; }\n.hub-description { font-size: 12px; color: var(--muted); line-height: 1.85; min-height: 44px; margin: 13px 0 12px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }\n@container (max-width: 470px) { .hub-grid { grid-template-columns: 1fr; } .hub-topline { flex-wrap: wrap; } .hub-header-art { display: none; } }\n";
309
142
 
310
- // src/client/index.jsx
311
- var NS = "@zaimokuza/dsh-plugin-hub";
312
- var MARKET_ID = "hub";
313
- var BRAND = define_HUB_BRAND_default;
314
- var request2 = (path, data, options) => request(path, data, { ...options, base: `/dsh-plugin-hub/${MARKET_ID}/api/` });
315
- function Icon({ name: name2 = "box", size = 18, ...props }) {
316
- const paths = {
317
- search: /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "10.5", cy: "10.5", r: "6.5" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "m16 16 4 4" })),
318
- box: /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("path", { d: "m12 3 9 5-9 5-9-5 9-5Z" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M3 8v9l9 5 9-5V8M12 13v9M7.5 5.5l9 5" })),
319
- download: /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 3v12m-5-5 5 5 5-5M4 16v5h16v-5" })),
320
- arrow: /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("path", { d: "M7 17 17 7M7 7h10v10" })),
321
- refresh: /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("path", { d: "M20 7v5h-5M4 17v-5h5" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M5.2 7A8 8 0 0 1 19 6l1 2M4 16l1 2a8 8 0 0 0 13.8-1" })),
322
- clock: /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "9" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 7v5l3 2" })),
323
- check: /* @__PURE__ */ import_react.default.createElement("path", { d: "m5 12 4 4L19 6" }),
324
- close: /* @__PURE__ */ import_react.default.createElement("path", { d: "m6 6 12 12M18 6 6 18" }),
325
- code: /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("path", { d: "m8 6-6 6 6 6m8-12 6 6-6 6m-3-15-2 18" })),
326
- book: /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 5v16M3 4c4-1 6 0 9 2 3-2 5-3 9-2v15c-4-1-6 0-9 2-3-2-5-3-9-2V4Z" })),
327
- plug: /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("path", { d: "M8 2v5m8-5v5M6 7h12v4a6 6 0 0 1-12 0V7ZM12 17v5" })),
328
- filter: /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("path", { d: "M4 7h16M7 12h10M10 17h4" }))
329
- };
330
- return /* @__PURE__ */ import_react.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...props }, paths[name2] ?? paths.box);
143
+ // src/client/resources.jsx
144
+ function ItemIcon({ row }) {
145
+ const [failed, setFailed] = (0, import_react.useState)(false);
146
+ const label = row.name.split("/").pop().replace(/^@/, "").slice(0, 1).toLocaleUpperCase();
147
+ return /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-item-icon", "aria-hidden": "true" }, row.icon && !failed ? /* @__PURE__ */ import_react.default.createElement("img", { src: row.icon, alt: "", referrerPolicy: "no-referrer", onError: () => setFailed(true) }) : label);
331
148
  }
332
- function Picker({ label, value, items, onChange, disabled, icon, title }) {
149
+ function ScopePicker({ data, scope, setScope, t, disabled }) {
333
150
  const [open, setOpen] = (0, import_react.useState)(false);
151
+ const items = [{ id: "", label: t("\u5168\u5C40") }, ...(data?.workspaces ?? []).map((row) => ({ id: row.id, label: row.title }))];
334
152
  return /* @__PURE__ */ import_react.default.createElement(
335
153
  import_dsh_client_ui_primitives.Menu,
336
154
  {
337
155
  open,
338
156
  onClose: () => setOpen(false),
339
157
  items,
340
- selectedId: value,
158
+ selectedId: scope,
341
159
  portal: true,
342
160
  align: "end",
343
161
  onSelect: (id) => {
344
162
  setOpen(false);
345
- onChange(id);
163
+ setScope(id);
346
164
  },
347
- anchor: /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { variant: "outline", size: "sm", disabled, "aria-label": label, "aria-haspopup": "menu", "aria-expanded": open, icon, onClick: () => setOpen((v) => !v) }, title ?? items.find((item) => item.id === value)?.label, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.IconChevronDownOutline14, null))
165
+ anchor: /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "md", disabled, "aria-label": t("\u8D44\u6E90\u8303\u56F4"), "aria-expanded": open, "aria-haspopup": "menu", onClick: () => setOpen(!open) }, items.find((row) => row.id === scope)?.label ?? t("\u5168\u5C40"))
348
166
  }
349
167
  );
350
168
  }
351
- function Badge({ tone = "neutral", children }) {
352
- const state = { green: "done", amber: "warning", red: "error", ongoing: "ongoing" }[tone];
353
- return /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Pill, null, state && /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.StateDot, { state }), " ", children);
354
- }
355
- function status(plugin, release, t, hours) {
356
- if (plugin.metadataLoading) return { label: t("\u6B63\u5728\u67E5\u8BE2\u7248\u672C"), tone: "ongoing" };
357
- if (plugin.queryError) return { label: t(plugin.queryError.includes("\uFF08404\uFF09") ? "\u5F53\u524D\u4ED3\u5E93\u672A\u627E\u5230" : plugin.queryError.includes("\u4ED3\u5E93\u4E0E\u76EE\u5F55\u4E0D\u4E00\u81F4") ? "\u6765\u6E90\u4E0D\u5339\u914D" : plugin.queryError.includes("\u672A\u58F0\u660E\u53EF\u6838\u5BF9\u7684 GitHub \u6765\u6E90") ? "\u6765\u6E90\u672A\u6838\u5B9E" : "\u67E5\u8BE2\u5931\u8D25"), tone: "neutral" };
358
- if (!release || release.compatibility === "unknown") return { label: t("\u517C\u5BB9\u6027\u672A\u77E5"), tone: "neutral" };
359
- if (release.compatibility === "incompatible") return { label: t("\u7248\u672C\u4E0D\u517C\u5BB9"), tone: "red" };
360
- if (release.age === "waiting") return { label: Number.isInteger(hours) ? t("\u672A\u6EE1 {hours} \u5C0F\u65F6", { hours }) : t("\u672A\u6EE1 {minutes} \u5206\u949F", { minutes: Math.round(hours * 60) }), tone: "amber" };
361
- if (release.age === "unknown") return { label: t("\u53D1\u5E03\u65F6\u95F4\u672A\u77E5"), tone: "neutral" };
362
- return release.canInstall ? { label: t("\u7B26\u5408\u5B89\u88C5\u6761\u4EF6"), tone: "green" } : { label: t("\u6682\u4E0D\u53EF\u5B89\u88C5"), tone: "neutral" };
169
+ function ResourceModal(props) {
170
+ (0, import_react.useEffect)(() => {
171
+ if (!props.open) return;
172
+ const escape = (event) => {
173
+ if (event.key !== "Escape" || event.isComposing) return;
174
+ event.preventDefault();
175
+ event.stopImmediatePropagation();
176
+ props.onClose();
177
+ };
178
+ window.addEventListener("keydown", escape, true);
179
+ return () => window.removeEventListener("keydown", escape, true);
180
+ }, [props.open, props.onClose]);
181
+ return /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Modal, { ...props });
363
182
  }
364
- function Market({ locale, t }) {
365
- const language = (0, import_react.useSyncExternalStore)((listener) => locale.subscribe(listener), () => locale.getSnapshot().active);
366
- const date = (value) => value ? new Date(value).toLocaleString(language.startsWith("zh") ? "zh-CN" : language, { month: "short", day: "2-digit", hour: "2-digit", minute: "2-digit", hour12: false }) : t("\u65F6\u95F4\u672A\u77E5");
367
- const explain = (value) => diagnostic(value, t, language);
368
- const [data, setData] = (0, import_react.useState)(null);
183
+ function McpEditor({ row, t, busy, save, close, request, profile }) {
184
+ const [format, setFormat] = (0, import_react.useState)("json");
185
+ const [help, setHelp] = (0, import_react.useState)(false);
186
+ const [text, setText] = (0, import_react.useState)(JSON.stringify({ serverName: "my_server", transport: "stdio", command: "npx", args: ["-y", "mcp-server-package"] }, null, 2));
187
+ const [loading, setLoading] = (0, import_react.useState)(Boolean(row));
369
188
  const [error, setError] = (0, import_react.useState)("");
370
- const [connectionError, setConnectionError] = (0, import_react.useState)("");
371
- const [loading, setLoading] = (0, import_react.useState)(true);
372
- const [query, setQuery] = (0, import_react.useState)("");
373
- const [tab, setTab] = (0, import_react.useState)("all");
374
- const [tag, setTag] = (0, import_react.useState)("all");
375
- const [visibleCount, setVisibleCount] = (0, import_react.useState)(40);
376
- (0, import_react.useEffect)(() => setVisibleCount(40), [query, tab, tag]);
377
- const [selected, setSelected] = (0, import_react.useState)({});
378
- const [detailName, setDetailName] = (0, import_react.useState)(null);
379
- const [showJobs, setShowJobs] = (0, import_react.useState)(false);
380
- const [submitting, setSubmitting] = (0, import_react.useState)({});
189
+ const [ready, setReady] = (0, import_react.useState)(!row);
381
190
  (0, import_react.useEffect)(() => {
191
+ if (!row) return;
382
192
  const controller = new AbortController();
383
- let timer;
384
- let failures = 0;
385
- async function poll(first = false) {
386
- try {
387
- const value = await request2("state", void 0, { signal: controller.signal });
388
- if (!controller.signal.aborted) {
389
- setData(value);
390
- setConnectionError("");
391
- failures = 0;
392
- }
393
- } catch (err) {
394
- if (!controller.signal.aborted) {
395
- setConnectionError(err.message);
396
- failures++;
397
- }
398
- } finally {
399
- if (!controller.signal.aborted) {
400
- if (first) setLoading(false);
401
- timer = setTimeout(() => poll(), Math.min(1e4, 2e3 * 2 ** failures));
402
- }
193
+ request("mcp-config", { id: row.id, revision: row.revision, profile, format: "json" }, { signal: controller.signal }).then((result) => {
194
+ if (!controller.signal.aborted) {
195
+ setText(result.text);
196
+ setReady(true);
403
197
  }
404
- }
405
- void poll(true);
406
- return () => {
407
- controller.abort();
408
- clearTimeout(timer);
409
- };
410
- }, []);
411
- const pendingVisible = (data?.lazyMetadata ? data.plugins.map((p) => localizePlugin(p, language)).filter((p) => inScope(p, resolveScope(tab, data.sources ?? [])) && (tag === "all" || p.tags.includes(tag)) && [p.displayName, p.packageName, p.description, p.owner, ...p.tags.map((id) => tagKeys[id] ? t(tagKeys[id]) : id)].join(" ").toLowerCase().includes(query.trim().toLowerCase())).slice(0, visibleCount).filter((p) => p.metadataLoading).slice(0, 40).map((p) => p.packageName) : []).join("|");
412
- (0, import_react.useEffect)(() => {
413
- if (!pendingVisible) return;
414
- const controller = new AbortController();
415
- void request2("releases", { packageNames: pendingVisible.split("|") }, { signal: controller.signal }).catch((error2) => {
198
+ }).catch((error2) => {
416
199
  if (!controller.signal.aborted) setError(error2.message);
200
+ }).finally(() => {
201
+ if (!controller.signal.aborted) setLoading(false);
417
202
  });
418
203
  return () => controller.abort();
419
- }, [pendingVisible]);
420
- function reportActionError(err) {
421
- if (["\u8FDE\u63A5\u5DF2\u65AD\u5F00\uFF0C\u8BF7\u786E\u8BA4\u672C\u5730 DSH \u5B9E\u4F8B\u6B63\u5728\u8FD0\u884C\u3002\u6062\u590D\u540E\u9875\u9762\u4F1A\u81EA\u52A8\u91CD\u8FDE\u3002", "\u8BF7\u6C42\u8D85\u65F6\uFF0C\u6B63\u5728\u7B49\u5F85 DSH \u54CD\u5E94\u3002", "\u8BF7\u5148\u767B\u5F55\u5F53\u524D DSH \u5B9E\u4F8B", "\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6548\u54CD\u5E94\uFF0C\u8BF7\u5237\u65B0 DSH \u9875\u9762\u3002"].includes(err.message)) setConnectionError(err.message);
422
- else setError(err.message);
423
- }
424
- async function update(path = "refresh", body = {}) {
204
+ }, [row, profile, request]);
205
+ const convert = async (target) => {
425
206
  setLoading(true);
426
207
  setError("");
427
208
  try {
428
- setData(await request2(path === "refresh" ? "refresh-start" : path, body));
429
- setConnectionError("");
430
- } catch (err) {
431
- reportActionError(err);
209
+ const result = await request("mcp-format", { text, format: target, profile });
210
+ setText(result.text);
211
+ setFormat(target);
212
+ } catch (error2) {
213
+ setError(error2.message);
432
214
  } finally {
433
215
  setLoading(false);
434
216
  }
217
+ };
218
+ const submit = async (event) => {
219
+ event.preventDefault();
220
+ setError("");
221
+ try {
222
+ await save({ action: row ? "mcp-edit" : "mcp-add", ...row ? { id: row.id, revision: row.revision } : {}, text });
223
+ } catch (error2) {
224
+ setError(error2.message);
225
+ }
226
+ };
227
+ const blocked = busy || loading;
228
+ return /* @__PURE__ */ import_react.default.createElement(
229
+ ResourceModal,
230
+ {
231
+ open: true,
232
+ className: `hub-resource-dialog hub-resource-editor-dialog ${help ? "with-help" : ""}`,
233
+ contentClassName: "hub-resource-dialog-scroll",
234
+ title: t(row ? "\u7F16\u8F91" : "\u6DFB\u52A0 MCP"),
235
+ closeLabel: t("\u5173\u95ED"),
236
+ onClose: blocked ? () => {
237
+ } : close,
238
+ footer: /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-resource-actions" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "md", disabled: blocked, onClick: close }, t("\u53D6\u6D88")), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "md", variant: "primary", type: "submit", form: "hub-mcp-editor", disabled: blocked || !ready }, t("\u4FDD\u5B58")))
239
+ },
240
+ /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-editor-columns" }, /* @__PURE__ */ import_react.default.createElement("form", { id: "hub-mcp-editor", className: "hub-resource-form", onSubmit: submit }, /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-resource-actions", role: "group", "aria-label": t("\u914D\u7F6E\u683C\u5F0F") }, ["json", "yaml"].map((value) => /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { key: value, size: "md", className: "hub-resource-tab", "aria-pressed": format === value, disabled: blocked || !ready, onClick: () => {
241
+ void convert(value);
242
+ } }, value.toUpperCase())), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "md", disabled: blocked || !ready, onClick: () => {
243
+ void convert(format);
244
+ } }, t("\u683C\u5F0F\u5316"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-resource-editor-note" }, t("\u63A8\u8350\u5728\u542F\u52A8 DSH \u7684\u73AF\u5883\u4E2D\u8BBE\u7F6E\u51ED\u636E\u3002YAML \u4F7F\u7528"), " ", /* @__PURE__ */ import_react.default.createElement("code", null, "!!js process.env.MCP_TOKEN"), t("\uFF1BJSON \u4F7F\u7528"), " ", /* @__PURE__ */ import_react.default.createElement("code", null, '{"__jsExpr":"process.env.MCP_TOKEN"}'), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "md", "aria-expanded": help, onClick: () => setHelp(!help) }, t("\u5E2E\u52A9"))), loading && /* @__PURE__ */ import_react.default.createElement("p", { role: "status" }, t("\u6B63\u5728\u8BFB\u53D6\u914D\u7F6E")), /* @__PURE__ */ import_react.default.createElement("label", { className: "hub-resource-field" }, t("MCP \u914D\u7F6E"), /* @__PURE__ */ import_react.default.createElement("textarea", { className: "hub-resource-code", value: ready ? text : "", onChange: (event) => setText(event.target.value), disabled: blocked || !ready, spellCheck: false, autoCapitalize: "off", autoComplete: "off", maxLength: 24e3, required: true })), error && /* @__PURE__ */ import_react.default.createElement("p", { role: "alert" }, t(error))), help && /* @__PURE__ */ import_react.default.createElement("aside", { className: "hub-editor-help" }, /* @__PURE__ */ import_react.default.createElement("h3", null, t("MCP \u914D\u7F6E\u5E2E\u52A9")), /* @__PURE__ */ import_react.default.createElement("p", null, "macOS / Linux: ", /* @__PURE__ */ import_react.default.createElement("code", null, "export MCP_TOKEN=\u2026"), /* @__PURE__ */ import_react.default.createElement("br", null), "Windows PowerShell: ", /* @__PURE__ */ import_react.default.createElement("code", null, "$env:MCP_TOKEN=\u2026")), /* @__PURE__ */ import_react.default.createElement("p", null, t("\u4E0B\u5217\u9ED8\u8BA4\u503C\u7531 DSH \u63D0\u4F9B\uFF1B\u5207\u6362\u683C\u5F0F\u4E0D\u4F1A\u8865\u5165\u8FD9\u4E9B\u5B57\u6BB5\u3002")), /* @__PURE__ */ import_react.default.createElement("dl", null, mcpFields.map(([key, description, fallback]) => /* @__PURE__ */ import_react.default.createElement("div", { key }, /* @__PURE__ */ import_react.default.createElement("dt", null, /* @__PURE__ */ import_react.default.createElement("code", null, key)), /* @__PURE__ */ import_react.default.createElement("dd", null, t(description), /* @__PURE__ */ import_react.default.createElement("span", null, t(fallback.includes("\u5FC5\u586B") ? "\u8981\u6C42" : "\u9ED8\u8BA4\u503C"), " \xB7 ", fallback.includes("\u5FC5\u586B") ? t(fallback) : fallback)))))))
245
+ );
246
+ }
247
+ function McpSummary({ row, t, activation }) {
248
+ const endpoint = row.endpoint || "";
249
+ let endpointLabel = endpoint;
250
+ if (row.transport === "stdio") endpointLabel = endpoint.split(/[\\/]/).filter(Boolean).pop() || endpoint;
251
+ else {
252
+ try {
253
+ endpointLabel = new URL(endpoint).host;
254
+ } catch {
255
+ }
435
256
  }
436
- async function install(plugin, release, action = "install") {
437
- if (action === "install" && !release?.canInstall) return;
438
- setSubmitting((previous) => ({ ...previous, [plugin.packageName]: true }));
257
+ const loaded = activation(row.activation);
258
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-mcp-summary" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-mcp-statuses" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Tooltip, { label: `${t("\u52A0\u8F7D\u72B6\u6001")} \xB7 ${loaded}` }, /* @__PURE__ */ import_react.default.createElement("span", { tabIndex: 0 }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Tag, { tone: { active: "success", loading: "info", unloading: "info", failed: "danger" }[row.activation] ?? "neutral" }, loaded === t("\u672A\u77E5") ? t("\u52A0\u8F7D\u672A\u77E5") : loaded))), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Tooltip, { label: t("\u5BBF\u4E3B\u672A\u516C\u5F00\u6301\u7EED\u8FDE\u63A5\u72B6\u6001\uFF1B\u5DF2\u52A0\u8F7D\u4E0D\u4EE3\u8868\u8FDE\u63A5\u6210\u529F\u3002") }, /* @__PURE__ */ import_react.default.createElement("span", { tabIndex: 0 }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Tag, { tone: "neutral" }, t("\u8FDE\u63A5\u672A\u77E5"))))), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Tooltip, { label: `${row.transport}${endpoint ? " \xB7 " + endpoint : ""}` }, /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-mcp-endpoint", tabIndex: 0 }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Tag, { tone: "neutral" }, row.transport === "streamable-http" ? "HTTP" : row.transport === "unknown" ? t("\u672A\u77E5") : row.transport), endpointLabel && /* @__PURE__ */ import_react.default.createElement("code", null, endpointLabel))));
259
+ }
260
+ function SkillPreview({ file, t, close }) {
261
+ const view = (0, import_react.useRef)(null);
262
+ const frontmatter = file.text.match(/^---\r?\n([\s\S]*?)\r?\n(?:---|\.\.\.)(?:\r?\n|$)/);
263
+ const title = file.path.split(/[\\/]/).slice(-2, -1).join("") + "/skill.md";
264
+ const body = frontmatter ? file.text.slice(frontmatter[0].length) : file.text;
265
+ (0, import_react.useEffect)(() => {
266
+ if (window.matchMedia("(max-width: 850px)").matches) view.current?.scrollIntoView({ block: "start" });
267
+ }, [file]);
268
+ return /* @__PURE__ */ import_react.default.createElement("aside", { className: "hub-skill-view", ref: view, "aria-label": title }, /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-resource-card-heading" }, /* @__PURE__ */ import_react.default.createElement("h2", { title }, title), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", onClick: close, icon: /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.IconCloseOutline16, null) }, t("\u5173\u95ED"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-skill-markdown" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.MarkdownText, { text: body, labels: { code: { copyLabel: t("\u590D\u5236"), copiedLabel: t("\u5DF2\u590D\u5236") }, footnotes: t("\u811A\u6CE8") } })));
269
+ }
270
+ function ResourceHub({ ctx, request, t, brand, panelId }) {
271
+ (0, import_react.useSyncExternalStore)((fn) => ctx.locale.subscribe(fn), () => ctx.locale.getSnapshot().active);
272
+ const [tab, setTab] = (0, import_react.useState)("skills");
273
+ const [scope, setScope] = (0, import_react.useState)("");
274
+ const [file, setFile] = (0, import_react.useState)(null);
275
+ const [desktopHelp, setDesktopHelp] = (0, import_react.useState)(false);
276
+ const [data, setData] = (0, import_react.useState)(null);
277
+ const [query, setQuery] = (0, import_react.useState)("");
278
+ const [error, setError] = (0, import_react.useState)("");
279
+ const [busy, setBusy] = (0, import_react.useState)(false);
280
+ const [editor, setEditor] = (0, import_react.useState)(null);
281
+ const [deleting, setDeleting] = (0, import_react.useState)(null);
282
+ const generation = (0, import_react.useRef)(0);
283
+ const mounted = (0, import_react.useRef)(true);
284
+ (0, import_react.useEffect)(() => {
285
+ mounted.current = true;
286
+ return () => {
287
+ mounted.current = false;
288
+ generation.current++;
289
+ };
290
+ }, []);
291
+ const refresh = async (signal) => {
292
+ const token = ++generation.current;
293
+ try {
294
+ const [result, experiments] = await Promise.all([request("resources", { workspaceId: scope }, { signal }), request("experiments", {}, { signal })]);
295
+ result.experiments = experiments;
296
+ if (mounted.current && token === generation.current) {
297
+ setData(result);
298
+ setError("");
299
+ }
300
+ } catch (error2) {
301
+ if (!signal?.aborted && mounted.current && token === generation.current) setError(error2.message);
302
+ }
303
+ };
304
+ (0, import_react.useEffect)(() => {
305
+ const controller = new AbortController();
306
+ setData(null);
307
+ void refresh(controller.signal);
308
+ return () => controller.abort();
309
+ }, [scope]);
310
+ const action = async (body, route = "resource-mutate") => {
311
+ setBusy(true);
439
312
  setError("");
440
313
  try {
441
- await request2(action, { packageName: plugin.packageName, ...action === "install" ? { version: release.version } : {} });
442
- setData(await request2("state"));
443
- setShowJobs(true);
444
- setConnectionError("");
445
- } catch (err) {
446
- reportActionError(err);
314
+ const result = await request(route, { ...body, workspaceId: scope, profile: data.profile.directory });
315
+ if (mounted.current && result.skills) {
316
+ generation.current++;
317
+ setData((previous) => ({ ...result, experiments: previous.experiments }));
318
+ }
319
+ return result;
320
+ } catch (error2) {
321
+ if (mounted.current) setError(error2.message);
322
+ throw error2;
447
323
  } finally {
448
- setSubmitting((previous) => ({ ...previous, [plugin.packageName]: false }));
324
+ if (mounted.current) setBusy(false);
449
325
  }
450
- }
451
- const releaseOf = (plugin) => plugin.versions.find((v) => v.version === selected[plugin.packageName]) ?? plugin.versions.find((v) => v.version === plugin.recommendedVersion) ?? plugin.versions[0];
452
- const linkFor = (plugin, key) => plugin[key];
453
- function documentLinks(plugin) {
454
- return /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-document-links" }, [["documentationUrl", "\u4ECB\u7ECD\u6587\u6863"], ["troubleshootingUrl", "\u6392\u67E5\u6307\u5357"]].filter(([key]) => plugin[key]).map(([key, label]) => /* @__PURE__ */ import_react.default.createElement("a", { className: "hub-help-link", key, href: linkFor(plugin, key), target: "_blank", rel: "noopener noreferrer", title: plugin[key] }, t(label), " ", /* @__PURE__ */ import_react.default.createElement(Icon, { name: "arrow", size: 13 }))));
455
- }
456
- function uninstallButton(plugin) {
457
- if (!plugin.installedVersion) return null;
458
- const job = data.jobs.find((job2) => job2.packageName === plugin.packageName && ["queued", "installing"].includes(job2.status));
459
- return /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", variant: "outline", disabled: Boolean(job) || submitting[plugin.packageName] || Boolean(connectionError), onClick: () => install(plugin, null, "uninstall") }, t(job?.action === "uninstall" ? "\u6B63\u5728\u5378\u8F7D\u2026" : "\u5378\u8F7D\u63D2\u4EF6"));
460
- }
461
- function installButton(plugin, release) {
462
- const job = data.jobs.find((job2) => job2.packageName === plugin.packageName && ["queued", "installing"].includes(job2.status));
463
- const installed = plugin.installedVersion === release?.version;
464
- const key = job ? job.status === "queued" ? "\u5DF2\u52A0\u5165\u961F\u5217" : job.action === "uninstall" ? "\u6B63\u5728\u5378\u8F7D\u2026" : "\u6B63\u5728\u5B89\u88C5\u2026" : installed ? "\u5DF2\u5B89\u88C5" : !release?.canInstall ? "\u6682\u4E0D\u53EF\u5B89\u88C5" : "\u5B89\u88C5\u63D2\u4EF6";
465
- return /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { variant: installed ? "outline" : "primary", size: "sm", disabled: !release?.canInstall || installed || Boolean(job) || submitting[plugin.packageName] || Boolean(connectionError), onClick: () => install(plugin, release), icon: /* @__PURE__ */ import_react.default.createElement(Icon, { name: installed ? "check" : job ? "clock" : "download", size: 15 }) }, t(key));
466
- }
467
- if (!data) return /* @__PURE__ */ import_react.default.createElement("section", { className: "hub-market" }, /* @__PURE__ */ import_react.default.createElement("style", null, market_default), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-empty" }, /* @__PURE__ */ import_react.default.createElement(Icon, { name: "box", size: 38 }), /* @__PURE__ */ import_react.default.createElement("h2", null, BRAND.navTitle), /* @__PURE__ */ import_react.default.createElement("p", { role: error || connectionError ? "alert" : void 0 }, explain(error || connectionError) || t("\u6B63\u5728\u8BFB\u53D6\u63D2\u4EF6\u76EE\u5F55\u2026")), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { variant: "outline", onClick: () => update() }, t("\u91CD\u65B0\u83B7\u53D6"))));
468
- const all = data.plugins.map((plugin) => localizePlugin(plugin, language));
469
- const tags = Object.fromEntries(Object.entries(tagKeys).map(([key, label]) => [key, t(label)]));
470
- const sourceTabs = (data.sources ?? []).filter((source) => !source.primary);
471
- const activeTab = resolveScope(tab, sourceTabs);
472
- const selectedSource = sourceTabs.find((source) => activeTab === "source:" + source.id);
473
- const tabs = [["all", "\u5168\u90E8\u63D2\u4EF6", all.length], ["installed", "\u5DF2\u5B89\u88C5", all.filter((p) => p.installedVersion).length], ...sourceTabs.map((source) => ["source:" + source.id, source.displayName, all.filter((p) => inScope(p, "source:" + source.id)).length])];
474
- const filtered = all.filter((plugin) => inScope(plugin, activeTab) && (tag === "all" || plugin.tags.includes(tag)) && [plugin.displayName, plugin.packageName, plugin.description, plugin.owner, ...plugin.tags.map((item) => tags[item] ?? item)].join(" ").toLowerCase().includes(query.trim().toLowerCase()));
475
- const detail = all.find((plugin) => plugin.packageName === detailName);
476
- const pending = data.jobs.filter((job) => ["queued", "installing"].includes(job.status)).length;
477
- const ready = all.filter((plugin) => plugin.recommendedVersion).length;
478
- const brand = data.brand ?? BRAND;
479
- return /* @__PURE__ */ import_react.default.createElement("section", { className: "hub-market", lang: language, style: { "--red": brand.primaryColor } }, /* @__PURE__ */ import_react.default.createElement("style", null, market_default), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-topline" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-brand" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-brandmark" }, brand.title.slice(0, 1)), brand.title, " ", /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-divider" }), " ", brand.subTitle), /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-runtime" }, /* @__PURE__ */ import_react.default.createElement("i", null), "DSH ", data.host.dsh)), /* @__PURE__ */ import_react.default.createElement("header", { className: "hub-header" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-eyebrow" }, t("\u63D2\u4EF6\u76EE\u5F55")), /* @__PURE__ */ import_react.default.createElement("h1", null, t("\u63D2\u4EF6\u5E02\u573A"), /* @__PURE__ */ import_react.default.createElement("span", null, t("\u3002"))), /* @__PURE__ */ import_react.default.createElement("p", null, t("\u627E\u5230\u9002\u5408\u5F53\u524D DSH \u7684\u5DE5\u5177\u3002"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-header-art" }, /* @__PURE__ */ import_react.default.createElement(Icon, { name: "box", size: 44 }), /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-art-plus" }, "+"), /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-art-dot" }))), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-stats" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("strong", null, all.length.toString().padStart(2, "0")), /* @__PURE__ */ import_react.default.createElement("span", null, t("\u6536\u5F55\u63D2\u4EF6"))), /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("strong", null, ready.toString().padStart(2, "0")), /* @__PURE__ */ import_react.default.createElement("span", null, t(data.lazyMetadata ? "\u5DF2\u786E\u8BA4\u53EF\u5B89\u88C5" : "\u6709\u53EF\u5B89\u88C5\u7248\u672C")))), /* @__PURE__ */ import_react.default.createElement("p", { className: "hub-footnote" }, t("\u51B7\u9759\u671F\uFF1A{minutes} \u5206\u949F \xB7 {source}", { minutes: data.minimumAgeMinutes, source: t(data.releaseAgeSource === "pnpm" ? "\u672C\u673A pnpm \u914D\u7F6E" : "\u9ED8\u8BA4 48 \u5C0F\u65F6") })), (data.lazyMetadata || data.metadataProgress?.running) && /* @__PURE__ */ import_react.default.createElement("p", null, t("\u5DF2\u67E5\u8BE2 {done} / {total} \u4E2A\u63D2\u4EF6\u7684\u7248\u672C", data.metadataProgress)), data.catalog.error && /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-notice amber" }, /* @__PURE__ */ import_react.default.createElement(Icon, { name: "clock" }), /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("b", null, t(data.catalog.stale ? "\u76EE\u5F55\u66F4\u65B0\u5931\u8D25\uFF0C\u7EE7\u7EED\u4F7F\u7528\u4E0A\u4E00\u4EFD\u6709\u6548\u6570\u636E" : "\u76EE\u5F55\u6682\u4E0D\u53EF\u7528")), /* @__PURE__ */ import_react.default.createElement("span", null, explain(data.catalog.error))), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", onClick: () => update() }, t("\u91CD\u8BD5"))), connectionError && /* @__PURE__ */ import_react.default.createElement("div", { role: "alert", className: "hub-notice red" }, /* @__PURE__ */ import_react.default.createElement("span", null, explain(connectionError)), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", onClick: () => update() }, t("\u91CD\u8BD5"))), error && error !== connectionError && /* @__PURE__ */ import_react.default.createElement("div", { role: "alert", className: "hub-notice red" }, /* @__PURE__ */ import_react.default.createElement("span", null, explain(error)), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", "aria-label": t("\u5173\u95ED\u9519\u8BEF"), onClick: () => setError(""), icon: /* @__PURE__ */ import_react.default.createElement(Icon, { name: "close" }) })), /* @__PURE__ */ import_react.default.createElement("nav", { className: "hub-tabs", "aria-label": t("\u63D2\u4EF6\u8303\u56F4") }, tabs.map(([key, label, count]) => /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { key, size: "sm", variant: activeTab === key ? "toolbar" : "ghost", "aria-pressed": activeTab === key, onClick: () => setTab(key) }, t(label), count !== null && /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-tab-count" }, count)))), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-toolbar" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Input, { className: "hub-search-input", icon: /* @__PURE__ */ import_react.default.createElement(Icon, { name: "search", size: 16 }), "aria-label": t("\u641C\u7D22\u63D2\u4EF6"), placeholder: t("\u641C\u7D22\u63D2\u4EF6\u3001\u7528\u9014\u6216\u7EF4\u62A4\u56E2\u961F"), value: query, onChange: (event) => setQuery(event.target.value) }), query && /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", "aria-label": t("\u6E05\u7A7A\u641C\u7D22"), onClick: () => setQuery(""), icon: /* @__PURE__ */ import_react.default.createElement(Icon, { name: "close", size: 14 }) }), /* @__PURE__ */ import_react.default.createElement(Picker, { label: t("\u6309\u6807\u7B7E\u7B5B\u9009"), value: tag, items: [{ id: "all", label: t("\u6240\u6709\u6807\u7B7E") }, ...Object.entries(tags).map(([id, label]) => ({ id, label }))], onChange: setTag, icon: /* @__PURE__ */ import_react.default.createElement(Icon, { name: "filter", size: 16 }) }), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { variant: "outline", size: "sm", disabled: loading, onClick: () => update(), title: t("\u5237\u65B0\u76EE\u5F55\u4E0E\u7248\u672C"), icon: /* @__PURE__ */ import_react.default.createElement(Icon, { name: "refresh", size: 16, className: loading ? "spinning" : "" }) }, t("\u5237\u65B0"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-results" }, /* @__PURE__ */ import_react.default.createElement("span", null, query ? t("\u201C{query}\u201D \u7684\u641C\u7D22\u7ED3\u679C", { query }) : t(selectedSource?.displayName ?? (activeTab === "installed" ? "\u4F60\u7684\u5DE5\u4F5C\u5DE5\u5177" : "\u4E3A\u56E2\u961F\u7CBE\u9009")), " ", /* @__PURE__ */ import_react.default.createElement("b", null, filtered.length)), /* @__PURE__ */ import_react.default.createElement("small", null, t("\u7248\u672C\u4FE1\u606F\u6765\u81EA npm \xB7 \u6309\u5F53\u524D DSH \u68C0\u67E5\u58F0\u660E"))), selectedSource?.error && /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-notice amber" }, /* @__PURE__ */ import_react.default.createElement("span", null, t(selectedSource.displayName), " \xB7 ", explain(selectedSource.error), selectedSource.stale && " \xB7 " + t("\u4F7F\u7528\u7F13\u5B58"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-grid" }, filtered.slice(0, visibleCount).map((plugin, index) => {
480
- const release = releaseOf(plugin);
481
- const state = status(plugin, release, t, data.minimumAgeHours);
482
- return /* @__PURE__ */ import_react.default.createElement("article", { className: "hub-card", key: plugin.packageName, style: { "--card-index": index } }, /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-card-top" }, /* @__PURE__ */ import_react.default.createElement("span", { className: `hub-plugin-icon icon-${plugin.tags[0]}` }, /* @__PURE__ */ import_react.default.createElement(Icon, { name: plugin.tags.includes("agent") ? "plug" : plugin.tags[0] === "knowledge" ? "book" : plugin.tags.includes("developer-tools") ? "code" : "box", size: 25 })), /* @__PURE__ */ import_react.default.createElement(Badge, { tone: state.tone }, state.label)), /* @__PURE__ */ import_react.default.createElement("h2", { className: "hub-card-heading" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", onClick: () => setDetailName(plugin.packageName) }, plugin.displayName, /* @__PURE__ */ import_react.default.createElement(Icon, { name: "arrow", size: 13 }))), /* @__PURE__ */ import_react.default.createElement("code", { className: "hub-card-package" }, plugin.packageName), (data.sources?.length ?? 0) > 1 && /* @__PURE__ */ import_react.default.createElement("small", { className: "hub-source-label" }, t("\u6765\u6E90"), " \xB7 ", t(plugin.catalogSource?.displayName ?? "")), /* @__PURE__ */ import_react.default.createElement("p", { className: "hub-description" }, plugin.description), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-tags" }, plugin.tags.map((item) => /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Pill, { key: item }, tags[item] ?? item))), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-version-row" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("\u9009\u62E9\u7248\u672C")), /* @__PURE__ */ import_react.default.createElement(Picker, { label: t("{name}\u7248\u672C", { name: plugin.displayName }), value: release?.version ?? "", disabled: !plugin.versions.length, items: plugin.versions.length ? plugin.versions.map((v) => ({ id: v.version, label: v.version + (v.version === plugin.recommendedVersion ? " \xB7 " + t("\u63A8\u8350") : "") })) : [{ id: "", label: t("\u6682\u4E0D\u53EF\u7528") }], onChange: (value) => setSelected((previous) => ({ ...previous, [plugin.packageName]: value })) })), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-version-note" }, plugin.queryError ? explain(plugin.queryError) : release?.canInstall ? t("\u53D1\u5E03\u4E8E {date}", { date: date(release.publishedAt) }) : explain(release?.reasons[0]) || t("\u6CA1\u6709\u53EF\u7528\u7248\u672C")), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-card-actions" }, installButton(plugin, release), uninstallButton(plugin)), documentLinks(plugin));
483
- })), filtered.length > visibleCount && /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-pagination" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { variant: "outline", size: "sm", onClick: () => setVisibleCount((value) => value + 40) }, t("\u52A0\u8F7D\u66F4\u591A"))), !filtered.length && /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-empty" }, /* @__PURE__ */ import_react.default.createElement(Icon, { name: "search", size: 32 }), /* @__PURE__ */ import_react.default.createElement("h3", null, t("\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u63D2\u4EF6")), /* @__PURE__ */ import_react.default.createElement("p", null, t("\u8BD5\u8BD5\u5176\u5B83\u5173\u952E\u8BCD\uFF0C\u6216\u6E05\u9664\u5F53\u524D\u7B5B\u9009\u6761\u4EF6\u3002")), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { variant: "outline", onClick: () => {
326
+ };
327
+ const run = (body, route) => {
328
+ void action(body, route).catch(() => {
329
+ });
330
+ };
331
+ const tabs = [{ id: "skills", label: "Skill" }, { id: "mcps", label: "MCP" }, { id: "plugins", label: "Plugin" }, { id: "experiments", label: t("\u5B9E\u9A8C\u6027\u529F\u80FD") }];
332
+ const rows = (data?.[tab] ?? []).filter((row) => [row.name, tab === "experiments" ? t(row.description) : row.description, row.source, row.directory, row.endpoint].filter(Boolean).join(" ").toLocaleLowerCase().includes(query.toLocaleLowerCase()));
333
+ const switchTab = (id) => {
334
+ setTab(id);
484
335
  setQuery("");
485
- setTag("all");
486
- setTab("all");
487
- } }, t("\u67E5\u770B\u5168\u90E8\u63D2\u4EF6"))), /* @__PURE__ */ import_react.default.createElement("footer", { className: "hub-footer" }, /* @__PURE__ */ import_react.default.createElement("span", null, /* @__PURE__ */ import_react.default.createElement("i", null), t("\u76EE\u5F55 {version} \xB7 \u66F4\u65B0\u4E8E {date}", { version: data.catalog.version ?? t("\u672A\u52A0\u8F7D"), date: date(data.catalog.updatedAt) })), /* @__PURE__ */ import_react.default.createElement("span", null, t("\u5E02\u573A v{version}", { version: data.marketVersion }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "hub-footnote" }, t("\u201C\u7B26\u5408\u5B89\u88C5\u6761\u4EF6\u201D\u4F9D\u636E\u7248\u672C\u58F0\u660E\u4E0E\u53D1\u5E03\u65F6\u95F4\uFF0C\u5B9E\u9645\u4E0B\u8F7D\u4ECD\u4EE5 Nexus \u4E3A\u51C6\u3002")), !!data.jobs.length && /* @__PURE__ */ import_react.default.createElement("aside", { className: "hub-queue" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-queue-summary" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-queue-icon" }, /* @__PURE__ */ import_react.default.createElement(Icon, { name: pending ? "download" : "check" })), /* @__PURE__ */ import_react.default.createElement("span", null, /* @__PURE__ */ import_react.default.createElement("b", null, pending ? t("{count} \u4E2A\u63D2\u4EF6\u64CD\u4F5C\u6B63\u5728\u6267\u884C", { count: pending }) : t("\u63D2\u4EF6\u64CD\u4F5C\u5DF2\u5B8C\u6210")), /* @__PURE__ */ import_react.default.createElement("small", null, t("{count} \u9879\u5F85\u624B\u52A8\u91CD\u542F\u751F\u6548", { count: data.pendingRestart }))), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", onClick: () => setShowJobs(!showJobs), "aria-expanded": showJobs }, t(showJobs ? "\u6536\u8D77" : "\u67E5\u770B\u4EFB\u52A1"))), showJobs && /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-jobs" }, data.jobs.slice().reverse().map((job) => /* @__PURE__ */ import_react.default.createElement("div", { key: job.id }, /* @__PURE__ */ import_react.default.createElement("span", null, /* @__PURE__ */ import_react.default.createElement("b", null, all.find((p) => p.packageName === job.packageName)?.displayName ?? job.packageName), /* @__PURE__ */ import_react.default.createElement("small", null, t(job.action === "uninstall" ? "\u5378\u8F7D" : "\u5B89\u88C5"), " \xB7 ", job.version)), /* @__PURE__ */ import_react.default.createElement(Badge, { tone: job.status === "completed" ? "green" : job.status === "failed" ? "red" : "amber" }, t({ queued: "\u6392\u961F\u4E2D", installing: job.action === "uninstall" ? "\u5378\u8F7D\u4E2D" : "\u5B89\u88C5\u4E2D", completed: "\u5F85\u91CD\u542F", failed: job.action === "uninstall" ? "\u5378\u8F7D\u5931\u8D25" : "\u5B89\u88C5\u5931\u8D25" }[job.status])), job.error && /* @__PURE__ */ import_react.default.createElement("p", null, explain(job.error)))))), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Modal, { open: Boolean(detail), onClose: () => setDetailName(null), title: detail?.displayName ?? "", closeLabel: t("\u5173\u95ED\u8BE6\u60C5"), className: "hub-detail-dialog", contentClassName: "hub-detail-scroll", description: detail?.description, footer: detail && /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-detail-actions" }, /* @__PURE__ */ import_react.default.createElement("div", null, installButton(detail, releaseOf(detail)), uninstallButton(detail)), documentLinks(detail)) }, detail && /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-detail-body" }, /* @__PURE__ */ import_react.default.createElement("code", { className: "hub-package-name" }, detail.packageName), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-detail-info" }, detail.owner && /* @__PURE__ */ import_react.default.createElement("span", null, t("\u7EF4\u62A4\u56E2\u961F"), /* @__PURE__ */ import_react.default.createElement("b", null, detail.owner)), /* @__PURE__ */ import_react.default.createElement("span", null, t("\u5F53\u524D\u5BBF\u4E3B"), /* @__PURE__ */ import_react.default.createElement("b", null, "DSH ", data.host.dsh))), /* @__PURE__ */ import_react.default.createElement("h3", null, t("\u53D1\u884C\u7248\u672C")), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-releases" }, detail.versions.map((release) => {
488
- const state = status(detail, release, t, data.minimumAgeHours);
489
- return /* @__PURE__ */ import_react.default.createElement("div", { key: release.version, className: "hub-release" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { variant: releaseOf(detail)?.version === release.version ? "toolbar" : "outline", size: "sm", "aria-pressed": releaseOf(detail)?.version === release.version, onClick: () => setSelected((previous) => ({ ...previous, [detail.packageName]: release.version })) }, release.version), /* @__PURE__ */ import_react.default.createElement(Badge, { tone: state.tone }, state.label)), /* @__PURE__ */ import_react.default.createElement("small", null, t("\u53D1\u5E03\u65F6\u95F4 {date} \xB7 DSH {range}", { date: date(release.publishedAt), range: release.dshRange ?? t(release.compatibilityBasis === "dshPluginHub.hostCompatibility" ? "\u4E0D\u6309\u7248\u672C\u9650\u5236\uFF0C\u8FD0\u884C\u65F6\u68C0\u67E5\u63A5\u53E3" : release.compatibilityBasis === "peerDependencies" ? "\u5BBF\u4E3B\u4F9D\u8D56\u58F0\u660E" : release.compatibilityBasis?.includes("dshReleases") ? "\u4F5C\u8005\u9010\u7248\u672C\u58F0\u660E" : "\u672A\u58F0\u660E") })), release.reasons.length > 0 && /* @__PURE__ */ import_react.default.createElement("p", null, release.reasons.map(explain).join(" \xB7 ")), release.age === "waiting" && /* @__PURE__ */ import_react.default.createElement("small", null, Number.isInteger(data.minimumAgeHours) ? t("\u9884\u8BA1\u6EE1 {hours} \u5C0F\u65F6\uFF1A{date}", { hours: data.minimumAgeHours, date: date(release.eligibleAt) }) : t("\u9884\u8BA1\u6EE1 {minutes} \u5206\u949F\uFF1A{date}", { minutes: data.minimumAgeMinutes, date: date(release.eligibleAt) })));
490
- }), detail.queryError && /* @__PURE__ */ import_react.default.createElement("p", null, explain(detail.queryError))))));
336
+ };
337
+ const activation = (state) => t({ active: "\u5DF2\u52A0\u8F7D", loading: "\u52A0\u8F7D\u4E2D", pending: "\u672A\u52A0\u8F7D", disabled: "\u5DF2\u7981\u7528", failed: "\u52A0\u8F7D\u5931\u8D25", disposed: "\u672A\u52A0\u8F7D", unloading: "\u52A0\u8F7D\u4E2D" }[state] ?? "\u672A\u77E5");
338
+ return /* @__PURE__ */ import_react.default.createElement("section", { className: `hub-resource-page ${file ? "with-file" : ""}`, "aria-label": brand.title }, /* @__PURE__ */ import_react.default.createElement("style", null, market_default, resources_default), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-market hub-resource-content", style: { "--red": brand.primaryColor } }, /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-topline" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-brand" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-brandmark" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.IconCordisPluginOutline14, { size: 17 })), brand.title, /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-divider" }), brand.subTitle), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "md", onClick: () => ctx.layout.selectPanel(null), icon: /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.IconCloseOutline16, null) }, t("\u8FD4\u56DE\u4F1A\u8BDD"))), /* @__PURE__ */ import_react.default.createElement("header", { className: "hub-header" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-eyebrow" }, "SKILLS \xB7 MCP \xB7 PLUGINS"), /* @__PURE__ */ import_react.default.createElement("h1", null, t("\u8D44\u6E90\u7BA1\u7406"), /* @__PURE__ */ import_react.default.createElement("span", null, ".")), /* @__PURE__ */ import_react.default.createElement("p", null, t("\u5728\u5F53\u524D\u5B9E\u4F8B\u4E2D\u7BA1\u7406 Skill\u3001MCP \u548C\u63D2\u4EF6\u3002"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-header-art", "aria-hidden": "true" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.IconCordisPluginOutline14, { size: 38 }), /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-art-plus" }, "+"), /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-art-dot" }))), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-resource-profile" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Pill, null, t("\u5F53\u524D profile"), " \xB7 ", data?.profile.name ?? "\u2026"), /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-resource-path", title: data?.profile.directory }, data?.profile.directory ?? "\u2026")), /* @__PURE__ */ import_react.default.createElement("div", { role: "tablist", className: "hub-tabs", "aria-label": brand.title, onKeyDown: (event) => {
339
+ const index = tabs.findIndex((row) => row.id === tab);
340
+ const next = event.key === "ArrowRight" ? (index + 1) % tabs.length : event.key === "ArrowLeft" ? (index + tabs.length - 1) % tabs.length : event.key === "Home" ? 0 : event.key === "End" ? tabs.length - 1 : -1;
341
+ if (next !== -1) {
342
+ event.preventDefault();
343
+ switchTab(tabs[next].id);
344
+ event.currentTarget.querySelectorAll('[role="tab"]')[next].focus();
345
+ }
346
+ } }, tabs.map((row) => /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { key: row.id, role: "tab", id: `${panelId}-${row.id}`, "aria-controls": `${panelId}-content`, "aria-selected": tab === row.id, tabIndex: tab === row.id ? 0 : -1, size: "md", className: "hub-resource-tab", onClick: () => switchTab(row.id) }, row.label, /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-tab-count" }, data?.[row.id]?.length ?? "\u2014")))), /* @__PURE__ */ import_react.default.createElement("div", { role: "tabpanel", id: `${panelId}-content`, "aria-labelledby": `${panelId}-${tab}` }, /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-toolbar" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Input, { className: "hub-search-input", icon: /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.IconSearchOutline16, null), "aria-label": t("\u641C\u7D22\u540D\u79F0\u3001\u63CF\u8FF0\u6216\u6765\u6E90"), placeholder: t("\u641C\u7D22\u540D\u79F0\u3001\u63CF\u8FF0\u6216\u6765\u6E90"), value: query, onChange: (event) => setQuery(event.target.value) }), tab === "skills" && /* @__PURE__ */ import_react.default.createElement(ScopePicker, { data, scope, setScope, t, disabled: busy }), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "md", disabled: busy, onClick: () => {
347
+ setBusy(true);
348
+ void refresh().finally(() => {
349
+ if (mounted.current) setBusy(false);
350
+ });
351
+ }, icon: /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.IconRefreshOutline16, null) }, t("\u5237\u65B0")), tab === "plugins" && data?.profile.installation === "desktop" && /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { onClick: () => setDesktopHelp(true) }, t("\u684C\u9762\u63D2\u4EF6\u7BA1\u7406")), tab === "mcps" && /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "md", variant: "primary", disabled: !data || busy, onClick: () => setEditor({}) }, t("\u6DFB\u52A0 MCP"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-results" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("\u5F53\u524D\u5217\u8868"), " ", /* @__PURE__ */ import_react.default.createElement("b", null, rows.length)), /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-resource-scope-note" }, t(tab === "skills" ? "\u5F00\u5173\u53EA\u5F71\u54CD\u5F53\u524D profile\uFF1BSkill \u6E90\u6587\u4EF6\u4FDD\u6301\u539F\u6837\u3002" : tab === "mcps" ? "MCP \u4E3A\u5F53\u524D profile \u7684\u5168\u5C40\u670D\u52A1\uFF1B\u5DE5\u4F5C\u533A\u8303\u56F4\u53EA\u7B5B\u9009 Skill\u3002" : tab === "plugins" ? "\u4EC5\u5C55\u793A\u5DF2\u5B89\u88C5\u7684\u975E\u5B98\u65B9\u63D2\u4EF6" : "\u5B9E\u9A8C\u6027\u529F\u80FD"))), error && /* @__PURE__ */ import_react.default.createElement("p", { role: "alert" }, t(error)), !data && !error && /* @__PURE__ */ import_react.default.createElement("p", { role: "status" }, t("\u6B63\u5728\u8BFB\u53D6\u8D44\u6E90")), data && tab === "skills" && !data.skillsComplete && /* @__PURE__ */ import_react.default.createElement("p", { role: "status" }, t("\u8D44\u6E90\u5C1A\u672A\u5B8C\u6574\u52A0\u8F7D\uFF0C\u8BF7\u5237\u65B0\u91CD\u8BD5")), /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-grid hub-resource-grid" }, rows.map((row) => /* @__PURE__ */ import_react.default.createElement("article", { key: row.id ?? row.name, className: "hub-card hub-resource-card" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-resource-card-heading" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-resource-identity" }, /* @__PURE__ */ import_react.default.createElement(ItemIcon, { row }), /* @__PURE__ */ import_react.default.createElement("h2", { className: "hub-resource-card-name", title: row.name }, row.name, (tab === "mcps" || tab === "plugins") && /* @__PURE__ */ import_react.default.createElement("span", { className: "hub-resource-version" }, "@", row.version || t("\u672A\u77E5")))), tab !== "plugins" && tab !== "experiments" ? /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Switch, { checked: Boolean(row.enabled), label: `${t(row.enabled ? "\u7981\u7528" : "\u542F\u7528")} ${row.name}`, disabled: busy || tab === "skills" && (!row.canToggle || !row.enabled && !row.managed), title: tab === "skills" && !row.canToggle ? t("\u6B64\u5F00\u5173\u7EE7\u627F\u81EA\u5176\u5B83\u8303\u56F4\uFF0C\u8BF7\u5207\u6362\u8303\u56F4\u4FEE\u6539") : void 0, onChange: (enabled) => run({ action: tab === "skills" ? "skill-toggle" : "mcp-toggle", id: row.id, revision: row.revision, enabled }) }) : tab === "experiments" ? /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Switch, { checked: Boolean(row.enabled), label: `${t(row.enabled ? "\u7981\u7528" : "\u542F\u7528")} ${row.name}`, disabled: busy || !row.canToggle, onChange: (enabled) => {
352
+ setBusy(true);
353
+ void request("experiment-mutate", { id: row.id, enabled, profile: data.profile.directory }).then(() => refresh()).catch((error2) => setError(error2.message)).finally(() => setBusy(false));
354
+ } }) : null), tab === "mcps" && /* @__PURE__ */ import_react.default.createElement(McpSummary, { row, t, activation }), /* @__PURE__ */ import_react.default.createElement("p", { className: "hub-description", title: tab === "experiments" ? t(row.description) : row.description }, (tab === "experiments" ? t(row.description) : row.description) || t(tab === "mcps" ? "\u670D\u52A1\u5C1A\u672A\u63D0\u4F9B\u63CF\u8FF0\uFF0C\u53EF\u6D4B\u8BD5\u8FDE\u63A5\u8BFB\u53D6\u3002" : "\u6682\u65E0\u63CF\u8FF0")), tab === "mcps" && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, row.probe && /* @__PURE__ */ import_react.default.createElement("p", { className: "hub-resource-meta" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Pill, null, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.StateDot, { state: row.probe.status === "success" ? "done" : "error" }), " ", t(row.probe.status === "success" ? "\u6D4B\u8BD5\u6210\u529F" : "\u6D4B\u8BD5\u5931\u8D25"), " \xB7 ", new Date(row.probe.at).toLocaleTimeString(), row.probe.tools !== void 0 && ` \xB7 ${t("\u5DE5\u5177\u6570")} ${row.probe.tools}`))), tab === "experiments" && /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-resource-actions" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Pill, null, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.StateDot, { state: row.pendingRestart ? "warning" : row.enabled ? "done" : "idle" }), t(row.pendingRestart ? "\u91CD\u542F DSH \u540E\u751F\u6548" : row.enabled === null ? "\u672A\u77E5" : row.enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u7981\u7528")), !row.installed && /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", disabled: busy || !row.canInstall, onClick: () => {
355
+ setBusy(true);
356
+ void request("experiment-mutate", { id: row.id, action: "install", profile: data.profile.directory }).then(() => refresh()).catch((error2) => setError(error2.message)).finally(() => setBusy(false));
357
+ } }, t("\u5B89\u88C5 Agent Teams")), data.profile.installation === "desktop" && /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", onClick: () => setDesktopHelp(true) }, t("\u684C\u9762\u63D2\u4EF6\u7BA1\u7406"))), tab !== "experiments" && /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-resource-card-footer" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-resource-actions" }, tab === "plugins" && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", disabled: busy, icon: /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.IconFolderOpenOutline16, null), onClick: () => run({ id: row.name, kind: "plugin" }, "open-directory") }, t("\u6253\u5F00\u76EE\u5F55"))), tab === "skills" && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", disabled: !row.directory || busy, onClick: () => {
358
+ setBusy(true);
359
+ void action({ id: row.id }, "skill-file").then(setFile).catch(() => {
360
+ });
361
+ } }, t("\u67E5\u770B SKILL.md")), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", disabled: !row.directory || busy, onClick: () => run({ id: row.id }, "open-directory"), icon: /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.IconFolderOpenOutline16, null) }, t("\u6253\u5F00\u76EE\u5F55"))), tab === "mcps" && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Tooltip, { label: t("\u72EC\u7ACB\u6D4B\u8BD5\u4F1A\u4E34\u65F6\u8FDE\u63A5\u670D\u52A1\u5E76\u8BFB\u53D6\u5DE5\u5177\u5217\u8868\uFF0C\u4E0D\u6267\u884C\u5DE5\u5177\u3002") }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", disabled: busy || !row.enabled, onClick: () => run({ id: row.id, revision: row.revision }, "mcp-test") }, t("\u6D4B\u8BD5\u8FDE\u63A5"))), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", disabled: busy || !row.enabled, onClick: () => run({ action: "mcp-reconnect", id: row.id, revision: row.revision }) }, t("\u91CD\u65B0\u8FDE\u63A5")), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", disabled: busy, onClick: () => setEditor(row) }, t("\u7F16\u8F91")), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Tooltip, { label: row.canDelete ? t("\u5220\u9664") : t("\u6765\u81EA\u5171\u4EAB\u914D\u7F6E\u6216\u5BBF\u4E3B\u5305\uFF0C\u8BF7\u5728\u6765\u6E90\u5904\u5220\u9664") }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { size: "sm", disabled: busy || !row.canDelete, onClick: () => setDeleting(row) }, t("\u5220\u9664"))))), /* @__PURE__ */ import_react.default.createElement("p", { className: "hub-resource-path hub-resource-source", title: row.directory ?? row.source }, t("\u6765\u6E90"), " \xB7 ", row.directory ?? row.source))))), data && !rows.length && /* @__PURE__ */ import_react.default.createElement("p", { className: "hub-resource-empty" }, t("\u672A\u627E\u5230\u5339\u914D\u8D44\u6E90")))), file && /* @__PURE__ */ import_react.default.createElement(SkillPreview, { key: file.path, file, t, close: () => setFile(null) }), /* @__PURE__ */ import_react.default.createElement(ResourceModal, { className: "hub-resource-dialog", open: desktopHelp, title: t("\u684C\u9762\u63D2\u4EF6\u7BA1\u7406"), closeLabel: t("\u5173\u95ED"), onClose: () => setDesktopHelp(false) }, /* @__PURE__ */ import_react.default.createElement("p", null, t("\u5F53\u524D DSH \u4E3B\u7A97\u53E3\u672A\u63D0\u4F9B\u6253\u5F00\u7BA1\u7406\u7A97\u53E3\u7684\u63A5\u53E3\u3002\u8BF7\u4F7F\u7528\u7CFB\u7EDF\u83DC\u5355\u7684 Desktop Plugins\uFF0C\u6216\u6309"), " ", /* @__PURE__ */ import_react.default.createElement("kbd", null, data?.profile.platform === "darwin" ? "\u2318 ," : "Ctrl+,"))), editor && /* @__PURE__ */ import_react.default.createElement(McpEditor, { request, profile: data.profile.directory, row: editor.id ? editor : null, t, busy, close: () => setEditor(null), save: async (body) => {
362
+ await action(body);
363
+ setEditor(null);
364
+ } }), /* @__PURE__ */ import_react.default.createElement(ResourceModal, { className: "hub-resource-dialog", contentClassName: "hub-resource-dialog-scroll", open: Boolean(deleting), title: t("\u786E\u8BA4\u5220\u9664"), closeLabel: t("\u5173\u95ED"), onClose: () => setDeleting(null), footer: /* @__PURE__ */ import_react.default.createElement("div", { className: "hub-resource-actions" }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { disabled: busy, onClick: () => setDeleting(null) }, t("\u53D6\u6D88")), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { variant: "primary", disabled: busy, onClick: () => {
365
+ void action({ action: "mcp-delete", id: deleting.id, revision: deleting.revision }).then(() => setDeleting(null)).catch(() => {
366
+ });
367
+ } }, t("\u5220\u9664"))) }, /* @__PURE__ */ import_react.default.createElement("p", null, deleting?.name), /* @__PURE__ */ import_react.default.createElement("p", null, t("\u5220\u9664\u4F1A\u65AD\u5F00\u8BE5 MCP\uFF0C\u5E76\u79FB\u9664\u5BF9\u5E94\u7684\u914D\u7F6E\u6761\u76EE\u3002"))));
368
+ }
369
+ function HubSidebarButton({ wide, usePanelInfo, ctx, panelId, brand }) {
370
+ const selected = usePanelInfo((state) => state.activePanelId === panelId);
371
+ return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("style", null, resources_default), /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Tooltip, { label: brand.navTitle, disabled: wide }, /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.Button, { className: `hub-sidebar-button ${wide ? "is-wide" : "is-rail"}`, "aria-label": brand.navTitle, "aria-pressed": selected, icon: /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.IconCordisPluginOutline14, { size: 18 }), onClick: () => ctx.layout.selectPanel(selected ? null : panelId) }, wide && /* @__PURE__ */ import_react.default.createElement("span", null, brand.navTitle))));
491
372
  }
373
+
374
+ // src/client/locale.js
375
+ var resourceWords = {
376
+ "HTTP \u5FC5\u586B": "Required for HTTP",
377
+ "HTTP \u8BF7\u6C42\u5934\uFF0C\u53EF\u5F15\u7528\u73AF\u5883\u53D8\u91CF\u3002": "HTTP request headers; environment references are supported.",
378
+ "Hub profile \u914D\u7F6E\u4E0E\u5F53\u524D\u5B9E\u4F8B\u4E0D\u4E00\u81F4": "Hub's configured profile does not match this instance.",
379
+ "Hub \u6B63\u5728\u5173\u95ED": "Hub is shutting down.",
380
+ "Hub \u8D44\u6E90\u914D\u7F6E\u4E0D\u53EF\u8BFB\u53D6\uFF0C\u5DF2\u505C\u6B62\u7BA1\u7406\uFF0C\u539F\u6587\u4EF6\u672A\u6539\u52A8": "Hub cannot read its resource configuration. Management is stopped and the original file is unchanged.",
381
+ "Hub \u8D44\u6E90\u914D\u7F6E\u683C\u5F0F\u65E0\u6548": "Hub resource configuration is invalid.",
382
+ "Hub \u914D\u7F6E\u76EE\u5F55\u4E0D\u5728\u5F53\u524D profile \u5185": "The Hub configuration directory is outside this profile.",
383
+ "JSON / YAML \u683C\u5F0F\u65E0\u6548\uFF0C\u8BF7\u68C0\u67E5\u7F29\u8FDB\u3001\u5F15\u53F7\u548C\u91CD\u590D\u5B57\u6BB5": "Invalid JSON or YAML. Check indentation, quotes and duplicate fields.",
384
+ "MCP URL \u5FC5\u987B\u4F7F\u7528 HTTP(S)\uFF0C\u51ED\u636E\u8BF7\u653E\u5165 headers": "The MCP URL must use HTTP(S). Put credentials in headers.",
385
+ "MCP \u4E3A\u5F53\u524D profile \u7684\u5168\u5C40\u670D\u52A1\uFF1B\u5DE5\u4F5C\u533A\u8303\u56F4\u53EA\u7B5B\u9009 Skill\u3002": "MCP services belong to this profile. The workspace selector filters Skills only.",
386
+ "MCP \u540D\u79F0\u53EA\u5141\u8BB8 1\u201332 \u4F4D\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\u548C\u8FDE\u5B57\u7B26": "MCP names must contain 1\u201332 letters, digits, underscores or hyphens.",
387
+ "MCP \u5DF2\u4E0D\u5B58\u5728": "This MCP no longer exists.",
388
+ "MCP \u914D\u7F6E": "MCP configuration",
389
+ "MCP \u914D\u7F6E\u5DF2\u53D8\u5316\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5": "The MCP configuration has changed. Refresh and try again.",
390
+ "MCP \u914D\u7F6E\u5E2E\u52A9": "MCP configuration help",
391
+ "MCP \u914D\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61": "MCP configuration must be an object.",
392
+ "Skill \u6587\u4EF6\u4E0D\u5728\u6765\u6E90\u76EE\u5F55\u5185": "The Skill file is outside its source directory.",
393
+ "Skill \u6587\u4EF6\u8FC7\u5927\uFF0C\u8BF7\u6253\u5F00\u76EE\u5F55\u67E5\u770B": "The Skill file is too large to preview. Open its directory to view it.",
394
+ "Streamable HTTP \u5730\u5740\u3002": "The Streamable HTTP endpoint URL.",
395
+ "args \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4": "args must be an array of strings.",
396
+ "cwd \u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84": "cwd must be an absolute path.",
397
+ "env / headers \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u952E\u503C\u5BF9\u8C61": "env and headers must be objects with string values.",
398
+ "failOnStartupError \u5FC5\u987B\u662F\u5E03\u5C14\u503C": "failOnStartupError must be a boolean.",
399
+ "reconnect \u914D\u7F6E\u65E0\u6548": "Invalid reconnect configuration.",
400
+ "stdio \u4E3A\u672C\u5730\u8FDB\u7A0B\uFF1Bstreamable-http \u4E3A HTTP \u670D\u52A1\u3002": "stdio runs a local process; streamable-http connects to an HTTP service.",
401
+ "stdio \u53EF\u6267\u884C\u6587\u4EF6\uFF1BWindows \u53EF\u4F7F\u7528 node.exe \u7684\u5B8C\u6574\u8DEF\u5F84\u3002": "The stdio executable. On Windows, a full path to node.exe is supported.",
402
+ "stdio \u5DE5\u4F5C\u76EE\u5F55\uFF0C\u7559\u7A7A\u4F7F\u7528\u5BBF\u4E3B\u5DE5\u4F5C\u76EE\u5F55\u3002": "The stdio working directory. Leave empty to use the host's working directory.",
403
+ "stdio \u5FC5\u586B": "Required for stdio",
404
+ "type \u4E0E transport \u4E0D\u4E00\u81F4": "type and transport do not match.",
405
+ "\u4E00\u6B21\u8FDE\u63A5\u6545\u969C\u7684\u8FDE\u7EED\u91CD\u8BD5\u6B21\u6570\u4E0A\u9650\u3002": "Maximum consecutive retries for one connection failure.",
406
+ "\u4E0B\u5217\u9ED8\u8BA4\u503C\u7531 DSH \u63D0\u4F9B\uFF1B\u5207\u6362\u683C\u5F0F\u4E0D\u4F1A\u8865\u5165\u8FD9\u4E9B\u5B57\u6BB5\u3002": "DSH supplies these defaults. Switching formats does not insert them.",
407
+ "\u4E0D\u652F\u6301\u7684 MCP \u534F\u8BAE": "Unsupported MCP transport.",
408
+ "\u4EC5\u5C55\u793A\u5DF2\u5B89\u88C5\u7684\u975E\u5B98\u65B9\u63D2\u4EF6": "Installed third-party plugins only",
409
+ "\u4EC5\u652F\u6301 process.env.NAME \u6216\u5E26\u6B64\u524D\u7F00\u7684\u6A21\u677F\u5B57\u7B26\u4E32\uFF0C\u4E0D\u6267\u884C\u4EFB\u610F JavaScript": "Only process.env.NAME and literal templates containing that reference are supported. Arbitrary JavaScript is not executed.",
410
+ "\u4F20\u7ED9\u53EF\u6267\u884C\u6587\u4EF6\u7684\u5B57\u7B26\u4E32\u6570\u7EC4\uFF0C\u4E0D\u7ECF\u8FC7 shell\u3002": "An array of arguments passed directly to the executable, without a shell.",
411
+ "\u4FDD\u5B58": "Save",
412
+ "\u5168\u5C40": "Global",
413
+ "\u5173\u95ED": "Close",
414
+ "\u521D\u59CB\u5316\u5931\u8D25\u65F6\u662F\u5426\u8BA9\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25\u3002": "Whether initialization errors cause plugin activation to fail.",
415
+ "\u5220\u9664": "Delete",
416
+ "\u5220\u9664\u4F1A\u65AD\u5F00\u8BE5 MCP\uFF0C\u5E76\u79FB\u9664\u5BF9\u5E94\u7684\u914D\u7F6E\u6761\u76EE\u3002": "Deleting disconnects this MCP and removes its configuration entry.",
417
+ "\u5237\u65B0": "Refresh",
418
+ "\u52A0\u8F7D\u4E2D": "Loading",
419
+ "\u52A0\u8F7D\u5931\u8D25": "Activation failed",
420
+ "\u52A0\u8F7D\u672A\u77E5": "Activation unknown",
421
+ "\u52A0\u8F7D\u72B6\u6001": "Activation",
422
+ "\u5355\u6B21\u5DE5\u5177\u8C03\u7528\u8D85\u65F6\uFF0C\u5355\u4F4D\u6BEB\u79D2\u3002": "Timeout for each tool call, in milliseconds.",
423
+ "\u539F\u751F DSH \u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u786E\u8BA4\u6B64 DSH \u7248\u672C\u63D0\u4F9B Agent Teams \u5305": "Native DSH installation failed. Check whether this DSH version provides Agent Teams packages.",
424
+ "\u53D6\u6D88": "Cancel",
425
+ "\u542F\u7528": "Enable",
426
+ "\u5728\u5F53\u524D\u5B9E\u4F8B\u4E2D\u7BA1\u7406 Skill\u3001MCP \u548C\u63D2\u4EF6\u3002": "Manage Skills, MCPs and plugins in this instance.",
427
+ "\u590D\u5236": "Copy",
428
+ "\u5B89\u88C5 Agent Teams": "Install Agent Teams",
429
+ "\u5B89\u88C5\u8D85\u65F6\uFF0C\u8BF7\u68C0\u67E5 DSH \u63D2\u4EF6\u7BA1\u7406\u72B6\u6001": "Installation timed out. Check DSH's plugin management status.",
430
+ "\u5B9E\u4F8B profile \u5DF2\u53D8\u5316\uFF0C\u8BF7\u5237\u65B0": "The instance profile has changed. Refresh to continue.",
431
+ "\u5B9E\u4F8B profile \u5DF2\u53D8\u5316\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5": "The instance profile has changed. Refresh and try again.",
432
+ "\u5B9E\u4F8B\u6216\u529F\u80FD\u5DF2\u53D8\u5316\uFF0C\u8BF7\u5237\u65B0": "The instance or feature has changed. Refresh to continue.",
433
+ "\u5B9E\u9A8C\u6027\u529F\u80FD": "Experimental",
434
+ "\u5B9E\u9A8C\u6027\u529F\u80FD\u6B63\u5728\u66F4\u65B0": "An experimental feature is being updated.",
435
+ "\u5B9E\u9A8C\u6027\u591A Agent \u534F\u4F5C\u5DE5\u5177\u4E0E\u56E2\u961F\u9762\u677F\u3002\u5207\u6362\u540E\u9700\u91CD\u542F DSH\uFF0C\u4F1A\u8BDD\u6570\u636E\u4FDD\u7559\u3002": "Experimental multi-agent tools and team panel. Changes require restarting DSH; conversations are preserved.",
436
+ "\u5BBF\u4E3B\u65E0\u6CD5\u6253\u5F00\u76EE\u5F55\uFF0C\u8BF7\u6839\u636E\u6765\u6E90\u8DEF\u5F84\u624B\u52A8\u6253\u5F00": "The host could not open the directory. Open it manually using the source path.",
437
+ "\u5BBF\u4E3B\u672A\u516C\u5F00\u6301\u7EED\u8FDE\u63A5\u72B6\u6001\uFF1B\u5DF2\u52A0\u8F7D\u4E0D\u4EE3\u8868\u8FDE\u63A5\u6210\u529F\u3002": "The host does not expose continuous connection status. Activation does not imply a successful connection.",
438
+ "\u5DE5\u5177\u547D\u540D\u7A7A\u95F4\uFF0C1\u201332 \u4F4D\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\u6216\u8FDE\u5B57\u7B26\u3002": "Tool namespace: 1\u201332 letters, digits, underscores or hyphens.",
439
+ "\u5DE5\u5177\u6570": "Tools",
440
+ "\u5DF2\u52A0\u8F7D": "Loaded",
441
+ "\u5DF2\u542F\u7528": "Enabled",
442
+ "\u5DF2\u590D\u5236": "Copied",
443
+ "\u5DF2\u7981\u7528": "Disabled",
444
+ "\u5E2E\u52A9": "Help",
445
+ "\u5F00\u5173\u53EA\u5F71\u54CD\u5F53\u524D profile\uFF1BSkill \u6E90\u6587\u4EF6\u4FDD\u6301\u539F\u6837\u3002": "Toggles apply to this profile. Skill source files are preserved.",
446
+ "\u5F53\u524D DSH \u4E3B\u7A97\u53E3\u672A\u63D0\u4F9B\u6253\u5F00\u7BA1\u7406\u7A97\u53E3\u7684\u63A5\u53E3\u3002\u8BF7\u4F7F\u7528\u7CFB\u7EDF\u83DC\u5355\u7684 Desktop Plugins\uFF0C\u6216\u6309": "This DSH main window has no API for opening the manager. Choose Desktop Plugins in the application menu, or press",
447
+ "\u5F53\u524D MCP \u6CA1\u6709\u53EF\u7528\u7684\u5DF2\u89E3\u6790\u914D\u7F6E\uFF0C\u8BF7\u5148\u542F\u7528": "This MCP has no available resolved configuration. Enable it first.",
448
+ "\u5F53\u524D MCP \u6CA1\u6709\u53EF\u7F16\u8F91\u7684\u914D\u7F6E": "This MCP has no editable configuration.",
449
+ "\u5F53\u524D profile": "Current profile",
450
+ "\u5F53\u524D profile \u5DF2\u6709\u540C\u540D MCP": "An MCP with this name already exists in this profile.",
451
+ "\u5F53\u524D profile \u672A\u63D0\u4F9B\u539F\u751F bundle \u5217\u8868": "This profile does not provide a native bundle list.",
452
+ "\u5F53\u524D\u5217\u8868": "Current list",
453
+ "\u5F53\u524D\u5B9E\u4F8B\u6CA1\u6709\u8FD9\u4E2A\u5DE5\u4F5C\u533A\uFF0C\u8BF7\u5237\u65B0": "This workspace is not available in the current instance. Refresh to continue.",
454
+ "\u5FC5\u586B": "Required",
455
+ "\u6253\u5F00\u76EE\u5F55": "Open directory",
456
+ "\u63A5\u53E3\u4E0D\u5B58\u5728": "This API endpoint does not exist.",
457
+ "\u63A8\u8350\u5728\u542F\u52A8 DSH \u7684\u73AF\u5883\u4E2D\u8BBE\u7F6E\u51ED\u636E\u3002YAML \u4F7F\u7528": "Set credentials in the environment used to start DSH. In YAML, use",
458
+ "\u641C\u7D22\u540D\u79F0\u3001\u63CF\u8FF0\u6216\u6765\u6E90": "Search name, description or source",
459
+ "\u65E0\u6548\u6216\u8FC7\u5927\u7684\u8BF7\u6C42": "Invalid request or request too large.",
460
+ "\u65E0\u6548\u7684\u5F00\u5173\u503C": "Invalid toggle value.",
461
+ "\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D\u5B9E\u4F8B\u7684 profile\uFF0C\u5DF2\u505C\u6B62\u7BA1\u7406\u64CD\u4F5C": "Cannot identify this instance's profile. Management operations are disabled.",
462
+ "\u663E\u5F0F\u4F20\u7ED9\u670D\u52A1\u7684\u73AF\u5883\u53D8\u91CF\uFF0C\u53EF\u7528 !!js process.env.NAME \u5F15\u7528\u3002": "Environment variables passed to the server. Use !!js process.env.NAME for references.",
463
+ "\u6682\u65E0\u63CF\u8FF0": "No description",
464
+ "\u670D\u52A1\u5C1A\u672A\u63D0\u4F9B\u63CF\u8FF0\uFF0C\u53EF\u6D4B\u8BD5\u8FDE\u63A5\u8BFB\u53D6\u3002": "No server description available. Test the connection to retrieve it.",
465
+ "\u672A\u52A0\u8F7D": "Not loaded",
466
+ "\u672A\u627E\u5230\u5339\u914D\u8D44\u6E90": "No matching resources",
467
+ "\u672A\u77E5": "Unknown",
468
+ "\u672A\u77E5\u7684\u8D44\u6E90\u64CD\u4F5C": "Unknown resource action.",
469
+ "\u6765\u6E90": "Source",
470
+ "\u6765\u6E90\u914D\u7F6E\u5DF2\u53D8\u5316\uFF0C\u8BF7\u5237\u65B0\u91CD\u8BD5": "The source configuration has changed. Refresh and try again.",
471
+ "\u6765\u81EA\u5171\u4EAB\u914D\u7F6E\u6216\u5BBF\u4E3B\u5305\uFF0C\u8BF7\u5728\u6765\u6E90\u5904\u5220\u9664": "Defined in shared configuration or a host package. Delete it at its source.",
472
+ "\u67E5\u770B SKILL.md": "View SKILL.md",
473
+ "\u683C\u5F0F\u5316": "Format",
474
+ "\u683C\u5F0F\u5FC5\u987B\u4E3A JSON \u6216 YAML": "The format must be JSON or YAML.",
475
+ "\u684C\u9762\u63D2\u4EF6\u7BA1\u7406": "Desktop Plugins",
476
+ "\u6B63\u5728\u8BFB\u53D6\u8D44\u6E90": "Loading resources",
477
+ "\u6B63\u5728\u8BFB\u53D6\u914D\u7F6E": "Loading configuration",
478
+ "\u6B64 MCP \u6765\u81EA\u5171\u4EAB\u914D\u7F6E\u6216\u5BBF\u4E3B\u5305\uFF0C\u8BF7\u5728\u6765\u6E90\u5904\u5220\u9664\uFF1BHub \u53EF\u7981\u7528\u5B83": "This MCP comes from shared configuration or a host package. Delete it at its source; Hub can disable it.",
479
+ "\u6B64 Skill \u6CA1\u6709\u672C\u5730\u6587\u4EF6": "This Skill has no local file.",
480
+ "\u6B64 Skill \u7684\u5F00\u5173\u5C5E\u4E8E\u5176\u5B83\u4F5C\u7528\u57DF\uFF0C\u8BF7\u5207\u6362\u8303\u56F4": "This Skill's toggle belongs to another scope. Switch scopes to change it.",
481
+ "\u6B64\u5F00\u5173\u7EE7\u627F\u81EA\u5176\u5B83\u8303\u56F4\uFF0C\u8BF7\u5207\u6362\u8303\u56F4\u4FEE\u6539": "This toggle is inherited. Switch to its owning scope to change it.",
482
+ "\u6B64\u9884\u8BBE\u6CA1\u6709\u539F\u751F Skill \u6216 MCP \u8D44\u6E90": "This preset has no native Skill or MCP resources.",
483
+ "\u6BCF\u6B21\u8BF7\u7C98\u8D34\u4E00\u4E2A mcpServers \u670D\u52A1\u914D\u7F6E": "Paste exactly one server configuration under mcpServers.",
484
+ "\u6D4B\u8BD5\u5931\u8D25": "Test failed",
485
+ "\u6D4B\u8BD5\u6210\u529F": "Test passed",
486
+ "\u6D4B\u8BD5\u8FDE\u63A5": "Test connection",
487
+ "\u6DFB\u52A0 MCP": "Add MCP",
488
+ "\u72EC\u7ACB\u6D4B\u8BD5\u4F1A\u4E34\u65F6\u8FDE\u63A5\u670D\u52A1\u5E76\u8BFB\u53D6\u5DE5\u5177\u5217\u8868\uFF0C\u4E0D\u6267\u884C\u5DE5\u5177\u3002": "A separate test temporarily connects and lists tools without executing them.",
489
+ "\u73AF\u5883\u53D8\u91CF\u5F15\u7528\u65E0\u6548": "Invalid environment variable reference.",
490
+ "\u786E\u8BA4\u5220\u9664": "Confirm deletion",
491
+ "\u7981\u7528": "Disable",
492
+ "\u7F16\u8F91": "Edit",
493
+ "\u811A\u6CE8": "Footnotes",
494
+ "\u8981\u6C42": "Requirement",
495
+ "\u8BF7\u4EC5\u7F16\u8F91 MCP \u7684 config \u6BB5\uFF0C\u542F\u505C\u4F7F\u7528\u5361\u7247\u5F00\u5173": "Edit only the MCP config section. Use the card's switch to enable or disable it.",
496
+ "\u8BF7\u5148\u542F\u7528 MCP": "Enable the MCP first.",
497
+ "\u8BF7\u5148\u5B89\u88C5 Agent Teams": "Install Agent Teams first.",
498
+ "\u8BF7\u63D0\u4F9B\u4E00\u4E2A MCP \u914D\u7F6E\u5BF9\u8C61": "Provide one MCP configuration object.",
499
+ "\u8BF7\u901A\u8FC7 Desktop \u539F\u751F\u63D2\u4EF6\u7BA1\u7406\u7A97\u53E3\u5207\u6362 Agent Teams": "Use the native Desktop Plugins window to toggle Agent Teams.",
500
+ "\u8D44\u6E90\u5C1A\u672A\u5B8C\u6574\u52A0\u8F7D\uFF0C\u8BF7\u5237\u65B0\u91CD\u8BD5": "Resource discovery is incomplete. Refresh to retry.",
501
+ "\u8D44\u6E90\u7BA1\u7406": "Resource management",
502
+ "\u8D44\u6E90\u8303\u56F4": "Resource scope",
503
+ "\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u5728 1000\u2013300000 \u6BEB\u79D2\u4E4B\u95F4": "The timeout must be between 1000 and 300000 milliseconds.",
504
+ "\u8FD4\u56DE\u4F1A\u8BDD": "Back to conversation",
505
+ "\u8FD9\u4E2A\u8D44\u6E90\u6CA1\u6709\u672C\u5730\u76EE\u5F55": "This resource has no local directory.",
506
+ "\u8FDE\u63A5\u4E22\u5931\u540E\u81EA\u52A8\u91CD\u8FDE\u3002": "Reconnect automatically after losing the connection.",
507
+ "\u8FDE\u63A5\u672A\u77E5": "Connection unknown",
508
+ "\u914D\u7F6E\u4E0D\u652F\u6301 YAML \u522B\u540D": "YAML aliases are not supported in configuration.",
509
+ "\u914D\u7F6E\u5305\u542B\u5BBF\u4E3B\u4E0D\u652F\u6301\u7684\u5B57\u6BB5\uFF0C\u8BF7\u6838\u5BF9 MCP \u914D\u7F6E": "The configuration contains unsupported fields. Check the MCP configuration.",
510
+ "\u914D\u7F6E\u6587\u672C\u6700\u957F 24000 \u5B57\u7B26": "Configuration text must not exceed 24000 characters.",
511
+ "\u914D\u7F6E\u683C\u5F0F": "Configuration format",
512
+ "\u91CD\u542F DSH \u540E\u751F\u6548": "Takes effect after restarting DSH",
513
+ "\u91CD\u65B0\u8FDE\u63A5": "Reconnect",
514
+ "\u91CD\u8FDE\u521D\u59CB\u95F4\u9694\u4E0D\u80FD\u8D85\u8FC7\u6700\u5927\u95F4\u9694": "The initial reconnect delay must not exceed the maximum delay.",
515
+ "\u91CD\u8FDE\u7B49\u5F85\u4E0A\u9650\uFF0C\u5355\u4F4D\u6BEB\u79D2\u3002": "Maximum reconnect delay, in milliseconds.",
516
+ "\u9700\u8981\u6709\u6548\u7684 MCP URL": "A valid MCP URL is required.",
517
+ "\u9700\u8981\u6709\u6548\u7684\u53EF\u6267\u884C\u547D\u4EE4": "A valid executable command is required.",
518
+ "\u9996\u6B21\u91CD\u8FDE\u7B49\u5F85\u6BEB\u79D2\u6570\uFF0C\u4E4B\u540E\u6307\u6570\u9012\u589E\u3002": "Initial reconnect delay in milliseconds; subsequent delays increase exponentially.",
519
+ "\u9ED8\u8BA4\u503C": "Default",
520
+ "\uFF1BJSON \u4F7F\u7528": "; in JSON, use",
521
+ "\u542F\u52A8 DSH \u7684\u73AF\u5883\u4E2D\u672A\u8BBE\u7F6E {name}": "{name} is not set in the environment used to start DSH."
522
+ };
523
+ function translate(localize) {
524
+ return (text) => {
525
+ const environment = /^启动 DSH 的环境中未设置 ([A-Za-z_][A-Za-z0-9_]*)$/.exec(text);
526
+ if (environment) return localize("\u542F\u52A8 DSH \u7684\u73AF\u5883\u4E2D\u672A\u8BBE\u7F6E {name}").replace("{name}", environment[1]);
527
+ return localize(text);
528
+ };
529
+ }
530
+
531
+ // src/client/api.js
532
+ var RequestError = class extends Error {
533
+ constructor(message) {
534
+ super(message);
535
+ this.name = "RequestError";
536
+ }
537
+ };
538
+ function connectionRequest(connection, marketId) {
539
+ const endpoint = "dshPluginHub_" + marketId.replaceAll("-", "_") + "/";
540
+ return async (path, data = {}, { signal } = {}) => {
541
+ const deadline = signal ? AbortSignal.any([signal, AbortSignal.timeout(path === "experiment-mutate" ? 37e4 : 2e4)]) : AbortSignal.timeout(path === "experiment-mutate" ? 37e4 : 2e4);
542
+ const result = await connection.rpc.call("/api", endpoint + path, data, deadline);
543
+ if (!result.ok) throw new RequestError(result.error.message);
544
+ return result.value;
545
+ };
546
+ }
547
+
548
+ // src/client/index.jsx
549
+ var NS = "@zaimokuza/dsh-plugin-hub";
550
+ var MARKET_ID = "hub";
551
+ var BRAND = define_HUB_BRAND_default;
492
552
  var name = NS;
493
- var inject = ["slots", "locale"];
553
+ var inject = ["slots", "locale", "layout", "connection"];
494
554
  function apply(ctx) {
555
+ const words = { zh: Object.fromEntries(Object.keys(resourceWords).map((key) => [key, key])), en: resourceWords };
495
556
  ctx.effect(() => ctx.locale.register(NS, words), "Plugin Hub: dictionaries");
496
- const t = ctx.locale.bind(NS);
497
- ctx.slots.inject("settings.section", () => ctx.slots.register({ name: "settings.section", id: MARKET_ID, order: 39, label: () => BRAND.navTitle, locale: NS }, () => /* @__PURE__ */ import_react.default.createElement(Market, { locale: ctx.locale, t })));
557
+ const t = translate(ctx.locale.bind(NS));
558
+ const request = connectionRequest(ctx.connection, MARKET_ID);
559
+ const panelId = "plugin-hub-" + MARKET_ID;
560
+ ctx.slots.inject("main", () => ctx.slots.register({ name: "main", key: panelId, locale: NS }, () => /* @__PURE__ */ import_react2.default.createElement(ResourceHub, { ctx, request, t, brand: BRAND, panelId })));
561
+ ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({ name: "sidebar.footer.action", id: panelId, order: 39, locale: NS }, (props) => /* @__PURE__ */ import_react2.default.createElement(HubSidebarButton, { ...props, ctx, panelId, brand: BRAND })));
498
562
  }
499
563
  return module.exports; } });
500
- //# sourceMappingURL=client.js.map