From 5920055473568a12387335c6f272e509665a2962 Mon Sep 17 00:00:00 2001 From: ReaperOfVeriod Date: Sun, 25 Oct 2026 06:25:02 +0100 Subject: [PATCH] Expose plugin runtime action --- src/App.svelte | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/App.svelte b/src/App.svelte index 7bceed7..ee14117 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1188,6 +1188,20 @@ } } + async function runPlugin(plugin: (typeof plugins)[number]) { + pluginBusy = true; + pluginError = ''; + try { + const response = await fetch(`${serverAddress}/api/v1/admin/plugins/${encodeURIComponent(plugin.plugin_id)}/run`, { method: 'POST', headers: { authorization: `Bearer ${sessionToken}` } }); + if (!response.ok) throw new Error('The plugin execution failed or the plugin is disabled.'); + pluginError = `${plugin.name} executed successfully.`; + } catch (error) { + pluginError = error instanceof Error ? error.message : 'The plugin execution failed.'; + } finally { + pluginBusy = false; + } + } + async function removePlugin(plugin: (typeof plugins)[number]) { if (!window.confirm(`Remove plugin ${plugin.name}?`)) return; pluginBusy = true; @@ -1532,6 +1546,7 @@ {:else if activeView === 'Plugins'}
WEBASSEMBLY PLUGINS

Packages are validated and started in a resource-limited WebAssembly runtime. Only explicitly declared Trixie permissions are accepted; installation never grants filesystem or process access.

{#if pluginError}
{pluginError}
{/if}{#if plugins.length}
{#each plugins as plugin}
{plugin.name}{plugin.plugin_id} · v{plugin.version}
API {plugin.manifest.api_version} · {plugin.manifest.permissions.length ? plugin.manifest.permissions.join(' · ') : 'NO PERMISSIONS'}
{plugin.enabled ? 'ENABLED' : 'DISABLED'}
{/each}
{:else}
No plugins are installed.
{/if}
PLUGIN SECRET APPROVAL

Plugins cannot read secrets until an administrator explicitly approves a binding. The secret value is never shown here.

{#if plugins.some((plugin) => plugin.manifest.required_secrets?.length)}
{#each plugins.filter((plugin) => plugin.manifest.required_secrets?.length) as plugin}
{plugin.name}Required: {plugin.manifest.required_secrets?.join(' · ')}
{/each}
{:else}
Installed plugins have no secret requirements.
{/if}
+
PLUGIN RUNTIME

Run only enabled packages. The server applies the manifest permissions and WebAssembly resource limits.

{#if plugins.length}{#each plugins as plugin}
{plugin.name}{plugin.enabled ? 'READY' : 'DISABLED'}
{/each}{:else}
No installed plugins.
{/if}
{:else if activeView === 'Bot'}
{commandFormId ? 'EDIT COMMAND' : 'NEW COMMAND'}
{#if commandVariableSuggestions.length}
{#each commandVariableSuggestions as variable}{/each}
{/if}
SIMULATION

Preview with literal sample data. Real requests are opt-in and use the same server-side safety checks.

{#if commandSimulationError}
{commandSimulationError}
{/if}{#if commandSimulationResult}
{commandSimulationResult.rendered ?? commandSimulationResult.error ?? 'Simulation completed.'}{#if commandSimulationResult.extracted_variables && Object.keys(commandSimulationResult.extracted_variables).length}Extracted: {formatExtractedVariables(commandSimulationResult.extracted_variables)}{/if}
{/if}
BOT COMMANDS
PUBLIC COMMAND CATALOG
{#if botCommandError}
{botCommandError}
{:else if botCommands.length}
{#each botCommands as command}
!{command.name}{command.description}{#if command.tags.length}
{command.tags.join(' · ')}
{/if}
{command.permission_level.toUpperCase()}{#if command.cooldown_seconds}{command.cooldown_seconds}s / {command.cooldown_scope}{/if}
{/each}
{:else}
No enabled commandsCreate commands on the server to make them available here.
{/if}
SECRETS MANAGEMENT
Values are encrypted and cannot be read after saving.
{#if botSecrets.length}
{#each botSecrets as secret}
{secret.name}{secret.description || 'No description'}{#if secret.used_by.length}
USED BY: {secret.used_by.join(', ')}
{/if}
{/each}
{:else}
There are no secrets yet.
{/if}{#if secretError}
{secretError}
{/if}