diff --git a/frontend/src/pages/communities/[slug]/plugins.astro b/frontend/src/pages/communities/[slug]/plugins.astro
index 99e2a4e..44ae7c2 100644
--- a/frontend/src/pages/communities/[slug]/plugins.astro
+++ b/frontend/src/pages/communities/[slug]/plugins.astro
@@ -117,6 +117,277 @@ const { slug } = Astro.params;
return res.json();
}
+ async function fetchPluginPolicy(communityId) {
+ const res = await fetch(`${apiBase}/api/communities/${communityId}/plugin-policy`, {
+ headers: { 'Authorization': `Bearer ${token}` },
+ });
+
+ if (!res.ok) {
+ const err = await res.text();
+ throw new Error(err || 'Failed to load plugin policy');
+ }
+
+ return res.json();
+ }
+
+ async function fetchPluginPackages(communityId) {
+ const res = await fetch(`${apiBase}/api/communities/${communityId}/plugin-packages`, {
+ headers: { 'Authorization': `Bearer ${token}` },
+ });
+
+ if (!res.ok) {
+ const err = await res.text();
+ throw new Error(err || 'Failed to load plugin packages');
+ }
+
+ return res.json();
+ }
+
+ function normalizeStringList(text) {
+ return String(text || '')
+ .split(/\r?\n/)
+ .map(v => v.trim())
+ .filter(v => v.length > 0);
+ }
+
+ function arrayBufferToBase64(buffer) {
+ const bytes = new Uint8Array(buffer);
+ const chunkSize = 0x8000;
+ let binary = '';
+ for (let i = 0; i < bytes.length; i += chunkSize) {
+ const chunk = bytes.subarray(i, i + chunkSize);
+ binary += String.fromCharCode.apply(null, chunk);
+ }
+ return btoa(binary);
+ }
+
+ function renderPolicyEditor(policy) {
+ const trust = policy?.trust_policy || 'signed_only';
+ const installSources = new Set(policy?.install_sources || []);
+ const allowOutbound = !!policy?.allow_outbound_http;
+ const httpAllowlist = (policy?.http_egress_allowlist || []).join('\n');
+ const registryAllowlist = (policy?.registry_allowlist || []).join('\n');
+ const allowBg = !!policy?.allow_background_jobs;
+ const publishers = (policy?.trusted_publishers || []).join('\n');
+
+ return `
+ Plugin Policy
+
No schema defined. Edit raw JSON:
+ +No packages installed.
+Install from registry or upload a WASM bundle.
+${escapeHtml(pkg.description || '')}
+ +No built-in plugins available.
+