package plugins import "fmt" // GenerateGuardScript returns a self-contained Node.js guard script that checks // whether the agent is frozen and blocks tool execution if so. // It caches the agent status locally (60s TTL) to avoid hitting the API on every // tool call, and fails open if the API is unreachable or config is missing. func GenerateGuardScript(agentName string, agentID string) string { return generateGuardScript(agentName, agentID, "", false) } func generateGuardScript(agentName, agentID, successOutput string, failClosed bool) string { return fmt.Sprintf(`#!/usr/bin/env node 'use strict'; // --------------------------------------------------------------------------- // Elydora agent guard (PreToolUse) for: %s // Generated by @elydora/sdk — DO NOT EDIT // --------------------------------------------------------------------------- const fs = require('node:fs'); const path = require('node:path'); const os = require('node:os'); const AGENT_NAME = %q; const AGENT_ID = %q; const SUCCESS_OUTPUT = %q; const FAIL_CLOSED = %t; const ELYDORA_DIR = path.join(os.homedir(), '.elydora'); const CONFIG_PATH = path.join(ELYDORA_DIR, AGENT_ID, 'config.json'); const STATUS_CACHE_PATH = path.join(ELYDORA_DIR, AGENT_ID, 'status-cache.json'); const CACHE_TTL_MS = 60000; %s process.stdin.resume(); process.stdin.on('data', () => {}); function blockAgent(status) { const state = status === 'frozen' ? 'is frozen by Elydora' : 'is revoked in Elydora'; process.stderr.write( 'Agent "' + AGENT_NAME + '" ' + state + '. Tool execution blocked.\n', ); process.exitCode = 2; } async function main() { let config; try { config = JSON.parse(readProtectedFile( CONFIG_PATH, 'Agent config', MAX_PROTECTED_CONFIG_BYTES, ).toString('utf-8')); } catch (err) { if (FAIL_CLOSED) { throw new Error('Failed to read agent config: ' + err.message); } process.stderr.write('[Elydora guard] Failed to read agent config: ' + err.message + '\n'); return; } try { const raw = fs.readFileSync(STATUS_CACHE_PATH, 'utf-8'); const cache = JSON.parse(raw); const age = Date.now() - (cache.cached_at || 0); if (age < CACHE_TTL_MS) { if (!['active', 'frozen', 'revoked'].includes(cache.status)) { throw new Error('Status cache contains an invalid status'); } if (cache.status !== 'active') { blockAgent(cache.status); } return; } } catch (err) { if (err.code !== 'ENOENT') { if (FAIL_CLOSED) { throw new Error('Failed to read status cache: ' + err.message); } process.stderr.write('[Elydora guard] Failed to read status cache: ' + err.message + '\n'); } } const baseURL = (config.base_url || 'https://api.elydora.com').replace(/\/+$/, ''); const token = config.token || ''; const agentID = config.agent_id; const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 3000); try { const headers = { 'Accept': 'application/json' }; if (token) { headers['Authorization'] = 'Bearer ' + token; } const response = await fetch(baseURL + '/v1/agents/' + encodeURIComponent(agentID), { headers: headers, signal: controller.signal, }); if (!response.ok) { throw new Error('Agent status API returned HTTP ' + response.status); } const data = await response.json(); const status = data.agent && data.agent.status; if (!['active', 'frozen', 'revoked'].includes(status)) { throw new Error('Agent status API returned an invalid status'); } try { fs.writeFileSync(STATUS_CACHE_PATH, JSON.stringify({ status: status, cached_at: Date.now(), }), 'utf-8'); } catch (err) { process.stderr.write('[Elydora guard] Failed to update status cache: ' + err.message + '\n'); } if (status !== 'active') { blockAgent(status); } } catch (err) { if (FAIL_CLOSED) { throw new Error('Failed to resolve agent status: ' + err.message); } process.stderr.write('[Elydora guard] Failed to resolve agent status: ' + err.message + '\n'); } finally { clearTimeout(timeout); } } main().then(() => { if ((!process.exitCode || process.exitCode === 0) && SUCCESS_OUTPUT) { process.stdout.write(SUCCESS_OUTPUT); } }).catch((err) => { process.stderr.write('[Elydora guard] ' + (err.stack || err.message || String(err)) + '\n'); process.exitCode = 1; }); `, agentName, agentName, agentID, successOutput, failClosed, protectedRuntimeFileReader) }