@dshforge/agent-plugins 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js ADDED
@@ -0,0 +1,771 @@
1
+ (() => {
2
+ // node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.1-rc.3_@deepseek-ai+cordis@4.0.5/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
3
+ var FILE_ADDRESS_PREFIX = "dsh-resource://file/";
4
+ function encodeSegment(segment) {
5
+ return encodeURIComponent(segment).replace(/%3A/gi, ":");
6
+ }
7
+ function encodePath(path) {
8
+ return path.split("/").map(encodeSegment).join("/");
9
+ }
10
+ function sessionFileAddress(sessionId, path) {
11
+ const normalized = path.replace(/\\/g, "/").replace(/^(?:\.\/)+/, "");
12
+ return `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(normalized)}`;
13
+ }
14
+
15
+ // src/client.js
16
+ window.__ModuleLoader__.load({
17
+ id: "@dshforge/agent-plugins",
18
+ factory(require2) {
19
+ const React = require2("react");
20
+ const { createSnapshotStore } = require2("@deepseek-ai/dsh-client-store");
21
+ const {
22
+ FileTypeIcon,
23
+ Button,
24
+ Modal,
25
+ IconWarningOutlineRegular,
26
+ IconChevronDownOutlineRegular,
27
+ IconChevronLeftOutlineRegular,
28
+ IconSearchOutlineRegular
29
+ } = require2("@deepseek-ai/dsh-client-ui-primitives");
30
+ const h = React.createElement;
31
+ const NS = "agentPlugins";
32
+ const en = {
33
+ nav: "Agent plugins",
34
+ title: "Agent plugins",
35
+ intro: "Inspect plugins and capabilities in ~/.agent/plugins/",
36
+ search: "Search plugins",
37
+ emptySearch: "No matching plugins.",
38
+ loading: "Loading Agent Plugins\u2026",
39
+ failed: "Agent Plugins could not be loaded.",
40
+ retry: "Retry",
41
+ back: "Agent plugins",
42
+ overview: "Overview",
43
+ skills: "Skills",
44
+ mcp: "MCP",
45
+ files: "Files",
46
+ version: "Version",
47
+ author: "Author",
48
+ license: "License",
49
+ spec: "Specification",
50
+ description: "Description",
51
+ noSkills: "This plugin provides no Skills.",
52
+ noMcp: "This plugin configures no MCP servers.",
53
+ noFiles: "This plugin has no previewable files.",
54
+ limited: "Only the first 200 entries are shown.",
55
+ emptyDirectory: "This directory is empty.",
56
+ previewNoSession: "Open a Session before using DSH Preview.",
57
+ manifest: "Manifest",
58
+ installPath: "Install path",
59
+ invalid: "Invalid",
60
+ warning: "Warning",
61
+ install: "Install from Git",
62
+ installTitle: "Install Agent Plugin from Git",
63
+ installHint: "Use an HTTPS .git or git@host:path address. Add #ref and &path:/subdirectory when needed.",
64
+ installPlaceholder: "https://github.com/org/repo.git&path:/plugins/demo",
65
+ installing: "Installing from Git\u2026",
66
+ cancel: "Cancel",
67
+ installFailed: "Git installation failed.",
68
+ close: "Close",
69
+ installDescription: "Enter a GitHub repository URL, with an optional ref and package subdirectory.",
70
+ installSafety: "Only install plugins you trust. No install scripts run, but enabled plugin code can act with your permissions.",
71
+ installExamples: "Installation examples",
72
+ installGuide: "Installation guide",
73
+ installGuideTitle: "Git repository address",
74
+ installGuideDescription: "Use HTTPS .git or SCP-style git@host:path, with optional #ref and &path:/subdirectory. Example: https://github.com/agentplugins/agent-plugins-example.git",
75
+ fillExample: "Fill example"
76
+ };
77
+ const zh = {
78
+ nav: "Agent \u63D2\u4EF6",
79
+ title: "Agent \u63D2\u4EF6",
80
+ intro: "\u67E5\u770B ~/.agent/plugins/ \u4E2D\u7684\u63D2\u4EF6\u53CA\u5176\u80FD\u529B",
81
+ search: "\u641C\u7D22\u63D2\u4EF6",
82
+ emptySearch: "\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u63D2\u4EF6\u3002",
83
+ loading: "\u6B63\u5728\u52A0\u8F7D Agent \u63D2\u4EF6\u2026",
84
+ failed: "Agent \u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25\u3002",
85
+ retry: "\u91CD\u8BD5",
86
+ back: "Agent \u63D2\u4EF6",
87
+ overview: "\u6982\u89C8",
88
+ skills: "Skills",
89
+ mcp: "MCP",
90
+ files: "\u6587\u4EF6",
91
+ version: "\u7248\u672C",
92
+ author: "\u4F5C\u8005",
93
+ license: "\u8BB8\u53EF\u8BC1",
94
+ spec: "\u89C4\u8303",
95
+ description: "\u63CF\u8FF0",
96
+ noSkills: "\u6B64\u63D2\u4EF6\u672A\u63D0\u4F9B Skills\u3002",
97
+ noMcp: "\u6B64\u63D2\u4EF6\u672A\u914D\u7F6E MCP \u670D\u52A1\u5668\u3002",
98
+ noFiles: "\u6B64\u63D2\u4EF6\u6CA1\u6709\u53EF\u9884\u89C8\u7684\u6587\u4EF6\u3002",
99
+ limited: "\u4EC5\u663E\u793A\u524D 200 \u9879\u3002",
100
+ emptyDirectory: "\u6B64\u76EE\u5F55\u4E3A\u7A7A\u3002",
101
+ previewNoSession: "\u8BF7\u5148\u6253\u5F00\u4E00\u4E2A\u4F1A\u8BDD\uFF0C\u518D\u4F7F\u7528 DSH \u9884\u89C8\u3002",
102
+ manifest: "Manifest",
103
+ installPath: "\u5B89\u88C5\u8DEF\u5F84",
104
+ invalid: "\u65E0\u6548",
105
+ warning: "\u8B66\u544A",
106
+ install: "\u4ECE Git \u5B89\u88C5",
107
+ installTitle: "\u4ECE Git \u5B89\u88C5 Agent \u63D2\u4EF6",
108
+ installHint: "\u652F\u6301 HTTPS .git \u6216 git@host:path\uFF0C\u53EF\u9644\u52A0 #ref \u548C &path:/\u5B50\u76EE\u5F55\u3002",
109
+ installPlaceholder: "https://github.com/org/repo.git&path:/plugins/demo",
110
+ installing: "\u6B63\u5728\u4ECE Git \u5B89\u88C5\u2026",
111
+ cancel: "\u53D6\u6D88",
112
+ installFailed: "Git \u5B89\u88C5\u5931\u8D25\u3002",
113
+ close: "\u5173\u95ED",
114
+ installDescription: "\u8F93\u5165 GitHub \u4ED3\u5E93\u5730\u5740\uFF0C\u53EF\u6307\u5B9A ref \u548C\u63D2\u4EF6\u5B50\u76EE\u5F55\u3002",
115
+ installSafety: "\u8BF7\u786E\u8BA4\u63D2\u4EF6\u6765\u6E90\u53EF\u4FE1\u3002\u5B89\u88C5\u4E0D\u6267\u884C\u811A\u672C\uFF0C\u4F46\u542F\u7528\u540E\uFF0C\u63D2\u4EF6\u4EE3\u7801\u53EF\u6309\u4F60\u7684\u6743\u9650\u8FD0\u884C\u5E76\u8BFB\u53D6\u6570\u636E\u3002",
116
+ installExamples: "\u5B89\u88C5\u793A\u4F8B",
117
+ installGuide: "\u5B89\u88C5\u5F15\u5BFC",
118
+ installGuideTitle: "\u586B\u5165 Git \u4ED3\u5E93\u5730\u5740",
119
+ installGuideDescription: "\u652F\u6301 HTTPS .git \u6216 SCP-style git@host:path\uFF1B\u53EF\u7528 #ref \u6307\u5B9A\u5206\u652F\u3001\u6807\u7B7E\u6216\u63D0\u4EA4\uFF0C\u7528 &path:/\u5B50\u76EE\u5F55\u9009\u62E9\u63D2\u4EF6\u3002\u793A\u4F8B\uFF1Ahttps://github.com/agentplugins/agent-plugins-example.git",
120
+ fillExample: "\u586B\u5165\u793A\u4F8B"
121
+ };
122
+ const css = `
123
+ .dsh-forge-agent-plugins{container:agent-plugins/inline-size;display:flex;flex-direction:column;gap:12px;width:100%;max-width:760px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px}
124
+ .dsh-forge-agent-plugins *{box-sizing:border-box}
125
+ .dsh-forge-agent-plugins button,.dsh-forge-agent-plugins input{font:inherit}
126
+ .dsh-forge-agent-plugins button:focus-visible,.dsh-forge-agent-plugins input:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:2px}
127
+ .ap-heading{margin:0;font-size:18px;line-height:26px;font-weight:600}
128
+ .ap-intro{margin:0;color:var(--dsw-alias-label-tertiary);font-size:13px}
129
+ .ap-catalog{display:flex;flex-direction:column;gap:12px;margin-top:2px}
130
+ .ap-search{position:relative;display:flex;align-items:center;color:var(--dsw-alias-label-tertiary)}
131
+ .ap-search>svg{position:absolute;left:12px;width:16px;height:16px;pointer-events:none}
132
+ .ap-search input{width:100%;height:36px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);padding:0 34px 0 36px;outline:none;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font-size:13px}
133
+ .ap-search input::placeholder{color:var(--dsw-alias-label-tertiary)}
134
+ .ap-search input:focus-visible{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--dsw-alias-state-business-primary) 18%,transparent)}
135
+ .ap-toolbar{display:flex;align-items:center;gap:8px}
136
+ .ap-toolbar .ap-search{flex:1;min-width:0}
137
+ .ap-button{display:inline-flex;align-items:center;justify-content:center;flex:none;min-height:32px;padding:4px 12px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font-size:12px;cursor:pointer}
138
+ .ap-button:hover{background:var(--dsw-alias-interactive-bg-hover)}
139
+ .ap-button:disabled{opacity:.5;cursor:default}
140
+ .ap-install-dialog{width:min(560px,100%);max-height:min(800px,100%)}
141
+ .ap-install-form{display:flex;flex-direction:column;gap:12px}
142
+ .ap-install-examples{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
143
+ .ap-install-examples summary{display:flex;align-items:center;gap:4px;cursor:pointer;list-style:none}
144
+ .ap-install-examples summary::-webkit-details-marker{display:none}
145
+ .ap-guide-chevron{transition:transform 120ms ease}
146
+ .ap-install-examples[open] .ap-guide-chevron{transform:rotate(180deg)}
147
+ .ap-guide-card{display:flex;align-items:center;gap:12px;margin-top:10px;padding:12px 14px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-layer-1)}
148
+ .ap-guide-content{display:flex;flex-direction:column;gap:6px;flex:1;min-width:0}
149
+ .ap-guide-content strong{font-size:13px;line-height:20px;font-weight:500}
150
+ .ap-guide-content p{margin:0;overflow-wrap:anywhere;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
151
+ .ap-guide-fill{flex:none}
152
+ .ap-install-input{width:100%;height:40px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);padding:0 14px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px}
153
+ .ap-install-footer{display:flex;flex-direction:column;gap:16px}
154
+ .ap-install-safety{display:flex;align-items:flex-start;gap:8px;margin:0;padding:10px 12px;border-radius:var(--dsw-radius-md);background:var(--dsw-alias-state-warn-tertiary);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
155
+ .ap-install-safety>svg{flex:none;margin-top:2px;color:var(--dsw-alias-state-warn-primary)}
156
+ .ap-install-submit{width:100%}
157
+ .ap-cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:0;padding:0;list-style:none}
158
+ .ap-card{min-width:0;overflow:hidden;border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-xl);background:var(--dsw-alias-settings-card-fill)}
159
+ .ap-card-button{display:flex;flex-direction:column;align-items:stretch;gap:2px;width:100%;min-height:52px;padding:12px 14px;border:0;background:transparent;color:inherit;text-align:left;cursor:pointer}
160
+ .ap-card-button:hover{background:var(--dsw-alias-interactive-bg-hover)}
161
+ .ap-card-button:active{background:var(--dsw-alias-interactive-bg-active)}
162
+ .ap-card-button:focus-visible{outline-offset:-2px!important}
163
+ .ap-card-main{display:flex;align-items:center;justify-content:space-between;gap:10px;min-width:0}
164
+ .ap-card-title{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--ds-font-family-code);font-size:13px;font-weight:500}
165
+ .ap-trailing{display:inline-flex;flex:none;align-items:center;gap:6px;color:var(--dsw-alias-label-tertiary)}
166
+ .ap-version{font-size:11px;line-height:16px}
167
+ .ap-description{display:-webkit-box;overflow:hidden;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;-webkit-box-orient:vertical;-webkit-line-clamp:2}
168
+ .ap-meta{display:flex;align-items:center;gap:6px;margin-top:auto;padding-top:6px}
169
+ .ap-meta code{display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-radius:var(--dsw-radius-xs);padding:1px 6px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);font-family:var(--ds-font-family-code);font-size:11px;line-height:18px}
170
+ .ap-warning-dot{width:6px;height:6px;flex:none;border-radius:999px;background:var(--dsw-alias-state-warning-primary,#f59e0b)}
171
+ .ap-status{margin:0;padding:28px 12px;color:var(--dsw-alias-label-tertiary);text-align:center}
172
+ .ap-back{display:inline-flex;align-items:center;align-self:flex-start;gap:4px;height:28px;margin:0 0 2px -6px;padding:0 6px;border:0;border-radius:var(--dsw-radius-sm);background:transparent;color:var(--dsw-alias-label-secondary);font-size:12px;cursor:pointer}
173
+ .ap-back:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
174
+ .ap-back svg{width:12px;height:12px}
175
+ .ap-detail-header{display:flex;flex-direction:column;gap:6px}
176
+ .ap-detail-title{margin:0;font-family:var(--ds-font-family-code);font-size:18px;line-height:26px;font-weight:600}
177
+ .ap-detail-description{margin:0;color:var(--dsw-alias-label-secondary);font-size:13px}
178
+ .ap-detail-meta{display:flex;flex-wrap:wrap;gap:4px 14px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
179
+ .ap-detail-path{display:flex;flex-wrap:wrap;gap:6px;margin-top:2px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
180
+ .ap-detail-path code{color:var(--dsw-alias-label-secondary);font-family:var(--ds-font-family-code);overflow-wrap:anywhere}
181
+ .ap-tabs{display:flex;align-items:flex-end;gap:22px;margin-top:2px;border-bottom:.5px solid var(--dsw-alias-border-l2)}
182
+ .ap-tab{position:relative;flex:none;border:0;padding:7px 1px 9px;background:transparent;color:var(--dsw-alias-label-tertiary);font-size:13px;cursor:pointer}
183
+ .ap-tab[data-active=true]{color:var(--dsw-alias-label-primary)}
184
+ .ap-tab[data-active=true]::after{position:absolute;right:0;bottom:-1px;left:0;height:2px;border-radius:2px 2px 0 0;background:var(--dsw-alias-label-primary);content:''}
185
+ .ap-tab-count{margin-left:3px;color:var(--dsw-alias-label-tertiary);font-size:11px}
186
+ .ap-panel{display:flex;flex-direction:column;gap:12px;min-width:0;padding-top:2px}
187
+ .ap-subheading{margin:0;font-size:14px;line-height:22px;font-weight:500}
188
+ .ap-summary{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
189
+ .ap-summary-item{display:flex;flex-direction:column;gap:2px;padding:12px;border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-module-platform)}
190
+ .ap-summary-value{font-size:16px;line-height:24px;font-weight:500}
191
+ .ap-summary-label{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
192
+ .ap-manifest{overflow:hidden;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-layer-2)}
193
+ .ap-manifest-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border-bottom:.5px solid var(--dsw-alias-border-l2)}
194
+ .ap-manifest-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 20px;margin:0;padding:14px}
195
+ .ap-manifest-grid>div{min-width:0}
196
+ .ap-manifest-wide{grid-column:1/-1}
197
+ .ap-manifest-grid dt{margin-bottom:2px;color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:17px}
198
+ .ap-manifest-grid dd{margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;overflow-wrap:anywhere}
199
+ .ap-link{padding:0;border:0;background:transparent;color:var(--dsw-alias-state-business-primary);font-size:12px;cursor:pointer;text-align:left}
200
+ .ap-link:hover{text-decoration:underline;text-decoration-style:dotted;text-underline-offset:3px}
201
+ .ap-components{display:flex;flex-direction:column;border-top:.5px solid var(--dsw-alias-border-l2)}
202
+ .ap-component{display:flex;flex-direction:column;gap:5px;padding:12px 0;border-bottom:.5px solid var(--dsw-alias-border-l2)}
203
+ .ap-component-top{display:flex;align-items:center;justify-content:space-between;gap:12px}
204
+ .ap-component-name{min-width:0;font-family:var(--ds-font-family-code);font-size:13px;font-weight:500;overflow-wrap:anywhere}
205
+ .ap-component-description{margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
206
+ .ap-component-path{color:var(--dsw-alias-label-tertiary);font-family:var(--ds-font-family-code);font-size:11px;line-height:17px;overflow-wrap:anywhere}
207
+ .ap-tag{display:inline-flex;flex:none;align-items:center;border-radius:999px;padding:1px 7px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);font-family:var(--ds-font-family-code);font-size:10px;line-height:16px}
208
+ .ap-config{border-radius:var(--dsw-radius-sm);padding:8px 10px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);font-family:var(--ds-font-family-code);font-size:12px;line-height:19px;overflow-wrap:anywhere;white-space:pre-wrap}
209
+ .ap-mcp-card{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-module-platform)}
210
+ .ap-mcp-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 16px;margin:0}
211
+ .ap-mcp-field{min-width:0}
212
+ .ap-mcp-field dt{margin-bottom:2px;color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:17px}
213
+ .ap-mcp-field dd{margin:0;color:var(--dsw-alias-label-secondary);font-family:var(--ds-font-family-code);font-size:12px;line-height:18px;overflow-wrap:anywhere}
214
+ .ap-tree,.ap-tree-level{margin:0;padding:0;list-style:none}
215
+ .ap-tree{display:flex;flex-direction:column;gap:2px}
216
+ .ap-tree-level{display:flex;flex-direction:column;gap:2px}
217
+ .ap-tree-row{display:flex;align-items:center;gap:6px;width:100%;min-height:32px;border:0;border-radius:var(--dsw-radius-sm);padding:4px 6px;background:transparent;color:inherit;text-align:left;cursor:pointer}
218
+ .ap-tree-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
219
+ .ap-tree-row.is-selected{background:var(--dsw-alias-state-business-tertiary)}
220
+ .ap-tree-row:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-1px}
221
+ .ap-tree-chevron{display:inline-flex;flex:none;align-items:center;justify-content:center;width:12px;height:12px;color:var(--dsw-alias-label-tertiary);transition:transform 100ms ease}
222
+ .ap-tree-chevron.is-open{transform:rotate(180deg)}
223
+ .ap-tree-spacer{width:12px;flex:none}
224
+ .ap-tree-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;line-height:20px}
225
+ .ap-tree-open{margin-left:auto;color:var(--dsw-alias-label-tertiary);font-size:12px;opacity:0}
226
+ .ap-tree-row:hover .ap-tree-open,.ap-tree-row.is-selected .ap-tree-open{opacity:.7}
227
+ .ap-tree-message{padding:6px 0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
228
+ .ap-empty,.ap-error{margin:0;padding:16px;border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-tertiary);font-size:13px}
229
+ .ap-error{color:var(--dsw-alias-state-error-primary)}
230
+ .ap-files{display:flex;flex-direction:column;gap:8px}
231
+ .ap-file-row{display:flex;align-items:center;justify-content:space-between;gap:16px;width:100%;padding:12px 14px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-2);text-align:left;cursor:pointer}
232
+ .ap-file-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
233
+ .ap-file-identity{display:flex;flex-direction:column;gap:2px;min-width:0}
234
+ .ap-file-identity strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--ds-font-family-code);font-size:12px;font-weight:500}
235
+ .ap-file-identity span{color:var(--dsw-alias-label-tertiary);font-size:11px}
236
+ .ap-file-open{flex:none;color:var(--dsw-alias-state-business-primary);font-size:12px}
237
+ @container agent-plugins (max-width:520px){.ap-cards{grid-template-columns:minmax(0,1fr)}.ap-manifest-grid{grid-template-columns:minmax(0,1fr)}.ap-summary{grid-template-columns:1fr}}
238
+ `;
239
+ function AgentPluginsSection({ t, useCatalog, reload, openFile, listDirectory, install, close }) {
240
+ const snapshot = useCatalog((snapshot2) => snapshot2);
241
+ const [selectedId, setSelectedId] = React.useState();
242
+ const [tab, setTab] = React.useState("overview");
243
+ const [previewError, setPreviewError] = React.useState();
244
+ const [installOpen, setInstallOpen] = React.useState(false);
245
+ const [installSpec, setInstallSpec] = React.useState("");
246
+ const [installState, setInstallState] = React.useState({ status: "idle", error: void 0 });
247
+ if (snapshot.status === "loading") return h("p", { className: "ap-status" }, t("loading"));
248
+ if (snapshot.status === "failed") {
249
+ return h(
250
+ "div",
251
+ { className: "ap-error" },
252
+ h("p", null, snapshot.error || t("failed")),
253
+ h("button", { type: "button", className: "ap-link", onClick: reload }, t("retry"))
254
+ );
255
+ }
256
+ const plugins = snapshot.value?.plugins ?? [];
257
+ const selected = plugins.find((plugin) => plugin.directoryName === selectedId);
258
+ const openPreview = (path) => {
259
+ const result = openFile(path);
260
+ if (result.ok) {
261
+ setPreviewError(void 0);
262
+ close();
263
+ } else {
264
+ setPreviewError(result.message);
265
+ }
266
+ };
267
+ const onInstall = async (event) => {
268
+ event.preventDefault();
269
+ setInstallState({ status: "installing", error: void 0 });
270
+ try {
271
+ const result = await install(installSpec);
272
+ if (result.ok) {
273
+ setInstallSpec("");
274
+ setInstallOpen(false);
275
+ setInstallState({ status: "idle", error: void 0 });
276
+ await reload();
277
+ } else {
278
+ setInstallState({ status: "failed", error: result.error.message });
279
+ }
280
+ } catch (error) {
281
+ setInstallState({ status: "failed", error: error instanceof Error ? error.message : String(error) });
282
+ }
283
+ };
284
+ return h(
285
+ "div",
286
+ { className: "dsh-forge-agent-plugins" },
287
+ previewError ? h("p", { className: "ap-error", role: "alert" }, previewError) : null,
288
+ h(InstallDialog, {
289
+ open: installOpen,
290
+ t,
291
+ spec: installSpec,
292
+ state: installState,
293
+ onSpec: setInstallSpec,
294
+ onSubmit: onInstall,
295
+ onCancel: () => {
296
+ setInstallOpen(false);
297
+ setInstallState({ status: "idle", error: void 0 });
298
+ }
299
+ }),
300
+ selected ? h(PluginDetail, {
301
+ plugin: selected,
302
+ t,
303
+ tab,
304
+ onTab: setTab,
305
+ onBack: () => {
306
+ setSelectedId(void 0);
307
+ setTab("overview");
308
+ },
309
+ onOpenFile: openPreview,
310
+ listDirectory
311
+ }) : h(PluginList, {
312
+ plugins,
313
+ t,
314
+ onSelect: (plugin) => {
315
+ setSelectedId(plugin.directoryName);
316
+ setTab("overview");
317
+ },
318
+ onInstall: () => setInstallOpen(true)
319
+ })
320
+ );
321
+ }
322
+ function PluginList({ plugins, t, onSelect, onInstall }) {
323
+ const [query, setQuery] = React.useState("");
324
+ const normalized = query.trim().toLocaleLowerCase();
325
+ const matches = plugins.filter((plugin) => `${plugin.name} ${plugin.directoryName} ${plugin.manifest?.description ?? ""}`.toLocaleLowerCase().includes(normalized));
326
+ return h(
327
+ React.Fragment,
328
+ null,
329
+ h("h2", { className: "ap-heading" }, t("title")),
330
+ h("p", { className: "ap-intro" }, t("intro")),
331
+ h(
332
+ "div",
333
+ { className: "ap-catalog" },
334
+ h(
335
+ "div",
336
+ { className: "ap-toolbar" },
337
+ h(
338
+ "label",
339
+ { className: "ap-search" },
340
+ h(IconSearchOutlineRegular, { size: 16 }),
341
+ h("input", {
342
+ type: "search",
343
+ value: query,
344
+ placeholder: t("search"),
345
+ "aria-label": t("search"),
346
+ onChange: (event) => setQuery(event.currentTarget.value)
347
+ })
348
+ ),
349
+ h("button", { type: "button", className: "ap-button", onClick: onInstall }, t("install"))
350
+ ),
351
+ plugins.length === 0 ? null : matches.length === 0 ? h("p", { className: "ap-status" }, t("emptySearch")) : h("ul", { className: "ap-cards" }, matches.map((plugin) => h(PluginCard, { key: plugin.directoryName, plugin, onSelect, t })))
352
+ )
353
+ );
354
+ }
355
+ function InstallDialog({ open, t, spec, state, onSpec, onSubmit, onCancel }) {
356
+ const busy = state.status === "installing";
357
+ return h(
358
+ Modal,
359
+ {
360
+ open,
361
+ onClose: () => {
362
+ if (!busy) onCancel();
363
+ },
364
+ title: t("installTitle"),
365
+ closeLabel: t("close"),
366
+ description: t("installDescription"),
367
+ className: "ap-install-dialog",
368
+ footer: h(
369
+ "div",
370
+ { className: "ap-install-footer" },
371
+ h(
372
+ "p",
373
+ { className: "ap-install-safety", role: "note" },
374
+ h(IconWarningOutlineRegular, { size: 14 }),
375
+ h("span", null, t("installSafety"))
376
+ ),
377
+ h(Button, {
378
+ variant: "primary",
379
+ className: "ap-install-submit",
380
+ disabled: busy || !spec.trim(),
381
+ "aria-busy": busy,
382
+ onClick: onSubmit
383
+ }, busy ? t("installing") : t("install"))
384
+ )
385
+ },
386
+ h(
387
+ "form",
388
+ { className: "ap-install-form", onSubmit },
389
+ h("input", {
390
+ className: "ap-install-input",
391
+ type: "text",
392
+ value: spec,
393
+ placeholder: t("installPlaceholder"),
394
+ "aria-label": t("installTitle"),
395
+ disabled: busy,
396
+ "data-modal-autofocus": true,
397
+ onChange: (event) => onSpec(event.currentTarget.value)
398
+ }),
399
+ state.error ? h("p", { className: "ap-error", role: "alert" }, `${t("installFailed")} ${state.error}`) : null,
400
+ h(
401
+ "details",
402
+ { className: "ap-install-examples" },
403
+ h(
404
+ "summary",
405
+ null,
406
+ h(IconChevronDownOutlineRegular, { size: 12, className: "ap-guide-chevron" }),
407
+ h("span", null, t("installGuide"))
408
+ ),
409
+ h(
410
+ "div",
411
+ { className: "ap-guide-card" },
412
+ h(
413
+ "div",
414
+ { className: "ap-guide-content" },
415
+ h("strong", null, t("installGuideTitle")),
416
+ h("p", null, t("installGuideDescription"))
417
+ ),
418
+ h("button", {
419
+ type: "button",
420
+ className: "ap-button ap-guide-fill",
421
+ disabled: busy,
422
+ onClick: () => onSpec("https://github.com/agentplugins/agent-plugins-example.git")
423
+ }, t("fillExample"))
424
+ )
425
+ )
426
+ )
427
+ );
428
+ }
429
+ function PluginCard({ plugin, onSelect, t }) {
430
+ const manifest = plugin.manifest;
431
+ return h(
432
+ "li",
433
+ { className: "ap-card" },
434
+ h(
435
+ "button",
436
+ { type: "button", className: "ap-card-button", onClick: () => onSelect(plugin) },
437
+ h(
438
+ "span",
439
+ { className: "ap-card-main" },
440
+ h("strong", { className: "ap-card-title" }, plugin.name),
441
+ h(
442
+ "span",
443
+ { className: "ap-trailing" },
444
+ plugin.status === "invalid" ? h("span", { className: "ap-tag" }, t("invalid")) : h("span", { className: "ap-version" }, manifest?.version ? `v${manifest.version}` : "")
445
+ )
446
+ ),
447
+ h("span", { className: "ap-description" }, manifest?.description ?? plugin.invalidReason ?? ""),
448
+ h(
449
+ "span",
450
+ { className: "ap-meta" },
451
+ h("code", null, `${plugin.skills.length} Skills \xB7 ${plugin.mcpServers.length} MCP`),
452
+ plugin.mcpError || plugin.status === "invalid" ? h("span", { className: "ap-warning-dot", title: plugin.mcpError ?? plugin.invalidReason }) : null
453
+ )
454
+ )
455
+ );
456
+ }
457
+ function PluginDetail({ plugin, t, tab, onTab, onBack, onOpenFile, listDirectory }) {
458
+ const manifest = plugin.manifest;
459
+ return h(
460
+ React.Fragment,
461
+ null,
462
+ h(
463
+ "button",
464
+ { type: "button", className: "ap-back", onClick: onBack },
465
+ h(IconChevronLeftOutlineRegular, { size: 12 }),
466
+ t("back")
467
+ ),
468
+ h(
469
+ "div",
470
+ { className: "ap-detail-header" },
471
+ h("h2", { className: "ap-detail-title" }, plugin.name),
472
+ manifest?.description ? h("p", { className: "ap-detail-description" }, manifest.description) : null,
473
+ h(
474
+ "div",
475
+ { className: "ap-detail-meta" },
476
+ h("span", null, manifest?.version ? `v${manifest.version}` : "\u2014"),
477
+ h("span", null, "Agent Plugins 1.0.0"),
478
+ manifest?.license ? h("span", null, manifest.license) : null
479
+ ),
480
+ h("div", { className: "ap-detail-path" }, h("span", null, t("installPath")), h("code", null, `${plugin.root}/`))
481
+ ),
482
+ h(
483
+ "div",
484
+ { className: "ap-tabs", role: "tablist", "aria-label": t("overview") },
485
+ h(Tab, { id: "overview", label: t("overview"), tab, onTab }),
486
+ h(Tab, { id: "skills", label: "Skills", count: plugin.skills.length, tab, onTab }),
487
+ h(Tab, { id: "mcp", label: "MCP", count: plugin.mcpServers.length, tab, onTab }),
488
+ h(Tab, { id: "files", label: t("files"), tab, onTab })
489
+ ),
490
+ tab === "overview" ? h(ManifestOverview, { plugin, t }) : tab === "skills" ? h(SkillsView, { plugin, t }) : tab === "mcp" ? h(McpView, { plugin, t }) : h(FilesView, { plugin, t, onOpenFile, listDirectory })
491
+ );
492
+ }
493
+ function Tab({ id, label, count, tab, onTab }) {
494
+ return h("button", {
495
+ type: "button",
496
+ role: "tab",
497
+ className: "ap-tab",
498
+ "data-active": tab === id ? "true" : "false",
499
+ "aria-selected": tab === id ? "true" : "false",
500
+ tabIndex: tab === id ? 0 : -1,
501
+ onClick: () => onTab(id)
502
+ }, label, count === void 0 ? null : h("span", { className: "ap-tab-count" }, count));
503
+ }
504
+ function ManifestOverview({ plugin, t }) {
505
+ const manifest = plugin.manifest;
506
+ if (plugin.status === "invalid") return h("p", { className: "ap-error", role: "alert" }, plugin.invalidReason);
507
+ return h(
508
+ "div",
509
+ { className: "ap-panel" },
510
+ h(
511
+ "div",
512
+ { className: "ap-summary" },
513
+ h("div", { className: "ap-summary-item" }, h("span", { className: "ap-summary-value" }, plugin.skills.length), h("span", { className: "ap-summary-label" }, "Skills")),
514
+ h("div", { className: "ap-summary-item" }, h("span", { className: "ap-summary-value" }, plugin.mcpServers.length), h("span", { className: "ap-summary-label" }, "MCP"))
515
+ ),
516
+ plugin.mcpError ? h("p", { className: "ap-error", role: "alert" }, plugin.mcpError) : null,
517
+ h(
518
+ "section",
519
+ { className: "ap-manifest", "aria-label": t("manifest") },
520
+ h(
521
+ "dl",
522
+ { className: "ap-manifest-grid" },
523
+ h(ManifestField, { label: t("version"), value: manifest.version ? `v${manifest.version}` : "\u2014" }),
524
+ h(ManifestField, { label: t("author"), value: manifest.author?.name ?? "\u2014" }),
525
+ h(ManifestField, { label: t("license"), value: manifest.license ?? "\u2014" }),
526
+ h(ManifestField, { label: t("spec"), value: "Agent Plugins 1.0.0" }),
527
+ h(ManifestField, { label: t("description"), value: manifest.description ?? "\u2014", wide: true })
528
+ )
529
+ )
530
+ );
531
+ }
532
+ function ManifestField({ label, value, wide }) {
533
+ return h("div", { className: wide ? "ap-manifest-wide" : void 0 }, h("dt", null, label), h("dd", null, value));
534
+ }
535
+ function SkillsView({ plugin, t }) {
536
+ if (plugin.skills.length === 0) return h("p", { className: "ap-empty" }, t("noSkills"));
537
+ return h("div", { className: "ap-components" }, plugin.skills.map((skill) => h(
538
+ "div",
539
+ { className: "ap-component", key: skill.name },
540
+ h("div", { className: "ap-component-top" }, h("span", { className: "ap-component-name" }, skill.name)),
541
+ h("p", { className: "ap-component-description" }, skill.description)
542
+ )));
543
+ }
544
+ function McpView({ plugin, t }) {
545
+ if (plugin.mcpServers.length === 0) return h("p", { className: "ap-empty" }, t("noMcp"));
546
+ return h("div", { className: "ap-components" }, plugin.mcpServers.map((server) => h(
547
+ "section",
548
+ { className: "ap-mcp-card", key: server.name },
549
+ h(
550
+ "div",
551
+ { className: "ap-component-top" },
552
+ h("span", { className: "ap-component-name" }, server.name),
553
+ h("span", { className: "ap-tag" }, server.type === "sse" ? `${server.type}\uFF08\u6682\u4E0D\u652F\u6301\uFF09` : server.type)
554
+ ),
555
+ h(
556
+ "dl",
557
+ { className: "ap-mcp-grid" },
558
+ server.type === "stdio" ? h(
559
+ React.Fragment,
560
+ null,
561
+ h(McpField, { label: "command", value: server.command }),
562
+ server.args?.length ? h(McpField, { label: "args", value: server.args.join(" ") }) : null,
563
+ h(McpField, { label: "cwd", value: server.cwd ?? "${PLUGIN_ROOT}" })
564
+ ) : h(
565
+ React.Fragment,
566
+ null,
567
+ h(McpField, { label: "url", value: server.url }),
568
+ server.headerNames?.length ? h(McpField, { label: "headers", value: server.headerNames.join(", ") }) : null
569
+ )
570
+ )
571
+ )));
572
+ }
573
+ function McpField({ label, value }) {
574
+ return h(
575
+ "div",
576
+ { className: "ap-mcp-field" },
577
+ h("dt", null, label),
578
+ h("dd", null, value)
579
+ );
580
+ }
581
+ function FilesView({ plugin, t, onOpenFile, listDirectory }) {
582
+ const [directories, setDirectories] = React.useState({});
583
+ const [expanded, setExpanded] = React.useState(() => /* @__PURE__ */ new Set());
584
+ const [selected, setSelected] = React.useState();
585
+ const controllers = React.useRef(/* @__PURE__ */ new Set());
586
+ const loadDirectory = React.useCallback((path) => {
587
+ const controller = new AbortController();
588
+ controllers.current.add(controller);
589
+ setDirectories((previous) => ({
590
+ ...previous,
591
+ [path]: { status: "loading", entries: previous[path]?.entries ?? [] }
592
+ }));
593
+ return listDirectory(plugin.directoryName, path, controller.signal).then((result) => {
594
+ if (controller.signal.aborted) return;
595
+ if (result.ok) {
596
+ setDirectories((previous) => ({
597
+ ...previous,
598
+ [path]: { status: "ready", entries: result.value.entries, truncated: result.value.truncated }
599
+ }));
600
+ } else {
601
+ setDirectories((previous) => ({ ...previous, [path]: { status: "error", error: result.error.message } }));
602
+ }
603
+ }).catch((error) => {
604
+ if (!controller.signal.aborted) {
605
+ setDirectories((previous) => ({ ...previous, [path]: { status: "error", error: String(error) } }));
606
+ }
607
+ }).finally(() => {
608
+ controllers.current.delete(controller);
609
+ });
610
+ }, [plugin.directoryName, listDirectory]);
611
+ React.useEffect(() => {
612
+ setDirectories({});
613
+ setExpanded(/* @__PURE__ */ new Set());
614
+ setSelected(void 0);
615
+ loadDirectory("");
616
+ return () => {
617
+ for (const controller of controllers.current) controller.abort();
618
+ controllers.current.clear();
619
+ };
620
+ }, [loadDirectory]);
621
+ const toggleDirectory = (path) => {
622
+ const isOpen = expanded.has(path);
623
+ setExpanded((previous) => {
624
+ const next = new Set(previous);
625
+ if (isOpen) next.delete(path);
626
+ else next.add(path);
627
+ return next;
628
+ });
629
+ if (!isOpen && (!directories[path] || directories[path].status === "error")) loadDirectory(path);
630
+ };
631
+ const openFile = (path) => {
632
+ setSelected(path);
633
+ onOpenFile(joinPath(plugin.root, path));
634
+ };
635
+ return h(
636
+ "div",
637
+ { className: "ap-files" },
638
+ h(
639
+ "ul",
640
+ { className: "ap-tree", role: "tree" },
641
+ h(DirectoryRows, {
642
+ path: "",
643
+ depth: 0,
644
+ directories,
645
+ expanded,
646
+ toggleDirectory,
647
+ openFile,
648
+ loadDirectory,
649
+ selected,
650
+ t
651
+ })
652
+ )
653
+ );
654
+ }
655
+ function DirectoryRows({ path, depth, directories, expanded, toggleDirectory, openFile, loadDirectory, selected, t }) {
656
+ const directory = directories[path];
657
+ if (!directory) return null;
658
+ if (directory.status === "loading") return h("li", { className: "ap-tree-message" }, t("loading"));
659
+ if (directory.status === "error") {
660
+ return h(
661
+ "li",
662
+ { className: "ap-tree-message" },
663
+ h("button", { type: "button", className: "ap-link", onClick: () => loadDirectory(path) }, t("retry"))
664
+ );
665
+ }
666
+ return h(
667
+ React.Fragment,
668
+ null,
669
+ directory.entries.map((entry) => {
670
+ const isDirectory = entry.kind === "directory";
671
+ const isOpen = expanded.has(entry.path);
672
+ return h(
673
+ "li",
674
+ { key: entry.path, role: "treeitem", "aria-expanded": isDirectory ? isOpen : void 0 },
675
+ h(
676
+ "button",
677
+ {
678
+ type: "button",
679
+ className: `ap-tree-row${selected === entry.path ? " is-selected" : ""}`,
680
+ style: { paddingLeft: 6 + depth * 16 },
681
+ onClick: () => isDirectory ? toggleDirectory(entry.path) : openFile(entry.path),
682
+ "aria-label": `${isDirectory ? "\u76EE\u5F55" : "\u6587\u4EF6"} ${entry.path}`
683
+ },
684
+ isDirectory ? h(IconChevronDownOutlineRegular, { size: 12, className: isOpen ? "ap-tree-chevron is-open" : "ap-tree-chevron" }) : h("span", { className: "ap-tree-spacer" }),
685
+ isDirectory ? h(FileTypeIcon, { kind: "folder", size: 16 }) : h(FileTypeIcon, { path: entry.name, size: 16 }),
686
+ h("span", { className: "ap-tree-name" }, entry.name),
687
+ !isDirectory ? h("span", { className: "ap-tree-open", "aria-hidden": "true" }, "\u2197") : null
688
+ ),
689
+ isDirectory && isOpen ? h(
690
+ "ul",
691
+ { role: "group", className: "ap-tree-level" },
692
+ h(DirectoryRows, {
693
+ path: entry.path,
694
+ depth: depth + 1,
695
+ directories,
696
+ expanded,
697
+ toggleDirectory,
698
+ openFile,
699
+ loadDirectory,
700
+ selected,
701
+ t
702
+ })
703
+ ) : null
704
+ );
705
+ }),
706
+ directory.truncated ? h("li", { className: "ap-tree-message" }, t("limited")) : null,
707
+ directory.entries.length === 0 ? h("li", { className: "ap-tree-message" }, t("emptyDirectory")) : null
708
+ );
709
+ }
710
+ function joinPath(root, relative) {
711
+ return `${root.replace(/[\\/]+$/, "")}/${relative}`;
712
+ }
713
+ function apply(ctx) {
714
+ const t = ctx.locale.bind(NS);
715
+ ctx.effect(() => ctx.locale.register(NS, { en, zh }), "agent-plugins: dictionaries");
716
+ const tagId = "@dshforge/agent-plugins/settings.css";
717
+ if (document.querySelector(`style[data-plugin-css="${tagId}"]`) === null) {
718
+ const tag = document.createElement("style");
719
+ tag.dataset.plugin = "@dshforge/agent-plugins";
720
+ tag.dataset.pluginCss = tagId;
721
+ tag.textContent = css;
722
+ document.head.appendChild(tag);
723
+ }
724
+ const catalog = createSnapshotStore({ status: "loading", value: void 0, error: void 0 });
725
+ let request = 0;
726
+ let started = false;
727
+ const load = () => {
728
+ const current = ++request;
729
+ catalog.set({ status: "loading", value: void 0, error: void 0 });
730
+ return ctx.connection.rpc.call("/agent-plugins", "catalog", null).then((result) => {
731
+ if (current !== request) return;
732
+ if (result.ok) catalog.set({ status: "ready", value: result.value, error: void 0 });
733
+ else catalog.set({ status: "failed", value: void 0, error: result.error.message });
734
+ }).catch((error) => {
735
+ if (current === request) catalog.set({ status: "failed", value: void 0, error: String(error) });
736
+ });
737
+ };
738
+ ctx.effect(() => () => {
739
+ request++;
740
+ }, "agent-plugins: discard stale catalog responses");
741
+ const listDirectory = (root, path, signal) => ctx.connection.rpc.call("/agent-plugins", "files", { root, path }, signal);
742
+ const install = (spec) => ctx.connection.rpc.call("/agent-plugins", "install", { spec });
743
+ const openFile = (path) => {
744
+ const sessionId = ctx.sidebarRight.mounted.getSnapshot();
745
+ if (sessionId === void 0) return { ok: false, message: t("previewNoSession") };
746
+ try {
747
+ ctx.sidebarRight.openResource(sessionFileAddress(sessionId, path));
748
+ return { ok: true };
749
+ } catch (error) {
750
+ return { ok: false, message: error instanceof Error ? error.message : String(error) };
751
+ }
752
+ };
753
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
754
+ name: "settings.section",
755
+ id: "agent-plugins",
756
+ order: 16,
757
+ label: () => t("nav"),
758
+ locale: NS,
759
+ inject: () => {
760
+ if (!started) {
761
+ started = true;
762
+ void load();
763
+ }
764
+ return { hooks: { catalog }, reload: load, openFile, listDirectory, install };
765
+ }
766
+ }, AgentPluginsSection));
767
+ }
768
+ return { inject: ["slots", "locale", "connection", "sidebarRight"], apply };
769
+ }
770
+ });
771
+ })();