@xrxs-ai/dsh-xrxs-plugins-store 0.2.4 → 0.2.5
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/lib/client.js +65 -3
- package/lib/host/self-update.d.ts +7 -2
- package/lib/host/self-update.js +7 -2
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -3652,21 +3652,82 @@ var rightStyle2 = {
|
|
|
3652
3652
|
alignItems: "flex-end",
|
|
3653
3653
|
gap: 4
|
|
3654
3654
|
};
|
|
3655
|
+
var PENDING_UPDATE_KEY = "xrxs-plugins-store:self-update-pending";
|
|
3656
|
+
function readPendingUpdate() {
|
|
3657
|
+
try {
|
|
3658
|
+
const raw = localStorage.getItem(PENDING_UPDATE_KEY);
|
|
3659
|
+
if (raw === null) return null;
|
|
3660
|
+
const parsed = JSON.parse(raw);
|
|
3661
|
+
return typeof parsed.version === "string" ? parsed.version : null;
|
|
3662
|
+
} catch {
|
|
3663
|
+
return null;
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
function writePendingUpdate(version) {
|
|
3667
|
+
try {
|
|
3668
|
+
localStorage.setItem(PENDING_UPDATE_KEY, JSON.stringify({ version }));
|
|
3669
|
+
} catch {
|
|
3670
|
+
}
|
|
3671
|
+
}
|
|
3672
|
+
function clearPendingUpdate() {
|
|
3673
|
+
try {
|
|
3674
|
+
localStorage.removeItem(PENDING_UPDATE_KEY);
|
|
3675
|
+
} catch {
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3655
3678
|
function messageOf3(error, fallback) {
|
|
3656
3679
|
return error instanceof Error && error.message !== "" ? error.message : fallback;
|
|
3657
3680
|
}
|
|
3681
|
+
function versionAtLeast(current, target) {
|
|
3682
|
+
const parse = (text) => text.trim().replace(/^v/, "").split(".").map((part) => {
|
|
3683
|
+
const numeric = /^\d+/.exec(part);
|
|
3684
|
+
return numeric === null ? 0 : Number(numeric[0]);
|
|
3685
|
+
});
|
|
3686
|
+
const left = parse(current);
|
|
3687
|
+
const right = parse(target);
|
|
3688
|
+
const length = Math.max(left.length, right.length);
|
|
3689
|
+
for (let index = 0; index < length; index += 1) {
|
|
3690
|
+
const diff = (left[index] ?? 0) - (right[index] ?? 0);
|
|
3691
|
+
if (diff !== 0) return diff > 0;
|
|
3692
|
+
}
|
|
3693
|
+
return true;
|
|
3694
|
+
}
|
|
3658
3695
|
function GeneralUpdateRow() {
|
|
3659
|
-
const [phase, setPhase] = (0, import_react11.useState)(
|
|
3696
|
+
const [phase, setPhase] = (0, import_react11.useState)(() => {
|
|
3697
|
+
const pending = readPendingUpdate();
|
|
3698
|
+
return pending !== null ? { kind: "updated", version: pending } : { kind: "checking" };
|
|
3699
|
+
});
|
|
3660
3700
|
const [error, setError] = (0, import_react11.useState)("");
|
|
3661
3701
|
const check = () => {
|
|
3662
3702
|
setPhase({ kind: "checking" });
|
|
3663
3703
|
setError("");
|
|
3664
|
-
void checkSelfUpdate().then((result) =>
|
|
3704
|
+
void checkSelfUpdate().then((result) => {
|
|
3705
|
+
const pending = readPendingUpdate();
|
|
3706
|
+
if (pending !== null && result.current !== null && versionAtLeast(result.current, pending)) {
|
|
3707
|
+
clearPendingUpdate();
|
|
3708
|
+
setPhase({ kind: "checked", check: result });
|
|
3709
|
+
return;
|
|
3710
|
+
}
|
|
3711
|
+
setPhase({ kind: "checked", check: result });
|
|
3712
|
+
}).catch((err) => {
|
|
3665
3713
|
setPhase({ kind: "checked", check: { current: null, latest: null, updateAvailable: false } });
|
|
3666
3714
|
setError(messageOf3(err, "\u68C0\u67E5\u66F4\u65B0\u5931\u8D25"));
|
|
3667
3715
|
});
|
|
3668
3716
|
};
|
|
3669
|
-
(0, import_react11.useEffect)(
|
|
3717
|
+
(0, import_react11.useEffect)(() => {
|
|
3718
|
+
if (readPendingUpdate() !== null) {
|
|
3719
|
+
void checkSelfUpdate().then((result) => {
|
|
3720
|
+
const pending = readPendingUpdate();
|
|
3721
|
+
if (pending !== null && result.current !== null && versionAtLeast(result.current, pending)) {
|
|
3722
|
+
clearPendingUpdate();
|
|
3723
|
+
setPhase({ kind: "checked", check: result });
|
|
3724
|
+
}
|
|
3725
|
+
}).catch(() => {
|
|
3726
|
+
});
|
|
3727
|
+
return;
|
|
3728
|
+
}
|
|
3729
|
+
check();
|
|
3730
|
+
}, []);
|
|
3670
3731
|
const handleUpdate = (target, check0) => {
|
|
3671
3732
|
setPhase({ kind: "updating", check: check0 });
|
|
3672
3733
|
setError("");
|
|
@@ -3675,6 +3736,7 @@ function GeneralUpdateRow() {
|
|
|
3675
3736
|
setPhase({ kind: "degraded", command: result.command, version: target });
|
|
3676
3737
|
return;
|
|
3677
3738
|
}
|
|
3739
|
+
writePendingUpdate(target);
|
|
3678
3740
|
setPhase({ kind: "updated", version: target });
|
|
3679
3741
|
}).catch((err) => {
|
|
3680
3742
|
setPhase({ kind: "checked", check: check0 });
|
|
@@ -12,7 +12,10 @@ import { type InstallOutcome, type InstallerDeps } from './installer.ts';
|
|
|
12
12
|
export declare const SELF_PACKAGE_NAME = "@xrxs-ai/dsh-xrxs-plugins-store";
|
|
13
13
|
/** 当前运行实例的版本(包根 package.json);读不到为 null(极端情况:裸文件运行)。
|
|
14
14
|
* 依次尝试:模块相对层级(tsc 产物 lib/host/ 与源码 src/host/ 都是上一级的上一级)、
|
|
15
|
-
* 按包名 resolve(profile 安装布局变化时的兜底);读到的包名必须匹配,防止层级猜错读成别的包。
|
|
15
|
+
* 按包名 resolve(profile 安装布局变化时的兜底);读到的包名必须匹配,防止层级猜错读成别的包。
|
|
16
|
+
* 模块级缓存且首次读取后不再重读:这里要报的是「运行实例」的版本,不是磁盘版本 ——
|
|
17
|
+
* 更新落盘后宿主可能只重挂 client 而不重载 host 模块,重读磁盘会把还在运行的旧实例
|
|
18
|
+
* 报成新版本;重启后 host 模块重新加载,缓存自然取到新版本。 */
|
|
16
19
|
export declare function currentSelfVersion(): string | null;
|
|
17
20
|
export interface SelfUpdateCheck {
|
|
18
21
|
/** 当前运行实例版本;读不到为 null(无法比较,不可更新) */
|
|
@@ -21,7 +24,9 @@ export interface SelfUpdateCheck {
|
|
|
21
24
|
latest: string | null;
|
|
22
25
|
updateAvailable: boolean;
|
|
23
26
|
}
|
|
24
|
-
/** 查 npm latest 并与当前版本比较;registry 查询失败时 latest 为 null(不抛,便于 UI 展示「检查失败」)。
|
|
27
|
+
/** 查 npm latest 并与当前版本比较;registry 查询失败时 latest 为 null(不抛,便于 UI 展示「检查失败」)。
|
|
28
|
+
* 当前版本走模块级缓存:报运行实例的版本 —— 更新落盘、宿主尚未重载时,磁盘已是新版本,
|
|
29
|
+
* 但内存里跑的还是旧实例,报旧值才能让 client 半的「已更新待重启」记录正确保留到重启。 */
|
|
25
30
|
export declare function checkSelfUpdate(): Promise<SelfUpdateCheck>;
|
|
26
31
|
/** 应用更新:复用安装链路装确切版本(不装 latest tag,避免「检查到装的」漂移)。 */
|
|
27
32
|
export declare function applySelfUpdate(version: string, deps: InstallerDeps): Promise<InstallOutcome>;
|
package/lib/host/self-update.js
CHANGED
|
@@ -20,7 +20,10 @@ const LATEST_TIMEOUT_MS = 10_000;
|
|
|
20
20
|
let cachedVersion = null;
|
|
21
21
|
/** 当前运行实例的版本(包根 package.json);读不到为 null(极端情况:裸文件运行)。
|
|
22
22
|
* 依次尝试:模块相对层级(tsc 产物 lib/host/ 与源码 src/host/ 都是上一级的上一级)、
|
|
23
|
-
* 按包名 resolve(profile 安装布局变化时的兜底);读到的包名必须匹配,防止层级猜错读成别的包。
|
|
23
|
+
* 按包名 resolve(profile 安装布局变化时的兜底);读到的包名必须匹配,防止层级猜错读成别的包。
|
|
24
|
+
* 模块级缓存且首次读取后不再重读:这里要报的是「运行实例」的版本,不是磁盘版本 ——
|
|
25
|
+
* 更新落盘后宿主可能只重挂 client 而不重载 host 模块,重读磁盘会把还在运行的旧实例
|
|
26
|
+
* 报成新版本;重启后 host 模块重新加载,缓存自然取到新版本。 */
|
|
24
27
|
export function currentSelfVersion() {
|
|
25
28
|
if (cachedVersion !== null)
|
|
26
29
|
return cachedVersion;
|
|
@@ -50,7 +53,9 @@ export function currentSelfVersion() {
|
|
|
50
53
|
}
|
|
51
54
|
return cachedVersion;
|
|
52
55
|
}
|
|
53
|
-
/** 查 npm latest 并与当前版本比较;registry 查询失败时 latest 为 null(不抛,便于 UI 展示「检查失败」)。
|
|
56
|
+
/** 查 npm latest 并与当前版本比较;registry 查询失败时 latest 为 null(不抛,便于 UI 展示「检查失败」)。
|
|
57
|
+
* 当前版本走模块级缓存:报运行实例的版本 —— 更新落盘、宿主尚未重载时,磁盘已是新版本,
|
|
58
|
+
* 但内存里跑的还是旧实例,报旧值才能让 client 半的「已更新待重启」记录正确保留到重启。 */
|
|
54
59
|
export async function checkSelfUpdate() {
|
|
55
60
|
const current = currentSelfVersion();
|
|
56
61
|
let latest = null;
|