opcode-pg-memory 2.2.8 → 2.3.0

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.
Files changed (76) hide show
  1. package/dist/cli.js +232 -214
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +30 -21006
  5. package/dist/index.js.map +1 -0
  6. package/dist/mcp-server.js +319 -302
  7. package/dist/mcp-server.js.map +1 -0
  8. package/dist/src/cache/semantic-cache.js +399 -0
  9. package/dist/src/cache/semantic-cache.js.map +1 -0
  10. package/dist/src/cli.js +404 -0
  11. package/dist/src/cli.js.map +1 -0
  12. package/dist/src/config.d.ts +5 -0
  13. package/dist/src/config.d.ts.map +1 -1
  14. package/dist/src/config.js +89 -0
  15. package/dist/src/config.js.map +1 -0
  16. package/dist/src/db/init-db.js +545 -0
  17. package/dist/src/db/init-db.js.map +1 -0
  18. package/dist/src/hooks/message-part-updated.js +203 -0
  19. package/dist/src/hooks/message-part-updated.js.map +1 -0
  20. package/dist/src/hooks/message-updated.js +347 -0
  21. package/dist/src/hooks/message-updated.js.map +1 -0
  22. package/dist/src/hooks/session-compacting.js +179 -0
  23. package/dist/src/hooks/session-compacting.js.map +1 -0
  24. package/dist/src/hooks/session-completed.js +337 -0
  25. package/dist/src/hooks/session-completed.js.map +1 -0
  26. package/dist/src/hooks/session-created.js +206 -0
  27. package/dist/src/hooks/session-created.js.map +1 -0
  28. package/dist/src/hooks/tool-execute.js +267 -0
  29. package/dist/src/hooks/tool-execute.js.map +1 -0
  30. package/dist/src/index.d.ts +1 -0
  31. package/dist/src/index.d.ts.map +1 -1
  32. package/dist/src/index.js +643 -0
  33. package/dist/src/index.js.map +1 -0
  34. package/dist/src/mcp/hindsight-reflect-omo.js +318 -0
  35. package/dist/src/mcp/hindsight-reflect-omo.js.map +1 -0
  36. package/dist/src/mcp/hindsight-reflect.js +838 -0
  37. package/dist/src/mcp/hindsight-reflect.js.map +1 -0
  38. package/dist/src/mcp/recall-memory-omo.js +263 -0
  39. package/dist/src/mcp/recall-memory-omo.js.map +1 -0
  40. package/dist/src/mcp/recall-memory.d.ts +6 -0
  41. package/dist/src/mcp/recall-memory.d.ts.map +1 -1
  42. package/dist/src/mcp/recall-memory.js +900 -0
  43. package/dist/src/mcp/recall-memory.js.map +1 -0
  44. package/dist/src/omo/adapter.js +583 -0
  45. package/dist/src/omo/adapter.js.map +1 -0
  46. package/dist/src/omo/types.js +44 -0
  47. package/dist/src/omo/types.js.map +1 -0
  48. package/dist/src/services/db-polling.d.ts +30 -0
  49. package/dist/src/services/db-polling.d.ts.map +1 -0
  50. package/dist/src/services/db-polling.js +97 -0
  51. package/dist/src/services/db-polling.js.map +1 -0
  52. package/dist/src/services/event-synchronizer.d.ts +15 -0
  53. package/dist/src/services/event-synchronizer.d.ts.map +1 -0
  54. package/dist/src/services/event-synchronizer.js +119 -0
  55. package/dist/src/services/event-synchronizer.js.map +1 -0
  56. package/dist/src/services/keyword.js +29 -0
  57. package/dist/src/services/keyword.js.map +1 -0
  58. package/dist/src/services/logger.js +42 -0
  59. package/dist/src/services/logger.js.map +1 -0
  60. package/dist/src/services/opencode-schema-adapter.d.ts +34 -0
  61. package/dist/src/services/opencode-schema-adapter.d.ts.map +1 -0
  62. package/dist/src/services/opencode-schema-adapter.js +96 -0
  63. package/dist/src/services/opencode-schema-adapter.js.map +1 -0
  64. package/dist/src/services/privacy.js +23 -0
  65. package/dist/src/services/privacy.js.map +1 -0
  66. package/dist/src/topic/segment-manager.js +447 -0
  67. package/dist/src/topic/segment-manager.js.map +1 -0
  68. package/dist/src/types.d.ts +20 -2
  69. package/dist/src/types.d.ts.map +1 -1
  70. package/dist/src/types.js +8 -0
  71. package/dist/src/types.js.map +1 -0
  72. package/dist/src/utils/embedding.js +180 -0
  73. package/dist/src/utils/embedding.js.map +1 -0
  74. package/dist/src/utils/token-budget.js +152 -0
  75. package/dist/src/utils/token-budget.js.map +1 -0
  76. package/package.json +6 -5
