/** * Example plugin — demonstrates every PluginContext API surface. * Loaded as CommonJS by the test harness (eval'd via new Function). */ module.exports = { name: 'Example Plugin', version: '1.0.0', /** @param {import('@paarrot/plugin-manager').PluginContext} ctx */ onLoad(ctx) { // ------------------------------------------------------------------------- // Settings — persisted to storage automatically // ------------------------------------------------------------------------- ctx.settings.define({ greeting: { type: 'string', label: 'Greeting word', default: 'Hello', }, autoExpand: { type: 'boolean', label: 'Auto-expand abbreviations (brb, omw, afk)', default: true, }, logLevel: { type: 'select', label: 'Log verbosity', default: 'normal', options: [ { value: 'quiet', label: 'Quiet' }, { value: 'normal', label: 'Normal' }, { value: 'verbose', label: 'Verbose' }, ], }, }); // ------------------------------------------------------------------------- // Commands // ------------------------------------------------------------------------- ctx.commands.register({ name: 'hello', description: 'Greet someone', args: [{ name: 'name', type: 'string', required: false, description: 'Who to greet' }], run(args) { const greeting = ctx.settings.get('greeting') ?? 'Hello'; return `${greeting}, ${args.name || 'World'}!`; }, }); ctx.commands.register({ name: 'echo', description: 'Echo text back', args: [{ name: 'text', type: 'string', description: 'Text to echo' }], run: (args) => args.text || '(nothing)', }); ctx.commands.register({ name: 'roll', description: 'Roll a dice — /roll ', args: [{ name: 'sides', type: 'number', description: 'Number of sides (default 6)' }], run(args) { const sides = parseInt(args.sides, 10) || 6; const result = Math.floor(Math.random() * sides) + 1; return `Rolled a d${sides}: ${result}`; }, }); ctx.commands.register({ name: 'setting', description: 'Read a plugin setting — /setting ', args: [{ name: 'key', type: 'string' }], run(args) { const val = ctx.settings.get(args.key); return val !== undefined ? `${args.key} = ${JSON.stringify(val)}` : `Setting "${args.key}" not found`; }, }); // ------------------------------------------------------------------------- // Message interceptors // ------------------------------------------------------------------------- ctx.messages.onBeforeSend((msg) => { if (!ctx.settings.get('autoExpand')) return; msg.content = msg.content .replace(/\bbrb\b/gi, 'be right back') .replace(/\bomw\b/gi, 'on my way') .replace(/\bafk\b/gi, 'away from keyboard'); if (ctx.settings.get('logLevel') === 'verbose') { ctx.log('beforeSend interceptor ran'); } }); ctx.messages.onReceive((msg) => { if (ctx.settings.get('logLevel') !== 'quiet') { ctx.log(`Received message in ${msg.roomId}: "${msg.content.slice(0, 40)}"`); } }); // ------------------------------------------------------------------------- // Theme — Ocean Blue dark palette // ------------------------------------------------------------------------- ctx.themes.register({ id: 'ocean', name: 'Ocean Blue', kind: 'dark', colors: { background: { container: '#0d1b2a', containerHover: '#1b2d42', containerActive: '#243856', containerLine: '#1e3a5f', onContainer: '#c9d6e3', }, surface: { container: '#112233', containerHover: '#1a3344', containerActive: '#224455', containerLine: '#1e3a5f', onContainer: '#d0dde8', }, surfaceVariant: { container: '#162840', containerHover: '#1f3555', containerActive: '#28426a', containerLine: '#2a4a70', onContainer: '#b8cfe0', }, primary: { main: '#0077b6', mainHover: '#0096c7', mainActive: '#00b4d8', mainLine: '#0077b6', onMain: '#ffffff', container: '#023e8a', containerHover: '#0d47a1', containerActive: '#1565c0', containerLine: '#0d47a1', onContainer: '#90e0ef', }, secondary: { main: '#48cae4', mainHover: '#00b4d8', mainActive: '#0096c7', mainLine: '#48cae4', onMain: '#000000', container: '#0d6986', containerHover: '#0e7fa0', containerActive: '#0f95bb', containerLine: '#0d6986', onContainer: '#caf0f8', }, success: { main: '#00b894', mainHover: '#00cca3', mainActive: '#00dfb2', mainLine: '#00b894', onMain: '#000000', container: '#007a65', containerHover: '#009478', containerActive: '#00ae8b', containerLine: '#007a65', onContainer: '#b2f0e8', }, warning: { main: '#f39c12', mainHover: '#f5a623', mainActive: '#f7b733', mainLine: '#f39c12', onMain: '#000000', container: '#a66c00', containerHover: '#bf7c00', containerActive: '#d98c00', containerLine: '#a66c00', onContainer: '#fde9b2', }, critical: { main: '#e74c3c', mainHover: '#ec5f50', mainActive: '#f17264', mainLine: '#e74c3c', onMain: '#ffffff', container: '#9c1e12', containerHover: '#b52316', containerActive: '#ce281a', containerLine: '#9c1e12', onContainer: '#fcd4d0', }, other: { focusRing: '#0096c7', shadow: 'rgba(0,0,0,0.5)', overlay: 'rgba(0,0,0,0.6)', }, }, extraCss: ` body.plugin-example-plugin-ocean { background: #0d1b2a; color: #c9d6e3; } `, }); // ------------------------------------------------------------------------- // Events — listen on the injected event client // ------------------------------------------------------------------------- ctx.events.on('test-event', (data) => { ctx.log(`test-event received: ${JSON.stringify(data)}`); }); // ------------------------------------------------------------------------- // Timers — heartbeat every 30 s // ------------------------------------------------------------------------- ctx.timers.setInterval(() => { if (ctx.settings.get('logLevel') === 'verbose') { ctx.log('Heartbeat tick'); } }, 30_000); // ------------------------------------------------------------------------- // Notify on load // ------------------------------------------------------------------------- ctx.notify({ title: 'Example Plugin', body: 'Loaded successfully! Try a /command below.', type: 'success', }); }, onUnload() { // Timers, event handlers, and themes are cleaned up automatically by the registry. }, /** Public API — accessible by other plugins via ctx.require('example-plugin') */ exports: { version: '1.0.0', greet: (name) => `Hi from Example Plugin, ${name}!`, }, };