@cuylabs/agent-core 0.7.0 → 0.9.0
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/{builder-BRvqCcIk.d.ts → builder-BgZ_j4Vs.d.ts} +3 -2
- package/dist/chunk-4QFNWPIF.js +202 -0
- package/dist/chunk-5ARZJWD2.js +259 -0
- package/dist/chunk-DXFBQMXP.js +53 -0
- package/dist/chunk-EKR6PKXU.js +180 -0
- package/dist/{chunk-IVUJDISU.js → chunk-GFTW23FV.js} +5 -14
- package/dist/{chunk-IEFIQENH.js → chunk-H3FUYU52.js} +15 -7
- package/dist/chunk-I6PKJ7XQ.js +292 -0
- package/dist/chunk-IYWQOJMQ.js +102 -0
- package/dist/{chunk-3HNO5SVI.js → chunk-J4QDGZIA.js} +20 -4
- package/dist/{chunk-7MUFEN4K.js → chunk-JLXG2SH7.js} +349 -3
- package/dist/{chunk-CDTV2UYU.js → chunk-MAZ5DY5B.js} +64 -276
- package/dist/{chunk-P6YF7USR.js → chunk-MHKK374K.js} +12 -11
- package/dist/{chunk-VBWWUHWI.js → chunk-OFDKHNCX.js} +4 -1
- package/dist/{chunk-YUUJK53A.js → chunk-RKEW5WXI.js} +1 -1
- package/dist/{chunk-LRHOS4ZN.js → chunk-SPILYYDF.js} +3 -2
- package/dist/{chunk-QGOGIP7T.js → chunk-UDCZ673N.js} +385 -233
- package/dist/{chunk-BDBZ3SLK.js → chunk-UHCJEM2E.js} +39 -2
- package/dist/chunk-WGZAPU6N.js +929 -0
- package/dist/{chunk-5K7AQVOU.js → chunk-WKHDSSXG.js} +130 -209
- package/dist/{chunk-BNSHUWCV.js → chunk-WWYYNWEW.js} +1 -1
- package/dist/context/index.js +1 -1
- package/dist/events-CE72w8W4.d.ts +149 -0
- package/dist/index-BCqEGzBj.d.ts +251 -0
- package/dist/{index-C33hlD6H.d.ts → index-DQuTZ8xL.d.ts} +319 -56
- package/dist/index.d.ts +42 -121
- package/dist/index.js +951 -848
- package/dist/inference/errors/index.d.ts +11 -0
- package/dist/inference/errors/index.js +16 -0
- package/dist/inference/index.d.ts +12 -8
- package/dist/inference/index.js +35 -7
- package/dist/llm-error-D93FNNLY.d.ts +32 -0
- package/dist/middleware/index.d.ts +246 -7
- package/dist/middleware/index.js +3 -1
- package/dist/models/index.d.ts +132 -9
- package/dist/models/index.js +48 -8
- package/dist/models/reasoning/index.d.ts +4 -0
- package/dist/{reasoning → models/reasoning}/index.js +2 -7
- package/dist/plugin/index.d.ts +414 -0
- package/dist/plugin/index.js +32 -0
- package/dist/presets/index.d.ts +53 -0
- package/dist/presets/index.js +30 -0
- package/dist/prompt/index.d.ts +11 -8
- package/dist/prompt/index.js +3 -2
- package/dist/{registry-BDLIHOQB.d.ts → registry-DwYqsQkX.d.ts} +1 -1
- package/dist/runner-CI-XeR16.d.ts +91 -0
- package/dist/runtime/index.d.ts +12 -8
- package/dist/runtime/index.js +8 -7
- package/dist/safety/index.d.ts +38 -0
- package/dist/safety/index.js +12 -0
- package/dist/scope/index.d.ts +2 -2
- package/dist/{session-manager-B_CWGTsl.d.ts → session-manager-KbYt2WUh.d.ts} +8 -0
- package/dist/signal/index.d.ts +28 -0
- package/dist/signal/index.js +6 -0
- package/dist/skill/index.d.ts +7 -6
- package/dist/skill/index.js +3 -3
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +1 -1
- package/dist/sub-agent/index.d.ts +16 -10
- package/dist/sub-agent/index.js +21 -4
- package/dist/tool/index.d.ts +22 -6
- package/dist/tool/index.js +3 -3
- package/dist/tool-CZWN3KbO.d.ts +141 -0
- package/dist/{tool-HUtkiVBx.d.ts → tool-DkhSCV2Y.d.ts} +2 -2
- package/dist/tracking/index.d.ts +2 -2
- package/dist/tracking/index.js +1 -1
- package/dist/{tool-Db1Ue-1U.d.ts → types-BfNpU8NS.d.ts} +1 -150
- package/dist/{types-FRpzzg_9.d.ts → types-BlOKk-Bb.d.ts} +10 -35
- package/dist/types-BlZwmnuW.d.ts +50 -0
- package/dist/{types-9jGQUjqW.d.ts → types-CQL-SvTn.d.ts} +1 -1
- package/dist/types-CWm-7rvB.d.ts +55 -0
- package/dist/{runner-DSKaEz3z.d.ts → types-DTSkxakL.d.ts} +7 -235
- package/dist/{types-CqDZTh4d.d.ts → types-DmDwi2zI.d.ts} +8 -4
- package/dist/types-YuWV4ag7.d.ts +72 -0
- package/package.json +67 -6
- package/dist/capability-resolver-CgRGsWVX.d.ts +0 -254
- package/dist/chunk-ZPMACVZK.js +0 -305
- package/dist/index-CfBGYrpd.d.ts +0 -317
- package/dist/reasoning/index.d.ts +0 -117
|
@@ -0,0 +1,929 @@
|
|
|
1
|
+
// src/plugin/event-bus.ts
|
|
2
|
+
var PluginEventBus = class {
|
|
3
|
+
channels = /* @__PURE__ */ new Map();
|
|
4
|
+
emit(channel, data) {
|
|
5
|
+
const handlers = this.channels.get(channel);
|
|
6
|
+
if (!handlers) return;
|
|
7
|
+
for (const fn of handlers) {
|
|
8
|
+
try {
|
|
9
|
+
fn(data);
|
|
10
|
+
} catch {
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
on(channel, handler) {
|
|
15
|
+
let set = this.channels.get(channel);
|
|
16
|
+
if (!set) {
|
|
17
|
+
set = /* @__PURE__ */ new Set();
|
|
18
|
+
this.channels.set(channel, set);
|
|
19
|
+
}
|
|
20
|
+
set.add(handler);
|
|
21
|
+
return () => {
|
|
22
|
+
set.delete(handler);
|
|
23
|
+
if (set.size === 0) this.channels.delete(channel);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** Number of active channels. */
|
|
27
|
+
get size() {
|
|
28
|
+
return this.channels.size;
|
|
29
|
+
}
|
|
30
|
+
/** Remove all listeners. */
|
|
31
|
+
clear() {
|
|
32
|
+
this.channels.clear();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// src/plugin/settings.ts
|
|
37
|
+
function isPlainObject(value) {
|
|
38
|
+
return typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype;
|
|
39
|
+
}
|
|
40
|
+
function cloneSettingsValue(value) {
|
|
41
|
+
if (Array.isArray(value)) {
|
|
42
|
+
return value.map((item) => cloneSettingsValue(item));
|
|
43
|
+
}
|
|
44
|
+
if (isPlainObject(value)) {
|
|
45
|
+
return Object.fromEntries(
|
|
46
|
+
Object.entries(value).map(([key, item]) => [
|
|
47
|
+
key,
|
|
48
|
+
cloneSettingsValue(item)
|
|
49
|
+
])
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
function mergeSettingsValue(base, override) {
|
|
55
|
+
if (isPlainObject(base) && isPlainObject(override)) {
|
|
56
|
+
const merged = { ...cloneSettingsValue(base) };
|
|
57
|
+
for (const [key, value] of Object.entries(override)) {
|
|
58
|
+
merged[key] = key in merged ? mergeSettingsValue(merged[key], value) : cloneSettingsValue(value);
|
|
59
|
+
}
|
|
60
|
+
return merged;
|
|
61
|
+
}
|
|
62
|
+
return cloneSettingsValue(override);
|
|
63
|
+
}
|
|
64
|
+
function parseSettingsValue(namespace, value, schema) {
|
|
65
|
+
const parsed = schema.safeParse(value);
|
|
66
|
+
if (parsed.success) {
|
|
67
|
+
return parsed.data;
|
|
68
|
+
}
|
|
69
|
+
throw new Error(
|
|
70
|
+
`Invalid settings for "${namespace}": ${parsed.error.issues.map((issue) => issue.message).join(", ")}`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
var NullSettings = class {
|
|
74
|
+
get(_namespace) {
|
|
75
|
+
return void 0;
|
|
76
|
+
}
|
|
77
|
+
parse(_namespace, _schema) {
|
|
78
|
+
return void 0;
|
|
79
|
+
}
|
|
80
|
+
require(namespace, _schema) {
|
|
81
|
+
throw new Error(`Missing required settings for "${namespace}"`);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var StaticSettings = class {
|
|
85
|
+
constructor(data) {
|
|
86
|
+
this.data = data;
|
|
87
|
+
}
|
|
88
|
+
get(namespace) {
|
|
89
|
+
const value = this.data[namespace];
|
|
90
|
+
return value === void 0 ? void 0 : value;
|
|
91
|
+
}
|
|
92
|
+
parse(namespace, schema) {
|
|
93
|
+
const value = this.get(namespace);
|
|
94
|
+
return value === void 0 ? void 0 : parseSettingsValue(namespace, value, schema);
|
|
95
|
+
}
|
|
96
|
+
require(namespace, schema) {
|
|
97
|
+
const value = this.get(namespace);
|
|
98
|
+
if (value === void 0) {
|
|
99
|
+
throw new Error(`Missing required settings for "${namespace}"`);
|
|
100
|
+
}
|
|
101
|
+
return parseSettingsValue(namespace, value, schema);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
var LayeredSettings = class {
|
|
105
|
+
constructor(layers) {
|
|
106
|
+
this.layers = layers;
|
|
107
|
+
}
|
|
108
|
+
get(namespace) {
|
|
109
|
+
let resolved;
|
|
110
|
+
let hasValue = false;
|
|
111
|
+
for (const layer of this.layers) {
|
|
112
|
+
const value = layer.get(namespace);
|
|
113
|
+
if (value !== void 0) {
|
|
114
|
+
resolved = hasValue ? mergeSettingsValue(resolved, value) : cloneSettingsValue(value);
|
|
115
|
+
hasValue = true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return hasValue ? resolved : void 0;
|
|
119
|
+
}
|
|
120
|
+
parse(namespace, schema) {
|
|
121
|
+
const value = this.get(namespace);
|
|
122
|
+
return value === void 0 ? void 0 : parseSettingsValue(namespace, value, schema);
|
|
123
|
+
}
|
|
124
|
+
require(namespace, schema) {
|
|
125
|
+
const value = this.get(namespace);
|
|
126
|
+
if (value === void 0) {
|
|
127
|
+
throw new Error(`Missing required settings for "${namespace}"`);
|
|
128
|
+
}
|
|
129
|
+
return parseSettingsValue(namespace, value, schema);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
var ValidatedSettings = class {
|
|
133
|
+
constructor(base, overrides) {
|
|
134
|
+
this.base = base;
|
|
135
|
+
this.overrides = overrides;
|
|
136
|
+
}
|
|
137
|
+
get(namespace) {
|
|
138
|
+
if (namespace in this.overrides) {
|
|
139
|
+
return this.overrides[namespace];
|
|
140
|
+
}
|
|
141
|
+
return this.base.get(namespace);
|
|
142
|
+
}
|
|
143
|
+
parse(namespace, schema) {
|
|
144
|
+
if (namespace in this.overrides) {
|
|
145
|
+
return parseSettingsValue(namespace, this.overrides[namespace], schema);
|
|
146
|
+
}
|
|
147
|
+
return this.base.parse(namespace, schema);
|
|
148
|
+
}
|
|
149
|
+
require(namespace, schema) {
|
|
150
|
+
if (namespace in this.overrides) {
|
|
151
|
+
return parseSettingsValue(namespace, this.overrides[namespace], schema);
|
|
152
|
+
}
|
|
153
|
+
return this.base.require(namespace, schema);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// src/plugin/loader.ts
|
|
158
|
+
import { existsSync } from "fs";
|
|
159
|
+
import fs from "fs/promises";
|
|
160
|
+
import path from "path";
|
|
161
|
+
import { fileURLToPath } from "url";
|
|
162
|
+
import { createJiti } from "jiti";
|
|
163
|
+
var DEFAULT_PLUGIN_DIR = ".cuylabs/plugins";
|
|
164
|
+
var LOADABLE_EXTS = /\.(ts|js|mjs|mts)$/;
|
|
165
|
+
var FRAMEWORK_PACKAGES = [
|
|
166
|
+
"@cuylabs/agent-core",
|
|
167
|
+
"@cuylabs/agent-code",
|
|
168
|
+
"@cuylabs/agent-runtime",
|
|
169
|
+
"@cuylabs/agent-http",
|
|
170
|
+
"@cuylabs/agent-runtime-dapr"
|
|
171
|
+
];
|
|
172
|
+
var _frameworkAliases;
|
|
173
|
+
function resolveFrameworkAliases() {
|
|
174
|
+
if (_frameworkAliases) return _frameworkAliases;
|
|
175
|
+
const aliases = {};
|
|
176
|
+
for (const specifier of FRAMEWORK_PACKAGES) {
|
|
177
|
+
const resolved = resolvePackagePath(specifier);
|
|
178
|
+
if (resolved) {
|
|
179
|
+
aliases[specifier] = resolved;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
_frameworkAliases = aliases;
|
|
183
|
+
return aliases;
|
|
184
|
+
}
|
|
185
|
+
function resetFrameworkAliases() {
|
|
186
|
+
_frameworkAliases = void 0;
|
|
187
|
+
}
|
|
188
|
+
function resolvePackagePath(specifier) {
|
|
189
|
+
try {
|
|
190
|
+
const resolved = import.meta.resolve(specifier);
|
|
191
|
+
if (resolved) {
|
|
192
|
+
return resolved.startsWith("file://") ? fileURLToPath(resolved) : resolved;
|
|
193
|
+
}
|
|
194
|
+
} catch {
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
const thisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
198
|
+
const packagesRoot = path.resolve(thisDir, "../../../..");
|
|
199
|
+
const shortName = specifier.replace("@cuylabs/", "");
|
|
200
|
+
const candidate = path.join(packagesRoot, shortName, "dist", "index.js");
|
|
201
|
+
if (existsSync(candidate)) {
|
|
202
|
+
return candidate;
|
|
203
|
+
}
|
|
204
|
+
} catch {
|
|
205
|
+
}
|
|
206
|
+
return void 0;
|
|
207
|
+
}
|
|
208
|
+
var _jiti = /* @__PURE__ */ new Map();
|
|
209
|
+
function getPluginLoader(options = {}) {
|
|
210
|
+
const key = getPluginLoaderKey(options);
|
|
211
|
+
const existing = _jiti.get(key);
|
|
212
|
+
if (existing) {
|
|
213
|
+
return existing;
|
|
214
|
+
}
|
|
215
|
+
const autoAliases = options.autoAlias ?? true ? resolveFrameworkAliases() : {};
|
|
216
|
+
const mergedAlias = { ...autoAliases, ...options.alias };
|
|
217
|
+
const loader = createJiti(import.meta.url, {
|
|
218
|
+
fsCache: true,
|
|
219
|
+
moduleCache: true,
|
|
220
|
+
sourceMaps: options.sourceMaps ?? true,
|
|
221
|
+
interopDefault: true,
|
|
222
|
+
tryNative: false,
|
|
223
|
+
debug: options.debug ?? false,
|
|
224
|
+
alias: mergedAlias,
|
|
225
|
+
nativeModules: options.nativeModules
|
|
226
|
+
});
|
|
227
|
+
_jiti.set(key, loader);
|
|
228
|
+
return loader;
|
|
229
|
+
}
|
|
230
|
+
function resetPluginLoader() {
|
|
231
|
+
_jiti.clear();
|
|
232
|
+
}
|
|
233
|
+
async function discoverPlugins(cwd, extraPaths = []) {
|
|
234
|
+
const results = [];
|
|
235
|
+
const seen = /* @__PURE__ */ new Set();
|
|
236
|
+
const pluginDir = path.resolve(cwd, DEFAULT_PLUGIN_DIR);
|
|
237
|
+
if (existsSync(pluginDir)) {
|
|
238
|
+
const entries = await fs.readdir(pluginDir, { withFileTypes: true });
|
|
239
|
+
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
240
|
+
for (const entry of entries) {
|
|
241
|
+
if (entry.name.startsWith("_")) continue;
|
|
242
|
+
if (entry.isFile() && isLoadable(entry.name)) {
|
|
243
|
+
const absPath = path.join(pluginDir, entry.name);
|
|
244
|
+
if (!seen.has(absPath)) {
|
|
245
|
+
seen.add(absPath);
|
|
246
|
+
results.push({
|
|
247
|
+
entryPath: absPath,
|
|
248
|
+
manifest: manifestFromFilename(entry.name)
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
} else if (entry.isDirectory()) {
|
|
252
|
+
const subdir = path.join(pluginDir, entry.name);
|
|
253
|
+
const nested = await discoverPluginDirectory(subdir, entry.name);
|
|
254
|
+
for (const plugin of nested) {
|
|
255
|
+
if (seen.has(plugin.entryPath)) continue;
|
|
256
|
+
seen.add(plugin.entryPath);
|
|
257
|
+
results.push(plugin);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
for (const p of extraPaths) {
|
|
263
|
+
const resolved = path.isAbsolute(p) ? p : path.resolve(cwd, p);
|
|
264
|
+
if (!existsSync(resolved)) {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
const stat = await fs.stat(resolved);
|
|
268
|
+
if (stat.isDirectory()) {
|
|
269
|
+
const nested = await discoverPluginDirectory(
|
|
270
|
+
resolved,
|
|
271
|
+
path.basename(resolved)
|
|
272
|
+
);
|
|
273
|
+
for (const plugin of nested) {
|
|
274
|
+
if (seen.has(plugin.entryPath)) continue;
|
|
275
|
+
seen.add(plugin.entryPath);
|
|
276
|
+
results.push(plugin);
|
|
277
|
+
}
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (!seen.has(resolved)) {
|
|
281
|
+
seen.add(resolved);
|
|
282
|
+
results.push({
|
|
283
|
+
entryPath: resolved,
|
|
284
|
+
manifest: manifestFromFilename(path.basename(resolved))
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return results;
|
|
289
|
+
}
|
|
290
|
+
async function loadPluginModule(entryPath, options) {
|
|
291
|
+
const jiti = getPluginLoader(options);
|
|
292
|
+
const mod = await jiti.import(entryPath, { default: true });
|
|
293
|
+
const init = typeof mod === "function" ? mod : mod.default ?? mod;
|
|
294
|
+
if (typeof init !== "function") {
|
|
295
|
+
throw new Error(
|
|
296
|
+
`Plugin at ${entryPath} must default-export a function, got ${typeof init}`
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
return init;
|
|
300
|
+
}
|
|
301
|
+
function isLoadable(filename) {
|
|
302
|
+
return LOADABLE_EXTS.test(filename) && !filename.startsWith("_");
|
|
303
|
+
}
|
|
304
|
+
function getPluginLoaderKey(options) {
|
|
305
|
+
const alias = options.alias ? Object.fromEntries(
|
|
306
|
+
Object.entries(options.alias).sort(
|
|
307
|
+
([left], [right]) => left.localeCompare(right)
|
|
308
|
+
)
|
|
309
|
+
) : void 0;
|
|
310
|
+
const nativeModules = options.nativeModules ? [...options.nativeModules].sort() : void 0;
|
|
311
|
+
return JSON.stringify({
|
|
312
|
+
alias,
|
|
313
|
+
nativeModules,
|
|
314
|
+
sourceMaps: options.sourceMaps ?? true,
|
|
315
|
+
debug: options.debug ?? false,
|
|
316
|
+
autoAlias: options.autoAlias ?? true
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
async function discoverPluginDirectory(dir, dirName) {
|
|
320
|
+
const { manifest, pluginEntries } = await readManifestFromDir(dir, dirName);
|
|
321
|
+
if (pluginEntries && pluginEntries.length > 0) {
|
|
322
|
+
return pluginEntries.map((entry, _index, entries) => ({
|
|
323
|
+
entryPath: path.resolve(dir, entry),
|
|
324
|
+
manifest: manifestForEntry(manifest, entry, entries.length)
|
|
325
|
+
}));
|
|
326
|
+
}
|
|
327
|
+
const indexPath = await findIndexFile(dir);
|
|
328
|
+
if (!indexPath) {
|
|
329
|
+
return [];
|
|
330
|
+
}
|
|
331
|
+
return [{ entryPath: indexPath, manifest }];
|
|
332
|
+
}
|
|
333
|
+
async function findIndexFile(dir) {
|
|
334
|
+
for (const name of ["index.ts", "index.mts", "index.js", "index.mjs"]) {
|
|
335
|
+
const candidate = path.join(dir, name);
|
|
336
|
+
if (existsSync(candidate)) return candidate;
|
|
337
|
+
}
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
function manifestFromFilename(filename) {
|
|
341
|
+
const stem = filename.replace(/\.[^.]+$/, "");
|
|
342
|
+
return { id: stem };
|
|
343
|
+
}
|
|
344
|
+
async function readManifestFromDir(dir, dirName) {
|
|
345
|
+
const pkgPath = path.join(dir, "package.json");
|
|
346
|
+
if (!existsSync(pkgPath)) {
|
|
347
|
+
return { manifest: { id: dirName } };
|
|
348
|
+
}
|
|
349
|
+
try {
|
|
350
|
+
const raw = await fs.readFile(pkgPath, "utf-8");
|
|
351
|
+
const pkg = JSON.parse(raw);
|
|
352
|
+
const pluginEntries = readPluginEntries(pkg);
|
|
353
|
+
return {
|
|
354
|
+
manifest: {
|
|
355
|
+
id: typeof pkg.name === "string" ? pkg.name : dirName,
|
|
356
|
+
name: typeof pkg.name === "string" ? pkg.name : void 0,
|
|
357
|
+
description: typeof pkg.description === "string" ? pkg.description : void 0,
|
|
358
|
+
version: typeof pkg.version === "string" ? pkg.version : void 0,
|
|
359
|
+
compatibility: readPluginCompatibility(pkg)
|
|
360
|
+
},
|
|
361
|
+
...pluginEntries ? { pluginEntries } : {}
|
|
362
|
+
};
|
|
363
|
+
} catch {
|
|
364
|
+
return { manifest: { id: dirName } };
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
function readPluginEntries(pkg) {
|
|
368
|
+
const cuylabs = isRecord(pkg.cuylabs) ? pkg.cuylabs : void 0;
|
|
369
|
+
const entries = cuylabs?.plugins;
|
|
370
|
+
if (typeof entries === "string" && entries.length > 0) {
|
|
371
|
+
return [entries];
|
|
372
|
+
}
|
|
373
|
+
if (!Array.isArray(entries)) {
|
|
374
|
+
return void 0;
|
|
375
|
+
}
|
|
376
|
+
const normalized = entries.filter(
|
|
377
|
+
(entry) => typeof entry === "string" && entry.length > 0
|
|
378
|
+
);
|
|
379
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
380
|
+
}
|
|
381
|
+
function readPluginCompatibility(pkg) {
|
|
382
|
+
const cuylabs = isRecord(pkg.cuylabs) ? pkg.cuylabs : void 0;
|
|
383
|
+
const rawApiVersion = cuylabs?.apiVersion;
|
|
384
|
+
const rawEngines = isRecord(pkg.engines) ? pkg.engines : void 0;
|
|
385
|
+
const rawNode = rawEngines?.node;
|
|
386
|
+
const compatibility = {
|
|
387
|
+
...typeof rawApiVersion === "string" && rawApiVersion.length > 0 ? { apiVersion: rawApiVersion } : {},
|
|
388
|
+
...typeof rawNode === "string" && rawNode.length > 0 ? { node: rawNode } : {}
|
|
389
|
+
};
|
|
390
|
+
return Object.keys(compatibility).length > 0 ? compatibility : void 0;
|
|
391
|
+
}
|
|
392
|
+
function manifestForEntry(manifest, entry, entryCount) {
|
|
393
|
+
if (entryCount <= 1) {
|
|
394
|
+
return manifest;
|
|
395
|
+
}
|
|
396
|
+
const suffix = entry.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\.[^.]+$/, "").replace(/\//g, ":");
|
|
397
|
+
return {
|
|
398
|
+
...manifest,
|
|
399
|
+
id: `${manifest.id}:${suffix || "entry"}`
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
function isRecord(value) {
|
|
403
|
+
return typeof value === "object" && value !== null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// src/plugin/compatibility.ts
|
|
407
|
+
var COMPARATOR_RE = /^(<=|>=|<|>|=)?\s*(\d+(?:\.\d+){0,2})$/;
|
|
408
|
+
function parseVersion(version) {
|
|
409
|
+
const match = version.trim().match(/^(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
|
|
410
|
+
if (!match) {
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
return [
|
|
414
|
+
Number.parseInt(match[1] ?? "0", 10),
|
|
415
|
+
Number.parseInt(match[2] ?? "0", 10),
|
|
416
|
+
Number.parseInt(match[3] ?? "0", 10)
|
|
417
|
+
];
|
|
418
|
+
}
|
|
419
|
+
function compareVersions(left, right) {
|
|
420
|
+
const leftParts = parseVersion(left);
|
|
421
|
+
const rightParts = parseVersion(right);
|
|
422
|
+
if (!leftParts || !rightParts) {
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
for (let i = 0; i < 3; i++) {
|
|
426
|
+
const delta = leftParts[i] - rightParts[i];
|
|
427
|
+
if (delta !== 0) {
|
|
428
|
+
return delta > 0 ? 1 : -1;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return 0;
|
|
432
|
+
}
|
|
433
|
+
function matchesVersionRequirement(version, requirement) {
|
|
434
|
+
const clauses = requirement.split(/\s+/).map((part) => part.trim()).filter(Boolean);
|
|
435
|
+
if (clauses.length === 0) {
|
|
436
|
+
return true;
|
|
437
|
+
}
|
|
438
|
+
return clauses.every((clause) => {
|
|
439
|
+
const match = clause.match(COMPARATOR_RE);
|
|
440
|
+
if (!match) {
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
const [, operator = "=", expected] = match;
|
|
444
|
+
const comparison = compareVersions(version, expected);
|
|
445
|
+
if (comparison === null) {
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
switch (operator) {
|
|
449
|
+
case ">":
|
|
450
|
+
return comparison > 0;
|
|
451
|
+
case ">=":
|
|
452
|
+
return comparison >= 0;
|
|
453
|
+
case "<":
|
|
454
|
+
return comparison < 0;
|
|
455
|
+
case "<=":
|
|
456
|
+
return comparison <= 0;
|
|
457
|
+
case "=":
|
|
458
|
+
return comparison === 0;
|
|
459
|
+
default:
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
function validatePluginCompatibility(options) {
|
|
465
|
+
const { compatibility, context } = options;
|
|
466
|
+
if (!compatibility) {
|
|
467
|
+
return void 0;
|
|
468
|
+
}
|
|
469
|
+
if (compatibility.apiVersion !== void 0 && context.apiVersion !== void 0 && compatibility.apiVersion !== context.apiVersion) {
|
|
470
|
+
return `requires plugin API ${compatibility.apiVersion}, host provides ${context.apiVersion}`;
|
|
471
|
+
}
|
|
472
|
+
if (compatibility.node !== void 0 && context.nodeVersion !== void 0 && !matchesVersionRequirement(context.nodeVersion, compatibility.node)) {
|
|
473
|
+
return `requires Node ${compatibility.node}, current runtime is ${context.nodeVersion}`;
|
|
474
|
+
}
|
|
475
|
+
return void 0;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// src/plugin/define.ts
|
|
479
|
+
function definePlugin(def) {
|
|
480
|
+
const init = (ctx) => {
|
|
481
|
+
if (def.tools) {
|
|
482
|
+
for (const tool of def.tools) ctx.addTool(tool);
|
|
483
|
+
}
|
|
484
|
+
if (def.middleware) {
|
|
485
|
+
for (const mw of def.middleware) ctx.addMiddleware(mw);
|
|
486
|
+
}
|
|
487
|
+
if (def.commands) {
|
|
488
|
+
for (const cmd of def.commands) ctx.addCommand(cmd);
|
|
489
|
+
}
|
|
490
|
+
if (def.promptSections) {
|
|
491
|
+
for (const section of def.promptSections) ctx.addPromptSection(section);
|
|
492
|
+
}
|
|
493
|
+
if (def.activate) {
|
|
494
|
+
const activateFn = def.activate;
|
|
495
|
+
ctx.onActivate(
|
|
496
|
+
(sessionCtx) => activateFn({
|
|
497
|
+
...sessionCtx,
|
|
498
|
+
events: ctx.events,
|
|
499
|
+
settings: ctx.settings
|
|
500
|
+
})
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
if (def.deactivate) {
|
|
504
|
+
ctx.onDeactivate(def.deactivate);
|
|
505
|
+
}
|
|
506
|
+
if (def.setup) {
|
|
507
|
+
return def.setup(ctx);
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
init.__definition = def;
|
|
511
|
+
return init;
|
|
512
|
+
}
|
|
513
|
+
function isDefinedPlugin(init) {
|
|
514
|
+
return "__definition" in init;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// src/plugin/registry.ts
|
|
518
|
+
var DEFAULT_TIMEOUTS = {
|
|
519
|
+
load: 3e4,
|
|
520
|
+
activate: 15e3,
|
|
521
|
+
deactivate: 1e4
|
|
522
|
+
};
|
|
523
|
+
var PluginRegistry = class {
|
|
524
|
+
settings;
|
|
525
|
+
eventBus;
|
|
526
|
+
loaderOptions;
|
|
527
|
+
compatibilityContext;
|
|
528
|
+
timeouts;
|
|
529
|
+
plugins = [];
|
|
530
|
+
pluginIds = /* @__PURE__ */ new Set();
|
|
531
|
+
commandOwners = /* @__PURE__ */ new WeakMap();
|
|
532
|
+
commandTokens = /* @__PURE__ */ new Map();
|
|
533
|
+
_contributions = {
|
|
534
|
+
tools: [],
|
|
535
|
+
middleware: [],
|
|
536
|
+
commands: [],
|
|
537
|
+
promptSections: [],
|
|
538
|
+
errors: []
|
|
539
|
+
};
|
|
540
|
+
activated = false;
|
|
541
|
+
activeSessionContext;
|
|
542
|
+
constructor(options = {}) {
|
|
543
|
+
this.settings = options.settings ?? new NullSettings();
|
|
544
|
+
this.eventBus = options.events ?? new PluginEventBus();
|
|
545
|
+
this.loaderOptions = options.loader;
|
|
546
|
+
this.compatibilityContext = {
|
|
547
|
+
apiVersion: options.compatibility?.apiVersion ?? "1",
|
|
548
|
+
nodeVersion: sanitizeNodeVersion(
|
|
549
|
+
options.compatibility?.nodeVersion ?? process.versions.node
|
|
550
|
+
) ?? process.versions.node
|
|
551
|
+
};
|
|
552
|
+
this.timeouts = {
|
|
553
|
+
load: normalizeTimeout(options.timeouts?.load, DEFAULT_TIMEOUTS.load),
|
|
554
|
+
activate: normalizeTimeout(
|
|
555
|
+
options.timeouts?.activate,
|
|
556
|
+
DEFAULT_TIMEOUTS.activate
|
|
557
|
+
),
|
|
558
|
+
deactivate: normalizeTimeout(
|
|
559
|
+
options.timeouts?.deactivate,
|
|
560
|
+
DEFAULT_TIMEOUTS.deactivate
|
|
561
|
+
)
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
/** The shared event bus wired to all loaded plugins. */
|
|
565
|
+
get events() {
|
|
566
|
+
return this.eventBus;
|
|
567
|
+
}
|
|
568
|
+
/** Read-only view of everything plugins have contributed. */
|
|
569
|
+
get contributions() {
|
|
570
|
+
return this._contributions;
|
|
571
|
+
}
|
|
572
|
+
/** Number of successfully loaded plugins. */
|
|
573
|
+
get pluginCount() {
|
|
574
|
+
return this.plugins.length;
|
|
575
|
+
}
|
|
576
|
+
/** Get the static definition for a plugin (if it used `definePlugin()`). */
|
|
577
|
+
getDefinition(pluginId) {
|
|
578
|
+
return this.plugins.find((p) => p.manifest.id === pluginId)?.definition;
|
|
579
|
+
}
|
|
580
|
+
/** Get all static definitions (only for declarative plugins). */
|
|
581
|
+
get definitions() {
|
|
582
|
+
return this.plugins.filter((p) => p.definition !== void 0).map((p) => p.definition);
|
|
583
|
+
}
|
|
584
|
+
/** Get the plugin ID that contributed a command. */
|
|
585
|
+
getCommandOwner(command) {
|
|
586
|
+
return this.commandOwners.get(command);
|
|
587
|
+
}
|
|
588
|
+
/** Record a host-level plugin error without throwing. */
|
|
589
|
+
recordError(pluginId, error) {
|
|
590
|
+
this._contributions.errors.push({ pluginId, error });
|
|
591
|
+
}
|
|
592
|
+
/** Discover, load, and execute all plugins. */
|
|
593
|
+
async loadAll(cwd, extraPaths) {
|
|
594
|
+
const discovered = await discoverPlugins(cwd, extraPaths);
|
|
595
|
+
for (const entry of discovered) {
|
|
596
|
+
try {
|
|
597
|
+
const init = await loadPluginModule(
|
|
598
|
+
entry.entryPath,
|
|
599
|
+
this.loaderOptions
|
|
600
|
+
);
|
|
601
|
+
await this.loadOne(init, entry.manifest, cwd, entry.entryPath);
|
|
602
|
+
} catch (err) {
|
|
603
|
+
this.recordError(
|
|
604
|
+
entry.manifest.id,
|
|
605
|
+
err instanceof Error ? err.message : String(err)
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
/** Load a single plugin from its init function (programmatic / tests). */
|
|
611
|
+
loadOne(init, manifest, cwd, entryPath = "<inline>") {
|
|
612
|
+
return Promise.resolve(this.executePlugin(init, manifest, entryPath, cwd));
|
|
613
|
+
}
|
|
614
|
+
/** Fire `onActivate` hooks sequentially in load order. */
|
|
615
|
+
async activate(ctx) {
|
|
616
|
+
if (this.activated) return;
|
|
617
|
+
this.activated = true;
|
|
618
|
+
this.activeSessionContext = Object.freeze({ ...ctx });
|
|
619
|
+
for (const plugin of this.plugins) {
|
|
620
|
+
await this.runActivateHooks(plugin, this.activeSessionContext);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
/** Fire `onDeactivate` hooks in reverse load order. */
|
|
624
|
+
async deactivate() {
|
|
625
|
+
if (!this.activated) return;
|
|
626
|
+
this.activated = false;
|
|
627
|
+
this.activeSessionContext = void 0;
|
|
628
|
+
for (let i = this.plugins.length - 1; i >= 0; i--) {
|
|
629
|
+
await this.runDeactivateHooks(this.plugins[i]);
|
|
630
|
+
}
|
|
631
|
+
this.eventBus.clear();
|
|
632
|
+
}
|
|
633
|
+
executePlugin(init, manifest, entryPath, cwd) {
|
|
634
|
+
const definition = isDefinedPlugin(init) ? init.__definition : void 0;
|
|
635
|
+
const effectiveManifest = mergePluginManifest(manifest, definition);
|
|
636
|
+
if (this.pluginIds.has(effectiveManifest.id)) {
|
|
637
|
+
this.recordError(
|
|
638
|
+
effectiveManifest.id,
|
|
639
|
+
`duplicate plugin ID "${effectiveManifest.id}"`
|
|
640
|
+
);
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
const compatibilityError = validatePluginCompatibility({
|
|
644
|
+
compatibility: effectiveManifest.compatibility,
|
|
645
|
+
context: this.compatibilityContext
|
|
646
|
+
});
|
|
647
|
+
if (compatibilityError) {
|
|
648
|
+
this.recordError(
|
|
649
|
+
effectiveManifest.id,
|
|
650
|
+
`compatibility check failed: ${compatibilityError}`
|
|
651
|
+
);
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
const settings = this.resolvePluginSettings(effectiveManifest, definition);
|
|
655
|
+
if ("error" in settings) {
|
|
656
|
+
this.recordError(effectiveManifest.id, settings.error);
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
const lifecycle = {
|
|
660
|
+
activate: [],
|
|
661
|
+
deactivate: []
|
|
662
|
+
};
|
|
663
|
+
const staged = {
|
|
664
|
+
tools: [],
|
|
665
|
+
middleware: [],
|
|
666
|
+
commands: [],
|
|
667
|
+
promptSections: []
|
|
668
|
+
};
|
|
669
|
+
const ctx = {
|
|
670
|
+
cwd,
|
|
671
|
+
manifest: Object.freeze({ ...effectiveManifest }),
|
|
672
|
+
addTool: (tool) => staged.tools.push(tool),
|
|
673
|
+
addMiddleware: (mw) => staged.middleware.push(mw),
|
|
674
|
+
addCommand: (cmd) => staged.commands.push(cmd),
|
|
675
|
+
addPromptSection: (section) => staged.promptSections.push(section),
|
|
676
|
+
events: this.eventBus,
|
|
677
|
+
settings: settings.provider,
|
|
678
|
+
onActivate: (fn) => {
|
|
679
|
+
lifecycle.activate.push(fn);
|
|
680
|
+
},
|
|
681
|
+
onDeactivate: (fn) => {
|
|
682
|
+
lifecycle.deactivate.push(fn);
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
const finalizeLoad = () => {
|
|
686
|
+
const commandConflict = this.findCommandConflict(
|
|
687
|
+
effectiveManifest.id,
|
|
688
|
+
staged.commands
|
|
689
|
+
);
|
|
690
|
+
if (commandConflict) {
|
|
691
|
+
this.recordError(effectiveManifest.id, commandConflict);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
const loadedPlugin = {
|
|
695
|
+
manifest: effectiveManifest,
|
|
696
|
+
entryPath,
|
|
697
|
+
lifecycle,
|
|
698
|
+
definition
|
|
699
|
+
};
|
|
700
|
+
this.commitPlugin(loadedPlugin, staged);
|
|
701
|
+
if (this.activated && this.activeSessionContext) {
|
|
702
|
+
return this.runActivateHooks(loadedPlugin, this.activeSessionContext);
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
try {
|
|
706
|
+
const result = withTimeout(
|
|
707
|
+
() => init(ctx),
|
|
708
|
+
this.timeouts.load,
|
|
709
|
+
`plugin init timed out after ${this.timeouts.load}ms`
|
|
710
|
+
);
|
|
711
|
+
if (isPromiseLike(result)) {
|
|
712
|
+
return result.then(
|
|
713
|
+
() => finalizeLoad(),
|
|
714
|
+
(err) => {
|
|
715
|
+
this.recordError(
|
|
716
|
+
effectiveManifest.id,
|
|
717
|
+
err instanceof Error ? err.message : String(err)
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
} catch (err) {
|
|
723
|
+
this.recordError(
|
|
724
|
+
effectiveManifest.id,
|
|
725
|
+
err instanceof Error ? err.message : String(err)
|
|
726
|
+
);
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
return finalizeLoad();
|
|
730
|
+
}
|
|
731
|
+
resolvePluginSettings(manifest, definition) {
|
|
732
|
+
const settingsDefinition = definition?.settings;
|
|
733
|
+
if (!settingsDefinition) {
|
|
734
|
+
return { provider: this.settings };
|
|
735
|
+
}
|
|
736
|
+
const namespace = settingsDefinition.namespace ?? manifest.id;
|
|
737
|
+
try {
|
|
738
|
+
const parsed = resolvePluginSettingsValue(
|
|
739
|
+
this.settings,
|
|
740
|
+
namespace,
|
|
741
|
+
settingsDefinition
|
|
742
|
+
);
|
|
743
|
+
if (parsed === void 0) {
|
|
744
|
+
return { provider: this.settings };
|
|
745
|
+
}
|
|
746
|
+
return {
|
|
747
|
+
provider: new ValidatedSettings(this.settings, { [namespace]: parsed })
|
|
748
|
+
};
|
|
749
|
+
} catch (err) {
|
|
750
|
+
return {
|
|
751
|
+
error: err instanceof Error ? err.message : String(err)
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
findCommandConflict(pluginId, commands) {
|
|
756
|
+
const seen = /* @__PURE__ */ new Map();
|
|
757
|
+
for (const command of commands) {
|
|
758
|
+
const name = normalizeCommandToken(command.name);
|
|
759
|
+
if (!name) {
|
|
760
|
+
return `command name cannot be empty`;
|
|
761
|
+
}
|
|
762
|
+
const nameConflict = this.checkCommandTokenConflict(
|
|
763
|
+
pluginId,
|
|
764
|
+
command.name,
|
|
765
|
+
name,
|
|
766
|
+
seen
|
|
767
|
+
);
|
|
768
|
+
if (nameConflict) {
|
|
769
|
+
return nameConflict;
|
|
770
|
+
}
|
|
771
|
+
for (const alias of command.alias ?? []) {
|
|
772
|
+
const normalizedAlias = normalizeCommandToken(alias);
|
|
773
|
+
if (!normalizedAlias) {
|
|
774
|
+
return `command alias cannot be empty for "${command.name}"`;
|
|
775
|
+
}
|
|
776
|
+
if (normalizedAlias === name) {
|
|
777
|
+
continue;
|
|
778
|
+
}
|
|
779
|
+
const aliasConflict = this.checkCommandTokenConflict(
|
|
780
|
+
pluginId,
|
|
781
|
+
alias,
|
|
782
|
+
normalizedAlias,
|
|
783
|
+
seen
|
|
784
|
+
);
|
|
785
|
+
if (aliasConflict) {
|
|
786
|
+
return aliasConflict;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return void 0;
|
|
791
|
+
}
|
|
792
|
+
checkCommandTokenConflict(pluginId, rawToken, normalizedToken, seen) {
|
|
793
|
+
const existingOwner = this.commandTokens.get(normalizedToken);
|
|
794
|
+
if (existingOwner) {
|
|
795
|
+
return `command token "${rawToken}" conflicts with plugin "${existingOwner}"`;
|
|
796
|
+
}
|
|
797
|
+
const localOwner = seen.get(normalizedToken);
|
|
798
|
+
if (localOwner) {
|
|
799
|
+
return `command token "${rawToken}" is declared multiple times within plugin "${pluginId}"`;
|
|
800
|
+
}
|
|
801
|
+
seen.set(normalizedToken, pluginId);
|
|
802
|
+
return void 0;
|
|
803
|
+
}
|
|
804
|
+
commitPlugin(plugin, staged) {
|
|
805
|
+
this.plugins.push(plugin);
|
|
806
|
+
this.pluginIds.add(plugin.manifest.id);
|
|
807
|
+
this._contributions.tools.push(...staged.tools);
|
|
808
|
+
this._contributions.middleware.push(...staged.middleware);
|
|
809
|
+
this._contributions.commands.push(...staged.commands);
|
|
810
|
+
this._contributions.promptSections.push(...staged.promptSections);
|
|
811
|
+
for (const command of staged.commands) {
|
|
812
|
+
this.commandOwners.set(command, plugin.manifest.id);
|
|
813
|
+
this.commandTokens.set(
|
|
814
|
+
normalizeCommandToken(command.name),
|
|
815
|
+
plugin.manifest.id
|
|
816
|
+
);
|
|
817
|
+
for (const alias of command.alias ?? []) {
|
|
818
|
+
const normalizedAlias = normalizeCommandToken(alias);
|
|
819
|
+
if (normalizedAlias) {
|
|
820
|
+
this.commandTokens.set(normalizedAlias, plugin.manifest.id);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
async runActivateHooks(plugin, ctx) {
|
|
826
|
+
for (const hook of plugin.lifecycle.activate) {
|
|
827
|
+
try {
|
|
828
|
+
await withTimeout(
|
|
829
|
+
() => hook(ctx),
|
|
830
|
+
this.timeouts.activate,
|
|
831
|
+
`activate timed out after ${this.timeouts.activate}ms`
|
|
832
|
+
);
|
|
833
|
+
} catch (err) {
|
|
834
|
+
this.recordError(
|
|
835
|
+
plugin.manifest.id,
|
|
836
|
+
`activate failed: ${err instanceof Error ? err.message : String(err)}`
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
async runDeactivateHooks(plugin) {
|
|
842
|
+
for (let i = plugin.lifecycle.deactivate.length - 1; i >= 0; i--) {
|
|
843
|
+
try {
|
|
844
|
+
await withTimeout(
|
|
845
|
+
() => plugin.lifecycle.deactivate[i](),
|
|
846
|
+
this.timeouts.deactivate,
|
|
847
|
+
`deactivate timed out after ${this.timeouts.deactivate}ms`
|
|
848
|
+
);
|
|
849
|
+
} catch (err) {
|
|
850
|
+
this.recordError(
|
|
851
|
+
plugin.manifest.id,
|
|
852
|
+
`deactivate failed: ${err instanceof Error ? err.message : String(err)}`
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
function resolvePluginSettingsValue(settings, namespace, definition) {
|
|
859
|
+
if (definition.optional ?? true) {
|
|
860
|
+
return settings.parse(namespace, definition.schema);
|
|
861
|
+
}
|
|
862
|
+
return settings.require(namespace, definition.schema);
|
|
863
|
+
}
|
|
864
|
+
function mergePluginManifest(manifest, definition) {
|
|
865
|
+
if (!definition) {
|
|
866
|
+
return manifest;
|
|
867
|
+
}
|
|
868
|
+
return {
|
|
869
|
+
...manifest,
|
|
870
|
+
id: definition.id ?? manifest.id,
|
|
871
|
+
name: definition.name ?? manifest.name,
|
|
872
|
+
description: definition.description ?? manifest.description,
|
|
873
|
+
version: definition.version ?? manifest.version,
|
|
874
|
+
compatibility: mergeCompatibility(manifest.compatibility, definition.compatibility) ?? manifest.compatibility
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
function mergeCompatibility(manifest, definition) {
|
|
878
|
+
if (!manifest) return definition;
|
|
879
|
+
if (!definition) return manifest;
|
|
880
|
+
return { ...manifest, ...definition };
|
|
881
|
+
}
|
|
882
|
+
function normalizeCommandToken(token) {
|
|
883
|
+
return token.trim().replace(/^\//, "").toLowerCase();
|
|
884
|
+
}
|
|
885
|
+
function sanitizeNodeVersion(version) {
|
|
886
|
+
return version?.replace(/^v/, "");
|
|
887
|
+
}
|
|
888
|
+
function normalizeTimeout(timeout, fallback) {
|
|
889
|
+
if (timeout === false) {
|
|
890
|
+
return false;
|
|
891
|
+
}
|
|
892
|
+
if (typeof timeout === "number" && Number.isFinite(timeout) && timeout > 0) {
|
|
893
|
+
return timeout;
|
|
894
|
+
}
|
|
895
|
+
return fallback;
|
|
896
|
+
}
|
|
897
|
+
function withTimeout(fn, timeoutMs, message) {
|
|
898
|
+
const result = fn();
|
|
899
|
+
if (timeoutMs === false) {
|
|
900
|
+
return result;
|
|
901
|
+
}
|
|
902
|
+
if (!isPromiseLike(result)) {
|
|
903
|
+
return result;
|
|
904
|
+
}
|
|
905
|
+
return new Promise((resolve, reject) => {
|
|
906
|
+
const timer = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
907
|
+
Promise.resolve(result).then(resolve, reject).finally(() => clearTimeout(timer));
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
function isPromiseLike(value) {
|
|
911
|
+
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
export {
|
|
915
|
+
PluginEventBus,
|
|
916
|
+
NullSettings,
|
|
917
|
+
StaticSettings,
|
|
918
|
+
LayeredSettings,
|
|
919
|
+
ValidatedSettings,
|
|
920
|
+
resolveFrameworkAliases,
|
|
921
|
+
resetFrameworkAliases,
|
|
922
|
+
getPluginLoader,
|
|
923
|
+
resetPluginLoader,
|
|
924
|
+
discoverPlugins,
|
|
925
|
+
loadPluginModule,
|
|
926
|
+
definePlugin,
|
|
927
|
+
isDefinedPlugin,
|
|
928
|
+
PluginRegistry
|
|
929
|
+
};
|