@@ -0,0 +1,545 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DatabaseInitializer = exports.DEFAULT_DB_CONFIG = void 0;
7
+ exports.getDatabaseInitializer = getDatabaseInitializer;
8
+ exports.initializeDatabase = initializeDatabase;
9
+ exports.closeDatabase = closeDatabase;
10
+ const pg_1 = require("pg");
11
+ const pgvector_1 = __importDefault(require("pgvector"));
12
+ const logger_1 = require("../services/logger");
13
+ exports.DEFAULT_DB_CONFIG = {
14
+ host: process.env.PG_HOST || 'localhost',
15
+ port: parseInt(process.env.PG_PORT || '5432', 10),
16
+ database: process.env.PG_DATABASE || 'opencode_memory',
17
+ user: process.env.PG_USER || 'opencode',
18
+ password: process.env.PG_PASSWORD || '',
19
+ ssl: process.env.PG_SSL === 'true',
20
+ maxConnections: parseInt(process.env.PG_MAX_CONNECTIONS || '20', 10)
21
+ };
22
+ class DatabaseInitializer {
23
+ pool = null;
24
+ config;
25
+ logger = (0, logger_1.createLogger)('init-db');
26
+ constructor(config = {}) {
27
+ this.config = { ...exports.DEFAULT_DB_CONFIG, ...config };
28
+ }
29
+ async initialize() {
30
+ if (this.pool) {
31
+ return this.pool;
32
+ }
33
+ this.pool = new pg_1.Pool({
34
+ host: this.config.host,
35
+ port: this.config.port,
36
+ database: this.config.database,
37
+ user: this.config.user,
38
+ password: this.config.password,
39
+ ssl: this.config.ssl,
40
+ max: this.config.maxConnections
41
+ });
42
+ // 注册 pgvector 类型
43
+ // @ts-ignore - pgvector types may vary
44
+ pgvector_1.default.registerTypes?.(this.pool);
45
+ // 测试连接
46
+ await this.testConnection();
47
+ // 初始化数据库结构
48
+ await this.setupDatabase();
49
+ return this.pool;
50
+ }
51
+ async testConnection() {
52
+ try {
53
+ const client = await this.pool.connect();
54
+ const result = await client.query('SELECT NOW() as now');
55
+ client.release();
56
+ this.logger.info('Database connected:', result.rows[0].now);
57
+ }
58
+ catch (error) {
59
+ this.logger.error('Database connection failed:', error);
60
+ throw new Error(`Failed to connect to PostgreSQL: ${error}`);
61
+ }
62
+ }
63
+ async setupDatabase() {
64
+ const client = await this.pool.connect();
65
+ try {
66
+ await client.query('BEGIN');
67
+ // 1. 启用 pgvector 扩展
68
+ await this.createExtensions(client);
69
+ // 2. 创建枚举类型
70
+ await this.createEnums(client);
71
+ // 3. 创建表
72
+ await this.createTables(client);
73
+ // 4. 迁移旧列名(session_id → session_map_id)
74
+ await this.migrateLegacyColumnNames(client);
75
+ // 5. 创建索引
76
+ await this.createIndexes(client);
77
+ // 6. 迁移旧 sessions 数据到 session_map
78
+ await this.migrateSessionsData(client);
79
+ // 6. 初始化 OmO 适配 Schema(如果启用)
80
+ await this.initializeOmOSchema(client);
81
+ await client.query('COMMIT');
82
+ this.logger.info('Database schema initialized successfully');
83
+ }
84
+ catch (error) {
85
+ await client.query('ROLLBACK');
86
+ this.logger.error('Database setup failed:', error);
87
+ throw error;
88
+ }
89
+ finally {
90
+ client.release();
91
+ }
92
+ }
93
+ async createExtensions(client) {
94
+ await client.query(`
95
+ CREATE EXTENSION IF NOT EXISTS vector;
96
+ CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
97
+ `);
98
+ this.logger.info('Extensions created');
99
+ }
100
+ async createEnums(client) {
101
+ await client.query(`
102
+ DO $$
103
+ BEGIN
104
+ IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entity_tier') THEN
105
+ CREATE TYPE entity_tier AS ENUM ('permanent', 'project', 'session');
106
+ END IF;
107
+
108
+ IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'relation_type') THEN
109
+ CREATE TYPE relation_type AS ENUM ('belongs_to', 'depends_on', 'references', 'implements', 'uses', 'custom');
110
+ END IF;
111
+ END $$;
112
+ `);
113
+ this.logger.info('Enums created');
114
+ }
115
+ async createTables(client) {
116
+ // ── session_map 表(替代旧 sessions 表,旧表保留为历史数据) ──
117
+ await client.query(`
118
+ CREATE TABLE IF NOT EXISTS session_map (
119
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
120
+ opencode_session_id VARCHAR(255) UNIQUE NOT NULL,
121
+ omo_task_id VARCHAR(255),
122
+ project_id VARCHAR(255),
123
+ model_context_limit INTEGER NOT NULL DEFAULT 128000,
124
+ created_at TIMESTAMPTZ DEFAULT NOW(),
125
+ last_active_at TIMESTAMPTZ DEFAULT NOW(),
126
+ metadata JSONB DEFAULT '{}'
127
+ );
128
+ `);
129
+ // ── topic_segments 表(NEW:会话内话题分段) ──
130
+ await client.query(`
131
+ CREATE TABLE IF NOT EXISTS topic_segments (
132
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
133
+ session_map_id UUID NOT NULL REFERENCES session_map(id) ON DELETE CASCADE,
134
+ segment_index INTEGER NOT NULL,
135
+ summary TEXT,
136
+ embedding vector(1536),
137
+ start_message_external_id VARCHAR(255),
138
+ end_message_external_id VARCHAR(255),
139
+ created_at TIMESTAMPTZ DEFAULT NOW(),
140
+ closed_at TIMESTAMPTZ,
141
+ observation_count INTEGER DEFAULT 0,
142
+ metadata JSONB DEFAULT '{}',
143
+ UNIQUE(session_map_id, segment_index)
144
+ );
145
+ `);
146
+ // ── entities 表 ──
147
+ await client.query(`
148
+ CREATE TABLE IF NOT EXISTS entities (
149
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
150
+ session_map_id UUID REFERENCES session_map(id) ON DELETE CASCADE,
151
+ topic_segment_id UUID REFERENCES topic_segments(id) ON DELETE SET NULL,
152
+ name VARCHAR(500) NOT NULL,
153
+ type VARCHAR(100) NOT NULL,
154
+ tier entity_tier DEFAULT 'session',
155
+ weight FLOAT DEFAULT 1.0 CHECK (weight >= 0 AND weight <= 10),
156
+ description TEXT,
157
+ embedding vector(1536),
158
+ first_seen_at TIMESTAMPTZ DEFAULT NOW(),
159
+ last_seen_at TIMESTAMPTZ DEFAULT NOW(),
160
+ confidence FLOAT DEFAULT 0.8 CHECK (confidence >= 0 AND confidence <= 1),
161
+ metadata JSONB DEFAULT '{}'
162
+ );
163
+ `);
164
+ // ── relations 表 ──
165
+ await client.query(`
166
+ CREATE TABLE IF NOT EXISTS relations (
167
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
168
+ source_entity_id UUID REFERENCES entities(id) ON DELETE CASCADE,
169
+ target_entity_id UUID REFERENCES entities(id) ON DELETE CASCADE,
170
+ relation_type relation_type NOT NULL,
171
+ confidence FLOAT DEFAULT 0.8 CHECK (confidence >= 0 AND confidence <= 1),
172
+ description TEXT,
173
+ created_at TIMESTAMPTZ DEFAULT NOW(),
174
+ session_map_id UUID REFERENCES session_map(id) ON DELETE CASCADE,
175
+ topic_segment_id UUID REFERENCES topic_segments(id) ON DELETE SET NULL,
176
+ CONSTRAINT chk_different_entities CHECK (source_entity_id != target_entity_id)
177
+ );
178
+ `);
179
+ // ── observations 表 ──
180
+ await client.query(`
181
+ CREATE TABLE IF NOT EXISTS observations (
182
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
183
+ session_map_id UUID REFERENCES session_map(id) ON DELETE CASCADE,
184
+ topic_segment_id UUID REFERENCES topic_segments(id) ON DELETE SET NULL,
185
+ tool_name VARCHAR(255),
186
+ tool_input_summary TEXT,
187
+ tool_output_summary TEXT,
188
+ embedding vector(1536),
189
+ importance INTEGER DEFAULT 3 CHECK (importance >= 1 AND importance <= 5),
190
+ created_at TIMESTAMPTZ DEFAULT NOW(),
191
+ message_id VARCHAR(255),
192
+ metadata JSONB DEFAULT '{}'
193
+ );
194
+ `);
195
+ // ── reflections 表 ──
196
+ await client.query(`
197
+ CREATE TABLE IF NOT EXISTS reflections (
198
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
199
+ session_map_id UUID REFERENCES session_map(id) ON DELETE CASCADE,
200
+ topic_segment_id UUID REFERENCES topic_segments(id) ON DELETE SET NULL,
201
+ summary TEXT NOT NULL,
202
+ source_observation_ids UUID[],
203
+ confidence FLOAT DEFAULT 0.8 CHECK (confidence >= 0 AND confidence <= 1),
204
+ pattern_type VARCHAR(100),
205
+ created_at TIMESTAMPTZ DEFAULT NOW(),
206
+ embedding vector(1536),
207
+ metadata JSONB DEFAULT '{}'
208
+ );
209
+ `);
210
+ // ── reflection_errors 表 ──
211
+ await client.query(`
212
+ CREATE TABLE IF NOT EXISTS reflection_errors (
213
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
214
+ session_map_id UUID REFERENCES session_map(id) ON DELETE CASCADE,
215
+ error_message TEXT NOT NULL,
216
+ error_stack TEXT,
217
+ observation_count INTEGER,
218
+ created_at TIMESTAMPTZ DEFAULT NOW(),
219
+ retry_count INTEGER DEFAULT 0
220
+ );
221
+ `);
222
+ // ── semantic_cache 表 ──
223
+ await client.query(`
224
+ CREATE TABLE IF NOT EXISTS semantic_cache (
225
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
226
+ query_hash VARCHAR(64) UNIQUE NOT NULL,
227
+ query_text TEXT NOT NULL,
228
+ query_embedding vector(1536) NOT NULL,
229
+ response_text TEXT NOT NULL,
230
+ hit_count INTEGER DEFAULT 1,
231
+ last_hit_at TIMESTAMPTZ DEFAULT NOW(),
232
+ created_at TIMESTAMPTZ DEFAULT NOW(),
233
+ similarity_threshold FLOAT DEFAULT 0.92,
234
+ is_pruned BOOLEAN DEFAULT FALSE,
235
+ session_map_id UUID REFERENCES session_map(id) ON DELETE SET NULL,
236
+ topic_segment_id UUID REFERENCES topic_segments(id) ON DELETE SET NULL
237
+ );
238
+ `);
239
+ // ── token_usage_log 表 ──
240
+ await client.query(`
241
+ CREATE TABLE IF NOT EXISTS token_usage_log (
242
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
243
+ session_map_id UUID REFERENCES session_map(id) ON DELETE CASCADE,
244
+ operation_type VARCHAR(100) NOT NULL,
245
+ tokens_used INTEGER NOT NULL,
246
+ model_name VARCHAR(100),
247
+ created_at TIMESTAMPTZ DEFAULT NOW(),
248
+ metadata JSONB DEFAULT '{}'
249
+ );
250
+ `);
251
+ // ── cache_threshold_log 表 ──
252
+ await client.query(`
253
+ CREATE TABLE IF NOT EXISTS cache_threshold_log (
254
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
255
+ threshold_value FLOAT NOT NULL,
256
+ hit_rate FLOAT,
257
+ query_count INTEGER,
258
+ adjustment_reason VARCHAR(50),
259
+ created_at TIMESTAMPTZ DEFAULT NOW()
260
+ );
261
+ `);
262
+ this.logger.info('Tables created');
263
+ }
264
+ async createIndexes(client) {
265
+ // ── session_map 表索引 ──
266
+ await client.query(`
267
+ CREATE INDEX IF NOT EXISTS idx_session_map_opencode_id ON session_map(opencode_session_id);
268
+ CREATE INDEX IF NOT EXISTS idx_session_map_omo_task_id ON session_map(omo_task_id);
269
+ CREATE INDEX IF NOT EXISTS idx_session_map_project_id ON session_map(project_id);
270
+ `);
271
+ // ── topic_segments 表索引 ──
272
+ await client.query(`
273
+ CREATE INDEX IF NOT EXISTS idx_topic_segments_session ON topic_segments(session_map_id);
274
+ `);
275
+ // HNSW 索引 for topic_segments
276
+ await client.query(`
277
+ CREATE INDEX IF NOT EXISTS idx_topic_segments_embedding ON topic_segments
278
+ USING hnsw (embedding vector_cosine_ops)
279
+ WITH (m = 16, ef_construction = 64);
280
+ `);
281
+ // ── entities 表索引 ──
282
+ await client.query(`
283
+ CREATE INDEX IF NOT EXISTS idx_entities_session_map_type ON entities(session_map_id, type);
284
+ CREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name);
285
+ CREATE INDEX IF NOT EXISTS idx_entities_tier_weight ON entities(tier, weight DESC) WHERE weight >= 0.3;
286
+ CREATE INDEX IF NOT EXISTS idx_entities_topic_segment ON entities(topic_segment_id);
287
+ `);
288
+ // HNSW 索引 for entities
289
+ await client.query(`
290
+ CREATE INDEX IF NOT EXISTS idx_entities_embedding ON entities
291
+ USING hnsw (embedding vector_cosine_ops)
292
+ WITH (m = 16, ef_construction = 64);
293
+ `);
294
+ // ── relations 表索引 ──
295
+ await client.query(`
296
+ CREATE INDEX IF NOT EXISTS idx_relations_source ON relations(source_entity_id);
297
+ CREATE INDEX IF NOT EXISTS idx_relations_target ON relations(target_entity_id);
298
+ CREATE INDEX IF NOT EXISTS idx_relations_session_map ON relations(session_map_id);
299
+ CREATE INDEX IF NOT EXISTS idx_relations_confidence ON relations(confidence) WHERE confidence >= 0.5;
300
+ CREATE INDEX IF NOT EXISTS idx_relations_topic_segment ON relations(topic_segment_id);
301
+ `);
302
+ // ── observations 表索引 ──
303
+ await client.query(`
304
+ CREATE INDEX IF NOT EXISTS idx_observations_session_map ON observations(session_map_id);
305
+ CREATE INDEX IF NOT EXISTS idx_observations_importance ON observations(importance DESC);
306
+ CREATE INDEX IF NOT EXISTS idx_observations_created_at ON observations(created_at DESC);
307
+ CREATE INDEX IF NOT EXISTS idx_observations_topic_segment ON observations(topic_segment_id);
308
+ `);
309
+ // HNSW 索引 for observations
310
+ await client.query(`
311
+ CREATE INDEX IF NOT EXISTS idx_observations_embedding ON observations
312
+ USING hnsw (embedding vector_cosine_ops)
313
+ WITH (m = 16, ef_construction = 64);
314
+ `);
315
+ // ── reflections 表索引 ──
316
+ await client.query(`
317
+ CREATE INDEX IF NOT EXISTS idx_reflections_session_map ON reflections(session_map_id);
318
+ CREATE INDEX IF NOT EXISTS idx_reflections_pattern ON reflections(pattern_type);
319
+ CREATE INDEX IF NOT EXISTS idx_reflections_confidence ON reflections(confidence) WHERE confidence >= 0.6;
320
+ CREATE INDEX IF NOT EXISTS idx_reflections_topic_segment ON reflections(topic_segment_id);
321
+ `);
322
+ // HNSW 索引 for reflections
323
+ await client.query(`
324
+ CREATE INDEX IF NOT EXISTS idx_reflections_embedding ON reflections
325
+ USING hnsw (embedding vector_cosine_ops)
326
+ WITH (m = 16, ef_construction = 64);
327
+ `);
328
+ // ── reflection_errors 表索引 ──
329
+ await client.query(`
330
+ CREATE INDEX IF NOT EXISTS idx_reflection_errors_session_map ON reflection_errors(session_map_id);
331
+ CREATE INDEX IF NOT EXISTS idx_reflection_errors_created_at ON reflection_errors(created_at DESC);
332
+ `);
333
+ // ── semantic_cache 表索引 ──
334
+ await client.query(`
335
+ CREATE INDEX IF NOT EXISTS idx_semantic_cache_hash ON semantic_cache(query_hash);
336
+ CREATE INDEX IF NOT EXISTS idx_semantic_cache_hit_count ON semantic_cache(hit_count DESC);
337
+ CREATE INDEX IF NOT EXISTS idx_semantic_cache_last_hit ON semantic_cache(last_hit_at DESC);
338
+ CREATE INDEX IF NOT EXISTS idx_semantic_cache_pruned ON semantic_cache(is_pruned) WHERE is_pruned = FALSE;
339
+ CREATE INDEX IF NOT EXISTS idx_semantic_cache_session_map ON semantic_cache(session_map_id);
340
+ CREATE INDEX IF NOT EXISTS idx_semantic_cache_topic_segment ON semantic_cache(topic_segment_id);
341
+ `);
342
+ // HNSW 索引 for semantic_cache
343
+ await client.query(`
344
+ CREATE INDEX IF NOT EXISTS idx_semantic_cache_embedding ON semantic_cache
345
+ USING hnsw (query_embedding vector_cosine_ops)
346
+ WITH (m = 16, ef_construction = 64);
347
+ `);
348
+ // ── token_usage_log 表索引 ──
349
+ await client.query(`
350
+ CREATE INDEX IF NOT EXISTS idx_token_usage_session_map ON token_usage_log(session_map_id);
351
+ CREATE INDEX IF NOT EXISTS idx_token_usage_operation ON token_usage_log(operation_type);
352
+ CREATE INDEX IF NOT EXISTS idx_token_usage_created_at ON token_usage_log(created_at DESC);
353
+ `);
354
+ // ── cache_threshold_log 表索引 ──
355
+ await client.query(`
356
+ CREATE INDEX IF NOT EXISTS idx_cache_threshold_created_at ON cache_threshold_log(created_at DESC);
357
+ `);
358
+ // ── 移除旧 sessions 表索引(如果存在) ──
359
+ // 旧 sessions 表保留为历史数据;新系统使用 session_map
360
+ await client.query(`
361
+ DROP INDEX IF EXISTS idx_sessions_external_id;
362
+ DROP INDEX IF EXISTS idx_sessions_project_id;
363
+ DROP INDEX IF EXISTS idx_sessions_reflection_last_at;
364
+ `);
365
+ // 移除旧子表 session_id 索引(如果存在)
366
+ await client.query(`
367
+ DROP INDEX IF EXISTS idx_entities_session_type;
368
+ DROP INDEX IF EXISTS idx_relations_session;
369
+ DROP INDEX IF EXISTS idx_observations_session;
370
+ DROP INDEX IF EXISTS idx_reflections_session;
371
+ DROP INDEX IF EXISTS idx_reflection_errors_session;
372
+ DROP INDEX IF EXISTS idx_token_usage_session;
373
+ `);
374
+ this.logger.info('Indexes created');
375
+ }
376
+ /**
377
+ * 迁移旧列名 session_id → session_map_id
378
+ *
379
+ * 兼容从 v1.x 升级的场景:旧 schema 中 entities/observations 等子表
380
+ * 使用 session_id 列名,但新 schema 使用 session_map_id。
381
+ * 重命名是 PostgreSQL 元数据操作,不重写数据行,FK 关联自动继承新列名。
382
+ */
383
+ async migrateLegacyColumnNames(client) {
384
+ const tables = ['entities', 'observations', 'relations', 'reflections',
385
+ 'semantic_cache', 'token_usage_log', 'reflection_errors'];
386
+ for (const table of tables) {
387
+ try {
388
+ // 检查表是否存在且包含旧列名 session_id 但不含 session_map_id
389
+ const hasOld = await client.query(`
390
+ SELECT 1 FROM information_schema.columns
391
+ WHERE table_schema = 'public' AND table_name = $1 AND column_name = 'session_id'
392
+ `, [table]);
393
+ const hasNew = await client.query(`
394
+ SELECT 1 FROM information_schema.columns
395
+ WHERE table_schema = 'public' AND table_name = $1 AND column_name = 'session_map_id'
396
+ `, [table]);
397
+ if (hasOld.rows.length > 0 && hasNew.rows.length === 0) {
398
+ await client.query(`
399
+ ALTER TABLE "${table}" RENAME COLUMN session_id TO session_map_id
400
+ `);
401
+ this.logger.info(`Renamed ${table}.session_id → session_map_id`);
402
+ }
403
+ }
404
+ catch (err) {
405
+ // 某些表可能没有旧列名(新安装),静默跳过
406
+ this.logger.info(`Skipped column rename for ${table}: ${err}`);
407
+ }
408
+ }
409
+ this.logger.info('Legacy column migration complete');
410
+ }
411
+ /**
412
+ * 将旧 sessions 表的数据迁移到新的 session_map 表。
413
+ * 旧 sessions 表保留不删除(_legacy),仅复制元数据映射。
414
+ * 注意:子表(entities/observations 等)的 session_map_id 不会自动填充,
415
+ * 需要单独的迁移脚本处理 FK 重映射。
416
+ */
417
+ async migrateSessionsData(client) {
418
+ try {
419
+ const exists = await client.query(`
420
+ SELECT 1 FROM information_schema.tables
421
+ WHERE table_schema = 'public' AND table_name = 'sessions'
422
+ `);
423
+ if (exists.rows.length === 0) {
424
+ this.logger.info('No legacy sessions table found, skipping migration');
425
+ return;
426
+ }
427
+ // 注释旧表为 legacy 标记
428
+ await client.query(`
429
+ COMMENT ON TABLE sessions IS '_legacy: replaced by session_map. Retained for data safety.';
430
+ `);
431
+ await client.query(`
432
+ INSERT INTO session_map (opencode_session_id, project_id, model_context_limit, created_at, last_active_at, metadata)
433
+ SELECT external_id, project_id, model_context_limit, created_at, updated_at, metadata
434
+ FROM sessions
435
+ ON CONFLICT (opencode_session_id) DO NOTHING;
436
+ `);
437
+ this.logger.info('Legacy sessions data migrated to session_map');
438
+ }
439
+ catch (error) {
440
+ this.logger.warn('Sessions migration warning (non-fatal):', error);
441
+ }
442
+ }
443
+ async initializeOmOSchema(client) {
444
+ // 检查是否需要 OmO 支持
445
+ const omOEnabled = process.env.OMO_ENABLED === 'true' ||
446
+ process.env.OMO_INTEGRATION === 'enabled';
447
+ if (!omOEnabled) {
448
+ this.logger.info('OmO integration not enabled, skipping OmO schema');
449
+ return;
450
+ }
451
+ this.logger.info('Initializing OmO schema...');
452
+ // 1. 添加 source_agent 字段到相关表
453
+ const tablesWithAgent = ['observations', 'semantic_cache', 'entities', 'reflections'];
454
+ for (const table of tablesWithAgent) {
455
+ try {
456
+ await client.query(`
457
+ ALTER TABLE ${table}
458
+ ADD COLUMN IF NOT EXISTS source_agent VARCHAR(255),
459
+ ADD COLUMN IF NOT EXISTS agent_task_id VARCHAR(255)
460
+ `);
461
+ // 创建索引
462
+ await client.query(`
463
+ CREATE INDEX IF NOT EXISTS idx_${table}_source_agent ON ${table}(source_agent)
464
+ `);
465
+ await client.query(`
466
+ CREATE INDEX IF NOT EXISTS idx_${table}_agent_task ON ${table}(agent_task_id)
467
+ `);
468
+ }
469
+ catch (error) {
470
+ this.logger.warn(`Schema update warning for ${table}:`, error);
471
+ }
472
+ }
473
+ // 2. 创建 OmO 协调表(使用 session_map_id 引用)
474
+ await client.query(`
475
+ CREATE TABLE IF NOT EXISTS omo_coordination (
476
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
477
+ session_map_id UUID REFERENCES session_map(id) ON DELETE CASCADE,
478
+ agent_id VARCHAR(255),
479
+ coordination_type VARCHAR(100) NOT NULL,
480
+ coordination_data JSONB DEFAULT '{}',
481
+ created_at TIMESTAMPTZ DEFAULT NOW()
482
+ )
483
+ `);
484
+ await client.query(`
485
+ CREATE INDEX IF NOT EXISTS idx_omo_coordination_session_map ON omo_coordination(session_map_id)
486
+ `);
487
+ await client.query(`
488
+ CREATE INDEX IF NOT EXISTS idx_omo_coordination_agent ON omo_coordination(agent_id)
489
+ `);
490
+ await client.query(`
491
+ CREATE INDEX IF NOT EXISTS idx_omo_coordination_type ON omo_coordination(coordination_type)
492
+ `);
493
+ // 3. 创建 OmO Wisdom 表(用于与 OmO Wisdom Accumulation 同步)
494
+ await client.query(`
495
+ CREATE TABLE IF NOT EXISTS omo_wisdom (
496
+ id VARCHAR(255) PRIMARY KEY,
497
+ type VARCHAR(100) NOT NULL,
498
+ content TEXT NOT NULL,
499
+ metadata JSONB DEFAULT '{}',
500
+ agent_id VARCHAR(255),
501
+ created_at TIMESTAMPTZ DEFAULT NOW()
502
+ )
503
+ `);
504
+ await client.query(`
505
+ CREATE INDEX IF NOT EXISTS idx_omo_wisdom_agent ON omo_wisdom(agent_id)
506
+ `);
507
+ await client.query(`
508
+ CREATE INDEX IF NOT EXISTS idx_omo_wisdom_type ON omo_wisdom(type)
509
+ `);
510
+ this.logger.info('OmO schema initialized');
511
+ }
512
+ async close() {
513
+ if (this.pool) {
514
+ await this.pool.end();
515
+ this.pool = null;
516
+ this.logger.info('Database connection closed');
517
+ }
518
+ }
519
+ getPool() {
520
+ if (!this.pool) {
521
+ throw new Error('Database not initialized. Call initialize() first.');
522
+ }
523
+ return this.pool;
524
+ }
525
+ }
526
+ exports.DatabaseInitializer = DatabaseInitializer;
527
+ // 单例导出
528
+ let initializer = null;
529
+ function getDatabaseInitializer(config) {
530
+ if (!initializer) {
531
+ initializer = new DatabaseInitializer(config);
532
+ }
533
+ return initializer;
534
+ }
535
+ async function initializeDatabase(config) {
536
+ const init = getDatabaseInitializer(config);
537
+ return init.initialize();
538
+ }
539
+ async function closeDatabase() {
540
+ if (initializer) {
541
+ await initializer.close();
542
+ initializer = null;
543
+ }
544
+ }
545
+ //# sourceMappingURL=init-db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init-db.js","sourceRoot":"","sources":["../../../src/db/init-db.ts"],"names":[],"mappings":"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"}