dsh-mcp-connector 0.2.68 → 0.2.69

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/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.2.69] - 2026-10-08
8
+
9
+ ### Changed
10
+
11
+ - DSH `>=0.2.0-rc.2` 的左侧入口改用官方 `sidebar.panellist` 与 keyed `main` 席位,由宿主统一渲染行高、折叠提示、选中态和无障碍名称;市场主体与设置页快捷弹框共用(#129)。
12
+ - DSH `0.1.x` 仅在原生席位不可用时按需启用 footer/Portal 兼容适配器;席位延迟到达时会原子替换,不会同时显示两个入口。
13
+ - 关闭“在侧边栏显示 MCP连接器”会真正注销原生行;如果当前正在连接器面板,先安全返回会话界面。
14
+
15
+ ### Verification
16
+
17
+ - 新增 DSH 0.2 原生席位、0.1.x 兼容回退、延迟席位替换和动态隐藏/恢复回归测试。
18
+
7
19
  ## [0.2.68] - 2026-10-06
8
20
 
9
21
  ### Fixed
package/README.en.md CHANGED
@@ -62,7 +62,7 @@ If the plugin helps you connect an MCP server faster, consider [starring the rep
62
62
 
63
63
  ## Features
64
64
 
65
- - A primary sidebar entry below New Conversation and above workspaces/conversations, with a public footer-slot fallback for incompatible DSH DOM versions.
65
+ - A native `sidebar.panellist` row and keyed main panel on DSH `>=0.2.0-rc.2`, inheriting host selection, collapsed tooltip, and accessibility behavior; DSH `0.1.x` automatically uses the compatibility entry.
66
66
  - A profile-wide sidebar visibility preference; even when the shortcut is hidden, the existing connector dialog remains available from **Settings → Plugins → Plugin Configuration → MCP Connector**.
67
67
  - Searchable Marketplace and Installed views; the default Marketplace groups cards into Featured plus nine business-category sections, previews four cards per section, keeps the category bar visible while scrolling, and shows every card when a single category is selected.
68
68
  - OAuth 2.0 Authorization Code with PKCE, including DCR public clients and `client_secret_post` / `client_secret_basic`; API key/Bearer/unauthenticated HTTP configuration, stdio local-process configuration, and `mcpServers` JSON import.
@@ -85,7 +85,7 @@ If the plugin helps you connect an MCP server faster, consider [starring the rep
85
85
  - Explicit, non-destructive migration from the two earlier Qichacha OAuth plugins, plus active-plugin conflict detection that blocks duplicate server management and credential overwrites.
86
86
 
87
87
  <!-- catalog-stats:start -->
88
- As of 2026-10-05, the public Registry publishes 108 connector descriptors. After merging and deduplicating them with the 4 bundled Qichacha cards, the Marketplace exposes 112 cards across 9 business categories. Recommendations remain limited to the four Qichacha cards, PKULaw, and Wind, for 6 featured cards in total. The Registry evolves independently; the badge shown after a client refresh and the live badges above are the authoritative current counts.
88
+ As of 2026-10-06, the public Registry publishes 109 connector descriptors. After merging and deduplicating them with the 4 bundled Qichacha cards, the Marketplace exposes 113 cards across 9 business categories. Recommendations remain limited to the four Qichacha cards, PKULaw, and Wind, for 6 featured cards in total. The Registry evolves independently; the badge shown after a client refresh and the live badges above are the authoritative current counts.
89
89
  <!-- catalog-stats:end -->
90
90
 
91
91
  ## Interface and demo
@@ -202,7 +202,7 @@ npm run dev:ui
202
202
 
203
203
  Every Registry merge regenerates `catalog-stats.json`; an hourly workflow in this repository synchronizes the Chinese and English product copy plus a local stats snapshot. The static npm README updates with package releases, while the live badges above read the Registry directly and therefore stay current without another npm release.
204
204
 
205
- The current public version is [`dsh-mcp-connector@0.2.68`](https://www.npmjs.com/package/dsh-mcp-connector), with [GitHub Release v0.2.68](https://github.com/duhu2000/dsh-mcp-connector/releases/tag/v0.2.68).
205
+ The current public version is [`dsh-mcp-connector@0.2.69`](https://www.npmjs.com/package/dsh-mcp-connector), with [GitHub Release v0.2.69](https://github.com/duhu2000/dsh-mcp-connector/releases/tag/v0.2.69).
206
206
 
207
207
  See [CHANGELOG.md](CHANGELOG.md) for version history and [docs/DESKTOP-E2E.md](docs/DESKTOP-E2E.md) for the Desktop release checklist.
208
208
 
package/README.md CHANGED
@@ -62,7 +62,7 @@ dsh plugin --profile web add dsh-mcp-connector
62
62
 
63
63
  ## 功能
64
64
 
65
- - 左侧主导航入口:目标位置为“新会话”下方、“工作区/会话列表”上方;若 DSH DOM 结构不兼容,自动回退到底部公开插槽。
65
+ - 左侧主导航入口:DSH `>=0.2.0-rc.2` 使用官方 `sidebar.panellist` 行与原生主面板,继承宿主选中态、折叠提示和无障碍行为;DSH `0.1.x` 自动回退到兼容入口。
66
66
  - 侧边栏入口可按当前 profile 隐藏;隐藏后仍可从“设置 → 插件 → 插件配置 → MCP连接器”临时打开现有连接器弹框,用完即关。
67
67
  - 图形化市场:默认“全部”按推荐与 9 类业务分类分章节展示,每章先展示 4 张并可展开;分类栏固定可见,单分类页展示全部卡片。
68
68
  - 图形化添加:手动 HTTP/stdio、`mcpServers` JSON、连接器描述 URL 三种入口,失败时保留表单并给出修复建议。
@@ -86,7 +86,7 @@ dsh plugin --profile web add dsh-mcp-connector
86
86
  - 对话工具:`mcp_connector_catalog`、`connect`、`configure`、`import_json`、`export_config`、`snapshot`、`install_from_url`、`status`、`scope`、`health_check`、`policy`、`set_enabled`、`session_tools`、`disconnect`、`refresh_catalog`、`publish`、`tools_list`、`tool_search`、`tool_detail`。搜索/详情只做渐进式能力发现,不执行目标 MCP 工具。
87
87
 
88
88
  <!-- catalog-stats:start -->
89
- 截至 2026-10-05,公共 Registry 已发布 108 条连接器描述;与随包的 4 张企查查卡片合并去重后,市场页可浏览 112 张卡片,覆盖企业数据、金融投资、法律合规、开发工具、办公协作、调研分析、设计创意、效率工具、其他 9 类。推荐位严格保留 4 张企查查卡片、北大法宝和 Wind,共 6 张;其他连接器按业务分类展示。Registry 可独立持续更新,实际数量以客户端刷新后的市场页签徽标和上方实时统计徽标为准。
89
+ 截至 2026-10-06,公共 Registry 已发布 109 条连接器描述;与随包的 4 张企查查卡片合并去重后,市场页可浏览 113 张卡片,覆盖企业数据、金融投资、法律合规、开发工具、办公协作、调研分析、设计创意、效率工具、其他 9 类。推荐位严格保留 4 张企查查卡片、北大法宝和 Wind,共 6 张;其他连接器按业务分类展示。Registry 可独立持续更新,实际数量以客户端刷新后的市场页签徽标和上方实时统计徽标为准。
90
90
  <!-- catalog-stats:end -->
91
91
 
92
92
  ## 界面与演示
@@ -197,7 +197,7 @@ npm run dev:ui
197
197
 
198
198
  公共 Registry 每次合并后会生成 `catalog-stats.json`;本仓库的定时工作流每小时同步中英文介绍和统计快照。npm 页面中的静态正文随版本发布更新,上方动态统计徽标则直接读取 Registry,可在不发布新 npm 版本时保持实时数量一致。
199
199
 
200
- 当前公开版本为 [`dsh-mcp-connector@0.2.68`](https://www.npmjs.com/package/dsh-mcp-connector),对应 [GitHub Release v0.2.68](https://github.com/duhu2000/dsh-mcp-connector/releases/tag/v0.2.68)。
200
+ 当前公开版本为 [`dsh-mcp-connector@0.2.69`](https://www.npmjs.com/package/dsh-mcp-connector),对应 [GitHub Release v0.2.69](https://github.com/duhu2000/dsh-mcp-connector/releases/tag/v0.2.69)。
201
201
 
202
202
  版本能力与变更记录见 [CHANGELOG.md](CHANGELOG.md)。
203
203
  Desktop 发版回归见 [docs/DESKTOP-E2E.md](docs/DESKTOP-E2E.md)。
@@ -47,10 +47,10 @@ dsh web
47
47
 
48
48
  重启后,可以用以下任一方式打开:
49
49
 
50
- - 在 DSH 左侧主导航点击“MCP连接器”。入口通常位于“新会话”下方、工作区/会话列表上方;如果当前 DSH 版本没有对应的公开插槽,入口会回退到左侧底部。
50
+ - 在 DSH 左侧主导航点击“MCP连接器”。DSH `>=0.2.0-rc.2` 使用宿主原生面板行,展开、折叠、选中态和键盘操作均与其他主导航一致;DSH `0.1.x` 自动使用左侧底部兼容入口。
51
51
  - 打开“设置 → 插件 → 插件配置 → MCP连接器”,展开卡片并点击“打开 MCP连接器”。该按钮直接复用同一个连接器弹框,不要求侧边栏入口可见;关闭弹框后仍回到设置页。
52
52
 
53
- 如需腾出侧边栏空间,可在同一配置卡片关闭“在侧边栏显示 MCP连接器”。该偏好作用于当前 DSH profile,并在重启后保留;它只隐藏快捷入口,不停用插件、已连接 MCP Server 或工具。隐藏后可以随时从该配置卡片直接打开连接器,或重新开启入口。旧版 DSH 没有 Settings 能力时,插件保持入口可见,不会因设置功能进入 Safe Mode。
53
+ 如需腾出侧边栏空间,可在同一配置卡片关闭“在侧边栏显示 MCP连接器”。该偏好作用于当前 DSH profile,并在重启后保留;它只隐藏快捷入口,不停用插件、已连接 MCP Server 或工具。如果隐藏时正在原生连接器面板,页面会先返回当前会话;之后仍可从该配置卡片直接打开弹框,或重新开启入口。旧版 DSH 没有 Settings 能力时,插件保持入口可见,不会因设置功能进入 Safe Mode。
54
54
 
55
55
  页面顶部提供:
56
56
 
package/lib/client.js CHANGED
@@ -38,9 +38,9 @@ window.__ModuleLoader__.load({
38
38
  ]);
39
39
 
40
40
  /**
41
- * sidebar.footer.action 的 SlotOutlet 由宿主以 display: contents 作为
42
- * 纯锚点。这里只能样式化本插件自己的节点,不能改写公共槽位或其它
43
- * 插件子项;否则第三方 flex-basis 会因主轴变化而隐藏相邻入口(#124)。
41
+ * DSH 0.1.x 的 sidebar.footer.action 兼容入口样式。新版宿主使用
42
+ * sidebar.panellist 原生行,不会安装本段 CSS。兼容适配器只样式化
43
+ * 本插件节点,不改写公共槽位或其它插件子项(#124)。
44
44
  */
45
45
  const SIDEBAR_STYLE_ID = "dsh-mcp-connector-sidebar";
46
46
  const sidebarCss = `
@@ -763,6 +763,7 @@ window.__ModuleLoader__.load({
763
763
  function createMarketViewStore() {
764
764
  let sidebarVisible = true;
765
765
  const liveActions = new Set();
766
+ const visibilityListeners = new Set();
766
767
  const spec = {
767
768
  init: () => ({ open: false, detailOpen: false, sidebarVisible }),
768
769
  actions: {
@@ -775,9 +776,19 @@ window.__ModuleLoader__.load({
775
776
  };
776
777
  return {
777
778
  spec,
779
+ getSidebarVisible() {
780
+ return sidebarVisible;
781
+ },
782
+ subscribeSidebarVisible(listener) {
783
+ visibilityListeners.add(listener);
784
+ return () => { visibilityListeners.delete(listener); };
785
+ },
778
786
  syncSidebarVisible(visible) {
779
- sidebarVisible = visible !== false;
787
+ const next = visible !== false;
788
+ if (sidebarVisible === next) return;
789
+ sidebarVisible = next;
780
790
  for (const actions of liveActions) actions.setSidebarVisible(sidebarVisible);
791
+ for (const listener of visibilityListeners) listener(sidebarVisible);
781
792
  },
782
793
  create() {
783
794
  let state = spec.init();
@@ -1079,17 +1090,24 @@ window.__ModuleLoader__.load({
1079
1090
  return sessionId;
1080
1091
  }
1081
1092
 
1082
- /** 弹框组件:居中显示市场 SPA(浅色主题)。 */
1093
+ /** 市场主体:原生 main 面板与设置页快捷弹框共用。 */
1083
1094
  function MarketOverlay(props) {
1084
1095
  const {
1085
1096
  wide,
1086
1097
  useStore,
1087
1098
  actions,
1099
+ presentation = "modal",
1100
+ closePanel = null,
1088
1101
  startPromptSession: launchPromptSession,
1089
1102
  workspaceContext = () => null,
1090
1103
  workspaceOptions = () => []
1091
1104
  } = props;
1092
- const open = useStore((state) => state.open);
1105
+ const modalOpen = useStore((state) => state.open);
1106
+ const open = presentation === "panel" || modalOpen;
1107
+ const closeView = () => {
1108
+ if (presentation === "panel") closePanel?.();
1109
+ else actions.close();
1110
+ };
1093
1111
  const detailOpen = useStore((state) => state.detailOpen);
1094
1112
  const [versionStatus, setVersionStatus] = (0, react.useState)(null);
1095
1113
  const [updateProviderState, setUpdateProviderState] = (0, react.useState)("checking");
@@ -1144,7 +1162,7 @@ window.__ModuleLoader__.load({
1144
1162
  }
1145
1163
  Promise.resolve(launchPromptSession(prompt)).then(() => {
1146
1164
  reply(true, "已带入新会话");
1147
- window.requestAnimationFrame(() => { actions.close(); });
1165
+ window.requestAnimationFrame(closeView);
1148
1166
  }, (error) => {
1149
1167
  const message = error instanceof Error ? error.message : String(error);
1150
1168
  console.error("[mcp-connector] start prompt session failed:", error);
@@ -1153,7 +1171,7 @@ window.__ModuleLoader__.load({
1153
1171
  };
1154
1172
  window.addEventListener("message", onMessage);
1155
1173
  return () => { window.removeEventListener("message", onMessage); };
1156
- }, [actions, launchPromptSession, workspaceContext]);
1174
+ }, [actions, closePanel, launchPromptSession, presentation, workspaceContext]);
1157
1175
  (0, react.useEffect)(() => {
1158
1176
  if (!open) return void 0;
1159
1177
  let disposed = false;
@@ -1284,14 +1302,14 @@ window.__ModuleLoader__.load({
1284
1302
  };
1285
1303
  }, [open, updateOperation?.operationId, updateProviderSelection?.provider?.id, expectedUpdateVersion]);
1286
1304
  (0, react.useEffect)(() => {
1287
- if (!open) return void 0;
1305
+ if (!open || presentation === "panel") return void 0;
1288
1306
  const opener = document.activeElement;
1289
1307
  closeRef.current?.focus?.();
1290
1308
  const onKeyDown = (event) => {
1291
1309
  if (event.key !== "Escape") return;
1292
1310
  event.preventDefault();
1293
1311
  event.stopPropagation();
1294
- actions.close();
1312
+ closeView();
1295
1313
  };
1296
1314
  // Capture at window before the underlying Settings dialog receives
1297
1315
  // Escape on document; only the topmost connector dialog should close.
@@ -1300,7 +1318,7 @@ window.__ModuleLoader__.load({
1300
1318
  window.removeEventListener("keydown", onKeyDown, true);
1301
1319
  if (opener?.isConnected !== false) opener?.focus?.();
1302
1320
  };
1303
- }, [open, actions]);
1321
+ }, [open, actions, closePanel, presentation]);
1304
1322
  if (!open) return null;
1305
1323
  const updateRunning = updateStarting || updateOperation !== null && ["queued", "running"].includes(updateOperation.state);
1306
1324
  const startUpdate = (force = false) => {
@@ -1567,30 +1585,21 @@ window.__ModuleLoader__.load({
1567
1585
  });
1568
1586
  };
1569
1587
  const src = window.location.origin + "/mcp-connector/ui/";
1570
- const modal = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1571
- style: {
1572
- position: "fixed",
1573
- inset: 0,
1574
- background: "rgba(0,0,0,0.4)",
1575
- display: "flex",
1576
- alignItems: "center",
1577
- justifyContent: "center",
1578
- zIndex: CONNECTOR_MODAL_Z_INDEX
1579
- },
1580
- onClick: (event) => { if (event.target === event.currentTarget) actions.close(); },
1581
- children: [
1582
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1588
+ const titleId = presentation === "panel"
1589
+ ? "mcp-connector-native-title"
1590
+ : "mcp-connector-modal-title";
1591
+ const marketPanel = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1583
1592
  className: "mcpConnectorMarketPanel",
1584
- role: "dialog",
1585
- "aria-modal": true,
1586
- "aria-labelledby": "mcp-connector-market-title",
1593
+ role: presentation === "panel" ? "region" : "dialog",
1594
+ "aria-modal": presentation === "panel" ? void 0 : true,
1595
+ "aria-labelledby": titleId,
1587
1596
  style: {
1588
- borderRadius: 16,
1589
- width: "min(800px, 90%)",
1590
- height: "min(800px, 85%)",
1597
+ borderRadius: presentation === "panel" ? 0 : 16,
1598
+ width: presentation === "panel" ? "100%" : "min(800px, 90%)",
1599
+ height: presentation === "panel" ? "100%" : "min(800px, 85%)",
1591
1600
  display: "flex",
1592
1601
  flexDirection: "column",
1593
- boxShadow: "0 20px 60px rgba(0,0,0,0.15)",
1602
+ boxShadow: presentation === "panel" ? "none" : "0 20px 60px rgba(0,0,0,0.15)",
1594
1603
  overflow: "hidden"
1595
1604
  },
1596
1605
  children: [
@@ -1626,7 +1635,7 @@ window.__ModuleLoader__.load({
1626
1635
  ]
1627
1636
  })
1628
1637
  }),
1629
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { id: "mcp-connector-market-title", className: "mcpConnectorMarketTitle", style: { fontSize: 18, fontWeight: 600 }, children: "MCP连接器" }),
1638
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { id: titleId, className: "mcpConnectorMarketTitle", style: { fontSize: 18, fontWeight: 600 }, children: "MCP连接器" }),
1630
1639
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1631
1640
  className: "mcpConnectorVersion",
1632
1641
  title: versionStatus === null ? "正在检查插件版本" : `当前版本 v${versionStatus.installedVersion}`,
@@ -1657,8 +1666,8 @@ window.__ModuleLoader__.load({
1657
1666
  ref: closeRef,
1658
1667
  className: "mcpConnectorMarketClose",
1659
1668
  type: "button",
1660
- "aria-label": "关闭 MCP连接器",
1661
- onClick: () => actions.close(),
1669
+ "aria-label": presentation === "panel" ? "返回会话" : "关闭 MCP连接器",
1670
+ onClick: closeView,
1662
1671
  style: {
1663
1672
  background: "transparent",
1664
1673
  border: "none",
@@ -1689,8 +1698,20 @@ window.__ModuleLoader__.load({
1689
1698
  }
1690
1699
  })
1691
1700
  ]
1692
- })
1693
- ]
1701
+ });
1702
+ if (presentation === "panel") return marketPanel;
1703
+ const modal = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1704
+ style: {
1705
+ position: "fixed",
1706
+ inset: 0,
1707
+ background: "rgba(0,0,0,0.4)",
1708
+ display: "flex",
1709
+ alignItems: "center",
1710
+ justifyContent: "center",
1711
+ zIndex: CONNECTOR_MODAL_Z_INDEX
1712
+ },
1713
+ onClick: (event) => { if (event.target === event.currentTarget) closeView(); },
1714
+ children: marketPanel
1694
1715
  });
1695
1716
  // shell.overlay lives inside a z-index:20 stacking context, while DSH
1696
1717
  // Settings is a root-level z-index:1000 modal. Portal to body so the
@@ -1702,8 +1723,8 @@ window.__ModuleLoader__.load({
1702
1723
  return modal;
1703
1724
  }
1704
1725
 
1705
- /** 左栏入口:固定图标列与文字间距,键盘焦点与鼠标悬停分别处理。 */
1706
- function SidebarEntry(props) {
1726
+ /** DSH 0.1.x 兼容入口:仅在原生面板席位不完整时挂载。 */
1727
+ function LegacySidebarEntry(props) {
1707
1728
  const { wide, useStore, actions } = props;
1708
1729
  const open = useStore((state) => state.open);
1709
1730
  const visible = useStore((state) => state.sidebarVisible !== false);
@@ -1772,6 +1793,147 @@ window.__ModuleLoader__.load({
1772
1793
  }), topMount);
1773
1794
  }
1774
1795
 
1796
+ /** 新版 DSH 会渲染整行按钮;插件只提供随 size/currentColor 变化的字形。 */
1797
+ function NativeSidebarIcon(props) {
1798
+ const size = Number.isFinite(props?.size) ? props.size : 16;
1799
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1800
+ viewBox: "0 0 16 16",
1801
+ width: size,
1802
+ height: size,
1803
+ fill: "none",
1804
+ stroke: "currentColor",
1805
+ "aria-hidden": "true",
1806
+ style: { display: "block" },
1807
+ children: [
1808
+ (0, react_jsx_runtime.jsx)("path", { d: "M6 2V4.5", strokeLinecap: "round" }),
1809
+ (0, react_jsx_runtime.jsx)("path", { d: "M10 2V4.5", strokeLinecap: "round" }),
1810
+ (0, react_jsx_runtime.jsx)("path", { d: "M3.5 4.5H12.5V8.25C12.5 10.7353 10.4853 12.75 8 12.75C5.51472 12.75 3.5 10.7353 3.5 8.25V4.5Z", strokeLinejoin: "round" }),
1811
+ (0, react_jsx_runtime.jsx)("path", { d: "M8 12.75V14.5", strokeLinecap: "round" })
1812
+ ]
1813
+ });
1814
+ }
1815
+
1816
+ function marketRuntimeProps(ctx) {
1817
+ return {
1818
+ startPromptSession: (promptText) => startPromptSession(ctx, promptText),
1819
+ workspaceContext: () => currentWorkspaceContext(ctx),
1820
+ workspaceOptions: () => availableWorkspaceContexts(ctx)
1821
+ };
1822
+ }
1823
+
1824
+ /**
1825
+ * 原生 main + sidebar.panellist 优先;两个席位未同时就绪时才启用
1826
+ * DSH 0.1.x footer/Portal 兼容适配器。席位可以延迟声明,因此状态不依赖 DOM 探测。
1827
+ */
1828
+ function installSidebarSlots(ctx, marketView) {
1829
+ let mainReady = false;
1830
+ let panelListReady = false;
1831
+ let footerReady = false;
1832
+ let nativeEntryDispose = null;
1833
+ let fallbackEntryDispose = null;
1834
+
1835
+ const layout = () => typeof ctx.get === "function" ? ctx.get("layout") ?? ctx.layout : ctx.layout;
1836
+ const leaveNativePanel = () => {
1837
+ const controller = layout();
1838
+ try {
1839
+ if (controller?.panelInfo?.getSnapshot?.().activePanelId === "mcp-connector") {
1840
+ controller.selectPanel(null);
1841
+ }
1842
+ } catch (error) {
1843
+ console.warn("[mcp-connector] failed to leave native panel:", error);
1844
+ }
1845
+ };
1846
+ const disposeNativeEntry = () => {
1847
+ if (nativeEntryDispose === null) return;
1848
+ leaveNativePanel();
1849
+ nativeEntryDispose();
1850
+ nativeEntryDispose = null;
1851
+ };
1852
+ const disposeFallbackEntry = () => {
1853
+ if (fallbackEntryDispose === null) return;
1854
+ fallbackEntryDispose();
1855
+ fallbackEntryDispose = null;
1856
+ };
1857
+ const syncEntries = () => {
1858
+ const visible = marketView.getSidebarVisible();
1859
+ const nativeReady = mainReady && panelListReady;
1860
+ if (nativeReady) {
1861
+ disposeFallbackEntry();
1862
+ if (visible && nativeEntryDispose === null) {
1863
+ nativeEntryDispose = ctx.slots.register({
1864
+ name: "sidebar.panellist",
1865
+ id: "mcp-connector",
1866
+ order: 40,
1867
+ label: "MCP连接器"
1868
+ }, NativeSidebarIcon);
1869
+ } else if (!visible) {
1870
+ disposeNativeEntry();
1871
+ }
1872
+ return;
1873
+ }
1874
+ disposeNativeEntry();
1875
+ if (footerReady && visible && fallbackEntryDispose === null) {
1876
+ fallbackEntryDispose = ctx.slots.register({
1877
+ name: "sidebar.footer.action",
1878
+ id: "mcp-connector",
1879
+ order: 0,
1880
+ store: marketView
1881
+ }, LegacySidebarEntry);
1882
+ } else if (!visible) {
1883
+ disposeFallbackEntry();
1884
+ }
1885
+ };
1886
+
1887
+ ctx.effect(() => {
1888
+ const unsubscribe = marketView.subscribeSidebarVisible(syncEntries);
1889
+ return () => {
1890
+ unsubscribe();
1891
+ disposeNativeEntry();
1892
+ disposeFallbackEntry();
1893
+ };
1894
+ }, "mcp-connector: sidebar entry visibility");
1895
+
1896
+ // main 必须先于 panellist 行就绪,否则宿主会拒绝选中缺页面的行。
1897
+ ctx.slots.inject("main", () => {
1898
+ const disposeMain = ctx.slots.register({
1899
+ name: "main",
1900
+ key: "mcp-connector",
1901
+ store: marketView,
1902
+ inject: () => ({
1903
+ ...marketRuntimeProps(ctx),
1904
+ presentation: "panel",
1905
+ closePanel: () => layout()?.selectPanel?.(null)
1906
+ })
1907
+ }, MarketOverlay);
1908
+ mainReady = true;
1909
+ syncEntries();
1910
+ return () => {
1911
+ leaveNativePanel();
1912
+ mainReady = false;
1913
+ syncEntries();
1914
+ disposeMain();
1915
+ };
1916
+ });
1917
+
1918
+ ctx.slots.inject("sidebar.panellist", () => {
1919
+ panelListReady = true;
1920
+ syncEntries();
1921
+ return () => {
1922
+ panelListReady = false;
1923
+ syncEntries();
1924
+ };
1925
+ });
1926
+
1927
+ ctx.slots.inject("sidebar.footer.action", () => {
1928
+ footerReady = true;
1929
+ syncEntries();
1930
+ return () => {
1931
+ footerReady = false;
1932
+ disposeFallbackEntry();
1933
+ };
1934
+ });
1935
+ }
1936
+
1775
1937
  function apply(ctx) {
1776
1938
  console.log('[mcp-connector] client apply() called');
1777
1939
  try {
@@ -1787,24 +1949,11 @@ window.__ModuleLoader__.load({
1787
1949
  id: "mcp-connector",
1788
1950
  order: 100,
1789
1951
  store: marketView,
1790
- inject: () => ({
1791
- startPromptSession: (promptText) => startPromptSession(ctx, promptText),
1792
- workspaceContext: () => currentWorkspaceContext(ctx),
1793
- workspaceOptions: () => availableWorkspaceContexts(ctx)
1794
- })
1952
+ inject: () => marketRuntimeProps(ctx)
1795
1953
  }, MarketOverlay);
1796
1954
  });
1797
1955
 
1798
- // 左栏:公开 footer slot 托管生命周期;组件会 Portal 到工作区列表上方。
1799
- ctx.slots.inject("sidebar.footer.action", () => {
1800
- console.log('[mcp-connector] registering sidebar.footer.action slot');
1801
- return ctx.slots.register({
1802
- name: "sidebar.footer.action",
1803
- id: "mcp-connector",
1804
- order: 0,
1805
- store: marketView
1806
- }, SidebarEntry);
1807
- });
1956
+ installSidebarSlots(ctx, marketView);
1808
1957
  console.log('[mcp-connector] client apply() completed');
1809
1958
  } catch (error) {
1810
1959
  console.error('[mcp-connector] client apply() failed:', error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mcp-connector",
3
- "version": "0.2.68",
3
+ "version": "0.2.69",
4
4
  "description": "DeepSeek Harness MCP Connector: connect servers, search tools across active connections, and troubleshoot discovery. Includes a continuously updated catalog; supports OAuth 2.0 PKCE, API keys, Streamable HTTP/stdio, and mcpServers JSON import.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",