@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 +26 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
- package/dist/db.cjs +206 -0
- package/dist/db.d.cts +93 -0
- package/dist/db.d.cts.map +1 -0
- package/dist/db.d.mts +93 -0
- package/dist/db.d.mts.map +1 -0
- package/dist/db.mjs +207 -0
- package/dist/db.mjs.map +1 -0
- package/dist/index.cjs +987 -0
- package/dist/index.d.cts +121 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +121 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +987 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +58 -0
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
|