// persona-server.js — Persona Sidecar v0.1.0 (Docker Lyra) // Node 18+, Express REST import express from "express"; import fs from "fs"; const app = express(); app.use(express.json()); const PORT = process.env.PORT || 7080; const CONFIG_FILE = process.env.PERSONAS_FILE || "./personas.json"; // allow JSON with // and /* */ comments function parseJsonWithComments(raw) { return JSON.parse( raw .replace(/\/\*[\s\S]*?\*\//g, "") // block comments .replace(/^\s*\/\/.*$/gm, "") // line comments ); } function loadConfig() { const raw = fs.readFileSync(CONFIG_FILE, "utf-8"); return parseJsonWithComments(raw); } function saveConfig(cfg) { fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2)); } // GET /persona → active persona JSON app.get("/persona", (_req, res) => { try { const cfg = loadConfig(); const active = cfg.active; const persona = cfg.personas?.[active]; if (!persona) return res.status(404).json({ error: "Active persona not found" }); res.json({ active, persona }); } catch (err) { res.status(500).json({ error: String(err.message || err) }); } }); // GET /personas → all personas app.get("/personas", (_req, res) => { try { const cfg = loadConfig(); res.json(cfg.personas || {}); } catch (err) { res.status(500).json({ error: String(err.message || err) }); } }); // POST /persona/select { name } app.post("/persona/select", (req, res) => { try { const { name } = req.body || {}; if (!name) return res.status(400).json({ error: "Missing 'name'" }); const cfg = loadConfig(); if (!cfg.personas || !cfg.personas[name]) { return res.status(404).json({ error: `Persona '${name}' not found` }); } cfg.active = name; saveConfig(cfg); res.json({ ok: true, active: name }); } catch (err) { res.status(500).json({ error: String(err.message || err) }); } }); // health + fallback app.get("/_health", (_req, res) => res.json({ ok: true, time: new Date().toISOString() })); app.use((_req, res) => res.status(404).json({ error: "no such route" })); app.listen(PORT, () => { console.log(`Persona Sidecar listening on :${PORT}`); });