bun_plugins 1.2.4 → 1.2.6

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.
Files changed (155) hide show
  1. package/README.md +2 -2
  2. package/dist/{src/PluginManager.d.ts → PluginManager.d.ts} +9 -16
  3. package/dist/PluginManager.d.ts.map +1 -0
  4. package/dist/{src/PluginManager.js → PluginManager.js} +188 -187
  5. package/dist/PluginManager.js.map +1 -0
  6. package/dist/{src/index.d.ts → index.d.ts} +1 -2
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/{src/index.js → index.js} +0 -2
  9. package/dist/index.js.map +1 -0
  10. package/dist/{src/managers → managers}/ContextFactory.d.ts +1 -1
  11. package/dist/managers/ContextFactory.d.ts.map +1 -0
  12. package/dist/{src/managers → managers}/ContextFactory.js +29 -52
  13. package/dist/managers/ContextFactory.js.map +1 -0
  14. package/dist/managers/DependencyManager.d.ts.map +1 -0
  15. package/dist/{src/managers → managers}/DependencyManager.js +5 -7
  16. package/dist/managers/DependencyManager.js.map +1 -0
  17. package/dist/{src/managers → managers}/HooksManager.d.ts +1 -4
  18. package/dist/managers/HooksManager.d.ts.map +1 -0
  19. package/dist/{src/managers → managers}/HooksManager.js +8 -36
  20. package/dist/managers/HooksManager.js.map +1 -0
  21. package/dist/managers/ResourceManager.d.ts.map +1 -0
  22. package/dist/{src/managers → managers}/ResourceManager.js +3 -3
  23. package/dist/managers/ResourceManager.js.map +1 -0
  24. package/dist/{src/storage → storage}/JsonPluginStorage.d.ts +1 -2
  25. package/dist/storage/JsonPluginStorage.d.ts.map +1 -0
  26. package/dist/storage/JsonPluginStorage.js +63 -0
  27. package/dist/storage/JsonPluginStorage.js.map +1 -0
  28. package/dist/{src/types.d.ts → types.d.ts} +19 -60
  29. package/dist/types.d.ts.map +1 -0
  30. package/dist/{src/types.js → types.js} +0 -7
  31. package/dist/types.js.map +1 -0
  32. package/dist/utils/errorParser.d.ts.map +1 -0
  33. package/dist/{src/utils → utils}/errorParser.js +5 -2
  34. package/dist/utils/errorParser.js.map +1 -0
  35. package/dist/utils/pluginValidator.d.ts +93 -0
  36. package/dist/utils/pluginValidator.d.ts.map +1 -0
  37. package/dist/{src/utils → utils}/pluginValidator.js +14 -12
  38. package/dist/utils/pluginValidator.js.map +1 -0
  39. package/dist/utils/security.d.ts.map +1 -0
  40. package/dist/utils/security.js.map +1 -0
  41. package/dist/worker/WorkerRunner.d.ts.map +1 -0
  42. package/dist/{src/worker → worker}/WorkerRunner.js +13 -33
  43. package/dist/worker/WorkerRunner.js.map +1 -0
  44. package/package.json +7 -18
  45. package/LICENSE +0 -9
  46. package/dist/plugins/ActionRegistryPlugin.d.ts +0 -23
  47. package/dist/plugins/ActionRegistryPlugin.d.ts.map +0 -1
  48. package/dist/plugins/ActionRegistryPlugin.js +0 -56
  49. package/dist/plugins/ActionRegistryPlugin.js.map +0 -1
  50. package/dist/plugins/DynamicJSActionsPlugin.d.ts +0 -21
  51. package/dist/plugins/DynamicJSActionsPlugin.d.ts.map +0 -1
  52. package/dist/plugins/DynamicJSActionsPlugin.js +0 -57
  53. package/dist/plugins/DynamicJSActionsPlugin.js.map +0 -1
  54. package/dist/plugins/DynamicMathActionsPlugin.d.ts +0 -22
  55. package/dist/plugins/DynamicMathActionsPlugin.d.ts.map +0 -1
  56. package/dist/plugins/DynamicMathActionsPlugin.js +0 -64
  57. package/dist/plugins/DynamicMathActionsPlugin.js.map +0 -1
  58. package/dist/plugins/DynamicTextActionsPlugin.d.ts +0 -22
  59. package/dist/plugins/DynamicTextActionsPlugin.d.ts.map +0 -1
  60. package/dist/plugins/DynamicTextActionsPlugin.js +0 -58
  61. package/dist/plugins/DynamicTextActionsPlugin.js.map +0 -1
  62. package/dist/plugins/DynamicUtilityActionsPlugin.d.ts +0 -22
  63. package/dist/plugins/DynamicUtilityActionsPlugin.d.ts.map +0 -1
  64. package/dist/plugins/DynamicUtilityActionsPlugin.js +0 -75
  65. package/dist/plugins/DynamicUtilityActionsPlugin.js.map +0 -1
  66. package/dist/plugins/LifecycleDemoPlugin.d.ts +0 -20
  67. package/dist/plugins/LifecycleDemoPlugin.d.ts.map +0 -1
  68. package/dist/plugins/LifecycleDemoPlugin.js +0 -34
  69. package/dist/plugins/LifecycleDemoPlugin.js.map +0 -1
  70. package/dist/plugins/MathPlugin.d.ts +0 -16
  71. package/dist/plugins/MathPlugin.d.ts.map +0 -1
  72. package/dist/plugins/MathPlugin.js +0 -25
  73. package/dist/plugins/MathPlugin.js.map +0 -1
  74. package/dist/plugins/MyJSPlugin.d.ts +0 -7
  75. package/dist/plugins/MyJSPlugin.d.ts.map +0 -1
  76. package/dist/plugins/MyJSPlugin.js +0 -12
  77. package/dist/plugins/MyJSPlugin.js.map +0 -1
  78. package/dist/plugins/arktype/index.d.ts +0 -8
  79. package/dist/plugins/arktype/index.d.ts.map +0 -1
  80. package/dist/plugins/arktype/index.js +0 -25
  81. package/dist/plugins/arktype/index.js.map +0 -1
  82. package/dist/src/Plugin.d.ts +0 -28
  83. package/dist/src/Plugin.d.ts.map +0 -1
  84. package/dist/src/Plugin.js +0 -36
  85. package/dist/src/Plugin.js.map +0 -1
  86. package/dist/src/PluginManager.d.ts.map +0 -1
  87. package/dist/src/PluginManager.js.map +0 -1
  88. package/dist/src/index.d.ts.map +0 -1
  89. package/dist/src/index.js.map +0 -1
  90. package/dist/src/logger/LoggerAdapter.d.ts +0 -77
  91. package/dist/src/logger/LoggerAdapter.d.ts.map +0 -1
  92. package/dist/src/logger/LoggerAdapter.js +0 -242
  93. package/dist/src/logger/LoggerAdapter.js.map +0 -1
  94. package/dist/src/logger/LoggerFactory.d.ts +0 -73
  95. package/dist/src/logger/LoggerFactory.d.ts.map +0 -1
  96. package/dist/src/logger/LoggerFactory.js +0 -99
  97. package/dist/src/logger/LoggerFactory.js.map +0 -1
  98. package/dist/src/logger/index.d.ts +0 -3
  99. package/dist/src/logger/index.d.ts.map +0 -1
  100. package/dist/src/logger/index.js +0 -3
  101. package/dist/src/logger/index.js.map +0 -1
  102. package/dist/src/managers/ContextFactory.d.ts.map +0 -1
  103. package/dist/src/managers/ContextFactory.js.map +0 -1
  104. package/dist/src/managers/DependencyManager.d.ts.map +0 -1
  105. package/dist/src/managers/DependencyManager.js.map +0 -1
  106. package/dist/src/managers/HooksManager.d.ts.map +0 -1
  107. package/dist/src/managers/HooksManager.js.map +0 -1
  108. package/dist/src/managers/ResourceManager.d.ts.map +0 -1
  109. package/dist/src/managers/ResourceManager.js.map +0 -1
  110. package/dist/src/storage/JsonPluginStorage.d.ts.map +0 -1
  111. package/dist/src/storage/JsonPluginStorage.js +0 -75
  112. package/dist/src/storage/JsonPluginStorage.js.map +0 -1
  113. package/dist/src/types/arktype_converter.d.ts +0 -19
  114. package/dist/src/types/arktype_converter.d.ts.map +0 -1
  115. package/dist/src/types/arktype_converter.js +0 -73
  116. package/dist/src/types/arktype_converter.js.map +0 -1
  117. package/dist/src/types/generator.d.ts +0 -9
  118. package/dist/src/types/generator.d.ts.map +0 -1
  119. package/dist/src/types/generator.js +0 -9
  120. package/dist/src/types/generator.js.map +0 -1
  121. package/dist/src/types/interfaces.d.ts +0 -55
  122. package/dist/src/types/interfaces.d.ts.map +0 -1
  123. package/dist/src/types/interfaces.js +0 -5
  124. package/dist/src/types/interfaces.js.map +0 -1
  125. package/dist/src/types/plugin-registry-base.d.ts +0 -78
  126. package/dist/src/types/plugin-registry-base.d.ts.map +0 -1
  127. package/dist/src/types/plugin-registry-base.js +0 -6
  128. package/dist/src/types/plugin-registry-base.js.map +0 -1
  129. package/dist/src/types/plugin-registry.d.ts +0 -2
  130. package/dist/src/types/plugin-registry.d.ts.map +0 -1
  131. package/dist/src/types/plugin-registry.js +0 -4
  132. package/dist/src/types/plugin-registry.js.map +0 -1
  133. package/dist/src/types/plugin_generator.d.ts +0 -62
  134. package/dist/src/types/plugin_generator.d.ts.map +0 -1
  135. package/dist/src/types/plugin_generator.js +0 -700
  136. package/dist/src/types/plugin_generator.js.map +0 -1
  137. package/dist/src/types.d.ts.map +0 -1
  138. package/dist/src/types.js.map +0 -1
  139. package/dist/src/utils/errorParser.d.ts.map +0 -1
  140. package/dist/src/utils/errorParser.js.map +0 -1
  141. package/dist/src/utils/pluginValidator.d.ts +0 -17
  142. package/dist/src/utils/pluginValidator.d.ts.map +0 -1
  143. package/dist/src/utils/pluginValidator.js.map +0 -1
  144. package/dist/src/utils/security.d.ts.map +0 -1
  145. package/dist/src/utils/security.js.map +0 -1
  146. package/dist/src/worker/WorkerRunner.d.ts.map +0 -1
  147. package/dist/src/worker/WorkerRunner.js.map +0 -1
  148. package/plugin-types/index.d.ts +0 -20
  149. package/plugin-types/plugin-registry.d.ts +0 -148
  150. /package/dist/{src/managers → managers}/DependencyManager.d.ts +0 -0
  151. /package/dist/{src/managers → managers}/ResourceManager.d.ts +0 -0
  152. /package/dist/{src/utils → utils}/errorParser.d.ts +0 -0
  153. /package/dist/{src/utils → utils}/security.d.ts +0 -0
  154. /package/dist/{src/utils → utils}/security.js +0 -0
  155. /package/dist/{src/worker → worker}/WorkerRunner.d.ts +0 -0
