@aigne/afs-persona 1.11.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.mjs","names":[],"sources":["../src/db.ts"],"sourcesContent":["import { Database } from \"bun:sqlite\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nconst SCHEMA_SQL = `\nCREATE TABLE IF NOT EXISTS interactions (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n character TEXT NOT NULL,\n platform TEXT NOT NULL,\n type TEXT NOT NULL,\n content TEXT,\n thread_id TEXT,\n external_id TEXT,\n metadata TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE TABLE IF NOT EXISTS sessions (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n character TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'running',\n actions_taken TEXT,\n started_at TEXT NOT NULL DEFAULT (datetime('now')),\n ended_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS seeded_topics (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n character TEXT NOT NULL,\n task_id TEXT NOT NULL,\n topic TEXT NOT NULL,\n angle TEXT,\n status TEXT NOT NULL DEFAULT 'pending',\n posted_at TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE INDEX IF NOT EXISTS idx_seeded_recent ON seeded_topics(task_id, status, posted_at);\n\nCREATE TABLE IF NOT EXISTS tasks (\n id TEXT PRIMARY KEY,\n topic TEXT NOT NULL,\n goal TEXT,\n material TEXT,\n config TEXT,\n assignments TEXT,\n status TEXT NOT NULL DEFAULT 'active',\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n`;\n\nexport interface InteractionRow {\n id: number;\n character: string;\n platform: string;\n type: string;\n content: string | null;\n thread_id: string | null;\n external_id: string | null;\n metadata: string | null;\n created_at: string;\n}\n\nexport interface SessionRow {\n id: number;\n character: string;\n status: string;\n actions_taken: string | null;\n started_at: string;\n ended_at: string | null;\n}\n\nexport interface SeededTopicRow {\n id: number;\n character: string;\n task_id: string;\n topic: string;\n angle: string | null;\n status: string;\n posted_at: string | null;\n created_at: string;\n}\n\nexport interface TaskRow {\n id: string;\n topic: string;\n goal: string | null;\n material: string | null;\n config: string | null;\n assignments: string | null;\n status: string;\n created_at: string;\n}\n\nexport class PersonaDB {\n private db: Database;\n private initialized = false;\n\n constructor(dbPath: string) {\n const dir = dirname(dbPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n this.db = new Database(dbPath);\n this.db.exec(\"PRAGMA journal_mode = WAL\");\n this.db.exec(\"PRAGMA foreign_keys = ON\");\n }\n\n ensureInitialized(): void {\n if (this.initialized) return;\n this.db.exec(SCHEMA_SQL);\n this.initialized = true;\n }\n\n close(): void {\n this.db.close();\n }\n\n // ========== Interactions ==========\n\n insertInteraction(params: {\n character: string;\n platform: string;\n type: string;\n content?: string | null;\n thread_id?: string | null;\n external_id?: string | null;\n metadata?: Record<string, unknown> | null;\n }): number {\n this.ensureInitialized();\n const stmt = this.db.prepare(`\n INSERT INTO interactions (character, platform, type, content, thread_id, external_id, metadata)\n VALUES ($character, $platform, $type, $content, $thread_id, $external_id, $metadata)\n `);\n const result = stmt.run({\n $character: params.character,\n $platform: params.platform,\n $type: params.type,\n $content: params.content ?? null,\n $thread_id: params.thread_id ?? null,\n $external_id: params.external_id ?? null,\n $metadata: params.metadata ? JSON.stringify(params.metadata) : null,\n });\n return Number(result.lastInsertRowid);\n }\n\n getRecentInteractions(character: string, limit = 10): InteractionRow[] {\n this.ensureInitialized();\n const stmt = this.db.prepare(\n \"SELECT * FROM interactions WHERE character = $character ORDER BY created_at DESC LIMIT $limit\",\n );\n return stmt.all({ $character: character, $limit: limit }) as InteractionRow[];\n }\n\n // ========== Sessions ==========\n\n insertSession(character: string): number {\n this.ensureInitialized();\n const stmt = this.db.prepare(\"INSERT INTO sessions (character) VALUES ($character)\");\n const result = stmt.run({ $character: character });\n return Number(result.lastInsertRowid);\n }\n\n updateSession(\n id: number,\n params: {\n status?: string;\n ended_at?: string;\n actions_taken?: unknown[] | null;\n },\n ): number {\n this.ensureInitialized();\n const sets: string[] = [];\n const values: Record<string, unknown> = { $id: id };\n\n if (params.status !== undefined) {\n sets.push(\"status = $status\");\n values.$status = params.status;\n }\n if (params.ended_at !== undefined) {\n sets.push(\"ended_at = $ended_at\");\n values.$ended_at = params.ended_at;\n }\n if (params.actions_taken !== undefined) {\n sets.push(\"actions_taken = $actions_taken\");\n values.$actions_taken = params.actions_taken ? JSON.stringify(params.actions_taken) : null;\n }\n\n if (sets.length === 0) return 0;\n\n const stmt = this.db.prepare(`UPDATE sessions SET ${sets.join(\", \")} WHERE id = $id`);\n const result = stmt.run(values as Record<string, string | number | null>);\n return result.changes;\n }\n\n getRunningSession(character: string): SessionRow | null {\n this.ensureInitialized();\n const stmt = this.db.prepare(\n \"SELECT * FROM sessions WHERE character = $character AND status = 'running' LIMIT 1\",\n );\n return (stmt.get({ $character: character }) as SessionRow) || null;\n }\n\n getLastSession(character: string): SessionRow | null {\n this.ensureInitialized();\n const stmt = this.db.prepare(\n \"SELECT * FROM sessions WHERE character = $character AND status != 'running' ORDER BY ended_at DESC LIMIT 1\",\n );\n return (stmt.get({ $character: character }) as SessionRow) || null;\n }\n\n getLastDoneSession(character: string): SessionRow | null {\n this.ensureInitialized();\n const stmt = this.db.prepare(\n \"SELECT * FROM sessions WHERE character = $character AND status = 'done' ORDER BY ended_at DESC LIMIT 1\",\n );\n return (stmt.get({ $character: character }) as SessionRow) || null;\n }\n\n getStaleSessions(thresholdMinutes = 60): SessionRow[] {\n this.ensureInitialized();\n const stmt = this.db.prepare(\n `SELECT * FROM sessions WHERE status = 'running' AND started_at < datetime('now', $threshold)`,\n );\n return stmt.all({ $threshold: `-${thresholdMinutes} minutes` }) as SessionRow[];\n }\n\n markStaleSessions(thresholdMinutes = 60): number {\n this.ensureInitialized();\n const stmt = this.db.prepare(\n `UPDATE sessions SET status = 'failed', ended_at = datetime('now')\n WHERE status = 'running' AND started_at < datetime('now', $threshold)`,\n );\n const result = stmt.run({ $threshold: `-${thresholdMinutes} minutes` });\n return result.changes;\n }\n\n // ========== Seeded Topics ==========\n\n insertSeededTopic(params: {\n character: string;\n task_id: string;\n topic: string;\n angle?: string | null;\n }): number {\n this.ensureInitialized();\n const stmt = this.db.prepare(`\n INSERT INTO seeded_topics (character, task_id, topic, angle)\n VALUES ($character, $task_id, $topic, $angle)\n `);\n const result = stmt.run({\n $character: params.character,\n $task_id: params.task_id,\n $topic: params.topic,\n $angle: params.angle ?? null,\n });\n return Number(result.lastInsertRowid);\n }\n\n getSeededTopics(character: string, status = \"pending\"): SeededTopicRow[] {\n this.ensureInitialized();\n const stmt = this.db.prepare(\n \"SELECT * FROM seeded_topics WHERE character = $character AND status = $status ORDER BY created_at ASC\",\n );\n return stmt.all({ $character: character, $status: status }) as SeededTopicRow[];\n }\n\n /**\n * Atomically claim a seeded topic for posting.\n * Returns true if claimed, false if 4-hour dedup prevents it.\n */\n claimSeededTopic(topicId: number, taskId: string): boolean {\n this.ensureInitialized();\n\n const txn = this.db.transaction(() => {\n // Check for same task_id posted within last 4 hours\n const checkStmt = this.db.prepare(`\n SELECT 1 FROM seeded_topics\n WHERE task_id = $task_id AND status = 'posted'\n AND posted_at > datetime('now', '-4 hours')\n LIMIT 1\n `);\n const existing = checkStmt.get({ $task_id: taskId });\n if (existing) return false;\n\n // Claim it\n const claimStmt = this.db.prepare(`\n UPDATE seeded_topics SET status = 'posted', posted_at = datetime('now')\n WHERE id = $id AND status = 'pending'\n `);\n const result = claimStmt.run({ $id: topicId });\n return result.changes > 0;\n });\n\n return txn();\n }\n\n // ========== Tasks ==========\n\n insertTask(params: {\n id: string;\n topic: string;\n goal?: string | null;\n material?: Record<string, unknown> | null;\n config?: Record<string, unknown> | null;\n assignments?: Record<string, string> | null;\n }): void {\n this.ensureInitialized();\n const stmt = this.db.prepare(`\n INSERT INTO tasks (id, topic, goal, material, config, assignments)\n VALUES ($id, $topic, $goal, $material, $config, $assignments)\n `);\n stmt.run({\n $id: params.id,\n $topic: params.topic,\n $goal: params.goal ?? null,\n $material: params.material ? JSON.stringify(params.material) : null,\n $config: params.config ? JSON.stringify(params.config) : null,\n $assignments: params.assignments ? JSON.stringify(params.assignments) : null,\n });\n }\n\n getTask(id: string): TaskRow | null {\n this.ensureInitialized();\n const stmt = this.db.prepare(\"SELECT * FROM tasks WHERE id = $id\");\n return (stmt.get({ $id: id }) as TaskRow) || null;\n }\n\n // ========== JSON Helpers ==========\n\n static parseJSON<T>(value: string | null): T | null {\n if (value === null) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return null;\n }\n }\n}\n"],"mappings":"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"}