aboutsummaryrefslogtreecommitdiff
path: root/modules/core/module-manager.js
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-05-25 18:02:02 +0200
committerAgando <roduccomm@gmail.com>2026-05-25 18:02:02 +0200
commit4baa484b84c5184286cac2743575251454a5ee2b (patch)
treecb9002f93644f363d0f35831dc97e6492bbb0ed6 /modules/core/module-manager.js
auto: 2026-05-25_18:02 changes
Diffstat (limited to 'modules/core/module-manager.js')
-rw-r--r--modules/core/module-manager.js138
1 files changed, 138 insertions, 0 deletions
diff --git a/modules/core/module-manager.js b/modules/core/module-manager.js
new file mode 100644
index 0000000..8e9e911
--- /dev/null
+++ b/modules/core/module-manager.js
@@ -0,0 +1,138 @@
+// Extracted from newOS4 index.html — ModuleManager
+ class ModuleManager {
+ constructor(terminal) {
+ this.terminal = terminal;
+ this.modules = {};
+ this.moduleRegistry = [];
+ this.loadFromStorage();
+ }
+ loadFromStorage() {
+ try {
+ const saved = localStorage.getItem('webx11_modules');
+ if (saved) {
+ this.moduleRegistry = JSON.parse(saved);
+ }
+ } catch (e) { console.error('Module load error:', e); }
+ }
+ saveToStorage() {
+ try {
+ localStorage.setItem('webx11_modules', JSON.stringify(this.moduleRegistry));
+ } catch (e) { console.error('Module save error:', e); }
+ }
+ async loadModuleFromURL(url) {
+ try {
+ this.terminal.print(`Loading module from ${url}...`, 'info');
+ const response = await fetch(url);
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
+ const code = await response.text();
+ const ModuleClass = this.createModuleClass(code, url);
+ if (ModuleClass) {
+ const instance = new ModuleClass();
+ this.registerModule(instance, url);
+ if (instance.init) {
+ await instance.init();
+ }
+ this.terminal.print(`Module loaded successfully from ${url}`, 'success');
+ return true;
+ }
+ } catch (error) {
+ this.terminal.print(`Failed to load module: ${error.message}`, 'error');
+ return false;
+ }
+ }
+ createModuleClass(code, url) {
+ try {
+ const classMatch = code.match(/class\s+(\w+)\s+(extends\s+\S+)?\s*\{/);
+ if (classMatch) {
+ const className = classMatch[1];
+ const mod = new Function('return ' + code + '\nreturn ' + className)();
+ return mod;
+ }
+ throw new Error('No valid module class found');
+ } catch (e) {
+ this.terminal.print(`Module parse error: ${e.message}`, 'error');
+ return null;
+ }
+ }
+ registerModule(instance, url = null) {
+ const name = instance.constructor.name;
+ this.modules[name] = instance;
+ instance.terminal = this.terminal;
+ if (instance.registerCommands) { instance.registerCommands(); }
+ // Only persist modules loaded from absolute URLs (not boot-time ext modules)
+ if (url && url.startsWith('http') && !this.moduleRegistry.find(m => m.name === name)) {
+ this.moduleRegistry.push({
+ name: name, url: url,
+ loaded: new Date().toISOString(), enabled: true
+ });
+ this.saveToStorage();
+ }
+ console.log(`Module registered: ${name}`);
+ }
+ unregisterModule(name) {
+ if (this.modules[name]) {
+ delete this.modules[name];
+ this.moduleRegistry = this.moduleRegistry.filter(m => m.name !== name);
+ this.saveToStorage();
+ return true;
+ }
+ return false;
+ }
+ getModuleList() {
+ const allNames = new Set([...this.moduleRegistry.map(m => m.name), ...Object.keys(this.modules)]);
+ return Array.from(allNames).map(name => ({
+ name,
+ url: (this.moduleRegistry.find(m => m.name === name) || {}).url || null,
+ loaded: this.modules[name] !== undefined
+ }));
+ }
+ clearAll() {
+ this.modules = {};
+ this.moduleRegistry = [];
+ this.saveToStorage();
+ }
+ getModuleRequirements(name) {
+ const mod = this.modules[name];
+ if (mod && typeof mod.requirements === 'function') {
+ return mod.requirements();
+ }
+ return null;
+ }
+ checkAllRequirements() {
+ const results = {};
+ for (const modName in this.modules) {
+ const mod = this.modules[modName];
+ if (typeof mod.requirements === 'function') {
+ results[modName] = mod.requirements();
+ }
+ }
+ return results;
+ }
+ getAllCommands() {
+ const commands = {};
+ for (const modName in this.modules) {
+ const mod = this.modules[modName];
+ if (mod.commands) {
+ for (const cmd in mod.commands) {
+ commands[cmd] = modName;
+ }
+ }
+ }
+ return commands;
+ }
+ getAllHelp() {
+ const help = {};
+ for (const modName in this.modules) {
+ const mod = this.modules[modName];
+ if (typeof mod.getHelpInfo === 'function') {
+ const modHelp = mod.getHelpInfo();
+ if (modHelp) Object.assign(help, modHelp);
+ } else if (mod.commands) {
+ for (const cmd in mod.commands) {
+ if (!help[cmd]) help[cmd] = cmd + ' — (no description)';
+ }
+ }
+ }
+ return help;
+ }
+ }