dsh-vscode-mode 0.20.1 → 0.20.2

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/README.md CHANGED
@@ -468,18 +468,18 @@ DSH 每次启动监听随机端口,`http://127.0.0.1:<port>` 就是浏览器 o
468
468
 
469
469
  官方 `dsh plugin` 方式,三选一。下面以 `web` profile 为例;Desktop 或其他命名
470
470
  profile 请替换为实际目标,不要把示例目录当成当前运行 profile。升级前可阅读
471
- **v0.20.1** 恢复官方差异的文件内增删展示、块级/文件级 Keep 与有可信原始字节证据的安全 Undo,并恢复总文件数、Keep All / Undo All,修复五秒轮询闪动。升级后重启 DSH 并刷新页面;持久化与回退边界见 [0.20.0 发布说明](docs/release-0.20.0.md);从 0.14.2 或更旧版本升级还须阅读
471
+ **v0.20.2** 修复项目 MCP 状态查询暂停或暂不可用时的会话列表误告警;Keep All / Undo All 使用 DSH 原生确认弹窗。保留 v0.20.1 的文件内差异展示、块级/文件级安全审查和跨分页批量操作。升级后重启 DSH 并刷新页面;持久化与回退边界见 [0.20.0 发布说明](docs/release-0.20.0.md);从 0.14.2 或更旧版本升级还须阅读
472
472
  [0.14.3 数据迁移与回退说明](docs/release-0.14.3.md)。
473
473
 
474
474
  ```bash
475
475
  # ① Git 安装(clone + prepare 构建;推荐打固定 tag)
476
- dsh plugin --profile web add github:Lenonss/DSH_VsCodeMode#v0.20.1
476
+ dsh plugin --profile web add github:Lenonss/DSH_VsCodeMode#v0.20.2
477
477
 
478
478
  # ② npm 注册表(发布到 npm 后)
479
- dsh plugin --profile web add dsh-vscode-mode@0.20.1
479
+ dsh plugin --profile web add dsh-vscode-mode@0.20.2
480
480
 
481
481
  # ③ GitHub Release tgz 直装(Release asset 可用后)
482
- dsh plugin --profile web add https://github.com/Lenonss/DSH_VsCodeMode/releases/download/v0.20.1/dsh-vscode-mode-0.20.1.tgz
482
+ dsh plugin --profile web add https://github.com/Lenonss/DSH_VsCodeMode/releases/download/v0.20.2/dsh-vscode-mode-0.20.2.tgz
483
483
  ```
484
484
 
485
485
  > **DSH 版本政策(0.17.0 起)**:六项 DSH peer 仍统一声明为 `*`,另以
