mioku-service-webui 4.0.7 → 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 +128 -167
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
|
> {
|
|
@@ -1800,7 +1747,7 @@ export async function updateWebUIDistFromRelease(): Promise<
|
|
|
1800
1747
|
|
|
1801
1748
|
let lastLogTime = 0;
|
|
1802
1749
|
const LOG_INTERVAL_MS = 2000;
|
|
1803
|
-
const downloadUrl =
|
|
1750
|
+
const downloadUrl = check.assetUrl;
|
|
1804
1751
|
const tempDir = path.join(
|
|
1805
1752
|
os.tmpdir(),
|
|
1806
1753
|
`mioku-webui-update-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
@@ -1813,53 +1760,65 @@ export async function updateWebUIDistFromRelease(): Promise<
|
|
|
1813
1760
|
|
|
1814
1761
|
let backupPath = "";
|
|
1815
1762
|
try {
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
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
|
+
);
|
|
1832
1782
|
|
|
1833
|
-
|
|
1834
|
-
|
|
1783
|
+
let stderr = "";
|
|
1784
|
+
curl.stderr.on("data", (chunk) => {
|
|
1785
|
+
stderr += String(chunk);
|
|
1786
|
+
});
|
|
1835
1787
|
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1788
|
+
curl.on("close", (code) => {
|
|
1789
|
+
if (code === 0) {
|
|
1790
|
+
resolve();
|
|
1791
|
+
} else {
|
|
1792
|
+
reject(new Error(`curl 下载失败 (code ${code}): ${stderr}`));
|
|
1793
|
+
}
|
|
1794
|
+
});
|
|
1839
1795
|
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1796
|
+
curl.on("error", (err) => {
|
|
1797
|
+
reject(new Error(`curl 进程异常: ${err.message}`));
|
|
1798
|
+
});
|
|
1843
1799
|
|
|
1844
|
-
|
|
1800
|
+
// Periodically log progress by checking file size
|
|
1801
|
+
const progressTimer = setInterval(() => {
|
|
1802
|
+
if (fs.existsSync(zipPath)) {
|
|
1803
|
+
const stat = fs.statSync(zipPath);
|
|
1845
1804
|
const now = Date.now();
|
|
1846
1805
|
if (now - lastLogTime >= LOG_INTERVAL_MS) {
|
|
1847
|
-
|
|
1848
|
-
|
|
1806
|
+
logger.info(
|
|
1807
|
+
`[webui] 正在下载 WebUI dist... ${(stat.size / 1024 / 1024).toFixed(1)} MB 已下载`,
|
|
1808
|
+
);
|
|
1849
1809
|
lastLogTime = now;
|
|
1850
1810
|
}
|
|
1851
1811
|
}
|
|
1852
|
-
}
|
|
1853
|
-
}
|
|
1854
|
-
|
|
1855
|
-
if (contentLength > 0 && receivedBytes !== contentLength) {
|
|
1856
|
-
logger.warn(`[webui] 下载字节数不匹配: 预期 ${contentLength}, 实际 ${receivedBytes}`);
|
|
1857
|
-
}
|
|
1812
|
+
}, 1000);
|
|
1858
1813
|
|
|
1859
|
-
|
|
1814
|
+
// Clear timer when done
|
|
1815
|
+
curl.on("close", () => clearInterval(progressTimer));
|
|
1816
|
+
});
|
|
1860
1817
|
|
|
1861
|
-
const
|
|
1862
|
-
|
|
1818
|
+
const zipStat = fs.statSync(zipPath);
|
|
1819
|
+
logger.info(
|
|
1820
|
+
`[webui] 下载完成 (${(zipStat.size / 1024 / 1024).toFixed(1)} MB),正在解压...`,
|
|
1821
|
+
);
|
|
1863
1822
|
|
|
1864
1823
|
const zip = new AdmZip(zipPath);
|
|
1865
1824
|
zip.extractAllTo(unpackDir, true);
|
|
@@ -1911,6 +1870,8 @@ export async function updateWebUIDistFromRelease(): Promise<
|
|
|
1911
1870
|
error: "",
|
|
1912
1871
|
};
|
|
1913
1872
|
|
|
1873
|
+
await notifyOwnerWebUIDownloaded(check.latestVersion);
|
|
1874
|
+
|
|
1914
1875
|
return {
|
|
1915
1876
|
ok: true,
|
|
1916
1877
|
updated: true,
|