@wenbin_wb/dsh-bridge 2.2.5 → 2.2.6
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/client/client.js +244 -67
- package/client/index.js +222 -64
- package/lib/bridge-rpc-constants.js +1 -0
- package/lib/bridge-rpc.js +5 -0
- package/lib/index.js +49 -8
- package/package.json +1 -1
package/client/client.js
CHANGED
|
@@ -42,6 +42,7 @@ var BRIDGE_ENDPOINTS = {
|
|
|
42
42
|
resetCloudflared: "resetCloudflared",
|
|
43
43
|
saveCustomTunnelConfig: "saveCustomTunnelConfig",
|
|
44
44
|
checkVersion: "checkVersion",
|
|
45
|
+
upgradePlugin: "upgradePlugin",
|
|
45
46
|
// 平台管理器(多 IM 平台统一接口)
|
|
46
47
|
listPlatforms: "listPlatforms",
|
|
47
48
|
platformLogin: "platformLogin",
|
|
@@ -103,6 +104,59 @@ var s = {
|
|
|
103
104
|
warn: { background: "var(--dsw-alias-state-warn-bg,#fffbeb)", border: "1px solid var(--dsw-alias-state-warn-border,#fde68a)", borderRadius: 8, padding: "10px 14px", fontSize: 12, color: "var(--dsw-alias-state-warn-primary,#92400e)", lineHeight: 1.6 },
|
|
104
105
|
tip: { background: "var(--dsw-alias-bg-layer-2,#f9fafb)", borderRadius: 8, padding: "10px 14px", fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)", lineHeight: 1.6 }
|
|
105
106
|
};
|
|
107
|
+
var Icons = {
|
|
108
|
+
wechat: (props) => React.createElement(
|
|
109
|
+
"svg",
|
|
110
|
+
{ viewBox: "0 0 24 24", width: 18, height: 18, fill: "currentColor", ...props },
|
|
111
|
+
React.createElement("path", { d: "M8.5 2C4.36 2 1 4.91 1 8.5c0 2.01 1.05 3.81 2.69 4.97l-.69 2.06 2.45-1.22c.94.43 1.98.69 3.05.69.21 0 .42-.01.62-.03-.23-.62-.37-1.28-.37-1.97 0-3.59 3.36-6.5 7.5-6.5.21 0 .41.01.62.03C15.87 4.54 12.44 2 8.5 2zM6 6.5a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5zm5 0a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5zm7.5 3.5c-3.59 0-6.5 2.46-6.5 5.5 0 1.66.86 3.14 2.21 4.1l-.56 1.69 2.01-1c.78.36 1.64.57 2.54.57 3.59 0 6.5-2.46 6.5-5.5s-2.91-5.5-6.5-5.5zm-2 4a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm4 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2z" })
|
|
112
|
+
),
|
|
113
|
+
qq: (props) => React.createElement(
|
|
114
|
+
"svg",
|
|
115
|
+
{ viewBox: "0 0 24 24", width: 18, height: 18, fill: "currentColor", ...props },
|
|
116
|
+
React.createElement("path", { d: "M12 2C7.58 2 4 5.37 4 9.53c0 1.95.78 3.73 2.07 5.07-.37 1.15-.99 2.19-1.8 3.08-.18.2-.04.52.23.52 2.22 0 3.99-1.07 4.9-1.86.8.25 1.66.39 2.6.39 4.42 0 8-3.37 8-7.53S16.42 2 12 2zm-3 8a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5zm6 0a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5z" })
|
|
117
|
+
),
|
|
118
|
+
feishu: (props) => React.createElement(
|
|
119
|
+
"svg",
|
|
120
|
+
{ viewBox: "0 0 24 24", width: 18, height: 18, fill: "currentColor", ...props },
|
|
121
|
+
React.createElement("path", { d: "M12 2.5L3.5 11.2l6.8 1.8 2.2 6.5 1.8-4.7 5.2-1.4L12 2.5zm-.8 11.1l-4.1-1.1 6.5-6.6-4.2 8.3 1.8-.6z" })
|
|
122
|
+
),
|
|
123
|
+
telegram: (props) => React.createElement(
|
|
124
|
+
"svg",
|
|
125
|
+
{ viewBox: "0 0 24 24", width: 18, height: 18, fill: "currentColor", ...props },
|
|
126
|
+
React.createElement("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19-.14.75-.42 1-.68 1.03-.58.05-1.02-.38-1.58-.75-.88-.58-1.38-.94-2.23-1.5-.99-.65-.35-1.01.22-1.59.15-.15 2.71-2.48 2.76-2.69a.2.2 0 0 0-.05-.18c-.06-.05-.14-.03-.21-.02-.09.02-1.49.95-4.22 2.79-.4.27-.76.41-1.08.4-.36-.01-1.04-.2-1.55-.37-.63-.2-1.12-.31-1.08-.66.02-.18.27-.36.74-.55 2.92-1.27 4.86-2.11 5.83-2.51 2.78-1.16 3.35-1.36 3.73-1.36.08 0 .27.02.39.12.1.08.13.19.14.27-.01.06.01.24 0 .38z" })
|
|
127
|
+
),
|
|
128
|
+
lan: (props) => React.createElement(
|
|
129
|
+
"svg",
|
|
130
|
+
{ viewBox: "0 0 24 24", width: 16, height: 16, fill: "currentColor", ...props },
|
|
131
|
+
React.createElement("path", { d: "M12 3c-4.97 0-9 4.03-9 9 0 2.12.74 4.07 1.97 5.61L4.29 19.3a1 1 0 0 0 1.41 1.41l1.7-1.7C9.02 19.64 10.46 20 12 20c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 15c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6zm0-9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z" })
|
|
132
|
+
),
|
|
133
|
+
tunnel: (props) => React.createElement(
|
|
134
|
+
"svg",
|
|
135
|
+
{ viewBox: "0 0 24 24", width: 16, height: 16, fill: "currentColor", ...props },
|
|
136
|
+
React.createElement("path", { d: "M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM19 18H6c-2.21 0-4-1.79-4-4 0-2.05 1.53-3.76 3.56-3.97l1.07-.11.5-.95C8.08 7.14 9.94 6 12 6c2.62 0 4.88 1.86 5.39 4.43l.3 1.5 1.53.11c1.56.1 2.78 1.41 2.78 2.96 0 1.65-1.35 3-3 3z" })
|
|
137
|
+
),
|
|
138
|
+
bot: (props) => React.createElement(
|
|
139
|
+
"svg",
|
|
140
|
+
{ viewBox: "0 0 24 24", width: 16, height: 16, fill: "currentColor", ...props },
|
|
141
|
+
React.createElement("path", { d: "M20 9V7c0-1.1-.9-2-2-2h-3c0-1.66-1.34-3-3-3S9 3.34 9 5H6c-1.1 0-2 .9-2 2v2c-1.66 0-3 1.34-3 3s1.34 3 3 3v4c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-4c1.66 0 3-1.34 3-3s-1.34-3-3-3zm-2 10H6V7h12v12zm-9-6c-.83 0-1.5-.67-1.5-1.5S8.17 10 9 10s1.5.67 1.5 1.5S9.83 13 9 13zm6 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" })
|
|
142
|
+
),
|
|
143
|
+
github: (props) => React.createElement(
|
|
144
|
+
"svg",
|
|
145
|
+
{ viewBox: "0 0 24 24", width: 13, height: 13, fill: "currentColor", ...props },
|
|
146
|
+
React.createElement("path", { d: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.53 1.032 1.53 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" })
|
|
147
|
+
),
|
|
148
|
+
refresh: (props) => React.createElement(
|
|
149
|
+
"svg",
|
|
150
|
+
{ viewBox: "0 0 24 24", width: 12, height: 12, fill: "none", stroke: "currentColor", strokeWidth: 2.2, strokeLinecap: "round", strokeLinejoin: "round", ...props },
|
|
151
|
+
React.createElement("path", { d: "M23 4v6h-6M1 20v-6h6" }),
|
|
152
|
+
React.createElement("path", { d: "M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" })
|
|
153
|
+
),
|
|
154
|
+
check: (props) => React.createElement(
|
|
155
|
+
"svg",
|
|
156
|
+
{ viewBox: "0 0 24 24", width: 12, height: 12, fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", ...props },
|
|
157
|
+
React.createElement("polyline", { points: "20 6 9 17 4 12" })
|
|
158
|
+
)
|
|
159
|
+
};
|
|
106
160
|
function useCopy() {
|
|
107
161
|
const [copied, setCopied] = React.useState(false);
|
|
108
162
|
const copy = React.useCallback((text) => {
|
|
@@ -472,7 +526,15 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
|
|
|
472
526
|
React.createElement(
|
|
473
527
|
"div",
|
|
474
528
|
null,
|
|
475
|
-
React.createElement(
|
|
529
|
+
React.createElement(
|
|
530
|
+
"div",
|
|
531
|
+
{ style: { ...s.label, display: "flex", alignItems: "center", gap: 7 } },
|
|
532
|
+
platformId === "wechat" && React.createElement(Icons.wechat, { style: { color: "#07C160", width: 20, height: 20 } }),
|
|
533
|
+
platformId === "qq" && React.createElement(Icons.qq, { style: { color: "#12B7F5", width: 20, height: 20 } }),
|
|
534
|
+
platformId === "feishu" && React.createElement(Icons.feishu, { style: { color: "#00D6B9", width: 20, height: 20 } }),
|
|
535
|
+
platformId === "telegram" && React.createElement(Icons.telegram, { style: { color: "#24A1DE", width: 20, height: 20 } }),
|
|
536
|
+
platformName
|
|
537
|
+
),
|
|
476
538
|
React.createElement("div", { style: { ...s.muted, marginTop: 2 } }, platformDesc)
|
|
477
539
|
),
|
|
478
540
|
React.createElement(StatusTag, { status: platform?.status, running: connected })
|
|
@@ -887,7 +949,11 @@ function UpgradeCommandRow({ cmd }) {
|
|
|
887
949
|
color: "var(--dsw-alias-label-secondary,#6b7280)",
|
|
888
950
|
flex: 1,
|
|
889
951
|
minWidth: 0,
|
|
890
|
-
wordBreak: "break-all"
|
|
952
|
+
wordBreak: "break-all",
|
|
953
|
+
background: "var(--dsw-alias-bg-layer-1,#ffffff)",
|
|
954
|
+
padding: "4px 8px",
|
|
955
|
+
borderRadius: 6,
|
|
956
|
+
border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)"
|
|
891
957
|
}
|
|
892
958
|
}, cmd),
|
|
893
959
|
React.createElement("button", {
|
|
@@ -900,6 +966,9 @@ function UpgradeCommandRow({ cmd }) {
|
|
|
900
966
|
function VersionBanner({ rpcCall }) {
|
|
901
967
|
const [info, setInfo] = React.useState(null);
|
|
902
968
|
const [loading, setLoading] = React.useState(false);
|
|
969
|
+
const [upgrading, setUpgrading] = React.useState(false);
|
|
970
|
+
const [upgradeResult, setUpgradeResult] = React.useState(null);
|
|
971
|
+
const [showManual, setShowManual] = React.useState(false);
|
|
903
972
|
const check = React.useCallback(async () => {
|
|
904
973
|
setLoading(true);
|
|
905
974
|
try {
|
|
@@ -913,6 +982,27 @@ function VersionBanner({ rpcCall }) {
|
|
|
913
982
|
check();
|
|
914
983
|
}, [check]);
|
|
915
984
|
const hasUpdate = info?.latest && info?.current && !info.error && semverGt(info.latest, info.current);
|
|
985
|
+
const isLatest = info?.latest && info?.current && !info.error && !semverGt(info.latest, info.current);
|
|
986
|
+
const handleUpgrade = React.useCallback(async () => {
|
|
987
|
+
if (!info?.latest || upgrading) return;
|
|
988
|
+
setUpgrading(true);
|
|
989
|
+
setUpgradeResult(null);
|
|
990
|
+
try {
|
|
991
|
+
const r = await rpcCall(BRIDGE_ENDPOINTS.upgradePlugin, { version: info.latest });
|
|
992
|
+
if (r?.ok && r.value?.ok) {
|
|
993
|
+
setUpgradeResult({ ok: true, message: `\u5DF2\u6210\u529F\u5347\u7EA7\u5230 v${info.latest}\uFF01\u8BF7\u91CD\u542F DSH \u670D\u52A1\u4F7F\u65B0\u7248\u672C\u751F\u6548\u3002` });
|
|
994
|
+
setTimeout(() => check(), 3e3);
|
|
995
|
+
} else {
|
|
996
|
+
setUpgradeResult({ ok: false, message: r?.value?.error || r?.error?.message || "\u5347\u7EA7\u5931\u8D25" });
|
|
997
|
+
setShowManual(true);
|
|
998
|
+
}
|
|
999
|
+
} catch (e) {
|
|
1000
|
+
setUpgradeResult({ ok: false, message: e.message || "\u5347\u7EA7\u8BF7\u6C42\u5931\u8D25" });
|
|
1001
|
+
setShowManual(true);
|
|
1002
|
+
} finally {
|
|
1003
|
+
setUpgrading(false);
|
|
1004
|
+
}
|
|
1005
|
+
}, [info?.latest, upgrading, rpcCall, check]);
|
|
916
1006
|
const links = React.createElement(
|
|
917
1007
|
"div",
|
|
918
1008
|
{ style: { display: "flex", gap: 12, alignItems: "center", flexWrap: "wrap" } },
|
|
@@ -921,95 +1011,174 @@ function VersionBanner({ rpcCall }) {
|
|
|
921
1011
|
target: "_blank",
|
|
922
1012
|
rel: "noreferrer",
|
|
923
1013
|
style: s.btnLink
|
|
924
|
-
}, "
|
|
1014
|
+
}, React.createElement(Icons.github), "GitHub"),
|
|
925
1015
|
React.createElement("a", {
|
|
926
1016
|
href: RELEASES_URL,
|
|
927
1017
|
target: "_blank",
|
|
928
1018
|
rel: "noreferrer",
|
|
929
1019
|
style: s.btnLink
|
|
930
|
-
}, "\
|
|
1020
|
+
}, "\u66F4\u65B0\u65E5\u5FD7"),
|
|
931
1021
|
React.createElement("a", {
|
|
932
1022
|
href: ISSUES_URL,
|
|
933
1023
|
target: "_blank",
|
|
934
1024
|
rel: "noreferrer",
|
|
935
1025
|
style: s.btnLink
|
|
936
|
-
}, "\
|
|
1026
|
+
}, "\u53CD\u9988 Issue")
|
|
937
1027
|
);
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1028
|
+
return React.createElement(
|
|
1029
|
+
"div",
|
|
1030
|
+
{ style: { marginBottom: 16 } },
|
|
1031
|
+
// 顶部状态行:版本徽标 + 刷新按钮 + 链接组
|
|
1032
|
+
React.createElement(
|
|
941
1033
|
"div",
|
|
942
|
-
{
|
|
1034
|
+
{
|
|
1035
|
+
style: {
|
|
1036
|
+
display: "flex",
|
|
1037
|
+
alignItems: "center",
|
|
1038
|
+
justifyContent: "space-between",
|
|
1039
|
+
flexWrap: "wrap",
|
|
1040
|
+
gap: 8
|
|
1041
|
+
}
|
|
1042
|
+
},
|
|
943
1043
|
React.createElement(
|
|
944
1044
|
"div",
|
|
945
|
-
{
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1045
|
+
{ style: { display: "flex", alignItems: "center", gap: 8 } },
|
|
1046
|
+
// 版本状态徽标
|
|
1047
|
+
React.createElement(
|
|
1048
|
+
"span",
|
|
1049
|
+
{
|
|
1050
|
+
style: {
|
|
1051
|
+
...s.tag,
|
|
1052
|
+
background: hasUpdate ? "var(--dsw-alias-state-info-bg,#eff6ff)" : isLatest ? "var(--dsw-alias-state-success-bg,#ecfdf5)" : "var(--dsw-alias-bg-layer-2,#f3f4f6)",
|
|
1053
|
+
color: hasUpdate ? "var(--dsw-alias-state-info-primary,#2563eb)" : isLatest ? "var(--dsw-alias-state-success-primary,#059669)" : "var(--dsw-alias-label-secondary,#6b7280)",
|
|
1054
|
+
padding: "3px 10px",
|
|
1055
|
+
fontSize: 12,
|
|
1056
|
+
fontWeight: 500,
|
|
1057
|
+
display: "inline-flex",
|
|
1058
|
+
alignItems: "center",
|
|
1059
|
+
gap: 5
|
|
1060
|
+
}
|
|
1061
|
+
},
|
|
1062
|
+
loading ? React.createElement("span", {
|
|
1063
|
+
style: { display: "inline-flex", alignItems: "center" }
|
|
1064
|
+
}, React.createElement(Icons.refresh)) : isLatest ? React.createElement(Icons.check) : null,
|
|
1065
|
+
info ? `v${info.current}` : "\u7248\u672C\u68C0\u67E5\u4E2D\u2026",
|
|
1066
|
+
isLatest && React.createElement("span", { style: { opacity: 0.85, fontSize: 11, fontWeight: 400 } }, "\xB7 \u5DF2\u662F\u6700\u65B0"),
|
|
1067
|
+
hasUpdate && React.createElement("span", { style: { fontWeight: 600, fontSize: 11 } }, `\u2794 v${info.latest}`),
|
|
1068
|
+
info?.error && React.createElement("span", { style: { color: "var(--dsw-alias-state-warn-primary,#d97706)", fontSize: 11 } }, "(\u7F51\u7EDC\u8D85\u65F6)")
|
|
1069
|
+
),
|
|
1070
|
+
// 刷新检查按钮
|
|
1071
|
+
React.createElement(
|
|
1072
|
+
"button",
|
|
1073
|
+
{
|
|
1074
|
+
style: {
|
|
1075
|
+
...s.btnGhost,
|
|
1076
|
+
height: 24,
|
|
1077
|
+
padding: "0 8px",
|
|
1078
|
+
fontSize: 11,
|
|
1079
|
+
opacity: loading ? 0.5 : 1,
|
|
1080
|
+
gap: 4
|
|
1081
|
+
},
|
|
1082
|
+
onClick: check,
|
|
1083
|
+
disabled: loading || upgrading,
|
|
1084
|
+
title: "\u91CD\u65B0\u68C0\u67E5 npm \u7EBF\u4E0A\u7248\u672C"
|
|
1085
|
+
},
|
|
1086
|
+
React.createElement(Icons.refresh),
|
|
1087
|
+
loading ? "\u68C0\u67E5\u4E2D\u2026" : "\u68C0\u67E5\u66F4\u65B0"
|
|
1088
|
+
)
|
|
1089
|
+
),
|
|
1090
|
+
links
|
|
1091
|
+
),
|
|
1092
|
+
// 发现新版本高亮卡片(支持一键直接升级)
|
|
1093
|
+
hasUpdate && React.createElement(
|
|
1094
|
+
"div",
|
|
1095
|
+
{
|
|
1096
|
+
style: {
|
|
1097
|
+
...s.card,
|
|
1098
|
+
background: "var(--dsw-alias-state-info-bg,#eff6ff)",
|
|
1099
|
+
border: "1px solid var(--dsw-alias-state-info-border,#bfdbfe)",
|
|
1100
|
+
padding: "14px 16px",
|
|
1101
|
+
marginTop: 10,
|
|
1102
|
+
marginBottom: 0
|
|
1103
|
+
}
|
|
1104
|
+
},
|
|
1105
|
+
React.createElement(
|
|
1106
|
+
"div",
|
|
1107
|
+
{ style: { display: "flex", alignItems: "flex-start", gap: 12 } },
|
|
1108
|
+
React.createElement("span", { style: { fontSize: 22 } }, "\u{1F680}"),
|
|
954
1109
|
React.createElement(
|
|
955
1110
|
"div",
|
|
956
|
-
{ style: {
|
|
957
|
-
React.createElement("span", { style: { fontSize: 20 } }, "\u{1F389}"),
|
|
1111
|
+
{ style: { flex: 1, minWidth: 0 } },
|
|
958
1112
|
React.createElement(
|
|
959
1113
|
"div",
|
|
960
|
-
{ style: { flex:
|
|
1114
|
+
{ style: { display: "flex", alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 8, marginBottom: 8 } },
|
|
961
1115
|
React.createElement("div", {
|
|
962
1116
|
style: {
|
|
963
1117
|
fontSize: 13,
|
|
964
1118
|
fontWeight: 600,
|
|
965
|
-
color: "var(--dsw-alias-state-info-primary,#1e40af)"
|
|
966
|
-
marginBottom: 8
|
|
1119
|
+
color: "var(--dsw-alias-state-info-primary,#1e40af)"
|
|
967
1120
|
}
|
|
968
1121
|
}, `\u53D1\u73B0\u65B0\u7248\u672C v${info.latest}\uFF08\u5F53\u524D v${info.current}\uFF09`),
|
|
969
|
-
// 升级命令:dsh plugin 与 npx 两种,均带复制按钮
|
|
970
1122
|
React.createElement(
|
|
971
|
-
"
|
|
972
|
-
{
|
|
973
|
-
|
|
1123
|
+
"button",
|
|
1124
|
+
{
|
|
1125
|
+
style: {
|
|
1126
|
+
...s.btnPri,
|
|
1127
|
+
height: 28,
|
|
1128
|
+
fontSize: 12,
|
|
1129
|
+
padding: "0 14px",
|
|
1130
|
+
background: upgradeResult?.ok ? "var(--dsw-alias-state-success-primary,#059669)" : "var(--dsw-alias-brand-primary,#4f6ef7)",
|
|
1131
|
+
opacity: upgrading ? 0.6 : 1
|
|
1132
|
+
},
|
|
1133
|
+
onClick: handleUpgrade,
|
|
1134
|
+
disabled: upgrading || upgradeResult?.ok
|
|
1135
|
+
},
|
|
1136
|
+
upgrading ? React.createElement(
|
|
1137
|
+
"span",
|
|
1138
|
+
{ style: { display: "inline-flex", alignItems: "center", gap: 6 } },
|
|
1139
|
+
React.createElement("span", { style: { animation: "spin 1s linear infinite", display: "inline-flex" } }, React.createElement(Icons.refresh)),
|
|
1140
|
+
"\u6B63\u5728\u81EA\u52A8\u5347\u7EA7\u2026"
|
|
1141
|
+
) : upgradeResult?.ok ? "\u2713 \u5DF2\u5B8C\u6210\u5347\u7EA7" : `\u4E00\u952E\u5347\u7EA7\u5230 v${info.latest}`
|
|
974
1142
|
)
|
|
975
1143
|
),
|
|
976
|
-
React.createElement("
|
|
1144
|
+
upgradeResult && React.createElement("div", {
|
|
977
1145
|
style: {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1146
|
+
background: upgradeResult.ok ? "var(--dsw-alias-state-success-bg,#ecfdf5)" : "var(--dsw-alias-state-error-bg,#fef2f2)",
|
|
1147
|
+
border: `1px solid ${upgradeResult.ok ? "var(--dsw-alias-state-success-border,#a7f3d0)" : "var(--dsw-alias-state-error-border,#fecaca)"}`,
|
|
1148
|
+
color: upgradeResult.ok ? "var(--dsw-alias-state-success-primary,#065f46)" : "var(--dsw-alias-state-error-primary,#991b1b)",
|
|
1149
|
+
padding: "8px 12px",
|
|
1150
|
+
borderRadius: 6,
|
|
981
1151
|
fontSize: 12,
|
|
982
|
-
|
|
983
|
-
|
|
1152
|
+
marginBottom: 8,
|
|
1153
|
+
lineHeight: 1.5
|
|
1154
|
+
}
|
|
1155
|
+
}, upgradeResult.message),
|
|
1156
|
+
React.createElement(
|
|
1157
|
+
"div",
|
|
1158
|
+
{ style: { marginTop: 4 } },
|
|
1159
|
+
React.createElement("button", {
|
|
1160
|
+
style: { ...s.btnLink, fontSize: 11, color: "var(--dsw-alias-label-secondary,#6b7280)" },
|
|
1161
|
+
onClick: () => setShowManual((v) => !v)
|
|
1162
|
+
}, showManual ? "\u25B4 \u6298\u53E0\u624B\u52A8\u547D\u4EE4\u884C" : "\u25BE \u67E5\u770B\u624B\u52A8\u5347\u7EA7\u547D\u4EE4 (\u5982\u9700)")
|
|
1163
|
+
),
|
|
1164
|
+
showManual && React.createElement(
|
|
1165
|
+
"div",
|
|
1166
|
+
{
|
|
1167
|
+
style: { display: "flex", flexDirection: "column", gap: 6, marginTop: 8 }
|
|
984
1168
|
},
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1169
|
+
upgradeCommands(info.latest).map(
|
|
1170
|
+
({ id, cmd }) => React.createElement(UpgradeCommandRow, { key: id, cmd })
|
|
1171
|
+
)
|
|
1172
|
+
)
|
|
988
1173
|
)
|
|
989
|
-
)
|
|
990
|
-
|
|
991
|
-
);
|
|
992
|
-
}
|
|
993
|
-
return React.createElement(
|
|
994
|
-
"div",
|
|
995
|
-
{ style: { marginBottom: 14, display: "flex", alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 8 } },
|
|
996
|
-
React.createElement(
|
|
997
|
-
"div",
|
|
998
|
-
{ style: { ...s.muted, display: "flex", alignItems: "center", gap: 8 } },
|
|
999
|
-
loading && !info ? React.createElement("span", null, "\u68C0\u67E5\u66F4\u65B0\u4E2D\u2026") : info ? React.createElement("span", null, `v${info.current}${info.latest && !info.error ? " \xB7 \u5DF2\u662F\u6700\u65B0" : info.error ? " \xB7 \u68C0\u67E5\u5931\u8D25" : ""}`) : null,
|
|
1000
|
-
info && React.createElement("button", {
|
|
1001
|
-
style: { ...s.btnGhost, height: 22, padding: "0 8px", fontSize: 11, opacity: loading ? 0.5 : 1 },
|
|
1002
|
-
onClick: check,
|
|
1003
|
-
disabled: loading
|
|
1004
|
-
}, loading ? "\u2026" : "\u91CD\u65B0\u68C0\u67E5")
|
|
1005
|
-
),
|
|
1006
|
-
links
|
|
1174
|
+
)
|
|
1175
|
+
)
|
|
1007
1176
|
);
|
|
1008
1177
|
}
|
|
1009
1178
|
var TABS = [
|
|
1010
|
-
{ id: "lan", label: "\u5C40\u57DF\u7F51", icon:
|
|
1011
|
-
{ id: "tunnel", label: "\u516C\u7F51\u96A7\u9053", icon:
|
|
1012
|
-
{ id: "im", label: "IM \u673A\u5668\u4EBA", icon:
|
|
1179
|
+
{ id: "lan", label: "\u5C40\u57DF\u7F51", icon: Icons.lan },
|
|
1180
|
+
{ id: "tunnel", label: "\u516C\u7F51\u96A7\u9053", icon: Icons.tunnel },
|
|
1181
|
+
{ id: "im", label: "IM \u673A\u5668\u4EBA", icon: Icons.bot }
|
|
1013
1182
|
];
|
|
1014
1183
|
function TabBar({ active, onChange, dots }) {
|
|
1015
1184
|
return React.createElement(
|
|
@@ -1022,7 +1191,7 @@ function TabBar({ active, onChange, dots }) {
|
|
|
1022
1191
|
borderBottom: "1px solid var(--dsw-alias-border-l2,#e5e7eb)"
|
|
1023
1192
|
}
|
|
1024
1193
|
},
|
|
1025
|
-
TABS.map(({ id, label, icon }) => {
|
|
1194
|
+
TABS.map(({ id, label, icon: TabIcon }) => {
|
|
1026
1195
|
const isActive = active === id;
|
|
1027
1196
|
const hasDot = dots?.[id];
|
|
1028
1197
|
return React.createElement(
|
|
@@ -1043,12 +1212,19 @@ function TabBar({ active, onChange, dots }) {
|
|
|
1043
1212
|
marginBottom: -1,
|
|
1044
1213
|
display: "inline-flex",
|
|
1045
1214
|
alignItems: "center",
|
|
1046
|
-
gap:
|
|
1215
|
+
gap: 7,
|
|
1047
1216
|
transition: "color .15s, border-color .15s",
|
|
1048
1217
|
whiteSpace: "nowrap"
|
|
1049
1218
|
}
|
|
1050
1219
|
},
|
|
1051
|
-
React.createElement(
|
|
1220
|
+
TabIcon && React.createElement(TabIcon, {
|
|
1221
|
+
style: {
|
|
1222
|
+
color: isActive ? "var(--dsw-alias-brand-primary,#4f6ef7)" : "var(--dsw-alias-label-tertiary,#9ca3af)",
|
|
1223
|
+
width: 16,
|
|
1224
|
+
height: 16,
|
|
1225
|
+
flexShrink: 0
|
|
1226
|
+
}
|
|
1227
|
+
}),
|
|
1052
1228
|
label,
|
|
1053
1229
|
hasDot && React.createElement("span", {
|
|
1054
1230
|
style: {
|
|
@@ -1187,9 +1363,10 @@ function BridgePanel({ rpcCall }) {
|
|
|
1187
1363
|
);
|
|
1188
1364
|
} else if (activeTab === "im") {
|
|
1189
1365
|
const IM_PLATFORMS = [
|
|
1190
|
-
{ id: "wechat", label: "\u5FAE\u4FE1", icon: "
|
|
1191
|
-
{ id: "qq", label: "QQ", icon: "
|
|
1192
|
-
{ id: "feishu", label: "\u98DE\u4E66", icon: "
|
|
1366
|
+
{ id: "wechat", label: "\u5FAE\u4FE1", icon: Icons.wechat, brandColor: "#07C160", desc: "ClawBot \u626B\u7801\u76F4\u8FDE \xB7 \u65E0\u9700\u516C\u7F51" },
|
|
1367
|
+
{ id: "qq", label: "QQ", icon: Icons.qq, brandColor: "#12B7F5", desc: "\u5B98\u65B9\u673A\u5668\u4EBA \xB7 \u79C1\u804A/\u7FA4\u804A/\u6309\u94AE" },
|
|
1368
|
+
{ id: "feishu", label: "\u98DE\u4E66", icon: Icons.feishu, brandColor: "#00D6B9", desc: "\u5B98\u65B9\u4E8B\u4EF6\u56DE\u8C03 API" },
|
|
1369
|
+
{ id: "telegram", label: "Telegram", icon: Icons.telegram, brandColor: "#24A1DE", desc: "\u5B98\u65B9 Bot API" }
|
|
1193
1370
|
];
|
|
1194
1371
|
tabContent = React.createElement(
|
|
1195
1372
|
"div",
|
|
@@ -1200,7 +1377,7 @@ function BridgePanel({ rpcCall }) {
|
|
|
1200
1377
|
{
|
|
1201
1378
|
style: { display: "flex", gap: 10, marginBottom: 16, flexWrap: "wrap" }
|
|
1202
1379
|
},
|
|
1203
|
-
IM_PLATFORMS.map(({ id, label, icon, desc }) => {
|
|
1380
|
+
IM_PLATFORMS.map(({ id, label, icon: IconComponent, brandColor, desc }) => {
|
|
1204
1381
|
const platformData = platforms?.[id];
|
|
1205
1382
|
const available = !!platformData;
|
|
1206
1383
|
const active = platformData?.status === "connected" || platformData?.status === "starting" || platformData?.status === "reconnecting";
|
|
@@ -1209,7 +1386,7 @@ function BridgePanel({ rpcCall }) {
|
|
|
1209
1386
|
{
|
|
1210
1387
|
key: id,
|
|
1211
1388
|
style: {
|
|
1212
|
-
flex: "1 1
|
|
1389
|
+
flex: "1 1 135px",
|
|
1213
1390
|
border: `1px solid ${selectedPlatform === id ? "var(--dsw-alias-brand-primary,#4f6ef7)" : active ? "var(--dsw-alias-state-success-primary,#10b981)" : "var(--dsw-alias-border-l2,#e5e7eb)"}`,
|
|
1214
1391
|
borderRadius: 10,
|
|
1215
1392
|
padding: "12px 14px",
|
|
@@ -1226,8 +1403,8 @@ function BridgePanel({ rpcCall }) {
|
|
|
1226
1403
|
{ style: { ...s.label, fontSize: 13, display: "flex", alignItems: "center", justifyContent: "space-between" } },
|
|
1227
1404
|
React.createElement(
|
|
1228
1405
|
"span",
|
|
1229
|
-
{ style: { display: "flex", alignItems: "center", gap:
|
|
1230
|
-
React.createElement(
|
|
1406
|
+
{ style: { display: "flex", alignItems: "center", gap: 7 } },
|
|
1407
|
+
IconComponent && React.createElement(IconComponent, { style: { color: brandColor, width: 18, height: 18, flexShrink: 0 } }),
|
|
1231
1408
|
label
|
|
1232
1409
|
),
|
|
1233
1410
|
active && React.createElement("span", {
|
package/client/index.js
CHANGED
|
@@ -51,6 +51,42 @@ const s = {
|
|
|
51
51
|
tip: { background: 'var(--dsw-alias-bg-layer-2,#f9fafb)', borderRadius: 8, padding: '10px 14px', fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)', lineHeight: 1.6 },
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
// ---- 官方品牌与 UI SVG 图标 ----
|
|
55
|
+
|
|
56
|
+
const Icons = {
|
|
57
|
+
wechat: (props) => React.createElement('svg', { viewBox: '0 0 24 24', width: 18, height: 18, fill: 'currentColor', ...props },
|
|
58
|
+
React.createElement('path', { d: 'M8.5 2C4.36 2 1 4.91 1 8.5c0 2.01 1.05 3.81 2.69 4.97l-.69 2.06 2.45-1.22c.94.43 1.98.69 3.05.69.21 0 .42-.01.62-.03-.23-.62-.37-1.28-.37-1.97 0-3.59 3.36-6.5 7.5-6.5.21 0 .41.01.62.03C15.87 4.54 12.44 2 8.5 2zM6 6.5a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5zm5 0a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5zm7.5 3.5c-3.59 0-6.5 2.46-6.5 5.5 0 1.66.86 3.14 2.21 4.1l-.56 1.69 2.01-1c.78.36 1.64.57 2.54.57 3.59 0 6.5-2.46 6.5-5.5s-2.91-5.5-6.5-5.5zm-2 4a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm4 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2z' })
|
|
59
|
+
),
|
|
60
|
+
qq: (props) => React.createElement('svg', { viewBox: '0 0 24 24', width: 18, height: 18, fill: 'currentColor', ...props },
|
|
61
|
+
React.createElement('path', { d: 'M12 2C7.58 2 4 5.37 4 9.53c0 1.95.78 3.73 2.07 5.07-.37 1.15-.99 2.19-1.8 3.08-.18.2-.04.52.23.52 2.22 0 3.99-1.07 4.9-1.86.8.25 1.66.39 2.6.39 4.42 0 8-3.37 8-7.53S16.42 2 12 2zm-3 8a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5zm6 0a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5z' })
|
|
62
|
+
),
|
|
63
|
+
feishu: (props) => React.createElement('svg', { viewBox: '0 0 24 24', width: 18, height: 18, fill: 'currentColor', ...props },
|
|
64
|
+
React.createElement('path', { d: 'M12 2.5L3.5 11.2l6.8 1.8 2.2 6.5 1.8-4.7 5.2-1.4L12 2.5zm-.8 11.1l-4.1-1.1 6.5-6.6-4.2 8.3 1.8-.6z' })
|
|
65
|
+
),
|
|
66
|
+
telegram: (props) => React.createElement('svg', { viewBox: '0 0 24 24', width: 18, height: 18, fill: 'currentColor', ...props },
|
|
67
|
+
React.createElement('path', { d: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19-.14.75-.42 1-.68 1.03-.58.05-1.02-.38-1.58-.75-.88-.58-1.38-.94-2.23-1.5-.99-.65-.35-1.01.22-1.59.15-.15 2.71-2.48 2.76-2.69a.2.2 0 0 0-.05-.18c-.06-.05-.14-.03-.21-.02-.09.02-1.49.95-4.22 2.79-.4.27-.76.41-1.08.4-.36-.01-1.04-.2-1.55-.37-.63-.2-1.12-.31-1.08-.66.02-.18.27-.36.74-.55 2.92-1.27 4.86-2.11 5.83-2.51 2.78-1.16 3.35-1.36 3.73-1.36.08 0 .27.02.39.12.1.08.13.19.14.27-.01.06.01.24 0 .38z' })
|
|
68
|
+
),
|
|
69
|
+
lan: (props) => React.createElement('svg', { viewBox: '0 0 24 24', width: 16, height: 16, fill: 'currentColor', ...props },
|
|
70
|
+
React.createElement('path', { d: 'M12 3c-4.97 0-9 4.03-9 9 0 2.12.74 4.07 1.97 5.61L4.29 19.3a1 1 0 0 0 1.41 1.41l1.7-1.7C9.02 19.64 10.46 20 12 20c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 15c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6zm0-9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z' })
|
|
71
|
+
),
|
|
72
|
+
tunnel: (props) => React.createElement('svg', { viewBox: '0 0 24 24', width: 16, height: 16, fill: 'currentColor', ...props },
|
|
73
|
+
React.createElement('path', { d: 'M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM19 18H6c-2.21 0-4-1.79-4-4 0-2.05 1.53-3.76 3.56-3.97l1.07-.11.5-.95C8.08 7.14 9.94 6 12 6c2.62 0 4.88 1.86 5.39 4.43l.3 1.5 1.53.11c1.56.1 2.78 1.41 2.78 2.96 0 1.65-1.35 3-3 3z' })
|
|
74
|
+
),
|
|
75
|
+
bot: (props) => React.createElement('svg', { viewBox: '0 0 24 24', width: 16, height: 16, fill: 'currentColor', ...props },
|
|
76
|
+
React.createElement('path', { d: 'M20 9V7c0-1.1-.9-2-2-2h-3c0-1.66-1.34-3-3-3S9 3.34 9 5H6c-1.1 0-2 .9-2 2v2c-1.66 0-3 1.34-3 3s1.34 3 3 3v4c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-4c1.66 0 3-1.34 3-3s-1.34-3-3-3zm-2 10H6V7h12v12zm-9-6c-.83 0-1.5-.67-1.5-1.5S8.17 10 9 10s1.5.67 1.5 1.5S9.83 13 9 13zm6 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z' })
|
|
77
|
+
),
|
|
78
|
+
github: (props) => React.createElement('svg', { viewBox: '0 0 24 24', width: 13, height: 13, fill: 'currentColor', ...props },
|
|
79
|
+
React.createElement('path', { d: 'M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.53 1.032 1.53 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z' })
|
|
80
|
+
),
|
|
81
|
+
refresh: (props) => React.createElement('svg', { viewBox: '0 0 24 24', width: 12, height: 12, fill: 'none', stroke: 'currentColor', strokeWidth: 2.2, strokeLinecap: 'round', strokeLinejoin: 'round', ...props },
|
|
82
|
+
React.createElement('path', { d: 'M23 4v6h-6M1 20v-6h6' }),
|
|
83
|
+
React.createElement('path', { d: 'M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15' })
|
|
84
|
+
),
|
|
85
|
+
check: (props) => React.createElement('svg', { viewBox: '0 0 24 24', width: 12, height: 12, fill: 'none', stroke: 'currentColor', strokeWidth: 2.5, strokeLinecap: 'round', strokeLinejoin: 'round', ...props },
|
|
86
|
+
React.createElement('polyline', { points: '20 6 9 17 4 12' })
|
|
87
|
+
),
|
|
88
|
+
};
|
|
89
|
+
|
|
54
90
|
// ---- 子组件 ----
|
|
55
91
|
|
|
56
92
|
// 通用复制 hook:返回 [copied, copy],copy(text) 复制文本并短暂显示成功状态
|
|
@@ -438,7 +474,13 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
|
|
|
438
474
|
return React.createElement('div', { style: s.card },
|
|
439
475
|
React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' } },
|
|
440
476
|
React.createElement('div', null,
|
|
441
|
-
React.createElement('div', { style: s.label
|
|
477
|
+
React.createElement('div', { style: { ...s.label, display: 'flex', alignItems: 'center', gap: 7 } },
|
|
478
|
+
platformId === 'wechat' && React.createElement(Icons.wechat, { style: { color: '#07C160', width: 20, height: 20 } }),
|
|
479
|
+
platformId === 'qq' && React.createElement(Icons.qq, { style: { color: '#12B7F5', width: 20, height: 20 } }),
|
|
480
|
+
platformId === 'feishu' && React.createElement(Icons.feishu, { style: { color: '#00D6B9', width: 20, height: 20 } }),
|
|
481
|
+
platformId === 'telegram' && React.createElement(Icons.telegram, { style: { color: '#24A1DE', width: 20, height: 20 } }),
|
|
482
|
+
platformName,
|
|
483
|
+
),
|
|
442
484
|
React.createElement('div', { style: { ...s.muted, marginTop: 2 } }, platformDesc),
|
|
443
485
|
),
|
|
444
486
|
React.createElement(StatusTag, { status: platform?.status, running: connected }),
|
|
@@ -775,6 +817,10 @@ function UpgradeCommandRow({ cmd }) {
|
|
|
775
817
|
flex: 1,
|
|
776
818
|
minWidth: 0,
|
|
777
819
|
wordBreak: 'break-all',
|
|
820
|
+
background: 'var(--dsw-alias-bg-layer-1,#ffffff)',
|
|
821
|
+
padding: '4px 8px',
|
|
822
|
+
borderRadius: 6,
|
|
823
|
+
border: '1px solid var(--dsw-alias-border-l2,#e5e7eb)',
|
|
778
824
|
},
|
|
779
825
|
}, cmd),
|
|
780
826
|
React.createElement('button', {
|
|
@@ -785,10 +831,13 @@ function UpgradeCommandRow({ cmd }) {
|
|
|
785
831
|
);
|
|
786
832
|
}
|
|
787
833
|
|
|
788
|
-
// 版本检查 + GitHub/反馈入口
|
|
834
|
+
// 版本检查 + 一键升级 + GitHub/反馈入口
|
|
789
835
|
function VersionBanner({ rpcCall }) {
|
|
790
836
|
const [info, setInfo] = React.useState(null);
|
|
791
837
|
const [loading, setLoading] = React.useState(false);
|
|
838
|
+
const [upgrading, setUpgrading] = React.useState(false);
|
|
839
|
+
const [upgradeResult, setUpgradeResult] = React.useState(null);
|
|
840
|
+
const [showManual, setShowManual] = React.useState(false);
|
|
792
841
|
|
|
793
842
|
const check = React.useCallback(async () => {
|
|
794
843
|
setLoading(true);
|
|
@@ -802,92 +851,195 @@ function VersionBanner({ rpcCall }) {
|
|
|
802
851
|
|
|
803
852
|
React.useEffect(() => { check(); }, [check]);
|
|
804
853
|
|
|
805
|
-
// 只有 npm 上的版本严格大于当前版本才算有新版本
|
|
806
854
|
const hasUpdate = info?.latest && info?.current && !info.error && semverGt(info.latest, info.current);
|
|
855
|
+
const isLatest = info?.latest && info?.current && !info.error && !semverGt(info.latest, info.current);
|
|
856
|
+
|
|
857
|
+
const handleUpgrade = React.useCallback(async () => {
|
|
858
|
+
if (!info?.latest || upgrading) return;
|
|
859
|
+
setUpgrading(true);
|
|
860
|
+
setUpgradeResult(null);
|
|
861
|
+
try {
|
|
862
|
+
const r = await rpcCall(BRIDGE_ENDPOINTS.upgradePlugin, { version: info.latest });
|
|
863
|
+
if (r?.ok && r.value?.ok) {
|
|
864
|
+
setUpgradeResult({ ok: true, message: `已成功升级到 v${info.latest}!请重启 DSH 服务使新版本生效。` });
|
|
865
|
+
setTimeout(() => check(), 3000);
|
|
866
|
+
} else {
|
|
867
|
+
setUpgradeResult({ ok: false, message: r?.value?.error || r?.error?.message || '升级失败' });
|
|
868
|
+
setShowManual(true);
|
|
869
|
+
}
|
|
870
|
+
} catch (e) {
|
|
871
|
+
setUpgradeResult({ ok: false, message: e.message || '升级请求失败' });
|
|
872
|
+
setShowManual(true);
|
|
873
|
+
} finally {
|
|
874
|
+
setUpgrading(false);
|
|
875
|
+
}
|
|
876
|
+
}, [info?.latest, upgrading, rpcCall, check]);
|
|
807
877
|
|
|
808
|
-
// 链接按钮组:GitHub + 更新日志 + 反馈 Bug
|
|
809
878
|
const links = React.createElement('div', { style: { display: 'flex', gap: 12, alignItems: 'center', flexWrap: 'wrap' } },
|
|
810
879
|
React.createElement('a', {
|
|
811
880
|
href: GITHUB_URL, target: '_blank', rel: 'noreferrer', style: s.btnLink,
|
|
812
|
-
}, '
|
|
881
|
+
}, React.createElement(Icons.github), 'GitHub'),
|
|
813
882
|
React.createElement('a', {
|
|
814
883
|
href: RELEASES_URL, target: '_blank', rel: 'noreferrer', style: s.btnLink,
|
|
815
|
-
}, '
|
|
884
|
+
}, '更新日志'),
|
|
816
885
|
React.createElement('a', {
|
|
817
886
|
href: ISSUES_URL, target: '_blank', rel: 'noreferrer', style: s.btnLink,
|
|
818
|
-
}, '
|
|
887
|
+
}, '反馈 Issue'),
|
|
819
888
|
);
|
|
820
889
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
890
|
+
return React.createElement('div', { style: { marginBottom: 16 } },
|
|
891
|
+
// 顶部状态行:版本徽标 + 刷新按钮 + 链接组
|
|
892
|
+
React.createElement('div', {
|
|
893
|
+
style: {
|
|
894
|
+
display: 'flex',
|
|
895
|
+
alignItems: 'center',
|
|
896
|
+
justifyContent: 'space-between',
|
|
897
|
+
flexWrap: 'wrap',
|
|
898
|
+
gap: 8,
|
|
899
|
+
},
|
|
900
|
+
},
|
|
901
|
+
React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } },
|
|
902
|
+
// 版本状态徽标
|
|
903
|
+
React.createElement('span', {
|
|
904
|
+
style: {
|
|
905
|
+
...s.tag,
|
|
906
|
+
background: hasUpdate
|
|
907
|
+
? 'var(--dsw-alias-state-info-bg,#eff6ff)'
|
|
908
|
+
: isLatest
|
|
909
|
+
? 'var(--dsw-alias-state-success-bg,#ecfdf5)'
|
|
910
|
+
: 'var(--dsw-alias-bg-layer-2,#f3f4f6)',
|
|
911
|
+
color: hasUpdate
|
|
912
|
+
? 'var(--dsw-alias-state-info-primary,#2563eb)'
|
|
913
|
+
: isLatest
|
|
914
|
+
? 'var(--dsw-alias-state-success-primary,#059669)'
|
|
915
|
+
: 'var(--dsw-alias-label-secondary,#6b7280)',
|
|
916
|
+
padding: '3px 10px',
|
|
917
|
+
fontSize: 12,
|
|
918
|
+
fontWeight: 500,
|
|
919
|
+
display: 'inline-flex',
|
|
920
|
+
alignItems: 'center',
|
|
921
|
+
gap: 5,
|
|
922
|
+
},
|
|
832
923
|
},
|
|
924
|
+
loading
|
|
925
|
+
? React.createElement('span', {
|
|
926
|
+
style: { display: 'inline-flex', alignItems: 'center' },
|
|
927
|
+
}, React.createElement(Icons.refresh))
|
|
928
|
+
: isLatest
|
|
929
|
+
? React.createElement(Icons.check)
|
|
930
|
+
: null,
|
|
931
|
+
info ? `v${info.current}` : '版本检查中…',
|
|
932
|
+
isLatest && React.createElement('span', { style: { opacity: 0.85, fontSize: 11, fontWeight: 400 } }, '· 已是最新'),
|
|
933
|
+
hasUpdate && React.createElement('span', { style: { fontWeight: 600, fontSize: 11 } }, `➔ v${info.latest}`),
|
|
934
|
+
info?.error && React.createElement('span', { style: { color: 'var(--dsw-alias-state-warn-primary,#d97706)', fontSize: 11 } }, '(网络超时)'),
|
|
935
|
+
),
|
|
936
|
+
// 刷新检查按钮
|
|
937
|
+
React.createElement('button', {
|
|
938
|
+
style: {
|
|
939
|
+
...s.btnGhost,
|
|
940
|
+
height: 24,
|
|
941
|
+
padding: '0 8px',
|
|
942
|
+
fontSize: 11,
|
|
943
|
+
opacity: loading ? 0.5 : 1,
|
|
944
|
+
gap: 4,
|
|
945
|
+
},
|
|
946
|
+
onClick: check,
|
|
947
|
+
disabled: loading || upgrading,
|
|
948
|
+
title: '重新检查 npm 线上版本',
|
|
949
|
+
},
|
|
950
|
+
React.createElement(Icons.refresh),
|
|
951
|
+
loading ? '检查中…' : '检查更新',
|
|
952
|
+
),
|
|
953
|
+
),
|
|
954
|
+
links,
|
|
955
|
+
),
|
|
956
|
+
|
|
957
|
+
// 发现新版本高亮卡片(支持一键直接升级)
|
|
958
|
+
hasUpdate && React.createElement('div', {
|
|
959
|
+
style: {
|
|
960
|
+
...s.card,
|
|
961
|
+
background: 'var(--dsw-alias-state-info-bg,#eff6ff)',
|
|
962
|
+
border: '1px solid var(--dsw-alias-state-info-border,#bfdbfe)',
|
|
963
|
+
padding: '14px 16px',
|
|
964
|
+
marginTop: 10,
|
|
965
|
+
marginBottom: 0,
|
|
833
966
|
},
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
967
|
+
},
|
|
968
|
+
React.createElement('div', { style: { display: 'flex', alignItems: 'flex-start', gap: 12 } },
|
|
969
|
+
React.createElement('span', { style: { fontSize: 22 } }, '🚀'),
|
|
970
|
+
React.createElement('div', { style: { flex: 1, minWidth: 0 } },
|
|
971
|
+
React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap', gap: 8, marginBottom: 8 } },
|
|
837
972
|
React.createElement('div', {
|
|
838
973
|
style: {
|
|
839
974
|
fontSize: 13,
|
|
840
975
|
fontWeight: 600,
|
|
841
976
|
color: 'var(--dsw-alias-state-info-primary,#1e40af)',
|
|
842
|
-
marginBottom: 8,
|
|
843
977
|
},
|
|
844
978
|
}, `发现新版本 v${info.latest}(当前 v${info.current})`),
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
979
|
+
React.createElement('button', {
|
|
980
|
+
style: {
|
|
981
|
+
...s.btnPri,
|
|
982
|
+
height: 28,
|
|
983
|
+
fontSize: 12,
|
|
984
|
+
padding: '0 14px',
|
|
985
|
+
background: upgradeResult?.ok
|
|
986
|
+
? 'var(--dsw-alias-state-success-primary,#059669)'
|
|
987
|
+
: 'var(--dsw-alias-brand-primary,#4f6ef7)',
|
|
988
|
+
opacity: upgrading ? 0.6 : 1,
|
|
989
|
+
},
|
|
990
|
+
onClick: handleUpgrade,
|
|
991
|
+
disabled: upgrading || upgradeResult?.ok,
|
|
992
|
+
},
|
|
993
|
+
upgrading
|
|
994
|
+
? React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', gap: 6 } },
|
|
995
|
+
React.createElement('span', { style: { animation: 'spin 1s linear infinite', display: 'inline-flex' } }, React.createElement(Icons.refresh)),
|
|
996
|
+
'正在自动升级…',
|
|
997
|
+
)
|
|
998
|
+
: upgradeResult?.ok
|
|
999
|
+
? '✓ 已完成升级'
|
|
1000
|
+
: `一键升级到 v${info.latest}`
|
|
848
1001
|
),
|
|
849
1002
|
),
|
|
850
|
-
|
|
1003
|
+
|
|
1004
|
+
upgradeResult && React.createElement('div', {
|
|
851
1005
|
style: {
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
1006
|
+
background: upgradeResult.ok ? 'var(--dsw-alias-state-success-bg,#ecfdf5)' : 'var(--dsw-alias-state-error-bg,#fef2f2)',
|
|
1007
|
+
border: `1px solid ${upgradeResult.ok ? 'var(--dsw-alias-state-success-border,#a7f3d0)' : 'var(--dsw-alias-state-error-border,#fecaca)'}`,
|
|
1008
|
+
color: upgradeResult.ok ? 'var(--dsw-alias-state-success-primary,#065f46)' : 'var(--dsw-alias-state-error-primary,#991b1b)',
|
|
1009
|
+
padding: '8px 12px',
|
|
1010
|
+
borderRadius: 6,
|
|
855
1011
|
fontSize: 12,
|
|
856
|
-
|
|
857
|
-
|
|
1012
|
+
marginBottom: 8,
|
|
1013
|
+
lineHeight: 1.5,
|
|
858
1014
|
},
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
1015
|
+
}, upgradeResult.message),
|
|
1016
|
+
|
|
1017
|
+
React.createElement('div', { style: { marginTop: 4 } },
|
|
1018
|
+
React.createElement('button', {
|
|
1019
|
+
style: { ...s.btnLink, fontSize: 11, color: 'var(--dsw-alias-label-secondary,#6b7280)' },
|
|
1020
|
+
onClick: () => setShowManual(v => !v),
|
|
1021
|
+
}, showManual ? '▴ 折叠手动命令行' : '▾ 查看手动升级命令 (如需)'),
|
|
1022
|
+
),
|
|
1023
|
+
|
|
1024
|
+
showManual && React.createElement('div', {
|
|
1025
|
+
style: { display: 'flex', flexDirection: 'column', gap: 6, marginTop: 8 },
|
|
1026
|
+
},
|
|
1027
|
+
upgradeCommands(info.latest).map(({ id, cmd }) =>
|
|
1028
|
+
React.createElement(UpgradeCommandRow, { key: id, cmd })
|
|
1029
|
+
),
|
|
1030
|
+
),
|
|
862
1031
|
),
|
|
863
1032
|
),
|
|
864
|
-
links,
|
|
865
|
-
);
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
// 正常状态:版本信息一行 + 链接
|
|
869
|
-
return React.createElement('div', { style: { marginBottom: 14, display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap', gap: 8 } },
|
|
870
|
-
React.createElement('div', { style: { ...s.muted, display: 'flex', alignItems: 'center', gap: 8 } },
|
|
871
|
-
loading && !info
|
|
872
|
-
? React.createElement('span', null, '检查更新中…')
|
|
873
|
-
: info
|
|
874
|
-
? React.createElement('span', null, `v${info.current}${info.latest && !info.error ? ' · 已是最新' : info.error ? ' · 检查失败' : ''}`)
|
|
875
|
-
: null,
|
|
876
|
-
info && React.createElement('button', {
|
|
877
|
-
style: { ...s.btnGhost, height: 22, padding: '0 8px', fontSize: 11, opacity: loading ? 0.5 : 1 },
|
|
878
|
-
onClick: check, disabled: loading,
|
|
879
|
-
}, loading ? '…' : '重新检查'),
|
|
880
1033
|
),
|
|
881
|
-
links,
|
|
882
1034
|
);
|
|
883
1035
|
}
|
|
884
1036
|
|
|
885
1037
|
// ---- Tab Bar ----
|
|
886
1038
|
|
|
887
1039
|
const TABS = [
|
|
888
|
-
{ id: 'lan', label: '局域网', icon:
|
|
889
|
-
{ id: 'tunnel', label: '公网隧道', icon:
|
|
890
|
-
{ id: 'im', label: 'IM 机器人', icon:
|
|
1040
|
+
{ id: 'lan', label: '局域网', icon: Icons.lan },
|
|
1041
|
+
{ id: 'tunnel', label: '公网隧道', icon: Icons.tunnel },
|
|
1042
|
+
{ id: 'im', label: 'IM 机器人', icon: Icons.bot },
|
|
891
1043
|
];
|
|
892
1044
|
|
|
893
1045
|
function TabBar({ active, onChange, dots }) {
|
|
@@ -897,7 +1049,7 @@ function TabBar({ active, onChange, dots }) {
|
|
|
897
1049
|
borderBottom: '1px solid var(--dsw-alias-border-l2,#e5e7eb)',
|
|
898
1050
|
},
|
|
899
1051
|
},
|
|
900
|
-
TABS.map(({ id, label, icon }) => {
|
|
1052
|
+
TABS.map(({ id, label, icon: TabIcon }) => {
|
|
901
1053
|
const isActive = active === id;
|
|
902
1054
|
const hasDot = dots?.[id];
|
|
903
1055
|
return React.createElement('button', {
|
|
@@ -913,12 +1065,17 @@ function TabBar({ active, onChange, dots }) {
|
|
|
913
1065
|
? '2px solid var(--dsw-alias-brand-primary,#4f6ef7)'
|
|
914
1066
|
: '2px solid transparent',
|
|
915
1067
|
marginBottom: -1,
|
|
916
|
-
display: 'inline-flex', alignItems: 'center', gap:
|
|
1068
|
+
display: 'inline-flex', alignItems: 'center', gap: 7,
|
|
917
1069
|
transition: 'color .15s, border-color .15s',
|
|
918
1070
|
whiteSpace: 'nowrap',
|
|
919
1071
|
},
|
|
920
1072
|
},
|
|
921
|
-
React.createElement(
|
|
1073
|
+
TabIcon && React.createElement(TabIcon, {
|
|
1074
|
+
style: {
|
|
1075
|
+
color: isActive ? 'var(--dsw-alias-brand-primary,#4f6ef7)' : 'var(--dsw-alias-label-tertiary,#9ca3af)',
|
|
1076
|
+
width: 16, height: 16, flexShrink: 0,
|
|
1077
|
+
},
|
|
1078
|
+
}),
|
|
922
1079
|
label,
|
|
923
1080
|
hasDot && React.createElement('span', {
|
|
924
1081
|
style: {
|
|
@@ -1062,9 +1219,10 @@ function BridgePanel({ rpcCall }) {
|
|
|
1062
1219
|
} else if (activeTab === 'im') {
|
|
1063
1220
|
// 从 listPlatforms 动态生成平台列表
|
|
1064
1221
|
const IM_PLATFORMS = [
|
|
1065
|
-
{ id: 'wechat',
|
|
1066
|
-
{ id: 'qq',
|
|
1067
|
-
{ id: 'feishu',
|
|
1222
|
+
{ id: 'wechat', label: '微信', icon: Icons.wechat, brandColor: '#07C160', desc: 'ClawBot 扫码直连 · 无需公网' },
|
|
1223
|
+
{ id: 'qq', label: 'QQ', icon: Icons.qq, brandColor: '#12B7F5', desc: '官方机器人 · 私聊/群聊/按钮' },
|
|
1224
|
+
{ id: 'feishu', label: '飞书', icon: Icons.feishu, brandColor: '#00D6B9', desc: '官方事件回调 API' },
|
|
1225
|
+
{ id: 'telegram', label: 'Telegram', icon: Icons.telegram, brandColor: '#24A1DE', desc: '官方 Bot API' },
|
|
1068
1226
|
];
|
|
1069
1227
|
|
|
1070
1228
|
tabContent = React.createElement('div', null,
|
|
@@ -1072,7 +1230,7 @@ function BridgePanel({ rpcCall }) {
|
|
|
1072
1230
|
React.createElement('div', {
|
|
1073
1231
|
style: { display: 'flex', gap: 10, marginBottom: 16, flexWrap: 'wrap' },
|
|
1074
1232
|
},
|
|
1075
|
-
IM_PLATFORMS.map(({ id, label, icon, desc }) => {
|
|
1233
|
+
IM_PLATFORMS.map(({ id, label, icon: IconComponent, brandColor, desc }) => {
|
|
1076
1234
|
const platformData = platforms?.[id];
|
|
1077
1235
|
const available = !!platformData;
|
|
1078
1236
|
const active = platformData?.status === 'connected' || platformData?.status === 'starting' || platformData?.status === 'reconnecting';
|
|
@@ -1080,7 +1238,7 @@ function BridgePanel({ rpcCall }) {
|
|
|
1080
1238
|
return React.createElement('div', {
|
|
1081
1239
|
key: id,
|
|
1082
1240
|
style: {
|
|
1083
|
-
flex: '1 1
|
|
1241
|
+
flex: '1 1 135px',
|
|
1084
1242
|
border: `1px solid ${selectedPlatform === id ? 'var(--dsw-alias-brand-primary,#4f6ef7)' : active ? 'var(--dsw-alias-state-success-primary,#10b981)' : 'var(--dsw-alias-border-l2,#e5e7eb)'}`,
|
|
1085
1243
|
borderRadius: 10,
|
|
1086
1244
|
padding: '12px 14px',
|
|
@@ -1093,8 +1251,8 @@ function BridgePanel({ rpcCall }) {
|
|
|
1093
1251
|
onClick: available ? () => setSelectedPlatform(id) : undefined,
|
|
1094
1252
|
},
|
|
1095
1253
|
React.createElement('div', { style: { ...s.label, fontSize: 13, display: 'flex', alignItems: 'center', justifyContent: 'space-between' } },
|
|
1096
|
-
React.createElement('span', { style: { display: 'flex', alignItems: 'center', gap:
|
|
1097
|
-
React.createElement(
|
|
1254
|
+
React.createElement('span', { style: { display: 'flex', alignItems: 'center', gap: 7 } },
|
|
1255
|
+
IconComponent && React.createElement(IconComponent, { style: { color: brandColor, width: 18, height: 18, flexShrink: 0 } }),
|
|
1098
1256
|
label,
|
|
1099
1257
|
),
|
|
1100
1258
|
active && React.createElement('span', {
|
|
@@ -11,6 +11,7 @@ export const BRIDGE_ENDPOINTS = {
|
|
|
11
11
|
resetCloudflared: 'resetCloudflared',
|
|
12
12
|
saveCustomTunnelConfig: 'saveCustomTunnelConfig',
|
|
13
13
|
checkVersion: 'checkVersion',
|
|
14
|
+
upgradePlugin: 'upgradePlugin',
|
|
14
15
|
// 平台管理器(多 IM 平台统一接口)
|
|
15
16
|
listPlatforms: 'listPlatforms',
|
|
16
17
|
platformLogin: 'platformLogin',
|
package/lib/bridge-rpc.js
CHANGED
|
@@ -123,6 +123,11 @@ export function installBridgeRpc(ctx, { service, wechat, platformManager, logger
|
|
|
123
123
|
return ok(result);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
if (endpoint === BRIDGE_ENDPOINTS.upgradePlugin) {
|
|
127
|
+
const result = await service.upgradePlugin(payload);
|
|
128
|
+
return ok(result);
|
|
129
|
+
}
|
|
130
|
+
|
|
126
131
|
// ---- 平台管理器(多 IM 平台)----
|
|
127
132
|
|
|
128
133
|
if (endpoint === BRIDGE_ENDPOINTS.listPlatforms) {
|
package/lib/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { join, dirname } from 'node:path';
|
|
|
12
12
|
import { fileURLToPath } from 'node:url';
|
|
13
13
|
import { readFileSync } from 'node:fs';
|
|
14
14
|
import { readFile, writeFile, mkdir, unlink } from 'node:fs/promises';
|
|
15
|
+
import { exec } from 'node:child_process';
|
|
15
16
|
import QRCode from 'qrcode';
|
|
16
17
|
import { installBridgeRpc } from './bridge-rpc.js';
|
|
17
18
|
import { CustomTunnelClient } from './tunnel-client.mjs';
|
|
@@ -406,24 +407,64 @@ class BridgeService {
|
|
|
406
407
|
this.cloudflaredState = { phase: 'idle', detail: '' };
|
|
407
408
|
}
|
|
408
409
|
|
|
409
|
-
// 检查 npm
|
|
410
|
+
// 检查 npm 上是否有新版本(优先国内高速镜像 npmmirror,降级 npmjs 官方源)
|
|
410
411
|
async checkVersion() {
|
|
411
|
-
|
|
412
|
-
const req = httpsGet(
|
|
412
|
+
const fetchRegistry = (url, timeoutMs = 4000) => new Promise((resolve, reject) => {
|
|
413
|
+
const req = httpsGet(url, { timeout: timeoutMs }, (res) => {
|
|
414
|
+
if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode}`));
|
|
413
415
|
const chunks = [];
|
|
414
416
|
res.on('data', (c) => chunks.push(c));
|
|
415
417
|
res.on('end', () => {
|
|
416
418
|
try {
|
|
417
419
|
const data = JSON.parse(Buffer.concat(chunks).toString());
|
|
418
|
-
resolve(
|
|
419
|
-
} catch {
|
|
420
|
-
|
|
420
|
+
resolve(data.version ?? null);
|
|
421
|
+
} catch (e) {
|
|
422
|
+
reject(e);
|
|
421
423
|
}
|
|
422
424
|
});
|
|
423
425
|
});
|
|
424
|
-
req.on('error',
|
|
425
|
-
req.on('timeout', () => { req.destroy();
|
|
426
|
+
req.on('error', reject);
|
|
427
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('请求超时')); });
|
|
426
428
|
});
|
|
429
|
+
|
|
430
|
+
try {
|
|
431
|
+
const latest = await fetchRegistry('https://registry.npmmirror.com/@wenbin_wb/dsh-bridge/latest', 3500)
|
|
432
|
+
.catch(() => fetchRegistry('https://registry.npmjs.org/@wenbin_wb/dsh-bridge/latest', 5000));
|
|
433
|
+
return { current: VERSION, latest: latest ?? null };
|
|
434
|
+
} catch (e) {
|
|
435
|
+
return { current: VERSION, latest: null, error: e.message ?? '检查失败' };
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// 一键直接升级插件(执行 dsh plugin / pnpm / npm 自动升级)
|
|
440
|
+
async upgradePlugin({ version } = {}) {
|
|
441
|
+
const targetVersion = version ? String(version).trim() : 'latest';
|
|
442
|
+
const pkgSpec = `@wenbin_wb/dsh-bridge@${targetVersion}`;
|
|
443
|
+
const commands = [
|
|
444
|
+
`dsh plugin --profile web add ${pkgSpec}`,
|
|
445
|
+
`npx --yes @deepseek-ai/dsh plugin --profile web add ${pkgSpec}`,
|
|
446
|
+
`npm install ${pkgSpec}`,
|
|
447
|
+
];
|
|
448
|
+
|
|
449
|
+
let lastError = null;
|
|
450
|
+
let output = '';
|
|
451
|
+
|
|
452
|
+
for (const cmd of commands) {
|
|
453
|
+
try {
|
|
454
|
+
const res = await new Promise((resolve, reject) => {
|
|
455
|
+
exec(cmd, { timeout: 90000, windowsHide: true }, (err, stdout, stderr) => {
|
|
456
|
+
if (err) return reject(new Error(stderr || err.message));
|
|
457
|
+
resolve({ stdout, stderr });
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
output = res.stdout || res.stderr || '升级成功';
|
|
461
|
+
return { ok: true, command: cmd, output, version: targetVersion };
|
|
462
|
+
} catch (err) {
|
|
463
|
+
lastError = err;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
return { ok: false, error: lastError?.message ?? '升级命令执行失败', version: targetVersion };
|
|
427
468
|
}
|
|
428
469
|
|
|
429
470
|
async dispose() {
|
package/package.json
CHANGED