luckytri 1.0.6 → 1.0.7
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/LICENSE +21 -21
- package/docs/en/CHANGELOG.md +25 -16
- package/docs/en/chat-style.md +28 -9
- package/docs/en/guide.md +5 -5
- package/docs/en/her-life.md +2 -2
- package/docs/en/webui.md +1 -1
- package/docs/zh/CHANGELOG.md +25 -16
- package/docs/zh/chat-style.md +30 -9
- package/docs/zh/guide.md +5 -5
- package/docs/zh/her-life.md +2 -2
- package/docs/zh/webui.md +1 -1
- package/package.json +1 -1
- package/public/app/assets/{ChatsPage-DCYMkJ91.js → ChatsPage-CshdtTzV.js} +2 -2
- package/public/app/assets/ChatsPage-DfyPCS9N.css +1 -0
- package/public/app/assets/{Empty-CLyZkxR5.js → Empty-C7yzOBzy.js} +1 -1
- package/public/app/assets/{Empty-DIobYG3x.css → Empty-DmUB2-Bk.css} +1 -1
- package/public/app/assets/{Field-BpaRwLI_.js → Field-BjFv4Rfn.js} +1 -1
- package/public/app/assets/HeartPage-Bft9wZp5.css +1 -0
- package/public/app/assets/{HeartPage-BIOMTiwr.js → HeartPage-eqo6ru16.js} +1 -1
- package/public/app/assets/LifePage-BUi5euBF.css +1 -0
- package/public/app/assets/{LifePage-BCgM4JkR.js → LifePage-CN8GE5NK.js} +1 -1
- package/public/app/assets/{MemoryPage-vShvRqMt.js → MemoryPage-CCpMN4Wg.js} +1 -1
- package/public/app/assets/MemoryPage-cZvXfkXb.css +1 -0
- package/public/app/assets/{NaturePage-Cy9ptr4G.js → NaturePage-C0JqdBTR.js} +2 -2
- package/public/app/assets/NaturePage-CHkpb5NK.css +1 -0
- package/public/app/assets/PeoplePage-BTU0H1pM.css +1 -0
- package/public/app/assets/{PeoplePage-CUZekB2E.js → PeoplePage-BXGBbO4u.js} +1 -1
- package/public/app/assets/{PluginsPage-1RM4rmJP.js → PluginsPage-Dksp5AV5.js} +1 -1
- package/public/app/assets/{SystemPage-BI2CB5Ig.css → SystemPage-BenIyTvk.css} +1 -1
- package/public/app/assets/{SystemPage-BeT5TmIV.js → SystemPage-Cd7aa8eE.js} +1 -1
- package/public/app/assets/TimePage-BOms_n4I.css +1 -0
- package/public/app/assets/{TimePage-taTmPMM8.js → TimePage-Bs_zImb4.js} +2 -2
- package/public/app/assets/{index-DY5AM0Hz.css → index-BHZcHUMh.css} +1 -1
- package/public/app/assets/{index-DdYwC5ZU.js → index-CyRtYxP3.js} +3 -3
- package/public/app/assets/{knowledge-DJmfu2KN.js → knowledge-BJOIyuJo.js} +1 -1
- package/public/app/assets/{media-BEtnE0Gv.js → media-Bwtx8blz.js} +1 -1
- package/public/app/assets/{mind-Dtiw0-QK.js → mind-DtTVrW6Z.js} +1 -1
- package/public/app/index.html +5 -6
- package/public/guide.en.html +3 -3
- package/public/guide.html +3 -3
- package/scripts/import-data.js +128 -128
- package/scripts/proxy-config.js +167 -167
- package/scripts/update-instance.js +201 -201
- package/server/channels/adapters.js +27 -27
- package/server/channels/onebot/adapter.js +288 -288
- package/server/channels/qqbot/adapter.js +253 -253
- package/server/channels/qqbot/api.js +199 -199
- package/server/channels/qqbot/credentials.js +11 -11
- package/server/channels/qqbot/gateway.js +274 -274
- package/server/channels/qqbot/index.js +389 -389
- package/server/channels/segments.js +40 -40
- package/server/channels/session-key.js +153 -153
- package/server/channels/state.js +42 -42
- package/server/core/api.js +564 -564
- package/server/core/context-builder.js +288 -288
- package/server/core/context-compactor.js +454 -454
- package/server/core/conversation-cues.js +365 -325
- package/server/core/conversation-grounding.js +178 -0
- package/server/core/conversation-manager.js +87 -87
- package/server/core/dialogue-context.js +52 -0
- package/server/core/feedback.js +8 -8
- package/server/core/group-style.js +72 -72
- package/server/core/initiative-context.js +66 -66
- package/server/core/input-budget.js +32 -32
- package/server/core/local-demo.js +98 -98
- package/server/core/message-manager.js +118 -118
- package/server/core/message-scheduler.js +78 -78
- package/server/core/model-json.js +190 -190
- package/server/core/model-presets.js +900 -900
- package/server/core/name-call.js +29 -29
- package/server/core/network.js +157 -157
- package/server/core/person-name.js +22 -22
- package/server/core/persona-manager.js +324 -269
- package/server/core/reply-delivery.js +472 -404
- package/server/core/reply-target-resolver.js +50 -50
- package/server/core/response-generator.js +58 -50
- package/server/core/response-validator.js +30 -27
- package/server/core/retired-prompts.js +51 -51
- package/server/core/sessions.js +109 -109
- package/server/core/speaker-names.js +92 -92
- package/server/core/topic-tracker.js +65 -65
- package/server/core/turn.js +42 -8
- package/server/http.js +18 -18
- package/server/i18n/decisions.js +209 -209
- package/server/i18n/index.js +144 -144
- package/server/i18n/labels.js +0 -5
- package/server/i18n/models.js +111 -111
- package/server/knowledge/api.js +342 -342
- package/server/knowledge/embedding-profile.js +114 -114
- package/server/knowledge/index.js +13 -13
- package/server/knowledge/retrieval.js +93 -93
- package/server/knowledge/schema.js +158 -158
- package/server/knowledge/vector-index.js +90 -90
- package/server/mind/affect.js +265 -265
- package/server/mind/attention.js +200 -200
- package/server/mind/bonds.js +565 -565
- package/server/mind/clock.js +83 -83
- package/server/mind/context-selection.js +16 -4
- package/server/mind/continuity.js +562 -562
- package/server/mind/conversation-origin.js +175 -175
- package/server/mind/days.js +210 -210
- package/server/mind/evidence-read.js +45 -45
- package/server/mind/faces.js +373 -373
- package/server/mind/guard.js +68 -60
- package/server/mind/initiative.js +338 -338
- package/server/mind/life/activities.js +21 -21
- package/server/mind/life/context.js +330 -330
- package/server/mind/life/growth.js +261 -261
- package/server/mind/life/presence.js +305 -305
- package/server/mind/meetings.js +1069 -1069
- package/server/mind/memory-policy.js +48 -48
- package/server/mind/memory.js +888 -888
- package/server/mind/nature.js +358 -358
- package/server/mind/novelty.js +19 -19
- package/server/mind/periods.js +118 -118
- package/server/mind/reading.js +120 -120
- package/server/mind/relationship-context.js +71 -71
- package/server/mind/relationships.js +390 -390
- package/server/mind/salience.js +201 -201
- package/server/mind/schema.js +567 -567
- package/server/mind/self.js +496 -484
- package/server/mind/thoughts.js +274 -274
- package/server/mind/time/agenda.js +242 -242
- package/server/mind/time/api.js +200 -200
- package/server/mind/time/attention.js +34 -34
- package/server/mind/time/delivery-links.js +130 -130
- package/server/mind/time/games.js +7 -3
- package/server/mind/time/index.js +3 -0
- package/server/mind/time/model-material.js +77 -77
- package/server/mind/time/presentation.js +35 -51
- package/server/mind/time/schedule.js +83 -83
- package/server/mind/time/schema.js +84 -84
- package/server/mind/time/search.js +383 -383
- package/server/mind/time/sharing.js +472 -472
- package/server/mind/time/task-links.js +311 -311
- package/server/mind/time/works.js +438 -432
- package/server/mind/traits.js +191 -191
- package/server/mind/view.js +43 -6
- package/server/runtime/installation.js +116 -116
- package/server/runtime/update-manager.js +140 -140
- package/server/storage/data-package.js +298 -298
- package/server/storage/data-transfer-api.js +50 -50
- package/server/storage/data-transfer-worker.js +18 -18
- package/server/storage/data-transfer.js +416 -416
- package/server/studio/display-names.js +139 -139
- package/server/studio/management.js +102 -102
- package/server/studio/updates.js +144 -144
- package/server/version.js +10 -10
- package/public/app/assets/ChatsPage-CFMVozoG.css +0 -1
- package/public/app/assets/HeartPage-C-2jvgzF.css +0 -1
- package/public/app/assets/LifePage-CG1OHbRK.css +0 -1
- package/public/app/assets/MemoryPage-C_Bu4rfb.css +0 -1
- package/public/app/assets/NaturePage-CPZlImT0.css +0 -1
- package/public/app/assets/PeoplePage-3RRUITDz.css +0 -1
- package/public/app/assets/TimePage-C-guwPk2.css +0 -1
|
@@ -1,201 +1,201 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import {
|
|
3
|
-
openSync,
|
|
4
|
-
closeSync,
|
|
5
|
-
writeFileSync,
|
|
6
|
-
readFileSync,
|
|
7
|
-
realpathSync,
|
|
8
|
-
} from "node:fs";
|
|
9
|
-
import { dirname, join, delimiter } from "node:path";
|
|
10
|
-
import { pathToFileURL } from "node:url";
|
|
11
|
-
import { prepareRuntime } from "./runtime.js";
|
|
12
|
-
import {
|
|
13
|
-
running,
|
|
14
|
-
serviceUrl,
|
|
15
|
-
serviceHeaders,
|
|
16
|
-
localServiceRequest,
|
|
17
|
-
} from "./service.js";
|
|
18
|
-
import { claimLaunch, clearStarting } from "../server/startup-lock.js";
|
|
19
|
-
import { performUpdate } from "../server/runtime/update-execution.js";
|
|
20
|
-
import {
|
|
21
|
-
processAlive,
|
|
22
|
-
readUpdateJob,
|
|
23
|
-
writeUpdateJob,
|
|
24
|
-
} from "../server/runtime/update-manager.js";
|
|
25
|
-
import { updateRoot } from "../server/runtime/installation.js";
|
|
26
|
-
|
|
27
|
-
export function installEnvironment(env) {
|
|
28
|
-
const kept = {};
|
|
29
|
-
for (const [key, value] of Object.entries(env))
|
|
30
|
-
if (
|
|
31
|
-
/^(?:PATH|PATHEXT|SYSTEMROOT|WINDIR|COMSPEC|USERPROFILE|HOME|APPDATA|LOCALAPPDATA|TEMP|TMP|TMPDIR|HTTP_PROXY|HTTPS_PROXY|ALL_PROXY|NO_PROXY|NODE_USE_ENV_PROXY)$/i.test(
|
|
32
|
-
key,
|
|
33
|
-
)
|
|
34
|
-
)
|
|
35
|
-
kept[key] = value;
|
|
36
|
-
return kept;
|
|
37
|
-
}
|
|
38
|
-
export function findNpmCli(env = process.env) {
|
|
39
|
-
const candidates = [
|
|
40
|
-
env.npm_execpath,
|
|
41
|
-
join(dirname(process.execPath), "node_modules/npm/bin/npm-cli.js"),
|
|
42
|
-
join(dirname(process.execPath), "../lib/node_modules/npm/bin/npm-cli.js"),
|
|
43
|
-
...String(env.PATH || env.Path || "")
|
|
44
|
-
.split(delimiter)
|
|
45
|
-
.flatMap((dir) => [
|
|
46
|
-
join(dir, "npm"),
|
|
47
|
-
join(dir, "node_modules/npm/bin/npm-cli.js"),
|
|
48
|
-
]),
|
|
49
|
-
];
|
|
50
|
-
for (const candidate of candidates.filter(Boolean)) {
|
|
51
|
-
try {
|
|
52
|
-
const cli = realpathSync(candidate);
|
|
53
|
-
if (
|
|
54
|
-
JSON.parse(
|
|
55
|
-
readFileSync(join(dirname(cli), "..", "package.json"), "utf8"),
|
|
56
|
-
).name === "npm"
|
|
57
|
-
)
|
|
58
|
-
return cli;
|
|
59
|
-
} catch {
|
|
60
|
-
/* Try the next native Node/npm installation location. */
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
throw Error("未找到 npm");
|
|
64
|
-
}
|
|
65
|
-
function command(args, { cwd, env = process.env, timeout = 600000, log } = {}) {
|
|
66
|
-
return new Promise((resolve, reject) => {
|
|
67
|
-
const fd = log ? openSync(log, "a", 0o600) : null;
|
|
68
|
-
const child = spawn(process.execPath, args, {
|
|
69
|
-
cwd,
|
|
70
|
-
env,
|
|
71
|
-
windowsHide: true,
|
|
72
|
-
stdio: fd === null ? "ignore" : ["ignore", fd, fd],
|
|
73
|
-
});
|
|
74
|
-
if (fd !== null) closeSync(fd);
|
|
75
|
-
const timer = setTimeout(() => {
|
|
76
|
-
child.kill();
|
|
77
|
-
reject(Error("更新步骤超时"));
|
|
78
|
-
}, timeout);
|
|
79
|
-
child.once("error", (e) => {
|
|
80
|
-
clearTimeout(timer);
|
|
81
|
-
reject(e);
|
|
82
|
-
});
|
|
83
|
-
child.once("exit", (code) => {
|
|
84
|
-
clearTimeout(timer);
|
|
85
|
-
code === 0 ? resolve() : reject(Error("更新程序校验失败"));
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
export function updateExecution(paths) {
|
|
90
|
-
const base = serviceUrl(),
|
|
91
|
-
spawned = new Set();
|
|
92
|
-
const pause = () => new Promise((r) => setTimeout(r, 250));
|
|
93
|
-
return {
|
|
94
|
-
async install(slot, version) {
|
|
95
|
-
const cli = findNpmCli();
|
|
96
|
-
const userconfig = join(updateRoot(paths.home), "install.npmrc");
|
|
97
|
-
writeFileSync(userconfig, "", { mode: 0o600 });
|
|
98
|
-
await command(
|
|
99
|
-
[
|
|
100
|
-
cli,
|
|
101
|
-
"install",
|
|
102
|
-
"--prefix",
|
|
103
|
-
slot,
|
|
104
|
-
"--registry=https://registry.npmjs.org/",
|
|
105
|
-
"--userconfig",
|
|
106
|
-
userconfig,
|
|
107
|
-
"--no-audit",
|
|
108
|
-
"--no-fund",
|
|
109
|
-
"--omit=dev",
|
|
110
|
-
"--engine-strict",
|
|
111
|
-
`luckytri@${version}`,
|
|
112
|
-
],
|
|
113
|
-
{ cwd: slot, env: installEnvironment(process.env), log: paths.log },
|
|
114
|
-
);
|
|
115
|
-
},
|
|
116
|
-
async check(root, version) {
|
|
117
|
-
const script = `import fs from 'node:fs';import {createRequire} from 'node:module';const p=JSON.parse(fs.readFileSync(${JSON.stringify(join(root, "package.json"))},'utf8'));if(p.version!==${JSON.stringify(version)})process.exit(1);await import(${JSON.stringify(pathToFileURL(join(root, "server/app.js")).href)});const sharp=createRequire(${JSON.stringify(pathToFileURL(join(root, "package.json")).href)})('sharp');await sharp({create:{width:1,height:1,channels:3,background:'#fff'}}).png().toBuffer();`;
|
|
118
|
-
await command(["--input-type=module", "-e", script], {
|
|
119
|
-
cwd: root,
|
|
120
|
-
env: installEnvironment(process.env),
|
|
121
|
-
timeout: 30000,
|
|
122
|
-
log: paths.log,
|
|
123
|
-
});
|
|
124
|
-
},
|
|
125
|
-
async stop(pid) {
|
|
126
|
-
if (!processAlive(pid)) return;
|
|
127
|
-
const info = await running({ base, lenient: true, local: true });
|
|
128
|
-
if (info?.pid === pid) {
|
|
129
|
-
const response = await localServiceRequest(base + "/api/service/stop", {
|
|
130
|
-
method: "POST",
|
|
131
|
-
headers: serviceHeaders(),
|
|
132
|
-
body: "{}",
|
|
133
|
-
timeout: 5000,
|
|
134
|
-
});
|
|
135
|
-
if (!response.ok) throw Error("服务拒绝停止请求");
|
|
136
|
-
await response.json();
|
|
137
|
-
} else if (spawned.has(pid)) process.kill(pid, "SIGTERM");
|
|
138
|
-
else throw Error("运行实例发生变化");
|
|
139
|
-
for (let n = 0; n < 160 && processAlive(pid); n++) await pause();
|
|
140
|
-
if (processAlive(pid)) throw Error("旧实例未停止");
|
|
141
|
-
},
|
|
142
|
-
claim: claimLaunch,
|
|
143
|
-
release: clearStarting,
|
|
144
|
-
async start(root) {
|
|
145
|
-
const log = openSync(paths.log, "a", 0o600);
|
|
146
|
-
try {
|
|
147
|
-
const child = spawn(
|
|
148
|
-
process.execPath,
|
|
149
|
-
[
|
|
150
|
-
...(process.execArgv.includes("--use-env-proxy")
|
|
151
|
-
? ["--use-env-proxy"]
|
|
152
|
-
: []),
|
|
153
|
-
join(root, "server", "index.js"),
|
|
154
|
-
],
|
|
155
|
-
{
|
|
156
|
-
cwd: paths.home,
|
|
157
|
-
env: { ...process.env, LUCKYTRI_LAUNCH_PID: String(process.pid) },
|
|
158
|
-
detached: true,
|
|
159
|
-
windowsHide: true,
|
|
160
|
-
stdio: ["ignore", log, log],
|
|
161
|
-
},
|
|
162
|
-
);
|
|
163
|
-
await new Promise((resolve, reject) => {
|
|
164
|
-
child.once("spawn", resolve);
|
|
165
|
-
child.once("error", reject);
|
|
166
|
-
});
|
|
167
|
-
child.unref();
|
|
168
|
-
spawned.add(child.pid);
|
|
169
|
-
return child.pid;
|
|
170
|
-
} finally {
|
|
171
|
-
closeSync(log);
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
async health(pid, version) {
|
|
175
|
-
for (let n = 0; n < 2400; n++) {
|
|
176
|
-
if (!processAlive(pid)) throw Error("新实例已退出");
|
|
177
|
-
const info = await running({ base, lenient: true, local: true });
|
|
178
|
-
if (info?.pid === pid && info.version === version) return;
|
|
179
|
-
await pause();
|
|
180
|
-
}
|
|
181
|
-
throw Error("新实例启动超时");
|
|
182
|
-
},
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
async function main() {
|
|
186
|
-
const paths = prepareRuntime({ initialize: false }),
|
|
187
|
-
id = process.argv[2],
|
|
188
|
-
job = readUpdateJob(paths.home, id);
|
|
189
|
-
if (job.parent !== Number(process.argv[3]) || !processAlive(job.parent))
|
|
190
|
-
throw Error("更新启动信息无效");
|
|
191
|
-
writeUpdateJob(paths.home, { ...job, workerPid: process.pid });
|
|
192
|
-
const result = await performUpdate(paths, id, updateExecution(paths));
|
|
193
|
-
console.log(
|
|
194
|
-
result.status === "done" ? "版本更新与实例重启完成。" : result.error,
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
|
|
198
|
-
main().catch((e) => {
|
|
199
|
-
console.error("版本更新未完成:", e.code || "请查看管理台更新状态");
|
|
200
|
-
process.exitCode = 1;
|
|
201
|
-
});
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import {
|
|
3
|
+
openSync,
|
|
4
|
+
closeSync,
|
|
5
|
+
writeFileSync,
|
|
6
|
+
readFileSync,
|
|
7
|
+
realpathSync,
|
|
8
|
+
} from "node:fs";
|
|
9
|
+
import { dirname, join, delimiter } from "node:path";
|
|
10
|
+
import { pathToFileURL } from "node:url";
|
|
11
|
+
import { prepareRuntime } from "./runtime.js";
|
|
12
|
+
import {
|
|
13
|
+
running,
|
|
14
|
+
serviceUrl,
|
|
15
|
+
serviceHeaders,
|
|
16
|
+
localServiceRequest,
|
|
17
|
+
} from "./service.js";
|
|
18
|
+
import { claimLaunch, clearStarting } from "../server/startup-lock.js";
|
|
19
|
+
import { performUpdate } from "../server/runtime/update-execution.js";
|
|
20
|
+
import {
|
|
21
|
+
processAlive,
|
|
22
|
+
readUpdateJob,
|
|
23
|
+
writeUpdateJob,
|
|
24
|
+
} from "../server/runtime/update-manager.js";
|
|
25
|
+
import { updateRoot } from "../server/runtime/installation.js";
|
|
26
|
+
|
|
27
|
+
export function installEnvironment(env) {
|
|
28
|
+
const kept = {};
|
|
29
|
+
for (const [key, value] of Object.entries(env))
|
|
30
|
+
if (
|
|
31
|
+
/^(?:PATH|PATHEXT|SYSTEMROOT|WINDIR|COMSPEC|USERPROFILE|HOME|APPDATA|LOCALAPPDATA|TEMP|TMP|TMPDIR|HTTP_PROXY|HTTPS_PROXY|ALL_PROXY|NO_PROXY|NODE_USE_ENV_PROXY)$/i.test(
|
|
32
|
+
key,
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
kept[key] = value;
|
|
36
|
+
return kept;
|
|
37
|
+
}
|
|
38
|
+
export function findNpmCli(env = process.env) {
|
|
39
|
+
const candidates = [
|
|
40
|
+
env.npm_execpath,
|
|
41
|
+
join(dirname(process.execPath), "node_modules/npm/bin/npm-cli.js"),
|
|
42
|
+
join(dirname(process.execPath), "../lib/node_modules/npm/bin/npm-cli.js"),
|
|
43
|
+
...String(env.PATH || env.Path || "")
|
|
44
|
+
.split(delimiter)
|
|
45
|
+
.flatMap((dir) => [
|
|
46
|
+
join(dir, "npm"),
|
|
47
|
+
join(dir, "node_modules/npm/bin/npm-cli.js"),
|
|
48
|
+
]),
|
|
49
|
+
];
|
|
50
|
+
for (const candidate of candidates.filter(Boolean)) {
|
|
51
|
+
try {
|
|
52
|
+
const cli = realpathSync(candidate);
|
|
53
|
+
if (
|
|
54
|
+
JSON.parse(
|
|
55
|
+
readFileSync(join(dirname(cli), "..", "package.json"), "utf8"),
|
|
56
|
+
).name === "npm"
|
|
57
|
+
)
|
|
58
|
+
return cli;
|
|
59
|
+
} catch {
|
|
60
|
+
/* Try the next native Node/npm installation location. */
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
throw Error("未找到 npm");
|
|
64
|
+
}
|
|
65
|
+
function command(args, { cwd, env = process.env, timeout = 600000, log } = {}) {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
const fd = log ? openSync(log, "a", 0o600) : null;
|
|
68
|
+
const child = spawn(process.execPath, args, {
|
|
69
|
+
cwd,
|
|
70
|
+
env,
|
|
71
|
+
windowsHide: true,
|
|
72
|
+
stdio: fd === null ? "ignore" : ["ignore", fd, fd],
|
|
73
|
+
});
|
|
74
|
+
if (fd !== null) closeSync(fd);
|
|
75
|
+
const timer = setTimeout(() => {
|
|
76
|
+
child.kill();
|
|
77
|
+
reject(Error("更新步骤超时"));
|
|
78
|
+
}, timeout);
|
|
79
|
+
child.once("error", (e) => {
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
reject(e);
|
|
82
|
+
});
|
|
83
|
+
child.once("exit", (code) => {
|
|
84
|
+
clearTimeout(timer);
|
|
85
|
+
code === 0 ? resolve() : reject(Error("更新程序校验失败"));
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export function updateExecution(paths) {
|
|
90
|
+
const base = serviceUrl(),
|
|
91
|
+
spawned = new Set();
|
|
92
|
+
const pause = () => new Promise((r) => setTimeout(r, 250));
|
|
93
|
+
return {
|
|
94
|
+
async install(slot, version) {
|
|
95
|
+
const cli = findNpmCli();
|
|
96
|
+
const userconfig = join(updateRoot(paths.home), "install.npmrc");
|
|
97
|
+
writeFileSync(userconfig, "", { mode: 0o600 });
|
|
98
|
+
await command(
|
|
99
|
+
[
|
|
100
|
+
cli,
|
|
101
|
+
"install",
|
|
102
|
+
"--prefix",
|
|
103
|
+
slot,
|
|
104
|
+
"--registry=https://registry.npmjs.org/",
|
|
105
|
+
"--userconfig",
|
|
106
|
+
userconfig,
|
|
107
|
+
"--no-audit",
|
|
108
|
+
"--no-fund",
|
|
109
|
+
"--omit=dev",
|
|
110
|
+
"--engine-strict",
|
|
111
|
+
`luckytri@${version}`,
|
|
112
|
+
],
|
|
113
|
+
{ cwd: slot, env: installEnvironment(process.env), log: paths.log },
|
|
114
|
+
);
|
|
115
|
+
},
|
|
116
|
+
async check(root, version) {
|
|
117
|
+
const script = `import fs from 'node:fs';import {createRequire} from 'node:module';const p=JSON.parse(fs.readFileSync(${JSON.stringify(join(root, "package.json"))},'utf8'));if(p.version!==${JSON.stringify(version)})process.exit(1);await import(${JSON.stringify(pathToFileURL(join(root, "server/app.js")).href)});const sharp=createRequire(${JSON.stringify(pathToFileURL(join(root, "package.json")).href)})('sharp');await sharp({create:{width:1,height:1,channels:3,background:'#fff'}}).png().toBuffer();`;
|
|
118
|
+
await command(["--input-type=module", "-e", script], {
|
|
119
|
+
cwd: root,
|
|
120
|
+
env: installEnvironment(process.env),
|
|
121
|
+
timeout: 30000,
|
|
122
|
+
log: paths.log,
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
async stop(pid) {
|
|
126
|
+
if (!processAlive(pid)) return;
|
|
127
|
+
const info = await running({ base, lenient: true, local: true });
|
|
128
|
+
if (info?.pid === pid) {
|
|
129
|
+
const response = await localServiceRequest(base + "/api/service/stop", {
|
|
130
|
+
method: "POST",
|
|
131
|
+
headers: serviceHeaders(),
|
|
132
|
+
body: "{}",
|
|
133
|
+
timeout: 5000,
|
|
134
|
+
});
|
|
135
|
+
if (!response.ok) throw Error("服务拒绝停止请求");
|
|
136
|
+
await response.json();
|
|
137
|
+
} else if (spawned.has(pid)) process.kill(pid, "SIGTERM");
|
|
138
|
+
else throw Error("运行实例发生变化");
|
|
139
|
+
for (let n = 0; n < 160 && processAlive(pid); n++) await pause();
|
|
140
|
+
if (processAlive(pid)) throw Error("旧实例未停止");
|
|
141
|
+
},
|
|
142
|
+
claim: claimLaunch,
|
|
143
|
+
release: clearStarting,
|
|
144
|
+
async start(root) {
|
|
145
|
+
const log = openSync(paths.log, "a", 0o600);
|
|
146
|
+
try {
|
|
147
|
+
const child = spawn(
|
|
148
|
+
process.execPath,
|
|
149
|
+
[
|
|
150
|
+
...(process.execArgv.includes("--use-env-proxy")
|
|
151
|
+
? ["--use-env-proxy"]
|
|
152
|
+
: []),
|
|
153
|
+
join(root, "server", "index.js"),
|
|
154
|
+
],
|
|
155
|
+
{
|
|
156
|
+
cwd: paths.home,
|
|
157
|
+
env: { ...process.env, LUCKYTRI_LAUNCH_PID: String(process.pid) },
|
|
158
|
+
detached: true,
|
|
159
|
+
windowsHide: true,
|
|
160
|
+
stdio: ["ignore", log, log],
|
|
161
|
+
},
|
|
162
|
+
);
|
|
163
|
+
await new Promise((resolve, reject) => {
|
|
164
|
+
child.once("spawn", resolve);
|
|
165
|
+
child.once("error", reject);
|
|
166
|
+
});
|
|
167
|
+
child.unref();
|
|
168
|
+
spawned.add(child.pid);
|
|
169
|
+
return child.pid;
|
|
170
|
+
} finally {
|
|
171
|
+
closeSync(log);
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
async health(pid, version) {
|
|
175
|
+
for (let n = 0; n < 2400; n++) {
|
|
176
|
+
if (!processAlive(pid)) throw Error("新实例已退出");
|
|
177
|
+
const info = await running({ base, lenient: true, local: true });
|
|
178
|
+
if (info?.pid === pid && info.version === version) return;
|
|
179
|
+
await pause();
|
|
180
|
+
}
|
|
181
|
+
throw Error("新实例启动超时");
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
async function main() {
|
|
186
|
+
const paths = prepareRuntime({ initialize: false }),
|
|
187
|
+
id = process.argv[2],
|
|
188
|
+
job = readUpdateJob(paths.home, id);
|
|
189
|
+
if (job.parent !== Number(process.argv[3]) || !processAlive(job.parent))
|
|
190
|
+
throw Error("更新启动信息无效");
|
|
191
|
+
writeUpdateJob(paths.home, { ...job, workerPid: process.pid });
|
|
192
|
+
const result = await performUpdate(paths, id, updateExecution(paths));
|
|
193
|
+
console.log(
|
|
194
|
+
result.status === "done" ? "版本更新与实例重启完成。" : result.error,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
|
|
198
|
+
main().catch((e) => {
|
|
199
|
+
console.error("版本更新未完成:", e.code || "请查看管理台更新状态");
|
|
200
|
+
process.exitCode = 1;
|
|
201
|
+
});
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { onebot } from "./onebot/adapter.js";
|
|
2
|
-
import { qqbot } from "./qqbot/adapter.js";
|
|
3
|
-
import { parseSessionKey } from "./session-key.js";
|
|
4
|
-
|
|
5
|
-
// What the core may ask a platform without being connected to it, such as
|
|
6
|
-
// which media links are safe to download. One entry per channel type.
|
|
7
|
-
const adapters = new Map([
|
|
8
|
-
[onebot.type, onebot],
|
|
9
|
-
[qqbot.type, qqbot],
|
|
10
|
-
]);
|
|
11
|
-
|
|
12
|
-
export function registerChannel(adapter) {
|
|
13
|
-
adapters.set(adapter.type, adapter);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function adapterFor(sessionOrType = "onebot") {
|
|
17
|
-
try {
|
|
18
|
-
const type = String(sessionOrType).includes(":")
|
|
19
|
-
? parseSessionKey(sessionOrType).channel
|
|
20
|
-
: sessionOrType;
|
|
21
|
-
return adapters.get(type) || onebot;
|
|
22
|
-
} catch {
|
|
23
|
-
return onebot;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export { onebot, qqbot };
|
|
1
|
+
import { onebot } from "./onebot/adapter.js";
|
|
2
|
+
import { qqbot } from "./qqbot/adapter.js";
|
|
3
|
+
import { parseSessionKey } from "./session-key.js";
|
|
4
|
+
|
|
5
|
+
// What the core may ask a platform without being connected to it, such as
|
|
6
|
+
// which media links are safe to download. One entry per channel type.
|
|
7
|
+
const adapters = new Map([
|
|
8
|
+
[onebot.type, onebot],
|
|
9
|
+
[qqbot.type, qqbot],
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
export function registerChannel(adapter) {
|
|
13
|
+
adapters.set(adapter.type, adapter);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function adapterFor(sessionOrType = "onebot") {
|
|
17
|
+
try {
|
|
18
|
+
const type = String(sessionOrType).includes(":")
|
|
19
|
+
? parseSessionKey(sessionOrType).channel
|
|
20
|
+
: sessionOrType;
|
|
21
|
+
return adapters.get(type) || onebot;
|
|
22
|
+
} catch {
|
|
23
|
+
return onebot;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { onebot, qqbot };
|