dsh-armory 2.2.1 → 2.3.1

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/index.js CHANGED
@@ -7,7 +7,7 @@ import { interpolate } from "@deepseek-ai/cordis-plugin-loader";
7
7
  import { withFileLock, writeFileAtomic } from "@deepseek-ai/dsh-atomic-write";
8
8
  import { basename, dirname, join } from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
- import { appendSelectedBuiltinMcpServers, BUILTIN_MCP_SERVERS, builtinMcpCatalog, normalizeMcpImport, readManagedMcpServers, setManagedMcpDisabled, updateManagedMcpPatch } from "./mcp-config.js";
10
+ import { normalizeMcpImport, readManagedMcpServers, setManagedMcpDisabled, updateManagedMcpPatch } from "./mcp-config.js";
11
11
  import { admitImportedServers } from "./import-admission.js";
12
12
  import { collectImportLocations, missingEnvNames, resolveImportLocation } from "./mcp-import-sources.js";
13
13
  import { deriveMcpPhase, formatMcpLog, sanitizeMcpLog } from "./mcp-observability.js";
@@ -16,12 +16,17 @@ import { allMcpEntries, entriesForName, projectToolSchema, revisionOf, toolInven
16
16
  import { removeSkillFromDisk } from "./skill-remove.js";
17
17
  import { WHATS_NEW } from "./whats-new.js";
18
18
  import { attachWhatsNewEnglish } from "./whats-new-en.js";
19
- import { probeMcpServersAuthorization, wbConnectorCatalog, wbConnectorCachedCount, wbConnectorPreview, wbSkillCatalog, wbSkillDetail, wbSkillInstall, wbSkillInstalled, wbSkillUninstall } from "./wb-market.js";
20
- // T03:多市场注册表(R4)与 codebuddy 插件市场(R5)的宿主侧数据层。
19
+ import { probeMcpServersAuthorization, wbConnectorCatalog, wbConnectorCachedCount, wbConnectorIcon, wbConnectorPreview, wbSkillCatalog, wbSkillDetail, wbSkillInstall, wbSkillInstalled, wbSkillUninstall } from "./wb-market.js";
20
+ // T03/R4:多市场注册表(连接器源)的宿主侧数据层。
21
21
  import { readRegistry, upsertMarketplace } from "./wb-registry.js";
22
- import { wbPluginCatalog, wbPluginDetail, wbPluginUpdateCheck } from "./wb-plugin-market.js";
23
22
  // T06/Awesome:DSH 社区插件市场(awesome-dsh-plugins)的宿主侧数据层。
24
23
  import { wbAwesomeCatalog, wbAwesomeDetail, wbAwesomeReadme, wbAwesomeUpdateCheck } from "./wb-awesome-market.js";
24
+ // 社区元信息(维护者 / 最近提交 / issue / star):打开详情时按需查,6 小时缓存。
25
+ import { wbRepoMeta } from "./community-meta.js";
26
+ // npm 近 30 天下载量:插件卡片底栏的「↓N」,目录里没有这个字段,只能去 npm 统计接口取。
27
+ import { wbNpmDownloads } from "./npm-downloads.js";
28
+ // 装备清单:只读汇总本机已装条目,校验与差异计算保持纯函数(lib/loadout.js)。
29
+ import { buildLoadout, diffLoadout } from "./loadout.js";
25
30
  import { readState as readInstallState, record as recordInstallState, forget as forgetInstallState } from "./wb-install-state.js";
26
31
  // 自定义套件(Skill 看板):读 / 整集合覆盖保存,数据层 lib/suites-registry.js。
27
32
  import { readSuites as readSkillSuites, saveSuites as writeSkillSuites } from "./suites-registry.js";
@@ -36,7 +41,7 @@ import {
36
41
  saveManualToken as oauthSaveManualToken,
37
42
  submitCallback as oauthSubmitCallback,
38
43
  } from "./mcp-oauth.js";
39
- import { hasTeamBridge, installExpertSkills, listExpertRecent, listExpertSkills, prepareExpertPersona, readExpertPresets, recordExpertRecent, removeExpertPreset, uninstallExpertSkills, uninstallTeamMemberPersonas, wbExpertCatalog, wbExpertDetail, writeExpertPreset } from "./expert-market.js";
44
+ import { hasTeamBridge, installExpertSkills, listExpertRecent, listExpertSkills, prepareExpertPersona, readExpertDisplayNames, readExpertPresets, recordExpertRecent, removeExpertPreset, uninstallExpertSkills, uninstallTeamMemberPersonas, wbExpertCatalog, wbExpertDetail, writeExpertPreset } from "./expert-market.js";
40
45
  import { attachPersona, detachPersona, listPersonas, reconcilePersonas } from "./session-persona.js";
41
46
  // clearTextCache 的 import 已随 toolTailor 的「清空缓存」动作一起删掉(见下方 toolTailor 注释)。
42
47
  import { scanSessionLedger } from "./tool-ledger.js";
@@ -381,12 +386,6 @@ function externalMcpEntries(ctx, state) {
381
386
  return !managedIds.has(entry.options.id) && !(!entry.options.group && managedNames.has(entry.options.config.serverName));
382
387
  });
383
388
  }
