Initial clean commit - unified Lyra stack
This commit is contained in:
14
core/persona-sidecar/Dockerfile
Normal file
14
core/persona-sidecar/Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
||||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# install deps
|
||||
COPY package.json ./package.json
|
||||
RUN npm install --production
|
||||
|
||||
# copy code + config
|
||||
COPY persona-server.js ./persona-server.js
|
||||
COPY personas.json ./personas.json
|
||||
|
||||
EXPOSE 7080
|
||||
CMD ["node", "persona-server.js"]
|
||||
8
core/persona-sidecar/package.json
Normal file
8
core/persona-sidecar/package.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "persona-sidecar",
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"express": "^4.19.2"
|
||||
}
|
||||
}
|
||||
78
core/persona-sidecar/persona-server.js
Normal file
78
core/persona-sidecar/persona-server.js
Normal file
@@ -0,0 +1,78 @@
|
||||
// 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}`);
|
||||
});
|
||||
17
core/persona-sidecar/personas.json
Normal file
17
core/persona-sidecar/personas.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
// v0.1.0 default active persona
|
||||
"active": "Lyra",
|
||||
|
||||
// Personas available to the service
|
||||
"personas": {
|
||||
"Lyra": {
|
||||
"name": "Lyra",
|
||||
"style": "warm, slyly supportive, collaborative confidante",
|
||||
"protocols": ["Project logs", "Confidence Bank", "Scar Notes"]
|
||||
}
|
||||
}
|
||||
|
||||
// Placeholders for later (commented out for now)
|
||||
// "Doyle": { "name": "Doyle", "style": "gritty poker grinder", "protocols": [] },
|
||||
// "Mr GPT": { "name": "Mr GPT", "style": "direct, tactical mentor", "protocols": [] }
|
||||
}
|
||||
Reference in New Issue
Block a user