@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.
package/LICENSE.md ADDED
@@ -0,0 +1,26 @@
1
+ # Proprietary License
2
+
3
+ Copyright (c) 2024-2025 ArcBlock, Inc. All Rights Reserved.
4
+
5
+ This software and associated documentation files (the "Software") are proprietary
6
+ and confidential. Unauthorized copying, modification, distribution, or use of
7
+ this Software, via any medium, is strictly prohibited.
8
+
9
+ The Software is provided for internal use only within ArcBlock, Inc. and its
10
+ authorized affiliates.
11
+
12
+ ## No License Granted
13
+
14
+ No license, express or implied, is granted to any party for any purpose.
15
+ All rights are reserved by ArcBlock, Inc.
16
+
17
+ ## Public Artifact Distribution
18
+
19
+ Portions of this Software may be released publicly under separate open-source
20
+ licenses (such as MIT License) through designated public repositories. Such
21
+ public releases are governed by their respective licenses and do not affect
22
+ the proprietary nature of this repository.
23
+
24
+ ## Contact
25
+
26
+ For licensing inquiries, contact: legal@arcblock.io
@@ -0,0 +1,11 @@
1
+
2
+ //#region \0@oxc-project+runtime@0.108.0/helpers/decorate.js
3
+ function __decorate(decorators, target, key, desc) {
4
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
5
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
6
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
7
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
8
+ }
9
+
10
+ //#endregion
11
+ exports.__decorate = __decorate;
@@ -0,0 +1,10 @@
1
+ //#region \0@oxc-project+runtime@0.108.0/helpers/decorate.js
2
+ function __decorate(decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ }
8
+
9
+ //#endregion
10
+ export { __decorate };
package/dist/db.cjs ADDED
@@ -0,0 +1,206 @@
1
+ let node_fs = require("node:fs");
2
+ let node_path = require("node:path");
3
+ let bun_sqlite = require("bun:sqlite");
4
+
5
+ //#region src/db.ts
6
+ const SCHEMA_SQL = `
7
+ CREATE TABLE IF NOT EXISTS interactions (
8
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
9
+ character TEXT NOT NULL,
10
+ platform TEXT NOT NULL,
11
+ type TEXT NOT NULL,
12
+ content TEXT,
13
+ thread_id TEXT,
14
+ external_id TEXT,
15
+ metadata TEXT,
16
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
17
+ );
18
+
19
+ CREATE TABLE IF NOT EXISTS sessions (
20
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
21
+ character TEXT NOT NULL,
22
+ status TEXT NOT NULL DEFAULT 'running',
23
+ actions_taken TEXT,
24
+ started_at TEXT NOT NULL DEFAULT (datetime('now')),
25
+ ended_at TEXT
26
+ );
27
+
28
+ CREATE TABLE IF NOT EXISTS seeded_topics (
29
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
30
+ character TEXT NOT NULL,
31
+ task_id TEXT NOT NULL,
32
+ topic TEXT NOT NULL,
33
+ angle TEXT,
34
+ status TEXT NOT NULL DEFAULT 'pending',
35
+ posted_at TEXT,
36
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
37
+ );
38
+
39
+ CREATE INDEX IF NOT EXISTS idx_seeded_recent ON seeded_topics(task_id, status, posted_at);
40
+
41
+ CREATE TABLE IF NOT EXISTS tasks (
42
+ id TEXT PRIMARY KEY,
43
+ topic TEXT NOT NULL,
44
+ goal TEXT,
45
+ material TEXT,
46
+ config TEXT,
47
+ assignments TEXT,
48
+ status TEXT NOT NULL DEFAULT 'active',
49
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
50
+ );
51
+ `;
52
+ var PersonaDB = class {
53
+ db;
54
+ initialized = false;
55
+ constructor(dbPath) {
56
+ const dir = (0, node_path.dirname)(dbPath);
57
+ if (!(0, node_fs.existsSync)(dir)) (0, node_fs.mkdirSync)(dir, { recursive: true });
58
+ this.db = new bun_sqlite.Database(dbPath);
59
+ this.db.exec("PRAGMA journal_mode = WAL");
60
+ this.db.exec("PRAGMA foreign_keys = ON");
61
+ }
62
+ ensureInitialized() {
63
+ if (this.initialized) return;
64
+ this.db.exec(SCHEMA_SQL);
65
+ this.initialized = true;
66
+ }
67
+ close() {
68
+ this.db.close();
69
+ }
70
+ insertInteraction(params) {
71
+ this.ensureInitialized();
72
+ const result = this.db.prepare(`
73
+ INSERT INTO interactions (character, platform, type, content, thread_id, external_id, metadata)
74
+ VALUES ($character, $platform, $type, $content, $thread_id, $external_id, $metadata)
75
+ `).run({
76
+ $character: params.character,
77
+ $platform: params.platform,
78
+ $type: params.type,
79
+ $content: params.content ?? null,
80
+ $thread_id: params.thread_id ?? null,
81
+ $external_id: params.external_id ?? null,
82
+ $metadata: params.metadata ? JSON.stringify(params.metadata) : null
83
+ });
84
+ return Number(result.lastInsertRowid);
85
+ }
86
+ getRecentInteractions(character, limit = 10) {
87
+ this.ensureInitialized();
88
+ return this.db.prepare("SELECT * FROM interactions WHERE character = $character ORDER BY created_at DESC LIMIT $limit").all({
89
+ $character: character,
90
+ $limit: limit
91
+ });
92
+ }
93
+ insertSession(character) {
94
+ this.ensureInitialized();
95
+ const result = this.db.prepare("INSERT INTO sessions (character) VALUES ($character)").run({ $character: character });
96
+ return Number(result.lastInsertRowid);
97
+ }
98
+ updateSession(id, params) {
99
+ this.ensureInitialized();
100
+ const sets = [];
101
+ const values = { $id: id };
102
+ if (params.status !== void 0) {
103
+ sets.push("status = $status");
104
+ values.$status = params.status;
105
+ }
106
+ if (params.ended_at !== void 0) {
107
+ sets.push("ended_at = $ended_at");
108
+ values.$ended_at = params.ended_at;
109
+ }
110
+ if (params.actions_taken !== void 0) {
111
+ sets.push("actions_taken = $actions_taken");
112
+ values.$actions_taken = params.actions_taken ? JSON.stringify(params.actions_taken) : null;
113
+ }
114
+ if (sets.length === 0) return 0;
115
+ return this.db.prepare(`UPDATE sessions SET ${sets.join(", ")} WHERE id = $id`).run(values).changes;
116
+ }
117
+ getRunningSession(character) {
118
+ this.ensureInitialized();
119
+ return this.db.prepare("SELECT * FROM sessions WHERE character = $character AND status = 'running' LIMIT 1").get({ $character: character }) || null;
120
+ }
121
+ getLastSession(character) {
122
+ this.ensureInitialized();
123
+ return this.db.prepare("SELECT * FROM sessions WHERE character = $character AND status != 'running' ORDER BY ended_at DESC LIMIT 1").get({ $character: character }) || null;
124
+ }
125
+ getLastDoneSession(character) {
126
+ this.ensureInitialized();
127
+ return this.db.prepare("SELECT * FROM sessions WHERE character = $character AND status = 'done' ORDER BY ended_at DESC LIMIT 1").get({ $character: character }) || null;
128
+ }
129
+ getStaleSessions(thresholdMinutes = 60) {
130
+ this.ensureInitialized();
131
+ return this.db.prepare(`SELECT * FROM sessions WHERE status = 'running' AND started_at < datetime('now', $threshold)`).all({ $threshold: `-${thresholdMinutes} minutes` });
132
+ }
133
+ markStaleSessions(thresholdMinutes = 60) {
134
+ this.ensureInitialized();
135
+ return this.db.prepare(`UPDATE sessions SET status = 'failed', ended_at = datetime('now')
136
+ WHERE status = 'running' AND started_at < datetime('now', $threshold)`).run({ $threshold: `-${thresholdMinutes} minutes` }).changes;
137
+ }
138
+ insertSeededTopic(params) {
139
+ this.ensureInitialized();
140
+ const result = this.db.prepare(`
141
+ INSERT INTO seeded_topics (character, task_id, topic, angle)
142
+ VALUES ($character, $task_id, $topic, $angle)
143
+ `).run({
144
+ $character: params.character,
145
+ $task_id: params.task_id,
146
+ $topic: params.topic,
147
+ $angle: params.angle ?? null
148
+ });
149
+ return Number(result.lastInsertRowid);
150
+ }
151
+ getSeededTopics(character, status = "pending") {
152
+ this.ensureInitialized();
153
+ return this.db.prepare("SELECT * FROM seeded_topics WHERE character = $character AND status = $status ORDER BY created_at ASC").all({
154
+ $character: character,
155
+ $status: status
156
+ });
157
+ }
158
+ /**
159
+ * Atomically claim a seeded topic for posting.
160
+ * Returns true if claimed, false if 4-hour dedup prevents it.
161
+ */
162
+ claimSeededTopic(topicId, taskId) {
163
+ this.ensureInitialized();
164
+ return this.db.transaction(() => {
165
+ if (this.db.prepare(`
166
+ SELECT 1 FROM seeded_topics
167
+ WHERE task_id = $task_id AND status = 'posted'
168
+ AND posted_at > datetime('now', '-4 hours')
169
+ LIMIT 1
170
+ `).get({ $task_id: taskId })) return false;
171
+ return this.db.prepare(`
172
+ UPDATE seeded_topics SET status = 'posted', posted_at = datetime('now')
173
+ WHERE id = $id AND status = 'pending'
174
+ `).run({ $id: topicId }).changes > 0;
175
+ })();
176
+ }
177
+ insertTask(params) {
178
+ this.ensureInitialized();
179
+ this.db.prepare(`
180
+ INSERT INTO tasks (id, topic, goal, material, config, assignments)
181
+ VALUES ($id, $topic, $goal, $material, $config, $assignments)
182
+ `).run({
183
+ $id: params.id,
184
+ $topic: params.topic,
185
+ $goal: params.goal ?? null,
186
+ $material: params.material ? JSON.stringify(params.material) : null,
187
+ $config: params.config ? JSON.stringify(params.config) : null,
188
+ $assignments: params.assignments ? JSON.stringify(params.assignments) : null
189
+ });
190
+ }
191
+ getTask(id) {
192
+ this.ensureInitialized();
193
+ return this.db.prepare("SELECT * FROM tasks WHERE id = $id").get({ $id: id }) || null;
194
+ }
195
+ static parseJSON(value) {
196
+ if (value === null) return null;
197
+ try {
198
+ return JSON.parse(value);
199
+ } catch {
200
+ return null;
201
+ }
202
+ }
203
+ };
204
+
205
+ //#endregion
206
+ exports.PersonaDB = PersonaDB;
package/dist/db.d.cts ADDED
@@ -0,0 +1,93 @@
1
+ //#region src/db.d.ts
2
+ interface InteractionRow {
3
+ id: number;
4
+ character: string;
5
+ platform: string;
6
+ type: string;
7
+ content: string | null;
8
+ thread_id: string | null;
9
+ external_id: string | null;
10
+ metadata: string | null;
11
+ created_at: string;
12
+ }
13
+ interface SessionRow {
14
+ id: number;
15
+ character: string;
16
+ status: string;
17
+ actions_taken: string | null;
18
+ started_at: string;
19
+ ended_at: string | null;
20
+ }
21
+ interface SeededTopicRow {
22
+ id: number;
23
+ character: string;
24
+ task_id: string;
25
+ topic: string;
26
+ angle: string | null;
27
+ status: string;
28
+ posted_at: string | null;
29
+ created_at: string;
30
+ }
31
+ interface TaskRow {
32
+ id: string;
33
+ topic: string;
34
+ goal: string | null;
35
+ material: string | null;
36
+ config: string | null;
37
+ assignments: string | null;
38
+ status: string;
39
+ created_at: string;
40
+ }
41
+ declare class PersonaDB {
42
+ private db;
43
+ private initialized;
44
+ constructor(dbPath: string);
45
+ ensureInitialized(): void;
46
+ close(): void;
47
+ insertInteraction(params: {
48
+ character: string;
49
+ platform: string;
50
+ type: string;
51
+ content?: string | null;
52
+ thread_id?: string | null;
53
+ external_id?: string | null;
54
+ metadata?: Record<string, unknown> | null;
55
+ }): number;
56
+ getRecentInteractions(character: string, limit?: number): InteractionRow[];
57
+ insertSession(character: string): number;
58
+ updateSession(id: number, params: {
59
+ status?: string;
60
+ ended_at?: string;
61
+ actions_taken?: unknown[] | null;
62
+ }): number;
63
+ getRunningSession(character: string): SessionRow | null;
64
+ getLastSession(character: string): SessionRow | null;
65
+ getLastDoneSession(character: string): SessionRow | null;
66
+ getStaleSessions(thresholdMinutes?: number): SessionRow[];
67
+ markStaleSessions(thresholdMinutes?: number): number;
68
+ insertSeededTopic(params: {
69
+ character: string;
70
+ task_id: string;
71
+ topic: string;
72
+ angle?: string | null;
73
+ }): number;
74
+ getSeededTopics(character: string, status?: string): SeededTopicRow[];
75
+ /**
76
+ * Atomically claim a seeded topic for posting.
77
+ * Returns true if claimed, false if 4-hour dedup prevents it.
78
+ */
79
+ claimSeededTopic(topicId: number, taskId: string): boolean;
80
+ insertTask(params: {
81
+ id: string;
82
+ topic: string;
83
+ goal?: string | null;
84
+ material?: Record<string, unknown> | null;
85
+ config?: Record<string, unknown> | null;
86
+ assignments?: Record<string, string> | null;
87
+ }): void;
88
+ getTask(id: string): TaskRow | null;
89
+ static parseJSON<T>(value: string | null): T | null;
90
+ }
91
+ //#endregion
92
+ export { InteractionRow, PersonaDB, SeededTopicRow, SessionRow, TaskRow };
93
+ //# sourceMappingURL=db.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.cts","names":[],"sources":["../src/db.ts"],"mappings":";UAmDiB,cAAA;EACf,EAAA;EACA,SAAA;EACA,QAAA;EACA,IAAA;EACA,OAAA;EACA,SAAA;EACA,WAAA;EACA,QAAA;EACA,UAAA;AAAA;AAAA,UAGe,UAAA;EACf,EAAA;EACA,SAAA;EACA,MAAA;EACA,aAAA;EACA,UAAA;EACA,QAAA;AAAA;AAAA,UAGe,cAAA;EACf,EAAA;EACA,SAAA;EACA,OAAA;EACA,KAAA;EACA,KAAA;EACA,MAAA;EACA,SAAA;EACA,UAAA;AAAA;AAAA,UAGe,OAAA;EACf,EAAA;EACA,KAAA;EACA,IAAA;EACA,QAAA;EACA,MAAA;EACA,WAAA;EACA,MAAA;EACA,UAAA;AAAA;AAAA,cAGW,SAAA;EAAA,QACH,EAAA;EAAA,QACA,WAAA;cAEI,MAAA;EAUZ,iBAAA,CAAA;EAMA,KAAA,CAAA;EAMA,iBAAA,CAAkB,MAAA;IAChB,SAAA;IACA,QAAA;IACA,IAAA;IACA,OAAA;IACA,SAAA;IACA,WAAA;IACA,QAAA,GAAW,MAAA;EAAA;EAmBb,qBAAA,CAAsB,SAAA,UAAmB,KAAA,YAAa,cAAA;EAUtD,aAAA,CAAc,SAAA;EAOd,aAAA,CACE,EAAA,UACA,MAAA;IACE,MAAA;IACA,QAAA;IACA,aAAA;EAAA;EA2BJ,iBAAA,CAAkB,SAAA,WAAoB,UAAA;EAQtC,cAAA,CAAe,SAAA,WAAoB,UAAA;EAQnC,kBAAA,CAAmB,SAAA,WAAoB,UAAA;EAQvC,gBAAA,CAAiB,gBAAA,YAAwB,UAAA;EAQzC,iBAAA,CAAkB,gBAAA;EAYlB,iBAAA,CAAkB,MAAA;IAChB,SAAA;IACA,OAAA;IACA,KAAA;IACA,KAAA;EAAA;EAgBF,eAAA,CAAgB,SAAA,UAAmB,MAAA,YAAqB,cAAA;EApKhD;;;;EAgLR,gBAAA,CAAiB,OAAA,UAAiB,MAAA;EA4BlC,UAAA,CAAW,MAAA;IACT,EAAA;IACA,KAAA;IACA,IAAA;IACA,QAAA,GAAW,MAAA;IACX,MAAA,GAAS,MAAA;IACT,WAAA,GAAc,MAAA;EAAA;EAiBhB,OAAA,CAAQ,EAAA,WAAa,OAAA;EAAA,OAQd,SAAA,GAAA,CAAa,KAAA,kBAAuB,CAAA;AAAA"}
package/dist/db.d.mts ADDED
@@ -0,0 +1,93 @@
1
+ //#region src/db.d.ts
2
+ interface InteractionRow {
3
+ id: number;
4
+ character: string;
5
+ platform: string;
6
+ type: string;
7
+ content: string | null;
8
+ thread_id: string | null;
9
+ external_id: string | null;
10
+ metadata: string | null;
11
+ created_at: string;
12
+ }
13
+ interface SessionRow {
14
+ id: number;
15
+ character: string;
16
+ status: string;
17
+ actions_taken: string | null;
18
+ started_at: string;
19
+ ended_at: string | null;
20
+ }
21
+ interface SeededTopicRow {
22
+ id: number;
23
+ character: string;
24
+ task_id: string;
25
+ topic: string;
26
+ angle: string | null;
27
+ status: string;
28
+ posted_at: string | null;
29
+ created_at: string;
30
+ }
31
+ interface TaskRow {
32
+ id: string;
33
+ topic: string;
34
+ goal: string | null;
35
+ material: string | null;
36
+ config: string | null;
37
+ assignments: string | null;
38
+ status: string;
39
+ created_at: string;
40
+ }
41
+ declare class PersonaDB {
42
+ private db;
43
+ private initialized;
44
+ constructor(dbPath: string);
45
+ ensureInitialized(): void;
46
+ close(): void;
47
+ insertInteraction(params: {
48
+ character: string;
49
+ platform: string;
50
+ type: string;
51
+ content?: string | null;
52
+ thread_id?: string | null;
53
+ external_id?: string | null;
54
+ metadata?: Record<string, unknown> | null;
55
+ }): number;
56
+ getRecentInteractions(character: string, limit?: number): InteractionRow[];
57
+ insertSession(character: string): number;
58
+ updateSession(id: number, params: {
59
+ status?: string;
60
+ ended_at?: string;
61
+ actions_taken?: unknown[] | null;
62
+ }): number;
63
+ getRunningSession(character: string): SessionRow | null;
64
+ getLastSession(character: string): SessionRow | null;
65
+ getLastDoneSession(character: string): SessionRow | null;
66
+ getStaleSessions(thresholdMinutes?: number): SessionRow[];
67
+ markStaleSessions(thresholdMinutes?: number): number;
68
+ insertSeededTopic(params: {
69
+ character: string;
70
+ task_id: string;
71
+ topic: string;
72
+ angle?: string | null;
73
+ }): number;
74
+ getSeededTopics(character: string, status?: string): SeededTopicRow[];
75
+ /**
76
+ * Atomically claim a seeded topic for posting.
77
+ * Returns true if claimed, false if 4-hour dedup prevents it.
78
+ */
79
+ claimSeededTopic(topicId: number, taskId: string): boolean;
80
+ insertTask(params: {
81
+ id: string;
82
+ topic: string;
83
+ goal?: string | null;
84
+ material?: Record<string, unknown> | null;
85
+ config?: Record<string, unknown> | null;
86
+ assignments?: Record<string, string> | null;
87
+ }): void;
88
+ getTask(id: string): TaskRow | null;
89
+ static parseJSON<T>(value: string | null): T | null;
90
+ }
91
+ //#endregion
92
+ export { InteractionRow, PersonaDB, SeededTopicRow, SessionRow, TaskRow };
93
+ //# sourceMappingURL=db.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.mts","names":[],"sources":["../src/db.ts"],"mappings":";UAmDiB,cAAA;EACf,EAAA;EACA,SAAA;EACA,QAAA;EACA,IAAA;EACA,OAAA;EACA,SAAA;EACA,WAAA;EACA,QAAA;EACA,UAAA;AAAA;AAAA,UAGe,UAAA;EACf,EAAA;EACA,SAAA;EACA,MAAA;EACA,aAAA;EACA,UAAA;EACA,QAAA;AAAA;AAAA,UAGe,cAAA;EACf,EAAA;EACA,SAAA;EACA,OAAA;EACA,KAAA;EACA,KAAA;EACA,MAAA;EACA,SAAA;EACA,UAAA;AAAA;AAAA,UAGe,OAAA;EACf,EAAA;EACA,KAAA;EACA,IAAA;EACA,QAAA;EACA,MAAA;EACA,WAAA;EACA,MAAA;EACA,UAAA;AAAA;AAAA,cAGW,SAAA;EAAA,QACH,EAAA;EAAA,QACA,WAAA;cAEI,MAAA;EAUZ,iBAAA,CAAA;EAMA,KAAA,CAAA;EAMA,iBAAA,CAAkB,MAAA;IAChB,SAAA;IACA,QAAA;IACA,IAAA;IACA,OAAA;IACA,SAAA;IACA,WAAA;IACA,QAAA,GAAW,MAAA;EAAA;EAmBb,qBAAA,CAAsB,SAAA,UAAmB,KAAA,YAAa,cAAA;EAUtD,aAAA,CAAc,SAAA;EAOd,aAAA,CACE,EAAA,UACA,MAAA;IACE,MAAA;IACA,QAAA;IACA,aAAA;EAAA;EA2BJ,iBAAA,CAAkB,SAAA,WAAoB,UAAA;EAQtC,cAAA,CAAe,SAAA,WAAoB,UAAA;EAQnC,kBAAA,CAAmB,SAAA,WAAoB,UAAA;EAQvC,gBAAA,CAAiB,gBAAA,YAAwB,UAAA;EAQzC,iBAAA,CAAkB,gBAAA;EAYlB,iBAAA,CAAkB,MAAA;IAChB,SAAA;IACA,OAAA;IACA,KAAA;IACA,KAAA;EAAA;EAgBF,eAAA,CAAgB,SAAA,UAAmB,MAAA,YAAqB,cAAA;EApKhD;;;;EAgLR,gBAAA,CAAiB,OAAA,UAAiB,MAAA;EA4BlC,UAAA,CAAW,MAAA;IACT,EAAA;IACA,KAAA;IACA,IAAA;IACA,QAAA,GAAW,MAAA;IACX,MAAA,GAAS,MAAA;IACT,WAAA,GAAc,MAAA;EAAA;EAiBhB,OAAA,CAAQ,EAAA,WAAa,OAAA;EAAA,OAQd,SAAA,GAAA,CAAa,KAAA,kBAAuB,CAAA;AAAA"}
package/dist/db.mjs ADDED
@@ -0,0 +1,207 @@
1
+ import { existsSync, mkdirSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { Database } from "bun:sqlite";
4
+
5
+ //#region src/db.ts
6
+ const SCHEMA_SQL = `
7
+ CREATE TABLE IF NOT EXISTS interactions (
8
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
9
+ character TEXT NOT NULL,
10
+ platform TEXT NOT NULL,
11
+ type TEXT NOT NULL,
12
+ content TEXT,
13
+ thread_id TEXT,
14
+ external_id TEXT,
15
+ metadata TEXT,
16
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
17
+ );
18
+
19
+ CREATE TABLE IF NOT EXISTS sessions (
20
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
21
+ character TEXT NOT NULL,
22
+ status TEXT NOT NULL DEFAULT 'running',
23
+ actions_taken TEXT,
24
+ started_at TEXT NOT NULL DEFAULT (datetime('now')),
25
+ ended_at TEXT
26
+ );
27
+
28
+ CREATE TABLE IF NOT EXISTS seeded_topics (
29
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
30
+ character TEXT NOT NULL,
31
+ task_id TEXT NOT NULL,
32
+ topic TEXT NOT NULL,
33
+ angle TEXT,
34
+ status TEXT NOT NULL DEFAULT 'pending',
35
+ posted_at TEXT,
36
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
37
+ );
38
+
39
+ CREATE INDEX IF NOT EXISTS idx_seeded_recent ON seeded_topics(task_id, status, posted_at);
40
+
41
+ CREATE TABLE IF NOT EXISTS tasks (
42
+ id TEXT PRIMARY KEY,
43
+ topic TEXT NOT NULL,
44
+ goal TEXT,
45
+ material TEXT,
46
+ config TEXT,
47
+ assignments TEXT,
48
+ status TEXT NOT NULL DEFAULT 'active',
49
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
50
+ );
51
+ `;
52
+ var PersonaDB = class {
53
+ db;
54
+ initialized = false;
55
+ constructor(dbPath) {
56
+ const dir = dirname(dbPath);
57
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
58
+ this.db = new Database(dbPath);
59
+ this.db.exec("PRAGMA journal_mode = WAL");
60
+ this.db.exec("PRAGMA foreign_keys = ON");
61
+ }
62
+ ensureInitialized() {
63
+ if (this.initialized) return;
64
+ this.db.exec(SCHEMA_SQL);
65
+ this.initialized = true;
66
+ }
67
+ close() {
68
+ this.db.close();
69
+ }
70
+ insertInteraction(params) {
71
+ this.ensureInitialized();
72
+ const result = this.db.prepare(`
73
+ INSERT INTO interactions (character, platform, type, content, thread_id, external_id, metadata)
74
+ VALUES ($character, $platform, $type, $content, $thread_id, $external_id, $metadata)
75
+ `).run({
76
+ $character: params.character,
77
+ $platform: params.platform,
78
+ $type: params.type,
79
+ $content: params.content ?? null,
80
+ $thread_id: params.thread_id ?? null,
81
+ $external_id: params.external_id ?? null,
82
+ $metadata: params.metadata ? JSON.stringify(params.metadata) : null
83
+ });
84
+ return Number(result.lastInsertRowid);
85
+ }
86
+ getRecentInteractions(character, limit = 10) {
87
+ this.ensureInitialized();
88
+ return this.db.prepare("SELECT * FROM interactions WHERE character = $character ORDER BY created_at DESC LIMIT $limit").all({
89
+ $character: character,
90
+ $limit: limit
91
+ });
92
+ }
93
+ insertSession(character) {
94
+ this.ensureInitialized();
95
+ const result = this.db.prepare("INSERT INTO sessions (character) VALUES ($character)").run({ $character: character });
96
+ return Number(result.lastInsertRowid);
97
+ }
98
+ updateSession(id, params) {
99
+ this.ensureInitialized();
100
+ const sets = [];
101
+ const values = { $id: id };
102
+ if (params.status !== void 0) {
103
+ sets.push("status = $status");
104
+ values.$status = params.status;
105
+ }
106
+ if (params.ended_at !== void 0) {
107
+ sets.push("ended_at = $ended_at");
108
+ values.$ended_at = params.ended_at;
109
+ }
110
+ if (params.actions_taken !== void 0) {
111
+ sets.push("actions_taken = $actions_taken");
112
+ values.$actions_taken = params.actions_taken ? JSON.stringify(params.actions_taken) : null;
113
+ }
114
+ if (sets.length === 0) return 0;
115
+ return this.db.prepare(`UPDATE sessions SET ${sets.join(", ")} WHERE id = $id`).run(values).changes;
116
+ }
117
+ getRunningSession(character) {
118
+ this.ensureInitialized();
119
+ return this.db.prepare("SELECT * FROM sessions WHERE character = $character AND status = 'running' LIMIT 1").get({ $character: character }) || null;
120
+ }
121
+ getLastSession(character) {
122
+ this.ensureInitialized();
123
+ return this.db.prepare("SELECT * FROM sessions WHERE character = $character AND status != 'running' ORDER BY ended_at DESC LIMIT 1").get({ $character: character }) || null;
124
+ }
125
+ getLastDoneSession(character) {
126
+ this.ensureInitialized();
127
+ return this.db.prepare("SELECT * FROM sessions WHERE character = $character AND status = 'done' ORDER BY ended_at DESC LIMIT 1").get({ $character: character }) || null;
128
+ }
129
+ getStaleSessions(thresholdMinutes = 60) {
130
+ this.ensureInitialized();
131
+ return this.db.prepare(`SELECT * FROM sessions WHERE status = 'running' AND started_at < datetime('now', $threshold)`).all({ $threshold: `-${thresholdMinutes} minutes` });
132
+ }
133
+ markStaleSessions(thresholdMinutes = 60) {
134
+ this.ensureInitialized();
135
+ return this.db.prepare(`UPDATE sessions SET status = 'failed', ended_at = datetime('now')
136
+ WHERE status = 'running' AND started_at < datetime('now', $threshold)`).run({ $threshold: `-${thresholdMinutes} minutes` }).changes;
137
+ }
138
+ insertSeededTopic(params) {
139
+ this.ensureInitialized();
140
+ const result = this.db.prepare(`
141
+ INSERT INTO seeded_topics (character, task_id, topic, angle)
142
+ VALUES ($character, $task_id, $topic, $angle)
143
+ `).run({
144
+ $character: params.character,
145
+ $task_id: params.task_id,
146
+ $topic: params.topic,
147
+ $angle: params.angle ?? null
148
+ });
149
+ return Number(result.lastInsertRowid);
150
+ }
151
+ getSeededTopics(character, status = "pending") {
152
+ this.ensureInitialized();
153
+ return this.db.prepare("SELECT * FROM seeded_topics WHERE character = $character AND status = $status ORDER BY created_at ASC").all({
154
+ $character: character,
155
+ $status: status
156
+ });
157
+ }
158
+ /**
159
+ * Atomically claim a seeded topic for posting.
160
+ * Returns true if claimed, false if 4-hour dedup prevents it.
161
+ */
162
+ claimSeededTopic(topicId, taskId) {
163
+ this.ensureInitialized();
164
+ return this.db.transaction(() => {
165
+ if (this.db.prepare(`
166
+ SELECT 1 FROM seeded_topics
167
+ WHERE task_id = $task_id AND status = 'posted'
168
+ AND posted_at > datetime('now', '-4 hours')
169
+ LIMIT 1
170
+ `).get({ $task_id: taskId })) return false;
171
+ return this.db.prepare(`
172
+ UPDATE seeded_topics SET status = 'posted', posted_at = datetime('now')
173
+ WHERE id = $id AND status = 'pending'
174
+ `).run({ $id: topicId }).changes > 0;
175
+ })();
176
+ }
177
+ insertTask(params) {
178
+ this.ensureInitialized();
179
+ this.db.prepare(`
180
+ INSERT INTO tasks (id, topic, goal, material, config, assignments)
181
+ VALUES ($id, $topic, $goal, $material, $config, $assignments)
182
+ `).run({
183
+ $id: params.id,
184
+ $topic: params.topic,
185
+ $goal: params.goal ?? null,
186
+ $material: params.material ? JSON.stringify(params.material) : null,
187
+ $config: params.config ? JSON.stringify(params.config) : null,
188
+ $assignments: params.assignments ? JSON.stringify(params.assignments) : null
189
+ });
190
+ }
191
+ getTask(id) {
192
+ this.ensureInitialized();
193
+ return this.db.prepare("SELECT * FROM tasks WHERE id = $id").get({ $id: id }) || null;
194
+ }
195
+ static parseJSON(value) {
196
+ if (value === null) return null;
197
+ try {
198
+ return JSON.parse(value);
199
+ } catch {
200
+ return null;
201
+ }
202
+ }
203
+ };
204
+
205
+ //#endregion
206
+ export { PersonaDB };
207
+ //# sourceMappingURL=db.mjs.map