384
- function effectiveMcpServers(ctx, state) {
385
- return [
386
- ...state.servers,
387
- ...externalMcpEntries(ctx, state).map((entry) => ({ ...entry.options.config, name: entry.options.config.serverName })),
388
- ];
389
- }
390
389
  function revealRevision(state, groups) {
391
390
  const values = [];
392
391
  for (const current of state.servers) {
@@ -589,7 +588,6 @@ function summarize(entry, inventory, managed, conflict = false, lastLog = null)
589
588
  // 已经是不可用的终态证据),而不是去猜 mcp-client 的日志文案;日志只用来填 lastError 的
590
589
  // 具体原因。挂载失败(我们自己 setup 阶段就挂不上:配置求值为空、工具注册被拒)与连接
591
590
  // 失败(mcp-client 那边的事)分开标记,不混为一谈。
592
- // 已导出作为测试接缝(同 checkForUpdate)。
593
591
  function summarizeWorkspaceRow(ctx, wsPath, server, mountError) {
594
592
  // 诊断通路就在这里被依赖,就在这里确保开着(按 root 幂等,与全局 list/status 同一份)。
595
593
  ensureLogCapture(ctx);
@@ -962,7 +960,64 @@ async function buildToolTailorReport(ctx, payload) {
962
960
  }
963
961
  }
964
962
  const schemas = [...ctx.tools.schemas()].map(projectToolSchema);
965
- return scanSessionLedger({ days, mcpServerNames, schemas, disabledServers });
963
+ const report = await scanSessionLedger({ days, mcpServerNames, schemas, disabledServers });
964
+ return attachRegisteredSkills(ctx, report);
965
+ }
966
+
967
+ /**
968
+ * §6.4 技能账本的第二半:把「注册表里存在」与「日志里真的被调用过」合起来。
969
+ *
970
+ * 只看日志能回答「谁被用了」,但回答不了最要紧的那一问——**注册了却一次没被用过的是哪些**。
971
+ * 那一问的答案正是「该不该留」的依据(本机实测 32 个技能里 21 个一次没调用过),而这批名字
972
+ * 只能来自 `ctx.skills` 注册表。scope 解析复用看板那条 `withSkillScope`(默认预设代言),
973
+ * 免得这里另写一套、漏掉预设层的发现范围。
974
+ *
975
+ * 注册表缺席时(老宿主 / 预设层没挂 skill-filesystem)**不伪造 0**:把
976
+ * `skillsRegistryAvailable` 置 false、`skillNeverUsedCount` 置 null,界面据此只说
977
+ * 「日志里出现过的技能」,而不是暗示「其余技能都没被用过」——后者会是一句假话。
978
+ */
979
+ async function attachRegisteredSkills(ctx, report) {
980
+ const observed = Array.isArray(report?.skills) ? report.skills : [];
981
+ let registered = [];
982
+ try {
983
+ const listed = await withSkillScope(ctx, {}, async (registry, options) => {
984
+ if (typeof registry.list !== "function") return undefined;
985
+ return registry.list(options);
986
+ });
987
+ if (Array.isArray(listed)) {
988
+ registered = listed.filter((skill) => typeof skill?.name === "string" && skill.name !== "");
989
+ }
990
+ } catch {
991
+ // 注册表读不了不挡工具账本:技能那一节退化为「只有日志里出现过的」。
992
+ }
993
+ const available = registered.length > 0;
994
+ const registeredNames = new Set(registered.map((skill) => skill.name));
995
+ const observedNames = new Set(observed.map((skill) => skill.name));
996
+ const merged = available
997
+ ? [
998
+ ...observed.map((skill) => ({ ...skill, registered: registeredNames.has(skill.name) })),
999
+ ...registered
1000
+ .filter((skill) => !observedNames.has(skill.name))
1001
+ .map((skill) => ({
1002
+ name: skill.name,
1003
+ calls: 0,
1004
+ errors: 0,
1005
+ errorRate: 0,
1006
+ firstUsedMs: null,
1007
+ lastUsedMs: null,
1008
+ registered: true,
1009
+ })),
1010
+ ].sort((a, b) => (b.calls - a.calls) || String(a.name).localeCompare(String(b.name)))
1011
+ : observed.map((skill) => ({ ...skill, registered: null }));
1012
+ return {
1013
+ ...report,
1014
+ skills: merged,
1015
+ skillsRegistryAvailable: available,
1016
+ skillRegisteredCount: available ? registered.length : null,
1017
+ // 「一次没被调用」只在注册表可用时才有意义(否则分母本身是未知的)。
1018
+ skillNeverUsedCount: available ? merged.filter((skill) => skill.calls === 0).length : null,
1019
+ skillCount: merged.length,
1020
+ };
966
1021
  }
967
1022
 
968
1023
  // 全局 MCP 列表核心(list / getWorkspaceView 共用)。
@@ -991,10 +1046,148 @@ async function listMcpServers(ctx) {
991
1046
  };
992
1047
  }
993
1048
 