@@ -820,6 +820,7 @@ Keep All / Undo All 却是亮的。修复:单文件 Keep / Undo 覆盖冲突
820
820
  完整变更见 [GitHub Releases](https://github.com/Lenonss/DSH_VsCodeMode/releases)。
821
821
  近期关键版本:
822
822
 
823
+ - **v0.20.2**:区分项目 MCP 的等待查询、查询暂停与暂不可用状态;过期观测不再让所有会话显示警告,悬浮详情保留上次观测时间并冻结历史耗时,只有新鲜的初始化错误继续告警。页面恢复可见后串行恢复查询,避免取消中的请求重叠。Keep All / Undo All 改用随 DSH 主题的原生确认弹窗,默认聚焦取消;确认前校验打开弹窗的会话生命周期,取消不执行批量修改。
823
824
  - **v0.20.1**:恢复官方差异文件内增删、差异导航和块级/文件级 Keep / Undo;Undo 仅在可信原始字节、差异覆盖及文件版本校验通过时写回,无证据或冲突不覆盖。恢复工作区差异文件总数及跨分页、跨轮次 Keep All / Undo All,批量撤销先检查能力、遇冲突停止并报告部分完成。工具栏明确区分全局与当前文件;相同元数据轮询不再重复发布,同文件刷新保留差异直到新详情就绪,消除五秒闪动。升级后需重启 DSH 并刷新页面。
824
825
  - **v0.20.0**:**官方净差异持久化与现有审查入口整合**——采集官方轮次摘要及差异块,SQLite 保存并保留跨轮次 pending;复用现有列表、角标和文件导航,不新增独立审查栏。支持标记已审和编辑当前文件,保存不自动已审;没有可信历史全文及原始字节时禁止拒绝写回。修复路径身份和冷启动历史补采,无法恢复的旧摘要明确显示缺口;修正浅色主题操作栏文字对比度。详见 [0.20.0 发布说明](docs/release-0.20.0.md)。
825
826
 
package/lib/client.js CHANGED
@@ -1652,7 +1652,7 @@ window.__ModuleLoader__.load({
1652
1652
  }
1653
1653
  //#endregion
1654
1654
  //#region src/client/ui/LargeTextView.ts
1655
- const Button$2 = _deepseek_ai_dsh_client_ui_primitives.Button;
1655
+ const Button$3 = _deepseek_ai_dsh_client_ui_primitives.Button;
1656
1656
  /**
1657
1657
  * Read-only paged text surface: never creates a Monaco model or exposes a save action.
1658
1658
  * @public @author ddj 2026年10月22号
@@ -1727,7 +1727,7 @@ window.__ModuleLoader__.load({
1727
1727
  return react.default.createElement("section", {
1728
1728
  className: "edrv-large-text",
1729
1729
  "aria-label": "大文件只读预览"
1730
- }, react.default.createElement("div", { className: "edrv-large-text-toolbar" }, react.default.createElement("span", { role: "status" }, status), react.default.createElement(Button$2, {
1730
+ }, react.default.createElement("div", { className: "edrv-large-text-toolbar" }, react.default.createElement("span", { role: "status" }, status), react.default.createElement(Button$3, {
1731
1731
  onClick: loadNext,
1732
1732
  disabled: !state || state.loading || state.eof || state.capped
1733
1733
  }, state?.loading ? "加载中…" : state?.error ? "重试本段" : "加载下一段")), react.default.createElement("pre", {
@@ -3580,6 +3580,35 @@ window.__ModuleLoader__.load({
3580
3580
  return result;
3581
3581
  }
3582
3582
  //#endregion
3583
+ //#region src/client/ui/ReviewAllConfirm.ts
3584
+ /**
3585
+ * @public
3586
+ * @author ddj 2026年10月27号
3587
+ * @description Confirm workspace-wide review through the DSH modal; dismissing never applies a decision.
3588
+ * @param props Pending file count, action and explicit confirmation callbacks.
3589
+ * @returns DSH-themed confirmation with distinct Keep and Undo safety descriptions.
3590
+ */
3591
+ function ReviewAllConfirm(props) {
3592
+ const action = props.reject ? "Undo All" : "Keep All";
3593
+ const warning = props.reject ? "撤销会改写磁盘;逐项安全校验,遇到冲突停止,已完成项不会自动恢复。" : "只标记待审修改为保留,不改写文件。";
3594
+ const footer = react.default.createElement(react.default.Fragment, null, react.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
3595
+ variant: "ghost",
3596
+ onClick: props.onCancel,
3597
+ autoFocus: true
3598
+ }, "取消"), react.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
3599
+ variant: "primary",
3600
+ onClick: props.onConfirm
3601
+ }, "确认 " + action));
3602
+ return react.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Modal, {
3603
+ open: true,
3604
+ title: action + " 确认",
3605
+ closeLabel: "取消",
3606
+ onClose: props.onCancel,
3607
+ description: `处理当前工作区全部 ${props.count} 个待审差异文件(含其他轮次)?`,
3608
+ footer
3609
+ }, react.default.createElement("p", null, warning));
3610
+ }
3611
+ //#endregion
3583
3612
  //#region src/shared/reviewRegions.ts
3584
3613
  /** @public @author ddj 2026年10月27号 @param diff Immutable official patch. @returns Contiguous change runs with stable source-coordinate identities. */
