class WpmModule { constructor() { this.commands = {}; this.terminal = null; this.indexUrl = 'https://webx11.duckdns.org/spaces/newos4/packages.json'; this.index = null; this.installed = this.loadInstalled(); } getHelpInfo() { return { 'wpm': 'wpm [...] — Web Package Manager for installing and managing modules' }; } loadInstalled() { try { const data = localStorage.getItem('webx11_wpm_installed'); return data ? JSON.parse(data) : {}; } catch (e) { return {}; } } saveInstalled() { localStorage.setItem('webx11_wpm_installed', JSON.stringify(this.installed)); } registerCommands() { this.commands['wpm'] = (args) => this.handle(args); } handle(args) { if (!args[0]) return this.terminal.print('Usage: wpm install , wpm list, wpm search , wpm update, wpm remove , wpm info ', 'warning'); const sub = args[0].toLowerCase(); if (sub === 'install') this.install(args[1]); else if (sub === 'list') this.list(); else if (sub === 'search') this.search(args.slice(1).join(' ')); else if (sub === 'update') this.update(); else if (sub === 'remove') this.remove(args[1]); else if (sub === 'info') this.info(args[1]); else this.terminal.print(`Unknown: ${sub}`, 'error'); } async loadIndex() { if (this.index) return this.index; try { this.terminal.print('Fetching package index...', 'info'); const res = await fetch(this.indexUrl); if (!res.ok) throw new Error('HTTP ' + res.status); this.index = await res.json(); return this.index; } catch (e) { this.terminal.print(`Failed to load index: ${e.message}`, 'error'); return null; } } async install(name) { if (!name) return this.terminal.print('Usage: wpm install ', 'warning'); const idx = await this.loadIndex(); if (!idx) return; const pkg = idx.packages[name]; if (!pkg) return this.terminal.print(`Package "${name}" not found. Try: wpm search `, 'error'); if (this.installed[name]) return this.terminal.print(`Package "${name}" already installed. Use wpm update to reinstall.`, 'warning'); this.terminal.print(`Installing ${pkg.name} v${pkg.version}...`, 'info'); this.terminal.print(` ${pkg.desc}`, 'info'); const success = await this.terminal.moduleManager.loadModuleFromURL(pkg.url); if (success) { this.installed[name] = { version: pkg.version, installed: new Date().toISOString() }; this.saveInstalled(); this.terminal.print(`"${name}" installed successfully!`, 'success'); } } async list() { const idx = await this.loadIndex(); if (!idx) return; const names = Object.keys(this.installed); this.terminal.print('=== Installed Packages ===', 'info'); if (names.length === 0) { this.terminal.print(' None. Use: wpm install ', 'info'); } else { names.forEach(name => { const inst = this.installed[name]; this.terminal.print(` ${name} v${inst.version} (${inst.installed.split('T')[0]})`); }); } this.terminal.print('\n=== Available Packages ===', 'info'); Object.keys(idx.packages).sort().forEach(name => { const pkg = idx.packages[name]; const installed = this.installed[name] ? ' ✅' : ''; this.terminal.print(` ${name} - ${pkg.desc}${installed}`); }); } async search(keyword) { if (!keyword) return this.terminal.print('Usage: wpm search ', 'warning'); const idx = await this.loadIndex(); if (!idx) return; const kw = keyword.toLowerCase(); const results = []; Object.entries(idx.packages).forEach(([name, pkg]) => { if (name.includes(kw) || pkg.desc.toLowerCase().includes(kw) || pkg.category.toLowerCase().includes(kw)) { results.push({ name, ...pkg }); } }); if (results.length === 0) return this.terminal.print(`No packages matching "${keyword}"`, 'info'); this.terminal.print(`=== Search: "${keyword}" (${results.length} results) ===`, 'info'); results.forEach(r => { const installed = this.installed[r.name] ? ' [installed]' : ''; this.terminal.print(` ${r.name} [${r.category}] - ${r.desc}${installed}`); }); this.terminal.print('Use: wpm install to install', 'info'); } async update() { this.index = null; await this.loadIndex(); if (!this.index) return; this.terminal.print('Index refreshed.', 'success'); const outdated = []; Object.keys(this.installed).forEach(name => { const pkg = this.index.packages[name]; if (pkg && pkg.version !== this.installed[name].version) { outdated.push(name); } }); if (outdated.length > 0) { this.terminal.print(`Outdated packages: ${outdated.join(', ')}. Reinstall with "wpm install "`, 'warning'); } } async remove(name) { if (!name) return this.terminal.print('Usage: wpm remove ', 'warning'); if (!this.installed[name]) return this.terminal.print(`Package "${name}" is not installed via wpm`, 'warning'); const idx = await this.loadIndex(); const className = idx && idx.packages[name] ? idx.packages[name].name.replace(/\s+/g, '') + 'Module' : null; if (className && this.terminal.moduleManager.unregisterModule(className)) { this.terminal.print(`Module ${className} unregistered`, 'info'); } delete this.installed[name]; this.saveInstalled(); this.terminal.print(`Package "${name}" removed. If module persists, use: removemod `, 'success'); } async info(name) { if (!name) return this.terminal.print('Usage: wpm info ', 'warning'); const idx = await this.loadIndex(); if (!idx) return; const pkg = idx.packages[name]; if (!pkg) return this.terminal.print(`Package "${name}" not found`, 'error'); this.terminal.print(`=== ${pkg.name} v${pkg.version} ===`, 'info'); this.terminal.print(`Description: ${pkg.desc}`); this.terminal.print(`Category: ${pkg.category}`); this.terminal.print(`Commands: ${pkg.commands.join(', ')}`); this.terminal.print(`URL: ${pkg.url}`); const installed = this.installed[name]; if (installed) this.terminal.print(`Installed: ${installed.installed}`, 'success'); else this.terminal.print('Not installed. Use: wpm install ' + name, 'info'); } } if (typeof window.webx11 !== 'undefined' && window.webx11) { webx11.moduleManager.registerModule(new WpmModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/wpm.js'); }