1049
+ // ── 装备清单:本机条目收集(只读,只投影身份字段)────────────────────────
1050
+ // 导出与导入对比共用这一份收集逻辑,避免两个入口对「本机装了什么」给出不同答案。
1051
+ // 绝不把 env / headers 的值带出去:MCP 只保留键名,技能只保留名称与来源,
1052
+ // 专家从 profile 补丁的召唤预设读 plugin、从目录缓存补展示名,插件读安装账本。
1053
+ function endpointHostOf(value) {
1054
+ if (typeof value !== "string" || !value) return "";
1055
+ try {
1056
+ return new URL(value).host || "";
1057
+ } catch {
1058
+ return "";
1059
+ }
1060
+ }
1061
+
1062
+ async function collectLoadoutItems(ctx) {
1063
+ const items = [];
1064
+ let records = [];
1065
+ try {
1066
+ const state = await readInstallState();
1067
+ records = Array.isArray(state?.items) ? state.items : [];
1068
+ } catch {
1069
+ // 账本读不到仍然可以导出 MCP / 技能 / 专家;插件条目会缺,但不该整单失败。
1070
+ }
1071
+
1072
+ // 1) MCP:以真实注册表为准;连接器账本用于补来源,名称对不上时保留账本条目。
1073
+ try {
1074
+ const { servers } = await listMcpServers(ctx);
1075
+ const connectorByName = new Map();
1076
+ for (const record of records) {
1077
+ if (record?.kind !== "connector") continue;
1078
+ const key = String(record.key || "").trim();
1079
+ if (key) connectorByName.set(key, record);
1080
+ const rowName = String(record.name || "").trim();
1081
+ if (rowName) connectorByName.set(rowName, record);
1082
+ }
1083
+ const seen = new Set();
1084
+ for (const server of servers) {
1085
+ const name = String(server?.serverName || "").trim();
1086
+ if (!name) continue;
1087
+ seen.add(name);
1088
+ const connector = connectorByName.get(name);
1089
+ const configKeys = [
1090
+ ...Object.keys(server.env || {}),
1091
+ ...Object.keys(server.headers || {}),
1092
+ ].filter(Boolean);
1093
+ const endpointHost = endpointHostOf(server.url);
1094
+ items.push({
1095
+ kind: "mcp",
1096
+ name,
1097
+ ...(server.transport ? { transport: server.transport } : {}),
1098
+ source: connector ? `connector:${connector.key}` : "manual",
1099
+ ...(endpointHost ? { endpointHost } : {}),
1100
+ ...(configKeys.length ? { configKeys: [...new Set(configKeys)] } : {}),
1101
+ ...(typeof server.enabled === "boolean" ? { enabled: server.enabled } : {}),
1102
+ });
1103
+ }
1104
+ for (const record of records) {
1105
+ if (record?.kind !== "connector") continue;
1106
+ const key = String(record.key || "").trim();
1107
+ const name = String(record.name || key).trim();
1108
+ if (!name || seen.has(name) || (key && seen.has(key))) continue;
1109
+ seen.add(name);
1110
+ items.push({ kind: "mcp", name, source: `connector:${key || name}` });
1111
+ }
1112
+ } catch {
1113
+ // MCP 注册表不可用时跳过这一组,其余组照常导出。
1114
+ }
1115
+
1116
+ // 2) 技能:宿主 skill 注册表的全局视图;账本用于补市场来源与版本。
1117
+ try {
1118
+ const ledger = new Map();
1119
+ for (const record of records) {
1120
+ if (record?.kind === "skill") ledger.set(String(record.key || ""), record);
1121
+ }
1122
+ await withSkillScope(ctx, { scope: "global" }, async (registry, options) => {
1123
+ if (typeof registry.list !== "function") return;
1124
+ const rows = await registry.list(options);
1125
+ for (const skill of rows) {
1126
+ const name = String(skill?.name || "").trim();
1127
+ if (!name) continue;
1128
+ const record = ledger.get(name);
1129
+ items.push({
1130
+ kind: "skill",
1131
+ name,
1132
+ source: String(record?.source?.marketplace || skill.source || "local"),
1133
+ ...(record?.version ? { version: String(record.version) } : {}),
1134
+ });
1135
+ }
1136
+ });
1137
+ } catch {
1138
+ // 宿主没挂 skill 注册表时跳过技能组。
1139
+ }
1140
+
1141
+ // 3) 专家:profile 补丁里的召唤预设 + 目录缓存补展示名 / 更新时间。
1142
+ try {
1143
+ const patch = await readPatch(ctx);
1144
+ const presets = readExpertPresets(patch.content);
1145
+ let experts = [];
1146
+ try {
1147
+ const catalog = await wbExpertCatalog();
1148
+ experts = Array.isArray(catalog?.experts) ? catalog.experts : [];
1149
+ } catch {
1150
+ // 目录拉不到就退回 plugin id 作名称。
1151
+ }
1152
+ const byPlugin = new Map(experts.map((expert) => [String(expert.plugin || ""), expert]));
1153
+ for (const preset of presets) {
1154
+ const plugin = String(preset?.plugin || "").trim();
1155
+ if (!plugin) continue;
1156
+ const expert = byPlugin.get(plugin);
1157
+ items.push({
1158
+ kind: "expert",
1159
+ name: String(expert?.name || plugin),
1160
+ plugin,
1161
+ source: "workbuddy-expert",
1162
+ ...(expert?.updatedAt ? { updatedAt: String(expert.updatedAt) } : {}),
1163
+ });
1164
+ }
1165
+ } catch {
1166
+ // 没有 profile 补丁(或读不到)时跳过专家组。
1167
+ }
1168
+
1169
+ // 4) 插件:只有客户端在安装成功后回写的账本知道装了什么。
1170
+ for (const record of records) {
1171
+ if (record?.kind !== "plugin") continue;
1172
+ const key = String(record.key || "").trim();
1173
+ const name = String(record.name || key).trim();
1174
+ if (!name) continue;
1175
+ items.push({
1176
+ kind: "plugin",
1177
+ name,
1178
+ ...(key ? { key } : {}),
1179
+ source: String(record.source?.marketplace || ""),
1180
+ ...(record.version ? { version: String(record.version) } : {}),
1181
+ });
1182
+ }
1183
+
1184
+ return items;
1185
+ }
1186
+
994
1187
  let McpManagerGateway = (() => {
995
1188
  let _classSuper = TypertRemoteService;
996
1189
  let _instanceExtraInitializers = [];
997
- let _list_decorators, _status_decorators, _enable_decorators, _disable_decorators, _reconnect_decorators, _tools_decorators, _builtins_decorators, _installBuiltins_decorators, _add_decorators, _update_decorators, _remove_decorators, _reveal_decorators, _previewImport_decorators, _importJson_decorators, _listWorkspaces_decorators, _getWorkspaceView_decorators, _addWorkspaceServer_decorators, _updateWorkspaceServer_decorators, _removeWorkspaceServer_decorators, _setWorkspaceExclude_decorators, _installWorkspaceBuiltins_decorators, _previewWorkspaceImport_decorators, _importWorkspaceJson_decorators, _revealWorkspaceServer_decorators, _projectConnections_decorators, _reconnectWorkspaceServer_decorators, _updateHint_decorators, _whatsNew_decorators, _scanImportSources_decorators, _previewImportSource_decorators, _importSource_decorators, _toolTailor_decorators, _wbConnectorCatalog_decorators, _wbConnectorCachedCount_decorators, _wbConnectorPreview_decorators, _wbConnectorInstall_decorators, _wbOAuthBegin_decorators, _wbOAuthPoll_decorators, _wbOAuthCancel_decorators, _wbOAuthToken_decorators, _wbOAuthOverview_decorators, _wbOAuthOpen_decorators, _wbSkillCatalog_decorators, _wbSkillDetail_decorators, _wbSkillInstall_decorators, _wbSkillUninstall_decorators, _wbSkillInstalled_decorators, _wbMarketRegistry_decorators, _wbMarketRegistryUpsert_decorators, _wbPluginCatalog_decorators, _wbPluginDetail_decorators, _wbInstallState_decorators, _wbInstallStateRecord_decorators, _wbInstallStateForget_decorators, _wbPluginUpdateCheck_decorators, _wbAwesomeCatalog_decorators, _wbAwesomeDetail_decorators, _wbAwesomeReadme_decorators, _wbAwesomeUpdateCheck_decorators;
1190
+ let _list_decorators, _status_decorators, _enable_decorators, _disable_decorators, _reconnect_decorators, _tools_decorators, _add_decorators, _update_decorators, _remove_decorators, _reveal_decorators, _previewImport_decorators, _importJson_decorators, _listWorkspaces_decorators, _getWorkspaceView_decorators, _addWorkspaceServer_decorators, _updateWorkspaceServer_decorators, _removeWorkspaceServer_decorators, _setWorkspaceExclude_decorators, _previewWorkspaceImport_decorators, _importWorkspaceJson_decorators, _revealWorkspaceServer_decorators, _projectConnections_decorators, _reconnectWorkspaceServer_decorators, _updateHint_decorators, _whatsNew_decorators, _scanImportSources_decorators, _previewImportSource_decorators, _importSource_decorators, _toolTailor_decorators, _wbConnectorCatalog_decorators, _wbConnectorCachedCount_decorators, _wbConnectorIcon_decorators, _wbConnectorPreview_decorators, _wbConnectorInstall_decorators, _wbOAuthBegin_decorators, _wbOAuthPoll_decorators, _wbOAuthCancel_decorators, _wbOAuthToken_decorators, _wbOAuthOverview_decorators, _wbOAuthOpen_decorators, _wbSkillCatalog_decorators, _wbSkillDetail_decorators, _wbSkillInstall_decorators, _wbSkillUninstall_decorators, _wbSkillInstalled_decorators, _wbMarketRegistry_decorators, _wbMarketRegistryUpsert_decorators, _wbInstallState_decorators, _wbInstallStateRecord_decorators, _wbInstallStateForget_decorators, _wbAwesomeCatalog_decorators, _wbAwesomeDetail_decorators, _wbAwesomeReadme_decorators, _wbAwesomeUpdateCheck_decorators, _wbRepoMeta_decorators, _wbNpmDownloads_decorators, _wbLoadoutExport_decorators, _wbLoadoutDiff_decorators;
998
1191
  return class McpManagerGateway extends _classSuper {
999
1192
  static {
1000
1193
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
@@ -1010,10 +1203,6 @@ let McpManagerGateway = (() => {
1010
1203
  __esDecorate(this, null, _reconnect_decorators, { kind: "method", name: "reconnect", static: false, private: false, access: { has: (obj) => "reconnect" in obj, get: (obj) => obj.reconnect }, metadata: _metadata }, null, _instanceExtraInitializers);
1011
1204
  _tools_decorators = [Remote("tools")];
1012
1205
  __esDecorate(this, null, _tools_decorators, { kind: "method", name: "tools", static: false, private: false, access: { has: (obj) => "tools" in obj, get: (obj) => obj.tools }, metadata: _metadata }, null, _instanceExtraInitializers);
1013
- _builtins_decorators = [Remote("builtins")];
1014
- __esDecorate(this, null, _builtins_decorators, { kind: "method", name: "builtins", static: false, private: false, access: { has: (obj) => "builtins" in obj, get: (obj) => obj.builtins }, metadata: _metadata }, null, _instanceExtraInitializers);
1015
- _installBuiltins_decorators = [Remote("installBuiltins")];
1016
- __esDecorate(this, null, _installBuiltins_decorators, { kind: "method", name: "installBuiltins", static: false, private: false, access: { has: (obj) => "installBuiltins" in obj, get: (obj) => obj.installBuiltins }, metadata: _metadata }, null, _instanceExtraInitializers);
1017
1206
  _add_decorators = [Remote("add")];
1018
1207
  __esDecorate(this, null, _add_decorators, { kind: "method", name: "add", static: false, private: false, access: { has: (obj) => "add" in obj, get: (obj) => obj.add }, metadata: _metadata }, null, _instanceExtraInitializers);
1019
1208
  _update_decorators = [Remote("update")];
@@ -1038,8 +1227,6 @@ let McpManagerGateway = (() => {
1038
1227
  __esDecorate(this, null, _removeWorkspaceServer_decorators, { kind: "method", name: "removeWorkspaceServer", static: false, private: false, access: { has: (obj) => "removeWorkspaceServer" in obj, get: (obj) => obj.removeWorkspaceServer }, metadata: _metadata }, null, _instanceExtraInitializers);
1039
1228
  _setWorkspaceExclude_decorators = [Remote("setWorkspaceExclude")];
1040
1229
  __esDecorate(this, null, _setWorkspaceExclude_decorators, { kind: "method", name: "setWorkspaceExclude", static: false, private: false, access: { has: (obj) => "setWorkspaceExclude" in obj, get: (obj) => obj.setWorkspaceExclude }, metadata: _metadata }, null, _instanceExtraInitializers);
1041
- _installWorkspaceBuiltins_decorators = [Remote("installWorkspaceBuiltins")];
1042
- __esDecorate(this, null, _installWorkspaceBuiltins_decorators, { kind: "method", name: "installWorkspaceBuiltins", static: false, private: false, access: { has: (obj) => "installWorkspaceBuiltins" in obj, get: (obj) => obj.installWorkspaceBuiltins }, metadata: _metadata }, null, _instanceExtraInitializers);
1043
1230
  _previewWorkspaceImport_decorators = [Remote("previewWorkspaceImport")];
1044
1231
  __esDecorate(this, null, _previewWorkspaceImport_decorators, { kind: "method", name: "previewWorkspaceImport", static: false, private: false, access: { has: (obj) => "previewWorkspaceImport" in obj, get: (obj) => obj.previewWorkspaceImport }, metadata: _metadata }, null, _instanceExtraInitializers);
1045
1232
  _importWorkspaceJson_decorators = [Remote("importWorkspaceJson")];
@@ -1066,6 +1253,8 @@ let McpManagerGateway = (() => {
1066
1253
  __esDecorate(this, null, _wbConnectorCatalog_decorators, { kind: "method", name: "wbConnectorCatalog", static: false, private: false, access: { has: (obj) => "wbConnectorCatalog" in obj, get: (obj) => obj.wbConnectorCatalog }, metadata: _metadata }, null, _instanceExtraInitializers);
1067
1254
  _wbConnectorCachedCount_decorators = [Remote("wbConnectorCachedCount")];
1068
1255
  __esDecorate(this, null, _wbConnectorCachedCount_decorators, { kind: "method", name: "wbConnectorCachedCount", static: false, private: false, access: { has: (obj) => "wbConnectorCachedCount" in obj, get: (obj) => obj.wbConnectorCachedCount }, metadata: _metadata }, null, _instanceExtraInitializers);
1256
+ _wbConnectorIcon_decorators = [Remote("wbConnectorIcon")];
1257
+ __esDecorate(this, null, _wbConnectorIcon_decorators, { kind: "method", name: "wbConnectorIcon", static: false, private: false, access: { has: (obj) => "wbConnectorIcon" in obj, get: (obj) => obj.wbConnectorIcon }, metadata: _metadata }, null, _instanceExtraInitializers);
1069
1258
  _wbConnectorPreview_decorators = [Remote("wbConnectorPreview")];
1070
1259
  __esDecorate(this, null, _wbConnectorPreview_decorators, { kind: "method", name: "wbConnectorPreview", static: false, private: false, access: { has: (obj) => "wbConnectorPreview" in obj, get: (obj) => obj.wbConnectorPreview }, metadata: _metadata }, null, _instanceExtraInitializers);
1071
1260
  _wbConnectorInstall_decorators = [Remote("wbConnectorInstall")];
@@ -1097,11 +1286,6 @@ let McpManagerGateway = (() => {
1097
1286
  __esDecorate(this, null, _wbMarketRegistry_decorators, { kind: "method", name: "wbMarketRegistry", static: false, private: false, access: { has: (obj) => "wbMarketRegistry" in obj, get: (obj) => obj.wbMarketRegistry }, metadata: _metadata }, null, _instanceExtraInitializers);
1098
1287
  _wbMarketRegistryUpsert_decorators = [Remote("wbMarketRegistryUpsert")];
1099
1288
  __esDecorate(this, null, _wbMarketRegistryUpsert_decorators, { kind: "method", name: "wbMarketRegistryUpsert", static: false, private: false, access: { has: (obj) => "wbMarketRegistryUpsert" in obj, get: (obj) => obj.wbMarketRegistryUpsert }, metadata: _metadata }, null, _instanceExtraInitializers);
1100
- // T03/R5:codebuddy 插件市场(列表 / 详情)。
1101
- _wbPluginCatalog_decorators = [Remote("wbPluginCatalog")];
1102
- __esDecorate(this, null, _wbPluginCatalog_decorators, { kind: "method", name: "wbPluginCatalog", static: false, private: false, access: { has: (obj) => "wbPluginCatalog" in obj, get: (obj) => obj.wbPluginCatalog }, metadata: _metadata }, null, _instanceExtraInitializers);
1103
- _wbPluginDetail_decorators = [Remote("wbPluginDetail")];
1104
- __esDecorate(this, null, _wbPluginDetail_decorators, { kind: "method", name: "wbPluginDetail", static: false, private: false, access: { has: (obj) => "wbPluginDetail" in obj, get: (obj) => obj.wbPluginDetail }, metadata: _metadata }, null, _instanceExtraInitializers);
1105
1289
  // T04/R8:安装状态登记(connector/skill/plugin 三类安装的统一账本)。
1106
1290
  _wbInstallState_decorators = [Remote("wbInstallState")];
1107
1291
  __esDecorate(this, null, _wbInstallState_decorators, { kind: "method", name: "wbInstallState", static: false, private: false, access: { has: (obj) => "wbInstallState" in obj, get: (obj) => obj.wbInstallState }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -1109,8 +1293,6 @@ let McpManagerGateway = (() => {
1109
1293
  __esDecorate(this, null, _wbInstallStateRecord_decorators, { kind: "method", name: "wbInstallStateRecord", static: false, private: false, access: { has: (obj) => "wbInstallStateRecord" in obj, get: (obj) => obj.wbInstallStateRecord }, metadata: _metadata }, null, _instanceExtraInitializers);
1110
1294
  _wbInstallStateForget_decorators = [Remote("wbInstallStateForget")];
1111
1295
  __esDecorate(this, null, _wbInstallStateForget_decorators, { kind: "method", name: "wbInstallStateForget", static: false, private: false, access: { has: (obj) => "wbInstallStateForget" in obj, get: (obj) => obj.wbInstallStateForget }, metadata: _metadata }, null, _instanceExtraInitializers);
1112
- _wbPluginUpdateCheck_decorators = [Remote("wbPluginUpdateCheck")];
1113
- __esDecorate(this, null, _wbPluginUpdateCheck_decorators, { kind: "method", name: "wbPluginUpdateCheck", static: false, private: false, access: { has: (obj) => "wbPluginUpdateCheck" in obj, get: (obj) => obj.wbPluginUpdateCheck }, metadata: _metadata }, null, _instanceExtraInitializers);
1114
1296
  // T06/Awesome:DSH 社区插件市场(awesome-dsh-plugins)。
1115
1297
  _wbAwesomeCatalog_decorators = [Remote("wbAwesomeCatalog")];
1116
1298
  __esDecorate(this, null, _wbAwesomeCatalog_decorators, { kind: "method", name: "wbAwesomeCatalog", static: false, private: false, access: { has: (obj) => "wbAwesomeCatalog" in obj, get: (obj) => obj.wbAwesomeCatalog }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -1120,6 +1302,14 @@ let McpManagerGateway = (() => {
1120
1302
  __esDecorate(this, null, _wbAwesomeReadme_decorators, { kind: "method", name: "wbAwesomeReadme", static: false, private: false, access: { has: (obj) => "wbAwesomeReadme" in obj, get: (obj) => obj.wbAwesomeReadme }, metadata: _metadata }, null, _instanceExtraInitializers);
1121
1303
  _wbAwesomeUpdateCheck_decorators = [Remote("wbAwesomeUpdateCheck")];
1122
1304
  __esDecorate(this, null, _wbAwesomeUpdateCheck_decorators, { kind: "method", name: "wbAwesomeUpdateCheck", static: false, private: false, access: { has: (obj) => "wbAwesomeUpdateCheck" in obj, get: (obj) => obj.wbAwesomeUpdateCheck }, metadata: _metadata }, null, _instanceExtraInitializers);
1305
+ _wbRepoMeta_decorators = [Remote("wbRepoMeta")];
1306
+ __esDecorate(this, null, _wbRepoMeta_decorators, { kind: "method", name: "wbRepoMeta", static: false, private: false, access: { has: (obj) => "wbRepoMeta" in obj, get: (obj) => obj.wbRepoMeta }, metadata: _metadata }, null, _instanceExtraInitializers);
1307
+ _wbNpmDownloads_decorators = [Remote("wbNpmDownloads")];
1308
+ __esDecorate(this, null, _wbNpmDownloads_decorators, { kind: "method", name: "wbNpmDownloads", static: false, private: false, access: { has: (obj) => "wbNpmDownloads" in obj, get: (obj) => obj.wbNpmDownloads }, metadata: _metadata }, null, _instanceExtraInitializers);
1309
+ _wbLoadoutExport_decorators = [Remote("wbLoadoutExport")];
1310
+ __esDecorate(this, null, _wbLoadoutExport_decorators, { kind: "method", name: "wbLoadoutExport", static: false, private: false, access: { has: (obj) => "wbLoadoutExport" in obj, get: (obj) => obj.wbLoadoutExport }, metadata: _metadata }, null, _instanceExtraInitializers);
1311
+ _wbLoadoutDiff_decorators = [Remote("wbLoadoutDiff")];
1312
+ __esDecorate(this, null, _wbLoadoutDiff_decorators, { kind: "method", name: "wbLoadoutDiff", static: false, private: false, access: { has: (obj) => "wbLoadoutDiff" in obj, get: (obj) => obj.wbLoadoutDiff }, metadata: _metadata }, null, _instanceExtraInitializers);
1123
1313
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
1124
1314
  }
1125
1315
  static inject = ["loader", "tools"];
@@ -1196,27 +1386,6 @@ let McpManagerGateway = (() => {
1196
1386
  const wsPath = typeof rawPath === "string" && rawPath ? canonicalWorkspacePath(rawPath) : undefined;
1197
1387
  return { tools: workspaceToolSchemas(this.ctx, value, wsPath).map(projectToolSchema), ambiguous: false };
1198
1388
  }
1199
- async builtins() {
1200
- const state = await managedState(this.ctx);
1201
- return { builtins: builtinMcpCatalog(effectiveMcpServers(this.ctx, state)) };
1202
- }
1203
- async installBuiltins(payload) {
1204
- return withPatchWrite(this.ctx, async () => {
1205
- const state = await managedState(this.ctx);
1206
- const result = appendSelectedBuiltinMcpServers(
1207
- state.content,
1208
- effectiveMcpServers(this.ctx, state),
1209
- payload?.ids,
1210
- { reservedIds: reservedEntryIds(this.ctx) },
1211
- );
1212
- if (result.content !== state.content) await writePatch(state, result.content);
1213
- const notes = [];
1214
- if (result.added.length) notes.push(`已追加:${result.added.join(", ")}`);
1215
- if (result.skipped.length) notes.push(`已存在并跳过:${result.skipped.join(", ")}`);
1216
- const { content: _content, ...summary } = result;
1217
- return { ...summary, note: notes.join(";") || "未修改配置" };
1218
- });
1219
- }
1220
1389
  async add(spec) {
1221
1390
  if (containsRedactedValue(spec)) throw new Error("新增 MCP 不能包含保留原值标记");
1222
1391
  const normalized = normalizeOne(spec);
@@ -1454,36 +1623,6 @@ let McpManagerGateway = (() => {
1454
1623
  catch (error) { this.ctx.logger?.error?.(`mcp-manager: 屏蔽已写入,但对齐会话作用域失败(下次挂载会重试): ${error?.message ?? error}`); }
1455
1624
  return result;
1456
1625
  }
1457
- async installWorkspaceBuiltins(payload) {
1458
- const wsPath = canonicalWorkspacePath(String(payload?.wsPath || ""));
1459
- const ids = payload?.ids;
1460
- if (!Array.isArray(ids) || !ids.length || !ids.every((id) => typeof id === "string")) throw new Error("内置 MCP ids 必须是非空字符串数组");
1461
- const result = await withWorkspaceWrite(wsPath, async () => {
1462
- const config = await readWorkspaceConfigCached(this.ctx, wsPath);
1463
- if (config.error) throw new Error(config.error);
1464
- const known = new Map(BUILTIN_MCP_SERVERS.map((builtin) => [builtin.id, builtin]));
1465
- const unknown = ids.filter((id) => !known.has(id));
1466
- if (unknown.length) throw new Error(`未知的内置 MCP:${unknown.join(", ")}`);
1467
- const existing = new Set(config.servers.map((server) => server.name));
1468
- const added = [];
1469
- const skipped = [];
1470
- for (const id of ids) {
1471
- const builtin = known.get(id);
1472
- if (existing.has(builtin.name)) { skipped.push(id); continue; }
1473
- const spec = { name: builtin.name };
1474
- for (const field of ["transport", "command", "args", "env", "cwd", "url", "headers", "toolCallTimeoutMs", "failOnStartupError", "reconnect"]) {
1475
- if (builtin[field] !== undefined) spec[field] = structuredClone(builtin[field]);
1476
- }
1477
- added.push(spec);
1478
- }
1479
- if (!added.length) return { note: skipped.length ? `已存在并跳过:${skipped.join(", ")}` : "未修改配置", unchanged: true };
1480
- await writeWorkspaceConfigFile(wsPath, [...config.servers, ...added], config.exclude);
1481
- return { note: `已追加:${added.map((server) => server.name).join(", ")}${skipped.length ? `;已存在并跳过:${skipped.join(", ")}` : ""}` };
1482
- });
1483
- // 没写盘就不用对齐(否则每次点"安装内置"都会白跑一遍挂载)。
1484
- if (!result.unchanged) await alignWorkspaceConnections(this.ctx, wsPath);
1485
- return { note: result.note };
1486
- }
1487
1626
  async previewWorkspaceImport(payload) {
1488
1627
  const wsPath = canonicalWorkspacePath(String(payload?.wsPath || ""));
1489
1628
  const json = typeof payload?.json === "string" ? JSON.parse(payload.json) : payload?.json;
@@ -1674,6 +1813,10 @@ let McpManagerGateway = (() => {
1674
1813
  async wbConnectorPreview(payload) {
1675
1814
  return wbConnectorPreview(payload?.connectorId);
1676
1815
  }
1816
+ // 某条连接器的图标(data URL)。市场卡片进视口才调,payload 形状同 wbConnectorPreview。
1817
+ async wbConnectorIcon(payload) {
1818
+ return wbConnectorIcon(payload?.connectorId);
1819
+ }
1677
1820
  async wbConnectorInstall(payload) {
1678
1821
  const connectorId = String(payload?.connectorId || "").trim();
1679
1822
  if (!connectorId) throw new Error("缺少 connectorId");
@@ -1845,15 +1988,6 @@ let McpManagerGateway = (() => {
1845
1988
  async wbMarketRegistryUpsert(payload) {
1846
1989
  return upsertMarketplace(payload || {});
1847
1990
  }
1848
- // ── T03/R5:codebuddy 插件市场 ──────────────────────────────────────
1849
- // 数据层在 lib/wb-plugin-market.js;这里只做 RPC 转发(下载/缓存/解析都在那边)。
1850
- async wbPluginCatalog() {
1851
- return wbPluginCatalog();
1852
- }
1853
- async wbPluginDetail(payload) {
1854
- return wbPluginDetail(payload?.name);
1855
- }
1856
-
1857
1991
  // ── T04/R8:安装状态账本(connector / skill / plugin 三类安装的统一登记) ──
1858
1992
  async wbInstallState() {
1859
1993
  return readInstallState();
@@ -1873,9 +2007,6 @@ let McpManagerGateway = (() => {
1873
2007
  return { note: `已移除安装状态:${kind}/${key}` };
1874
2008
  }
1875
2009
 
1876
- async wbPluginUpdateCheck() {
1877
- return wbPluginUpdateCheck();
1878
- }
1879
2010
  // ── T06/Awesome:DSH 社区插件市场(awesome-dsh-plugins)──────────────
1880
2011
  // 数据层在 lib/wb-awesome-market.js;这里只做 RPC 转发。
1881
2012
  async wbAwesomeCatalog(payload) {
@@ -1890,6 +2021,35 @@ let McpManagerGateway = (() => {
1890
2021
  async wbAwesomeUpdateCheck() {
1891
2022
  return wbAwesomeUpdateCheck();
1892
2023
  }
2024
+ // ── 社区元信息:仓库「人味」信号(维护者 / 最近提交 / issue / star)────────
2025
+ // 详情弹层按需调用,只读公开接口,6 小时缓存;不接收也不保存任何凭据。
2026
+ async wbRepoMeta(payload) {
2027
+ return wbRepoMeta(payload || {});
2028
+ }
2029
+ // ── npm 近 30 天下载量(只读)───────────────────────────────────────
2030
+ // 卡片进视口才按需批量取,7 天缓存;只读公开统计接口,不接收也不保存任何凭据。
2031
+ async wbNpmDownloads(payload) {
2032
+ return wbNpmDownloads(payload || {});
2033
+ }
2034
+ // ── 装备清单(只读)────────────────────────────────────────────────
2035
+ // 导出:收集本机全局 MCP / 技能 / 已召唤专家 / 已装插件,只留身份字段。
2036
+ // 对比:校验用户贴入的清单并与本机做差异,返回逐条状态;不安装、不写盘。
2037
+ async wbLoadoutExport(payload) {
2038
+ const items = await collectLoadoutItems(this.ctx);
2039
+ return {
2040
+ ok: true,
2041
+ loadout: buildLoadout({
2042
+ name: payload?.name,
2043
+ items,
2044
+ appVersion: pluginVersion(),
2045
+ }),
2046
+ };
2047
+ }
2048
+ async wbLoadoutDiff(payload) {
2049
+ const raw = payload?.loadout ?? payload?.text ?? payload;
2050
+ const items = await collectLoadoutItems(this.ctx);
2051
+ return { ok: true, ...diffLoadout(raw, items) };
2052
+ }
1893
2053
  // ── WorkBuddy 专家直连(召唤预设 + 捆绑技能)────────────────────────
1894
2054
  // 数据与安装逻辑都在 lib/expert-market.js;这里只做 RPC 转发与 patch 写盘收尾。
1895
2055
  // 召唤 = 往 profile patch 插入一条独立 @deepseek-ai/dsh-agent-preset 行(persona.prefix
@@ -2031,7 +2191,31 @@ let McpManagerGateway = (() => {
2031
2191
  // 不存在的 TeamCreate/Agent(成员开不出来)。标记桥接判定放前端(需要市场目录的
2032
2192
  // expertType),这里只把 personaText 原样带出去。
2033
2193
  const patch = await readPatch(this.ctx);
2034
- return { presets: readExpertPresets(patch.content), skills: await listExpertSkills() };
2194
+ const presets = readExpertPresets(patch.content);
2195
+ // patch 只记 plugin / presetId,中英显示名在专家目录缓存里。这里补上两个字段,
2196
+ // 客户端按宿主语言挑:中文名给中文界面,英文名给英文界面。读缓存失败只回落
2197
+ // plugin 名,不影响「已召唤 / 已装技能」本身的状态判断。
2198
+ // 回落有三层(目录缓存 → 预设行自带的名字 → 英文标识名):召唤那一刻
2199
+ // `WorkBuddy 专家 · <显示名>` 就写进了 patch 行,readExpertPresets 剥前缀即得,
2200
+ // 所以目录没落盘 / 专家已下架时菜单仍能出「吴八哥」,而不是 senior-developer。
2201
+ let displayNames = new Map();
2202
+ try {
2203
+ displayNames = await readExpertDisplayNames();
2204
+ } catch (error) {
2205
+ this.ctx.logger?.warn?.(`wb-expert: 读取专家显示名失败:${error?.message ?? error}`);
2206
+ }
2207
+ return {
2208
+ presets: presets.map((row) => {
2209
+ const info = displayNames.get(row.plugin) || {};
2210
+ return {
2211
+ ...row,
2212
+ ...info,
2213
+ nameZh: info.nameZh || row.displayName || "",
2214
+ nameEn: info.nameEn || row.displayName || "",
2215
+ };
2216
+ }),
2217
+ skills: await listExpertSkills(),
2218
+ };
2035
2219
  }
2036
2220
  // 最近使用记录(输入框召唤菜单的数据源):召唤/送还时自动记录专家;技能与 MCP 由
2037
2221
  // 客户端在用户从菜单里显式选用时上报(recordUse)。只存展示所需最小字段。
@@ -2046,4 +2230,4 @@ let McpManagerGateway = (() => {
2046
2230
  };
2047
2231
  })();
2048
2232
 
2049
- export { checkForUpdate, McpManagerGateway, McpManagerGateway as default, summarizeWorkspaceRow };
2233
+ export { McpManagerGateway, McpManagerGateway as default };