mioku 0.9.2 → 0.9.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/dist/{cli.cjs → cli/index.cjs} +267 -287
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.js +446 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.cjs +255 -335
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +237 -322
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +237 -322
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +283 -363
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.js +0 -466
- package/dist/cli.js.map +0 -1
- /package/dist/{cli.d.cts → cli/index.d.cts} +0 -0
- /package/dist/{cli.d.ts → cli/index.d.ts} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import * as path$
|
|
4
|
-
import * as fs$6 from "fs/promises";
|
|
5
|
-
import * as fs$5 from "fs/promises";
|
|
6
|
-
import * as fs$4 from "fs/promises";
|
|
7
|
-
import * as fs$3 from "fs/promises";
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import { existsSync, mkdirSync } from "fs";
|
|
3
|
+
import * as path$8 from "path";
|
|
8
4
|
import * as path$7 from "path";
|
|
9
5
|
import * as path$6 from "path";
|
|
10
6
|
import * as path$5 from "path";
|
|
11
7
|
import * as path$4 from "path";
|
|
8
|
+
import * as path$3 from "path";
|
|
12
9
|
import * as path$2 from "path";
|
|
13
10
|
import * as path$1 from "path";
|
|
14
|
-
import * as
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
import * as path from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
|
+
import * as fs$6 from "fs/promises";
|
|
14
|
+
import * as fs$5 from "fs/promises";
|
|
15
|
+
import * as fs$4 from "fs/promises";
|
|
16
|
+
import * as fs$3 from "fs/promises";
|
|
17
|
+
import * as fs$2 from "fs/promises";
|
|
18
|
+
import * as fs$1 from "fs/promises";
|
|
19
|
+
import { botConfig } from "mioki";
|
|
19
20
|
|
|
20
|
-
//#endregion
|
|
21
21
|
//#region src/core/logger.ts
|
|
22
22
|
const fallbackLogger = {
|
|
23
23
|
error: (...args) => console.error(...args),
|
|
@@ -39,9 +39,8 @@ const logger = {
|
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
//#endregion
|
|
42
|
-
//#region src/core/
|
|
43
|
-
|
|
44
|
-
async function pathExists$3(filePath) {
|
|
42
|
+
//#region src/core/module-scanner.ts
|
|
43
|
+
async function pathExists(filePath) {
|
|
45
44
|
try {
|
|
46
45
|
await fs$6.access(filePath);
|
|
47
46
|
return true;
|
|
@@ -49,68 +48,126 @@ async function pathExists$3(filePath) {
|
|
|
49
48
|
return false;
|
|
50
49
|
}
|
|
51
50
|
}
|
|
51
|
+
async function resolveRealpath(p) {
|
|
52
|
+
try {
|
|
53
|
+
return await fs$6.realpath(p);
|
|
54
|
+
} catch {
|
|
55
|
+
return p;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function toImportPath(filePath) {
|
|
59
|
+
if (process.platform === "win32") return "file:///" + filePath.replace(/\\/g, "/");
|
|
60
|
+
return filePath;
|
|
61
|
+
}
|
|
62
|
+
async function scanLocalDir(dir) {
|
|
63
|
+
const results = [];
|
|
64
|
+
if (!await pathExists(dir)) return results;
|
|
65
|
+
let entries;
|
|
66
|
+
try {
|
|
67
|
+
entries = await fs$6.readdir(dir, { withFileTypes: true });
|
|
68
|
+
} catch {
|
|
69
|
+
return results;
|
|
70
|
+
}
|
|
71
|
+
for (const entry of entries) {
|
|
72
|
+
const entryPath = path$8.join(dir, entry.name);
|
|
73
|
+
try {
|
|
74
|
+
const stat = await fs$6.stat(entryPath);
|
|
75
|
+
if (!stat.isDirectory()) continue;
|
|
76
|
+
} catch {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
results.push({
|
|
80
|
+
name: entry.name,
|
|
81
|
+
path: await resolveRealpath(entryPath)
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return results;
|
|
85
|
+
}
|
|
86
|
+
async function scanNodeModules(prefix) {
|
|
87
|
+
const results = [];
|
|
88
|
+
const nodeModulesPath = path$8.resolve(process.cwd(), "node_modules");
|
|
89
|
+
if (!await pathExists(nodeModulesPath)) return results;
|
|
90
|
+
let entries;
|
|
91
|
+
try {
|
|
92
|
+
entries = await fs$6.readdir(nodeModulesPath, { withFileTypes: true });
|
|
93
|
+
} catch {
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
for (const entry of entries) {
|
|
97
|
+
if (!entry.name.startsWith(prefix)) continue;
|
|
98
|
+
const name = entry.name.slice(prefix.length);
|
|
99
|
+
const fullPath = path$8.join(nodeModulesPath, entry.name);
|
|
100
|
+
results.push({
|
|
101
|
+
name,
|
|
102
|
+
path: await resolveRealpath(fullPath)
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return results;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/core/plugin-linker.ts
|
|
110
|
+
const DEFAULT_RUNTIME_PLUGINS_DIR = ".mioku/plugins";
|
|
52
111
|
async function removeIfBrokenSymlink(entryPath) {
|
|
53
112
|
let stat;
|
|
54
113
|
try {
|
|
55
|
-
stat = await fs$
|
|
114
|
+
stat = await fs$5.lstat(entryPath);
|
|
56
115
|
} catch {
|
|
57
116
|
return "removed";
|
|
58
117
|
}
|
|
59
118
|
if (!stat.isSymbolicLink()) return "blocked";
|
|
60
119
|
try {
|
|
61
|
-
await fs$
|
|
120
|
+
await fs$5.realpath(entryPath);
|
|
62
121
|
return "ok";
|
|
63
122
|
} catch {
|
|
64
|
-
await fs$
|
|
123
|
+
await fs$5.rm(entryPath, { force: true });
|
|
65
124
|
logger.warn(`[plugin-linker] Removed broken plugin link: ${entryPath}`);
|
|
66
125
|
return "removed";
|
|
67
126
|
}
|
|
68
127
|
}
|
|
69
128
|
function relativeSymlinkTarget(linkPath, targetPath) {
|
|
70
|
-
|
|
71
|
-
return relativePath || ".";
|
|
129
|
+
return path$7.relative(path$7.dirname(linkPath), targetPath) || ".";
|
|
72
130
|
}
|
|
73
131
|
async function ensurePluginLink(runtimePluginsDir, metadata) {
|
|
74
132
|
const linkPath = path$7.join(runtimePluginsDir, metadata.name);
|
|
75
133
|
const targetPath = metadata.path;
|
|
76
134
|
let stat;
|
|
77
135
|
try {
|
|
78
|
-
stat = await fs$
|
|
136
|
+
stat = await fs$5.lstat(linkPath);
|
|
79
137
|
} catch {
|
|
80
138
|
stat = null;
|
|
81
139
|
}
|
|
82
140
|
if (stat?.isSymbolicLink()) try {
|
|
83
|
-
const currentTarget = await fs$
|
|
84
|
-
const expectedTarget = await fs$
|
|
141
|
+
const currentTarget = await fs$5.realpath(linkPath);
|
|
142
|
+
const expectedTarget = await fs$5.realpath(targetPath);
|
|
85
143
|
if (currentTarget === expectedTarget) return true;
|
|
86
|
-
await fs$
|
|
144
|
+
await fs$5.rm(linkPath, { force: true });
|
|
87
145
|
logger.info(`[plugin-linker] Rebuilding plugin link: ${metadata.name}`);
|
|
88
146
|
} catch {
|
|
89
|
-
await fs$
|
|
147
|
+
await fs$5.rm(linkPath, { force: true });
|
|
90
148
|
logger.warn(`[plugin-linker] Removed broken plugin link: ${linkPath}`);
|
|
91
149
|
}
|
|
92
150
|
else if (stat) {
|
|
93
151
|
logger.warn(`[plugin-linker] ${linkPath} exists and is not a symlink, skip linking ${metadata.name}`);
|
|
94
152
|
return false;
|
|
95
153
|
}
|
|
96
|
-
if (!await pathExists
|
|
154
|
+
if (!await pathExists(targetPath)) {
|
|
97
155
|
logger.warn(`[plugin-linker] Plugin target missing, skip linking ${metadata.name}: ${targetPath}`);
|
|
98
156
|
return false;
|
|
99
157
|
}
|
|
100
|
-
if (process.platform === "win32") await fs$
|
|
101
|
-
else await fs$
|
|
158
|
+
if (process.platform === "win32") await fs$5.symlink(targetPath, linkPath, "junction");
|
|
159
|
+
else await fs$5.symlink(relativeSymlinkTarget(linkPath, targetPath), linkPath, "dir");
|
|
102
160
|
return true;
|
|
103
161
|
}
|
|
104
162
|
async function prepareRuntimePluginLinks(plugins, runtimePluginsDir = path$7.resolve(process.cwd(), DEFAULT_RUNTIME_PLUGINS_DIR)) {
|
|
105
|
-
await fs$
|
|
106
|
-
const discoveredNames = new Set(plugins.map((
|
|
107
|
-
const entries = await fs$
|
|
163
|
+
await fs$5.mkdir(runtimePluginsDir, { recursive: true });
|
|
164
|
+
const discoveredNames = new Set(plugins.map((p) => p.name));
|
|
165
|
+
const entries = await fs$5.readdir(runtimePluginsDir, { withFileTypes: true });
|
|
108
166
|
for (const entry of entries) {
|
|
109
167
|
const entryPath = path$7.join(runtimePluginsDir, entry.name);
|
|
110
|
-
|
|
111
|
-
if (symlinkState !== "ok") continue;
|
|
168
|
+
if (await removeIfBrokenSymlink(entryPath) !== "ok") continue;
|
|
112
169
|
if (entry.isSymbolicLink() && !discoveredNames.has(entry.name)) {
|
|
113
|
-
await fs$
|
|
170
|
+
await fs$5.rm(entryPath, { force: true });
|
|
114
171
|
logger.info(`[plugin-linker] Removed stale plugin link: ${entry.name}`);
|
|
115
172
|
}
|
|
116
173
|
}
|
|
@@ -120,279 +177,166 @@ async function prepareRuntimePluginLinks(plugins, runtimePluginsDir = path$7.res
|
|
|
120
177
|
}
|
|
121
178
|
|
|
122
179
|
//#endregion
|
|
123
|
-
//#region src/core/
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
180
|
+
//#region src/core/registry.ts
|
|
181
|
+
const STORE_SYMBOL = Symbol.for("mioku.globalStore");
|
|
182
|
+
function store$1() {
|
|
183
|
+
const g = globalThis;
|
|
184
|
+
if (!g[STORE_SYMBOL]) g[STORE_SYMBOL] = {};
|
|
185
|
+
return g[STORE_SYMBOL];
|
|
186
|
+
}
|
|
187
|
+
function getOrCreate(key, factory) {
|
|
188
|
+
const s = store$1();
|
|
189
|
+
if (s[key] === void 0) s[key] = factory();
|
|
190
|
+
return s[key];
|
|
132
191
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
*/
|
|
192
|
+
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/core/plugin-manager.ts
|
|
195
|
+
const PLUGIN_PREFIX = "mioku-plugin-";
|
|
138
196
|
var PluginManager = class PluginManager {
|
|
139
|
-
|
|
197
|
+
plugins = new Map();
|
|
140
198
|
static getInstance() {
|
|
141
|
-
|
|
142
|
-
if (!g[PLUGIN_MANAGER_SYMBOL]) g[PLUGIN_MANAGER_SYMBOL] = new PluginManager();
|
|
143
|
-
return g[PLUGIN_MANAGER_SYMBOL];
|
|
199
|
+
return getOrCreate("plugin-manager", () => new PluginManager());
|
|
144
200
|
}
|
|
145
201
|
async discoverPlugins(miokuConfig = {}) {
|
|
146
|
-
const
|
|
147
|
-
const pluginsDir =
|
|
148
|
-
this.
|
|
149
|
-
if (!await pathExists
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
|
|
202
|
+
const configuredDir = miokuConfig.plugins_dir;
|
|
203
|
+
const pluginsDir = configuredDir && configuredDir !== DEFAULT_RUNTIME_PLUGINS_DIR ? path$6.resolve(process.cwd(), configuredDir) : path$6.resolve(process.cwd(), "plugins");
|
|
204
|
+
this.plugins.clear();
|
|
205
|
+
if (!await pathExists(pluginsDir)) mkdirSync(pluginsDir, { recursive: true });
|
|
206
|
+
const local = await scanLocalDir(pluginsDir);
|
|
207
|
+
for (const { name, path: p } of local) {
|
|
208
|
+
const metadata = await this.loadPluginMetadata(name, p);
|
|
209
|
+
if (metadata) this.plugins.set(metadata.name, metadata);
|
|
154
210
|
}
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
async discoverFromDir(pluginsDir) {
|
|
161
|
-
const discovered = [];
|
|
162
|
-
try {
|
|
163
|
-
const entries = await fs$5.readdir(pluginsDir, { withFileTypes: true });
|
|
164
|
-
for (const entry of entries) {
|
|
165
|
-
const pluginPath = path$6.join(pluginsDir, entry.name);
|
|
166
|
-
const metadataPath = await this.resolveDirectoryPath(pluginPath);
|
|
167
|
-
if (!metadataPath) continue;
|
|
168
|
-
const metadata = await this.loadPluginMetadata(entry.name, pluginPath);
|
|
169
|
-
if (metadata) {
|
|
170
|
-
discovered.push(metadata);
|
|
171
|
-
this.pluginMetadata.set(metadata.name, metadata);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
} catch (error) {
|
|
175
|
-
logger.error(`扫描插件目录失败: ${error}`);
|
|
176
|
-
}
|
|
177
|
-
return discovered;
|
|
178
|
-
}
|
|
179
|
-
async discoverFromNodeModules() {
|
|
180
|
-
const discovered = [];
|
|
181
|
-
const nodeModulesPath = path$6.resolve(process.cwd(), "node_modules");
|
|
182
|
-
if (!await pathExists$2(nodeModulesPath)) return discovered;
|
|
183
|
-
try {
|
|
184
|
-
const entries = await fs$5.readdir(nodeModulesPath, { withFileTypes: true });
|
|
185
|
-
for (const entry of entries) {
|
|
186
|
-
if (!entry.name.startsWith("mioku-plugin-")) continue;
|
|
187
|
-
const pluginName = entry.name.replace(/^mioku-plugin-/, "");
|
|
188
|
-
const pluginPath = path$6.join(nodeModulesPath, entry.name);
|
|
189
|
-
const metadata = await this.loadPluginMetadata(pluginName, pluginPath);
|
|
190
|
-
if (metadata) {
|
|
191
|
-
discovered.push(metadata);
|
|
192
|
-
this.pluginMetadata.set(metadata.name, metadata);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
} catch (error) {
|
|
196
|
-
logger.debug(`扫描 node_modules 插件失败: ${error}`);
|
|
197
|
-
}
|
|
198
|
-
return discovered;
|
|
199
|
-
}
|
|
200
|
-
async resolveDirectoryPath(entryPath) {
|
|
201
|
-
try {
|
|
202
|
-
const stat = await fs$5.stat(entryPath);
|
|
203
|
-
return stat.isDirectory() ? entryPath : null;
|
|
204
|
-
} catch {
|
|
205
|
-
return null;
|
|
211
|
+
const external = await scanNodeModules(PLUGIN_PREFIX);
|
|
212
|
+
for (const { name, path: p } of external) {
|
|
213
|
+
const metadata = await this.loadPluginMetadata(name, p);
|
|
214
|
+
if (metadata) this.plugins.set(metadata.name, metadata);
|
|
206
215
|
}
|
|
216
|
+
logger.info(`O.o 发现了 ${this.plugins.size} 个插件`);
|
|
217
|
+
return [...this.plugins.values()];
|
|
207
218
|
}
|
|
208
219
|
async loadPluginMetadata(name, pluginPath) {
|
|
209
|
-
|
|
210
|
-
try {
|
|
211
|
-
resolvedPath = await fs$5.realpath(pluginPath);
|
|
212
|
-
} catch {}
|
|
213
|
-
const packageJsonPath = path$6.join(resolvedPath, "package.json");
|
|
220
|
+
const resolvedPath = await resolveRealpath(pluginPath);
|
|
214
221
|
let packageJson = null;
|
|
215
222
|
try {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
223
|
+
packageJson = JSON.parse(await fs$4.readFile(path$6.join(resolvedPath, "package.json"), "utf-8"));
|
|
224
|
+
} catch (error) {
|
|
225
|
+
logger.warn(`[plugin-manager] 读取 ${name} 的 package.json 失败: ${error}`);
|
|
226
|
+
}
|
|
227
|
+
const config = packageJson?.mioku ?? {};
|
|
228
|
+
return {
|
|
220
229
|
name,
|
|
221
|
-
version: packageJson?.version
|
|
230
|
+
version: packageJson?.version ?? "0.0.0",
|
|
222
231
|
description: packageJson?.description,
|
|
223
232
|
path: resolvedPath,
|
|
224
|
-
packageJson,
|
|
225
|
-
config
|
|
233
|
+
packageJson: packageJson ?? {},
|
|
234
|
+
config
|
|
226
235
|
};
|
|
227
|
-
return metadata;
|
|
228
236
|
}
|
|
229
237
|
collectRequiredServices() {
|
|
230
238
|
const services = new Set();
|
|
231
|
-
for (const metadata of this.
|
|
239
|
+
for (const metadata of this.plugins.values()) for (const service of metadata.config.services ?? []) services.add(service);
|
|
232
240
|
return services;
|
|
233
241
|
}
|
|
234
242
|
getPluginMetadata(name) {
|
|
235
|
-
return this.
|
|
243
|
+
return this.plugins.get(name);
|
|
236
244
|
}
|
|
237
245
|
getAllMetadata() {
|
|
238
|
-
return
|
|
246
|
+
return [...this.plugins.values()];
|
|
239
247
|
}
|
|
240
248
|
reset() {
|
|
241
|
-
this.
|
|
249
|
+
this.plugins.clear();
|
|
242
250
|
}
|
|
243
251
|
};
|
|
244
252
|
var plugin_manager_default = PluginManager.getInstance();
|
|
245
253
|
|
|
246
254
|
//#endregion
|
|
247
255
|
//#region src/core/service-manager.ts
|
|
248
|
-
const
|
|
249
|
-
async function pathExists$1(filePath) {
|
|
250
|
-
try {
|
|
251
|
-
await fs$4.access(filePath);
|
|
252
|
-
return true;
|
|
253
|
-
} catch {
|
|
254
|
-
return false;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* 服务管理器
|
|
259
|
-
*/
|
|
256
|
+
const SERVICE_PREFIX = "mioku-service-";
|
|
260
257
|
var ServiceManager = class ServiceManager {
|
|
261
258
|
services = new Map();
|
|
262
259
|
serviceMetadata = new Map();
|
|
263
|
-
servicesDir = "services";
|
|
264
260
|
static getInstance() {
|
|
265
|
-
|
|
266
|
-
if (!g[SERVICE_MANAGER_SYMBOL]) g[SERVICE_MANAGER_SYMBOL] = new ServiceManager();
|
|
267
|
-
return g[SERVICE_MANAGER_SYMBOL];
|
|
261
|
+
return getOrCreate("service-manager", () => new ServiceManager());
|
|
268
262
|
}
|
|
269
263
|
async discoverServices(miokuConfig = {}) {
|
|
270
|
-
|
|
271
|
-
else this.servicesDir = path$5.resolve(process.cwd(), "services");
|
|
272
|
-
const discovered = [];
|
|
264
|
+
const servicesDir = miokuConfig.services_dir ? path$5.resolve(process.cwd(), miokuConfig.services_dir) : path$5.resolve(process.cwd(), "services");
|
|
273
265
|
this.serviceMetadata.clear();
|
|
274
|
-
if (existsSync(
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
logger.info(`o.O 发现了 ${this.serviceMetadata.size} 个服务`);
|
|
280
|
-
return Array.from(this.serviceMetadata.values());
|
|
281
|
-
}
|
|
282
|
-
async discoverFromDir(servicesDir) {
|
|
283
|
-
const discovered = [];
|
|
284
|
-
try {
|
|
285
|
-
const entries = await fs$4.readdir(servicesDir, { withFileTypes: true });
|
|
286
|
-
for (const entry of entries) {
|
|
287
|
-
if (!entry.isDirectory()) continue;
|
|
288
|
-
const servicePath = path$5.join(servicesDir, entry.name);
|
|
289
|
-
const metadata = await this.loadServiceMetadata(entry.name, servicePath);
|
|
290
|
-
if (metadata) {
|
|
291
|
-
discovered.push(metadata);
|
|
292
|
-
this.serviceMetadata.set(entry.name, metadata);
|
|
293
|
-
}
|
|
266
|
+
if (existsSync(servicesDir)) {
|
|
267
|
+
const local = await scanLocalDir(servicesDir);
|
|
268
|
+
for (const { name, path: p } of local) {
|
|
269
|
+
const metadata = await this.loadServiceMetadata(name, p);
|
|
270
|
+
if (metadata) this.serviceMetadata.set(name, metadata);
|
|
294
271
|
}
|
|
295
|
-
}
|
|
296
|
-
|
|
272
|
+
} else mkdirSync(servicesDir, { recursive: true });
|
|
273
|
+
const external = await scanNodeModules(SERVICE_PREFIX);
|
|
274
|
+
for (const { name, path: p } of external) {
|
|
275
|
+
const metadata = await this.loadServiceMetadata(name, p);
|
|
276
|
+
if (metadata) this.serviceMetadata.set(name, metadata);
|
|
297
277
|
}
|
|
298
|
-
|
|
278
|
+
logger.info(`o.O 发现了 ${this.serviceMetadata.size} 个服务`);
|
|
279
|
+
return [...this.serviceMetadata.values()];
|
|
299
280
|
}
|
|
300
281
|
async loadServiceMetadata(name, servicePath) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
resolvedPath = await fs$4.realpath(servicePath);
|
|
304
|
-
} catch {}
|
|
305
|
-
const packageJsonPath = path$5.join(resolvedPath, "package.json");
|
|
306
|
-
if (!await pathExists$1(packageJsonPath)) return null;
|
|
282
|
+
const packageJsonPath = path$5.join(servicePath, "package.json");
|
|
283
|
+
if (!await pathExists(packageJsonPath)) return null;
|
|
307
284
|
try {
|
|
308
|
-
const packageJson = JSON.parse(await fs$
|
|
309
|
-
|
|
285
|
+
const packageJson = JSON.parse(await fs$3.readFile(packageJsonPath, "utf-8"));
|
|
286
|
+
return {
|
|
310
287
|
name,
|
|
311
|
-
version: packageJson.version
|
|
288
|
+
version: packageJson.version ?? "0.0.0",
|
|
312
289
|
description: packageJson.description,
|
|
313
|
-
path:
|
|
290
|
+
path: servicePath,
|
|
314
291
|
packageJson
|
|
315
292
|
};
|
|
316
|
-
return metadata;
|
|
317
293
|
} catch (error) {
|
|
318
|
-
logger.
|
|
294
|
+
logger.warn(`[service-manager] 解析服务 ${name} 失败: ${error}`);
|
|
319
295
|
return null;
|
|
320
296
|
}
|
|
321
297
|
}
|
|
322
|
-
|
|
323
|
-
* Load built-in services from the package
|
|
324
|
-
*/
|
|
325
|
-
async loadBuiltinServices() {
|
|
326
|
-
await this.discoverFromNodeModules();
|
|
327
|
-
}
|
|
328
|
-
async discoverFromNodeModules() {
|
|
329
|
-
const nodeModulesPath = path$5.resolve(process.cwd(), "node_modules");
|
|
330
|
-
if (!await pathExists$1(nodeModulesPath)) return;
|
|
331
|
-
try {
|
|
332
|
-
const entries = await fs$4.readdir(nodeModulesPath, { withFileTypes: true });
|
|
333
|
-
for (const entry of entries) {
|
|
334
|
-
if (!entry.name.startsWith("mioku-service-")) continue;
|
|
335
|
-
const serviceName = entry.name.replace(/^mioku-service-/, "");
|
|
336
|
-
const servicePath = path$5.join(nodeModulesPath, entry.name);
|
|
337
|
-
const metadata = await this.loadServiceMetadata(serviceName, servicePath);
|
|
338
|
-
if (metadata) this.serviceMetadata.set(serviceName, metadata);
|
|
339
|
-
}
|
|
340
|
-
} catch (error) {
|
|
341
|
-
logger.debug(`扫描 node_modules 服务失败: ${error}`);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
async checkMissingServices(requiredServices) {
|
|
298
|
+
async checkMissingServices(required) {
|
|
345
299
|
const missing = [];
|
|
346
|
-
for (const
|
|
300
|
+
for (const name of required) if (!this.serviceMetadata.has(name)) missing.push(name);
|
|
347
301
|
return missing;
|
|
348
302
|
}
|
|
349
303
|
async loadAllServices(ctx) {
|
|
350
|
-
const
|
|
351
|
-
logger.info(`O.o 准备加载 ${
|
|
352
|
-
for (const metadata of
|
|
304
|
+
const all = [...this.serviceMetadata.values()];
|
|
305
|
+
logger.info(`O.o 准备加载 ${all.length} 个服务...`);
|
|
306
|
+
for (const metadata of all) await this.loadService(metadata, ctx);
|
|
353
307
|
}
|
|
354
308
|
async loadService(metadata, ctx) {
|
|
355
309
|
try {
|
|
356
|
-
const
|
|
357
|
-
const
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
if (!entryPoint || !indexExists && !indexJsExists) {
|
|
362
|
-
logger.error(`服务 ${metadata.name} 入口丢失`);
|
|
310
|
+
const tsEntry = path$5.join(metadata.path, "index.ts");
|
|
311
|
+
const jsEntry = path$5.join(metadata.path, "index.js");
|
|
312
|
+
const entry = await pathExists(tsEntry) ? tsEntry : await pathExists(jsEntry) ? jsEntry : null;
|
|
313
|
+
if (!entry) {
|
|
314
|
+
logger.error(`[service-manager] 服务 ${metadata.name} 入口丢失`);
|
|
363
315
|
return false;
|
|
364
316
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
await service.init();
|
|
371
|
-
if (service.api) {
|
|
372
|
-
if (!ctx.services) ctx.services = {};
|
|
373
|
-
ctx.services[metadata.name] = service.api;
|
|
317
|
+
const serviceModule = await import(toImportPath(entry));
|
|
318
|
+
const service = serviceModule.default ?? serviceModule;
|
|
319
|
+
if (!service || typeof service.init !== "function") {
|
|
320
|
+
logger.warn(`[service-manager] 服务 ${metadata.name} 无效:缺少 init()`);
|
|
321
|
+
return false;
|
|
374
322
|
}
|
|
323
|
+
await service.init();
|
|
324
|
+
if (service.api) ctx.services[metadata.name] = service.api;
|
|
375
325
|
this.services.set(metadata.name, service);
|
|
376
326
|
return true;
|
|
377
327
|
} catch (error) {
|
|
378
|
-
logger.error(
|
|
328
|
+
logger.error(`[service-manager] 加载服务 ${metadata.name} 失败: ${error}`);
|
|
379
329
|
return false;
|
|
380
330
|
}
|
|
381
331
|
}
|
|
382
|
-
/**
|
|
383
|
-
* Register a builtin service directly
|
|
384
|
-
*/
|
|
385
332
|
registerBuiltinService(name, service) {
|
|
386
333
|
this.services.set(name, service);
|
|
387
334
|
}
|
|
388
|
-
/**
|
|
389
|
-
* Get a loaded service
|
|
390
|
-
*/
|
|
391
335
|
getService(name) {
|
|
392
336
|
return this.services.get(name);
|
|
393
337
|
}
|
|
394
338
|
async disposeAll() {
|
|
395
|
-
for (const [
|
|
339
|
+
for (const [, service] of this.services) await service.dispose?.();
|
|
396
340
|
this.services.clear();
|
|
397
341
|
}
|
|
398
342
|
reset() {
|
|
@@ -403,21 +347,56 @@ var ServiceManager = class ServiceManager {
|
|
|
403
347
|
var service_manager_default = ServiceManager.getInstance();
|
|
404
348
|
|
|
405
349
|
//#endregion
|
|
406
|
-
//#region src/core/
|
|
407
|
-
async function
|
|
350
|
+
//#region src/core/bootstrap.ts
|
|
351
|
+
async function readMiokuConfig() {
|
|
352
|
+
const packageJsonPath = path$4.join(process.cwd(), "package.json");
|
|
408
353
|
try {
|
|
409
|
-
await fs$
|
|
410
|
-
return
|
|
354
|
+
const pkg = JSON.parse(await fs$2.readFile(packageJsonPath, "utf-8"));
|
|
355
|
+
return pkg.mioki ?? {};
|
|
411
356
|
} catch {
|
|
412
|
-
return
|
|
357
|
+
return {};
|
|
413
358
|
}
|
|
414
359
|
}
|
|
415
|
-
function
|
|
416
|
-
|
|
417
|
-
|
|
360
|
+
function ensureRuntimeDirectories() {
|
|
361
|
+
for (const dir of [
|
|
362
|
+
"data",
|
|
363
|
+
"config",
|
|
364
|
+
"temp"
|
|
365
|
+
]) if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
418
366
|
}
|
|
367
|
+
async function discoverAndLinkPlugins(miokuConfig) {
|
|
368
|
+
logger.info("O.o Miku 正在翻找插件..");
|
|
369
|
+
const discovered = await plugin_manager_default.discoverPlugins(miokuConfig);
|
|
370
|
+
logger.info(`O.o 共发现 ${discovered.length} 个插件: ${discovered.map((p) => p.name).join(", ")}`);
|
|
371
|
+
const runtimePluginsDir = path$4.resolve(process.cwd(), DEFAULT_RUNTIME_PLUGINS_DIR);
|
|
372
|
+
return prepareRuntimePluginLinks(discovered, runtimePluginsDir);
|
|
373
|
+
}
|
|
374
|
+
async function discoverAndValidateServices(miokuConfig) {
|
|
375
|
+
logger.info("o.O Miku 正在翻找服务..");
|
|
376
|
+
await service_manager_default.discoverServices(miokuConfig);
|
|
377
|
+
const requiredServices = plugin_manager_default.collectRequiredServices();
|
|
378
|
+
const missing = await service_manager_default.checkMissingServices(requiredServices);
|
|
379
|
+
if (missing.length > 0) logger.warn(`发现缺失服务: ${missing.join(", ")}`);
|
|
380
|
+
}
|
|
381
|
+
function applyPluginAllowlist(miokuConfig, botConfig$1, linkedPluginNames) {
|
|
382
|
+
botConfig$1.plugins_dir = DEFAULT_RUNTIME_PLUGINS_DIR;
|
|
383
|
+
if (miokuConfig.plugins !== void 0) return;
|
|
384
|
+
for (const name of linkedPluginNames) if (!botConfig$1.plugins.includes(name)) botConfig$1.plugins.push(name);
|
|
385
|
+
}
|
|
386
|
+
async function bootstrapMioku(deps) {
|
|
387
|
+
const { cwd, botConfig: botConfig$1, startMioki } = deps;
|
|
388
|
+
const miokuConfig = await readMiokuConfig();
|
|
389
|
+
ensureRuntimeDirectories();
|
|
390
|
+
const linkedPluginNames = await discoverAndLinkPlugins(miokuConfig);
|
|
391
|
+
await discoverAndValidateServices(miokuConfig);
|
|
392
|
+
applyPluginAllowlist(miokuConfig, botConfig$1, linkedPluginNames);
|
|
393
|
+
await startMioki({ cwd });
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
//#endregion
|
|
397
|
+
//#region src/core/plugin-artifact-registry.ts
|
|
419
398
|
function isAISkill(value) {
|
|
420
|
-
return value && typeof value === "object" && typeof value.name === "string" && Array.isArray(value.tools);
|
|
399
|
+
return !!value && typeof value === "object" && typeof value.name === "string" && Array.isArray(value.tools);
|
|
421
400
|
}
|
|
422
401
|
function extractSkills(moduleExports) {
|
|
423
402
|
const candidates = [
|
|
@@ -432,20 +411,17 @@ function extractSkills(moduleExports) {
|
|
|
432
411
|
return [];
|
|
433
412
|
}
|
|
434
413
|
async function resolveSkillsEntry(pluginPath) {
|
|
435
|
-
const tsPath = path$
|
|
414
|
+
const tsPath = path$3.join(pluginPath, "skills.ts");
|
|
436
415
|
if (await pathExists(tsPath)) return tsPath;
|
|
437
|
-
const jsPath = path$
|
|
416
|
+
const jsPath = path$3.join(pluginPath, "skills.js");
|
|
438
417
|
if (await pathExists(jsPath)) return jsPath;
|
|
439
418
|
return null;
|
|
440
419
|
}
|
|
441
|
-
/**
|
|
442
|
-
* Auto-register plugin help manifests and AI skills
|
|
443
|
-
*/
|
|
444
420
|
async function registerPluginArtifacts(ctx) {
|
|
445
|
-
const enabledPlugins = new Set(
|
|
421
|
+
const enabledPlugins = new Set(botConfig.plugins ?? []);
|
|
446
422
|
const pluginMetadata = plugin_manager_default.getAllMetadata().filter((metadata) => enabledPlugins.size > 0 ? enabledPlugins.has(metadata.name) : true);
|
|
447
|
-
const helpService = ctx.services
|
|
448
|
-
const aiService = ctx.services
|
|
423
|
+
const helpService = ctx.services.help;
|
|
424
|
+
const aiService = ctx.services.ai;
|
|
449
425
|
if (helpService) {
|
|
450
426
|
let helpCount = 0;
|
|
451
427
|
for (const metadata of pluginMetadata) {
|
|
@@ -464,7 +440,7 @@ async function registerPluginArtifacts(ctx) {
|
|
|
464
440
|
const moduleExports = await import(toImportPath(skillsEntry));
|
|
465
441
|
const skills = extractSkills(moduleExports);
|
|
466
442
|
if (skills.length === 0) {
|
|
467
|
-
logger.warn(`[plugin-artifacts] Plugin ${metadata.name} has ${path$
|
|
443
|
+
logger.warn(`[plugin-artifacts] Plugin ${metadata.name} has ${path$3.basename(skillsEntry)} but exported no valid skill`);
|
|
468
444
|
continue;
|
|
469
445
|
}
|
|
470
446
|
for (const skill of skills) {
|
|
@@ -472,7 +448,7 @@ async function registerPluginArtifacts(ctx) {
|
|
|
472
448
|
skillCount += 1;
|
|
473
449
|
}
|
|
474
450
|
} catch (error) {
|
|
475
|
-
logger.error(`[plugin-artifacts] Failed to load skills for plugin ${metadata.name}: ${error
|
|
451
|
+
logger.error(`[plugin-artifacts] Failed to load skills for plugin ${metadata.name}: ${error}`);
|
|
476
452
|
}
|
|
477
453
|
}
|
|
478
454
|
logger.info(`[plugin-artifacts] Registered ${skillCount} skill(s)`);
|
|
@@ -482,136 +458,97 @@ async function registerPluginArtifacts(ctx) {
|
|
|
482
458
|
//#region src/core/service-config.ts
|
|
483
459
|
const SERVICE_CONFIG_ROOT = "service";
|
|
484
460
|
function resolveConfigDir(serviceName) {
|
|
485
|
-
return path$
|
|
461
|
+
return path$2.join(process.cwd(), "config", SERVICE_CONFIG_ROOT, serviceName);
|
|
486
462
|
}
|
|
487
463
|
function resolveConfigPath(serviceName, configName) {
|
|
488
|
-
return path$
|
|
464
|
+
return path$2.join(resolveConfigDir(serviceName), `${configName}.json`);
|
|
489
465
|
}
|
|
490
466
|
function ensureDir(serviceName) {
|
|
491
467
|
const dir = resolveConfigDir(serviceName);
|
|
492
|
-
if (!
|
|
468
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
493
469
|
}
|
|
494
|
-
function registerServiceConfig(serviceName, configName, defaults) {
|
|
470
|
+
async function registerServiceConfig(serviceName, configName, defaults) {
|
|
495
471
|
ensureDir(serviceName);
|
|
496
472
|
const configPath = resolveConfigPath(serviceName, configName);
|
|
497
|
-
if (!
|
|
473
|
+
if (!existsSync(configPath)) await fs$1.writeFile(configPath, JSON.stringify(defaults, null, 2), "utf-8");
|
|
498
474
|
}
|
|
499
|
-
function getServiceConfig(serviceName, configName) {
|
|
475
|
+
async function getServiceConfig(serviceName, configName) {
|
|
500
476
|
const configPath = resolveConfigPath(serviceName, configName);
|
|
501
477
|
try {
|
|
502
|
-
|
|
503
|
-
} catch {
|
|
504
|
-
|
|
478
|
+
return JSON.parse(await fs$1.readFile(configPath, "utf-8"));
|
|
479
|
+
} catch (error) {
|
|
480
|
+
if (!existsSync(configPath)) return {};
|
|
481
|
+
logger.warn(`[service-config] 读取 ${serviceName}/${configName} 失败: ${error}`);
|
|
482
|
+
return {};
|
|
483
|
+
}
|
|
505
484
|
}
|
|
506
|
-
function updateServiceConfig(serviceName, configName, value) {
|
|
485
|
+
async function updateServiceConfig(serviceName, configName, value) {
|
|
507
486
|
ensureDir(serviceName);
|
|
508
|
-
fs$
|
|
487
|
+
await fs$1.writeFile(resolveConfigPath(serviceName, configName), JSON.stringify(value, null, 2), "utf-8");
|
|
509
488
|
}
|
|
510
|
-
function getServiceConfigs(serviceName) {
|
|
489
|
+
async function getServiceConfigs(serviceName) {
|
|
511
490
|
const dir = resolveConfigDir(serviceName);
|
|
512
|
-
if (!
|
|
491
|
+
if (!existsSync(dir)) return {};
|
|
513
492
|
const result = {};
|
|
514
|
-
const files = fs$
|
|
515
|
-
for (const file of files) {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
} catch {}
|
|
493
|
+
const files = (await fs$1.readdir(dir)).filter((name) => name.endsWith(".json"));
|
|
494
|
+
for (const file of files) try {
|
|
495
|
+
result[path$2.basename(file, ".json")] = JSON.parse(await fs$1.readFile(path$2.join(dir, file), "utf-8"));
|
|
496
|
+
} catch (error) {
|
|
497
|
+
logger.warn(`[service-config] 读取 ${serviceName}/${file} 失败: ${error}`);
|
|
520
498
|
}
|
|
521
499
|
return result;
|
|
522
500
|
}
|
|
523
|
-
function deleteServiceConfig(serviceName, configName) {
|
|
501
|
+
async function deleteServiceConfig(serviceName, configName) {
|
|
524
502
|
const configPath = resolveConfigPath(serviceName, configName);
|
|
525
|
-
if (!
|
|
526
|
-
fs$
|
|
503
|
+
if (!existsSync(configPath)) return false;
|
|
504
|
+
await fs$1.unlink(configPath);
|
|
527
505
|
return true;
|
|
528
506
|
}
|
|
529
507
|
|
|
530
508
|
//#endregion
|
|
531
|
-
//#region src/
|
|
509
|
+
//#region src/types.ts
|
|
532
510
|
const TOOL_RESULT_FOLLOWUP_KEY = "__miokuFollowup";
|
|
533
511
|
|
|
534
512
|
//#endregion
|
|
535
513
|
//#region src/core/data-paths.ts
|
|
536
|
-
/**
|
|
537
|
-
* Get the data directory for a specific plugin
|
|
538
|
-
* Returns: {cwd}/data/{pluginName}
|
|
539
|
-
*/
|
|
540
514
|
function getPluginDataDir(pluginName) {
|
|
541
|
-
|
|
542
|
-
return dataDir;
|
|
515
|
+
return path$1.join(process.cwd(), "data", pluginName);
|
|
543
516
|
}
|
|
544
|
-
/**
|
|
545
|
-
* Get the data directory for a service
|
|
546
|
-
* Returns: {cwd}/data/{serviceName}
|
|
547
|
-
*/
|
|
548
517
|
function getServiceDataDir(serviceName) {
|
|
549
|
-
|
|
550
|
-
return dataDir;
|
|
518
|
+
return path$1.join(process.cwd(), "data", serviceName);
|
|
551
519
|
}
|
|
552
|
-
/**
|
|
553
|
-
* Get the main data directory
|
|
554
|
-
* Returns: {cwd}/data
|
|
555
|
-
*/
|
|
556
520
|
function getDataDir() {
|
|
557
|
-
return path$
|
|
521
|
+
return path$1.join(process.cwd(), "data");
|
|
558
522
|
}
|
|
559
|
-
/**
|
|
560
|
-
* Get the config directory for a plugin
|
|
561
|
-
* Returns: {cwd}/config/{pluginName}
|
|
562
|
-
*/
|
|
563
523
|
function getPluginConfigDir(pluginName) {
|
|
564
|
-
|
|
565
|
-
return configDir;
|
|
524
|
+
return path$1.join(process.cwd(), "config", pluginName);
|
|
566
525
|
}
|
|
567
|
-
/**
|
|
568
|
-
* Get the config directory for a service
|
|
569
|
-
* Returns: {cwd}/config/service/{serviceName}
|
|
570
|
-
*/
|
|
571
526
|
function getServiceConfigDir(serviceName) {
|
|
572
|
-
|
|
573
|
-
return configDir;
|
|
527
|
+
return path$1.join(process.cwd(), "config", "service", serviceName);
|
|
574
528
|
}
|
|
575
|
-
/**
|
|
576
|
-
* Get the main config directory
|
|
577
|
-
* Returns: {cwd}/config
|
|
578
|
-
*/
|
|
579
529
|
function getConfigDir() {
|
|
580
|
-
return path$
|
|
530
|
+
return path$1.join(process.cwd(), "config");
|
|
581
531
|
}
|
|
582
|
-
/**
|
|
583
|
-
* Ensure a directory exists, creating it if necessary
|
|
584
|
-
*/
|
|
585
532
|
function ensureDataDir(pluginName) {
|
|
586
533
|
const dir = getPluginDataDir(pluginName);
|
|
587
|
-
|
|
588
|
-
if (!existsSync$1(dir)) mkdirSync$1(dir, { recursive: true });
|
|
534
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
589
535
|
return dir;
|
|
590
536
|
}
|
|
591
537
|
|
|
592
538
|
//#endregion
|
|
593
539
|
//#region src/core/plugin-runtime-state.ts
|
|
594
|
-
const
|
|
595
|
-
/**
|
|
596
|
-
* Get the runtime state for a plugin
|
|
597
|
-
*/
|
|
540
|
+
const store = getOrCreate("plugin-runtime-state", () => ({}));
|
|
598
541
|
function getPluginRuntimeState(pluginName) {
|
|
599
|
-
if (!
|
|
600
|
-
return
|
|
542
|
+
if (!store[pluginName]) store[pluginName] = {};
|
|
543
|
+
return store[pluginName];
|
|
601
544
|
}
|
|
602
|
-
/**
|
|
603
|
-
* Set/update the runtime state for a plugin
|
|
604
|
-
*/
|
|
605
545
|
function setPluginRuntimeState(pluginName, state) {
|
|
606
|
-
if (!
|
|
607
|
-
Object.assign(
|
|
608
|
-
return
|
|
546
|
+
if (!store[pluginName]) store[pluginName] = {};
|
|
547
|
+
Object.assign(store[pluginName], state);
|
|
548
|
+
return store[pluginName];
|
|
609
549
|
}
|
|
610
|
-
/**
|
|
611
|
-
* Reset the runtime state for a plugin
|
|
612
|
-
*/
|
|
613
550
|
function resetPluginRuntimeState(pluginName) {
|
|
614
|
-
delete
|
|
551
|
+
delete store[pluginName];
|
|
615
552
|
}
|
|
616
553
|
|
|
617
554
|
//#endregion
|
|
@@ -619,48 +556,31 @@ function resetPluginRuntimeState(pluginName) {
|
|
|
619
556
|
function definePlugin(plugin) {
|
|
620
557
|
return plugin;
|
|
621
558
|
}
|
|
622
|
-
/**
|
|
623
|
-
* Start Mioku with plugin and service discovery
|
|
624
|
-
*/
|
|
625
559
|
async function start(options = {}) {
|
|
626
560
|
const { cwd = process.cwd() } = options;
|
|
627
561
|
if (cwd) process.chdir(cwd);
|
|
628
|
-
const { start: startMioki, logger: logger$1, botConfig } = await import("mioki");
|
|
562
|
+
const { start: startMioki, logger: logger$1, botConfig: botConfig$1 } = await import("mioki");
|
|
629
563
|
setMiokuLogger(logger$1);
|
|
630
|
-
const packageJsonPath = path$1.join(process.cwd(), "package.json");
|
|
631
|
-
let miokuConfig = {};
|
|
632
|
-
if (fs$1.existsSync(packageJsonPath)) {
|
|
633
|
-
const pkg = JSON.parse(fs$1.readFileSync(packageJsonPath, "utf-8"));
|
|
634
|
-
miokuConfig = pkg.mioki || {};
|
|
635
|
-
}
|
|
636
564
|
logger$1.info("こんにちは..");
|
|
637
565
|
logger$1.info("---------------------------------------");
|
|
638
566
|
logger$1.info("---------- Mioku 正在启动 ------------");
|
|
639
567
|
logger$1.info("---------------------------------------");
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
await service_manager_default.discoverServices(miokuConfig);
|
|
654
|
-
const requiredServices = plugin_manager_default.collectRequiredServices();
|
|
655
|
-
const missingServices = await service_manager_default.checkMissingServices(requiredServices);
|
|
656
|
-
if (missingServices.length > 0) logger$1.warn(`发现缺失服务: ${missingServices.join(", ")}`);
|
|
657
|
-
const userSpecifiedPlugins = miokuConfig.plugins !== void 0;
|
|
658
|
-
if (!userSpecifiedPlugins) {
|
|
659
|
-
for (const name of linkedPluginNames) if (!botConfig.plugins.includes(name)) botConfig.plugins.push(name);
|
|
568
|
+
await bootstrapMioku({
|
|
569
|
+
cwd,
|
|
570
|
+
botConfig: botConfig$1,
|
|
571
|
+
startMioki
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
function readVersion() {
|
|
575
|
+
try {
|
|
576
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
577
|
+
const pkgPath = path.join(here, "..", "package.json");
|
|
578
|
+
return JSON.parse(fs.readFileSync(pkgPath, "utf-8")).version ?? "0.0.0";
|
|
579
|
+
} catch {
|
|
580
|
+
return "0.0.0";
|
|
660
581
|
}
|
|
661
|
-
await startMioki({ cwd });
|
|
662
582
|
}
|
|
663
|
-
const version =
|
|
583
|
+
const version = readVersion();
|
|
664
584
|
|
|
665
585
|
//#endregion
|
|
666
586
|
export { TOOL_RESULT_FOLLOWUP_KEY, definePlugin, deleteServiceConfig, ensureDataDir, getConfigDir, getDataDir, getPluginConfigDir, getPluginDataDir, getPluginRuntimeState, getServiceConfig, getServiceConfigDir, getServiceConfigs, getServiceDataDir, plugin_manager_default as pluginManager, registerPluginArtifacts, registerServiceConfig, resetPluginRuntimeState, service_manager_default as serviceManager, setPluginRuntimeState, start, updateServiceConfig, version };
|