@srgay/cursor-extension 1.0.2 → 1.0.4
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 +1 -1
- package/package.json +1 -1
- package/src/mcp-followup/cursor-mcp-followup.js +37 -12
package/README.md
CHANGED
|
@@ -178,7 +178,7 @@ window.__cursorMcpFollowup.uninstall() // 卸载面板
|
|
|
178
178
|
|
|
179
179
|
- `scanStart` / `scanCount`:扫描起始端口与数量(默认从 `8765` 起、共 `5` 个,即 `8765–8769`)。
|
|
180
180
|
- `probeTimeoutMs`:单端口探测超时(默认 `2500` ms;含一次 `run_command` 读取窗口工作区的往返)。
|
|
181
|
-
- `reconnectMs
|
|
181
|
+
- `reconnectMs`:WebSocket 存活探测间隔(默认 `8000` ms;不做周期性重连)。
|
|
182
182
|
|
|
183
183
|
### 排障
|
|
184
184
|
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
styleId: "cursor-mcp-followup-style",
|
|
10
10
|
panelId: "cursor-mcp-followup-panel",
|
|
11
11
|
mountScanMs: 600,
|
|
12
|
-
reconnectMs:
|
|
12
|
+
reconnectMs: 8000,
|
|
13
13
|
scanStart: 8765,
|
|
14
14
|
scanCount: 5,
|
|
15
15
|
probeTimeoutMs: 2500,
|
|
@@ -391,6 +391,18 @@
|
|
|
391
391
|
refreshOptionLabels();
|
|
392
392
|
}
|
|
393
393
|
|
|
394
|
+
// 确保隐藏 select(数据载体)里存在某端口的 option。自定义浮层用 foundPorts 渲染,
|
|
395
|
+
// 但隐藏 select 只在全量扫描时重填;按需扫描新发现的端口必须补进来,否则给原生
|
|
396
|
+
// <select> 设一个不存在的 value 会被静默置空 → 连空端口 offline。
|
|
397
|
+
function ensurePortOption(value) {
|
|
398
|
+
if (!els.portSelect) return;
|
|
399
|
+
const v = String(value);
|
|
400
|
+
const opts = Array.from(els.portSelect.options);
|
|
401
|
+
if (opts.some((o) => o.value === v)) return;
|
|
402
|
+
const custom = opts.find((o) => o.value === config.customValue);
|
|
403
|
+
els.portSelect.insertBefore(h("option", { value: v }), custom || null);
|
|
404
|
+
}
|
|
405
|
+
|
|
394
406
|
function makeScanIcon() {
|
|
395
407
|
const svg = svgEl("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true" });
|
|
396
408
|
svg.appendChild(svgEl("circle", { cx: "11", cy: "11", r: "6", stroke: "currentColor", "stroke-width": "2" }));
|
|
@@ -828,7 +840,11 @@
|
|
|
828
840
|
|
|
829
841
|
// 点选某端口:写回隐藏 select 的 value,关菜单,刷新按钮,再走既有连接逻辑(onPortChange)。
|
|
830
842
|
function selectPort(port) {
|
|
831
|
-
|
|
843
|
+
const v = String(port);
|
|
844
|
+
// 关键:浮层从 foundPorts 渲染,可能领先于隐藏 select 的 options;先补齐再赋值,
|
|
845
|
+
// 否则原生 <select> 对不存在的 value 会静默置空,导致连空端口 → offline。
|
|
846
|
+
ensurePortOption(v);
|
|
847
|
+
els.portSelect.value = v;
|
|
832
848
|
closePortMenu();
|
|
833
849
|
updatePortButton();
|
|
834
850
|
onPortChange();
|
|
@@ -1575,8 +1591,9 @@
|
|
|
1575
1591
|
: "扫描完成:" + from + "–" + to + " 未发现活跃 MCP 端口。";
|
|
1576
1592
|
|
|
1577
1593
|
if (refreshOnly) {
|
|
1578
|
-
//
|
|
1579
|
-
//
|
|
1594
|
+
// 自定义下拉:先把本次扫到的端口补进隐藏 select(数据载体),保证点选时 value 设得上;
|
|
1595
|
+
// 菜单仍展开则用最新结果渲染浮层(渲染后保持稳定,点选即时生效、无打断、无闪)。
|
|
1596
|
+
found.forEach((p) => ensurePortOption(String(p)));
|
|
1580
1597
|
if (state.expanded) renderPortMenu();
|
|
1581
1598
|
return;
|
|
1582
1599
|
}
|
|
@@ -1731,18 +1748,16 @@
|
|
|
1731
1748
|
}
|
|
1732
1749
|
}
|
|
1733
1750
|
|
|
1734
|
-
//
|
|
1735
|
-
//
|
|
1736
|
-
// 定期重连以抢占活跃连接并同步当前会话;仅在用户正在输入时不打断(输入期间一般无其他端抢占)。
|
|
1751
|
+
// 定期探测当前 WebSocket 是否仍存活。这里不主动重连,避免周期性关闭/新建连接扰动
|
|
1752
|
+
// Cursor renderer 和 MCP 服务端的「最后连接」状态;重连只在启动、手动切端口、聚焦输入框或发送前触发。
|
|
1737
1753
|
function refreshTick() {
|
|
1738
1754
|
if (state.scanning) return;
|
|
1739
1755
|
if (els.portSelect.value === config.customValue) return;
|
|
1740
1756
|
if (els.customInput === document.activeElement) return;
|
|
1741
1757
|
if (els.prompt === document.activeElement && els.prompt.value.trim()) return;
|
|
1742
1758
|
|
|
1743
|
-
//
|
|
1744
|
-
//
|
|
1745
|
-
// 端口已关时 onerror 会清归属并置 offline,等待用户展开下拉重新选择本窗口端口)。
|
|
1759
|
+
// 不做后台扫描(扫描仅发生在启动时与下拉展开期间),也不做周期性重连。
|
|
1760
|
+
// OPEN → 发 heartbeat 探活;CONNECTING → 等待;其它状态 → 标记离线,等待用户操作触发连接。
|
|
1746
1761
|
if (
|
|
1747
1762
|
state.socket &&
|
|
1748
1763
|
state.socket.readyState === WebSocket.OPEN &&
|
|
@@ -1751,12 +1766,22 @@
|
|
|
1751
1766
|
try {
|
|
1752
1767
|
state.socket.send(JSON.stringify({ type: "heartbeat", timestamp: Date.now() }));
|
|
1753
1768
|
} catch (error) {
|
|
1754
|
-
|
|
1769
|
+
setOptionLabel(els.portSelect.value, "offline");
|
|
1770
|
+
setVisualState("offline", els.portSelect.value + " WebSocket heartbeat 发送失败。");
|
|
1755
1771
|
}
|
|
1756
1772
|
return;
|
|
1757
1773
|
}
|
|
1758
1774
|
|
|
1759
|
-
|
|
1775
|
+
if (
|
|
1776
|
+
state.socket &&
|
|
1777
|
+
state.socket.readyState === WebSocket.CONNECTING &&
|
|
1778
|
+
state.socketPort === els.portSelect.value
|
|
1779
|
+
) {
|
|
1780
|
+
return;
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
setOptionLabel(els.portSelect.value, "offline");
|
|
1784
|
+
setVisualState("offline", els.portSelect.value + " WebSocket 未连接或已断开。");
|
|
1760
1785
|
}
|
|
1761
1786
|
|
|
1762
1787
|
function autoResize() {
|