luckytri 1.0.0 → 1.0.2
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/.github/SECURITY.md +4 -4
- package/README.en.md +252 -250
- package/README.md +252 -250
- package/bin/luckytri.js +5 -1
- package/docs/en/CHANGELOG.md +8 -0
- package/docs/en/connect.md +18 -18
- package/docs/en/guide.md +202 -216
- package/docs/en/npm-release.md +25 -25
- package/docs/zh/CHANGELOG.md +8 -0
- package/docs/zh/connect.md +17 -17
- package/docs/zh/guide.md +202 -216
- package/docs/zh/npm-release.md +33 -33
- package/package.json +110 -108
- package/plugins/sdk/index.d.ts +155 -155
- package/plugins/sdk/testing.js +58 -58
- package/plugins/weather/index.js +82 -82
- package/plugins/weather/luckytri-plugin.json +29 -29
- package/public/app/assets/ChatsPage-BhlJHseG.js +3 -0
- package/public/app/assets/Empty-DP6WMGHi.js +2 -0
- package/public/app/assets/Field-CtbdqaiB.js +1 -0
- package/public/app/assets/HeartPage-32BeTPn2.js +1 -0
- package/public/app/assets/LifePage-CxSm0XKI.js +1 -0
- package/public/app/assets/MemoryPage-BeKBcPCY.js +1 -0
- package/public/app/assets/NaturePage-NEPYl2HS.js +3 -0
- package/public/app/assets/PeoplePage-DxtpekwM.js +1 -0
- package/public/app/assets/PluginsPage-CVVQwEBI.css +1 -0
- package/public/app/assets/PluginsPage-DksEZbUU.js +2 -0
- package/public/app/assets/{SystemPage-CAMPoYqM.css → SystemPage-BkRu0Rvx.css} +1 -1
- package/public/app/assets/SystemPage-BvzJlHuY.js +1 -0
- package/public/app/assets/TimePage-7-awH5XL.js +3 -0
- package/public/app/assets/index-4rItIkD-.js +4 -0
- package/public/app/assets/{index-YDz1ree1.css → index-DY4e15Kh.css} +1 -1
- package/public/app/assets/{knowledge-DG0e0uKw.js → knowledge-C6_HvoyB.js} +1 -1
- package/public/app/assets/media-SMfTT-yc.js +1 -0
- package/public/app/index.html +3 -3
- package/public/guide.en.html +72 -99
- package/public/guide.html +44 -86
- package/public/tutorial.en.md +25 -39
- package/public/tutorial.md +25 -39
- package/scripts/backup.js +311 -311
- package/scripts/browser.js +41 -41
- package/scripts/import-data.js +128 -0
- package/scripts/launch.js +101 -94
- package/scripts/plugin.js +150 -150
- package/scripts/reset-password.js +22 -0
- package/scripts/runtime.js +25 -25
- package/scripts/service.js +56 -47
- package/scripts/setup.js +50 -50
- package/scripts/start-server.js +41 -41
- package/scripts/stop.js +36 -36
- package/server/app.js +112 -96
- package/server/auth.js +217 -0
- package/server/channels/contract.js +57 -57
- package/server/channels/hub.js +165 -165
- package/server/channels/index.js +28 -25
- package/server/channels/onebot/index.js +335 -336
- package/server/channels/onebot/token.js +22 -3
- package/server/core/capabilities.js +208 -208
- package/server/core/events.js +64 -60
- package/server/core/image-preprocessor.js +208 -208
- package/server/core/model-manager.js +1213 -1213
- package/server/core/net-guard.js +49 -49
- package/server/core/orchestrator.js +569 -569
- package/server/core/perceivers.js +91 -91
- package/server/core/persona-manager.js +243 -243
- package/server/core/repository.js +293 -293
- package/server/core/response-validator.js +508 -508
- package/server/core/turn-processor.js +630 -630
- package/server/core/turn.js +236 -236
- package/server/core/vision-manager.js +633 -633
- package/server/i18n/errors.js +548 -497
- package/server/i18n/labels.js +649 -653
- package/server/index.js +151 -102
- package/server/knowledge/manager.js +386 -386
- package/server/knowledge/schema.js +12 -8
- package/server/local-access.js +32 -0
- package/server/mind/anticipations.js +507 -507
- package/server/mind/api.js +703 -703
- package/server/mind/budget.js +152 -152
- package/server/mind/context-selection.js +61 -61
- package/server/mind/day-planner.js +324 -324
- package/server/mind/evidence.js +148 -148
- package/server/mind/index.js +445 -445
- package/server/mind/life/diary.js +786 -786
- package/server/mind/life/index.js +1049 -1049
- package/server/mind/observations.js +84 -84
- package/server/mind/own-day.js +324 -324
- package/server/mind/own-voice.js +318 -318
- package/server/mind/senses.js +53 -53
- package/server/mind/time/activity-clock.js +196 -196
- package/server/mind/time/availability.js +69 -69
- package/server/mind/time/commitment-review.js +198 -198
- package/server/mind/time/executor.js +512 -512
- package/server/mind/time/experiences.js +128 -128
- package/server/mind/time/games.js +562 -562
- package/server/mind/time/index.js +739 -739
- package/server/mind/time/intent.js +166 -166
- package/server/mind/time/kinds.js +171 -171
- package/server/mind/time/plugin-activity.js +207 -207
- package/server/mind/time/tasks.js +587 -587
- package/server/mind/util.js +110 -110
- package/server/mind/view.js +273 -273
- package/server/paths.js +102 -102
- package/server/plugins/api.js +204 -204
- package/server/plugins/host.js +967 -967
- package/server/plugins/install.js +295 -295
- package/server/plugins/manifest.js +201 -201
- package/server/plugins/permissions.js +42 -42
- package/server/plugins/runner/guard.mjs +36 -36
- package/server/plugins/runner/worker.mjs +250 -250
- package/server/plugins/schema.js +91 -91
- package/server/plugins/zip.js +112 -112
- package/server/startup-lock.js +118 -118
- package/server/storage/archive.js +242 -241
- package/server/storage/backup-cleanup-worker.js +8 -8
- package/server/storage/backup-cleanup.js +415 -414
- package/server/storage/backup-lock.js +76 -76
- package/server/storage/backup-scheduler.js +131 -131
- package/server/storage/data-package.js +298 -0
- package/server/storage/data-transfer-api.js +50 -0
- package/server/storage/data-transfer-worker.js +18 -0
- package/server/storage/data-transfer.js +415 -0
- package/server/storage/store.js +202 -199
- package/server/studio/readiness.js +181 -190
- package/server/studio/settings.js +236 -236
- package/public/app/assets/ChatsPage-C-FcRapR.js +0 -3
- package/public/app/assets/Empty-CpP5kQHH.js +0 -2
- package/public/app/assets/Field-D4gY-INU.js +0 -1
- package/public/app/assets/HeartPage-CPy_thQd.js +0 -1
- package/public/app/assets/LifePage-CxWvwmSf.js +0 -1
- package/public/app/assets/MemoryPage-DC4rhQ68.js +0 -1
- package/public/app/assets/NaturePage-IvYw04Zq.js +0 -3
- package/public/app/assets/PeoplePage-Cqefm9-q.js +0 -1
- package/public/app/assets/PluginsPage-DKSaKvXb.js +0 -2
- package/public/app/assets/PluginsPage-HyBe5D8w.css +0 -1
- package/public/app/assets/SystemPage-CJmtJkrK.js +0 -1
- package/public/app/assets/TimePage-Cw44inM4.js +0 -3
- package/public/app/assets/index-BheRW-1t.js +0 -4
- package/public/app/assets/media-BzPDBm7e.js +0 -1
package/scripts/plugin.js
CHANGED
|
@@ -1,150 +1,150 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
mkdirSync,
|
|
4
|
-
readdirSync,
|
|
5
|
-
readFileSync,
|
|
6
|
-
statSync,
|
|
7
|
-
writeFileSync,
|
|
8
|
-
} from "node:fs";
|
|
9
|
-
import { join, relative } from "node:path";
|
|
10
|
-
import { validateManifest } from "../server/plugins/manifest.js";
|
|
11
|
-
|
|
12
|
-
const command = process.argv[2];
|
|
13
|
-
const arg = process.argv[3];
|
|
14
|
-
|
|
15
|
-
function walk(dir, out = []) {
|
|
16
|
-
for (const name of readdirSync(dir)) {
|
|
17
|
-
if (name === "node_modules") continue;
|
|
18
|
-
const path = join(dir, name);
|
|
19
|
-
if (statSync(path).isDirectory()) walk(path, out);
|
|
20
|
-
else out.push(path);
|
|
21
|
-
}
|
|
22
|
-
return out;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function crc32(buffer) {
|
|
26
|
-
let crc = ~0;
|
|
27
|
-
for (const byte of buffer) {
|
|
28
|
-
crc ^= byte;
|
|
29
|
-
for (let bit = 0; bit < 8; bit++)
|
|
30
|
-
crc = crc & 1 ? (crc >>> 1) ^ 0xedb88320 : crc >>> 1;
|
|
31
|
-
}
|
|
32
|
-
return ~crc >>> 0;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function pack(dir) {
|
|
36
|
-
const files = walk(dir).map((path) => ({
|
|
37
|
-
name: relative(dir, path).replace(/\\/g, "/"),
|
|
38
|
-
bytes: readFileSync(path),
|
|
39
|
-
}));
|
|
40
|
-
const locals = [];
|
|
41
|
-
const central = [];
|
|
42
|
-
let offset = 0;
|
|
43
|
-
for (const file of files) {
|
|
44
|
-
const name = Buffer.from(file.name);
|
|
45
|
-
const crc = crc32(file.bytes);
|
|
46
|
-
const local = Buffer.alloc(30 + name.length);
|
|
47
|
-
local.writeUInt32LE(0x04034b50, 0);
|
|
48
|
-
local.writeUInt16LE(20, 4);
|
|
49
|
-
local.writeUInt32LE(crc, 14);
|
|
50
|
-
local.writeUInt32LE(file.bytes.length, 18);
|
|
51
|
-
local.writeUInt32LE(file.bytes.length, 22);
|
|
52
|
-
local.writeUInt16LE(name.length, 26);
|
|
53
|
-
name.copy(local, 30);
|
|
54
|
-
const centralHeader = Buffer.alloc(46 + name.length);
|
|
55
|
-
centralHeader.writeUInt32LE(0x02014b50, 0);
|
|
56
|
-
centralHeader.writeUInt16LE(20, 4);
|
|
57
|
-
centralHeader.writeUInt16LE(20, 6);
|
|
58
|
-
centralHeader.writeUInt32LE(crc, 16);
|
|
59
|
-
centralHeader.writeUInt32LE(file.bytes.length, 20);
|
|
60
|
-
centralHeader.writeUInt32LE(file.bytes.length, 24);
|
|
61
|
-
centralHeader.writeUInt16LE(name.length, 28);
|
|
62
|
-
centralHeader.writeUInt32LE(offset, 42);
|
|
63
|
-
name.copy(centralHeader, 46);
|
|
64
|
-
locals.push(local, file.bytes);
|
|
65
|
-
central.push(centralHeader);
|
|
66
|
-
offset += local.length + file.bytes.length;
|
|
67
|
-
}
|
|
68
|
-
const directory = Buffer.concat(central);
|
|
69
|
-
const end = Buffer.alloc(22);
|
|
70
|
-
end.writeUInt32LE(0x06054b50, 0);
|
|
71
|
-
end.writeUInt16LE(files.length, 8);
|
|
72
|
-
end.writeUInt16LE(files.length, 10);
|
|
73
|
-
end.writeUInt32LE(directory.length, 12);
|
|
74
|
-
end.writeUInt32LE(offset, 16);
|
|
75
|
-
return Buffer.concat([...locals, directory, end]);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (command === "new") {
|
|
79
|
-
const id = arg || "example";
|
|
80
|
-
const dir = join("plugins", id);
|
|
81
|
-
mkdirSync(dir, { recursive: true });
|
|
82
|
-
writeFileSync(
|
|
83
|
-
join(dir, "luckytri-plugin.json"),
|
|
84
|
-
JSON.stringify(
|
|
85
|
-
{
|
|
86
|
-
id,
|
|
87
|
-
name: id,
|
|
88
|
-
version: "0.1.0",
|
|
89
|
-
pluginApi: "1.0",
|
|
90
|
-
luckytri: ">=1.0.0 <2.0.0",
|
|
91
|
-
description: "",
|
|
92
|
-
entry: "index.js",
|
|
93
|
-
permissions: [],
|
|
94
|
-
contributes: {},
|
|
95
|
-
},
|
|
96
|
-
null,
|
|
97
|
-
2,
|
|
98
|
-
),
|
|
99
|
-
);
|
|
100
|
-
writeFileSync(
|
|
101
|
-
join(dir, "index.js"),
|
|
102
|
-
"export default { activate(ctx) { ctx.status.set({ text: '已接上', tone: 'ok' }); } };\n",
|
|
103
|
-
);
|
|
104
|
-
console.log(dir);
|
|
105
|
-
} else if (command === "pack") {
|
|
106
|
-
const dir = arg;
|
|
107
|
-
const manifest = JSON.parse(
|
|
108
|
-
readFileSync(join(dir, "luckytri-plugin.json"), "utf8"),
|
|
109
|
-
);
|
|
110
|
-
const bytes = pack(dir);
|
|
111
|
-
const file = `${manifest.id}-${manifest.version}.zip`;
|
|
112
|
-
writeFileSync(file, bytes);
|
|
113
|
-
const sha256 = createHash("sha256").update(bytes).digest("hex");
|
|
114
|
-
console.log(
|
|
115
|
-
JSON.stringify(
|
|
116
|
-
{
|
|
117
|
-
id: manifest.id,
|
|
118
|
-
version: manifest.version,
|
|
119
|
-
pluginApi: manifest.pluginApi,
|
|
120
|
-
luckytri: manifest.luckytri,
|
|
121
|
-
sha256,
|
|
122
|
-
permissions: manifest.permissions,
|
|
123
|
-
network: manifest.network || [],
|
|
124
|
-
file,
|
|
125
|
-
},
|
|
126
|
-
null,
|
|
127
|
-
2,
|
|
128
|
-
),
|
|
129
|
-
);
|
|
130
|
-
} else if (command === "registry-check") {
|
|
131
|
-
const index = JSON.parse(readFileSync(arg || "index.json", "utf8"));
|
|
132
|
-
if (index.format !== 1 || !Array.isArray(index.plugins))
|
|
133
|
-
throw new Error("插件索引无效");
|
|
134
|
-
for (const plugin of index.plugins)
|
|
135
|
-
for (const version of plugin.versions || [])
|
|
136
|
-
if (!version.sha256 || !version.url) throw new Error("插件索引无效");
|
|
137
|
-
console.log(`ok ${index.plugins.length}`);
|
|
138
|
-
} else if (command === "check") {
|
|
139
|
-
const dir = resolveDir(arg);
|
|
140
|
-
const manifest = validateManifest(
|
|
141
|
-
JSON.parse(readFileSync(join(dir, "luckytri-plugin.json"), "utf8")),
|
|
142
|
-
);
|
|
143
|
-
console.log(`${manifest.id} ${manifest.version} 清单通过`);
|
|
144
|
-
} else {
|
|
145
|
-
console.log("用法: npm run plugin -- new|check|pack|registry-check");
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function resolveDir(value) {
|
|
149
|
-
return value || ".";
|
|
150
|
-
}
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
mkdirSync,
|
|
4
|
+
readdirSync,
|
|
5
|
+
readFileSync,
|
|
6
|
+
statSync,
|
|
7
|
+
writeFileSync,
|
|
8
|
+
} from "node:fs";
|
|
9
|
+
import { join, relative } from "node:path";
|
|
10
|
+
import { validateManifest } from "../server/plugins/manifest.js";
|
|
11
|
+
|
|
12
|
+
const command = process.argv[2];
|
|
13
|
+
const arg = process.argv[3];
|
|
14
|
+
|
|
15
|
+
function walk(dir, out = []) {
|
|
16
|
+
for (const name of readdirSync(dir)) {
|
|
17
|
+
if (name === "node_modules") continue;
|
|
18
|
+
const path = join(dir, name);
|
|
19
|
+
if (statSync(path).isDirectory()) walk(path, out);
|
|
20
|
+
else out.push(path);
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function crc32(buffer) {
|
|
26
|
+
let crc = ~0;
|
|
27
|
+
for (const byte of buffer) {
|
|
28
|
+
crc ^= byte;
|
|
29
|
+
for (let bit = 0; bit < 8; bit++)
|
|
30
|
+
crc = crc & 1 ? (crc >>> 1) ^ 0xedb88320 : crc >>> 1;
|
|
31
|
+
}
|
|
32
|
+
return ~crc >>> 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function pack(dir) {
|
|
36
|
+
const files = walk(dir).map((path) => ({
|
|
37
|
+
name: relative(dir, path).replace(/\\/g, "/"),
|
|
38
|
+
bytes: readFileSync(path),
|
|
39
|
+
}));
|
|
40
|
+
const locals = [];
|
|
41
|
+
const central = [];
|
|
42
|
+
let offset = 0;
|
|
43
|
+
for (const file of files) {
|
|
44
|
+
const name = Buffer.from(file.name);
|
|
45
|
+
const crc = crc32(file.bytes);
|
|
46
|
+
const local = Buffer.alloc(30 + name.length);
|
|
47
|
+
local.writeUInt32LE(0x04034b50, 0);
|
|
48
|
+
local.writeUInt16LE(20, 4);
|
|
49
|
+
local.writeUInt32LE(crc, 14);
|
|
50
|
+
local.writeUInt32LE(file.bytes.length, 18);
|
|
51
|
+
local.writeUInt32LE(file.bytes.length, 22);
|
|
52
|
+
local.writeUInt16LE(name.length, 26);
|
|
53
|
+
name.copy(local, 30);
|
|
54
|
+
const centralHeader = Buffer.alloc(46 + name.length);
|
|
55
|
+
centralHeader.writeUInt32LE(0x02014b50, 0);
|
|
56
|
+
centralHeader.writeUInt16LE(20, 4);
|
|
57
|
+
centralHeader.writeUInt16LE(20, 6);
|
|
58
|
+
centralHeader.writeUInt32LE(crc, 16);
|
|
59
|
+
centralHeader.writeUInt32LE(file.bytes.length, 20);
|
|
60
|
+
centralHeader.writeUInt32LE(file.bytes.length, 24);
|
|
61
|
+
centralHeader.writeUInt16LE(name.length, 28);
|
|
62
|
+
centralHeader.writeUInt32LE(offset, 42);
|
|
63
|
+
name.copy(centralHeader, 46);
|
|
64
|
+
locals.push(local, file.bytes);
|
|
65
|
+
central.push(centralHeader);
|
|
66
|
+
offset += local.length + file.bytes.length;
|
|
67
|
+
}
|
|
68
|
+
const directory = Buffer.concat(central);
|
|
69
|
+
const end = Buffer.alloc(22);
|
|
70
|
+
end.writeUInt32LE(0x06054b50, 0);
|
|
71
|
+
end.writeUInt16LE(files.length, 8);
|
|
72
|
+
end.writeUInt16LE(files.length, 10);
|
|
73
|
+
end.writeUInt32LE(directory.length, 12);
|
|
74
|
+
end.writeUInt32LE(offset, 16);
|
|
75
|
+
return Buffer.concat([...locals, directory, end]);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (command === "new") {
|
|
79
|
+
const id = arg || "example";
|
|
80
|
+
const dir = join("plugins", id);
|
|
81
|
+
mkdirSync(dir, { recursive: true });
|
|
82
|
+
writeFileSync(
|
|
83
|
+
join(dir, "luckytri-plugin.json"),
|
|
84
|
+
JSON.stringify(
|
|
85
|
+
{
|
|
86
|
+
id,
|
|
87
|
+
name: id,
|
|
88
|
+
version: "0.1.0",
|
|
89
|
+
pluginApi: "1.0",
|
|
90
|
+
luckytri: ">=1.0.0 <2.0.0",
|
|
91
|
+
description: "",
|
|
92
|
+
entry: "index.js",
|
|
93
|
+
permissions: [],
|
|
94
|
+
contributes: {},
|
|
95
|
+
},
|
|
96
|
+
null,
|
|
97
|
+
2,
|
|
98
|
+
),
|
|
99
|
+
);
|
|
100
|
+
writeFileSync(
|
|
101
|
+
join(dir, "index.js"),
|
|
102
|
+
"export default { activate(ctx) { ctx.status.set({ text: '已接上', tone: 'ok' }); } };\n",
|
|
103
|
+
);
|
|
104
|
+
console.log(dir);
|
|
105
|
+
} else if (command === "pack") {
|
|
106
|
+
const dir = arg;
|
|
107
|
+
const manifest = JSON.parse(
|
|
108
|
+
readFileSync(join(dir, "luckytri-plugin.json"), "utf8"),
|
|
109
|
+
);
|
|
110
|
+
const bytes = pack(dir);
|
|
111
|
+
const file = `${manifest.id}-${manifest.version}.zip`;
|
|
112
|
+
writeFileSync(file, bytes);
|
|
113
|
+
const sha256 = createHash("sha256").update(bytes).digest("hex");
|
|
114
|
+
console.log(
|
|
115
|
+
JSON.stringify(
|
|
116
|
+
{
|
|
117
|
+
id: manifest.id,
|
|
118
|
+
version: manifest.version,
|
|
119
|
+
pluginApi: manifest.pluginApi,
|
|
120
|
+
luckytri: manifest.luckytri,
|
|
121
|
+
sha256,
|
|
122
|
+
permissions: manifest.permissions,
|
|
123
|
+
network: manifest.network || [],
|
|
124
|
+
file,
|
|
125
|
+
},
|
|
126
|
+
null,
|
|
127
|
+
2,
|
|
128
|
+
),
|
|
129
|
+
);
|
|
130
|
+
} else if (command === "registry-check") {
|
|
131
|
+
const index = JSON.parse(readFileSync(arg || "index.json", "utf8"));
|
|
132
|
+
if (index.format !== 1 || !Array.isArray(index.plugins))
|
|
133
|
+
throw new Error("插件索引无效");
|
|
134
|
+
for (const plugin of index.plugins)
|
|
135
|
+
for (const version of plugin.versions || [])
|
|
136
|
+
if (!version.sha256 || !version.url) throw new Error("插件索引无效");
|
|
137
|
+
console.log(`ok ${index.plugins.length}`);
|
|
138
|
+
} else if (command === "check") {
|
|
139
|
+
const dir = resolveDir(arg);
|
|
140
|
+
const manifest = validateManifest(
|
|
141
|
+
JSON.parse(readFileSync(join(dir, "luckytri-plugin.json"), "utf8")),
|
|
142
|
+
);
|
|
143
|
+
console.log(`${manifest.id} ${manifest.version} 清单通过`);
|
|
144
|
+
} else {
|
|
145
|
+
console.log("用法: npm run plugin -- new|check|pack|registry-check");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function resolveDir(value) {
|
|
149
|
+
return value || ".";
|
|
150
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { prepareRuntime } from "./runtime.js";
|
|
2
|
+
import { running, serviceHeaders, serviceUrl } from "./service.js";
|
|
3
|
+
try {
|
|
4
|
+
prepareRuntime({ initialize: false });
|
|
5
|
+
const base = serviceUrl();
|
|
6
|
+
if (!(await running({ base })))
|
|
7
|
+
throw Error("请先运行 luckytri,再重置管理密码。");
|
|
8
|
+
const response = await fetch(base + "/api/auth/reset", {
|
|
9
|
+
method: "POST",
|
|
10
|
+
headers: serviceHeaders(),
|
|
11
|
+
body: "{}",
|
|
12
|
+
signal: AbortSignal.timeout(5000),
|
|
13
|
+
});
|
|
14
|
+
if (!response.ok)
|
|
15
|
+
throw Error("无法重置密码,请确认正在运行 LuckyTri 1.0.1 或更新版本。");
|
|
16
|
+
console.log(
|
|
17
|
+
"管理密码已重置,刷新管理台后重新设置。数据库、记忆和配置均保留。",
|
|
18
|
+
);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error(error.message);
|
|
21
|
+
process.exitCode = 1;
|
|
22
|
+
}
|
package/scripts/runtime.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { mkdirSync } from "node:fs";
|
|
2
|
-
import { runtimePaths } from "../server/paths.js";
|
|
3
|
-
import { initializeEnvironment } from "./setup.js";
|
|
4
|
-
|
|
5
|
-
export function prepareRuntime({ initialize = true } = {}) {
|
|
6
|
-
let paths = runtimePaths();
|
|
7
|
-
process.env.LUCKYTRI_HOME = paths.home;
|
|
8
|
-
if (initialize) {
|
|
9
|
-
mkdirSync(paths.home, { recursive: true, mode: 0o700 });
|
|
10
|
-
if (initializeEnvironment(paths.home))
|
|
11
|
-
console.log(
|
|
12
|
-
`已创建本机配置 / Created local configuration: ${paths.config}\n
|
|
13
|
-
);
|
|
14
|
-
}
|
|
15
|
-
try {
|
|
16
|
-
process.loadEnvFile(paths.config);
|
|
17
|
-
} catch (error) {
|
|
18
|
-
if (error.code !== "ENOENT") throw error;
|
|
19
|
-
}
|
|
20
|
-
paths = runtimePaths();
|
|
21
|
-
// Child processes and backup workers inherit the same absolute paths.
|
|
22
|
-
process.env.DB_PATH = paths.database;
|
|
23
|
-
process.env.BACKUP_DIR = paths.backups;
|
|
24
|
-
return paths;
|
|
25
|
-
}
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import { runtimePaths } from "../server/paths.js";
|
|
3
|
+
import { initializeEnvironment } from "./setup.js";
|
|
4
|
+
|
|
5
|
+
export function prepareRuntime({ initialize = true } = {}) {
|
|
6
|
+
let paths = runtimePaths();
|
|
7
|
+
process.env.LUCKYTRI_HOME = paths.home;
|
|
8
|
+
if (initialize) {
|
|
9
|
+
mkdirSync(paths.home, { recursive: true, mode: 0o700 });
|
|
10
|
+
if (initializeEnvironment(paths.home))
|
|
11
|
+
console.log(
|
|
12
|
+
`已创建本机配置 / Created local configuration: ${paths.config}\n首次打开管理台时设置一个密码即可。`,
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
process.loadEnvFile(paths.config);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
if (error.code !== "ENOENT") throw error;
|
|
19
|
+
}
|
|
20
|
+
paths = runtimePaths();
|
|
21
|
+
// Child processes and backup workers inherit the same absolute paths.
|
|
22
|
+
process.env.DB_PATH = paths.database;
|
|
23
|
+
process.env.BACKUP_DIR = paths.backups;
|
|
24
|
+
return paths;
|
|
25
|
+
}
|
package/scripts/service.js
CHANGED
|
@@ -1,47 +1,56 @@
|
|
|
1
|
-
import { runtimePaths } from "../server/paths.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
import { runtimePaths } from "../server/paths.js";
|
|
2
|
+
import { localServiceKey } from "../server/local-access.js";
|
|
3
|
+
let legacy = false;
|
|
4
|
+
|
|
5
|
+
export function serviceUrl(env = process.env) {
|
|
6
|
+
const port = Number(env.PORT || 3210);
|
|
7
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
8
|
+
throw Error("PORT 必须是 1–65535 / PORT must be between 1 and 65535");
|
|
9
|
+
const raw = env.HOST || "127.0.0.1";
|
|
10
|
+
const host = raw === "0.0.0.0" ? "127.0.0.1" : raw === "::" ? "::1" : raw;
|
|
11
|
+
return new URL(`http://${host.includes(":") ? `[${host}]` : host}:${port}`)
|
|
12
|
+
.origin;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const serviceHeaders = () => ({
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
Authorization: `Bearer ${legacy ? process.env.ADMIN_TOKEN : localServiceKey()}`,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export async function running({ base = serviceUrl(), lenient = false } = {}) {
|
|
21
|
+
let response;
|
|
22
|
+
try {
|
|
23
|
+
response = await fetch(base + "/api/service/status", {
|
|
24
|
+
headers: serviceHeaders(),
|
|
25
|
+
signal: AbortSignal.timeout(1500),
|
|
26
|
+
});
|
|
27
|
+
} catch (error) {
|
|
28
|
+
if (lenient || error.cause?.code === "ECONNREFUSED") {
|
|
29
|
+
legacy = false;
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
throw Error("无法确认端口状态,请检查服务或网络;未重复启动。");
|
|
33
|
+
}
|
|
34
|
+
if (response.status === 401 && !legacy && process.env.ADMIN_TOKEN) {
|
|
35
|
+
// Allow the new CLI to gracefully stop a still-running 1.0.0 instance.
|
|
36
|
+
legacy = true;
|
|
37
|
+
return running({ base, lenient });
|
|
38
|
+
}
|
|
39
|
+
if (!response.ok) throw Error("端口已被占用或不是当前实例,请检查本机配置。");
|
|
40
|
+
let info;
|
|
41
|
+
try {
|
|
42
|
+
info = await response.json();
|
|
43
|
+
} catch {
|
|
44
|
+
throw Error("此端口运行的不是 LuckyTri。");
|
|
45
|
+
}
|
|
46
|
+
const paths = runtimePaths();
|
|
47
|
+
const normalize = (value) =>
|
|
48
|
+
process.platform === "win32" ? value.toLowerCase() : value;
|
|
49
|
+
if (
|
|
50
|
+
!["luckytri", "luckybot", "lucky", "xiaoman"].includes(info.app) ||
|
|
51
|
+
typeof (info.home ?? info.workspace) !== "string" ||
|
|
52
|
+
normalize(info.home ?? info.workspace) !== normalize(paths.home)
|
|
53
|
+
)
|
|
54
|
+
throw Error("此端口已被其他实例占用,未操作任何进程。");
|
|
55
|
+
return info;
|
|
56
|
+
}
|
package/scripts/setup.js
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
"",
|
|
18
|
-
"#
|
|
19
|
-
"#
|
|
20
|
-
"
|
|
21
|
-
"",
|
|
22
|
-
"# OneBot
|
|
23
|
-
|
|
24
|
-
"",
|
|
25
|
-
"# QQ 官方机器人 / QQ official bot",
|
|
26
|
-
"# QQBOT_APP_ID=",
|
|
27
|
-
"# QQBOT_APP_SECRET=",
|
|
28
|
-
"",
|
|
29
|
-
"LLM_API_KEY=",
|
|
30
|
-
"",
|
|
31
|
-
].join("\n");
|
|
32
|
-
try {
|
|
33
|
-
writeFileSync(file, content, { flag: "wx", mode: 0o600 });
|
|
34
|
-
return true;
|
|
35
|
-
} catch (error) {
|
|
36
|
-
if (error.code === "EEXIST") return false;
|
|
37
|
-
throw error;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (
|
|
41
|
-
process.argv[1] &&
|
|
42
|
-
import.meta.url === pathToFileURL(resolve(process.argv[1])).href
|
|
43
|
-
) {
|
|
44
|
-
const created = initializeEnvironment();
|
|
45
|
-
console.log(
|
|
46
|
-
created
|
|
47
|
-
? "
|
|
48
|
-
: "已有 .env,已保留原文件,不覆盖任何配置。\nA .env already exists and was left untouched.",
|
|
49
|
-
);
|
|
50
|
-
}
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { runtimePaths } from "../server/paths.js";
|
|
5
|
+
|
|
6
|
+
export function initializeEnvironment(directory = runtimePaths().home) {
|
|
7
|
+
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
8
|
+
const file = resolve(directory, ".env");
|
|
9
|
+
const content = [
|
|
10
|
+
"# LuckyTri 本机配置。修改后重启服务,不要公开此文件。",
|
|
11
|
+
"# LuckyTri local configuration. Restart after editing and never share this file.",
|
|
12
|
+
"HOST=127.0.0.1",
|
|
13
|
+
"PORT=3210",
|
|
14
|
+
"# 首次打开管理台时设置一个管理密码。",
|
|
15
|
+
"# Set your management password on the first visit to the studio.",
|
|
16
|
+
"",
|
|
17
|
+
"# 连接 QQ 的方式二选一,也可以在管理界面「连接 QQ」里选择。",
|
|
18
|
+
"# Pick one way to connect QQ; it can also be chosen in the studio under Connect QQ.",
|
|
19
|
+
"# LUCKYTRI_CHANNEL=onebot # onebot | qqbot;设置后界面里不能再改 / locks the choice when set",
|
|
20
|
+
"",
|
|
21
|
+
"# OneBot 11",
|
|
22
|
+
"# 本机 OneBot 接入无需单独令牌;远程接入可使用管理密码。",
|
|
23
|
+
"# Local OneBot clients need no separate token; remote clients can use the management password.",
|
|
24
|
+
"",
|
|
25
|
+
"# QQ 官方机器人 / QQ official bot",
|
|
26
|
+
"# QQBOT_APP_ID=",
|
|
27
|
+
"# QQBOT_APP_SECRET=",
|
|
28
|
+
"",
|
|
29
|
+
"LLM_API_KEY=",
|
|
30
|
+
"",
|
|
31
|
+
].join("\n");
|
|
32
|
+
try {
|
|
33
|
+
writeFileSync(file, content, { flag: "wx", mode: 0o600 });
|
|
34
|
+
return true;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (error.code === "EEXIST") return false;
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (
|
|
41
|
+
process.argv[1] &&
|
|
42
|
+
import.meta.url === pathToFileURL(resolve(process.argv[1])).href
|
|
43
|
+
) {
|
|
44
|
+
const created = initializeEnvironment();
|
|
45
|
+
console.log(
|
|
46
|
+
created
|
|
47
|
+
? "已生成本机配置,首次打开管理台时设置密码。\nCreated local configuration. Set a password on the first visit to the studio."
|
|
48
|
+
: "已有 .env,已保留原文件,不覆盖任何配置。\nA .env already exists and was left untouched.",
|
|
49
|
+
);
|
|
50
|
+
}
|