@@ -1,22 +1,21 @@
1
1
  import { EventEmitter } from "node:events";
2
2
  import { readdir, mkdir } from "node:fs/promises";
3
- import { join } from "node:path";
3
+ import { join, dirname } from "node:path";
4
4
  import { watch, existsSync } from "node:fs";
5
5
  import { WorkerMessageType, PluginPermission, RPCMethod, HookType } from "./types";
6
6
  import { validatePlugin } from "./utils/pluginValidator";
7
7
  import { JsonPluginStorage } from "./storage/JsonPluginStorage";
8
- import * as semver from "semver";
8
+ import semver from "semver";
9
9
  import { ResourceManager } from "./managers/ResourceManager";
10
10
  import { DependencyManager } from "./managers/DependencyManager";
11
11
  import { HooksManager } from "./managers/HooksManager";
12
12
  import { createPluginContext } from "./managers/ContextFactory";
13
13
  import { errorParser } from "./utils/errorParser";
14
14
  import { checkNetworkPermission, checkPermission as checkGeneralPermission } from "./utils/security";
15
- import { logger } from "./logger";
16
15
  export class PluginManager extends EventEmitter {
17
16
  plugins = new Map();
18
17
  availablePlugins = new Map();
19
- configs = new Map();
18
+ pluginFiles = new Map(); // filePath -> pluginName
20
19
  // Modules
21
20
  resources;
22
21
  dependencyManager;
@@ -26,6 +25,8 @@ export class PluginManager extends EventEmitter {
26
25
  pluginLoadTimeout;
27
26
  workerFactory;
28
27
  workerRunnerPath;
28
+ hotReloadWatcher = null;
29
+ hotReloadTimer = null;
29
30
  constructor(storageRoot = join(process.cwd(), "storage"), options) {
30
31
  super();
31
32
  this.storageRoot = storageRoot;
@@ -61,7 +62,7 @@ export class PluginManager extends EventEmitter {
61
62
  throw new Error(`Plugin ${plugin.name} requires host version ${plugin.engines.host}, but found ${this.hostVersion}`);
62
63
  }
63
64
  }
64
- logger.getLogger("PluginManager").info(`Loading plugin: ${plugin.name} v${plugin.version}`);
65
+ console.log(`Loading plugin: ${plugin.name} v${plugin.version}`);
65
66
  // 1. Prepare Storage
66
67
  const storage = new JsonPluginStorage(this.storageRoot, plugin.name);
67
68
  // 2. Load & Validate Configuration
@@ -72,7 +73,8 @@ export class PluginManager extends EventEmitter {
72
73
  }
73
74
  catch (e) {
74
75
  const error = errorParser(e, `Error in plugin ${plugin.name}`);
75
- logger.getLogger("PluginManager").warn(`[SafeMode] Using default config, validation failed. Error: ${error.message}`);
76
+ console.warn(`[SafeMode] Using default config, validation failed. Error: ${error.message}`);
77
+ config = {}; // Reset to empty config on validation failure to prevent downstream errors
76
78
  }
77
79
  }
78
80
  // 3. Initialize Resources
@@ -82,57 +84,37 @@ export class PluginManager extends EventEmitter {
82
84
  throw new Error(`Invalid plugin name: ${plugin.name}. Name cannot contain path traversal characters.`);
83
85
  }
84
86
  // 4. Context Creation
85
- this.configs.set(plugin.name, config);
86
- const context = createPluginContext(this, plugin, this.resources, storage);
87
+ const context = createPluginContext(this, plugin, this.resources, storage, config);
87
88
  // 5. Setup Hooks with Performance Monitoring (Delegated to HooksManager via Builder)
88
89
  if (plugin.setup) {
89
90
  try {
90
- await plugin.setup(this.hooksManager.getBuilder(plugin.name, config));
91
+ await plugin.setup(this.hooksManager.getBuilder(plugin.name));
91
92
  }
92
93
  catch (e) {
93
- logger.getLogger("PluginManager").error(`Error during setup for ${plugin.name}:`, e);
94
+ console.error(`Error during setup for ${plugin.name}:`, e);
94
95
  throw errorParser(e, `Error during setup for ${plugin.name}`);
95
96
  }
96
97
  }
97
98
  // 6. Lifecycle onLoad
98
99
  try {
99
- let completed = false;
100
- let timeoutError = null;
101
- const timeoutId = setTimeout(() => {
102
- if (!completed) {
103
- completed = true;
104
- timeoutError = new Error(`Plugin ${plugin.name} timed out (${this.pluginLoadTimeout}ms)`);
105
- }
106
- }, this.pluginLoadTimeout);
100
+ const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error(`Plugin ${plugin.name} timed out (${this.pluginLoadTimeout}ms)`)), this.pluginLoadTimeout));
107
101
  const start = performance.now();
