BMHQ Upgrade: Add Auto-Run, Execution Logs, Change Log, Brainown panels
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
interface ChangeLogEntry {
|
||||
id: string;
|
||||
date: string;
|
||||
agent: string;
|
||||
type: string;
|
||||
description: string;
|
||||
version?: string;
|
||||
}
|
||||
|
||||
const TYPE_ICONS: Record<string, string> = {
|
||||
skill_update: "🧠",
|
||||
template_change: "📝",
|
||||
new_feature: "✨",
|
||||
bug_fix: "🐛"
|
||||
};
|
||||
|
||||
const TYPE_COLORS: Record<string, string> = {
|
||||
skill_update: "#8b5cf6",
|
||||
template_change: "#ec4899",
|
||||
new_feature: "#10b981",
|
||||
bug_fix: "#ef4444"
|
||||
};
|
||||
|
||||
const AGENT_NAMES: Record<string, string> = {
|
||||
thoth: "Thoth",
|
||||
"thoth-trading": "Thoth Trading",
|
||||
ptah: "Ptah",
|
||||
seshat: "Seshat",
|
||||
anubis: "Anubis",
|
||||
sekhmet: "Sekhmet",
|
||||
horus: "Horus"
|
||||
};
|
||||
|
||||
export default function ChangeLogPanel() {
|
||||
const [entries, setEntries] = useState<ChangeLogEntry[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [showAdd, setShowAdd] = useState(false);
|
||||
const [newEntry, setNewEntry] = useState({
|
||||
agent: "horus",
|
||||
type: "new_feature",
|
||||
description: "",
|
||||
version: ""
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
fetchChangelog();
|
||||
}, []);
|
||||
|
||||
const fetchChangelog = async () => {
|
||||
const res = await fetch("/api/changelog?limit=50");
|
||||
const data = await res.json();
|
||||
setEntries(data);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const addEntry = async () => {
|
||||
if (!newEntry.description.trim()) return;
|
||||
|
||||
await fetch("/api/changelog", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
action: "add",
|
||||
entry: newEntry
|
||||
})
|
||||
});
|
||||
|
||||
setNewEntry({ agent: "horus", type: "new_feature", description: "", version: "" });
|
||||
setShowAdd(false);
|
||||
fetchChangelog();
|
||||
};
|
||||
|
||||
const deleteEntry = async (entryId: string) => {
|
||||
if (!confirm("Delete this entry?")) return;
|
||||
|
||||
await fetch("/api/changelog", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ action: "delete", entryId })
|
||||
});
|
||||
|
||||
fetchChangelog();
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <div className="p-4 text-white/50">Loading changelog...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex justify-between items-center">
|
||||
<h3 className="text-lg font-semibold">📝 Change Log</h3>
|
||||
<button
|
||||
onClick={() => setShowAdd(!showAdd)}
|
||||
className="px-3 py-1 bg-brand-pink hover:bg-[#ff7bc0] rounded text-sm font-medium"
|
||||
>
|
||||
{showAdd ? "✕ Cancel" : "+ Add Entry"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Add Entry Form */}
|
||||
{showAdd && (
|
||||
<div className="p-4 bg-white/10 rounded-lg space-y-3">
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<select
|
||||
value={newEntry.agent}
|
||||
onChange={(e) => setNewEntry({ ...newEntry, agent: e.target.value })}
|
||||
className="bg-black/30 border border-white/20 rounded px-3 py-2 text-white"
|
||||
>
|
||||
{Object.entries(AGENT_NAMES).map(([id, name]) => (
|
||||
<option key={id} value={id}>{name}</option>
|
||||
))}
|
||||
</select>
|
||||
<select
|
||||
value={newEntry.type}
|
||||
onChange={(e) => setNewEntry({ ...newEntry, type: e.target.value })}
|
||||
className="bg-black/30 border border-white/20 rounded px-3 py-2 text-white"
|
||||
>
|
||||
<option value="new_feature">✨ New Feature</option>
|
||||
<option value="skill_update">🧠 Skill Update</option>
|
||||
<option value="template_change">📝 Template Change</option>
|
||||
<option value="bug_fix">🐛 Bug Fix</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
value={newEntry.version}
|
||||
onChange={(e) => setNewEntry({ ...newEntry, version: e.target.value })}
|
||||
placeholder="Version (optional, e.g., v2.0)"
|
||||
className="w-full bg-black/30 border border-white/20 rounded px-3 py-2 text-white placeholder-white/50"
|
||||
/>
|
||||
|
||||
<textarea
|
||||
value={newEntry.description}
|
||||
onChange={(e) => setNewEntry({ ...newEntry, description: e.target.value })}
|
||||
placeholder="What changed?"
|
||||
rows={3}
|
||||
className="w-full bg-black/30 border border-white/20 rounded px-3 py-2 text-white placeholder-white/50"
|
||||
/>
|
||||
|
||||
<button
|
||||
onClick={addEntry}
|
||||
className="w-full py-2 bg-green-600 hover:bg-green-700 rounded font-medium"
|
||||
>
|
||||
Save Entry
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Entries List */}
|
||||
<div className="space-y-3 max-h-[500px] overflow-y-auto">
|
||||
{entries.map((entry) => (
|
||||
<div
|
||||
key={entry.id}
|
||||
className="p-3 bg-white/5 rounded-lg border border-white/10"
|
||||
>
|
||||
<div className="flex justify-between items-start">
|
||||
<div className="flex items-center gap-2">
|
||||
<span
|
||||
className="px-2 py-0.5 rounded text-xs"
|
||||
style={{ backgroundColor: TYPE_COLORS[entry.type] || "#666" }}
|
||||
>
|
||||
{TYPE_ICONS[entry.type] || "📌"} {entry.type.replace("_", " ")}
|
||||
</span>
|
||||
<span className="text-white/50 text-xs">
|
||||
{new Date(entry.date).toLocaleDateString()}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => deleteEntry(entry.id)}
|
||||
className="text-white/30 hover:text-red-400 text-xs"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p className="mt-2 text-white/90">{entry.description}</p>
|
||||
|
||||
<div className="flex gap-3 mt-2 text-xs text-white/50">
|
||||
<span>{AGENT_NAMES[entry.agent] || entry.agent}</span>
|
||||
{entry.version && <span>v{entry.version}</span>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{entries.length === 0 && (
|
||||
<div className="text-center py-8 text-white/50">
|
||||
No changes recorded yet. Add an entry to track agent improvements.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user