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 +5 -4
- package/lib/client.js +134 -35
- package/lib/client.js.map +1 -1
- package/package.json +1 -1
- package/src/client/mcpSessionState.ts +42 -15
- package/src/client/ui/EditorView.ts +32 -6
- package/src/client/ui/McpSessionStatus.ts +22 -7
- package/src/client/ui/ReviewAllConfirm.ts +35 -0
- package/src/client-primitives.d.ts +12 -0
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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$
|
|
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$
|
|
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
|
-
|
|
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
|
-
|
|
27005
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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) ??
|
|
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.
|
|
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.
|
|
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月
|
|
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
|
-
|
|
32543
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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)
|
|
32574
|
-
this.
|
|
32575
|
-
|
|
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
|
|
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.
|
|
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)
|
|
32659
|
-
|
|
32660
|
-
|
|
32661
|
-
|
|
32662
|
-
|
|
32663
|
-
|
|
32664
|
-
|
|
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 ??
|
|
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", {
|