karin-plugin-kkk 2.44.1 → 2.45.0-beta.3
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/CHANGELOG.md +64 -0
- package/config/default_config/app.yaml +4 -0
- package/config/default_config/config.json +42 -7
- package/lib/build-metadata.json +5 -5
- package/lib/core_chunk/main.js +717 -45
- package/lib/style.css +49 -0
- package/lib/web/assets/{CronEditor-7jONBXc7.js → CronEditor-B8UDHt0_.js} +1 -1
- package/lib/web/assets/{DesktopLayout-DBoDs9Vs.js → DesktopLayout-drMRNCzE.js} +1 -1
- package/lib/web/assets/{MobileLayout-DRRbkB4n.js → MobileLayout-DVcUuYNA.js} +1 -1
- package/lib/web/assets/{ThemeSwitch-CwRb5j8E.js → ThemeSwitch-CtOTxsWS.js} +1 -1
- package/lib/web/assets/{index-C6OKJLTC.js → index-CKFMwQze.js} +2 -2
- package/lib/web/assets/{separator-DpAAkxFR.js → separator-CRsEEbKb.js} +1 -1
- package/lib/web/index.html +1 -1
- package/package.json +2 -2
package/lib/core_chunk/main.js
CHANGED
|
@@ -6,7 +6,7 @@ import { createRequire } from "node:module";
|
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
import path, { resolve } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
-
import karin, { BOT_CONNECT, app, authMiddleware, checkPkgUpdate, common, config, createBadRequestResponse, createNotFoundResponse, createServerErrorResponse, createSuccessResponse, db, defineConfig, ffmpeg, ffprobe, hooks, isDocker, karin as karin$1, karinPathHtml, logger, logs, mkdirSync, parseChangelog, range, render, restart, segment, updatePkg, watch } from "node-karin";
|
|
9
|
+
import karin, { BOT_CONNECT, app, authMiddleware, checkPkgUpdate, common, config, createBadRequestResponse, createNotFoundResponse, createServerErrorResponse, createSuccessResponse, db, defineConfig, exec, ffmpeg, ffprobe, getPkgVersion, getRemotePkgVersion, hooks, isDocker, karin as karin$1, karinPathHtml, logger, logs, mkdirSync, parseChangelog, range, render, restart, segment, updatePkg, watch } from "node-karin";
|
|
10
10
|
import crypto from "node:crypto";
|
|
11
11
|
import { deflateSync, inflateSync } from "node:zlib";
|
|
12
12
|
import express from "node-karin/express";
|
|
@@ -7433,6 +7433,26 @@ var resolveEmojiSrc = (filename) => {
|
|
|
7433
7433
|
};
|
|
7434
7434
|
setUnicodeEmojiSrcResolver(resolveEmojiSrc);
|
|
7435
7435
|
//#endregion
|
|
7436
|
+
//#region src/module/utils/releaseChannel.ts
|
|
7437
|
+
var parseReleaseChannel = (version) => {
|
|
7438
|
+
const v = version.trim().replace(/^[vV]/, "").split("+", 1)[0];
|
|
7439
|
+
const match = /^\d+\.\d+\.\d+(?:-(.+))?$/.exec(v);
|
|
7440
|
+
if (!match) return "Canary";
|
|
7441
|
+
if (!match[1]) return "Stable";
|
|
7442
|
+
const pre = match[1].split(".");
|
|
7443
|
+
if (pre[0] === "rc") return "Rc";
|
|
7444
|
+
if (pre[0] === "canary") return "Canary";
|
|
7445
|
+
if (pre[0] === "beta" && pre.length <= 2) return "Beta";
|
|
7446
|
+
return "Canary";
|
|
7447
|
+
};
|
|
7448
|
+
/** 渠道显示名(中文) */
|
|
7449
|
+
var RELEASE_CHANNEL_LABEL = {
|
|
7450
|
+
Stable: "正式版",
|
|
7451
|
+
Beta: "测试版",
|
|
7452
|
+
Rc: "预览版",
|
|
7453
|
+
Canary: "金丝雀"
|
|
7454
|
+
};
|
|
7455
|
+
//#endregion
|
|
7436
7456
|
//#region src/module/utils/semver.ts
|
|
7437
7457
|
/**
|
|
7438
7458
|
* 语义化版本比较
|
|
@@ -7832,7 +7852,7 @@ var Render = async (event, path, data) => {
|
|
|
7832
7852
|
plugin: "karin-plugin",
|
|
7833
7853
|
pluginName: "kkk",
|
|
7834
7854
|
pluginVersion: Root.pluginVersion,
|
|
7835
|
-
releaseType:
|
|
7855
|
+
releaseType: parseReleaseChannel(Root.pluginVersion),
|
|
7836
7856
|
poweredBy: "Karin",
|
|
7837
7857
|
frameworkVersion: Root.karinVersion,
|
|
7838
7858
|
hasUpdate
|
|
@@ -11413,6 +11433,15 @@ var ViteLogo = ({ className = "w-auto h-12" }) => /* @__PURE__ */ (0, import_jsx
|
|
|
11413
11433
|
* @param props 组件属性
|
|
11414
11434
|
* @returns JSX元素
|
|
11415
11435
|
*/
|
|
11436
|
+
/**
|
|
11437
|
+
* 渠道徽章文案:ctx.version.releaseType → 中文渠道名(未知值回显原值兜底)
|
|
11438
|
+
*/
|
|
11439
|
+
var RELEASE_TYPE_LABEL = {
|
|
11440
|
+
Stable: "正式版",
|
|
11441
|
+
Beta: "测试版",
|
|
11442
|
+
Rc: "预览版",
|
|
11443
|
+
Canary: "金丝雀"
|
|
11444
|
+
};
|
|
11416
11445
|
var DefaultLayout = ({ children, ctx, className = "", style = {} }) => {
|
|
11417
11446
|
const useDarkTheme = isDark(ctx);
|
|
11418
11447
|
const { version } = ctx;
|
|
@@ -11480,21 +11509,21 @@ var DefaultLayout = ({ children, ctx, className = "", style = {} }) => {
|
|
|
11480
11509
|
strokeWidth: 3,
|
|
11481
11510
|
className: "w-4 h-4"
|
|
11482
11511
|
}),
|
|
11483
|
-
!version.hasUpdate && version.releaseType === "
|
|
11512
|
+
!version.hasUpdate && (version.releaseType === "Beta" || version.releaseType === "Rc") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, {
|
|
11484
11513
|
strokeWidth: 3,
|
|
11485
11514
|
className: "w-4 h-4 text-warning"
|
|
11486
11515
|
}),
|
|
11487
|
-
!version.hasUpdate && version.releaseType
|
|
11516
|
+
!version.hasUpdate && version.releaseType === "Canary" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Info, {
|
|
11488
11517
|
strokeWidth: 3,
|
|
11489
11518
|
className: "w-4 h-4"
|
|
11490
11519
|
}),
|
|
11491
11520
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
11492
|
-
className: cn(version.hasUpdate && "text-success", !version.hasUpdate && version.releaseType === "
|
|
11493
|
-
children: version.hasUpdate ? "有可用更新" : version.releaseType
|
|
11521
|
+
className: cn(version.hasUpdate && "text-success", !version.hasUpdate && (version.releaseType === "Beta" || version.releaseType === "Rc") && "text-warning"),
|
|
11522
|
+
children: version.hasUpdate ? "有可用更新" : RELEASE_TYPE_LABEL[version.releaseType] ?? version.releaseType
|
|
11494
11523
|
})
|
|
11495
11524
|
]
|
|
11496
11525
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
11497
|
-
className: cn("text-5xl font-bold tracking-wide", version.hasUpdate && "text-success", !version.hasUpdate && version.releaseType === "
|
|
11526
|
+
className: cn("text-5xl font-bold tracking-wide", version.hasUpdate && "text-success", !version.hasUpdate && (version.releaseType === "Beta" || version.releaseType === "Rc") && "text-warning"),
|
|
11498
11527
|
children: ["v", version.pluginVersion]
|
|
11499
11528
|
})]
|
|
11500
11529
|
}),
|
|
@@ -23944,7 +23973,7 @@ var qrlogin_default = defineTemplate({
|
|
|
23944
23973
|
var RuntimeReport = import_react.memo((props) => {
|
|
23945
23974
|
const { data } = props;
|
|
23946
23975
|
const dark = isDark(props.ctx);
|
|
23947
|
-
const releaseLabel = data.identity.releaseType
|
|
23976
|
+
const releaseLabel = RELEASE_TYPE_LABEL[data.identity.releaseType] ?? data.identity.releaseType;
|
|
23948
23977
|
const buildStatus = data.build.state === "matched" ? {
|
|
23949
23978
|
label: "构建信息一致",
|
|
23950
23979
|
icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CircleCheck, { className: "h-8 w-8" }),
|
|
@@ -24412,6 +24441,463 @@ var runtime_default = defineTemplate({
|
|
|
24412
24441
|
component: RuntimeReport
|
|
24413
24442
|
});
|
|
24414
24443
|
//#endregion
|
|
24444
|
+
//#region ktr/template/other/updateHelp/components/updateHelp.tsx
|
|
24445
|
+
/**
|
|
24446
|
+
* `#kkk更新` 用法面板(kkk-design 系统 B × Apple 排版原则)。
|
|
24447
|
+
*
|
|
24448
|
+
* 主情绪色为深青(teal)——紫罗兰系在 runtime/更新日志等模板已被占用,避开色彩同质化。
|
|
24449
|
+
* 构图:横向 Hero 带(左主标题、右当前安装版本,版本号按长度分级缩放防溢出)→
|
|
24450
|
+
* 表格式渠道清单(固定列宽 grid,命令列纵向对齐)→ 命令→说明单行对。
|
|
24451
|
+
* 状态为完整 semver 比较:有更新 / 已是最新 / 低于当前版本三分,而非笼统布尔。
|
|
24452
|
+
* 噪点沿用 runtime 的高对比离散颗粒(深色 0.16 / 浅色 0.12)。
|
|
24453
|
+
*/
|
|
24454
|
+
/** 完整 semver 比较(core 数字 + prerelease 段,规则与 core 的 semver.ts 一致) */
|
|
24455
|
+
var semverCompare = (a, b) => {
|
|
24456
|
+
const parse = (v) => {
|
|
24457
|
+
const [core, pre] = v.trim().replace(/^[vV]/, "").split("+")[0].split("-");
|
|
24458
|
+
const [maj, min, pat] = core.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
24459
|
+
return {
|
|
24460
|
+
maj,
|
|
24461
|
+
min,
|
|
24462
|
+
pat,
|
|
24463
|
+
pre: pre ? pre.split(".") : []
|
|
24464
|
+
};
|
|
24465
|
+
};
|
|
24466
|
+
const p = parse(a);
|
|
24467
|
+
const q = parse(b);
|
|
24468
|
+
if (p.maj !== q.maj) return p.maj - q.maj;
|
|
24469
|
+
if (p.min !== q.min) return p.min - q.min;
|
|
24470
|
+
if (p.pat !== q.pat) return p.pat - q.pat;
|
|
24471
|
+
if (p.pre.length === 0 && q.pre.length === 0) return 0;
|
|
24472
|
+
if (p.pre.length === 0) return 1;
|
|
24473
|
+
if (q.pre.length === 0) return -1;
|
|
24474
|
+
const len = Math.min(p.pre.length, q.pre.length);
|
|
24475
|
+
for (let i = 0; i < len; i++) {
|
|
24476
|
+
const an = /^\d+$/.test(p.pre[i]);
|
|
24477
|
+
const bn = /^\d+$/.test(q.pre[i]);
|
|
24478
|
+
if (an !== bn) return an ? -1 : 1;
|
|
24479
|
+
if (p.pre[i] !== q.pre[i]) {
|
|
24480
|
+
if (an && bn) return Number(p.pre[i]) - Number(q.pre[i]);
|
|
24481
|
+
return p.pre[i] > q.pre[i] ? 1 : -1;
|
|
24482
|
+
}
|
|
24483
|
+
}
|
|
24484
|
+
return p.pre.length === q.pre.length ? 0 : p.pre.length > q.pre.length ? 1 : -1;
|
|
24485
|
+
};
|
|
24486
|
+
/**
|
|
24487
|
+
* Hero 版本号布局:
|
|
24488
|
+
* - 短版本(纯 semver,≤6 字符)与主标题同行横排,150px;
|
|
24489
|
+
* - 长版本(canary 等 prerelease)独占整行堆叠在标题下方,字号按「可用宽 1180px ÷
|
|
24490
|
+
* 等宽字符宽 0.6em」自适应,上限仍 150px——标题与版本号不再挤同一行。
|
|
24491
|
+
*/
|
|
24492
|
+
var heroStacked = (version) => version.trim().replace(/^[vV]/, "").length > 6;
|
|
24493
|
+
var heroVersionSize = (version) => {
|
|
24494
|
+
const len = version.trim().replace(/^[vV]/, "").length;
|
|
24495
|
+
if (len <= 6) return 150;
|
|
24496
|
+
return Math.max(72, Math.min(150, Math.floor(1180 / (len * .6))));
|
|
24497
|
+
};
|
|
24498
|
+
//#endregion
|
|
24499
|
+
//#region ktr/template/other/updateHelp/index.tsx
|
|
24500
|
+
var updateHelp_default = defineTemplate({
|
|
24501
|
+
name: "更新渠道面板",
|
|
24502
|
+
description: "#kkk更新 用法与各渠道可用版本一览",
|
|
24503
|
+
component: import_react.memo((props) => {
|
|
24504
|
+
const { data } = props;
|
|
24505
|
+
const palette = isDark(props.ctx) ? {
|
|
24506
|
+
background: "#081416",
|
|
24507
|
+
glowPrimary: "rgba(45, 212, 191, 0.28)",
|
|
24508
|
+
glowSecondary: "rgba(56, 130, 246, 0.14)",
|
|
24509
|
+
glowWarm: "rgba(250, 204, 21, 0.12)",
|
|
24510
|
+
bgWord: "#99f6e4",
|
|
24511
|
+
ink: "#effefd",
|
|
24512
|
+
muted: "rgba(239, 254, 253, 0.62)",
|
|
24513
|
+
faint: "rgba(239, 254, 253, 0.36)",
|
|
24514
|
+
pillBg: "rgba(45, 212, 191, 0.12)",
|
|
24515
|
+
pillBorder: "rgba(94, 234, 212, 0.32)",
|
|
24516
|
+
pillText: "#5eead4",
|
|
24517
|
+
accentText: "#5eead4",
|
|
24518
|
+
success: "#4ade80",
|
|
24519
|
+
warning: "#fbbf24",
|
|
24520
|
+
noiseOpacity: .16
|
|
24521
|
+
} : {
|
|
24522
|
+
background: "#effaf8",
|
|
24523
|
+
glowPrimary: "rgba(20, 184, 166, 0.26)",
|
|
24524
|
+
glowSecondary: "rgba(125, 211, 252, 0.40)",
|
|
24525
|
+
glowWarm: "rgba(250, 204, 21, 0.26)",
|
|
24526
|
+
bgWord: "#0c3b38",
|
|
24527
|
+
ink: "#0c3b38",
|
|
24528
|
+
muted: "rgba(12, 59, 56, 0.68)",
|
|
24529
|
+
faint: "rgba(12, 59, 56, 0.42)",
|
|
24530
|
+
pillBg: "rgba(20, 184, 166, 0.10)",
|
|
24531
|
+
pillBorder: "rgba(20, 184, 166, 0.30)",
|
|
24532
|
+
pillText: "#0f766e",
|
|
24533
|
+
accentText: "#0d9488",
|
|
24534
|
+
success: "#15803d",
|
|
24535
|
+
warning: "#8a5a06",
|
|
24536
|
+
noiseOpacity: .12
|
|
24537
|
+
};
|
|
24538
|
+
/**
|
|
24539
|
+
* 渠道状态:文案按具体状态区分(有更新 / 已是最新 / 低于当前版本 / 暂未发布 / 获取失败),
|
|
24540
|
+
* 颜色只分两档 —— 可升级(success)与置灰(faint):非可升级状态一律不引导行动。
|
|
24541
|
+
* active 供行内所有元素同步置灰。
|
|
24542
|
+
*/
|
|
24543
|
+
const statusView = (channel) => {
|
|
24544
|
+
if (channel.status === "missing") return {
|
|
24545
|
+
dot: palette.faint,
|
|
24546
|
+
text: "该渠道暂未发布",
|
|
24547
|
+
active: false
|
|
24548
|
+
};
|
|
24549
|
+
if (channel.status === "error") return {
|
|
24550
|
+
dot: palette.faint,
|
|
24551
|
+
text: "获取失败",
|
|
24552
|
+
active: false
|
|
24553
|
+
};
|
|
24554
|
+
if (channel.status === "canary") return channel.hasUpdate ? {
|
|
24555
|
+
dot: palette.success,
|
|
24556
|
+
text: "有新构建可升级",
|
|
24557
|
+
active: true
|
|
24558
|
+
} : {
|
|
24559
|
+
dot: palette.accentText,
|
|
24560
|
+
text: "main 分支构建",
|
|
24561
|
+
active: true
|
|
24562
|
+
};
|
|
24563
|
+
const order = semverCompare(channel.version ?? "0.0.0", data.currentVersion);
|
|
24564
|
+
if (order > 0) return {
|
|
24565
|
+
dot: palette.success,
|
|
24566
|
+
text: "有更新可升级",
|
|
24567
|
+
active: true
|
|
24568
|
+
};
|
|
24569
|
+
if (order === 0) return {
|
|
24570
|
+
dot: palette.faint,
|
|
24571
|
+
text: "已是最新",
|
|
24572
|
+
active: false
|
|
24573
|
+
};
|
|
24574
|
+
return {
|
|
24575
|
+
dot: palette.faint,
|
|
24576
|
+
text: "低于当前版本",
|
|
24577
|
+
active: false
|
|
24578
|
+
};
|
|
24579
|
+
};
|
|
24580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DefaultLayout, {
|
|
24581
|
+
...props,
|
|
24582
|
+
className: "relative min-h-440 overflow-hidden",
|
|
24583
|
+
style: { backgroundColor: palette.background },
|
|
24584
|
+
children: [
|
|
24585
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24586
|
+
className: "pointer-events-none absolute inset-0 z-0 overflow-hidden",
|
|
24587
|
+
children: [
|
|
24588
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
24589
|
+
className: "absolute -left-130 -top-120 h-337.5 w-375 rounded-full blur-[230px]",
|
|
24590
|
+
style: { background: `radial-gradient(ellipse at center, ${palette.glowPrimary} 0%, transparent 70%)` }
|
|
24591
|
+
}),
|
|
24592
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
24593
|
+
className: "absolute -right-130 top-[36%] h-312.5 w-300 rounded-full blur-[240px]",
|
|
24594
|
+
style: { background: `radial-gradient(ellipse at center, ${palette.glowSecondary} 0%, transparent 72%)` }
|
|
24595
|
+
}),
|
|
24596
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
24597
|
+
className: "absolute -bottom-120 -left-80 h-287.5 w-337.5 rounded-full blur-[260px]",
|
|
24598
|
+
style: { background: `radial-gradient(ellipse at center, ${palette.glowWarm} 0%, transparent 72%)` }
|
|
24599
|
+
}),
|
|
24600
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
24601
|
+
className: "pointer-events-none absolute right-14 top-8 select-none font-bold leading-none tracking-[-0.02em]",
|
|
24602
|
+
style: {
|
|
24603
|
+
fontSize: "220px",
|
|
24604
|
+
opacity: .04,
|
|
24605
|
+
color: palette.bgWord
|
|
24606
|
+
},
|
|
24607
|
+
children: "UPDATE"
|
|
24608
|
+
})
|
|
24609
|
+
]
|
|
24610
|
+
}),
|
|
24611
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
24612
|
+
className: "pointer-events-none absolute inset-0 z-0",
|
|
24613
|
+
style: { opacity: palette.noiseOpacity },
|
|
24614
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
|
|
24615
|
+
className: "h-full w-full",
|
|
24616
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
24617
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("filter", {
|
|
24618
|
+
id: "updateHelpNoise",
|
|
24619
|
+
x: "0%",
|
|
24620
|
+
y: "0%",
|
|
24621
|
+
width: "100%",
|
|
24622
|
+
height: "100%",
|
|
24623
|
+
children: [
|
|
24624
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feTurbulence", {
|
|
24625
|
+
type: "fractalNoise",
|
|
24626
|
+
baseFrequency: "0.8",
|
|
24627
|
+
numOctaves: "1",
|
|
24628
|
+
stitchTiles: "stitch",
|
|
24629
|
+
result: "noise"
|
|
24630
|
+
}),
|
|
24631
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feColorMatrix", {
|
|
24632
|
+
type: "saturate",
|
|
24633
|
+
values: "0",
|
|
24634
|
+
result: "gray"
|
|
24635
|
+
}),
|
|
24636
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("feComponentTransfer", { children: [
|
|
24637
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncR", {
|
|
24638
|
+
type: "discrete",
|
|
24639
|
+
tableValues: "0 1"
|
|
24640
|
+
}),
|
|
24641
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncG", {
|
|
24642
|
+
type: "discrete",
|
|
24643
|
+
tableValues: "0 1"
|
|
24644
|
+
}),
|
|
24645
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("feFuncB", {
|
|
24646
|
+
type: "discrete",
|
|
24647
|
+
tableValues: "0 1"
|
|
24648
|
+
})
|
|
24649
|
+
] })
|
|
24650
|
+
]
|
|
24651
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
|
|
24652
|
+
width: "100%",
|
|
24653
|
+
height: "100%",
|
|
24654
|
+
filter: "url(#updateHelpNoise)"
|
|
24655
|
+
})]
|
|
24656
|
+
})
|
|
24657
|
+
}),
|
|
24658
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", {
|
|
24659
|
+
className: "relative z-10 px-22 pb-16 pt-20",
|
|
24660
|
+
children: [
|
|
24661
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
|
|
24662
|
+
className: "relative flex items-center justify-between gap-12",
|
|
24663
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24664
|
+
className: "flex items-center gap-4",
|
|
24665
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24666
|
+
className: "h-3 w-3 rounded-full",
|
|
24667
|
+
style: { background: palette.accentText }
|
|
24668
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24669
|
+
className: "whitespace-nowrap text-[24px] font-bold tracking-[0.28em] text-foreground/44",
|
|
24670
|
+
children: "更新面板 · UPDATE PANEL"
|
|
24671
|
+
})]
|
|
24672
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24673
|
+
className: "whitespace-nowrap rounded-full border px-6 py-2 text-[22px] font-bold tracking-[0.14em]",
|
|
24674
|
+
style: {
|
|
24675
|
+
borderColor: palette.pillBorder,
|
|
24676
|
+
background: palette.pillBg,
|
|
24677
|
+
color: palette.pillText
|
|
24678
|
+
},
|
|
24679
|
+
children: data.currentChannel
|
|
24680
|
+
})]
|
|
24681
|
+
}),
|
|
24682
|
+
heroStacked(data.currentVersion) ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
|
|
24683
|
+
className: "whitespace-nowrap text-[96px] font-bold leading-[1.04] tracking-[-0.02em] text-foreground",
|
|
24684
|
+
children: "更新渠道"
|
|
24685
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
24686
|
+
className: "mt-6 whitespace-nowrap text-[30px] font-semibold text-foreground/48",
|
|
24687
|
+
children: data.currentChannel === "金丝雀" ? "金丝雀构建跟随 main 分支实时发布,可随时切换回正式渠道" : "各渠道可用版本与 #kkk更新 用法一览"
|
|
24688
|
+
})] }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24689
|
+
className: "relative mt-14",
|
|
24690
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
24691
|
+
className: "text-[22px] font-bold uppercase tracking-[0.22em] text-foreground/36",
|
|
24692
|
+
children: "当前安装 · INSTALLED"
|
|
24693
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24694
|
+
className: "mt-4 whitespace-nowrap font-mono font-bold leading-none tracking-[-0.05em] tabular-nums text-foreground",
|
|
24695
|
+
style: { fontSize: `${heroVersionSize(data.currentVersion)}px` },
|
|
24696
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24697
|
+
className: "mr-3 align-top text-[0.42em] font-bold text-foreground/40",
|
|
24698
|
+
children: "v"
|
|
24699
|
+
}), data.currentVersion]
|
|
24700
|
+
})]
|
|
24701
|
+
})] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24702
|
+
className: "relative mt-14 flex items-end justify-between gap-12",
|
|
24703
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
|
|
24704
|
+
className: "whitespace-nowrap text-[96px] font-bold leading-[1.04] tracking-[-0.02em] text-foreground",
|
|
24705
|
+
children: "更新渠道"
|
|
24706
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
24707
|
+
className: "mt-6 whitespace-nowrap text-[30px] font-semibold text-foreground/48",
|
|
24708
|
+
children: data.currentChannel === "金丝雀" ? "金丝雀构建跟随 main 分支实时发布,可随时切换回正式渠道" : "各渠道可用版本与 #kkk更新 用法一览"
|
|
24709
|
+
})] }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24710
|
+
className: "flex shrink-0 flex-col items-end",
|
|
24711
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
24712
|
+
className: "text-[22px] font-bold uppercase tracking-[0.22em] text-foreground/36",
|
|
24713
|
+
children: "当前安装 · INSTALLED"
|
|
24714
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24715
|
+
className: "mt-4 whitespace-nowrap font-mono font-bold leading-none tracking-[-0.05em] tabular-nums text-foreground",
|
|
24716
|
+
style: { fontSize: `${heroVersionSize(data.currentVersion)}px` },
|
|
24717
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24718
|
+
className: "mr-3 align-top text-[0.42em] font-bold text-foreground/40",
|
|
24719
|
+
children: "v"
|
|
24720
|
+
}), data.currentVersion]
|
|
24721
|
+
})]
|
|
24722
|
+
})]
|
|
24723
|
+
}),
|
|
24724
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
24725
|
+
className: "relative mt-24",
|
|
24726
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24727
|
+
className: "flex items-center gap-4",
|
|
24728
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24729
|
+
className: "h-3 w-3 rounded-full",
|
|
24730
|
+
style: { background: palette.accentText }
|
|
24731
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24732
|
+
className: "text-[24px] font-bold tracking-[0.28em] text-foreground/44",
|
|
24733
|
+
children: "可用版本 · AVAILABLE"
|
|
24734
|
+
})]
|
|
24735
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
24736
|
+
className: "mt-12 flex flex-col gap-14",
|
|
24737
|
+
children: data.channels.map((channel) => {
|
|
24738
|
+
const status = statusView(channel);
|
|
24739
|
+
const publishedDate = channel.publishedAt ? new Date(channel.publishedAt) : void 0;
|
|
24740
|
+
if (channel.status === "canary") return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24741
|
+
className: "flex flex-col gap-4",
|
|
24742
|
+
children: [
|
|
24743
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24744
|
+
className: "flex items-center justify-between gap-10",
|
|
24745
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24746
|
+
className: "flex items-center gap-4",
|
|
24747
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24748
|
+
className: "whitespace-nowrap text-[30px] font-semibold",
|
|
24749
|
+
style: { color: status.active ? palette.muted : palette.faint },
|
|
24750
|
+
children: channel.label
|
|
24751
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24752
|
+
className: "whitespace-nowrap rounded-full border px-4 py-0.5 font-mono text-[20px] font-semibold",
|
|
24753
|
+
style: {
|
|
24754
|
+
borderColor: palette.pillBorder,
|
|
24755
|
+
background: palette.pillBg,
|
|
24756
|
+
color: status.active ? palette.pillText : palette.faint
|
|
24757
|
+
},
|
|
24758
|
+
children: channel.tag
|
|
24759
|
+
})]
|
|
24760
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24761
|
+
className: "flex items-center gap-6",
|
|
24762
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24763
|
+
className: "whitespace-nowrap font-mono text-[46px] font-bold leading-none",
|
|
24764
|
+
style: { color: status.active ? palette.ink : palette.faint },
|
|
24765
|
+
children: channel.version
|
|
24766
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
24767
|
+
className: "flex items-center gap-3 whitespace-nowrap text-[24px] font-semibold",
|
|
24768
|
+
style: { color: status.dot },
|
|
24769
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24770
|
+
className: "h-2.5 w-2.5 rounded-full",
|
|
24771
|
+
style: { background: status.dot }
|
|
24772
|
+
}), status.text]
|
|
24773
|
+
})]
|
|
24774
|
+
})]
|
|
24775
|
+
}),
|
|
24776
|
+
channel.installCommand && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
24777
|
+
className: "whitespace-nowrap rounded-3xl px-7 py-4 font-mono text-[27px] font-semibold",
|
|
24778
|
+
style: {
|
|
24779
|
+
background: status.active ? palette.pillBg : "transparent",
|
|
24780
|
+
color: status.active ? palette.pillText : palette.faint
|
|
24781
|
+
},
|
|
24782
|
+
children: channel.installCommand
|
|
24783
|
+
}),
|
|
24784
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24785
|
+
className: "flex items-center justify-between gap-10 whitespace-nowrap",
|
|
24786
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
24787
|
+
className: "text-[24px] text-foreground/42",
|
|
24788
|
+
children: ["发布于 ", publishedDate && format(publishedDate, "yyyy/MM/dd HH:mm")]
|
|
24789
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24790
|
+
className: "font-mono text-[24px] font-semibold",
|
|
24791
|
+
style: { color: palette.faint },
|
|
24792
|
+
title: channel.publishedAt,
|
|
24793
|
+
children: publishedDate && formatDistanceToNow(publishedDate, {
|
|
24794
|
+
addSuffix: true,
|
|
24795
|
+
locale: zhCN
|
|
24796
|
+
})
|
|
24797
|
+
})]
|
|
24798
|
+
})
|
|
24799
|
+
]
|
|
24800
|
+
}, channel.tag);
|
|
24801
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24802
|
+
className: "grid grid-cols-[11rem_1fr_auto] items-center gap-8",
|
|
24803
|
+
children: [
|
|
24804
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24805
|
+
className: "flex flex-col gap-2",
|
|
24806
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24807
|
+
className: "whitespace-nowrap text-[30px] font-semibold",
|
|
24808
|
+
style: { color: status.active ? palette.muted : palette.faint },
|
|
24809
|
+
children: channel.label
|
|
24810
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24811
|
+
className: "w-fit whitespace-nowrap rounded-full border px-4 py-0.5 font-mono text-[20px] font-semibold",
|
|
24812
|
+
style: {
|
|
24813
|
+
borderColor: palette.pillBorder,
|
|
24814
|
+
background: palette.pillBg,
|
|
24815
|
+
color: status.active ? palette.pillText : palette.faint
|
|
24816
|
+
},
|
|
24817
|
+
children: channel.tag
|
|
24818
|
+
})]
|
|
24819
|
+
}),
|
|
24820
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24821
|
+
className: "whitespace-nowrap font-mono text-[24px] font-semibold",
|
|
24822
|
+
style: { color: status.active ? palette.muted : palette.faint },
|
|
24823
|
+
children: channel.command
|
|
24824
|
+
}),
|
|
24825
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24826
|
+
className: "flex flex-col items-end gap-2.5 whitespace-nowrap",
|
|
24827
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24828
|
+
className: "font-mono text-[56px] font-bold leading-none tracking-[-0.02em] tabular-nums",
|
|
24829
|
+
style: { color: status.active ? palette.ink : palette.faint },
|
|
24830
|
+
children: channel.status === "ok" ? `v${channel.version}` : "—"
|
|
24831
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
24832
|
+
className: "flex items-center gap-3 text-[24px] font-semibold",
|
|
24833
|
+
style: { color: status.dot },
|
|
24834
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24835
|
+
className: "h-2.5 w-2.5 rounded-full",
|
|
24836
|
+
style: { background: status.dot }
|
|
24837
|
+
}), status.text]
|
|
24838
|
+
})]
|
|
24839
|
+
})
|
|
24840
|
+
]
|
|
24841
|
+
}, channel.tag);
|
|
24842
|
+
})
|
|
24843
|
+
})]
|
|
24844
|
+
}),
|
|
24845
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
24846
|
+
className: "relative mt-28",
|
|
24847
|
+
children: [
|
|
24848
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24849
|
+
className: "flex items-center gap-4",
|
|
24850
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24851
|
+
className: "h-3 w-3 rounded-full",
|
|
24852
|
+
style: { background: palette.accentText }
|
|
24853
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24854
|
+
className: "text-[24px] font-bold tracking-[0.28em] text-foreground/44",
|
|
24855
|
+
children: "用法 · COMMANDS"
|
|
24856
|
+
})]
|
|
24857
|
+
}),
|
|
24858
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
24859
|
+
className: "mt-12 flex flex-col gap-10",
|
|
24860
|
+
children: [
|
|
24861
|
+
{
|
|
24862
|
+
command: "#kkk更新",
|
|
24863
|
+
desc: "更新到最新正式版"
|
|
24864
|
+
},
|
|
24865
|
+
{
|
|
24866
|
+
command: "#kkk更新rc",
|
|
24867
|
+
desc: "更新到预览渠道最新版"
|
|
24868
|
+
},
|
|
24869
|
+
{
|
|
24870
|
+
command: "#kkk更新beta",
|
|
24871
|
+
desc: "更新到测试渠道最新版"
|
|
24872
|
+
},
|
|
24873
|
+
{
|
|
24874
|
+
command: "#kkk更新<版本号>",
|
|
24875
|
+
desc: "更新到指定 stable 版本,例如 #kkk更新2.45.0"
|
|
24876
|
+
}
|
|
24877
|
+
].map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24878
|
+
className: "grid grid-cols-[24rem_1fr] items-baseline gap-8",
|
|
24879
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24880
|
+
className: "whitespace-nowrap font-mono text-[34px] font-bold text-foreground",
|
|
24881
|
+
children: item.command
|
|
24882
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
24883
|
+
className: "whitespace-nowrap text-[26px] font-semibold text-foreground/48",
|
|
24884
|
+
children: item.desc
|
|
24885
|
+
})]
|
|
24886
|
+
}, item.command))
|
|
24887
|
+
}),
|
|
24888
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
24889
|
+
className: "mt-16 flex flex-col gap-2 whitespace-nowrap font-mono text-[22px] font-semibold text-foreground/28",
|
|
24890
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "金丝雀版本经 pkg.pr.new 分发,不提供渠道订阅与更新推送" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "指定低于当前安装版本的版本号属于降级,需回复「确认」才会执行" })]
|
|
24891
|
+
})
|
|
24892
|
+
]
|
|
24893
|
+
})
|
|
24894
|
+
]
|
|
24895
|
+
})
|
|
24896
|
+
]
|
|
24897
|
+
});
|
|
24898
|
+
})
|
|
24899
|
+
});
|
|
24900
|
+
//#endregion
|
|
24415
24901
|
//#region ktr/template/other/version_warning/components/VersionWarning.tsx
|
|
24416
24902
|
var VersionWarning = (props) => {
|
|
24417
24903
|
const dark = isDark(props.ctx);
|
|
@@ -28329,6 +28815,7 @@ var templates = {
|
|
|
28329
28815
|
"other/live-photo-tip": live_photo_tip_default,
|
|
28330
28816
|
"other/qrlogin": qrlogin_default,
|
|
28331
28817
|
"other/runtime": runtime_default,
|
|
28818
|
+
"other/updateHelp": updateHelp_default,
|
|
28332
28819
|
"other/version_warning": version_warning_default,
|
|
28333
28820
|
"statistics/global": global_default,
|
|
28334
28821
|
"statistics/group": group_default,
|
|
@@ -38114,7 +38601,7 @@ var collectRuntimeReport = (event) => {
|
|
|
38114
38601
|
pluginName: Root.pluginName,
|
|
38115
38602
|
pluginVersion: Root.pluginVersion,
|
|
38116
38603
|
karinVersion: Root.karinVersion || "未知",
|
|
38117
|
-
releaseType:
|
|
38604
|
+
releaseType: parseReleaseChannel(Root.pluginVersion),
|
|
38118
38605
|
requiredNodeVersion: packageMetadata.engines?.node ?? "未声明",
|
|
38119
38606
|
requiredKarinVersion: packageMetadata.karin?.engines ?? packageMetadata.engines?.karin ?? "未声明"
|
|
38120
38607
|
},
|
|
@@ -39928,6 +40415,7 @@ var getChangelogImage = async (ctx, props) => {
|
|
|
39928
40415
|
const localMeta = getBuildMetadata();
|
|
39929
40416
|
if (localMeta?.buildTime) buildTime = formatBuildTime(localMeta.buildTime);
|
|
39930
40417
|
}
|
|
40418
|
+
changelog = changelog.replace(/^(## \[\d+\.\d+\.\d+-[^\]]+\][^\r\n]*)/gm, "$1 「测试版」");
|
|
39931
40419
|
return await Render(event, "other/changelog", {
|
|
39932
40420
|
markdown: changelog,
|
|
39933
40421
|
Tip: props.Tip,
|
|
@@ -39941,32 +40429,43 @@ var getChangelogImage = async (ctx, props) => {
|
|
|
39941
40429
|
//#endregion
|
|
39942
40430
|
//#region src/apps/update.ts
|
|
39943
40431
|
var UPDATE_LOCK_KEY = "kkk:update:lock";
|
|
39944
|
-
var UPDATE_MSGID_KEY = "kkk:update:
|
|
40432
|
+
var UPDATE_MSGID_KEY = "kkk:update:msgid";
|
|
39945
40433
|
/**
|
|
39946
40434
|
* 定时更新检测处理器
|
|
39947
|
-
*
|
|
39948
|
-
*
|
|
40435
|
+
* 按订阅渠道检查远程版本(latest 恒参与 —— 装 prerelease 的用户也要收到转正提醒),
|
|
40436
|
+
* 候选取 semver 最大且大于本地者,渲染变更日志并私聊通知所有主人。
|
|
39949
40437
|
*
|
|
39950
40438
|
* @returns 是否继续后续任务
|
|
39951
40439
|
*/
|
|
39952
40440
|
var Handler = async () => {
|
|
39953
|
-
|
|
39954
|
-
|
|
39955
|
-
|
|
39956
|
-
|
|
39957
|
-
|
|
39958
|
-
|
|
39959
|
-
|
|
39960
|
-
|
|
40441
|
+
const tags = ["latest", ...(Config.app.UpdateNotifyChannels?.length ? Config.app.UpdateNotifyChannels : ["stable"]).filter((c) => c !== "stable")];
|
|
40442
|
+
const installedIsCanary = parseReleaseChannel(Root.pluginVersion) === "Canary";
|
|
40443
|
+
const installedBuildTime = getBuildMetadata()?.buildTimestamp;
|
|
40444
|
+
const remotes = await Promise.all(tags.map(async (tag) => {
|
|
40445
|
+
try {
|
|
40446
|
+
return await getRemotePkgVersion(Root.pluginName, tag) || null;
|
|
40447
|
+
} catch {
|
|
40448
|
+
return null;
|
|
40449
|
+
}
|
|
40450
|
+
}));
|
|
40451
|
+
const canaryInfo = installedIsCanary ? await fetchCanaryInfo() : null;
|
|
40452
|
+
const remote = [...new Set(remotes.filter((v) => !!v))].filter((version) => {
|
|
40453
|
+
if (installedIsCanary && installedBuildTime !== void 0) {
|
|
40454
|
+
const releaseNode = canaryInfo?.nodes.find((n) => n.message.includes(version));
|
|
40455
|
+
if (releaseNode) return releaseNode.time > installedBuildTime;
|
|
40456
|
+
}
|
|
40457
|
+
return isSemverGreater(version, Root.pluginVersion);
|
|
40458
|
+
}).sort((a, b) => isSemverGreater(b, a) ? 1 : -1)[0];
|
|
40459
|
+
if (!remote) return true;
|
|
39961
40460
|
try {
|
|
39962
40461
|
const lockedVersion = await db.get(UPDATE_LOCK_KEY);
|
|
39963
40462
|
if (typeof lockedVersion === "string" && lockedVersion.length > 0) {
|
|
39964
40463
|
if (!isSemverGreater(lockedVersion, Root.pluginVersion)) await db.del(UPDATE_LOCK_KEY);
|
|
39965
|
-
else if (!isSemverGreater(
|
|
40464
|
+
else if (!isSemverGreater(remote, lockedVersion)) return true;
|
|
39966
40465
|
}
|
|
39967
40466
|
} catch {}
|
|
39968
40467
|
try {
|
|
39969
|
-
await db.set(UPDATE_LOCK_KEY,
|
|
40468
|
+
await db.set(UPDATE_LOCK_KEY, remote);
|
|
39970
40469
|
} catch {}
|
|
39971
40470
|
const masters = config.master().filter((id) => id !== "console");
|
|
39972
40471
|
if (masters.length === 0) return true;
|
|
@@ -39977,9 +40476,7 @@ var Handler = async () => {
|
|
|
39977
40476
|
try {
|
|
39978
40477
|
const list = await item.bot.getFriendList();
|
|
39979
40478
|
friendsMap.set(item.bot.account.selfId, list || []);
|
|
39980
|
-
} catch {
|
|
39981
|
-
friendsMap.set(item.bot.account.selfId, []);
|
|
39982
|
-
}
|
|
40479
|
+
} catch {}
|
|
39983
40480
|
}));
|
|
39984
40481
|
const masterToBot = /* @__PURE__ */ new Map();
|
|
39985
40482
|
for (const owner of masters) {
|
|
@@ -39991,7 +40488,7 @@ var Handler = async () => {
|
|
|
39991
40488
|
if (!Array.from(masterToBot.entries()).some(([, b]) => b.account.selfId === item.bot.account.selfId)) continue;
|
|
39992
40489
|
const img = await getChangelogImage({ bot: item.bot }, {
|
|
39993
40490
|
localVersion: Root.pluginVersion,
|
|
39994
|
-
remoteVersion:
|
|
40491
|
+
remoteVersion: remote,
|
|
39995
40492
|
Tip: true
|
|
39996
40493
|
});
|
|
39997
40494
|
if (img && img.length > 0) botToImage.set(item.bot.account.selfId, [segment.text("karin-plugin-kkk 有新的更新!"), ...img]);
|
|
@@ -40033,39 +40530,214 @@ var kkkUpdate = hooks.message.friend(async (e, next) => {
|
|
|
40033
40530
|
}
|
|
40034
40531
|
next();
|
|
40035
40532
|
}, { priority: 100 });
|
|
40533
|
+
/** 解析 #kkk更新 的可选参数:缺省/stable=正式版,beta/rc=渠道 tag,其余识别为版本号 */
|
|
40534
|
+
var parseUpdateArg = (arg) => {
|
|
40535
|
+
if (!arg) return { type: "latest" };
|
|
40536
|
+
if (arg === "stable" || arg === "latest") return { type: "latest" };
|
|
40537
|
+
if (arg === "beta" || arg === "rc") return {
|
|
40538
|
+
type: "tag",
|
|
40539
|
+
tag: arg
|
|
40540
|
+
};
|
|
40541
|
+
if (/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(arg)) return {
|
|
40542
|
+
type: "version",
|
|
40543
|
+
version: arg
|
|
40544
|
+
};
|
|
40545
|
+
return { type: "unknown" };
|
|
40546
|
+
};
|
|
40547
|
+
/** 解析目标版本号:latest / 渠道 tag 取对应 dist-tag,指定版本号校验存在性 */
|
|
40548
|
+
var resolveUpdateTarget = async (parsed) => {
|
|
40549
|
+
if (parsed.type === "latest") {
|
|
40550
|
+
const version = await getRemotePkgVersion(Root.pluginName).catch(() => "");
|
|
40551
|
+
return version ? {
|
|
40552
|
+
version,
|
|
40553
|
+
tag: "latest"
|
|
40554
|
+
} : { error: "获取远程版本失败" };
|
|
40555
|
+
}
|
|
40556
|
+
if (parsed.type === "tag") {
|
|
40557
|
+
const version = await getRemotePkgVersion(Root.pluginName, parsed.tag).catch(() => "");
|
|
40558
|
+
return version ? {
|
|
40559
|
+
version,
|
|
40560
|
+
tag: parsed.tag
|
|
40561
|
+
} : { error: `渠道 ${parsed.tag} 暂无可用版本` };
|
|
40562
|
+
}
|
|
40563
|
+
if (parsed.type === "version") {
|
|
40564
|
+
const { status, stdout } = await exec(`npm view ${Root.pluginName}@${parsed.version} version`);
|
|
40565
|
+
const found = status ? stdout.toString().trim() : "";
|
|
40566
|
+
return found ? {
|
|
40567
|
+
version: found,
|
|
40568
|
+
tag: ""
|
|
40569
|
+
} : { error: `版本 ${parsed.version} 不存在` };
|
|
40570
|
+
}
|
|
40571
|
+
return { error: "未识别的渠道或版本" };
|
|
40572
|
+
};
|
|
40573
|
+
/** 安装指定版本并重启(含降级;调用前必须已完成二次确认) */
|
|
40574
|
+
var installAndRestart = async (e, version) => {
|
|
40575
|
+
await e.reply(`开始更新 karin-plugin-kkk → ${version} ......`, { reply: true });
|
|
40576
|
+
const { error } = await exec(`pnpm up ${Root.pluginName}@${version}`);
|
|
40577
|
+
if (error) {
|
|
40578
|
+
e.reply(`${Root.pluginName} 更新失败: ${error}`, { reply: true });
|
|
40579
|
+
return;
|
|
40580
|
+
}
|
|
40581
|
+
const installed = await getPkgVersion(Root.pluginName);
|
|
40582
|
+
if (installed !== version) {
|
|
40583
|
+
e.reply(`更新失败:安装后版本为 ${installed},预期 ${version}。可尝试手动执行 pnpm up ${Root.pluginName}@${version}`, { reply: true });
|
|
40584
|
+
return;
|
|
40585
|
+
}
|
|
40586
|
+
const msgResult = await e.reply(`${Root.pluginName} 更新成功!→ ${version}\n开始执行重启......`);
|
|
40587
|
+
if (msgResult.messageId) try {
|
|
40588
|
+
await db.del(UPDATE_MSGID_KEY);
|
|
40589
|
+
await db.del(UPDATE_LOCK_KEY);
|
|
40590
|
+
} catch {}
|
|
40591
|
+
await restart(e.selfId, e.contact, msgResult.messageId);
|
|
40592
|
+
};
|
|
40593
|
+
/** pkg.pr.new 仓库(金丝雀数据源,只跟踪 main 分支构建) */
|
|
40594
|
+
var PKG_PR_NEW_REPO = "ikenxuan/karin-plugin-kkk";
|
|
40595
|
+
/** 拉取 pkg.pr.new 的发布历史与 main 分支最新构建(失败返回 null,由调用方降级展示) */
|
|
40596
|
+
var fetchCanaryInfo = async () => {
|
|
40597
|
+
try {
|
|
40598
|
+
const [owner, repo] = PKG_PR_NEW_REPO.split("/");
|
|
40599
|
+
const nodes = (await axios.get(`https://pkg.pr.new/api/repo/commits?owner=${owner}&repo=${repo}`, { timeout: 1e4 })).data?.target?.history?.nodes;
|
|
40600
|
+
if (!Array.isArray(nodes)) return null;
|
|
40601
|
+
const history = nodes.map((n) => ({
|
|
40602
|
+
sha: (n.abbreviatedOid ?? "").slice(0, 7),
|
|
40603
|
+
time: n.authoredDate ? new Date(n.authoredDate).getTime() : 0,
|
|
40604
|
+
message: n.message ?? ""
|
|
40605
|
+
}));
|
|
40606
|
+
const mainNode = nodes.find((n) => n.branch === "main" && n.statusCheckRollup?.contexts?.nodes?.some((c) => c.packages?.some((pkg) => pkg.installUrl)));
|
|
40607
|
+
const pkg = mainNode?.statusCheckRollup?.contexts?.nodes?.flatMap((c) => c.packages ?? []).find((p) => p.installUrl);
|
|
40608
|
+
if (!mainNode?.abbreviatedOid || !pkg?.installUrl) return null;
|
|
40609
|
+
return {
|
|
40610
|
+
channel: {
|
|
40611
|
+
label: "金丝雀",
|
|
40612
|
+
tag: "pkg.pr.new · main",
|
|
40613
|
+
status: "canary",
|
|
40614
|
+
version: mainNode.abbreviatedOid.slice(0, 7),
|
|
40615
|
+
installCommand: `pnpm add ${pkg.installUrl} -w`,
|
|
40616
|
+
publishedAt: mainNode.authoredDate
|
|
40617
|
+
},
|
|
40618
|
+
nodes: history
|
|
40619
|
+
};
|
|
40620
|
+
} catch {
|
|
40621
|
+
return null;
|
|
40622
|
+
}
|
|
40623
|
+
};
|
|
40624
|
+
/** 渲染 #kkk更新 用法面板(含各渠道可用版本) */
|
|
40625
|
+
var getUpdateHelpImage = async (e) => {
|
|
40626
|
+
const { status, stdout } = await exec(`npm view ${Root.pluginName} dist-tags --json`);
|
|
40627
|
+
let distTags = {};
|
|
40628
|
+
if (status) try {
|
|
40629
|
+
distTags = JSON.parse(stdout.toString());
|
|
40630
|
+
} catch {}
|
|
40631
|
+
const canaryInfo = await fetchCanaryInfo();
|
|
40632
|
+
const installedIsCanary = parseReleaseChannel(Root.pluginVersion) === "Canary";
|
|
40633
|
+
const build = getBuildMetadata();
|
|
40634
|
+
const installedBuildTime = build?.buildTimestamp;
|
|
40635
|
+
const channels = [
|
|
40636
|
+
{
|
|
40637
|
+
label: "正式版",
|
|
40638
|
+
tag: "latest",
|
|
40639
|
+
command: "#kkk更新"
|
|
40640
|
+
},
|
|
40641
|
+
{
|
|
40642
|
+
label: "预览版",
|
|
40643
|
+
tag: "rc",
|
|
40644
|
+
command: "#kkk更新rc"
|
|
40645
|
+
},
|
|
40646
|
+
{
|
|
40647
|
+
label: "测试版",
|
|
40648
|
+
tag: "beta",
|
|
40649
|
+
command: "#kkk更新beta"
|
|
40650
|
+
}
|
|
40651
|
+
].map((def) => {
|
|
40652
|
+
if (!status) return {
|
|
40653
|
+
...def,
|
|
40654
|
+
status: "error"
|
|
40655
|
+
};
|
|
40656
|
+
const version = distTags[def.tag];
|
|
40657
|
+
if (!version) return {
|
|
40658
|
+
...def,
|
|
40659
|
+
status: "missing"
|
|
40660
|
+
};
|
|
40661
|
+
if (installedIsCanary && installedBuildTime !== void 0) {
|
|
40662
|
+
const releaseNode = canaryInfo?.nodes.find((n) => n.message.includes(version));
|
|
40663
|
+
if (releaseNode) return {
|
|
40664
|
+
...def,
|
|
40665
|
+
status: "ok",
|
|
40666
|
+
version,
|
|
40667
|
+
hasUpdate: releaseNode.time > installedBuildTime
|
|
40668
|
+
};
|
|
40669
|
+
}
|
|
40670
|
+
return {
|
|
40671
|
+
...def,
|
|
40672
|
+
status: "ok",
|
|
40673
|
+
version,
|
|
40674
|
+
hasUpdate: isSemverGreater(version, Root.pluginVersion)
|
|
40675
|
+
};
|
|
40676
|
+
});
|
|
40677
|
+
const canaryChannel = canaryInfo?.channel ?? {
|
|
40678
|
+
label: "金丝雀",
|
|
40679
|
+
tag: "pkg.pr.new · main",
|
|
40680
|
+
status: "error"
|
|
40681
|
+
};
|
|
40682
|
+
const installedSha = (build?.shortCommitHash ?? "").slice(0, 7);
|
|
40683
|
+
if (installedIsCanary && canaryChannel.status === "canary" && installedSha) canaryChannel.hasUpdate = installedSha !== canaryChannel.version;
|
|
40684
|
+
channels.push(canaryChannel);
|
|
40685
|
+
return await Render(e, "other/updateHelp", {
|
|
40686
|
+
currentVersion: Root.pluginVersion,
|
|
40687
|
+
currentChannel: RELEASE_CHANNEL_LABEL[parseReleaseChannel(Root.pluginVersion)],
|
|
40688
|
+
channels
|
|
40689
|
+
});
|
|
40690
|
+
};
|
|
40036
40691
|
var handleKkkUpdate = wrapWithErrorHandler(async (e) => {
|
|
40037
|
-
const
|
|
40038
|
-
|
|
40039
|
-
|
|
40692
|
+
const arg = /^#?kkk更新(?:\s*(\S+))?$/.exec(e.msg)?.[1];
|
|
40693
|
+
const parsed = parseUpdateArg(arg);
|
|
40694
|
+
if (parsed.type === "unknown") {
|
|
40695
|
+
const img = await getUpdateHelpImage(e).catch(() => null);
|
|
40696
|
+
if (img && img.length > 0) e.reply(img, { reply: true });
|
|
40697
|
+
else e.reply("渲染更新面板失败。用法:#kkk更新 | #kkk更新beta | #kkk更新rc | #kkk更新<版本号>", { reply: true });
|
|
40040
40698
|
return;
|
|
40041
40699
|
}
|
|
40042
|
-
|
|
40043
|
-
|
|
40700
|
+
const resolved = await resolveUpdateTarget(parsed);
|
|
40701
|
+
if ("error" in resolved) {
|
|
40702
|
+
e.reply(resolved.error, { reply: true });
|
|
40044
40703
|
return;
|
|
40045
40704
|
}
|
|
40046
|
-
|
|
40047
|
-
|
|
40705
|
+
const { version: remote } = resolved;
|
|
40706
|
+
const local = Root.pluginVersion;
|
|
40707
|
+
if (remote === local) {
|
|
40708
|
+
e.reply(`当前已是该版本:${local}`, { reply: true });
|
|
40709
|
+
return;
|
|
40710
|
+
}
|
|
40711
|
+
if (!isSemverGreater(remote, local)) {
|
|
40712
|
+
e.reply([
|
|
40713
|
+
`⚠️ 检测到降级更新:当前 ${local} → 目标 ${remote}`,
|
|
40714
|
+
"降级可能带来配置或数据兼容问题,请确认你知道自己在做什么。",
|
|
40715
|
+
"回复「确认」继续更新,回复其他内容放弃(2 分钟内有效)。"
|
|
40716
|
+
].join("\n"), { reply: true });
|
|
40717
|
+
const confirmCtx = await karin.ctx(e, {
|
|
40718
|
+
time: 120,
|
|
40719
|
+
reply: true,
|
|
40720
|
+
throwOnTimeout: false
|
|
40721
|
+
});
|
|
40722
|
+
if (!confirmCtx) return;
|
|
40723
|
+
if (confirmCtx.msg.trim() !== "确认") {
|
|
40724
|
+
e.reply("已放弃降级更新。", { reply: true });
|
|
40725
|
+
return;
|
|
40726
|
+
}
|
|
40727
|
+
await installAndRestart(e, remote);
|
|
40048
40728
|
return;
|
|
40049
40729
|
}
|
|
40050
40730
|
const ChangeLogImg = await getChangelogImage(e, {
|
|
40051
|
-
localVersion:
|
|
40052
|
-
remoteVersion:
|
|
40731
|
+
localVersion: local,
|
|
40732
|
+
remoteVersion: remote,
|
|
40053
40733
|
Tip: false,
|
|
40054
40734
|
isRemote: true
|
|
40055
40735
|
});
|
|
40056
40736
|
if (ChangeLogImg) e.reply([segment.text(`${Root.pluginName} 的更新日志:`), ...ChangeLogImg], { reply: true });
|
|
40057
40737
|
else e.reply("获取更新日志失败,更新进程继续......", { reply: true });
|
|
40058
|
-
|
|
40059
|
-
if (result.status === "ok") {
|
|
40060
|
-
const msgResult = await e.reply(`${Root.pluginName} 更新成功!\n${result.local} -> ${result.remote}\n开始执行重启......`);
|
|
40061
|
-
if (msgResult.messageId) try {
|
|
40062
|
-
await db.del(UPDATE_MSGID_KEY);
|
|
40063
|
-
await db.del(UPDATE_LOCK_KEY);
|
|
40064
|
-
} catch {}
|
|
40065
|
-
await restart(e.selfId, e.contact, msgResult.messageId);
|
|
40066
|
-
} else e.reply(`${Root.pluginName} 更新失败: ${result.data ?? "更新执行失败"}`);
|
|
40738
|
+
await installAndRestart(e, remote);
|
|
40067
40739
|
}, { businessName: "KKK更新" });
|
|
40068
|
-
var kkkUpdateCommand = karin.command(/^#?kkk
|
|
40740
|
+
var kkkUpdateCommand = karin.command(/^#?kkk更新(?:\s*(\S+))?$/, handleKkkUpdate, {
|
|
40069
40741
|
name: "kkk-更新",
|
|
40070
40742
|
perm: "master"
|
|
40071
40743
|
});
|