mioku-service-webui 4.0.6 → 4.0.8
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/package.json +1 -1
- package/system.ts +139 -142
package/package.json
CHANGED
package/system.ts
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
WEBUI_DIST,
|
|
33
33
|
writeJsonFile,
|
|
34
34
|
} from "./utils";
|
|
35
|
+
import { spawn } from "node:child_process";
|
|
35
36
|
|
|
36
37
|
async function fetchJson(url: string): Promise<any> {
|
|
37
38
|
const res = await fetch(url, {
|
|
@@ -516,17 +517,7 @@ async function getGitOriginUrl(dir: string): Promise<string> {
|
|
|
516
517
|
}
|
|
517
518
|
|
|
518
519
|
function resolveWebUIProjectDir(): string {
|
|
519
|
-
|
|
520
|
-
path.join(process.cwd(), "mioku-webui"),
|
|
521
|
-
path.join(process.cwd(), "webui"),
|
|
522
|
-
];
|
|
523
|
-
|
|
524
|
-
for (const dir of candidates) {
|
|
525
|
-
if (fs.existsSync(path.join(dir, "package.json"))) {
|
|
526
|
-
return dir;
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
return candidates[0];
|
|
520
|
+
return path.join(process.cwd(), "..", "mioku-webui");
|
|
530
521
|
}
|
|
531
522
|
|
|
532
523
|
function readInstalledWebUIVersion(): string {
|
|
@@ -1010,11 +1001,17 @@ export async function installManagedPackage(
|
|
|
1010
1001
|
...Object.keys(afterPkg?.devDependencies || {}),
|
|
1011
1002
|
];
|
|
1012
1003
|
const installedName =
|
|
1013
|
-
afterDeps.find(
|
|
1014
|
-
(name
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1004
|
+
afterDeps.find(
|
|
1005
|
+
(name) =>
|
|
1006
|
+
!beforeDeps.has(name) &&
|
|
1007
|
+
(name.startsWith("mioku-plugin-") || name.startsWith("mioku-service-")),
|
|
1008
|
+
) || pkgName;
|
|
1009
|
+
|
|
1010
|
+
const packageJsonPath = path.join(
|
|
1011
|
+
NODE_MODULES_DIR,
|
|
1012
|
+
installedName,
|
|
1013
|
+
"package.json",
|
|
1014
|
+
);
|
|
1018
1015
|
const packageJson = readPackageJson(packageJsonPath);
|
|
1019
1016
|
const missingServices = checkDependentServices(packageJson);
|
|
1020
1017
|
|
|
@@ -1500,19 +1497,20 @@ async function fetchLatestWebUIUpdate(
|
|
|
1500
1497
|
}
|
|
1501
1498
|
|
|
1502
1499
|
const job = (async () => {
|
|
1503
|
-
const projectDir = resolveWebUIProjectDir();
|
|
1504
1500
|
const currentVersion = readInstalledWebUIVersion();
|
|
1505
|
-
|
|
1506
|
-
const
|
|
1507
|
-
|
|
1508
|
-
|
|
1501
|
+
// mioku-webui repo is at mioku-lab/mioku-webui, used for GitHub API and dist download
|
|
1502
|
+
const repo = {
|
|
1503
|
+
owner: "mioku-lab",
|
|
1504
|
+
repo: "mioku-webui",
|
|
1505
|
+
fullName: "mioku-lab/mioku-webui",
|
|
1506
|
+
};
|
|
1509
1507
|
|
|
1510
1508
|
const fallback: WebUIUpdateCheckResult = {
|
|
1511
1509
|
currentVersion,
|
|
1512
1510
|
latestVersion: currentVersion,
|
|
1513
1511
|
releaseTag: "",
|
|
1514
1512
|
releaseUrl: "",
|
|
1515
|
-
sourceRepo: repo
|
|
1513
|
+
sourceRepo: repo.fullName,
|
|
1516
1514
|
hasUpdates: false,
|
|
1517
1515
|
canUpdate: false,
|
|
1518
1516
|
assetName: "",
|
|
@@ -1520,13 +1518,6 @@ async function fetchLatestWebUIUpdate(
|
|
|
1520
1518
|
checkedAt: Date.now(),
|
|
1521
1519
|
};
|
|
1522
1520
|
|
|
1523
|
-
if (!repo) {
|
|
1524
|
-
return {
|
|
1525
|
-
...fallback,
|
|
1526
|
-
error: "WebUI 仓库不是 GitHub,暂不支持自动检查更新",
|
|
1527
|
-
};
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
1521
|
const res = await fetch(
|
|
1531
1522
|
`https://api.github.com/repos/${repo.owner}/${repo.repo}/releases/latest`,
|
|
1532
1523
|
{
|
|
@@ -1612,101 +1603,36 @@ async function fetchLatestMiokuUpdate(
|
|
|
1612
1603
|
const cwd = process.cwd();
|
|
1613
1604
|
const rootPkg = readRootPackageJson() || {};
|
|
1614
1605
|
const currentVersion = normalizeVersionSpec(rootPkg?.version || "unknown");
|
|
1615
|
-
const originUrl = (await getGitOriginUrl(cwd)) || "";
|
|
1616
|
-
const repoUrl = originUrl || getRepositoryFromPackage(rootPkg);
|
|
1617
|
-
const repo = parseGitHubRepo(repoUrl);
|
|
1618
|
-
const { currentBranch, targetRef, targetBranch } =
|
|
1619
|
-
await resolveMiokuTargetRef(cwd);
|
|
1620
|
-
|
|
1621
|
-
const fallback: MiokuUpdateCheckResult = {
|
|
1622
|
-
currentVersion,
|
|
1623
|
-
latestVersion: currentVersion,
|
|
1624
|
-
sourceRepo: repo?.fullName || "",
|
|
1625
|
-
currentBranch,
|
|
1626
|
-
targetRef,
|
|
1627
|
-
hasUpdates: false,
|
|
1628
|
-
behind: 0,
|
|
1629
|
-
changelog: [],
|
|
1630
|
-
checkedAt: Date.now(),
|
|
1631
|
-
};
|
|
1632
|
-
|
|
1633
|
-
if (!fs.existsSync(path.join(cwd, ".git"))) {
|
|
1634
|
-
return {
|
|
1635
|
-
...fallback,
|
|
1636
|
-
error: isContainerRuntime()
|
|
1637
|
-
? "当前 Docker 容器未挂载 .git 到 /app/.git,无法检查 Mioku 更新"
|
|
1638
|
-
: "当前目录不是 Git 仓库,无法检查 Mioku 更新",
|
|
1639
|
-
};
|
|
1640
|
-
}
|
|
1641
|
-
|
|
1642
|
-
if (!repo) {
|
|
1643
|
-
return {
|
|
1644
|
-
...fallback,
|
|
1645
|
-
error: "Mioku 仓库不是 GitHub,暂不支持自动检查更新",
|
|
1646
|
-
};
|
|
1647
|
-
}
|
|
1648
|
-
|
|
1649
|
-
const fetchRes = await runCommand(
|
|
1650
|
-
"git",
|
|
1651
|
-
["fetch", "origin", targetBranch],
|
|
1652
|
-
cwd,
|
|
1653
|
-
);
|
|
1654
|
-
|
|
1655
|
-
if (fetchRes.code !== 0) {
|
|
1656
|
-
return {
|
|
1657
|
-
...fallback,
|
|
1658
|
-
error: `git fetch 失败: ${fetchRes.stderr || fetchRes.stdout}`.trim(),
|
|
1659
|
-
};
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
const compare = await runCommand(
|
|
1663
|
-
"git",
|
|
1664
|
-
["rev-list", "--left-right", "--count", `HEAD...${targetRef}`],
|
|
1665
|
-
cwd,
|
|
1666
|
-
);
|
|
1667
|
-
|
|
1668
|
-
if (compare.code !== 0) {
|
|
1669
|
-
return {
|
|
1670
|
-
...fallback,
|
|
1671
|
-
error: `无法比较更新: ${compare.stderr || compare.stdout}`.trim(),
|
|
1672
|
-
};
|
|
1673
|
-
}
|
|
1674
|
-
|
|
1675
|
-
const parts = compare.stdout
|
|
1676
|
-
.trim()
|
|
1677
|
-
.split(/\s+/)
|
|
1678
|
-
.map((item) => Number(item));
|
|
1679
|
-
const behind = Number.isFinite(parts[1]) ? parts[1] : 0;
|
|
1680
|
-
const changelogRes = await runCommand(
|
|
1681
|
-
"git",
|
|
1682
|
-
["log", "--oneline", `HEAD..${targetRef}`, "-n", "30"],
|
|
1683
|
-
cwd,
|
|
1684
|
-
);
|
|
1685
1606
|
|
|
1607
|
+
// Get latest version from npm registry
|
|
1686
1608
|
let latestVersion = currentVersion;
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
latestVersion = normalizeVersionSpec(parsed?.version || currentVersion);
|
|
1696
|
-
} catch {
|
|
1697
|
-
latestVersion = currentVersion;
|
|
1609
|
+
try {
|
|
1610
|
+
const latestOutput = await runCommand(
|
|
1611
|
+
"bun",
|
|
1612
|
+
["info", "mioku", "version"],
|
|
1613
|
+
cwd,
|
|
1614
|
+
);
|
|
1615
|
+
if (latestOutput.code === 0 && latestOutput.stdout.trim()) {
|
|
1616
|
+
latestVersion = normalizeVersionSpec(latestOutput.stdout.trim());
|
|
1698
1617
|
}
|
|
1618
|
+
} catch {
|
|
1619
|
+
// ignore - keep currentVersion as fallback
|
|
1699
1620
|
}
|
|
1700
1621
|
|
|
1622
|
+
const hasUpdates =
|
|
1623
|
+
latestVersion !== "unknown" &&
|
|
1624
|
+
currentVersion !== "unknown" &&
|
|
1625
|
+
isVersionNewer(latestVersion, currentVersion);
|
|
1626
|
+
|
|
1701
1627
|
return {
|
|
1702
1628
|
currentVersion,
|
|
1703
1629
|
latestVersion,
|
|
1704
|
-
sourceRepo:
|
|
1705
|
-
currentBranch,
|
|
1706
|
-
targetRef,
|
|
1707
|
-
hasUpdates
|
|
1708
|
-
behind,
|
|
1709
|
-
changelog:
|
|
1630
|
+
sourceRepo: "mioku",
|
|
1631
|
+
currentBranch: "",
|
|
1632
|
+
targetRef: "",
|
|
1633
|
+
hasUpdates,
|
|
1634
|
+
behind: hasUpdates ? 1 : 0,
|
|
1635
|
+
changelog: [],
|
|
1710
1636
|
checkedAt: Date.now(),
|
|
1711
1637
|
error: "",
|
|
1712
1638
|
};
|
|
@@ -1730,24 +1656,18 @@ export async function checkMiokuReleaseUpdate(
|
|
|
1730
1656
|
|
|
1731
1657
|
export async function updateMiokuFromMain(): Promise<Record<string, any>> {
|
|
1732
1658
|
const cwd = process.cwd();
|
|
1733
|
-
if (!fs.existsSync(path.join(cwd, ".git"))) {
|
|
1734
|
-
throw new Error(
|
|
1735
|
-
isContainerRuntime()
|
|
1736
|
-
? "当前 Docker 容器未挂载 .git 到 /app/.git,无法更新 Mioku"
|
|
1737
|
-
: "当前目录不是 Git 仓库,无法更新 Mioku",
|
|
1738
|
-
);
|
|
1739
|
-
}
|
|
1740
1659
|
|
|
1741
|
-
const
|
|
1742
|
-
const
|
|
1743
|
-
const pull = await runCommand("git", ["pull", "origin", targetBranch], cwd);
|
|
1660
|
+
const beforePkg = readRootPackageJson();
|
|
1661
|
+
const beforeVersion = beforePkg?.version || "unknown";
|
|
1744
1662
|
|
|
1745
|
-
|
|
1746
|
-
|
|
1663
|
+
const update = await runCommand("bun", ["update", "mioku"], cwd);
|
|
1664
|
+
if (update.code !== 0) {
|
|
1665
|
+
throw new Error(`bun update mioku 失败: ${update.stderr || update.stdout}`);
|
|
1747
1666
|
}
|
|
1748
1667
|
|
|
1749
|
-
const
|
|
1750
|
-
const
|
|
1668
|
+
const afterPkg = readRootPackageJson();
|
|
1669
|
+
const afterVersion = afterPkg?.version || beforeVersion;
|
|
1670
|
+
const changed = beforeVersion !== afterVersion;
|
|
1751
1671
|
|
|
1752
1672
|
let reinstallOutput = "";
|
|
1753
1673
|
if (changed) {
|
|
@@ -1773,6 +1693,33 @@ export async function updateMiokuFromMain(): Promise<Record<string, any>> {
|
|
|
1773
1693
|
};
|
|
1774
1694
|
}
|
|
1775
1695
|
|
|
1696
|
+
async function notifyOwnerWebUIDownloaded(version: string): Promise<void> {
|
|
1697
|
+
const miokuConfig = getMiokuConfig();
|
|
1698
|
+
const owners = miokuConfig?.owners || [];
|
|
1699
|
+
if (owners.length === 0) {
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
const bots = Array.from(connectedBots.values());
|
|
1704
|
+
if (bots.length === 0) {
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
const bot = bots[0];
|
|
1709
|
+
const message = `🎉 WebUI 已自动更新到 v${version},记得重启哦~`;
|
|
1710
|
+
|
|
1711
|
+
for (const ownerId of owners) {
|
|
1712
|
+
try {
|
|
1713
|
+
await bot.api("send_private_msg", {
|
|
1714
|
+
user_id: Number(ownerId),
|
|
1715
|
+
message,
|
|
1716
|
+
});
|
|
1717
|
+
} catch (err: any) {
|
|
1718
|
+
logger.warn(`[webui] 通知主人 ${ownerId} 失败: ${err?.message || err}`);
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1776
1723
|
export async function updateWebUIDistFromRelease(): Promise<
|
|
1777
1724
|
Record<string, any>
|
|
1778
1725
|
> {
|
|
@@ -1798,6 +1745,9 @@ export async function updateWebUIDistFromRelease(): Promise<
|
|
|
1798
1745
|
);
|
|
1799
1746
|
}
|
|
1800
1747
|
|
|
1748
|
+
let lastLogTime = 0;
|
|
1749
|
+
const LOG_INTERVAL_MS = 2000;
|
|
1750
|
+
const downloadUrl = check.assetUrl;
|
|
1801
1751
|
const tempDir = path.join(
|
|
1802
1752
|
os.tmpdir(),
|
|
1803
1753
|
`mioku-webui-update-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
@@ -1810,20 +1760,65 @@ export async function updateWebUIDistFromRelease(): Promise<
|
|
|
1810
1760
|
|
|
1811
1761
|
let backupPath = "";
|
|
1812
1762
|
try {
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
"
|
|
1818
|
-
|
|
1819
|
-
|
|
1763
|
+
logger.info(`[webui] 正在下载 WebUI dist...`);
|
|
1764
|
+
|
|
1765
|
+
await new Promise<void>((resolve, reject) => {
|
|
1766
|
+
const curl = spawn(
|
|
1767
|
+
"curl",
|
|
1768
|
+
[
|
|
1769
|
+
"-L",
|
|
1770
|
+
"-o",
|
|
1771
|
+
zipPath,
|
|
1772
|
+
"-A",
|
|
1773
|
+
"mioku-webui-updater/1.0",
|
|
1774
|
+
"--silent",
|
|
1775
|
+
"--show-error",
|
|
1776
|
+
downloadUrl,
|
|
1777
|
+
],
|
|
1778
|
+
{
|
|
1779
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1780
|
+
},
|
|
1781
|
+
);
|
|
1820
1782
|
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1783
|
+
let stderr = "";
|
|
1784
|
+
curl.stderr.on("data", (chunk) => {
|
|
1785
|
+
stderr += String(chunk);
|
|
1786
|
+
});
|
|
1787
|
+
|
|
1788
|
+
curl.on("close", (code) => {
|
|
1789
|
+
if (code === 0) {
|
|
1790
|
+
resolve();
|
|
1791
|
+
} else {
|
|
1792
|
+
reject(new Error(`curl 下载失败 (code ${code}): ${stderr}`));
|
|
1793
|
+
}
|
|
1794
|
+
});
|
|
1795
|
+
|
|
1796
|
+
curl.on("error", (err) => {
|
|
1797
|
+
reject(new Error(`curl 进程异常: ${err.message}`));
|
|
1798
|
+
});
|
|
1799
|
+
|
|
1800
|
+
// Periodically log progress by checking file size
|
|
1801
|
+
const progressTimer = setInterval(() => {
|
|
1802
|
+
if (fs.existsSync(zipPath)) {
|
|
1803
|
+
const stat = fs.statSync(zipPath);
|
|
1804
|
+
const now = Date.now();
|
|
1805
|
+
if (now - lastLogTime >= LOG_INTERVAL_MS) {
|
|
1806
|
+
logger.info(
|
|
1807
|
+
`[webui] 正在下载 WebUI dist... ${(stat.size / 1024 / 1024).toFixed(1)} MB 已下载`,
|
|
1808
|
+
);
|
|
1809
|
+
lastLogTime = now;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
}, 1000);
|
|
1813
|
+
|
|
1814
|
+
// Clear timer when done
|
|
1815
|
+
curl.on("close", () => clearInterval(progressTimer));
|
|
1816
|
+
});
|
|
1824
1817
|
|
|
1825
|
-
const
|
|
1826
|
-
|
|
1818
|
+
const zipStat = fs.statSync(zipPath);
|
|
1819
|
+
logger.info(
|
|
1820
|
+
`[webui] 下载完成 (${(zipStat.size / 1024 / 1024).toFixed(1)} MB),正在解压...`,
|
|
1821
|
+
);
|
|
1827
1822
|
|
|
1828
1823
|
const zip = new AdmZip(zipPath);
|
|
1829
1824
|
zip.extractAllTo(unpackDir, true);
|
|
@@ -1875,6 +1870,8 @@ export async function updateWebUIDistFromRelease(): Promise<
|
|
|
1875
1870
|
error: "",
|
|
1876
1871
|
};
|
|
1877
1872
|
|
|
1873
|
+
await notifyOwnerWebUIDownloaded(check.latestVersion);
|
|
1874
|
+
|
|
1878
1875
|
return {
|
|
1879
1876
|
ok: true,
|
|
1880
1877
|
updated: true,
|