108
- try {
109
- await plugin.onLoad(context);
110
- }
111
- finally {
112
- completed = true;
113
- clearTimeout(timeoutId);
114
- }
115
- // Check if timeout triggered
116
- if (timeoutError) {
117
- throw timeoutError;
118
- }
102
+ await Promise.race([plugin.onLoad(context), timeoutPromise]);
119
103
  const duration = performance.now() - start;
120
104
  this.plugins.set(plugin.name, plugin);
121
- logger.getLogger("PluginManager").info(`Plugin ${plugin.name} loaded successfully in ${duration.toFixed(2)}ms.`);
105
+ console.log(`Plugin ${plugin.name} loaded successfully in ${duration.toFixed(2)}ms.`);
122
106
  // Trigger onStarted after registration if provided
123
107
  if (plugin.onStarted) {
124
108
  try {
125
109
  await plugin.onStarted();
126
110
  }
127
111
  catch (e) {
128
- logger.getLogger("PluginManager").error(`Error in onStarted for ${plugin.name}:`, e);
112
+ console.error(`Error in onStarted for ${plugin.name}:`, e);
129
113
  }
130
114
  }
131
- // 7. Trigger onStart hooks registered via setup()
132
- await this.hooksManager.runOnStart();
133
115
  }
134
116
  catch (error) {
135
- logger.getLogger("PluginManager").error(`Failed to load plugin ${plugin.name}:`, error);
117
+ console.error(`Failed to load plugin ${plugin.name}:`, error);
136
118
  // Cleanup resources directly since plugin is not in this.plugins yet
137
119
  this.resources.cleanup(plugin.name, this);
138
120
  this.hooksManager.cleanup(plugin.name);
@@ -142,7 +124,7 @@ export class PluginManager extends EventEmitter {
142
124
  async registerIsolated(pluginPath, pluginName) {
143
125
  return new Promise((resolve, reject) => {
144
126
  const workerScript = this.workerRunnerPath;
145
- logger.getLogger("PluginManager").info("Worker Path:", workerScript);
127
+ console.log("Worker Path:", workerScript);
146
128
  const timeoutId = setTimeout(() => {
147
129
  worker.terminate();
148
130
  reject(new Error(`Isolated plugin ${pluginName} timed out during loading (${this.pluginLoadTimeout}ms)`));
@@ -223,22 +205,16 @@ export class PluginManager extends EventEmitter {
223
205
  else if (type === HookType.ON_LOAD) {
224
206
  this.hooksManager.registerOnLoad(filterRegExp, proxyCallback, pluginName, options?.order);
225
207
  }
226
- else if (type === HookType.ON_START) {
227
- this.hooksManager.registerOnStart(() => proxyCallback({}), pluginName);
228
- }
229
208
  result = true;
230
209
  }
231
210
  else if (method === RPCMethod.ManagerGetPlugin) {
232
211
  const targetName = args[0];
233
212
  const p = this.getPlugin(targetName);
234
- result = p && typeof p === 'object' && 'getApi' in p && typeof p.getApi === 'function'
235
- ? p.getApi()
236
- : undefined;
213
+ result = p?.getSharedApi ? p.getSharedApi() : undefined;
237
214
  }
238
215
  else if (method === RPCMethod.Log) {
239
216
  const level = args[0];
240
- const [msg, ...restArgs] = args.slice(1);
241
- logger.getLogger(pluginName)[level](msg, ...restArgs);
217
+ console[level](`[${pluginName}]`, ...args.slice(1));
242
218
  result = true;
243
219
  }
244
220
  else if (method === RPCMethod.PermissionCheck) {
@@ -254,22 +230,13 @@ export class PluginManager extends EventEmitter {
254
230
  const urlStr = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
255
231
  checkPermission(PluginPermission.Network, urlStr);
256
232
  const response = await fetch(input, init);
257
- const responseHeaders = {};
258
- response.headers.forEach((v, k) => { responseHeaders[k] = v; });
259
233
  result = {
260
234
  status: response.status,
261
235
  statusText: response.statusText,
262
- headers: responseHeaders,
236
+ headers: Object.fromEntries(response.headers.entries()),
263
237
  body: await response.text()
264
238
  };
265
239
  }
266
- else if (method === RPCMethod.ConfigGet) {
267
- result = this.getPluginConfig(pluginName);
268
- }
269
- else if (method === RPCMethod.StorageReload) {
270
- await storage.reload();
271
- result = true;
272
- }
273
240
  worker.postMessage({ id, result });
274
241
  }
275
242
  catch (e) {
@@ -296,7 +263,7 @@ export class PluginManager extends EventEmitter {
296
263
  else if (msg.type === WorkerMessageType.MANIFEST) {
297
264
  const { metadata } = msg;
298
265
  pluginMetadata = metadata;
299
- logger.getLogger("PluginManager").info(`Metadata received for isolated plugin: ${metadata.name}`);
266
+ console.log(`Metadata received for isolated plugin: ${metadata.name}`);
300
267
  }
301
268
  else if (msg.type === WorkerMessageType.LOAD_SUCCESS) {
302
269
  clearTimeout(timeoutId); // Success, clear global timeout
@@ -319,20 +286,20 @@ export class PluginManager extends EventEmitter {
319
286
  await new Promise(r => setTimeout(r, 200));
320
287
  worker.terminate();
321
288
  // Clear pending hooks on unload
322
- for (const pending of Array.from(pendingHooks.values())) {
289
+ for (const pending of pendingHooks.values()) {
323
290
  pending.reject(new Error("Plugin unloaded"));
324
291
  }
325
292
  pendingHooks.clear();
326
293
  },
327
294
  };
328
295
  this.plugins.set(metadata.name, proxyPlugin);
329
- logger.getLogger("PluginManager").info(`Isolated Plugin ${metadata.name} loaded in worker.`);
296
+ console.log(`Isolated Plugin ${metadata.name} loaded in worker.`);
330
297
  resolve();
331
298
  }
332
299
  else if (msg.type === WorkerMessageType.LOAD_ERROR) {
333
300
  clearTimeout(timeoutId);
334
301
  // Cleanup pending hooks on load error
335
- for (const pending of Array.from(pendingHooks.values())) {
302
+ for (const pending of pendingHooks.values()) {
336
303
  pending.reject(new Error(`Load error: ${msg.error}`));
337
304
  }
338
305
  pendingHooks.clear();
@@ -343,9 +310,9 @@ export class PluginManager extends EventEmitter {
343
310
  worker.addEventListener("message", (event) => rpcHandler(event.data));
344
311
  worker.addEventListener("error", (err) => {
345
312
  clearTimeout(timeoutId);
346
- logger.getLogger("PluginManager").error(`[Isolated:${pluginName}] Worker Error:`, err);
313
+ console.error(`[Isolated:${pluginName}] Worker Error:`, err);
347
314
  // Reject all pending hooks on crash
348
- for (const pending of Array.from(pendingHooks.values())) {
315
+ for (const pending of pendingHooks.values()) {
349
316
  pending.reject(new Error("Worker terminated unexpectedly"));
350
317
  }
351
318
  pendingHooks.clear();
@@ -357,39 +324,27 @@ export class PluginManager extends EventEmitter {
357
324
  const plugin = this.plugins.get(pluginName);
358
325
  if (!plugin)
359
326
  return;
360
- for (const [name, p] of Array.from(this.plugins.entries())) {
327
+ for (const [name, p] of this.plugins.entries()) {
361
328
  if (p.dependencies && p.dependencies[pluginName]) {
362
- logger.getLogger("PluginManager").warn(`Warning: Plugin ${name} depends on ${pluginName} which is being unloaded.`);
329
+ console.warn(`Warning: Plugin ${name} depends on ${pluginName} which is being unloaded.`);
363
330
  }
364
331
  }
365
332
  try {
366
333
  await plugin.onUnload();
367
334
  }
368
335
  catch (error) {
369
- logger.getLogger("PluginManager").error(`Error unloading plugin ${pluginName}:`, error);
336
+ console.error(`Error unloading plugin ${pluginName}:`, error);
370
337
  }
371
338
  finally {
372
339
  this.plugins.delete(pluginName);
373
340
  this.resources.cleanup(pluginName, this);
374
341
  this.hooksManager.cleanup(pluginName);
375
- logger.getLogger("PluginManager").info(`Plugin ${pluginName} unloaded.`);
342
+ console.log(`Plugin ${pluginName} unloaded.`);
376
343
  }
377
344
  }
378
345
  getPlugin(name) {
379
346
  return this.plugins.get(name);
380
347
  }
381
- getApi(name) {
382
- const plugin = this.plugins.get(name);
383
- if (!plugin)
384
- return undefined;
385
- if (plugin.getApi) {
386
- return plugin.getApi();
387
- }
388
- return undefined;
389
- }
390
- getPluginConfig(name) {
391
- return this.configs.get(name) || {};
392
- }
393
348
  listPlugins() {
394
349
  return Array.from(this.plugins.keys());
395
350
  }
@@ -399,12 +354,6 @@ export class PluginManager extends EventEmitter {
399
354
  on(eventName, listener) {
400
355
  return super.on(eventName, listener);
401
356
  }
402
- once(eventName, listener) {
403
- return super.once(eventName, listener);
404
- }
405
- off(eventName, listener) {
406
- return super.off(eventName, listener);
407
- }
408
357
  async loadPluginsFromDirectory(directoryPath = join(process.cwd(), "plugins")) {
409
358
  try {
410
359
  const globalConfigPath = join(this.storageRoot, "plugins.json");
@@ -417,35 +366,15 @@ export class PluginManager extends EventEmitter {
417
366
  }
418
367
  }
419
368
  catch (e) {
420
- logger.getLogger("PluginManager").warn("Failed to load global plugin config", e);
369
+ console.warn("Failed to load global plugin config", e);
421
370
  }
422
- const entries = await readdir(directoryPath, { withFileTypes: true });
371
+ const files = await readdir(directoryPath);
423
372
  this.availablePlugins.clear();
424
- for (const entry of entries) {
425
- let fullPath = null;
426
- if (entry.isDirectory()) {
427
- const pluginDir = join(directoryPath, entry.name);
428
- const pkgPath = join(pluginDir, "package.json");
429
- if (existsSync(pkgPath)) {
430
- // Auto-install dependencies if node_modules missing
431
- await this.ensureDependenciesInstalled(pluginDir);
432
- fullPath = pluginDir;
433
- }
434
- else {
435
- const distPath = join(pluginDir, "dist");
436
- if (existsSync(distPath)) {
437
- fullPath = distPath;
438
- }
439
- }
440
- }
441
- else if ((entry.name.endsWith(".ts") || entry.name.endsWith(".js")) && !entry.name.endsWith(".d.ts")) {
442
- fullPath = join(directoryPath, entry.name);
443
- }
444
- if (fullPath) {
373
+ for (const file of files) {
374
+ if ((file.endsWith(".ts") || file.endsWith(".js")) && !file.endsWith(".d.ts")) {
375
+ const fullPath = join(directoryPath, file);
445
376
  try {
446
- // Use cache-busting for hot reload
447
- const query = `?update=${Date.now()}`;
448
- const module = await import(fullPath + query);
377
+ const module = await import(fullPath);
449
378
  for (const key in module) {
450
379
  const ExportedItem = module[key];
451
380
  const validation = validatePlugin(ExportedItem);
@@ -453,23 +382,22 @@ export class PluginManager extends EventEmitter {
453
382
  this.availablePlugins.set(validation.plugin.name, validation.plugin);
454
383
  }
455
384
  else {
456
- const errorMsg = validation.error;
457
- logger.getLogger("PluginManager").warn(`Skipping invalid plugin item in ${entry.name}: ${errorMsg}`);
385
+ console.warn(`Skipping invalid plugin in ${file}: ${validation.error}`);
458
386
  }
459
387
  }
460
388
  }
461
389
  catch (err) {
462
- logger.getLogger("PluginManager").error(`Error importing ${fullPath}:`, err);
390
+ console.error(`Error importing ${fullPath}:`, err);
463
391
  }
464
392
  }
465
393
  }
466
394
  const pluginsToLoad = [];
467
- for (const plugin of Array.from(this.availablePlugins.values())) {
395
+ for (const plugin of this.availablePlugins.values()) {
468
396
  if (!disabledPlugins.includes(plugin.name)) {
469
397
  pluginsToLoad.push(plugin);
470
398
  }
471
399
  else {
472
- logger.getLogger("PluginManager").info(`Plugin ${plugin.name} is disabled.`);
400
+ console.log(`Plugin ${plugin.name} is disabled.`);
473
401
  }
474
402
  }
475
403
  try {
@@ -480,7 +408,7 @@ export class PluginManager extends EventEmitter {
480
408
  if (plugin.dependencies) {
481
409
  for (const dep of Object.keys(plugin.dependencies)) {
482
410
  if (!this.plugins.has(dep)) {
483
- logger.getLogger("PluginManager").warn(`Skipping ${plugin.name}: Dependency ${dep} failed to load or is missing.`);
411
+ console.warn(`Skipping ${plugin.name}: Dependency ${dep} failed to load or is missing.`);
484
412
  dependenciesOk = false;
485
413
  break;
486
414
  }
@@ -489,18 +417,13 @@ export class PluginManager extends EventEmitter {
489
417
  if (!dependenciesOk)
490
418
  continue;
491
419
  try {
492
- if (this.plugins.has(plugin.name)) {
493
- logger.getLogger("PluginManager").info(`Updating plugin: ${plugin.name}`);
494
- await this.reloadPlugin(plugin.name);
495
- loadedPlugins.push(plugin);
496
- }
497
- else {
420
+ if (!this.plugins.has(plugin.name)) {
498
421
  await this.register(plugin);
499
422
  loadedPlugins.push(plugin);
500
423
  }
501
424
  }
502
425
  catch (e) {
503
- logger.getLogger("PluginManager").error(`Failed to load/update ${plugin.name}:`, e);
426
+ console.error(`Failed to load ${plugin.name}:`, e);
504
427
  }
505
428
  }
506
429
  for (const plugin of loadedPlugins) {
@@ -509,23 +432,23 @@ export class PluginManager extends EventEmitter {
509
432
  await plugin.onStarted();
510
433
  }
511
434
  catch (e) {
512
- logger.getLogger("PluginManager").error(`Error in onStarted for ${plugin.name}:`, e);
435
+ console.error(`Error in onStarted for ${plugin.name}:`, e);
513
436
  }
514
437
  }
515
438
  }
516
439
  }
517
440
  catch (e) {
518
- logger.getLogger("PluginManager").error("Failed to resolve plugin dependencies or load plugins:", e);
441
+ console.error("Failed to resolve plugin dependencies or load plugins:", e);
519
442
  }
520
443
  }
521
444
  catch (error) {
522
- logger.getLogger("PluginManager").error(`Failed to load plugins from ${directoryPath}`, error);
445
+ console.error(`Failed to load plugins from ${directoryPath}`, error);
523
446
  }
524
447
  }
525
448
  async disablePlugin(name) {
526
449
  await this.unregister(name);
527
450
  await this.updatePluginState(name, true);
528
- logger.getLogger("PluginManager").info(`Plugin ${name} disabled.`);
451
+ console.log(`Plugin ${name} disabled.`);
529
452
  }
530
453
  async enablePlugin(name) {
531
454
  await this.updatePluginState(name, false);
@@ -535,7 +458,7 @@ export class PluginManager extends EventEmitter {
535
458
  if (plugin.dependencies) {
536
459
  for (const dep of Object.keys(plugin.dependencies)) {
537
460
  if (!this.plugins.has(dep)) {
538
- logger.getLogger("PluginManager").warn(`Cannot enable ${name}: Dependency ${dep} is not loaded.`);
461
+ console.warn(`Cannot enable ${name}: Dependency ${dep} is not loaded.`);
539
462
  return;
540
463
  }
541
464
  }
@@ -543,33 +466,19 @@ export class PluginManager extends EventEmitter {
543
466
  await this.register(plugin);
544
467
  }
545
468
  else {
546
- logger.getLogger("PluginManager").warn(`Plugin ${name} enabled but not found in available plugins.`);
469
+ console.warn(`Plugin ${name} enabled but not found in available plugins.`);
547
470
  }
548
471
  }
549
472
  }
550
473
  async reloadPlugin(name) {
551
- const oldPlugin = this.plugins.get(name);
552
- if (oldPlugin) {
553
- logger.getLogger("PluginManager").info(`Reloading plugin ${name}...`);
474
+ const plugin = this.plugins.get(name);
475
+ if (plugin) {
476
+ console.log(`Reloading plugin ${name}...`);
554
477
  await this.unregister(name);
555
478
  }
556
479
  const definition = this.availablePlugins.get(name);
557
480
  if (definition) {
558
481
  await this.register(definition);
559
- const newPlugin = this.plugins.get(name);
560
- // If the new version has onReload, call it
561
- if (newPlugin && newPlugin.onReload) {
562
- // We need a context for onReload as well
563
- const storage = new JsonPluginStorage(this.storageRoot, name);
564
- const context = createPluginContext(this, newPlugin, this.resources, storage);
565
- try {
566
- await newPlugin.onReload(context);
567
- }
568
- catch (e) {
569
- logger.getLogger("PluginManager").error(`Error in onReload for ${name}:`, e);
570
- }
571
- }
572
- this.emit("plugin:updated", { name: definition.name, version: definition.version });
573
482
  }
574
483
  else {
575
484
  throw new Error(`Plugin ${name} not found in available plugins.`);
@@ -595,7 +504,7 @@ export class PluginManager extends EventEmitter {
595
504
  await Bun.write(globalConfigPath, JSON.stringify(config, null, 2));
596
505
  }
597
506
  catch (e) {
598
- logger.getLogger("PluginManager").error("Failed to update plugin state", e);
507
+ console.error("Failed to update plugin state", e);
599
508
  }
600
509
  }
601
510
  async runOnResolve(args) {
@@ -604,34 +513,158 @@ export class PluginManager extends EventEmitter {
604
513
  async runOnLoad(args) {
605
514
  return this.hooksManager.runOnLoad(args);
606
515
  }
607
- // Bun-like Aliases
608
- async use(plugin) { return this.register(plugin); }
609
- async plugin(plugin) { return this.register(plugin); }
610
- async remove(pluginName) { return this.unregister(pluginName); }
611
516
  toBunPlugin() {
612
517
  return this.hooksManager.toBunPlugin();
613
518
  }
614
- hotReloadTimer = null;
615
519
  enableHotReload(pluginDir) {
616
- logger.getLogger("PluginManager").info(`[HotReload] Watching ${pluginDir} for changes...`);
617
- watch(pluginDir, { recursive: true }, async (event, filename) => {
520
+ // Close existing watcher if any
521
+ if (this.hotReloadWatcher) {
522
+ this.hotReloadWatcher.close();
523
+ }
524
+ // Initial scan to build file map
525
+ this.scanAndTrackPlugins(pluginDir);
526
+ console.log(`[HotReload] Watching ${pluginDir} for changes...`);
527
+ this.hotReloadWatcher = watch(pluginDir, { recursive: true }, async (event, filename) => {
618
528
  if (!filename || (!filename.endsWith(".ts") && !filename.endsWith(".js")))
619
529
  return;
530
+ if (filename.endsWith(".d.ts"))
531
+ return; // Skip type definitions
532
+ const fullPath = join(pluginDir, filename);
620
533
  if (this.hotReloadTimer)
621
534
  clearTimeout(this.hotReloadTimer);
622
535
  this.hotReloadTimer = setTimeout(async () => {
623
- logger.getLogger("PluginManager").info(`[HotReload] Change detected in ${filename}. Re-scanning plugins...`);
624
- await this.loadPluginsFromDirectory(pluginDir);
536
+ await this.handleFileChange(event, fullPath, filename, pluginDir);
625
537
  }, 300);
626
538
  });
627
539
  }
540
+ async scanAndTrackPlugins(pluginDir) {
541
+ this.pluginFiles.clear();
542
+ try {
543
+ const files = await readdir(pluginDir);
544
+ for (const file of files) {
545
+ if ((file.endsWith(".ts") || file.endsWith(".js")) && !file.endsWith(".d.ts")) {
546
+ const fullPath = join(pluginDir, file);
547
+ try {
548
+ const module = await import(fullPath);
549
+ for (const key in module) {
550
+ const ExportedItem = module[key];
551
+ const validation = validatePlugin(ExportedItem);
552
+ if (validation.valid) {
553
+ this.pluginFiles.set(fullPath, validation.plugin.name);
554
+ this.availablePlugins.set(validation.plugin.name, validation.plugin);
555
+ }
556
+ }
557
+ }
558
+ catch (err) {
559
+ console.warn(`[HotReload] Failed to scan ${file}:`, err);
560
+ }
561
+ }
562
+ }
563
+ }
564
+ catch (err) {
565
+ console.error(`[HotReload] Failed to scan plugin directory:`, err);
566
+ }
567
+ }
568
+ async handleFileChange(event, fullPath, filename, pluginDir) {
569
+ const exists = existsSync(fullPath);
570
+ const previousName = this.pluginFiles.get(fullPath);
571
+ if (!exists && previousName) {
572
+ // File was removed - uninstall plugin
573
+ console.log(`[HotReload] Plugin file removed: ${filename}. Unloading plugin ${previousName}...`);
574
+ this.pluginFiles.delete(fullPath);
575
+ if (this.plugins.has(previousName)) {
576
+ await this.unregister(previousName);
577
+ console.log(`[HotReload] Plugin ${previousName} unloaded.`);
578
+ }
579
+ }
580
+ else if (exists && !previousName) {
581
+ // New file added - install plugin
582
+ console.log(event, `[HotReload] New plugin file detected: ${filename}. Loading plugin...`);
583
+ try {
584
+ const module = await import(fullPath);
585
+ for (const key in module) {
586
+ const ExportedItem = module[key];
587
+ const validation = validatePlugin(ExportedItem);
588
+ if (validation.valid) {
589
+ const plugin = validation.plugin;
590
+ this.pluginFiles.set(fullPath, plugin.name);
591
+ this.availablePlugins.set(plugin.name, plugin);
592
+ // Check if not disabled and load it
593
+ const globalConfigPath = join(this.storageRoot, "plugins.json");
594
+ let disabledPlugins = [];
595
+ try {
596
+ const file = Bun.file(globalConfigPath);
597
+ if (await file.exists()) {
598
+ const data = await file.json();
599
+ disabledPlugins = data.disabled || [];
600
+ }
601
+ }
602
+ catch (e) { /* ignore */ }
603
+ if (!disabledPlugins.includes(plugin.name) && !this.plugins.has(plugin.name)) {
604
+ await this.register(plugin);
605
+ console.log(`[HotReload] Plugin ${plugin.name} loaded.`);
606
+ }
607
+ }
608
+ }
609
+ }
610
+ catch (err) {
611
+ console.error(`[HotReload] Failed to load new plugin ${filename}:`, pluginDir, err);
612
+ }
613
+ }
614
+ else if (exists && previousName) {
615
+ // File was modified - reload plugin
616
+ console.log(`[HotReload] Plugin file modified: ${filename}. Reloading plugin ${previousName}...`);
617
+ try {
618
+ // Remove from module cache to force reimport
619
+ delete require.cache[fullPath];
620
+ // Unload existing plugin
621
+ if (this.plugins.has(previousName)) {
622
+ await this.unregister(previousName);
623
+ }
624
+ // Reload the plugin
625
+ const module = await import(fullPath);
626
+ for (const key in module) {
627
+ const ExportedItem = module[key];
628
+ const validation = validatePlugin(ExportedItem);
629
+ if (validation.valid) {
630
+ const plugin = validation.plugin;
631
+ this.availablePlugins.set(plugin.name, plugin);
632
+ // Check if not disabled and load it
633
+ const globalConfigPath = join(this.storageRoot, "plugins.json");
634
+ let disabledPlugins = [];
635
+ try {
636
+ const file = Bun.file(globalConfigPath);
637
+ if (await file.exists()) {
638
+ const data = await file.json();
639
+ disabledPlugins = data.disabled || [];
640
+ }
641
+ }
642
+ catch (e) { /* ignore */ }
643
+ if (!disabledPlugins.includes(plugin.name)) {
644
+ await this.register(plugin);
645
+ console.log(`[HotReload] Plugin ${plugin.name} reloaded.`);
646
+ }
647
+ }
648
+ }
649
+ }
650
+ catch (err) {
651
+ console.error(`[HotReload] Failed to reload plugin ${filename}:`, err);
652
+ }
653
+ }
654
+ }
655
+ disableHotReload() {
656
+ if (this.hotReloadWatcher) {
657
+ this.hotReloadWatcher.close();
658
+ this.hotReloadWatcher = null;
659
+ console.log(`[HotReload] File watcher stopped.`);
660
+ }
661
+ }
628
662
  getMetrics() {
629
663
  return {
630
664
  totalPlugins: this.plugins.size,
631
665
  activePlugins: Array.from(this.plugins.keys()),
632
666
  resources: this.resources.getUsageSummary(),
633
667
  hooks: {
634
- onStart: this.hooksManager.getHookCount(HookType.ON_START),
635
668
  onResolve: this.hooksManager.getHookCount(HookType.ON_RESOLVE),
636
669
  onLoad: this.hooksManager.getHookCount(HookType.ON_LOAD)
637
670
  }
@@ -639,7 +672,7 @@ export class PluginManager extends EventEmitter {
639
672
  }
640
673
  getPluginStatus() {
641
674
  const status = {};
642
- for (const [name, plugin] of Array.from(this.plugins)) {
675
+ for (const [name, plugin] of this.plugins) {
643
676
  const resources = this.resources.get(name);
644
677
  status[name] = {
645
678
  version: plugin.version,
@@ -653,37 +686,5 @@ export class PluginManager extends EventEmitter {
653
686
  }
654
687
  return status;
655
688
  }
656
- async ensureDependenciesInstalled(pluginPath) {
657
- const nodeModulesPath = join(pluginPath, "node_modules");
658
- if (!existsSync(nodeModulesPath)) {
659
- // 1. Check if we are in production
660
- const isProduction = process.env.NODE_ENV === "production";
661
- if (isProduction) {
662
- logger.getLogger("PluginManager").warn(`[PluginManager] Warning: Plugin at ${pluginPath} is missing node_modules. Auto-install is disabled in production.`);
663
- return;
664
- }
665
- // 2. Check if 'bun' CLI is even available in the system
666
- const bunPath = Bun.which("bun");
667
- if (!bunPath) {
668
- logger.getLogger("PluginManager").warn(`[PluginManager] Warning: node_modules missing in ${pluginPath}, but 'bun' CLI was not found. Cannot auto-install.`);
669
- return;
670
- }
671
- logger.getLogger("PluginManager").info(`[PluginManager] Development mode detected. node_modules missing in ${pluginPath}. Installing deps...`);
672
- try {
673
- const proc = Bun.spawn([bunPath, "install"], {
674
- cwd: pluginPath,
675
- stdout: "inherit",
676
- stderr: "inherit",
677
- });
678
- const exitCode = await proc.exited;
679
- if (exitCode !== 0) {
680
- logger.getLogger("PluginManager").error(`[PluginManager] Failed to install dependencies for ${pluginPath}. Exit code: ${exitCode}`);
681
- }
682
- }
683
- catch (e) {
684
- logger.getLogger("PluginManager").error(`[PluginManager] Error running bun install for ${pluginPath}:`, e);
685
- }
686
- }
687
- }
688
689
  }
689
690
  //# sourceMappingURL=PluginManager.js.map