3585
3614
  function reviewBlocks(diff) {
@@ -23878,6 +23907,7 @@ window.__ModuleLoader__.load({
23878
23907
  const hoverPanelRef = react.default.useRef(false);
23879
23908
  const batchBusyRef = react.default.useRef(false);
23880
23909
  const [reviewBatchBusy, setReviewBatchBusy] = react.default.useState(false);
23910
+ const [reviewAllPrompt, setReviewAllPrompt] = react.default.useState(null);
23881
23911
  const reviewLifeRef = react.default.useRef(null);
23882
23912
  react.default.useEffect(() => {
23883
23913
  const token = { live: true };
@@ -26936,9 +26966,7 @@ window.__ModuleLoader__.load({
26936
26966
  setError("官方待审列表尚未就绪,未执行批量操作");
26937
26967
  return;
26938
26968
  }
26939
- const count = sum.pendingFiles.length;
26940
- if (!count) return;
26941
- if (!window.confirm(`${reject ? "Undo All" : "Keep All"}:处理当前工作区全部 ${count} 个待审差异文件(含其他轮次)?${reject ? "\n撤销会改写磁盘;逐项安全校验,遇到冲突停止,已完成项不会自动恢复。" : "\n只标记待审修改为保留,不改写文件。"}`)) return;
26969
+ if (!sum.pendingFiles.length) return;
26942
26970
  const token = reviewLifeRef.current;
26943
26971
  const undoPath = activeRef.current;
26944
26972
  const undoModel = editorRef.current?.getModel?.();
@@ -27001,8 +27029,32 @@ window.__ModuleLoader__.load({
27001
27029
  if (token?.live) setReviewBatchBusy(false);
27002
27030
  }
27003
27031
  }
27004
- const acceptAllFiles = () => actReviewAll(false);
27005
- const undoAllFiles = () => actReviewAll(true);
27032
+ /** @private @author ddj 2026年10月27号 @param reject Whether to undo pending files. @description Open a DSH confirmation without starting any mutations. */
27033
+ function askReviewAll(reject) {
27034
+ if (batchBusyRef.current || !sum.pendingFiles.length) return;
27035
+ if (!review.page?.overview) {
27036
+ setError("官方待审列表尚未就绪,未执行批量操作");
27037
+ return;
27038
+ }
27039
+ setReviewAllPrompt({
27040
+ reject,
27041
+ count: sum.pendingFiles.length,
27042
+ token: reviewLifeRef.current
27043
+ });
27044
+ }
27045
+ /** @private @author ddj 2026年10月27号 @description Dismiss the pending confirmation without changing review state. */
27046
+ function cancelReviewAll() {
27047
+ setReviewAllPrompt(null);
27048
+ }
27049
+ /** @private @author ddj 2026年10月27号 @description Confirm only within the session lifetime that opened the modal. @returns The guarded batch operation, if still valid. */
27050
+ function confirmReviewAll() {
27051
+ const prompt = reviewAllPrompt;
27052
+ setReviewAllPrompt(null);
27053
+ if (!prompt?.token?.live || prompt.token !== reviewLifeRef.current) return;
27054
+ return actReviewAll(prompt.reject);
27055
+ }
27056
+ const acceptAllFiles = () => askReviewAll(false);
27057
+ const undoAllFiles = () => askReviewAll(true);
27006
27058
  const rollbackFile = () => {
27007
27059
  if (!active) return;
27008
27060
  if (!window.confirm("回滚当前文件到修改前状态?(相关差异将归档)")) return;
@@ -29090,7 +29142,7 @@ window.__ModuleLoader__.load({
29090
29142
  }))
29091
29143
  }) : null;
29092
29144
  const dapBpEditEl = null;
29093
- return layout === "side" ? react.default.createElement("div", {
29145
+ const rootEl = layout === "side" ? react.default.createElement("div", {
29094
29146
  ref: viewRootRef,
29095
29147
  "data-edrv-view": "1",
29096
29148
  "data-edrv-layout": "side",
@@ -29104,6 +29156,13 @@ window.__ModuleLoader__.load({
29104
29156
  maxHeight: "var(--edrv-editor-height, 100%)"
29105
29157
  })
29106
29158
  }, editorRow, tabMenuEl, paletteEl, svnLogEl, svnUpdateEl, svnDiffEl, patchDialogEl, sumDialogEl, dlogEl, snippetPickerEl, dapBpMenuEl, dapBpEditEl);
29159
+ const reviewAllEl = reviewAllPrompt?.token?.live && reviewAllPrompt.token === reviewLifeRef.current ? react.default.createElement(ReviewAllConfirm, {
29160
+ reject: reviewAllPrompt.reject,
29161
+ count: reviewAllPrompt.count,
29162
+ onCancel: cancelReviewAll,
29163
+ onConfirm: confirmReviewAll
29164
+ }) : null;
29165
+ return react.default.createElement(react.default.Fragment, null, rootEl, reviewAllEl);
29107
29166
  }
29108
29167
  //#endregion
29109
29168
  //#region src/client/ui/DiffBadge.ts
@@ -32473,8 +32532,6 @@ window.__ModuleLoader__.load({
32473
32532
  //#endregion
32474
32533
  //#region src/client/mcpSessionState.ts
32475
32534
  /** Shared, read-only sidebar MCP polling. @author ddj 2026年10月20号 */
32476
- const unavailable = { stale: true };
32477
- const inactive = { stale: false };
32478
32535
  /** One poller for all mounted row/hover consumers; never retains or activates sessions. */
32479
32536
  var McpSessionState = class {
32480
32537
  fetchStatus;
@@ -32484,7 +32541,10 @@ window.__ModuleLoader__.load({
32484
32541
  timer;
32485
32542
  request;
32486
32543
  epoch = 0;
32487
- stale = true;
32544
+ fallback = {
32545
+ stale: true,
32546
+ reason: "pending"
32547
+ };
32488
32548
  disposed = false;
32489
32549
  /** @public @author ddj 2026年10月20号 @param fetchStatus Authenticated read-only query. @param page Visibility boundary, omitted for server tests. */
32490
32550
  constructor(fetchStatus, page) {
@@ -32493,7 +32553,7 @@ window.__ModuleLoader__.load({
32493
32553
  }
32494
32554
  /** @public @author ddj 2026年10月20号 @param sessionId Row identity. @returns Stable view until the next observation. */
32495
32555
  get(sessionId) {
32496
- return this.views.get(sessionId) ?? (this.stale ? unavailable : inactive);
32556
+ return this.views.get(sessionId) ?? this.fallback;
32497
32557
  }
32498
32558
  /** @public @author ddj 2026年10月20号 @param sessionId Row identity. @param listener React invalidation. @returns Idempotent unsubscribe; the last consumer stops polling. */
32499
32559
  subscribe(sessionId, listener) {
@@ -32504,7 +32564,8 @@ window.__ModuleLoader__.load({
32504
32564
  this.listeners.set(sessionId, listeners);
32505
32565
  if (first) {
32506
32566
  this.page?.addEventListener("visibilitychange", this.visibility);
32507
- this.poll();
32567
+ if (this.page?.hidden) this.markStale("paused");
32568
+ else this.poll();
32508
32569
  }
32509
32570
  return () => {
32510
32571
  listeners.delete(listener);
@@ -32523,7 +32584,7 @@ window.__ModuleLoader__.load({
32523
32584
  clearTimeout(this.timer);
32524
32585
  this.timer = void 0;
32525
32586
  this.request?.abort();
32526
- this.publish(void 0);
32587
+ this.markStale("paused");
32527
32588
  }
32528
32589
  /** @private @author ddj 2026年10月20号 Cleans listener lifetime as well as timers. */
32529
32590
  pause() {
@@ -32537,42 +32598,68 @@ window.__ModuleLoader__.load({
32537
32598
  this.listeners.clear();
32538
32599
  this.views.clear();
32539
32600
  }
32540
- /** @private @author ddj 2026年10月20号 @param snapshot Fresh ledger, or undefined to mark all previous observations stale. */
32601
+ /** @private @author ddj 2026年10月27号 @param snapshot Fresh ledger. Records browser receipt time without changing the host protocol. */
32541
32602
  publish(snapshot) {
32542
- this.stale = snapshot === void 0;
32543
- if (snapshot) this.views = new Map(snapshot.sessions.map((status) => [status.sessionId, {
32603
+ const observedAt = Date.now();
32604
+ this.fallback = {
32605
+ stale: false,
32606
+ observedAt
32607
+ };
32608
+ this.views = new Map(snapshot.sessions.map((status) => [status.sessionId, {
32544
32609
  status,
32545
- stale: false
32610
+ stale: false,
32611
+ observedAt
32546
32612
  }]));
32547
- else for (const [id, view] of this.views) this.views.set(id, {
32613
+ this.notify();
32614
+ }
32615
+ /** @private @author ddj 2026年10月27号 @param reason Query lifecycle, never a claim about connection health. Preserves stable references for unchanged observations. */
32616
+ markStale(reason) {
32617
+ if (this.fallback.stale && this.fallback.reason === reason) return;
32618
+ this.fallback = {
32619
+ ...this.fallback,
32620
+ stale: true,
32621
+ reason
32622
+ };
32623
+ for (const [id, view] of this.views) this.views.set(id, {
32548
32624
  ...view,
32549
- stale: true
32625
+ stale: true,
32626
+ reason
32550
32627
  });
32628
+ this.notify();
32629
+ }
32630
+ /** @private @author ddj 2026年10月27号 Notifies mounted row and hover consumers after an observation changes. */
32631
+ notify() {
32551
32632
  for (const listeners of this.listeners.values()) for (const listener of listeners) listener();
32552
32633
  }
32553
32634
  /** @private @author ddj 2026年10月20号 Queries once, with a 10-second deadline and a 2.5-second gap after settlement. */
32554
32635
  async poll() {
32555
32636
  if (this.disposed || this.request || !this.listeners.size || this.page?.hidden) return;
32637
+ clearTimeout(this.timer);
32638
+ this.timer = void 0;
32639
+ if (this.fallback.reason === "paused") this.markStale("pending");
32556
32640
  const request = new AbortController();
32557
32641
  const epoch = this.epoch;
32558
32642
  this.request = request;
32559
32643
  /** @author ddj 2026年10月20号 Marks overdue responses unusable even if a transport ignores cancellation. */
32560
32644
  const expire = () => {
32561
32645
  request.abort();
32562
- if (epoch === this.epoch) this.publish(void 0);
32646
+ if (epoch === this.epoch) this.markStale("unavailable");
32563
32647
  };
32564
32648
  const deadline = setTimeout(expire, 1e4);
32565
32649
  try {
32566
32650
  const snapshot = await this.fetchStatus(request.signal);
32567
32651
  if (epoch === this.epoch && !request.signal.aborted) this.publish(snapshot);
32568
32652
  } catch {
32569
- if (epoch === this.epoch) this.publish(void 0);
32653
+ if (epoch === this.epoch) this.markStale("unavailable");
32570
32654
  } finally {
32571
32655
  clearTimeout(deadline);
32572
32656
  this.request = void 0;
32573
- if (!this.disposed && this.listeners.size && !this.page?.hidden) this.timer = setTimeout(() => {
32574
- this.poll();
32575
- }, 2500);
32657
+ if (!this.disposed && this.listeners.size && !this.page?.hidden) {
32658
+ const delay = epoch === this.epoch ? 2500 : 0;
32659
+ this.timer = setTimeout(() => {
32660
+ this.poll();
32661
+ }, delay);
32662
+ }
32576
32663
  }
32577
32664
  }
32578
32665
  };
@@ -32615,7 +32702,7 @@ window.__ModuleLoader__.load({
32615
32702
  }
32616
32703
  /** @public @author ddj 2026年10月20号 @param view Current observation. @returns Accessible row label; steady states deliberately do not occupy the leading slot. */
32617
32704
  function mcpRowLabel(view) {
32618
- if (view.stale) return "项目 MCP 状态暂不可用(上次状态已过期)";
32705
+ if (view.stale) return void 0;
32619
32706
  if (!view.status || !busy.has(view.status.phase) && view.status.phase !== "error") return void 0;
32620
32707
  return "项目 MCP:" + labels[view.status.phase];
32621
32708
  }
@@ -32624,7 +32711,7 @@ window.__ModuleLoader__.load({
32624
32711
  const view = useMcpView(props);
32625
32712
  const label = mcpRowLabel(view);
32626
32713
  if (!label) return null;
32627
- const warning = view.stale || view.status?.phase === "error";
32714
+ const warning = view.status?.phase === "error";
32628
32715
  return react.default.createElement("span", {
32629
32716
  role: "img",
32630
32717
  "aria-label": label,
@@ -32644,6 +32731,12 @@ window.__ModuleLoader__.load({
32644
32731
  function elapsed(start, end) {
32645
32732
  return Math.max(0, (end - start) / 1e3).toFixed(1) + " 秒";
32646
32733
  }
32734
+ /** @private @author ddj 2026年10月27号 @param view Query observation. @returns Query-only explanation, separate from initialization health. */
32735
+ function queryMessage(view) {
32736
+ if (view.reason === "paused") return "状态查询已暂停";
32737
+ if (view.reason === "pending") return "正在查询项目 MCP 状态";
32738
+ return "状态查询暂不可用,不代表 MCP 初始化失败";
32739
+ }
32647
32740
  /** @public @author ddj 2026年10月20号 @param props Official hover sessionId and poller. @returns Project-only diagnostic detail, never transport credentials. */
32648
32741
  function McpSessionDetail(props) {
32649
32742
  const view = useMcpView(props);
@@ -32655,20 +32748,26 @@ window.__ModuleLoader__.load({
32655
32748
  return () => clearInterval(tick);
32656
32749
  }, [status, view.stale]);
32657
32750
  const children = [react.default.createElement("strong", { key: "title" }, "项目 MCP")];
32658
- if (view.stale) children.push(react.default.createElement("div", {
32659
- key: "stale",
32660
- role: "status"
32661
- }, "状态暂不可用;以下如有记录,为上次观测结果"));
32662
- if (!status) children.push(react.default.createElement("div", { key: "empty" }, view.stale ? "等待状态查询" : "当前无活跃 MCP 实例"));
32663
- else {
32664
- const end = status.finishedAt ?? now;
32751
+ if (view.stale) {
32752
+ children.push(react.default.createElement("div", {
32753
+ key: "stale",
32754
+ role: "status"
32755
+ }, queryMessage(view)));
32756
+ if (status) children.push(react.default.createElement("div", { key: "history" }, "以下为上次观测结果,不代表当前状态"));
32757
+ if (view.observedAt !== void 0) children.push(react.default.createElement("div", { key: "observed" }, "上次观测时间:" + new Date(view.observedAt).toLocaleString()));
32758
+ }
32759
+ if (!status && !view.stale) children.push(react.default.createElement("div", { key: "empty" }, "当前无活跃 MCP 实例"));
32760
+ if (status) {
32761
+ let observedNow = now;
32762
+ if (view.stale) observedNow = view.observedAt ?? status.phaseAt;
32763
+ const end = status.finishedAt ?? observedNow;
32665
32764
  const completed = status.servers.filter((server) => server.phase === "ready").length;
32666
32765
  const slow = !view.stale && busy.has(status.phase) && now - status.phaseAt > 1e4;
32667
32766
  children.push(react.default.createElement("div", { key: "phase" }, labels[status.phase], slow ? "(耗时较长,不代表失败)" : ""));
32668
32767
  children.push(react.default.createElement("div", { key: "time" }, `${completed}/${status.servers.length} 已初始化 · 总耗时 ${elapsed(status.startedAt, end)} · 当前阶段 ${elapsed(status.phaseAt, end)}`));
32669
32768
  if (status.configMs !== void 0) children.push(react.default.createElement("div", { key: "config" }, `配置准备 ${elapsed(0, status.configMs)}`));
32670
32769
  if (status.error) children.push(react.default.createElement("div", { key: "error" }, status.error));
32671
- for (const server of status.servers) children.push(react.default.createElement("div", { key: "server:" + server.serverName }, `${server.serverName}:${labels[server.phase]}${server.reused ? " · 复用已有连接" : ""}${server.phase === "idle" ? "" : " · " + elapsed(server.startedAt, server.finishedAt ?? now)}`, server.queuedMs === void 0 ? "" : " · 排队 " + elapsed(0, server.queuedMs), server.connectMs === void 0 ? "" : " · 初始化 " + elapsed(0, server.connectMs), server.firstCallMs === void 0 ? "" : " · 首次工具执行 " + elapsed(0, server.firstCallMs), server.error ? " · " + server.error : ""));
32770
+ for (const server of status.servers) children.push(react.default.createElement("div", { key: "server:" + server.serverName }, `${server.serverName}:${labels[server.phase]}${server.reused ? " · 复用已有连接" : ""}${server.phase === "idle" ? "" : " · " + elapsed(server.startedAt, server.finishedAt ?? observedNow)}`, server.queuedMs === void 0 ? "" : " · 排队 " + elapsed(0, server.queuedMs), server.connectMs === void 0 ? "" : " · 初始化 " + elapsed(0, server.connectMs), server.firstCallMs === void 0 ? "" : " · 首次工具执行 " + elapsed(0, server.firstCallMs), server.error ? " · " + server.error : ""));
32672
32771
  }
32673
32772
  children.push(react.default.createElement("small", { key: "scope" }, "仅 VSCodeMode 管理的项目 MCP;不含全局或 preset MCP。"));
32674
32773
  return react.default.createElement("section", {