@kafca/agentdock 0.1.7
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/README.md +70 -0
- package/bin/agentdock.mjs +275 -0
- package/build/icon.png +0 -0
- package/dist/renderer/assets/index-BaNpzC6d.js +482 -0
- package/dist/renderer/assets/index-CLWJyO0E.css +11 -0
- package/dist/renderer/favicon.svg +19 -0
- package/dist/renderer/index.html +14 -0
- package/dist/renderer/logo-options.svg +153 -0
- package/dist-electron/electron/knowledge-skill-script.test.js +125 -0
- package/dist-electron/electron/lac-cli.test.js +221 -0
- package/dist-electron/electron/local-core-refactor.test.js +1075 -0
- package/dist-electron/electron/main.js +163 -0
- package/dist-electron/electron/plugin-kernel.test.js +534 -0
- package/dist-electron/electron/preload.js +2 -0
- package/dist-electron/package.json +3 -0
- package/dist-electron/packages/contracts/src/index.js +18 -0
- package/dist-electron/packages/contracts/src/local-core.js +2 -0
- package/dist-electron/packages/core-sdk/src/index.js +406 -0
- package/dist-electron/packages/knowledge-api/src/ai-vector-provider.js +388 -0
- package/dist-electron/packages/knowledge-api/src/index.js +146 -0
- package/dist-electron/packages/knowledge-api/src/sqlite-store.js +467 -0
- package/dist-electron/packages/knowledge-api/src/thread-knowledge-store.js +21 -0
- package/dist-electron/packages/knowledge-api/test/ai-vector-provider.test.js +412 -0
- package/dist-electron/packages/plugin-sdk/src/index.js +2 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +369 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-response-processor.js +110 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +171 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +635 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-transport.js +190 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +244 -0
- package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +52 -0
- package/dist-electron/services/local-ai-core/src/cli/lac.js +290 -0
- package/dist-electron/services/local-ai-core/src/gateway/local-core-lark-gateway.js +976 -0
- package/dist-electron/services/local-ai-core/src/gateway/local-core-weixin-gateway.js +1143 -0
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +291 -0
- package/dist-electron/services/local-ai-core/src/kernel/capability-registry.js +67 -0
- package/dist-electron/services/local-ai-core/src/kernel/diagnostics.js +27 -0
- package/dist-electron/services/local-ai-core/src/kernel/event-bus.js +27 -0
- package/dist-electron/services/local-ai-core/src/kernel/lifecycle-manager.js +85 -0
- package/dist-electron/services/local-ai-core/src/kernel/plugin-registry.js +60 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js +114 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-lark-plugin.js +59 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-weixin-plugin.js +56 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-ai-vector-plugin.js +7 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-noop-plugin.js +7 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/runtime-capabilities-plugin.js +62 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/scheduler-cron-plugin.js +49 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/scheduler-lark-plugin.js +38 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/scheduler-weixin-plugin.js +38 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +230 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-router-types.js +2 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-router.js +389 -0
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +315 -0
- package/dist-electron/services/local-ai-core/src/runtime/local-core-runtime-state.js +282 -0
- package/dist-electron/services/local-ai-core/src/runtime/server.js +465 -0
- package/dist-electron/services/local-ai-core/src/runtime/standalone.js +38 -0
- package/dist-electron/services/local-ai-core/src/scheduler/adapters.js +2 -0
- package/dist-electron/services/local-ai-core/src/scheduler/cron-command-detector.js +70 -0
- package/dist-electron/services/local-ai-core/src/scheduler/cron.js +53 -0
- package/dist-electron/services/local-ai-core/src/scheduler/execution-policy.js +2 -0
- package/dist-electron/services/local-ai-core/src/scheduler/lark-execution-policies.js +66 -0
- package/dist-electron/services/local-ai-core/src/scheduler/lark-schedule-adapter.js +77 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +46 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduler-run-lifecycle.js +64 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +133 -0
- package/dist-electron/services/local-ai-core/src/scheduler/weixin-execution-policies.js +66 -0
- package/dist-electron/services/local-ai-core/src/scheduler/weixin-schedule-adapter.js +78 -0
- package/dist-electron/services/local-ai-core/src/thread/workspace-thread-id.js +17 -0
- package/dist-electron/services/local-ai-core/src/thread/workspace-thread-mappers.js +43 -0
- package/dist-electron/shared/desktop.js +195 -0
- package/dist-electron/src/api/client.js +73 -0
- package/dist-electron/src/api/sessions.js +21 -0
- package/dist-electron/src/lib/session-utils.js +51 -0
- package/dist-electron/src/pages/Threads/thread-chat-model.js +246 -0
- package/dist-electron/src/pages/Threads/thread-chat-model.test.js +76 -0
- package/dist-electron/src/pages/Threads/thread-chat-permission.js +26 -0
- package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +102 -0
- package/dist-electron/src/pages/Threads/thread-chat-task-state.js +65 -0
- package/package.json +146 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KnowledgeSqliteStore = void 0;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const node_sqlite_1 = require("node:sqlite");
|
|
7
|
+
const SCHEMA_VERSION = '2';
|
|
8
|
+
function clone(value) {
|
|
9
|
+
return JSON.parse(JSON.stringify(value));
|
|
10
|
+
}
|
|
11
|
+
function parseMetadata(raw) {
|
|
12
|
+
if (!raw) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(raw);
|
|
17
|
+
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function cleanupDatabaseFiles(dbPath) {
|
|
24
|
+
(0, node_fs_1.rmSync)(dbPath, { force: true });
|
|
25
|
+
(0, node_fs_1.rmSync)(`${dbPath}-shm`, { force: true });
|
|
26
|
+
(0, node_fs_1.rmSync)(`${dbPath}-wal`, { force: true });
|
|
27
|
+
}
|
|
28
|
+
class KnowledgeSqliteStore {
|
|
29
|
+
dbPath;
|
|
30
|
+
legacyStorePath;
|
|
31
|
+
legacyBackupPath;
|
|
32
|
+
db;
|
|
33
|
+
constructor(options) {
|
|
34
|
+
this.dbPath = (0, node_path_1.join)(options.userDataPath, 'runtime', 'knowledge.db');
|
|
35
|
+
this.legacyStorePath = (0, node_path_1.join)(options.userDataPath, 'runtime', 'knowledge-store.json');
|
|
36
|
+
this.legacyBackupPath = `${this.legacyStorePath}.bak`;
|
|
37
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(this.dbPath), { recursive: true });
|
|
38
|
+
const shouldMigrate = !(0, node_fs_1.existsSync)(this.dbPath) && (0, node_fs_1.existsSync)(this.legacyStorePath);
|
|
39
|
+
this.db = new node_sqlite_1.DatabaseSync(this.dbPath);
|
|
40
|
+
try {
|
|
41
|
+
this.initializeSchema();
|
|
42
|
+
if (shouldMigrate) {
|
|
43
|
+
this.migrateLegacyJson();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
this.db.close();
|
|
48
|
+
if (shouldMigrate) {
|
|
49
|
+
cleanupDatabaseFiles(this.dbPath);
|
|
50
|
+
}
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
close() {
|
|
55
|
+
this.db.close();
|
|
56
|
+
}
|
|
57
|
+
listFolders() {
|
|
58
|
+
const rows = this.db.prepare(`
|
|
59
|
+
SELECT id, name, parent_id, path, sort_order, created_at, updated_at
|
|
60
|
+
FROM knowledge_folders
|
|
61
|
+
ORDER BY path ASC, sort_order ASC
|
|
62
|
+
`).all();
|
|
63
|
+
return rows.map((row) => this.mapFolder(row));
|
|
64
|
+
}
|
|
65
|
+
getFolder(id) {
|
|
66
|
+
const row = this.db.prepare(`
|
|
67
|
+
SELECT id, name, parent_id, path, sort_order, created_at, updated_at
|
|
68
|
+
FROM knowledge_folders
|
|
69
|
+
WHERE id = ?
|
|
70
|
+
LIMIT 1
|
|
71
|
+
`).get(id);
|
|
72
|
+
return row ? this.mapFolder(row) : null;
|
|
73
|
+
}
|
|
74
|
+
insertFolder(folder) {
|
|
75
|
+
this.db.prepare(`
|
|
76
|
+
INSERT INTO knowledge_folders (
|
|
77
|
+
id, name, parent_id, path, sort_order, created_at, updated_at
|
|
78
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
79
|
+
`).run(folder.id, folder.name, folder.parentId, folder.path, folder.sortOrder, folder.createdAt, folder.updatedAt);
|
|
80
|
+
return clone(folder);
|
|
81
|
+
}
|
|
82
|
+
renameFolder(id, input) {
|
|
83
|
+
this.transaction(() => {
|
|
84
|
+
const updateResult = this.db.prepare(`
|
|
85
|
+
UPDATE knowledge_folders
|
|
86
|
+
SET name = ?, path = ?, updated_at = ?
|
|
87
|
+
WHERE id = ?
|
|
88
|
+
`).run(input.name, input.nextPath, input.updatedAt, id);
|
|
89
|
+
if (Number(updateResult.changes || 0) === 0) {
|
|
90
|
+
throw new Error('Folder does not exist.');
|
|
91
|
+
}
|
|
92
|
+
this.db.prepare(`
|
|
93
|
+
UPDATE knowledge_folders
|
|
94
|
+
SET path = replace(path, ?, ?), updated_at = ?
|
|
95
|
+
WHERE id <> ? AND path LIKE ?
|
|
96
|
+
`).run(input.previousPath, input.nextPath, input.updatedAt, id, `${input.previousPath}/%`);
|
|
97
|
+
});
|
|
98
|
+
const folder = this.getFolder(id);
|
|
99
|
+
if (!folder) {
|
|
100
|
+
throw new Error('Folder does not exist.');
|
|
101
|
+
}
|
|
102
|
+
return folder;
|
|
103
|
+
}
|
|
104
|
+
deleteFolder(id) {
|
|
105
|
+
this.db.prepare('DELETE FROM knowledge_folders WHERE id = ?').run(id);
|
|
106
|
+
}
|
|
107
|
+
listKnowledgeBases() {
|
|
108
|
+
const rows = this.db.prepare(`
|
|
109
|
+
SELECT
|
|
110
|
+
bases.id,
|
|
111
|
+
bases.name,
|
|
112
|
+
bases.description,
|
|
113
|
+
bases.folder_id,
|
|
114
|
+
bases.creator_name,
|
|
115
|
+
bases.icon,
|
|
116
|
+
bases.created_at,
|
|
117
|
+
bases.updated_at,
|
|
118
|
+
COALESCE(stats.file_count, 0) AS file_count,
|
|
119
|
+
COALESCE(stats.word_count, 0) AS word_count
|
|
120
|
+
FROM knowledge_bases AS bases
|
|
121
|
+
LEFT JOIN (
|
|
122
|
+
SELECT
|
|
123
|
+
knowledgebase_id,
|
|
124
|
+
COUNT(*) AS file_count,
|
|
125
|
+
COALESCE(SUM(COALESCE(word_count, 0)), 0) AS word_count
|
|
126
|
+
FROM knowledge_files
|
|
127
|
+
GROUP BY knowledgebase_id
|
|
128
|
+
) AS stats ON stats.knowledgebase_id = bases.id
|
|
129
|
+
ORDER BY bases.updated_at DESC
|
|
130
|
+
`).all();
|
|
131
|
+
return rows.map((row) => this.mapKnowledgeBase(row));
|
|
132
|
+
}
|
|
133
|
+
getKnowledgeBase(id) {
|
|
134
|
+
const row = this.db.prepare(`
|
|
135
|
+
SELECT
|
|
136
|
+
bases.id,
|
|
137
|
+
bases.name,
|
|
138
|
+
bases.description,
|
|
139
|
+
bases.folder_id,
|
|
140
|
+
bases.creator_name,
|
|
141
|
+
bases.icon,
|
|
142
|
+
bases.created_at,
|
|
143
|
+
bases.updated_at,
|
|
144
|
+
COALESCE(stats.file_count, 0) AS file_count,
|
|
145
|
+
COALESCE(stats.word_count, 0) AS word_count
|
|
146
|
+
FROM knowledge_bases AS bases
|
|
147
|
+
LEFT JOIN (
|
|
148
|
+
SELECT
|
|
149
|
+
knowledgebase_id,
|
|
150
|
+
COUNT(*) AS file_count,
|
|
151
|
+
COALESCE(SUM(COALESCE(word_count, 0)), 0) AS word_count
|
|
152
|
+
FROM knowledge_files
|
|
153
|
+
GROUP BY knowledgebase_id
|
|
154
|
+
) AS stats ON stats.knowledgebase_id = bases.id
|
|
155
|
+
WHERE bases.id = ?
|
|
156
|
+
LIMIT 1
|
|
157
|
+
`).get(id);
|
|
158
|
+
return row ? this.mapKnowledgeBase(row) : null;
|
|
159
|
+
}
|
|
160
|
+
insertKnowledgeBase(base) {
|
|
161
|
+
this.db.prepare(`
|
|
162
|
+
INSERT INTO knowledge_bases (
|
|
163
|
+
id, name, description, folder_id, creator_name, icon, created_at, updated_at
|
|
164
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
165
|
+
`).run(base.id, base.name, base.description, base.folderId, base.creatorName, base.icon, base.createdAt, base.updatedAt);
|
|
166
|
+
return clone(base);
|
|
167
|
+
}
|
|
168
|
+
updateKnowledgeBase(base) {
|
|
169
|
+
const result = this.db.prepare(`
|
|
170
|
+
UPDATE knowledge_bases
|
|
171
|
+
SET name = ?, description = ?, folder_id = ?, creator_name = ?, icon = ?, updated_at = ?
|
|
172
|
+
WHERE id = ?
|
|
173
|
+
`).run(base.name, base.description, base.folderId, base.creatorName, base.icon, base.updatedAt, base.id);
|
|
174
|
+
if (Number(result.changes || 0) === 0) {
|
|
175
|
+
throw new Error('Knowledge base does not exist.');
|
|
176
|
+
}
|
|
177
|
+
return this.getKnowledgeBase(base.id) || clone(base);
|
|
178
|
+
}
|
|
179
|
+
touchKnowledgeBase(id, updatedAt) {
|
|
180
|
+
this.db.prepare('UPDATE knowledge_bases SET updated_at = ? WHERE id = ?').run(updatedAt, id);
|
|
181
|
+
}
|
|
182
|
+
deleteKnowledgeBase(id) {
|
|
183
|
+
this.transaction(() => {
|
|
184
|
+
this.db.prepare('DELETE FROM thread_knowledge_bases WHERE knowledge_base_id = ?').run(id);
|
|
185
|
+
this.db.prepare('DELETE FROM knowledge_files WHERE knowledgebase_id = ?').run(id);
|
|
186
|
+
this.db.prepare('DELETE FROM knowledge_bases WHERE id = ?').run(id);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
listKnowledgeBaseFiles(knowledgeBaseId) {
|
|
190
|
+
const rows = this.db.prepare(`
|
|
191
|
+
SELECT
|
|
192
|
+
knowledgebase_id,
|
|
193
|
+
file_id,
|
|
194
|
+
file_name,
|
|
195
|
+
file_type,
|
|
196
|
+
file_size,
|
|
197
|
+
folder,
|
|
198
|
+
create_time,
|
|
199
|
+
word_count,
|
|
200
|
+
metadata_json,
|
|
201
|
+
abstract,
|
|
202
|
+
full_content,
|
|
203
|
+
updated_at
|
|
204
|
+
FROM knowledge_files
|
|
205
|
+
WHERE knowledgebase_id = ?
|
|
206
|
+
ORDER BY create_time DESC, file_name COLLATE NOCASE ASC
|
|
207
|
+
`).all(knowledgeBaseId);
|
|
208
|
+
return rows.map((row) => this.mapKnowledgeFile(row));
|
|
209
|
+
}
|
|
210
|
+
upsertKnowledgeBaseFiles(files) {
|
|
211
|
+
if (files.length === 0) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const statement = this.db.prepare(`
|
|
215
|
+
INSERT INTO knowledge_files (
|
|
216
|
+
knowledgebase_id,
|
|
217
|
+
file_id,
|
|
218
|
+
file_name,
|
|
219
|
+
file_type,
|
|
220
|
+
file_size,
|
|
221
|
+
folder,
|
|
222
|
+
create_time,
|
|
223
|
+
word_count,
|
|
224
|
+
metadata_json,
|
|
225
|
+
abstract,
|
|
226
|
+
full_content,
|
|
227
|
+
updated_at
|
|
228
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
229
|
+
ON CONFLICT(file_id) DO UPDATE SET
|
|
230
|
+
knowledgebase_id = excluded.knowledgebase_id,
|
|
231
|
+
file_name = excluded.file_name,
|
|
232
|
+
file_type = excluded.file_type,
|
|
233
|
+
file_size = excluded.file_size,
|
|
234
|
+
folder = excluded.folder,
|
|
235
|
+
create_time = excluded.create_time,
|
|
236
|
+
word_count = excluded.word_count,
|
|
237
|
+
metadata_json = excluded.metadata_json,
|
|
238
|
+
abstract = excluded.abstract,
|
|
239
|
+
full_content = excluded.full_content,
|
|
240
|
+
updated_at = excluded.updated_at
|
|
241
|
+
`);
|
|
242
|
+
this.transaction(() => {
|
|
243
|
+
files.forEach((file) => {
|
|
244
|
+
statement.run(file.knowledgebaseId || null, file.fileId, file.fileName, file.fileType, file.fileSize, file.folder || null, file.createTime, file.wordCount ?? null, file.metadata ? JSON.stringify(file.metadata) : null, file.abstract || null, file.fullContent || null, new Date().toISOString());
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
deleteKnowledgeBaseFile(fileId) {
|
|
249
|
+
this.db.prepare('DELETE FROM knowledge_files WHERE file_id = ?').run(fileId);
|
|
250
|
+
}
|
|
251
|
+
listThreadKnowledgeBaseIds(threadId) {
|
|
252
|
+
const rows = this.db.prepare(`
|
|
253
|
+
SELECT thread_id, knowledge_base_id, created_at
|
|
254
|
+
FROM thread_knowledge_bases
|
|
255
|
+
WHERE thread_id = ?
|
|
256
|
+
ORDER BY created_at ASC, rowid ASC
|
|
257
|
+
`).all(threadId);
|
|
258
|
+
return rows.map((row) => row.knowledge_base_id);
|
|
259
|
+
}
|
|
260
|
+
replaceThreadKnowledgeBaseIds(threadId, knowledgeBaseIds) {
|
|
261
|
+
const uniqueIds = Array.from(new Set(knowledgeBaseIds.map((id) => String(id || '').trim()).filter(Boolean)));
|
|
262
|
+
const missingId = uniqueIds.find((knowledgeBaseId) => !this.getKnowledgeBase(knowledgeBaseId));
|
|
263
|
+
if (missingId) {
|
|
264
|
+
throw new Error(`Knowledge base does not exist: ${missingId}`);
|
|
265
|
+
}
|
|
266
|
+
this.transaction(() => {
|
|
267
|
+
this.db.prepare('DELETE FROM thread_knowledge_bases WHERE thread_id = ?').run(threadId);
|
|
268
|
+
if (uniqueIds.length === 0) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const insertStatement = this.db.prepare(`
|
|
272
|
+
INSERT INTO thread_knowledge_bases (
|
|
273
|
+
thread_id,
|
|
274
|
+
knowledge_base_id,
|
|
275
|
+
created_at
|
|
276
|
+
) VALUES (?, ?, ?)
|
|
277
|
+
`);
|
|
278
|
+
uniqueIds.forEach((knowledgeBaseId) => {
|
|
279
|
+
insertStatement.run(threadId, knowledgeBaseId, new Date().toISOString());
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
return uniqueIds;
|
|
283
|
+
}
|
|
284
|
+
deleteThreadKnowledgeBaseLinks(threadId) {
|
|
285
|
+
this.db.prepare('DELETE FROM thread_knowledge_bases WHERE thread_id = ?').run(threadId);
|
|
286
|
+
}
|
|
287
|
+
hasFolderChildren(id) {
|
|
288
|
+
const row = this.db.prepare(`
|
|
289
|
+
SELECT 1 AS value
|
|
290
|
+
FROM knowledge_folders
|
|
291
|
+
WHERE parent_id = ?
|
|
292
|
+
LIMIT 1
|
|
293
|
+
`).get(id);
|
|
294
|
+
return Boolean(row?.value);
|
|
295
|
+
}
|
|
296
|
+
hasKnowledgeBasesInFolder(id) {
|
|
297
|
+
const row = this.db.prepare(`
|
|
298
|
+
SELECT 1 AS value
|
|
299
|
+
FROM knowledge_bases
|
|
300
|
+
WHERE folder_id = ?
|
|
301
|
+
LIMIT 1
|
|
302
|
+
`).get(id);
|
|
303
|
+
return Boolean(row?.value);
|
|
304
|
+
}
|
|
305
|
+
runInTransaction(callback) {
|
|
306
|
+
return this.transaction(callback);
|
|
307
|
+
}
|
|
308
|
+
initializeSchema() {
|
|
309
|
+
this.db.exec('PRAGMA foreign_keys = ON;');
|
|
310
|
+
this.db.exec(`
|
|
311
|
+
CREATE TABLE IF NOT EXISTS meta (
|
|
312
|
+
key TEXT PRIMARY KEY,
|
|
313
|
+
value TEXT NOT NULL
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
CREATE TABLE IF NOT EXISTS knowledge_folders (
|
|
317
|
+
id TEXT PRIMARY KEY,
|
|
318
|
+
name TEXT NOT NULL,
|
|
319
|
+
parent_id TEXT,
|
|
320
|
+
path TEXT NOT NULL,
|
|
321
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
322
|
+
created_at TEXT NOT NULL,
|
|
323
|
+
updated_at TEXT NOT NULL
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
CREATE TABLE IF NOT EXISTS knowledge_bases (
|
|
327
|
+
id TEXT PRIMARY KEY,
|
|
328
|
+
name TEXT NOT NULL,
|
|
329
|
+
description TEXT NOT NULL DEFAULT '',
|
|
330
|
+
folder_id TEXT,
|
|
331
|
+
creator_name TEXT NOT NULL,
|
|
332
|
+
icon TEXT NOT NULL,
|
|
333
|
+
created_at TEXT NOT NULL,
|
|
334
|
+
updated_at TEXT NOT NULL
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
CREATE TABLE IF NOT EXISTS knowledge_files (
|
|
338
|
+
file_id TEXT PRIMARY KEY,
|
|
339
|
+
knowledgebase_id TEXT,
|
|
340
|
+
file_name TEXT NOT NULL,
|
|
341
|
+
file_type TEXT NOT NULL,
|
|
342
|
+
file_size INTEGER NOT NULL DEFAULT 0,
|
|
343
|
+
folder TEXT,
|
|
344
|
+
create_time TEXT NOT NULL,
|
|
345
|
+
word_count INTEGER,
|
|
346
|
+
metadata_json TEXT,
|
|
347
|
+
abstract TEXT,
|
|
348
|
+
full_content TEXT,
|
|
349
|
+
updated_at TEXT NOT NULL
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
CREATE TABLE IF NOT EXISTS thread_knowledge_bases (
|
|
353
|
+
thread_id TEXT NOT NULL,
|
|
354
|
+
knowledge_base_id TEXT NOT NULL,
|
|
355
|
+
created_at TEXT NOT NULL,
|
|
356
|
+
PRIMARY KEY (thread_id, knowledge_base_id)
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
CREATE INDEX IF NOT EXISTS idx_knowledge_folders_parent_id
|
|
360
|
+
ON knowledge_folders (parent_id);
|
|
361
|
+
CREATE INDEX IF NOT EXISTS idx_knowledge_bases_folder_id
|
|
362
|
+
ON knowledge_bases (folder_id);
|
|
363
|
+
CREATE INDEX IF NOT EXISTS idx_knowledge_files_knowledgebase_id
|
|
364
|
+
ON knowledge_files (knowledgebase_id);
|
|
365
|
+
CREATE INDEX IF NOT EXISTS idx_knowledge_files_create_time
|
|
366
|
+
ON knowledge_files (create_time DESC);
|
|
367
|
+
CREATE INDEX IF NOT EXISTS idx_thread_knowledge_bases_thread_id
|
|
368
|
+
ON thread_knowledge_bases (thread_id);
|
|
369
|
+
`);
|
|
370
|
+
this.db.prepare(`
|
|
371
|
+
INSERT INTO meta (key, value)
|
|
372
|
+
VALUES ('schema_version', ?)
|
|
373
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value
|
|
374
|
+
`).run(SCHEMA_VERSION);
|
|
375
|
+
}
|
|
376
|
+
migrateLegacyJson() {
|
|
377
|
+
if (!(0, node_fs_1.existsSync)(this.legacyStorePath)) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
if ((0, node_fs_1.existsSync)(this.legacyBackupPath)) {
|
|
381
|
+
(0, node_fs_1.unlinkSync)(this.legacyBackupPath);
|
|
382
|
+
}
|
|
383
|
+
(0, node_fs_1.renameSync)(this.legacyStorePath, this.legacyBackupPath);
|
|
384
|
+
try {
|
|
385
|
+
const raw = JSON.parse((0, node_fs_1.readFileSync)(this.legacyBackupPath, 'utf8'));
|
|
386
|
+
const folders = Array.isArray(raw.folders) ? raw.folders : [];
|
|
387
|
+
const knowledgeBases = Array.isArray(raw.knowledgeBases) ? raw.knowledgeBases : [];
|
|
388
|
+
this.transaction(() => {
|
|
389
|
+
const insertFolder = this.db.prepare(`
|
|
390
|
+
INSERT INTO knowledge_folders (
|
|
391
|
+
id, name, parent_id, path, sort_order, created_at, updated_at
|
|
392
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
393
|
+
`);
|
|
394
|
+
const insertKnowledgeBase = this.db.prepare(`
|
|
395
|
+
INSERT INTO knowledge_bases (
|
|
396
|
+
id, name, description, folder_id, creator_name, icon, created_at, updated_at
|
|
397
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
398
|
+
`);
|
|
399
|
+
folders.forEach((folder) => {
|
|
400
|
+
insertFolder.run(folder.id, folder.name, folder.parentId || null, folder.path, folder.sortOrder, folder.createdAt, folder.updatedAt);
|
|
401
|
+
});
|
|
402
|
+
knowledgeBases.forEach((base) => {
|
|
403
|
+
insertKnowledgeBase.run(base.id, base.name, base.description, base.folderId || null, base.creatorName, base.icon, base.createdAt, base.updatedAt);
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
if ((0, node_fs_1.existsSync)(this.legacyBackupPath) && !(0, node_fs_1.existsSync)(this.legacyStorePath)) {
|
|
409
|
+
(0, node_fs_1.renameSync)(this.legacyBackupPath, this.legacyStorePath);
|
|
410
|
+
}
|
|
411
|
+
throw error;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
transaction(callback) {
|
|
415
|
+
this.db.exec('BEGIN IMMEDIATE');
|
|
416
|
+
try {
|
|
417
|
+
const result = callback();
|
|
418
|
+
this.db.exec('COMMIT');
|
|
419
|
+
return result;
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
this.db.exec('ROLLBACK');
|
|
423
|
+
throw error;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
mapFolder(row) {
|
|
427
|
+
return {
|
|
428
|
+
id: row.id,
|
|
429
|
+
name: row.name,
|
|
430
|
+
parentId: row.parent_id,
|
|
431
|
+
path: row.path,
|
|
432
|
+
sortOrder: Number(row.sort_order || 0),
|
|
433
|
+
createdAt: row.created_at,
|
|
434
|
+
updatedAt: row.updated_at,
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
mapKnowledgeBase(row) {
|
|
438
|
+
return {
|
|
439
|
+
id: row.id,
|
|
440
|
+
name: row.name,
|
|
441
|
+
description: row.description,
|
|
442
|
+
folderId: row.folder_id,
|
|
443
|
+
creatorName: row.creator_name,
|
|
444
|
+
icon: row.icon,
|
|
445
|
+
fileCount: Number(row.file_count || 0),
|
|
446
|
+
wordCount: Number(row.word_count || 0),
|
|
447
|
+
createdAt: row.created_at,
|
|
448
|
+
updatedAt: row.updated_at,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
mapKnowledgeFile(row) {
|
|
452
|
+
return {
|
|
453
|
+
knowledgebaseId: row.knowledgebase_id,
|
|
454
|
+
fileId: row.file_id,
|
|
455
|
+
fileName: row.file_name,
|
|
456
|
+
fileType: row.file_type,
|
|
457
|
+
fileSize: Number(row.file_size || 0),
|
|
458
|
+
folder: row.folder,
|
|
459
|
+
createTime: row.create_time,
|
|
460
|
+
wordCount: typeof row.word_count === 'number' ? row.word_count : null,
|
|
461
|
+
metadata: parseMetadata(row.metadata_json),
|
|
462
|
+
abstract: row.abstract,
|
|
463
|
+
fullContent: row.full_content,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
exports.KnowledgeSqliteStore = KnowledgeSqliteStore;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SqliteThreadKnowledgeAttachmentStore = void 0;
|
|
4
|
+
const sqlite_store_js_1 = require("./sqlite-store.js");
|
|
5
|
+
class SqliteThreadKnowledgeAttachmentStore {
|
|
6
|
+
store;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.store = new sqlite_store_js_1.KnowledgeSqliteStore({ userDataPath: options.userDataPath });
|
|
9
|
+
}
|
|
10
|
+
async listThreadKnowledgeBaseIds(threadId) {
|
|
11
|
+
return this.store.listThreadKnowledgeBaseIds(threadId);
|
|
12
|
+
}
|
|
13
|
+
async updateThreadKnowledgeBaseIds(threadId, knowledgeBaseIds) {
|
|
14
|
+
return this.store.replaceThreadKnowledgeBaseIds(threadId, knowledgeBaseIds);
|
|
15
|
+
}
|
|
16
|
+
async deleteThreadKnowledgeBaseLinks(threadId) {
|
|
17
|
+
this.store.deleteThreadKnowledgeBaseLinks(threadId);
|
|
18
|
+
return { deleted: true };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.SqliteThreadKnowledgeAttachmentStore = SqliteThreadKnowledgeAttachmentStore;
|