dsh-agent-plugins-market 0.4.3
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/LICENSE +21 -0
- package/README.md +171 -0
- package/README.zh.md +171 -0
- package/client/client.js +954 -0
- package/client/client.js.map +1 -0
- package/cordis.patch.yml +4 -0
- package/lib/commands-mounts.js +169 -0
- package/lib/context.js +80 -0
- package/lib/discovery/manifests.js +214 -0
- package/lib/discovery/surfaces.js +232 -0
- package/lib/discovery.js +234 -0
- package/lib/git.js +52 -0
- package/lib/hooks-mounts.js +95 -0
- package/lib/index.js +73 -0
- package/lib/manager.js +490 -0
- package/lib/mcp-config.js +100 -0
- package/lib/mcp-mounts.js +88 -0
- package/lib/paths.js +85 -0
- package/lib/routes.js +208 -0
- package/lib/skills-parse.js +114 -0
- package/lib/skills-provider.js +170 -0
- package/lib/state.js +64 -0
- package/lib/types/commands-mounts.d.ts +29 -0
- package/lib/types/context.d.ts +13 -0
- package/lib/types/discovery/manifests.d.ts +55 -0
- package/lib/types/discovery/surfaces.d.ts +15 -0
- package/lib/types/discovery.d.ts +16 -0
- package/lib/types/git.d.ts +8 -0
- package/lib/types/hooks-mounts.d.ts +19 -0
- package/lib/types/index.d.ts +27 -0
- package/lib/types/manager.d.ts +87 -0
- package/lib/types/mcp-config.d.ts +28 -0
- package/lib/types/mcp-mounts.d.ts +31 -0
- package/lib/types/paths.d.ts +29 -0
- package/lib/types/routes.d.ts +11 -0
- package/lib/types/skills-parse.d.ts +22 -0
- package/lib/types/skills-provider.d.ts +16 -0
- package/lib/types/state.d.ts +6 -0
- package/lib/types/types.d.ts +165 -0
- package/lib/types/validate.d.ts +34 -0
- package/lib/types.js +10 -0
- package/lib/validate.js +199 -0
- package/package.json +114 -0
- package/schemas/1.0.0/mcp.schema.json +120 -0
- package/schemas/1.0.0/plugin.schema.json +65 -0
- package/schemas/README.md +14 -0
package/client/client.js
ADDED
|
@@ -0,0 +1,954 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({ id: "dsh-agent-plugins-market", factory: (require) => {
|
|
2
|
+
|
|
3
|
+
var module = { exports: {} };
|
|
4
|
+
var exports = module.exports;
|
|
5
|
+
(function(){if(typeof document!=="undefined"){var s=document.createElement("style");s.setAttribute("data-dsh-client","dsh-agent-plugins-market");s.textContent=".qMtKNa_market {\n min-width: 0;\n height: 100%;\n min-height: 0;\n color: var(--dsw-alias-label-primary, #1f2328);\n flex-direction: column;\n gap: 14px;\n display: flex;\n}\n\n.qMtKNa_header {\n flex-direction: column;\n flex-shrink: 0;\n gap: 8px;\n display: flex;\n}\n\n.qMtKNa_titleRow {\n align-items: center;\n gap: 12px;\n display: flex;\n}\n\n.qMtKNa_title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n.qMtKNa_sub {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n align-items: center;\n gap: 8px;\n min-width: 0;\n margin: 0;\n font-size: 13px;\n line-height: 20px;\n display: flex;\n overflow: hidden;\n}\n\n.qMtKNa_spacer {\n flex: 1;\n}\n\n.qMtKNa_tabGap {\n flex-shrink: 0;\n width: 16px;\n}\n\n.qMtKNa_searchGroup {\n align-items: center;\n gap: 2px;\n display: flex;\n}\n\n.qMtKNa_searchWrap, .qMtKNa_searchInput {\n align-items: center;\n display: flex;\n}\n\n.qMtKNa_searchInput input {\n width: 240px;\n font-size: 12px;\n line-height: 20px;\n}\n\n.qMtKNa_tabRow {\n border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n justify-content: flex-end;\n align-items: flex-end;\n gap: 2px;\n display: flex;\n}\n\n.qMtKNa_tab, .qMtKNa_tabOn {\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n white-space: nowrap;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n padding: 7px 12px;\n font-size: 13px;\n}\n\n.qMtKNa_tabOn {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n border-bottom-color: var(--dsw-alias-brand-primary, #4f6ef7);\n font-weight: 600;\n}\n\n.qMtKNa_viewSwitch {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n white-space: nowrap;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n padding: 7px 12px;\n font-size: 13px;\n}\n\n.qMtKNa_viewSwitch:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n.qMtKNa_body {\n flex: 1;\n align-items: flex-start;\n gap: 20px;\n min-height: 0;\n display: flex;\n}\n\n.qMtKNa_sourceTabsRow {\n padding: 0;\n display: block;\n}\n\n.qMtKNa_sourceTabsScroll {\n grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));\n gap: 6px;\n display: grid;\n}\n\n.qMtKNa_srcTabEdit {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 2px;\n font-size: 12px;\n line-height: 18px;\n}\n\n.qMtKNa_srcTabEdit:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n\n.qMtKNa_srcTabOn .qMtKNa_srcTabEdit {\n color: #ffffffd9;\n}\n\n.qMtKNa_srcTabOn .qMtKNa_srcTabEdit:hover {\n color: #fff;\n}\n\n.qMtKNa_srcTab, .qMtKNa_srcTabOn {\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-1, #fff);\n border-radius: 999px;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 24px;\n display: inline-flex;\n overflow: hidden;\n}\n\n.qMtKNa_srcTabMain {\n font: inherit;\n color: var(--dsw-alias-label-primary, #1f2328);\n cursor: pointer;\n white-space: nowrap;\n text-overflow: ellipsis;\n background: none;\n border: none;\n flex: 1;\n min-width: 0;\n padding: 2px 2px 2px 10px;\n font-size: 12px;\n line-height: 18px;\n overflow: hidden;\n}\n\n.qMtKNa_srcTabMain:hover {\n color: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n.qMtKNa_srcTabOn {\n background: var(--dsw-alias-brand-primary, #4f6ef7);\n border-color: var(--dsw-alias-brand-primary, #4f6ef7);\n}\n\n.qMtKNa_srcTabOn .qMtKNa_srcTabMain {\n color: #fff;\n font-weight: 600;\n}\n\n.qMtKNa_srcTabDel {\n font: inherit;\n color: var(--dsw-alias-label-tertiary, #9ca3af);\n cursor: pointer;\n background: none;\n border: none;\n flex-shrink: 0;\n padding: 2px 8px 2px 2px;\n font-size: 12px;\n line-height: 18px;\n}\n\n.qMtKNa_srcTabDel:hover {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n.qMtKNa_srcTabOn .qMtKNa_srcTabDel {\n color: #ffffffd9;\n}\n\n.qMtKNa_srcTabOn .qMtKNa_srcTabDel:hover {\n color: #fff;\n}\n\n.qMtKNa_grid {\n scrollbar-gutter: stable;\n flex: 1;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-content: start;\n gap: 12px;\n min-width: 0;\n min-height: 0;\n padding-right: 4px;\n display: grid;\n overflow-y: auto;\n}\n\n.qMtKNa_list {\n scrollbar-gutter: stable;\n flex-direction: column;\n flex: 1;\n gap: 8px;\n min-width: 0;\n min-height: 0;\n padding-right: 4px;\n display: flex;\n overflow-y: auto;\n}\n\n.qMtKNa_list .qMtKNa_card {\n flex-flow: wrap;\n align-items: center;\n gap: 8px 14px;\n}\n\n.qMtKNa_list .qMtKNa_cardTop {\n flex: none;\n}\n\n.qMtKNa_list .qMtKNa_cardDesc {\n -webkit-line-clamp: 1;\n flex: 1;\n min-width: 200px;\n min-height: 0;\n}\n\n.qMtKNa_list .qMtKNa_cardActions {\n flex: none;\n}\n\n.qMtKNa_list .qMtKNa_meta {\n flex-basis: 100%;\n}\n\n.qMtKNa_empty {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-align: center;\n grid-column: 1 / -1;\n padding: 48px 0;\n font-size: 13px;\n}\n\n.qMtKNa_card {\n background: var(--dsw-alias-bg-layer-1, #fff);\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 12px;\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n padding: 12px 14px;\n display: flex;\n}\n\n.qMtKNa_cardTop {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.qMtKNa_cardTitle {\n flex: 1;\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.qMtKNa_cardName {\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n font-weight: 600;\n line-height: 22px;\n overflow: hidden;\n}\n\n.qMtKNa_version {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n font-size: 12px;\n line-height: 20px;\n}\n\n.qMtKNa_cardActions {\n flex-shrink: 0;\n align-items: center;\n gap: 4px;\n display: flex;\n}\n\n.qMtKNa_switchOn, .qMtKNa_switchOff {\n cursor: pointer;\n border: none;\n border-radius: 999px;\n flex-shrink: 0;\n width: 38px;\n height: 22px;\n padding: 0;\n transition: background-color .15s;\n position: relative;\n}\n\n.qMtKNa_switchOn {\n background: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.qMtKNa_switchOff {\n background: var(--dsw-alias-state-neutral, #d1d5db);\n}\n\n.qMtKNa_switchOn:disabled, .qMtKNa_switchOff:disabled {\n opacity: .6;\n cursor: default;\n}\n\n.qMtKNa_switchThumb {\n pointer-events: none;\n background: #fff;\n border-radius: 50%;\n width: 16px;\n height: 16px;\n transition: left .15s;\n position: absolute;\n top: 3px;\n left: 3px;\n box-shadow: 0 1px 2px #0003;\n}\n\n.qMtKNa_switchOn .qMtKNa_switchThumb {\n left: 19px;\n}\n\n.qMtKNa_desc {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n min-height: 36px;\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n display: -webkit-box;\n overflow: hidden;\n}\n\n.qMtKNa_meta {\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.qMtKNa_src {\n color: var(--dsw-alias-label-secondary, #9ca3af);\n font-size: 12px;\n text-decoration: none;\n}\n\n.qMtKNa_tag {\n border: 1px solid var(--dsw-alias-border-l3, #d9dde3);\n color: var(--dsw-alias-label-secondary, #6b7280);\n border-radius: 4px;\n flex-shrink: 0;\n padding: 1px 6px;\n font-size: 12px;\n line-height: 18px;\n}\n\n.qMtKNa_okState {\n color: var(--dsw-alias-state-success-primary, #16a34a);\n white-space: nowrap;\n font-size: 12px;\n font-weight: 600;\n}\n\n.qMtKNa_warnLine {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n cursor: help;\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n}\n\n.qMtKNa_modalFooter {\n justify-content: flex-end;\n gap: 8px;\n width: 100%;\n display: flex;\n}\n\n.qMtKNa_modalFooterLeft {\n gap: 8px;\n margin-right: auto;\n display: flex;\n}\n\n.qMtKNa_editorDialog {\n width: min(500px, 92vw);\n}\n\n.qMtKNa_editorForm {\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n display: flex;\n}\n\n.qMtKNa_modeRow {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n background: var(--dsw-alias-bg-layer-2, #f3f4f6);\n border-radius: 10px;\n align-self: flex-start;\n gap: 6px;\n padding: 3px;\n display: flex;\n}\n\n.qMtKNa_seg, .qMtKNa_segOn {\n font: inherit;\n color: var(--dsw-alias-label-secondary, #6b7280);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 8px;\n padding: 5px 14px;\n font-size: 13px;\n line-height: 20px;\n}\n\n.qMtKNa_segOn {\n background: var(--dsw-alias-bg-layer-1, #fff);\n color: var(--dsw-alias-label-primary, #1f2328);\n font-weight: 600;\n box-shadow: 0 1px 2px #00000014;\n}\n\n.qMtKNa_fieldGroup {\n flex-direction: column;\n gap: 5px;\n display: flex;\n}\n\n.qMtKNa_fieldLabel {\n color: var(--dsw-alias-label-secondary, #6b7280);\n font-size: 12px;\n font-weight: 600;\n}\n\n.qMtKNa_fieldHint {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 12px;\n line-height: 16px;\n}\n\n.qMtKNa_staticId {\n border: 1px dashed var(--dsw-alias-border-l3, #d9dde3);\n background: var(--dsw-alias-bg-layer-2, #f3f4f6);\n border-radius: 8px;\n align-items: center;\n gap: 8px;\n padding: 7px 10px;\n display: flex;\n}\n\n.qMtKNa_staticIdValue {\n color: var(--dsw-alias-label-primary, #1f2328);\n font-size: 13px;\n font-weight: 600;\n}\n\n.qMtKNa_detailDialog {\n width: min(800px, 94vw);\n}\n\n.qMtKNa_detailBody {\n flex-direction: column;\n gap: 14px;\n max-height: 78vh;\n display: flex;\n overflow-y: auto;\n}\n\n.qMtKNa_detailSections {\n flex-direction: column;\n gap: 14px;\n display: flex;\n}\n\n.qMtKNa_detailSection {\n flex-direction: column;\n gap: 6px;\n display: flex;\n}\n\n.qMtKNa_detailHead {\n color: var(--dsw-alias-label-secondary, #6b7280);\n border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n margin: 0;\n padding-bottom: 4px;\n font-size: 13px;\n font-weight: 600;\n}\n\n.qMtKNa_detailGrid {\n grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n gap: 6px 14px;\n display: grid;\n}\n\n.qMtKNa_detailCell {\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n display: flex;\n}\n\n.qMtKNa_detailKey {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n font-size: 12px;\n}\n\n.qMtKNa_detailValue {\n color: var(--dsw-alias-label-primary, #1f2328);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n overflow: hidden;\n}\n\n.qMtKNa_detailDesc {\n color: var(--dsw-alias-label-secondary, #6b7280);\n margin: 4px 0 0;\n font-size: 13px;\n line-height: 20px;\n}\n\n.qMtKNa_mono {\n word-break: break-all;\n white-space: pre-wrap;\n color: var(--dsw-alias-label-primary, #1f2328);\n margin: 0;\n font-family: ui-monospace, Menlo, Consolas, monospace;\n font-size: 12px;\n line-height: 18px;\n}\n\n.qMtKNa_detailItem {\n border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n border-radius: 8px;\n flex-direction: column;\n display: flex;\n overflow: hidden;\n}\n\n.qMtKNa_detailItemRow, .qMtKNa_detailItemOpen {\n width: 100%;\n font: inherit;\n text-align: left;\n cursor: pointer;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: none;\n border: none;\n align-items: center;\n gap: 8px;\n padding: 7px 10px;\n display: flex;\n}\n\n.qMtKNa_detailItemRow:hover {\n background: var(--dsw-alias-bg-hover, #0000000d);\n}\n\n.qMtKNa_detailItemOpen {\n background: var(--dsw-alias-bg-selected, #4f6ef714);\n}\n\n.qMtKNa_detailItemName {\n flex-shrink: 0;\n font-size: 13px;\n font-weight: 600;\n}\n\n.qMtKNa_detailItemDesc {\n min-width: 0;\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n font-size: 12px;\n overflow: hidden;\n}\n\n.qMtKNa_detailChevron {\n color: var(--dsw-alias-label-tertiary, #8b93a1);\n flex-shrink: 0;\n}\n\n.qMtKNa_skillContent {\n border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb);\n max-height: 320px;\n color: var(--dsw-alias-label-primary, #1f2328);\n padding: 10px 12px;\n font-size: 13px;\n line-height: 20px;\n overflow-y: auto;\n}\n";document.head.appendChild(s);}})();
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
//#region \0rolldown/runtime.js
|
|
8
|
+
var __create = Object.create;
|
|
9
|
+
var __defProp = Object.defineProperty;
|
|
10
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
11
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
12
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __copyProps = (to, from, except, desc) => {
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
16
|
+
key = keys[i];
|
|
17
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
18
|
+
get: ((k) => from[k]).bind(null, key),
|
|
19
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
25
|
+
value: mod,
|
|
26
|
+
enumerable: true
|
|
27
|
+
}) : target, mod));
|
|
28
|
+
//#endregion
|
|
29
|
+
let react = require("react");
|
|
30
|
+
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
31
|
+
_deepseek_ai_dsh_client_ui_primitives = __toESM(_deepseek_ai_dsh_client_ui_primitives, 1);
|
|
32
|
+
//#region src/client/locales.ts
|
|
33
|
+
const zh = {
|
|
34
|
+
nav: "Agent Plugins 市场",
|
|
35
|
+
subtitle: "发现与安装 Agent Plugins(agent-plugins.org 便携包)",
|
|
36
|
+
searchPh: "搜索 Agent Plugins…",
|
|
37
|
+
tabAll: "全部",
|
|
38
|
+
tabInstalled: "已安装",
|
|
39
|
+
tabUninstalled: "未安装",
|
|
40
|
+
market: "仓库源",
|
|
41
|
+
addSource: "添加源",
|
|
42
|
+
sourceIdPh: "源 id(小写字母数字)",
|
|
43
|
+
sourceUrlPh: "git 仓库地址",
|
|
44
|
+
sourceUrlLocalPh: "本地仓库路径(绝对路径或 ~/…)",
|
|
45
|
+
sourceModeGit: "远程 git",
|
|
46
|
+
sourceModeLocal: "本地目录",
|
|
47
|
+
branchPh: "分支(可选)",
|
|
48
|
+
sourceLocal: "本地",
|
|
49
|
+
editSource: "编辑当前源",
|
|
50
|
+
editSourceTitle: "编辑仓库源",
|
|
51
|
+
addSourceTitle: "新增仓库源",
|
|
52
|
+
save: "保存",
|
|
53
|
+
confirmDelete: "确认删除",
|
|
54
|
+
refreshAll: "刷新全部",
|
|
55
|
+
detailTitle: "Agent Plugins 详情",
|
|
56
|
+
overviewSection: "概览",
|
|
57
|
+
skillsSection: "技能",
|
|
58
|
+
mcpSection: "MCP 服务",
|
|
59
|
+
commandsSection: "命令",
|
|
60
|
+
agentsSection: "子代理",
|
|
61
|
+
hooksLabel: "Hooks",
|
|
62
|
+
sourceLabel: "来源",
|
|
63
|
+
dimensionLabel: "维度",
|
|
64
|
+
layoutLabel: "布局",
|
|
65
|
+
statusLabel: "状态",
|
|
66
|
+
authorLabel: "作者",
|
|
67
|
+
keywordsLabel: "关键词",
|
|
68
|
+
disabledLabel: "已停用",
|
|
69
|
+
notInstalledLabel: "未安装",
|
|
70
|
+
noSkills: "(无技能)",
|
|
71
|
+
noMcp: "(无 MCP 服务)",
|
|
72
|
+
loading: "加载中…",
|
|
73
|
+
lspSection: "LSP 服务",
|
|
74
|
+
editorHint: "仓库源提供 Agent Plugins。本地目录直接读取(实时反映工作树);git 源克隆到 ~/.dsh/agent-plugins/.sources/<id>。",
|
|
75
|
+
idHint: "小写字母/数字/连字符,全局唯一",
|
|
76
|
+
urlGitHint: "git 仓库地址,例如 https://github.com/org/repo.git",
|
|
77
|
+
urlLocalHint: "绝对路径或 ~/…,直接读取本地目录(不克隆、移除源时不会删除)",
|
|
78
|
+
branchHint: "可选;不填则跟踪默认分支",
|
|
79
|
+
idFixed: "id 不可修改(源标识全局唯一)",
|
|
80
|
+
idAutoLabel: "源 ID(自动生成)",
|
|
81
|
+
idAutoHint: "自动从插件清单名或仓库名解析,无需填写",
|
|
82
|
+
detailHint: "点击技能或 MCP 服务行可展开查看详情",
|
|
83
|
+
add: "添加",
|
|
84
|
+
remove: "移除",
|
|
85
|
+
refresh: "刷新",
|
|
86
|
+
install: "安装",
|
|
87
|
+
installing: "安装中…",
|
|
88
|
+
installedBadge: "已安装",
|
|
89
|
+
uninstall: "卸载",
|
|
90
|
+
uninstallConfirmTitle: "卸载 Agent Plugins",
|
|
91
|
+
uninstallConfirmDesc: "将从已安装列表移除该 Agent Plugins,其技能与 MCP 工具随即停止注入。仓库源克隆保留。",
|
|
92
|
+
removeSourceConfirmTitle: "移除仓库源",
|
|
93
|
+
removeSourceConfirmDesc: "将删除该源的本地克隆与全部安装记录。",
|
|
94
|
+
enable: "启用",
|
|
95
|
+
disable: "禁用",
|
|
96
|
+
cancel: "取消",
|
|
97
|
+
confirm: "确认",
|
|
98
|
+
empty: "没有匹配的 Agent Plugins",
|
|
99
|
+
installedEmpty: "还没有安装 Agent Plugins",
|
|
100
|
+
loadFail: "Agent Plugins 目录加载失败,请稍后重试",
|
|
101
|
+
actionFail: "操作失败",
|
|
102
|
+
version: "版本",
|
|
103
|
+
dimensionUser: "用户级",
|
|
104
|
+
dimensionProject: "项目级",
|
|
105
|
+
layoutV1: "便携 v1",
|
|
106
|
+
layoutCC: "Claude Code",
|
|
107
|
+
layoutCodex: "Codex",
|
|
108
|
+
layoutSkills: "技能集合",
|
|
109
|
+
layoutUniversal: "通用",
|
|
110
|
+
layoutCursor: "Cursor",
|
|
111
|
+
layoutKimi: "Kimi",
|
|
112
|
+
layoutRemote: "远程引用",
|
|
113
|
+
remoteRef: "远程",
|
|
114
|
+
surfaceSkills: "技能",
|
|
115
|
+
surfaceMcp: "MCP",
|
|
116
|
+
surfaceHooks: "Hooks",
|
|
117
|
+
surfaceCommands: "命令",
|
|
118
|
+
surfaceAgents: "子代理",
|
|
119
|
+
surfaceLsp: "LSP",
|
|
120
|
+
sourceNotCloned: "未克隆",
|
|
121
|
+
sourceCloned: "已克隆",
|
|
122
|
+
errors: "校验问题",
|
|
123
|
+
grid: "网格",
|
|
124
|
+
list: "列表",
|
|
125
|
+
openSettings: "在设置中打开",
|
|
126
|
+
rootLabel: "Agent Plugins 目录",
|
|
127
|
+
dataLabel: "Agent Plugins 数据目录",
|
|
128
|
+
countAll: "共 {n} 个 Agent Plugins",
|
|
129
|
+
countInstalled: "已装 {n}",
|
|
130
|
+
countEnabled: "启用 {n}"
|
|
131
|
+
};
|
|
132
|
+
const en = {
|
|
133
|
+
nav: "Agent Plugins Market",
|
|
134
|
+
subtitle: "Discover and install Agent Plugins suites (agent-plugins.org portable packages)",
|
|
135
|
+
searchPh: "Search suites…",
|
|
136
|
+
tabAll: "All",
|
|
137
|
+
tabInstalled: "Installed",
|
|
138
|
+
tabUninstalled: "Uninstalled",
|
|
139
|
+
market: "Sources",
|
|
140
|
+
addSource: "Add source",
|
|
141
|
+
sourceIdPh: "source id (lowercase alnum)",
|
|
142
|
+
sourceUrlPh: "git repository URL",
|
|
143
|
+
sourceUrlLocalPh: "local repository path (absolute or ~/…)",
|
|
144
|
+
sourceModeGit: "remote git",
|
|
145
|
+
sourceModeLocal: "local dir",
|
|
146
|
+
branchPh: "branch (optional)",
|
|
147
|
+
sourceLocal: "local",
|
|
148
|
+
editSource: "Edit source",
|
|
149
|
+
editSourceTitle: "Edit source",
|
|
150
|
+
addSourceTitle: "Add source",
|
|
151
|
+
save: "Save",
|
|
152
|
+
confirmDelete: "Delete",
|
|
153
|
+
refreshAll: "Refresh all",
|
|
154
|
+
detailTitle: "Suite details",
|
|
155
|
+
overviewSection: "Overview",
|
|
156
|
+
skillsSection: "Skills",
|
|
157
|
+
mcpSection: "MCP servers",
|
|
158
|
+
commandsSection: "Commands",
|
|
159
|
+
agentsSection: "Subagents",
|
|
160
|
+
hooksLabel: "Hooks",
|
|
161
|
+
sourceLabel: "Source",
|
|
162
|
+
dimensionLabel: "Dimension",
|
|
163
|
+
layoutLabel: "Layout",
|
|
164
|
+
statusLabel: "Status",
|
|
165
|
+
authorLabel: "Author",
|
|
166
|
+
keywordsLabel: "Keywords",
|
|
167
|
+
disabledLabel: "disabled",
|
|
168
|
+
notInstalledLabel: "not installed",
|
|
169
|
+
noSkills: "(no skills)",
|
|
170
|
+
noMcp: "(no MCP servers)",
|
|
171
|
+
loading: "Loading…",
|
|
172
|
+
lspSection: "LSP servers",
|
|
173
|
+
editorHint: "A source provides suites (Agent Plugins). Local directories are read in place (live working tree); git sources clone into ~/.dsh/agent-plugins/.sources/<id>.",
|
|
174
|
+
idHint: "lowercase letters / digits / hyphens, globally unique",
|
|
175
|
+
urlGitHint: "git repository URL, e.g. https://github.com/org/repo.git",
|
|
176
|
+
urlLocalHint: "absolute path or ~/…, read in place (never cloned, never deleted on removal)",
|
|
177
|
+
branchHint: "optional; defaults to the repository default branch",
|
|
178
|
+
idFixed: "id is fixed (the source identifier is globally unique)",
|
|
179
|
+
idAutoLabel: "Source ID (auto)",
|
|
180
|
+
idAutoHint: "Derived from the suite or repo name — no need to type it",
|
|
181
|
+
detailHint: "Click a skill or MCP server row to expand its details",
|
|
182
|
+
add: "Add",
|
|
183
|
+
remove: "Remove",
|
|
184
|
+
refresh: "Refresh",
|
|
185
|
+
install: "Install",
|
|
186
|
+
installing: "Installing…",
|
|
187
|
+
installedBadge: "Installed",
|
|
188
|
+
uninstall: "Uninstall",
|
|
189
|
+
uninstallConfirmTitle: "Uninstall suite",
|
|
190
|
+
uninstallConfirmDesc: "Removes the suite from the installed list; its skills and MCP tools stop injecting. The source clone stays.",
|
|
191
|
+
removeSourceConfirmTitle: "Remove source",
|
|
192
|
+
removeSourceConfirmDesc: "Deletes the local clone and all install records of this source.",
|
|
193
|
+
enable: "Enable",
|
|
194
|
+
disable: "Disable",
|
|
195
|
+
cancel: "Cancel",
|
|
196
|
+
confirm: "Confirm",
|
|
197
|
+
empty: "No matching suites",
|
|
198
|
+
installedEmpty: "No suites installed yet",
|
|
199
|
+
loadFail: "Failed to load the suite catalog, try again later",
|
|
200
|
+
actionFail: "Action failed",
|
|
201
|
+
version: "Version",
|
|
202
|
+
dimensionUser: "user",
|
|
203
|
+
dimensionProject: "project",
|
|
204
|
+
layoutV1: "portable v1",
|
|
205
|
+
layoutCC: "Claude Code",
|
|
206
|
+
layoutCodex: "Codex",
|
|
207
|
+
layoutSkills: "skill dir",
|
|
208
|
+
layoutUniversal: "universal",
|
|
209
|
+
layoutCursor: "Cursor",
|
|
210
|
+
layoutKimi: "Kimi",
|
|
211
|
+
layoutRemote: "remote reference",
|
|
212
|
+
remoteRef: "remote",
|
|
213
|
+
surfaceSkills: "skills",
|
|
214
|
+
surfaceMcp: "MCP",
|
|
215
|
+
surfaceHooks: "hooks",
|
|
216
|
+
surfaceCommands: "commands",
|
|
217
|
+
surfaceAgents: "subagents",
|
|
218
|
+
surfaceLsp: "LSP",
|
|
219
|
+
sourceNotCloned: "not cloned",
|
|
220
|
+
sourceCloned: "cloned",
|
|
221
|
+
errors: "validation issues",
|
|
222
|
+
grid: "grid",
|
|
223
|
+
list: "list",
|
|
224
|
+
openSettings: "Open in settings",
|
|
225
|
+
rootLabel: "Suite root",
|
|
226
|
+
dataLabel: "Suite data root",
|
|
227
|
+
countAll: "{n} suites",
|
|
228
|
+
countInstalled: "{n} installed",
|
|
229
|
+
countEnabled: "{n} enabled"
|
|
230
|
+
};
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/client/api.ts
|
|
233
|
+
async function fetchOverview() {
|
|
234
|
+
const response = await fetch("/api/agent-plugins/overview", { credentials: "same-origin" });
|
|
235
|
+
if (!response.ok) throw new Error(`overview failed: ${response.status}`);
|
|
236
|
+
return response.json();
|
|
237
|
+
}
|
|
238
|
+
async function fetchSuiteDetail(sourceId, suiteId) {
|
|
239
|
+
const response = await fetch(`/api/agent-plugins/suite?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}`, { credentials: "same-origin" });
|
|
240
|
+
if (!response.ok) throw new Error(`suite detail failed: ${response.status}`);
|
|
241
|
+
return response.json();
|
|
242
|
+
}
|
|
243
|
+
async function fetchSkillContent(sourceId, suiteId, skill) {
|
|
244
|
+
const response = await fetch(`/api/agent-plugins/skill?sourceId=${encodeURIComponent(sourceId)}&suiteId=${encodeURIComponent(suiteId)}&skill=${encodeURIComponent(skill)}`, { credentials: "same-origin" });
|
|
245
|
+
if (!response.ok) throw new Error(`skill content failed: ${response.status}`);
|
|
246
|
+
return response.json();
|
|
247
|
+
}
|
|
248
|
+
async function postAction(path, body) {
|
|
249
|
+
const response = await fetch(`/api/agent-plugins/${path}`, {
|
|
250
|
+
method: "POST",
|
|
251
|
+
credentials: "same-origin",
|
|
252
|
+
headers: { "content-type": "application/json" },
|
|
253
|
+
body: JSON.stringify(body)
|
|
254
|
+
});
|
|
255
|
+
const payload = await response.json();
|
|
256
|
+
if (!response.ok || payload.ok !== true) throw new Error(payload.error ?? `request failed: ${response.status}`);
|
|
257
|
+
return payload;
|
|
258
|
+
}
|
|
259
|
+
//#endregion
|
|
260
|
+
//#region src/client/ErrorBoundary.tsx
|
|
261
|
+
/**
|
|
262
|
+
* Error boundary for untrusted preview content.
|
|
263
|
+
*
|
|
264
|
+
* Skill/command/agent bodies and hook/LSP JSON are third-party content; a
|
|
265
|
+
* renderer throw must degrade to a plain-text fallback instead of unmounting
|
|
266
|
+
* the whole settings section (React has no built-in boundary).
|
|
267
|
+
*/
|
|
268
|
+
var ErrorBoundary = class extends react.Component {
|
|
269
|
+
state = { error: void 0 };
|
|
270
|
+
static getDerivedStateFromError(error) {
|
|
271
|
+
return { error };
|
|
272
|
+
}
|
|
273
|
+
componentDidCatch(error, info) {
|
|
274
|
+
console.warn("[dsh-agent-plugins-market] preview render failed:", error, info);
|
|
275
|
+
}
|
|
276
|
+
render() {
|
|
277
|
+
if (this.state.error !== void 0) return this.props.fallback === void 0 ? (0, react.createElement)("pre", { className: "dsh-agent-plugins-fallback" }, `预览渲染失败:${this.state.error.message}`) : this.props.fallback(this.state.error);
|
|
278
|
+
return this.props.children;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
//#endregion
|
|
282
|
+
//#region src/client/market.module.css
|
|
283
|
+
var market_module_default = {
|
|
284
|
+
"body": "qMtKNa_body",
|
|
285
|
+
"card": "qMtKNa_card",
|
|
286
|
+
"cardActions": "qMtKNa_cardActions",
|
|
287
|
+
"cardDesc": "qMtKNa_cardDesc",
|
|
288
|
+
"cardName": "qMtKNa_cardName",
|
|
289
|
+
"cardTitle": "qMtKNa_cardTitle",
|
|
290
|
+
"cardTop": "qMtKNa_cardTop",
|
|
291
|
+
"desc": "qMtKNa_desc",
|
|
292
|
+
"detailBody": "qMtKNa_detailBody",
|
|
293
|
+
"detailCell": "qMtKNa_detailCell",
|
|
294
|
+
"detailChevron": "qMtKNa_detailChevron",
|
|
295
|
+
"detailDesc": "qMtKNa_detailDesc",
|
|
296
|
+
"detailDialog": "qMtKNa_detailDialog",
|
|
297
|
+
"detailGrid": "qMtKNa_detailGrid",
|
|
298
|
+
"detailHead": "qMtKNa_detailHead",
|
|
299
|
+
"detailItem": "qMtKNa_detailItem",
|
|
300
|
+
"detailItemDesc": "qMtKNa_detailItemDesc",
|
|
301
|
+
"detailItemName": "qMtKNa_detailItemName",
|
|
302
|
+
"detailItemOpen": "qMtKNa_detailItemOpen",
|
|
303
|
+
"detailItemRow": "qMtKNa_detailItemRow",
|
|
304
|
+
"detailKey": "qMtKNa_detailKey",
|
|
305
|
+
"detailSection": "qMtKNa_detailSection",
|
|
306
|
+
"detailSections": "qMtKNa_detailSections",
|
|
307
|
+
"detailValue": "qMtKNa_detailValue",
|
|
308
|
+
"editorDialog": "qMtKNa_editorDialog",
|
|
309
|
+
"editorForm": "qMtKNa_editorForm",
|
|
310
|
+
"empty": "qMtKNa_empty",
|
|
311
|
+
"fieldGroup": "qMtKNa_fieldGroup",
|
|
312
|
+
"fieldHint": "qMtKNa_fieldHint",
|
|
313
|
+
"fieldLabel": "qMtKNa_fieldLabel",
|
|
314
|
+
"grid": "qMtKNa_grid",
|
|
315
|
+
"header": "qMtKNa_header",
|
|
316
|
+
"list": "qMtKNa_list",
|
|
317
|
+
"market": "qMtKNa_market",
|
|
318
|
+
"meta": "qMtKNa_meta",
|
|
319
|
+
"modalFooter": "qMtKNa_modalFooter",
|
|
320
|
+
"modalFooterLeft": "qMtKNa_modalFooterLeft",
|
|
321
|
+
"modeRow": "qMtKNa_modeRow",
|
|
322
|
+
"mono": "qMtKNa_mono",
|
|
323
|
+
"okState": "qMtKNa_okState",
|
|
324
|
+
"searchGroup": "qMtKNa_searchGroup",
|
|
325
|
+
"searchInput": "qMtKNa_searchInput",
|
|
326
|
+
"searchWrap": "qMtKNa_searchWrap",
|
|
327
|
+
"seg": "qMtKNa_seg",
|
|
328
|
+
"segOn": "qMtKNa_segOn",
|
|
329
|
+
"skillContent": "qMtKNa_skillContent",
|
|
330
|
+
"sourceTabsRow": "qMtKNa_sourceTabsRow",
|
|
331
|
+
"sourceTabsScroll": "qMtKNa_sourceTabsScroll",
|
|
332
|
+
"spacer": "qMtKNa_spacer",
|
|
333
|
+
"src": "qMtKNa_src",
|
|
334
|
+
"srcTab": "qMtKNa_srcTab",
|
|
335
|
+
"srcTabDel": "qMtKNa_srcTabDel",
|
|
336
|
+
"srcTabEdit": "qMtKNa_srcTabEdit",
|
|
337
|
+
"srcTabMain": "qMtKNa_srcTabMain",
|
|
338
|
+
"srcTabOn": "qMtKNa_srcTabOn",
|
|
339
|
+
"staticId": "qMtKNa_staticId",
|
|
340
|
+
"staticIdValue": "qMtKNa_staticIdValue",
|
|
341
|
+
"sub": "qMtKNa_sub",
|
|
342
|
+
"switchOff": "qMtKNa_switchOff",
|
|
343
|
+
"switchOn": "qMtKNa_switchOn",
|
|
344
|
+
"switchThumb": "qMtKNa_switchThumb",
|
|
345
|
+
"tab": "qMtKNa_tab",
|
|
346
|
+
"tabGap": "qMtKNa_tabGap",
|
|
347
|
+
"tabOn": "qMtKNa_tabOn",
|
|
348
|
+
"tabRow": "qMtKNa_tabRow",
|
|
349
|
+
"tag": "qMtKNa_tag",
|
|
350
|
+
"title": "qMtKNa_title",
|
|
351
|
+
"titleRow": "qMtKNa_titleRow",
|
|
352
|
+
"version": "qMtKNa_version",
|
|
353
|
+
"viewSwitch": "qMtKNa_viewSwitch",
|
|
354
|
+
"warnLine": "qMtKNa_warnLine"
|
|
355
|
+
};
|
|
356
|
+
//#endregion
|
|
357
|
+
//#region src/client/SuiteDetail.tsx
|
|
358
|
+
/**
|
|
359
|
+
* Suite detail modal: click one suite card to browse its internals.
|
|
360
|
+
*
|
|
361
|
+
* Sections: manifest overview, the skill list (each skill expands to its
|
|
362
|
+
* SKILL.md body through the safe MarkdownText renderer), the validated
|
|
363
|
+
* mcp.json servers (each expands to its full config), command/subagent file
|
|
364
|
+
* lists, hook/LSP counts, and validation diagnostics.
|
|
365
|
+
*/
|
|
366
|
+
function SuiteDetailModal({ t, sourceId, suiteId, onClose }) {
|
|
367
|
+
const [detail, setDetail] = (0, react.useState)(void 0);
|
|
368
|
+
const [error, setError] = (0, react.useState)(void 0);
|
|
369
|
+
const [openSkill, setOpenSkill] = (0, react.useState)(void 0);
|
|
370
|
+
const [skillText, setSkillText] = (0, react.useState)(void 0);
|
|
371
|
+
const [skillLoading, setSkillLoading] = (0, react.useState)(false);
|
|
372
|
+
const [openMcp, setOpenMcp] = (0, react.useState)(void 0);
|
|
373
|
+
const [openPreview, setOpenPreview] = (0, react.useState)(void 0);
|
|
374
|
+
(0, react.useEffect)(() => {
|
|
375
|
+
let cancelled = false;
|
|
376
|
+
setDetail(void 0);
|
|
377
|
+
setError(void 0);
|
|
378
|
+
fetchSuiteDetail(sourceId, suiteId).then((value) => {
|
|
379
|
+
if (!cancelled) setDetail(value);
|
|
380
|
+
}).catch((reason) => {
|
|
381
|
+
if (!cancelled) setError(reason instanceof Error ? reason.message : String(reason));
|
|
382
|
+
});
|
|
383
|
+
return () => {
|
|
384
|
+
cancelled = true;
|
|
385
|
+
};
|
|
386
|
+
}, [sourceId, suiteId]);
|
|
387
|
+
const toggleSkill = async (name) => {
|
|
388
|
+
if (openSkill === name) {
|
|
389
|
+
setOpenSkill(void 0);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
setOpenSkill(name);
|
|
393
|
+
setSkillLoading(true);
|
|
394
|
+
setSkillText(void 0);
|
|
395
|
+
try {
|
|
396
|
+
const content = await fetchSkillContent(sourceId, suiteId, name);
|
|
397
|
+
setSkillText(content.content);
|
|
398
|
+
} catch (reason) {
|
|
399
|
+
setSkillText(`⚠ ${reason instanceof Error ? reason.message : String(reason)}`);
|
|
400
|
+
} finally {
|
|
401
|
+
setSkillLoading(false);
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
const toggleMcp = (key) => {
|
|
405
|
+
setOpenMcp(openMcp === key ? void 0 : key);
|
|
406
|
+
};
|
|
407
|
+
const layoutLabel = detail === void 0 ? "" : detail.layout === "agent-plugin-v1" ? t("layoutV1") : detail.layout === "claude-code" ? t("layoutCC") : detail.layout === "codex" ? t("layoutCodex") : detail.layout === "remote" ? t("layoutRemote") : t("layoutSkills");
|
|
408
|
+
return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
409
|
+
open: true,
|
|
410
|
+
onClose,
|
|
411
|
+
title: detail === void 0 ? t("detailTitle") : `${detail.name}${detail.version === null ? "" : ` v${detail.version}`}`,
|
|
412
|
+
description: detail === void 0 ? void 0 : t("detailHint"),
|
|
413
|
+
closeLabel: t("cancel"),
|
|
414
|
+
className: market_module_default.detailDialog,
|
|
415
|
+
contentClassName: market_module_default.detailBody,
|
|
416
|
+
footer: (0, react.createElement)("div", { className: market_module_default.modalFooter }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
417
|
+
variant: "ghost",
|
|
418
|
+
onClick: onClose
|
|
419
|
+
}, t("cancel"))),
|
|
420
|
+
children: (0, react.createElement)(ErrorBoundary, {
|
|
421
|
+
fallback: (boundaryError) => (0, react.createElement)("div", { className: market_module_default.warnLine }, `${t("actionFail")}: ${boundaryError.message}`),
|
|
422
|
+
children: error !== void 0 ? (0, react.createElement)("div", { className: market_module_default.warnLine }, error) : detail === void 0 ? (0, react.createElement)("div", { className: market_module_default.empty }, t("loading")) : (0, react.createElement)("div", { className: market_module_default.detailSections }, (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, t("overviewSection")), (0, react.createElement)("div", { className: market_module_default.detailGrid }, (0, react.createElement)("div", { className: market_module_default.detailCell }, (0, react.createElement)("span", { className: market_module_default.detailKey }, t("sourceLabel")), (0, react.createElement)("span", { className: market_module_default.detailValue }, detail.sourceId)), (0, react.createElement)("div", { className: market_module_default.detailCell }, (0, react.createElement)("span", { className: market_module_default.detailKey }, t("dimensionLabel")), (0, react.createElement)("span", { className: market_module_default.detailValue }, detail.dimension === "user" ? t("dimensionUser") : t("dimensionProject"))), (0, react.createElement)("div", { className: market_module_default.detailCell }, (0, react.createElement)("span", { className: market_module_default.detailKey }, t("layoutLabel")), (0, react.createElement)("span", { className: market_module_default.detailValue }, layoutLabel)), (0, react.createElement)("div", { className: market_module_default.detailCell }, (0, react.createElement)("span", { className: market_module_default.detailKey }, t("statusLabel")), (0, react.createElement)("span", { className: detail.enabled ? market_module_default.okState : market_module_default.detailValue }, detail.installed ? detail.enabled ? t("installedBadge") : t("disabledLabel") : t("notInstalledLabel"))), detail.author === null ? null : (0, react.createElement)("div", { className: market_module_default.detailCell }, (0, react.createElement)("span", { className: market_module_default.detailKey }, t("authorLabel")), (0, react.createElement)("span", { className: market_module_default.detailValue }, detail.author)), detail.keywords.length === 0 ? null : (0, react.createElement)("div", { className: market_module_default.detailCell }, (0, react.createElement)("span", { className: market_module_default.detailKey }, t("keywordsLabel")), (0, react.createElement)("span", { className: market_module_default.detailValue }, detail.keywords.join(", ")))), detail.description === null ? null : (0, react.createElement)("p", { className: market_module_default.detailDesc }, detail.description), (0, react.createElement)("div", { className: market_module_default.detailCell }, (0, react.createElement)("span", { className: market_module_default.detailKey }, t("rootLabel")), (0, react.createElement)("span", { className: market_module_default.mono }, detail.root))), (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("skillsSection")} (${detail.skills.length})`), detail.skills.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.skills.map((skill) => (0, react.createElement)("div", {
|
|
423
|
+
key: skill.name,
|
|
424
|
+
className: market_module_default.detailItem
|
|
425
|
+
}, (0, react.createElement)("button", {
|
|
426
|
+
type: "button",
|
|
427
|
+
className: openSkill === skill.name ? market_module_default.detailItemOpen : market_module_default.detailItemRow,
|
|
428
|
+
onClick: () => {
|
|
429
|
+
toggleSkill(skill.name);
|
|
430
|
+
}
|
|
431
|
+
}, (0, react.createElement)("span", { className: market_module_default.detailItemName }, skill.name), (0, react.createElement)("span", { className: market_module_default.detailItemDesc }, skill.description), (0, react.createElement)("span", { className: market_module_default.detailChevron }, openSkill === skill.name ? "▾" : "▸")), openSkill !== skill.name ? null : (0, react.createElement)("div", { className: market_module_default.skillContent }, skillLoading ? t("loading") : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, { text: skillText ?? "" }))))), (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("mcpSection")} (${detail.mcpServers.length})`), detail.mcpServers.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.mcpServers.map((server) => (0, react.createElement)("div", {
|
|
432
|
+
key: server.key,
|
|
433
|
+
className: market_module_default.detailItem
|
|
434
|
+
}, (0, react.createElement)("button", {
|
|
435
|
+
type: "button",
|
|
436
|
+
className: openMcp === server.key ? market_module_default.detailItemOpen : market_module_default.detailItemRow,
|
|
437
|
+
onClick: () => toggleMcp(server.key)
|
|
438
|
+
}, (0, react.createElement)("span", { className: market_module_default.detailItemName }, server.key), (0, react.createElement)("span", { className: market_module_default.detailItemDesc }, mcpSummary(server)), (0, react.createElement)("span", { className: market_module_default.detailChevron }, openMcp === server.key ? "▾" : "▸")), openMcp !== server.key ? null : (0, react.createElement)("pre", { className: market_module_default.mono }, JSON.stringify(server, null, 2))))), (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("commandsSection")} (${detail.commands.length})`), detail.commands.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.commands.map((command) => (0, react.createElement)(PreviewRow, {
|
|
439
|
+
key: `c:${command.name}`,
|
|
440
|
+
t,
|
|
441
|
+
name: `/${command.name}`,
|
|
442
|
+
description: command.description,
|
|
443
|
+
open: openPreview === `c:${command.name}`,
|
|
444
|
+
onToggle: () => setOpenPreview(openPreview === `c:${command.name}` ? void 0 : `c:${command.name}`),
|
|
445
|
+
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, { text: command.content })
|
|
446
|
+
}))), (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("agentsSection")} (${detail.agents.length})`), detail.agents.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.agents.map((agent) => (0, react.createElement)(PreviewRow, {
|
|
447
|
+
key: `a:${agent.name}`,
|
|
448
|
+
t,
|
|
449
|
+
name: agent.name,
|
|
450
|
+
description: agent.description,
|
|
451
|
+
open: openPreview === `a:${agent.name}`,
|
|
452
|
+
onToggle: () => setOpenPreview(openPreview === `a:${agent.name}` ? void 0 : `a:${agent.name}`),
|
|
453
|
+
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, { text: agent.content })
|
|
454
|
+
}))), (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("hooksLabel")} (${detail.hooks.count})`), detail.hooks.count === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.hooks.entries.map((hook, index) => (0, react.createElement)(PreviewRow, {
|
|
455
|
+
key: `h:${index}`,
|
|
456
|
+
t,
|
|
457
|
+
name: hook.event,
|
|
458
|
+
description: hook.command,
|
|
459
|
+
open: openPreview === `h:${index}`,
|
|
460
|
+
onToggle: () => setOpenPreview(openPreview === `h:${index}` ? void 0 : `h:${index}`),
|
|
461
|
+
children: (0, react.createElement)("pre", { className: market_module_default.mono }, JSON.stringify(hook, null, 2))
|
|
462
|
+
}))), (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("lspSection")} (${detail.lsp.length})`), detail.lsp.length === 0 ? (0, react.createElement)("div", { className: market_module_default.sidebarEmpty }, "—") : detail.lsp.map((entry) => (0, react.createElement)(PreviewRow, {
|
|
463
|
+
key: `l:${entry.name}`,
|
|
464
|
+
t,
|
|
465
|
+
name: entry.name,
|
|
466
|
+
open: openPreview === `l:${entry.name}`,
|
|
467
|
+
onToggle: () => setOpenPreview(openPreview === `l:${entry.name}` ? void 0 : `l:${entry.name}`),
|
|
468
|
+
children: (0, react.createElement)("pre", { className: market_module_default.mono }, entry.content)
|
|
469
|
+
}))), detail.errors.length === 0 ? null : (0, react.createElement)("section", { className: market_module_default.detailSection }, (0, react.createElement)("h4", { className: market_module_default.detailHead }, `${t("errors")} (${detail.errors.length})`), detail.errors.map((entry, index) => (0, react.createElement)("div", {
|
|
470
|
+
key: index,
|
|
471
|
+
className: market_module_default.warnLine
|
|
472
|
+
}, entry))))
|
|
473
|
+
})
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
function mcpSummary(server) {
|
|
477
|
+
if (server.type === "stdio") return server.command ?? server.type;
|
|
478
|
+
return server.url ?? server.type;
|
|
479
|
+
}
|
|
480
|
+
function PreviewRow(props) {
|
|
481
|
+
const { t: _t, name, description, open, onToggle, children } = props;
|
|
482
|
+
return (0, react.createElement)("div", { className: market_module_default.detailItem }, (0, react.createElement)("button", {
|
|
483
|
+
type: "button",
|
|
484
|
+
className: open ? market_module_default.detailItemOpen : market_module_default.detailItemRow,
|
|
485
|
+
onClick: onToggle
|
|
486
|
+
}, (0, react.createElement)("span", { className: market_module_default.detailItemName }, name), description === void 0 ? null : (0, react.createElement)("span", { className: market_module_default.detailItemDesc }, description), (0, react.createElement)("span", { className: market_module_default.detailChevron }, open ? "▾" : "▸")), open ? (0, react.createElement)("div", { className: market_module_default.skillContent }, children) : null);
|
|
487
|
+
}
|
|
488
|
+
//#endregion
|
|
489
|
+
//#region src/client/MarketSection.tsx
|
|
490
|
+
/**
|
|
491
|
+
* The Agent Plugins Market settings section.
|
|
492
|
+
*
|
|
493
|
+
* Layout: repository sources run along the TOP as chips (全部 first), with
|
|
494
|
+
* edit-current / add / refresh-all controls on the right; below sit search,
|
|
495
|
+
* status tabs, and the card grid. Colors ride the dsh --dsw-alias-* tokens
|
|
496
|
+
* with light-mode fallbacks so the page follows the active theme.
|
|
497
|
+
*/
|
|
498
|
+
const EMPTY_OVERVIEW = {
|
|
499
|
+
sources: [],
|
|
500
|
+
suites: [],
|
|
501
|
+
totals: {
|
|
502
|
+
all: 0,
|
|
503
|
+
installed: 0,
|
|
504
|
+
enabled: 0
|
|
505
|
+
},
|
|
506
|
+
roots: {
|
|
507
|
+
user: "",
|
|
508
|
+
data: ""
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
function MarketSection({ t }) {
|
|
512
|
+
const [overview, setOverview] = (0, react.useState)(EMPTY_OVERVIEW);
|
|
513
|
+
const [loading, setLoading] = (0, react.useState)(true);
|
|
514
|
+
const [search, setSearch] = (0, react.useState)("");
|
|
515
|
+
const [tab, setTab] = (0, react.useState)("all");
|
|
516
|
+
const [category, setCategory] = (0, react.useState)("all");
|
|
517
|
+
const [view, setView] = (0, react.useState)("grid");
|
|
518
|
+
const [busy, setBusy] = (0, react.useState)(void 0);
|
|
519
|
+
const [toast, setToast] = (0, react.useState)(void 0);
|
|
520
|
+
const [confirm, setConfirm] = (0, react.useState)(void 0);
|
|
521
|
+
const [editor, setEditor] = (0, react.useState)(void 0);
|
|
522
|
+
const [detail, setDetail] = (0, react.useState)(void 0);
|
|
523
|
+
const refresh = (0, react.useCallback)(async () => {
|
|
524
|
+
try {
|
|
525
|
+
setOverview(await fetchOverview());
|
|
526
|
+
} catch {
|
|
527
|
+
setToast({
|
|
528
|
+
key: Date.now(),
|
|
529
|
+
message: t("loadFail")
|
|
530
|
+
});
|
|
531
|
+
} finally {
|
|
532
|
+
setLoading(false);
|
|
533
|
+
}
|
|
534
|
+
}, [t]);
|
|
535
|
+
(0, react.useEffect)(() => {
|
|
536
|
+
refresh();
|
|
537
|
+
}, [refresh]);
|
|
538
|
+
const action = (0, react.useCallback)(async (key, path, body) => {
|
|
539
|
+
setBusy(key);
|
|
540
|
+
try {
|
|
541
|
+
await postAction(path, body);
|
|
542
|
+
await refresh();
|
|
543
|
+
return true;
|
|
544
|
+
} catch (error) {
|
|
545
|
+
setToast({
|
|
546
|
+
key: Date.now(),
|
|
547
|
+
message: `${t("actionFail")}: ${error instanceof Error ? error.message : String(error)}`
|
|
548
|
+
});
|
|
549
|
+
return false;
|
|
550
|
+
} finally {
|
|
551
|
+
setBusy(void 0);
|
|
552
|
+
}
|
|
553
|
+
}, [refresh, t]);
|
|
554
|
+
const scopeTotals = (0, react.useMemo)(() => {
|
|
555
|
+
if (category === "all") return overview.totals;
|
|
556
|
+
const scoped = overview.suites.filter((suite) => suite.sourceId === category);
|
|
557
|
+
return {
|
|
558
|
+
all: scoped.length,
|
|
559
|
+
installed: scoped.filter((suite) => suite.installed).length,
|
|
560
|
+
enabled: scoped.filter((suite) => suite.enabled).length
|
|
561
|
+
};
|
|
562
|
+
}, [overview, category]);
|
|
563
|
+
const filtered = (0, react.useMemo)(() => {
|
|
564
|
+
const needle = search.trim().toLowerCase();
|
|
565
|
+
return overview.suites.filter((suite) => {
|
|
566
|
+
if (category !== "all" && suite.sourceId !== category) return false;
|
|
567
|
+
if (tab === "installed" && !suite.installed) return false;
|
|
568
|
+
if (tab === "uninstalled" && suite.installed) return false;
|
|
569
|
+
if (needle === "") return true;
|
|
570
|
+
return `${suite.name} ${suite.description ?? ""} ${suite.keywords.join(" ")}`.toLowerCase().includes(needle);
|
|
571
|
+
});
|
|
572
|
+
}, [
|
|
573
|
+
overview,
|
|
574
|
+
search,
|
|
575
|
+
tab,
|
|
576
|
+
category
|
|
577
|
+
]);
|
|
578
|
+
const openUninstall = (0, react.useCallback)((suite) => {
|
|
579
|
+
setConfirm({
|
|
580
|
+
kind: "uninstall",
|
|
581
|
+
sourceId: suite.sourceId,
|
|
582
|
+
suiteId: suite.suiteId
|
|
583
|
+
});
|
|
584
|
+
}, []);
|
|
585
|
+
const confirmAction = (0, react.useCallback)(async () => {
|
|
586
|
+
if (confirm === void 0) return;
|
|
587
|
+
if (confirm.kind === "uninstall" && confirm.suiteId !== void 0) await action(`u:${confirm.suiteId}`, "uninstall", {
|
|
588
|
+
sourceId: confirm.sourceId,
|
|
589
|
+
suiteId: confirm.suiteId
|
|
590
|
+
});
|
|
591
|
+
else if (confirm.kind === "removeSource") {
|
|
592
|
+
await action(`s:${confirm.sourceId}`, "sources/remove", { id: confirm.sourceId });
|
|
593
|
+
if (category === confirm.sourceId) setCategory("all");
|
|
594
|
+
}
|
|
595
|
+
setConfirm(void 0);
|
|
596
|
+
}, [
|
|
597
|
+
confirm,
|
|
598
|
+
action,
|
|
599
|
+
category
|
|
600
|
+
]);
|
|
601
|
+
const selectedSource = category === "all" ? void 0 : overview.sources.find((source) => source.id === category);
|
|
602
|
+
return (0, react.createElement)(ErrorBoundary, {
|
|
603
|
+
fallback: (error) => (0, react.createElement)("div", { className: market_module_default.empty }, `${t("actionFail")}: ${error.message}`),
|
|
604
|
+
children: (0, react.createElement)("div", { className: market_module_default.market }, (0, react.createElement)("header", { className: market_module_default.header }, (0, react.createElement)("div", { className: market_module_default.titleRow }, (0, react.createElement)("h2", { className: market_module_default.title }, t("nav")), (0, react.createElement)("p", { className: market_module_default.sub }, t("subtitle")), (0, react.createElement)("div", { className: market_module_default.spacer }), (0, react.createElement)("div", { className: market_module_default.searchGroup }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
605
|
+
variant: "ghost",
|
|
606
|
+
size: "sm",
|
|
607
|
+
title: t("addSource"),
|
|
608
|
+
onClick: () => setEditor({ mode: "add" })
|
|
609
|
+
}, "+"), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
610
|
+
variant: "ghost",
|
|
611
|
+
size: "sm",
|
|
612
|
+
title: t("refreshAll"),
|
|
613
|
+
onClick: () => {
|
|
614
|
+
action("s:refresh:all", "sources/refresh", {});
|
|
615
|
+
}
|
|
616
|
+
}, "↻"), (0, react.createElement)("div", { className: market_module_default.searchWrap }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
617
|
+
className: market_module_default.searchInput,
|
|
618
|
+
placeholder: t("searchPh"),
|
|
619
|
+
value: search,
|
|
620
|
+
onChange: (event) => setSearch(event.target.value)
|
|
621
|
+
})))), (0, react.createElement)("div", { className: market_module_default.sourceTabsRow }, (0, react.createElement)("div", { className: market_module_default.sourceTabsScroll }, (0, react.createElement)(SourceTab, {
|
|
622
|
+
key: "__all__",
|
|
623
|
+
t,
|
|
624
|
+
active: category === "all",
|
|
625
|
+
label: `${t("tabAll")} ${overview.totals.all}`,
|
|
626
|
+
onSelect: () => setCategory("all")
|
|
627
|
+
}), ...[...overview.sources].sort((a, b) => a.id.localeCompare(b.id)).map((source) => (0, react.createElement)(SourceTab, {
|
|
628
|
+
key: source.id,
|
|
629
|
+
t,
|
|
630
|
+
active: category === source.id,
|
|
631
|
+
label: `${source.id}${source.local === true ? ` · ${t("sourceLocal")}` : ""} ${source.suiteIds.length}${source.cloned === false ? " ⚠" : ""}`,
|
|
632
|
+
onSelect: () => setCategory(source.id),
|
|
633
|
+
onDelete: () => setConfirm({
|
|
634
|
+
kind: "removeSource",
|
|
635
|
+
sourceId: source.id
|
|
636
|
+
}),
|
|
637
|
+
onEdit: selectedSource?.id === source.id ? () => setEditor({
|
|
638
|
+
mode: "edit",
|
|
639
|
+
source
|
|
640
|
+
}) : void 0
|
|
641
|
+
})))), (0, react.createElement)("div", { className: market_module_default.tabRow }, (0, react.createElement)(TabButton, {
|
|
642
|
+
t,
|
|
643
|
+
active: tab === "all",
|
|
644
|
+
label: `${t("tabAll")} ${scopeTotals.all}`,
|
|
645
|
+
onClick: () => setTab("all")
|
|
646
|
+
}), (0, react.createElement)(TabButton, {
|
|
647
|
+
t,
|
|
648
|
+
active: tab === "installed",
|
|
649
|
+
label: `${t("tabInstalled")} ${scopeTotals.installed}`,
|
|
650
|
+
onClick: () => setTab("installed")
|
|
651
|
+
}), (0, react.createElement)(TabButton, {
|
|
652
|
+
t,
|
|
653
|
+
active: tab === "uninstalled",
|
|
654
|
+
label: `${t("tabUninstalled")} ${scopeTotals.all - scopeTotals.installed}`,
|
|
655
|
+
onClick: () => setTab("uninstalled")
|
|
656
|
+
}), (0, react.createElement)("div", { className: market_module_default.tabGap }), (0, react.createElement)("button", {
|
|
657
|
+
type: "button",
|
|
658
|
+
className: market_module_default.viewSwitch,
|
|
659
|
+
onClick: () => setView(view === "grid" ? "list" : "grid")
|
|
660
|
+
}, view === "grid" ? t("list") : t("grid")))), (0, react.createElement)("main", { className: view === "grid" ? market_module_default.grid : market_module_default.list }, loading ? (0, react.createElement)("div", { className: market_module_default.empty }, "…") : filtered.length === 0 ? (0, react.createElement)("div", { className: market_module_default.empty }, tab === "installed" ? t("installedEmpty") : t("empty")) : filtered.map((suite) => (0, react.createElement)(SuiteCard, {
|
|
661
|
+
key: `${suite.sourceId}/${suite.suiteId}`,
|
|
662
|
+
t,
|
|
663
|
+
suite,
|
|
664
|
+
busy: busy !== void 0,
|
|
665
|
+
onOpen: () => setDetail({
|
|
666
|
+
sourceId: suite.sourceId,
|
|
667
|
+
suiteId: suite.suiteId
|
|
668
|
+
}),
|
|
669
|
+
onInstall: () => {
|
|
670
|
+
action(`i:${suite.suiteId}`, "install", {
|
|
671
|
+
sourceId: suite.sourceId,
|
|
672
|
+
suiteId: suite.suiteId
|
|
673
|
+
});
|
|
674
|
+
},
|
|
675
|
+
onToggle: () => {
|
|
676
|
+
action(`e:${suite.suiteId}`, "set-enabled", {
|
|
677
|
+
sourceId: suite.sourceId,
|
|
678
|
+
suiteId: suite.suiteId,
|
|
679
|
+
enabled: !suite.enabled
|
|
680
|
+
});
|
|
681
|
+
},
|
|
682
|
+
onRefresh: () => {
|
|
683
|
+
action(`r:${suite.suiteId}`, "sources/refresh", { id: suite.sourceId });
|
|
684
|
+
},
|
|
685
|
+
onUninstall: () => openUninstall(suite)
|
|
686
|
+
}))), toast === void 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
687
|
+
key: toast.key,
|
|
688
|
+
text: toast.message,
|
|
689
|
+
onDone: () => setToast(void 0)
|
|
690
|
+
}), confirm === void 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
691
|
+
open: true,
|
|
692
|
+
onClose: () => setConfirm(void 0),
|
|
693
|
+
title: confirm.kind === "uninstall" ? t("uninstallConfirmTitle") : `${t("removeSourceConfirmTitle")}「${confirm.sourceId}」`,
|
|
694
|
+
closeLabel: t("cancel"),
|
|
695
|
+
description: confirm.kind === "uninstall" ? t("uninstallConfirmDesc") : t("removeSourceConfirmDesc"),
|
|
696
|
+
footer: (0, react.createElement)("div", { className: market_module_default.modalFooter }, (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
697
|
+
variant: "ghost",
|
|
698
|
+
onClick: () => setConfirm(void 0)
|
|
699
|
+
}, t("cancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
700
|
+
variant: "primary",
|
|
701
|
+
onClick: () => {
|
|
702
|
+
confirmAction();
|
|
703
|
+
}
|
|
704
|
+
}, t("confirmDelete")))
|
|
705
|
+
}), detail === void 0 ? null : (0, react.createElement)(SuiteDetailModal, {
|
|
706
|
+
t,
|
|
707
|
+
sourceId: detail.sourceId,
|
|
708
|
+
suiteId: detail.suiteId,
|
|
709
|
+
onClose: () => setDetail(void 0)
|
|
710
|
+
}), editor === void 0 ? null : (0, react.createElement)(SourceEditorModal, {
|
|
711
|
+
t,
|
|
712
|
+
editor,
|
|
713
|
+
busy: busy !== void 0,
|
|
714
|
+
onClose: () => setEditor(void 0),
|
|
715
|
+
onSave: async (url, branch, local) => {
|
|
716
|
+
const key = editor.mode === "edit" ? `s:edit:${editor.source.id}` : `s:add:${url}`;
|
|
717
|
+
const body = {
|
|
718
|
+
url,
|
|
719
|
+
...branch === "" ? {} : { branch },
|
|
720
|
+
local
|
|
721
|
+
};
|
|
722
|
+
if (editor.mode === "add") {
|
|
723
|
+
setBusy(key);
|
|
724
|
+
try {
|
|
725
|
+
const derived = (await postAction("sources/add", body))["source"]?.id;
|
|
726
|
+
await refresh();
|
|
727
|
+
setEditor(void 0);
|
|
728
|
+
if (derived !== void 0) setCategory(derived);
|
|
729
|
+
return true;
|
|
730
|
+
} catch (error) {
|
|
731
|
+
setToast({
|
|
732
|
+
key: Date.now(),
|
|
733
|
+
message: `${t("actionFail")}: ${error instanceof Error ? error.message : String(error)}`
|
|
734
|
+
});
|
|
735
|
+
return false;
|
|
736
|
+
} finally {
|
|
737
|
+
setBusy(void 0);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
const ok = await action(key, "sources/update", {
|
|
741
|
+
id: editor.source.id,
|
|
742
|
+
...body
|
|
743
|
+
});
|
|
744
|
+
if (ok) setEditor(void 0);
|
|
745
|
+
return ok;
|
|
746
|
+
},
|
|
747
|
+
onRemove: async (id) => {
|
|
748
|
+
setConfirm({
|
|
749
|
+
kind: "removeSource",
|
|
750
|
+
sourceId: id
|
|
751
|
+
});
|
|
752
|
+
setEditor(void 0);
|
|
753
|
+
}
|
|
754
|
+
}))
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
function TabButton({ t: _t, active, label, onClick }) {
|
|
758
|
+
return (0, react.createElement)("button", {
|
|
759
|
+
type: "button",
|
|
760
|
+
className: active ? market_module_default.tabOn : market_module_default.tab,
|
|
761
|
+
onClick
|
|
762
|
+
}, label);
|
|
763
|
+
}
|
|
764
|
+
/** A source tab with a trailing delete control (deletion confirms at the section level). */
|
|
765
|
+
function SourceTab(props) {
|
|
766
|
+
const { t, active = false, label, onSelect, onDelete, onEdit } = props;
|
|
767
|
+
return (0, react.createElement)("div", { className: active ? market_module_default.srcTabOn : market_module_default.srcTab }, (0, react.createElement)("button", {
|
|
768
|
+
type: "button",
|
|
769
|
+
className: market_module_default.srcTabMain,
|
|
770
|
+
onClick: onSelect
|
|
771
|
+
}, label), onEdit === void 0 ? null : (0, react.createElement)("button", {
|
|
772
|
+
type: "button",
|
|
773
|
+
className: market_module_default.srcTabEdit,
|
|
774
|
+
title: t("editSource"),
|
|
775
|
+
onClick: (event) => {
|
|
776
|
+
event.stopPropagation();
|
|
777
|
+
onEdit();
|
|
778
|
+
}
|
|
779
|
+
}, "✎"), onDelete === void 0 ? null : (0, react.createElement)("button", {
|
|
780
|
+
type: "button",
|
|
781
|
+
className: market_module_default.srcTabDel,
|
|
782
|
+
title: t("remove"),
|
|
783
|
+
onClick: (event) => {
|
|
784
|
+
event.stopPropagation();
|
|
785
|
+
onDelete();
|
|
786
|
+
}
|
|
787
|
+
}, "×"));
|
|
788
|
+
}
|
|
789
|
+
function SourceEditorModal(props) {
|
|
790
|
+
const { t, editor } = props;
|
|
791
|
+
const [local, setLocal] = (0, react.useState)(editor.mode === "edit" && editor.source.local === true);
|
|
792
|
+
const [url, setUrl] = (0, react.useState)(editor.mode === "edit" ? editor.source.url : "");
|
|
793
|
+
const [branch, setBranch] = (0, react.useState)(editor.mode === "edit" ? editor.source.branch ?? "" : "");
|
|
794
|
+
const id = editor.mode === "edit" ? editor.source.id : "";
|
|
795
|
+
const title = editor.mode === "edit" ? t("editSourceTitle") : t("addSourceTitle");
|
|
796
|
+
return (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
797
|
+
open: true,
|
|
798
|
+
onClose: props.onClose,
|
|
799
|
+
title,
|
|
800
|
+
description: t("editorHint"),
|
|
801
|
+
closeLabel: t("cancel"),
|
|
802
|
+
className: market_module_default.editorDialog,
|
|
803
|
+
footer: (0, react.createElement)("div", { className: market_module_default.modalFooter }, (0, react.createElement)("div", { className: market_module_default.modalFooterLeft }, editor.mode === "edit" ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
804
|
+
variant: "ghost",
|
|
805
|
+
onClick: () => props.onRemove(id)
|
|
806
|
+
}, `🗑 ${t("remove")}`) : null), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
807
|
+
variant: "ghost",
|
|
808
|
+
onClick: props.onClose
|
|
809
|
+
}, t("cancel")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
810
|
+
variant: "primary",
|
|
811
|
+
disabled: props.busy,
|
|
812
|
+
onClick: () => {
|
|
813
|
+
props.onSave(url.trim(), branch.trim(), local);
|
|
814
|
+
}
|
|
815
|
+
}, t("save"))),
|
|
816
|
+
children: (0, react.createElement)("div", { className: market_module_default.editorForm }, (0, react.createElement)("div", { className: market_module_default.modeRow }, (0, react.createElement)("button", {
|
|
817
|
+
type: "button",
|
|
818
|
+
className: local ? market_module_default.seg : market_module_default.segOn,
|
|
819
|
+
onClick: () => setLocal(false)
|
|
820
|
+
}, t("sourceModeGit")), (0, react.createElement)("button", {
|
|
821
|
+
type: "button",
|
|
822
|
+
className: local ? market_module_default.segOn : market_module_default.seg,
|
|
823
|
+
onClick: () => setLocal(true)
|
|
824
|
+
}, t("sourceModeLocal"))), editor.mode === "edit" ? (0, react.createElement)("div", { className: market_module_default.fieldGroup }, (0, react.createElement)("label", { className: market_module_default.fieldLabel }, t("sourceIdPh")), (0, react.createElement)("div", { className: market_module_default.staticId }, (0, react.createElement)("span", { className: market_module_default.staticIdValue }, id), (0, react.createElement)("span", { className: market_module_default.fieldHint }, t("idFixed")))) : null, (0, react.createElement)("div", { className: market_module_default.fieldGroup }, (0, react.createElement)("label", { className: market_module_default.fieldLabel }, local ? t("sourceUrlLocalPh") : t("sourceUrlPh")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
825
|
+
placeholder: local ? t("sourceUrlLocalPh") : t("sourceUrlPh"),
|
|
826
|
+
value: url,
|
|
827
|
+
onChange: (event) => setUrl(event.target.value)
|
|
828
|
+
}), (0, react.createElement)("span", { className: market_module_default.fieldHint }, local ? t("urlLocalHint") : t("urlGitHint"))), local ? null : (0, react.createElement)("div", { className: market_module_default.fieldGroup }, (0, react.createElement)("label", { className: market_module_default.fieldLabel }, t("branchPh")), (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
829
|
+
placeholder: t("branchPh"),
|
|
830
|
+
value: branch,
|
|
831
|
+
onChange: (event) => setBranch(event.target.value)
|
|
832
|
+
}), (0, react.createElement)("span", { className: market_module_default.fieldHint }, t("branchHint"))))
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
/** A green/gray switch control for suite enable state. */
|
|
836
|
+
function ToggleSwitch(props) {
|
|
837
|
+
return (0, react.createElement)("button", {
|
|
838
|
+
type: "button",
|
|
839
|
+
role: "switch",
|
|
840
|
+
"aria-checked": props.on,
|
|
841
|
+
title: props.title,
|
|
842
|
+
disabled: props.disabled,
|
|
843
|
+
className: props.on ? market_module_default.switchOn : market_module_default.switchOff,
|
|
844
|
+
onClick: (event) => {
|
|
845
|
+
event.stopPropagation();
|
|
846
|
+
props.onChange();
|
|
847
|
+
}
|
|
848
|
+
}, (0, react.createElement)("span", { className: market_module_default.switchThumb }));
|
|
849
|
+
}
|
|
850
|
+
function SuiteCard(props) {
|
|
851
|
+
const { t, suite, busy } = props;
|
|
852
|
+
const tags = [
|
|
853
|
+
[t("surfaceSkills"), suite.surfaces.skills],
|
|
854
|
+
[t("surfaceMcp"), suite.surfaces.mcp],
|
|
855
|
+
[t("surfaceHooks"), suite.surfaces.hooks],
|
|
856
|
+
[t("surfaceCommands"), suite.surfaces.commands],
|
|
857
|
+
[t("surfaceAgents"), suite.surfaces.agents],
|
|
858
|
+
[t("surfaceLsp"), suite.surfaces.lsp]
|
|
859
|
+
].filter(([, count]) => count > 0);
|
|
860
|
+
const layoutLabel = suite.layout === "agent-plugin-v1" ? t("layoutV1") : suite.layout === "claude-code" ? t("layoutCC") : suite.layout === "codex" ? t("layoutCodex") : suite.layout === "universal" ? t("layoutUniversal") : suite.layout === "cursor" ? t("layoutCursor") : suite.layout === "kimi" ? t("layoutKimi") : suite.layout === "remote" ? t("layoutRemote") : t("layoutSkills");
|
|
861
|
+
const isRemote = suite.remoteUrl !== void 0;
|
|
862
|
+
const stop = (callback) => (event) => {
|
|
863
|
+
event.stopPropagation();
|
|
864
|
+
callback();
|
|
865
|
+
};
|
|
866
|
+
return (0, react.createElement)("article", {
|
|
867
|
+
className: market_module_default.card,
|
|
868
|
+
onClick: props.onOpen
|
|
869
|
+
}, (0, react.createElement)("div", { className: market_module_default.cardTop }, (0, react.createElement)("div", { className: market_module_default.cardTitle }, (0, react.createElement)("span", { className: market_module_default.cardName }, suite.name), suite.version === void 0 ? null : (0, react.createElement)("span", { className: market_module_default.version }, `v${suite.version}`)), (0, react.createElement)("div", { className: market_module_default.cardActions }, suite.installed ? (0, react.createElement)(ToggleSwitch, {
|
|
870
|
+
on: suite.enabled,
|
|
871
|
+
disabled: busy,
|
|
872
|
+
title: suite.enabled ? t("disable") : t("enable"),
|
|
873
|
+
onChange: props.onToggle
|
|
874
|
+
}) : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
875
|
+
variant: "primary",
|
|
876
|
+
size: "sm",
|
|
877
|
+
disabled: busy || isRemote,
|
|
878
|
+
title: isRemote ? suite.remoteUrl : void 0,
|
|
879
|
+
onClick: stop(props.onInstall)
|
|
880
|
+
}, isRemote ? t("remoteRef") : t("install")), suite.installed ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
881
|
+
variant: "ghost",
|
|
882
|
+
size: "sm",
|
|
883
|
+
title: t("refresh"),
|
|
884
|
+
disabled: busy,
|
|
885
|
+
onClick: stop(props.onRefresh)
|
|
886
|
+
}, "↻") : null, suite.installed ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
887
|
+
variant: "ghost",
|
|
888
|
+
size: "sm",
|
|
889
|
+
title: t("uninstall"),
|
|
890
|
+
disabled: busy,
|
|
891
|
+
onClick: stop(props.onUninstall)
|
|
892
|
+
}, "🗑") : null)), (0, react.createElement)("p", { className: market_module_default.desc }, suite.description ?? ""), (0, react.createElement)("div", { className: market_module_default.meta }, (0, react.createElement)("span", { className: market_module_default.src }, `${suite.sourceId} · ${isRemote ? t("remoteRef") : suite.dimension === "user" ? t("dimensionUser") : t("dimensionProject")}`), (0, react.createElement)("span", { className: market_module_default.tag }, layoutLabel), suite.installed ? (0, react.createElement)("span", { className: suite.enabled ? market_module_default.okState : market_module_default.tag }, suite.enabled ? `✓ ${t("installedBadge")}` : t("installedBadge")) : null, ...tags.map(([label, count]) => (0, react.createElement)("span", {
|
|
893
|
+
key: label,
|
|
894
|
+
className: market_module_default.tag
|
|
895
|
+
}, `${label} ${count}`)), suite.errors.length === 0 ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
896
|
+
label: suite.errors.slice(0, 8).join(";"),
|
|
897
|
+
children: (0, react.createElement)("span", { className: market_module_default.warnLine }, `⚠ ${t("errors")} ${suite.errors.length}`)
|
|
898
|
+
})));
|
|
899
|
+
}
|
|
900
|
+
//#endregion
|
|
901
|
+
//#region src/client/index.ts
|
|
902
|
+
/**
|
|
903
|
+
* dsh-agent-plugins-market client: registers the Agent Plugins Market section inside the Web
|
|
904
|
+
* GUI's settings dialog (the same settings.section seat dshmarket uses).
|
|
905
|
+
* Mirrors the market's integration contract: the bundle's only externals are
|
|
906
|
+
* react and the injected `dsh.client.inject` module table, so it cannot reach
|
|
907
|
+
* packages the host does not serve.
|
|
908
|
+
*/
|
|
909
|
+
const NS = "dsh-agent-plugins-market";
|
|
910
|
+
const name = "dsh-agent-plugins-market";
|
|
911
|
+
const inject = ["slots", "locale"];
|
|
912
|
+
/** Primitives this section renders with; absent exports degrade the whole section. */
|
|
913
|
+
const REQUIRED_PRIMITIVES = [
|
|
914
|
+
"Button",
|
|
915
|
+
"Input",
|
|
916
|
+
"Modal",
|
|
917
|
+
"Toast",
|
|
918
|
+
"Tooltip"
|
|
919
|
+
];
|
|
920
|
+
/** Detect host primitives that predate the exports this UI relies on. */
|
|
921
|
+
function missingPrimitives(module, required = REQUIRED_PRIMITIVES) {
|
|
922
|
+
return required.filter((name) => module[name] === void 0);
|
|
923
|
+
}
|
|
924
|
+
function apply(ctx) {
|
|
925
|
+
ctx.effect(() => ctx.locale.register(NS, {
|
|
926
|
+
zh,
|
|
927
|
+
en
|
|
928
|
+
}), "dsh-agent-plugins: dictionaries");
|
|
929
|
+
const t = ctx.locale.bind(NS);
|
|
930
|
+
const gaps = missingPrimitives(_deepseek_ai_dsh_client_ui_primitives);
|
|
931
|
+
if (gaps.length > 0) {
|
|
932
|
+
console.warn(`[dsh-agent-plugins-market] host ui-primitives missing ${gaps.join(", ")} — Agent Plugins Market section disabled (dsh web >= 0.1.0-rc.6 required)`);
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
936
|
+
name: "settings.section",
|
|
937
|
+
id: "agent-plugin",
|
|
938
|
+
order: 45,
|
|
939
|
+
label: () => t("nav"),
|
|
940
|
+
locale: NS,
|
|
941
|
+
inject: () => ({ t })
|
|
942
|
+
}, () => (0, react.createElement)(MarketSection, { t })));
|
|
943
|
+
}
|
|
944
|
+
//#endregion
|
|
945
|
+
exports.REQUIRED_PRIMITIVES = REQUIRED_PRIMITIVES;
|
|
946
|
+
exports.apply = apply;
|
|
947
|
+
exports.inject = inject;
|
|
948
|
+
exports.missingPrimitives = missingPrimitives;
|
|
949
|
+
exports.name = name;
|
|
950
|
+
|
|
951
|
+
//# sourceMappingURL=client.js.map
|
|
952
|
+
return module.exports;
|
|
953
|
+
}
|
|
954
|
+
});
|