Files
sitemente/app/api/memory/list/route.ts
T
horus 45af56d9cf feat(mission-control): restore MC tabs - temple, office, memory, claude, pdf-viewer, resume, resume-upload, temple-3d, demos
Also added:
- Memory API endpoints
- Briefs API endpoints
- AnveVoice stats API
- Claude spawn API
- TTS proxy
- Cleopatra voice widget
- api-auth middleware
2026-03-23 16:30:44 +01:00

142 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { NextResponse } from 'next/server';
import * as fs from 'fs';
import * as path from 'path';
const API_SECRET = process.env.API_SECRET || 'horus-mc-secret-2026';
function checkAuth(request: Request): boolean {
const authHeader = request.headers.get('authorization');
return authHeader === `Bearer ${API_SECRET}`;
}
const MAIN_AGENTS = ["horus", "cleopatra", "amun"];
const AGENTS = [
{ id: "horus", name: "Horus", icon: "👁️", color: "#3b82f6" },
{ id: "cleopatra", name: "Cleopatra", icon: "👸", color: "#a855f7" },
{ id: "amun", name: "Amun", icon: "👑", color: "#f59e0b" },
{ id: "anubis", name: "Anubis", icon: "🐕", color: "#22c55e" },
{ id: "thoth", name: "Thoth", icon: "📚", color: "#06b6d4" },
{ id: "ptah", name: "Ptah", icon: "🎨", color: "#f97316" },
{ id: "seshat", name: "Seshat", icon: "📝", color: "#ec4899" },
{ id: "hathor", name: "Hathor", icon: "💕", color: "#ef4444" },
{ id: "sekhmet", name: "Sekhmet", icon: "⚔️", color: "#94a3b8" },
{ id: "maat", name: "Maat", icon: "⚖️", color: "#64748b" },
];
interface AgentInfo {
id: string;
name: string;
icon: string;
color: string;
}
function getAgentInfo(agentName: string): AgentInfo {
const lower = agentName.toLowerCase();
const found = AGENTS.find(a => lower.includes(a.id) || lower.includes(a.name.toLowerCase()));
return found || { id: "unknown", name: agentName, icon: "🤖", color: "#64748b" };
}
export async function GET(request: Request) {
// Check auth
if (!checkAuth(request)) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
try {
const memoryDir = '/root/.openclaw/workspace/memory';
const briefsMorningDir = '/root/.openclaw/workspace/briefs/morning';
const briefsEodDir = '/root/.openclaw/workspace/briefs/eod';
const files = fs.readdirSync(memoryDir)
.filter(f => f.endsWith('.md'))
.filter(f => /^\d{4}-\d{2}-\d{2}$/.test(f.replace('.md', '')));
const days: any[] = [];
const allTags: string[] = [];
for (const file of files) {
const date = file.replace('.md', '');
const filePath = path.join(memoryDir, file);
const content = fs.readFileSync(filePath, 'utf8');
const entries: any[] = [];
const lines = content.split('\n');
let currentEntry: any = null;
for (const line of lines) {
const agentMatch = line.match(/^##\s*(\w+)\s*[-]\s*(\d{2}:\d{2})/);
if (agentMatch) {
if (currentEntry?.content?.trim()) {
entries.push(currentEntry);
}
const agentInfo = getAgentInfo(agentMatch[1]);
currentEntry = {
agent: agentInfo.name,
agentIcon: agentInfo.icon,
agentColor: agentInfo.color,
time: agentMatch[2],
content: '',
tags: [],
isMainAgent: MAIN_AGENTS.includes(agentInfo.id),
};
} else if (currentEntry) {
const trimmed = line.trim();
if (!trimmed) continue;
const standaloneTagsMatch = trimmed.match(/^\[Tags:\s*(.+?)\]$/);
if (standaloneTagsMatch) {
const tags = standaloneTagsMatch[1]
.split(',')
.map((t: string) => t.trim().replace(/^#/, '').trim())
.filter(Boolean);
currentEntry.tags = [...new Set([...currentEntry.tags, ...tags])];
tags.forEach((t: string) => {
if (!allTags.includes(t)) allTags.push(t);
});
} else {
const inlineTagsMatch = trimmed.match(/\[Tags:\s*(.+?)\]/);
if (inlineTagsMatch) {
const tags = inlineTagsMatch[1]
.split(',')
.map((t: string) => t.trim().replace(/^#/, '').trim())
.filter(Boolean);
currentEntry.tags = [...new Set([...currentEntry.tags, ...tags])];
tags.forEach((t: string) => {
if (!allTags.includes(t)) allTags.push(t);
});
}
const cleanLine = trimmed.replace(/\[Tags:.*?\]/g, '').trim();
if (cleanLine) {
currentEntry.content += (currentEntry.content ? '\n' : '') + cleanLine;
}
}
}
}
if (currentEntry?.content?.trim()) {
entries.push(currentEntry);
}
const hasMorning = fs.existsSync(path.join(briefsMorningDir, `${date}.md`));
const hasEod = fs.existsSync(path.join(briefsEodDir, `${date}.md`));
days.push({
date,
entries,
hasBriefs: { morning: hasMorning, eod: hasEod },
});
}
days.sort((a, b) => b.date.localeCompare(a.date));
return NextResponse.json({
days,
allTags,
totalDays: days.length,
});
} catch (error) {
console.error('Memory list error:', error);
return NextResponse.json({ days: [], allTags: [], error: 'Failed to load memory' }, { status: 500 });
}
}