Files
hermes-agent-mission-control/prisma/seed.ts
T
sharbelxyzandClaude Opus 4.8 b463027468 Hermy HQ: self-hostable mission-control template for your Hermes agent
A Next.js 16 + Prisma/Postgres dashboard that pairs with a local Hermes
agent over a Postgres message bus: dispatch work, approve side-effecting
actions, browse the agent's memory, and watch it run. Ships with an
agent-onboarding prompt (ONBOARDING.md) so your Hermes can install it for
you step by step. All secrets are env-configured; nothing sensitive is
bundled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 09:33:24 +02:00

308 lines
9.0 KiB
TypeScript

import { PrismaClient } from '@prisma/client'
import * as fs from 'fs'
import * as path from 'path'
const prisma = new PrismaClient()
const DATA_DIR = './data'
function readJson(filename: string): unknown {
const p = path.join(DATA_DIR, filename)
if (!fs.existsSync(p)) { console.warn(`⚠️ Missing: ${filename}`); return null }
return JSON.parse(fs.readFileSync(p, 'utf-8'))
}
function safeDate(val: unknown, fallback = new Date()): Date {
if (!val) return fallback
const d = new Date(val as string)
return isNaN(d.getTime()) ? fallback : d
}
async function seedDrafts() {
const raw = readJson('drafts.json') as any[]
if (!raw) return
console.log(`📝 Seeding ${raw.length} drafts...`)
for (const d of raw) {
const feedback = d.feedback ?? {}
await prisma.draft.upsert({
where: { id: d.id },
update: {},
create: {
id: d.id,
text: d.text ?? '',
title: d.title ?? null,
model: d.model ?? null,
status: d.status ?? 'pending',
type: d.type ?? null,
category: d.category ?? null,
hookType: d.hookType ?? null,
feedbackRating: feedback.rating ?? null,
feedbackReason: feedback.reason ?? null,
viralScore: d.viralScore ?? undefined,
impressionScore: d.impressionScore ?? undefined,
scheduledDate: d.scheduledDate ?? null,
scheduledTime: d.scheduledTime ?? null,
visualUrl: d.visualUrl ?? null,
variantGroup: d.variantGroup ?? null,
postedAt: d.postedAt ? safeDate(d.postedAt) : null,
postedUrl: d.postedUrl ?? null,
tweetUrl: d.tweetUrl ?? null,
tweetId: d.tweetId ?? null,
metrics: d.metrics ?? undefined,
editHistory: d.editHistory ?? [],
createdAt: safeDate(d.createdAt),
updatedAt: safeDate(d.updatedAt),
},
})
}
console.log(` ✅ ${raw.length} drafts done`)
}
async function seedIdeas() {
const raw = readJson('ideas.json') as any[]
if (!raw) return
console.log(`💡 Seeding ${raw.length} ideas...`)
for (const d of raw) {
await prisma.idea.upsert({
where: { id: d.id },
update: {},
create: {
id: d.id,
title: d.title ?? '',
description: d.description ?? null,
category: d.category ?? null,
type: d.type ?? null,
model: d.model ?? null,
status: d.status ?? null,
timestamp: safeDate(d.timestamp),
},
})
}
console.log(` ✅ ${raw.length} ideas done`)
}
async function seedLongformScripts() {
const raw = readJson('longform-scripts.json') as any[]
if (!raw) return
console.log(`📄 Seeding ${raw.length} longform scripts...`)
for (const d of raw) {
await prisma.longformScript.upsert({
where: { id: d.id },
update: {},
create: {
id: d.id,
title: d.title ?? '',
type: d.type ?? null,
status: d.status ?? 'draft',
platform: d.platform ?? null,
platforms: d.platforms ?? undefined,
description: d.description ?? null,
hook: d.hook ?? null,
outline: d.outline ?? null,
fullScript: d.fullScript ?? null,
targetLength: d.targetLength ?? null,
factCheck: d.factCheck ?? undefined,
notes: d.notes ?? null,
createdAt: safeDate(d.createdAt),
updatedAt: safeDate(d.updatedAt),
},
})
}
console.log(` ✅ ${raw.length} longform scripts done`)
}
async function seedYoutubeScripts() {
const raw = readJson('youtube-scripts.json') as any[]
if (!raw) return
console.log(`🎬 Seeding ${raw.length} YouTube scripts...`)
for (const d of raw) {
await prisma.youtubeScript.upsert({
where: { id: d.id },
update: {},
create: {
id: d.id,
title: d.title ?? '',
hook: d.hook ?? null,
storySetup: d.storySetup ?? null,
conflict: d.conflict ?? null,
insight: d.insight ?? null,
cta: d.cta ?? null,
caption: d.caption ?? null,
onScreenText: d.onScreenText ?? null,
hookType: d.hookType ?? null,
funnelStage: d.funnelStage ?? null,
factCheck: d.factCheck ?? undefined,
status: d.status ?? 'draft',
rejectedReason: d.rejectedReason ?? null,
createdAt: safeDate(d.createdAt),
updatedAt: safeDate(d.updatedAt),
},
})
}
console.log(` ✅ ${raw.length} YouTube scripts done`)
}
async function seedYoutubeIdeas() {
const raw = readJson('youtube-ideas.json') as any[]
if (!raw) return
console.log(`🎯 Seeding ${raw.length} YouTube ideas...`)
// Delete and re-insert (no stable IDs in source file)
await prisma.youtubeIdea.deleteMany()
for (const d of raw) {
await prisma.youtubeIdea.create({
data: {
title: d.title ?? '',
hook: d.hook ?? null,
angle: d.angle ?? null,
hookType: d.hookType ?? null,
funnelStage: d.funnelStage ?? null,
status: d.status ?? 'pending',
rejectedReason: d.rejectedReason ?? null,
createdAt: safeDate(d.createdAt),
},
})
}
console.log(` ✅ ${raw.length} YouTube ideas done`)
}
async function seedYoutubeFeedback() {
const raw = readJson('youtube-feedback.json') as any[]
if (!raw) return
console.log(`💬 Seeding ${raw.length} YouTube feedback...`)
await prisma.youtubeFeedback.deleteMany()
for (const d of raw) {
await prisma.youtubeFeedback.create({
data: {
title: d.title ?? '',
reason: d.reason ?? null,
type: d.type ?? null,
date: safeDate(d.date),
},
})
}
console.log(` ✅ ${raw.length} YouTube feedback done`)
}
async function seedTweetMetrics() {
const raw = readJson('tweet-metrics.json') as any[]
if (!raw) return
console.log(`📊 Seeding ${raw.length} tweet metrics...`)
await prisma.tweetMetric.deleteMany()
for (const d of raw) {
await prisma.tweetMetric.create({
data: {
draftId: d.draftId ?? '',
tweetId: d.tweetId ?? null,
url: d.url ?? null,
postedAt: d.postedAt ? safeDate(d.postedAt) : null,
checkpoints: d.checkpoints ?? undefined,
createdAt: safeDate(d.createdAt),
},
})
}
console.log(` ✅ ${raw.length} tweet metrics done`)
}
async function seedAgentState() {
const raw = readJson('agent-state.json') as any[]
if (!raw) return
console.log(`🤖 Seeding ${raw.length} agent states...`)
for (const d of raw) {
await prisma.agentState.upsert({
where: { id: d.id },
update: {
name: d.name,
emoji: d.emoji ?? null,
role: d.role ?? null,
status: d.status ?? 'offline',
lastActive: d.lastActive ? safeDate(d.lastActive) : null,
tasksCompleted: d.tasksCompleted ?? 0,
totalCost: d.totalCost ?? 0,
currentTask: d.currentTask ?? null,
recentActivity: d.recentActivity ?? [],
updatedAt: new Date(),
},
create: {
id: d.id,
name: d.name,
emoji: d.emoji ?? null,
role: d.role ?? null,
status: d.status ?? 'offline',
lastActive: d.lastActive ? safeDate(d.lastActive) : null,
tasksCompleted: d.tasksCompleted ?? 0,
totalCost: d.totalCost ?? 0,
currentTask: d.currentTask ?? null,
recentActivity: d.recentActivity ?? [],
updatedAt: new Date(),
},
})
}
console.log(` ✅ ${raw.length} agent states done`)
}
async function seedContentCalendar() {
const raw = readJson('content-calendar.json') as any
if (!raw) return
// File is { week: "...", days: [...] }
const week = raw.week
if (!week) { console.warn('⚠️ content-calendar.json missing week field'); return }
console.log(`📅 Seeding content calendar (week ${week})...`)
await prisma.contentCalendar.upsert({
where: { week },
update: { data: raw },
create: { week, data: raw },
})
console.log(` ✅ Calendar done`)
}
async function seedContentRequests() {
const raw = readJson('content-requests.json') as any[]
if (!raw || !raw.length) return
console.log(`📬 Seeding ${raw.length} content requests...`)
for (const d of raw) {
await prisma.contentRequest.upsert({
where: { id: d.id },
update: {},
create: {
id: d.id,
prompt: d.prompt ?? '',
status: d.status ?? 'pending',
resultDraftIds: d.resultDraftIds ?? undefined,
createdAt: safeDate(d.createdAt),
completedAt: d.completedAt ? safeDate(d.completedAt) : null,
},
})
}
console.log(` ✅ ${raw.length} content requests done`)
}
async function main() {
console.log('🌱 Starting Max HQ data seed...\n')
await seedAgentState()
await seedDrafts()
await seedIdeas()
await seedLongformScripts()
await seedYoutubeScripts()
await seedYoutubeIdeas()
await seedYoutubeFeedback()
await seedTweetMetrics()
await seedContentCalendar()
await seedContentRequests()
console.log('\n✅ All done! Max HQ database is fully seeded.')
}
main()
.catch((e) => { console.error('❌ Seed failed:', e); process.exit(1) })
.finally(() => prisma.$disconnect())