mioku-service-webui 4.0.7 → 4.0.9
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 +137 -167
package/package.json
CHANGED
package/system.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
WebUISettings,
|
|
14
14
|
} from "./types";
|
|
15
15
|
import {
|
|
16
|
+
AUTH_PATH,
|
|
16
17
|
CHAT_CONFIG_DIR,
|
|
17
18
|
defaultWebUISettings,
|
|
18
19
|
ensureDir,
|
|
@@ -32,6 +33,7 @@ import {
|
|
|
32
33
|
WEBUI_DIST,
|
|
33
34
|
writeJsonFile,
|
|
34
35
|
} from "./utils";
|
|
36
|
+
import { spawn } from "node:child_process";
|
|
35
37
|
|
|
36
38
|
async function fetchJson(url: string): Promise<any> {
|
|
37
39
|
const res = await fetch(url, {
|
|
@@ -516,17 +518,7 @@ async function getGitOriginUrl(dir: string): Promise<string> {
|
|
|
516
518
|
}
|
|
517
519
|
|
|
518
520
|
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];
|
|
521
|
+
return path.join(process.cwd(), "..", "mioku-webui");
|
|
530
522
|
}
|
|
531
523
|
|
|
532
524
|
function readInstalledWebUIVersion(): string {
|
|
@@ -1010,11 +1002,17 @@ export async function installManagedPackage(
|
|
|
1010
1002
|
...Object.keys(afterPkg?.devDependencies || {}),
|
|
1011
1003
|
];
|
|
1012
1004
|
const installedName =
|
|
1013
|
-
afterDeps.find(
|
|
1014
|
-
(name
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1005
|
+
afterDeps.find(
|
|
1006
|
+
(name) =>
|
|
1007
|
+
!beforeDeps.has(name) &&
|
|
1008
|
+
(name.startsWith("mioku-plugin-") || name.startsWith("mioku-service-")),
|
|
1009
|
+
) || pkgName;
|
|
1010
|
+
|
|
1011
|
+
const packageJsonPath = path.join(
|
|
1012
|
+
NODE_MODULES_DIR,
|
|
1013
|
+
installedName,
|
|
1014
|
+
"package.json",
|
|
1015
|
+
);
|
|
1018
1016
|
const packageJson = readPackageJson(packageJsonPath);
|
|
1019
1017
|
const missingServices = checkDependentServices(packageJson);
|
|
1020
1018
|
|
|
@@ -1500,19 +1498,20 @@ async function fetchLatestWebUIUpdate(
|
|
|
1500
1498
|
}
|
|
1501
1499
|
|
|
1502
1500
|
const job = (async () => {
|
|
1503
|
-
const projectDir = resolveWebUIProjectDir();
|
|
1504
1501
|
const currentVersion = readInstalledWebUIVersion();
|
|
1505
|
-
|
|
1506
|
-
const
|
|
1507
|
-
|
|
1508
|
-
|
|
1502
|
+
// mioku-webui repo is at mioku-lab/mioku-webui, used for GitHub API and dist download
|
|
1503
|
+
const repo = {
|
|
1504
|
+
owner: "mioku-lab",
|
|
1505
|
+
repo: "mioku-webui",
|
|
1506
|
+
fullName: "mioku-lab/mioku-webui",
|
|
1507
|
+
};
|
|
1509
1508
|
|
|
1510
1509
|
const fallback: WebUIUpdateCheckResult = {
|
|
1511
1510
|
currentVersion,
|
|
1512
1511
|
latestVersion: currentVersion,
|
|
1513
1512
|
releaseTag: "",
|
|
1514
1513
|
releaseUrl: "",
|
|
1515
|
-
sourceRepo: repo
|
|
1514
|
+
sourceRepo: repo.fullName,
|
|
1516
1515
|
hasUpdates: false,
|
|
1517
1516
|
canUpdate: false,
|
|
1518
1517
|
assetName: "",
|
|
@@ -1520,13 +1519,6 @@ async function fetchLatestWebUIUpdate(
|
|
|
1520
1519
|
checkedAt: Date.now(),
|
|
1521
1520
|
};
|
|
1522
1521
|
|
|
1523
|
-
if (!repo) {
|
|
1524
|
-
return {
|
|
1525
|
-
...fallback,
|
|
1526
|
-
error: "WebUI 仓库不是 GitHub,暂不支持自动检查更新",
|
|
1527
|
-
};
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
1522
|
const res = await fetch(
|
|
1531
1523
|
`https://api.github.com/repos/${repo.owner}/${repo.repo}/releases/latest`,
|
|
1532
1524
|
{
|
|
@@ -1612,101 +1604,36 @@ async function fetchLatestMiokuUpdate(
|
|
|
1612
1604
|
const cwd = process.cwd();
|
|
1613
1605
|
const rootPkg = readRootPackageJson() || {};
|
|
1614
1606
|
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
1607
|
|
|
1608
|
+
// Get latest version from npm registry
|
|
1686
1609
|
let latestVersion = currentVersion;
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
latestVersion = normalizeVersionSpec(parsed?.version || currentVersion);
|
|
1696
|
-
} catch {
|
|
1697
|
-
latestVersion = currentVersion;
|
|
1610
|
+
try {
|
|
1611
|
+
const latestOutput = await runCommand(
|
|
1612
|
+
"bun",
|
|
1613
|
+
["info", "mioku", "version"],
|
|
1614
|
+
cwd,
|
|
1615
|
+
);
|
|
1616
|
+
if (latestOutput.code === 0 && latestOutput.stdout.trim()) {
|
|
1617
|
+
latestVersion = normalizeVersionSpec(latestOutput.stdout.trim());
|
|
1698
1618
|
}
|
|
1619
|
+
} catch {
|
|
1620
|
+
// ignore - keep currentVersion as fallback
|
|
1699
1621
|
}
|
|
1700
1622
|
|
|
1623
|
+
const hasUpdates =
|
|
1624
|
+
latestVersion !== "unknown" &&
|
|
1625
|
+
currentVersion !== "unknown" &&
|
|
1626
|
+
isVersionNewer(latestVersion, currentVersion);
|
|
1627
|
+
|
|
1701
1628
|
return {
|
|
1702
1629
|
currentVersion,
|
|
1703
1630
|
latestVersion,
|
|
1704
|
-
sourceRepo:
|
|
1705
|
-
currentBranch,
|
|
1706
|
-
targetRef,
|
|
1707
|
-
hasUpdates
|
|
1708
|
-
behind,
|
|
1709
|
-
changelog:
|
|
1631
|
+
sourceRepo: "mioku",
|
|
1632
|
+
currentBranch: "",
|
|
1633
|
+
targetRef: "",
|
|
1634
|
+
hasUpdates,
|
|
1635
|
+
behind: hasUpdates ? 1 : 0,
|
|
1636
|
+
changelog: [],
|
|
1710
1637
|
checkedAt: Date.now(),
|
|
1711
1638
|
error: "",
|
|
1712
1639
|
};
|
|
@@ -1730,24 +1657,18 @@ export async function checkMiokuReleaseUpdate(
|
|
|
1730
1657
|
|
|
1731
1658
|
export async function updateMiokuFromMain(): Promise<Record<string, any>> {
|
|
1732
1659
|
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
1660
|
|
|
1741
|
-
const
|
|
1742
|
-
const
|
|
1743
|
-
const pull = await runCommand("git", ["pull", "origin", targetBranch], cwd);
|
|
1661
|
+
const beforePkg = readRootPackageJson();
|
|
1662
|
+
const beforeVersion = beforePkg?.version || "unknown";
|
|
1744
1663
|
|
|
1745
|
-
|
|
1746
|
-
|
|
1664
|
+
const update = await runCommand("bun", ["update", "mioku"], cwd);
|
|
1665
|
+
if (update.code !== 0) {
|
|
1666
|
+
throw new Error(`bun update mioku 失败: ${update.stderr || update.stdout}`);
|
|
1747
1667
|
}
|
|
1748
1668
|
|
|
1749
|
-
const
|
|
1750
|
-
const
|
|
1669
|
+
const afterPkg = readRootPackageJson();
|
|
1670
|
+
const afterVersion = afterPkg?.version || beforeVersion;
|
|
1671
|
+
const changed = beforeVersion !== afterVersion;
|
|
1751
1672
|
|
|
1752
1673
|
let reinstallOutput = "";
|
|
1753
1674
|
if (changed) {
|
|
@@ -1773,6 +1694,41 @@ export async function updateMiokuFromMain(): Promise<Record<string, any>> {
|
|
|
1773
1694
|
};
|
|
1774
1695
|
}
|
|
1775
1696
|
|
|
1697
|
+
async function notifyOwnerWebUIDownloaded(version: string): Promise<void> {
|
|
1698
|
+
const miokuConfig = getMiokuConfig();
|
|
1699
|
+
const owners = miokuConfig?.owners || [];
|
|
1700
|
+
if (owners.length === 0) {
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
const bots = Array.from(connectedBots.values());
|
|
1705
|
+
if (bots.length === 0) {
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
const bot = bots[0];
|
|
1710
|
+
const settings = getWebUISettings();
|
|
1711
|
+
const auth = readJsonFile<{ token?: string }>(AUTH_PATH, {});
|
|
1712
|
+
const url = `http://${settings.host}:${settings.port}`;
|
|
1713
|
+
const token = auth?.token || "未设置";
|
|
1714
|
+
const message = [
|
|
1715
|
+
`🎉 WebUI v${version} 已就绪`,
|
|
1716
|
+
`地址: ${url}`,
|
|
1717
|
+
`鉴权密钥: ${token}`,
|
|
1718
|
+
].join("\n");
|
|
1719
|
+
|
|
1720
|
+
for (const ownerId of owners) {
|
|
1721
|
+
try {
|
|
1722
|
+
await bot.api("send_private_msg", {
|
|
1723
|
+
user_id: Number(ownerId),
|
|
1724
|
+
message,
|
|
1725
|
+
});
|
|
1726
|
+
} catch (err: any) {
|
|
1727
|
+
logger.warn(`[webui] 通知主人 ${ownerId} 失败: ${err?.message || err}`);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1776
1732
|
export async function updateWebUIDistFromRelease(): Promise<
|
|
1777
1733
|
Record<string, any>
|
|
1778
1734
|
> {
|
|
@@ -1800,7 +1756,7 @@ export async function updateWebUIDistFromRelease(): Promise<
|
|
|
1800
1756
|
|
|
1801
1757
|
let lastLogTime = 0;
|
|
1802
1758
|
const LOG_INTERVAL_MS = 2000;
|
|
1803
|
-
const downloadUrl =
|
|
1759
|
+
const downloadUrl = check.assetUrl;
|
|
1804
1760
|
const tempDir = path.join(
|
|
1805
1761
|
os.tmpdir(),
|
|
1806
1762
|
`mioku-webui-update-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
@@ -1813,53 +1769,65 @@ export async function updateWebUIDistFromRelease(): Promise<
|
|
|
1813
1769
|
|
|
1814
1770
|
let backupPath = "";
|
|
1815
1771
|
try {
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1772
|
+
logger.info(`[webui] 正在下载 WebUI dist...`);
|
|
1773
|
+
|
|
1774
|
+
await new Promise<void>((resolve, reject) => {
|
|
1775
|
+
const curl = spawn(
|
|
1776
|
+
"curl",
|
|
1777
|
+
[
|
|
1778
|
+
"-L",
|
|
1779
|
+
"-o",
|
|
1780
|
+
zipPath,
|
|
1781
|
+
"-A",
|
|
1782
|
+
"mioku-webui-updater/1.0",
|
|
1783
|
+
"--silent",
|
|
1784
|
+
"--show-error",
|
|
1785
|
+
downloadUrl,
|
|
1786
|
+
],
|
|
1787
|
+
{
|
|
1788
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1789
|
+
},
|
|
1790
|
+
);
|
|
1832
1791
|
|
|
1833
|
-
|
|
1834
|
-
|
|
1792
|
+
let stderr = "";
|
|
1793
|
+
curl.stderr.on("data", (chunk) => {
|
|
1794
|
+
stderr += String(chunk);
|
|
1795
|
+
});
|
|
1835
1796
|
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1797
|
+
curl.on("close", (code) => {
|
|
1798
|
+
if (code === 0) {
|
|
1799
|
+
resolve();
|
|
1800
|
+
} else {
|
|
1801
|
+
reject(new Error(`curl 下载失败 (code ${code}): ${stderr}`));
|
|
1802
|
+
}
|
|
1803
|
+
});
|
|
1839
1804
|
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1805
|
+
curl.on("error", (err) => {
|
|
1806
|
+
reject(new Error(`curl 进程异常: ${err.message}`));
|
|
1807
|
+
});
|
|
1843
1808
|
|
|
1844
|
-
|
|
1809
|
+
// Periodically log progress by checking file size
|
|
1810
|
+
const progressTimer = setInterval(() => {
|
|
1811
|
+
if (fs.existsSync(zipPath)) {
|
|
1812
|
+
const stat = fs.statSync(zipPath);
|
|
1845
1813
|
const now = Date.now();
|
|
1846
1814
|
if (now - lastLogTime >= LOG_INTERVAL_MS) {
|
|
1847
|
-
|
|
1848
|
-
|
|
1815
|
+
logger.info(
|
|
1816
|
+
`[webui] 正在下载 WebUI dist... ${(stat.size / 1024 / 1024).toFixed(1)} MB 已下载`,
|
|
1817
|
+
);
|
|
1849
1818
|
lastLogTime = now;
|
|
1850
1819
|
}
|
|
1851
1820
|
}
|
|
1852
|
-
}
|
|
1853
|
-
}
|
|
1854
|
-
|
|
1855
|
-
if (contentLength > 0 && receivedBytes !== contentLength) {
|
|
1856
|
-
logger.warn(`[webui] 下载字节数不匹配: 预期 ${contentLength}, 实际 ${receivedBytes}`);
|
|
1857
|
-
}
|
|
1821
|
+
}, 1000);
|
|
1858
1822
|
|
|
1859
|
-
|
|
1823
|
+
// Clear timer when done
|
|
1824
|
+
curl.on("close", () => clearInterval(progressTimer));
|
|
1825
|
+
});
|
|
1860
1826
|
|
|
1861
|
-
const
|
|
1862
|
-
|
|
1827
|
+
const zipStat = fs.statSync(zipPath);
|
|
1828
|
+
logger.info(
|
|
1829
|
+
`[webui] 下载完成 (${(zipStat.size / 1024 / 1024).toFixed(1)} MB),正在解压...`,
|
|
1830
|
+
);
|
|
1863
1831
|
|
|
1864
1832
|
const zip = new AdmZip(zipPath);
|
|
1865
1833
|
zip.extractAllTo(unpackDir, true);
|
|
@@ -1911,6 +1879,8 @@ export async function updateWebUIDistFromRelease(): Promise<
|
|
|
1911
1879
|
error: "",
|
|
1912
1880
|
};
|
|
1913
1881
|
|
|
1882
|
+
await notifyOwnerWebUIDownloaded(check.latestVersion);
|
|
1883
|
+
|
|
1914
1884
|
return {
|
|
1915
1885
|
ok: true,
|
|
1916
1886
|
updated: true,
|