import type { CharacterArcNode } from '../../shared/arc' import { KnowledgeRepository } from '../db/repositories/knowledge.repo' import { SettingRepository } from '../db/repositories/setting.repo' import { ChapterRepository } from '../db/repositories/chapter.repo' import type { SqliteDb } from '../db/types' export class ArcService { constructor(private db: SqliteDb) {} getForCharacter(settingId: string): CharacterArcNode[] { const setting = new SettingRepository(this.db).get(settingId) if (!setting || setting.type !== 'character') return [] const knowledge = new KnowledgeRepository(this.db) .list() .filter((k) => k.type === 'character' && k.title.includes(setting.name)) const chapterRepo = new ChapterRepository(this.db) const chapters = new Map(chapterRepo.list().map((c) => [c.id, c])) const nodes: CharacterArcNode[] = knowledge .map((k) => { const chapterId = k.lastMentionChapterId ?? k.sourceChapterId const chapter = chapterId ? chapters.get(chapterId) : undefined return { id: k.id, title: k.title, content: k.content, chapterId: chapterId ?? null, chapterTitle: chapter?.title ?? null, updatedAt: k.updatedAt } }) .sort((a, b) => a.updatedAt.localeCompare(b.updatedAt)) if (nodes.length === 0 && setting.description.trim()) { nodes.push({ id: `setting:${setting.id}`, title: '角色设定', content: setting.description.replace(/<[^>]+>/g, '').slice(0, 200), chapterId: null, chapterTitle: null, updatedAt: setting.updatedAt }) } return nodes } }