Add getRegisteredPlugins, plugin manager panel in test app
This commit is contained in:
13
dist/PluginRegistry.d.ts
vendored
13
dist/PluginRegistry.d.ts
vendored
@@ -114,6 +114,19 @@ export declare class PluginRegistry {
|
|||||||
clearLogs(pluginId?: string): void;
|
clearLogs(pluginId?: string): void;
|
||||||
/** Get the public exports of a loaded plugin. */
|
/** Get the public exports of a loaded plugin. */
|
||||||
getPluginExports(pluginId: string): unknown;
|
getPluginExports(pluginId: string): unknown;
|
||||||
|
/**
|
||||||
|
* Returns metadata for all currently registered plugins.
|
||||||
|
* Useful for displaying a plugin directory / manager UI.
|
||||||
|
*/
|
||||||
|
getRegisteredPlugins(): Array<{
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
commandCount: number;
|
||||||
|
interceptorCount: number;
|
||||||
|
themeCount: number;
|
||||||
|
hasSettings: boolean;
|
||||||
|
}>;
|
||||||
/** Unload the current plugin instance and load a new one in-place. */
|
/** Unload the current plugin instance and load a new one in-place. */
|
||||||
reloadPlugin(pluginId: string, newPlugin: Plugin, newContext: PluginContext): Promise<void>;
|
reloadPlugin(pluginId: string, newPlugin: Plugin, newContext: PluginContext): Promise<void>;
|
||||||
/** Unload all plugins and clear all registry state. */
|
/** Unload all plugins and clear all registry state. */
|
||||||
|
|||||||
2
dist/PluginRegistry.d.ts.map
vendored
2
dist/PluginRegistry.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"PluginRegistry.d.ts","sourceRoot":"","sources":["../src/PluginRegistry.ts"],"names":[],"mappings":"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"}
|
{"version":3,"file":"PluginRegistry.d.ts","sourceRoot":"","sources":["../src/PluginRegistry.ts"],"names":[],"mappings":"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"}
|
||||||
18
dist/PluginRegistry.js
vendored
18
dist/PluginRegistry.js
vendored
@@ -302,6 +302,24 @@ export class PluginRegistry {
|
|||||||
getPluginExports(pluginId) {
|
getPluginExports(pluginId) {
|
||||||
return this.plugins.get(pluginId)?.plugin.exports;
|
return this.plugins.get(pluginId)?.plugin.exports;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Returns metadata for all currently registered plugins.
|
||||||
|
* Useful for displaying a plugin directory / manager UI.
|
||||||
|
*/
|
||||||
|
getRegisteredPlugins() {
|
||||||
|
return Array.from(this.plugins.entries()).map(([id, { plugin }]) => ({
|
||||||
|
id,
|
||||||
|
name: plugin.name ?? id,
|
||||||
|
version: plugin.version ?? '—',
|
||||||
|
commandCount: [...this.commands.values()].filter(c => c.pluginId === id).length,
|
||||||
|
interceptorCount: this.beforeSendInterceptors.filter(i => i.pluginId === id).length +
|
||||||
|
this.receiveInterceptors.filter(i => i.pluginId === id).length,
|
||||||
|
themeCount: [...this.themes.values()].filter(t => t.pluginId === id).length,
|
||||||
|
hasSettings: (this.settingsSchemas.get(id)?.constructor === Object
|
||||||
|
? Object.keys(this.settingsSchemas.get(id)).length > 0
|
||||||
|
: !!this.settingsSchemas.get(id)),
|
||||||
|
}));
|
||||||
|
}
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Hot reload
|
// Hot reload
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
2
dist/PluginRegistry.js.map
vendored
2
dist/PluginRegistry.js.map
vendored
File diff suppressed because one or more lines are too long
@@ -394,6 +394,34 @@ export class PluginRegistry {
|
|||||||
return this.plugins.get(pluginId)?.plugin.exports;
|
return this.plugins.get(pluginId)?.plugin.exports;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns metadata for all currently registered plugins.
|
||||||
|
* Useful for displaying a plugin directory / manager UI.
|
||||||
|
*/
|
||||||
|
getRegisteredPlugins(): Array<{
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
commandCount: number;
|
||||||
|
interceptorCount: number;
|
||||||
|
themeCount: number;
|
||||||
|
hasSettings: boolean;
|
||||||
|
}> {
|
||||||
|
return Array.from(this.plugins.entries()).map(([id, { plugin }]) => ({
|
||||||
|
id,
|
||||||
|
name: plugin.name ?? id,
|
||||||
|
version: plugin.version ?? '—',
|
||||||
|
commandCount: [...this.commands.values()].filter(c => c.pluginId === id).length,
|
||||||
|
interceptorCount:
|
||||||
|
this.beforeSendInterceptors.filter(i => i.pluginId === id).length +
|
||||||
|
this.receiveInterceptors.filter(i => i.pluginId === id).length,
|
||||||
|
themeCount: [...this.themes.values()].filter(t => t.pluginId === id).length,
|
||||||
|
hasSettings: (this.settingsSchemas.get(id)?.constructor === Object
|
||||||
|
? Object.keys(this.settingsSchemas.get(id)!).length > 0
|
||||||
|
: !!this.settingsSchemas.get(id)),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Hot reload
|
// Hot reload
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -40,13 +40,19 @@
|
|||||||
main {
|
main {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
/* left: plugin manager, center: commands+interceptor, right: settings+log */
|
||||||
|
grid-template-columns: 280px 1fr 1fr;
|
||||||
grid-template-rows: 1fr 1fr;
|
grid-template-rows: 1fr 1fr;
|
||||||
gap: 1px;
|
gap: 1px;
|
||||||
background: #0f3460;
|
background: #0f3460;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Plugin manager spans both rows */
|
||||||
|
#panel-manager {
|
||||||
|
grid-row: 1 / 3;
|
||||||
|
}
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
background: #1a1a2e;
|
background: #1a1a2e;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -155,6 +161,55 @@
|
|||||||
|
|
||||||
/* Theme section */
|
/* Theme section */
|
||||||
.theme-row { display: flex; gap: 8px; flex-wrap: wrap; }
|
.theme-row { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||||
|
|
||||||
|
/* Plugin manager cards */
|
||||||
|
.plugin-card {
|
||||||
|
background: #0f3460;
|
||||||
|
border: 1px solid #1e3a6e;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.plugin-card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.plugin-name { font-weight: 700; font-size: 13px; color: #e0e0e0; }
|
||||||
|
.plugin-version { font-size: 10px; color: #7986cb; background: #162250; padding: 1px 6px; border-radius: 8px; }
|
||||||
|
.plugin-badges { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 2px; }
|
||||||
|
.badge {
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 1px 6px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #162250;
|
||||||
|
color: #90caf9;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.badge.green { background: #1a4a2e; color: #4caf50; }
|
||||||
|
.badge.red { background: #4a1a1a; color: #e94560; }
|
||||||
|
.badge.amber { background: #4a3a00; color: #ffb300; }
|
||||||
|
|
||||||
|
.plugin-unload-btn {
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
background: #3a0f20;
|
||||||
|
color: #e94560;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-top: 2px;
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
.plugin-unload-btn:hover { background: #5a1a30; }
|
||||||
|
|
||||||
|
/* Load-plugin section */
|
||||||
|
#load-plugin-row { display: flex; gap: 6px; }
|
||||||
|
#load-plugin-row input { flex: 1; font-size: 11px; }
|
||||||
|
#load-plugin-row button { white-space: nowrap; font-size: 11px; padding: 4px 10px; }
|
||||||
|
|
||||||
|
#no-plugins-msg { color: #555; font-size: 12px; text-align: center; padding: 20px 0; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -164,7 +219,21 @@
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<!-- Top-left: Commands -->
|
<!-- Left: Plugin Manager (spans both rows) -->
|
||||||
|
<div class="panel" id="panel-manager">
|
||||||
|
<div class="panel-header">Plugin Manager</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div style="font-size:11px;color:#7986cb;margin-bottom:2px;">Load plugin from file:</div>
|
||||||
|
<div id="load-plugin-row">
|
||||||
|
<input type="text" id="load-plugin-path" placeholder="/path/to/plugin/index.js" />
|
||||||
|
<button class="primary" id="load-plugin-btn">Load</button>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:10px;font-size:11px;color:#7986cb;margin-bottom:4px;">Registered plugins:</div>
|
||||||
|
<div id="plugin-list"><div id="no-plugins-msg">No plugins loaded</div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Top-center: Commands -->
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<div class="panel-header">Commands</div>
|
<div class="panel-header">Commands</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
@@ -195,7 +264,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Bottom-left: Settings + Theme -->
|
<!-- Bottom-center: Settings + Theme -->
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<div class="panel-header">Settings & Theme</div>
|
<div class="panel-header">Settings & Theme</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
|||||||
@@ -105,7 +105,121 @@
|
|||||||
document.getElementById('status-badge').classList.add('loaded');
|
document.getElementById('status-badge').classList.add('loaded');
|
||||||
addLog('example-plugin loaded successfully', 'success');
|
addLog('example-plugin loaded successfully', 'success');
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Plugin Manager panel
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Renders the plugin directory card list. */
|
||||||
|
function refreshPluginList() {
|
||||||
|
const listEl = document.getElementById('plugin-list');
|
||||||
|
const plugins = registry.getRegisteredPlugins();
|
||||||
|
|
||||||
|
if (!plugins.length) {
|
||||||
|
listEl.innerHTML = '<div id="no-plugins-msg" style="color:#555;font-size:12px;text-align:center;padding:20px 0;">No plugins loaded</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
listEl.innerHTML = plugins.map(p => `
|
||||||
|
<div class="plugin-card" data-id="${p.id}">
|
||||||
|
<div class="plugin-card-header">
|
||||||
|
<span class="plugin-name">${p.name}</span>
|
||||||
|
<span class="plugin-version">v${p.version}</span>
|
||||||
|
</div>
|
||||||
|
<div style="font-size:10px;color:#7986cb;font-family:monospace;">${p.id}</div>
|
||||||
|
<div class="plugin-badges">
|
||||||
|
<span class="badge green">loaded</span>
|
||||||
|
${p.commandCount ? `<span class="badge">${p.commandCount} cmd${p.commandCount !== 1 ? 's' : ''}</span>` : ''}
|
||||||
|
${p.interceptorCount ? `<span class="badge">${p.interceptorCount} interceptor${p.interceptorCount !== 1 ? 's' : ''}</span>` : ''}
|
||||||
|
${p.themeCount ? `<span class="badge amber">${p.themeCount} theme${p.themeCount !== 1 ? 's' : ''}</span>` : ''}
|
||||||
|
${p.hasSettings ? `<span class="badge">has settings</span>` : ''}
|
||||||
|
</div>
|
||||||
|
<button class="plugin-unload-btn" data-id="${p.id}">Unload</button>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
|
||||||
|
listEl.querySelectorAll('.plugin-unload-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', async () => {
|
||||||
|
const id = btn.dataset.id;
|
||||||
|
await registry.unregisterPlugin(id);
|
||||||
|
addLog(`Plugin unloaded: ${id}`, 'warn');
|
||||||
|
refreshPluginList();
|
||||||
|
refreshCommandList();
|
||||||
|
renderSettings();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a plugin from an arbitrary file path entered in the Load input.
|
||||||
|
* Supports CJS modules (same eval pattern as cinny-desktop).
|
||||||
|
* @param {string} filePath
|
||||||
|
*/
|
||||||
|
async function loadPluginFromPath(filePath) {
|
||||||
|
try {
|
||||||
|
const code = fs.readFileSync(filePath, 'utf-8');
|
||||||
|
const m = { exports: {} };
|
||||||
|
// eslint-disable-next-line no-new-func
|
||||||
|
new Function('module', 'exports', code)(m, m.exports);
|
||||||
|
const p = m.exports;
|
||||||
|
|
||||||
|
if (!p || typeof p.onLoad !== 'function') {
|
||||||
|
throw new Error('File does not export a valid plugin (needs an onLoad function)');
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = p.id ?? path.basename(path.dirname(filePath));
|
||||||
|
if (registry.getRegisteredPlugins().some(r => r.id === id)) {
|
||||||
|
throw new Error(`Plugin with id "${id}" is already loaded`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = createPluginContext(
|
||||||
|
{
|
||||||
|
pluginId: id,
|
||||||
|
eventClient: eventEmitter,
|
||||||
|
onNotify: (opts) =>
|
||||||
|
addLog(`[${opts.type?.toUpperCase() ?? 'NOTIFY'}] ${opts.title}: ${opts.body}`, 'info'),
|
||||||
|
},
|
||||||
|
registry
|
||||||
|
);
|
||||||
|
ctx.log = (...args) => {
|
||||||
|
console.log(`[Plugin ${id}]`, ...args);
|
||||||
|
registry.addLog(id, 'log', args);
|
||||||
|
addLog(args.map(String).join(' '), 'log');
|
||||||
|
};
|
||||||
|
|
||||||
|
registry.registerPlugin(id, p, ctx);
|
||||||
|
await p.onLoad(ctx);
|
||||||
|
|
||||||
|
addLog(`Plugin loaded from path: ${id}`, 'success');
|
||||||
|
refreshPluginList();
|
||||||
|
refreshCommandList();
|
||||||
|
renderSettings();
|
||||||
|
} catch (err) {
|
||||||
|
addLog(`Failed to load plugin: ${err.message}`, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('load-plugin-btn').addEventListener('click', () => {
|
||||||
|
const filePath = document.getElementById('load-plugin-path').value.trim();
|
||||||
|
if (!filePath) { addLog('Enter a path to a plugin index.js', 'error'); return; }
|
||||||
|
loadPluginFromPath(filePath);
|
||||||
|
document.getElementById('load-plugin-path').value = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('load-plugin-path').addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Enter') document.getElementById('load-plugin-btn').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
refreshPluginList();
|
||||||
|
|
||||||
// Populate registered command list
|
// Populate registered command list
|
||||||
|
function refreshCommandList() {
|
||||||
|
const cmdListEl = document.getElementById('cmd-list');
|
||||||
|
cmdListEl.innerHTML = registry
|
||||||
|
.getCommands()
|
||||||
|
.map(c => `<li><code>/${c.name}</code> — ${c.command.description ?? ''}</li>`)
|
||||||
|
.join('') || '<li style="color:#555">No commands registered</li>';
|
||||||
|
}
|
||||||
|
|
||||||
const cmdListEl = document.getElementById('cmd-list');
|
const cmdListEl = document.getElementById('cmd-list');
|
||||||
cmdListEl.innerHTML = registry
|
cmdListEl.innerHTML = registry
|
||||||
.getCommands()
|
.getCommands()
|
||||||
|
|||||||
Reference in New Issue
Block a user