memory-pulse-mcp-server 0.1.8 → 0.1.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/dist/index.js +48 -0
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
- package/prisma/schema.prisma +54 -0
package/dist/index.js
CHANGED
|
@@ -1650,6 +1650,11 @@ var PostgreSQLStorage = class {
|
|
|
1650
1650
|
};
|
|
1651
1651
|
|
|
1652
1652
|
// src/index.ts
|
|
1653
|
+
import { execSync } from "child_process";
|
|
1654
|
+
import { fileURLToPath } from "url";
|
|
1655
|
+
import { dirname, join } from "path";
|
|
1656
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
1657
|
+
import { homedir } from "os";
|
|
1653
1658
|
var server = new Server(
|
|
1654
1659
|
{
|
|
1655
1660
|
name: "elb-memory-pulse",
|
|
@@ -1664,6 +1669,30 @@ var server = new Server(
|
|
|
1664
1669
|
}
|
|
1665
1670
|
);
|
|
1666
1671
|
var storageType = process.env.MEMORY_STORAGE || "sqlite";
|
|
1672
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
1673
|
+
var __dirname = dirname(__filename);
|
|
1674
|
+
var RUNTIME_CONFIG_PATH = join(homedir(), ".emp", "runtime-config.json");
|
|
1675
|
+
function writeRuntimeConfig(config) {
|
|
1676
|
+
try {
|
|
1677
|
+
const configDir = dirname(RUNTIME_CONFIG_PATH);
|
|
1678
|
+
mkdirSync(configDir, { recursive: true });
|
|
1679
|
+
writeFileSync(
|
|
1680
|
+
RUNTIME_CONFIG_PATH,
|
|
1681
|
+
JSON.stringify(
|
|
1682
|
+
{
|
|
1683
|
+
...config,
|
|
1684
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1685
|
+
pid: process.pid
|
|
1686
|
+
},
|
|
1687
|
+
null,
|
|
1688
|
+
2
|
|
1689
|
+
)
|
|
1690
|
+
);
|
|
1691
|
+
console.error(`\u{1F4DD} \u8FD0\u884C\u65F6\u914D\u7F6E\u5DF2\u5199\u5165: ${RUNTIME_CONFIG_PATH}`);
|
|
1692
|
+
} catch (error) {
|
|
1693
|
+
console.error("\u26A0\uFE0F \u5199\u5165\u8FD0\u884C\u65F6\u914D\u7F6E\u5931\u8D25:", error.message);
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1667
1696
|
function createStorage() {
|
|
1668
1697
|
if (storageType === "postgresql") {
|
|
1669
1698
|
const databaseUrl = process.env.DATABASE_URL;
|
|
@@ -1672,10 +1701,29 @@ function createStorage() {
|
|
|
1672
1701
|
process.exit(1);
|
|
1673
1702
|
}
|
|
1674
1703
|
console.error(`Memory Pulse \u4F7F\u7528 PostgreSQL \u5B58\u50A8: ${databaseUrl.replace(/:[^:@]+@/, ":****@")}`);
|
|
1704
|
+
try {
|
|
1705
|
+
const schemaPath = join(__dirname, "..", "prisma", "schema.prisma");
|
|
1706
|
+
console.error("\u{1F4E6} \u6B63\u5728\u540C\u6B65\u6570\u636E\u5E93\u8868\u7ED3\u6784...");
|
|
1707
|
+
execSync(`npx prisma db push --schema="${schemaPath}" --skip-generate`, {
|
|
1708
|
+
env: { ...process.env, DATABASE_URL: databaseUrl },
|
|
1709
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
1710
|
+
});
|
|
1711
|
+
console.error("\u2705 \u6570\u636E\u5E93\u8868\u7ED3\u6784\u540C\u6B65\u5B8C\u6210");
|
|
1712
|
+
} catch (error) {
|
|
1713
|
+
console.error("\u26A0\uFE0F \u6570\u636E\u5E93\u8868\u7ED3\u6784\u540C\u6B65\u5931\u8D25\uFF08\u53EF\u80FD\u8868\u5DF2\u5B58\u5728\uFF09:", error.message);
|
|
1714
|
+
}
|
|
1715
|
+
writeRuntimeConfig({
|
|
1716
|
+
storageType: "postgresql",
|
|
1717
|
+
databaseUrl
|
|
1718
|
+
});
|
|
1675
1719
|
return new PostgreSQLStorage(databaseUrl);
|
|
1676
1720
|
}
|
|
1677
1721
|
const dbPath = process.env.MEMORY_DB_PATH || "./memory.db";
|
|
1678
1722
|
console.error(`Memory Pulse \u4F7F\u7528 SQLite \u5B58\u50A8: ${dbPath}`);
|
|
1723
|
+
writeRuntimeConfig({
|
|
1724
|
+
storageType: "sqlite",
|
|
1725
|
+
dbPath
|
|
1726
|
+
});
|
|
1679
1727
|
return new SQLiteStorage(dbPath);
|
|
1680
1728
|
}
|
|
1681
1729
|
var storage = createStorage();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../../storage/src/sqlite-storage.ts","../../core/src/types.ts","../../core/src/features.ts","../../core/src/embedding.ts","../../storage/src/schema.ts","../../storage/src/cache.ts","../../storage/src/postgresql-storage.ts"],"sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n ListResourcesRequestSchema,\n ReadResourceRequestSchema,\n ListPromptsRequestSchema,\n GetPromptRequestSchema,\n Tool,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { SQLiteStorage, PostgreSQLStorage } from '@emp/storage';\nimport type {\n IStorage,\n DecisionContext,\n SolutionContext,\n SessionContext,\n SearchFilters,\n TimelineOptions,\n RelationsOptions,\n} from '@emp/core';\nimport { SearchStrategy } from '@emp/core';\n\n/**\n * Memory Pulse (记忆脉搏) MCP Server\n *\n * 提供以下工具:\n * - mpulse_store: 智能存储\n * - mpulse_store_decision: 存储决策\n * - mpulse_store_solution: 存储解决方案\n * - mpulse_store_session: 存储会话\n * - mpulse_recall: 检索记忆(全文搜索,AI 自己理解语义)\n * - mpulse_timeline: 时间线视图\n * - mpulse_relations: 关系链查询\n */\n\nconst server = new Server(\n {\n name: 'elb-memory-pulse',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n resources: {},\n prompts: {},\n },\n }\n);\n\n// 存储类型:sqlite(默认) 或 postgresql\nconst storageType = process.env.MEMORY_STORAGE || 'sqlite';\n\n// 初始化存储\nfunction createStorage(): IStorage {\n if (storageType === 'postgresql') {\n const databaseUrl = process.env.DATABASE_URL;\n if (!databaseUrl) {\n console.error('错误: 使用 PostgreSQL 存储需要设置 DATABASE_URL 环境变量');\n process.exit(1);\n }\n console.error(`Memory Pulse 使用 PostgreSQL 存储: ${databaseUrl.replace(/:[^:@]+@/, ':****@')}`);\n return new PostgreSQLStorage(databaseUrl);\n }\n\n // SQLite 存储(默认)\n const dbPath = process.env.MEMORY_DB_PATH || './memory.db';\n console.error(`Memory Pulse 使用 SQLite 存储: ${dbPath}`);\n return new SQLiteStorage(dbPath);\n}\n\nconst storage = createStorage();\n\n// 定义工具列表\nconst tools: Tool[] = [\n {\n name: 'mpulse_store',\n description: '智能存储记忆,AI 自动分类和结构化',\n inputSchema: {\n type: 'object',\n properties: {\n content: {\n type: 'string',\n description: 'AI 总结的内容',\n },\n rawContext: {\n type: 'object',\n description: '完整原始数据(不压缩)',\n },\n projectId: {\n type: 'string',\n description: '项目 ID',\n },\n type: {\n type: 'string',\n enum: ['decision', 'solution', 'config', 'code', 'error', 'session'],\n description: '记忆类型(可选,不填则默认为 code)',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: '标签',\n },\n sessionId: {\n type: 'string',\n description: '会话 ID(可选)',\n },\n },\n required: ['content', 'rawContext', 'projectId'],\n },\n },\n {\n name: 'mpulse_store_decision',\n description: '存储架构决策(强制字段,防止 AI 偷懒)',\n inputSchema: {\n type: 'object',\n properties: {\n question: {\n type: 'string',\n description: '决策问题',\n },\n options: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n pros: { type: 'array', items: { type: 'string' } },\n cons: { type: 'array', items: { type: 'string' } },\n },\n required: ['name', 'pros', 'cons'],\n },\n description: '考虑的选项',\n },\n chosen: {\n type: 'string',\n description: '选择的方案',\n },\n reason: {\n type: 'string',\n description: '选择理由',\n },\n projectId: {\n type: 'string',\n description: '项目 ID',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: '标签',\n },\n sessionId: {\n type: 'string',\n description: '会话 ID(可选)',\n },\n },\n required: ['question', 'options', 'chosen', 'reason', 'projectId'],\n },\n },\n {\n name: 'mpulse_store_solution',\n description: '存储问题解决方案',\n inputSchema: {\n type: 'object',\n properties: {\n problem: {\n type: 'string',\n description: '问题描述',\n },\n rootCause: {\n type: 'string',\n description: '根因分析',\n },\n solution: {\n type: 'string',\n description: '解决方案',\n },\n prevention: {\n type: 'string',\n description: '如何预防',\n },\n relatedIssues: {\n type: 'array',\n items: { type: 'string' },\n description: '关联问题',\n },\n projectId: {\n type: 'string',\n description: '项目 ID',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: '标签',\n },\n sessionId: {\n type: 'string',\n description: '会话 ID(可选)',\n },\n artifacts: {\n type: 'object',\n description: '相关文件(代码片段等)',\n },\n },\n required: ['problem', 'rootCause', 'solution', 'projectId'],\n },\n },\n {\n name: 'mpulse_store_session',\n description: '存储会话总结(会话结束时调用)',\n inputSchema: {\n type: 'object',\n properties: {\n summary: {\n type: 'string',\n description: '本次会话总结',\n },\n decisions: {\n type: 'array',\n items: { type: 'string' },\n description: '本次做出的决策',\n },\n unfinishedTasks: {\n type: 'array',\n items: { type: 'string' },\n description: '未完成的任务',\n },\n nextSteps: {\n type: 'array',\n items: { type: 'string' },\n description: '下次从哪继续',\n },\n projectId: {\n type: 'string',\n description: '项目 ID',\n },\n sessionId: {\n type: 'string',\n description: '会话 ID',\n },\n },\n required: ['summary', 'projectId', 'sessionId'],\n },\n },\n {\n name: 'mpulse_recall',\n description: '检索记忆(全文搜索,AI 自己理解结果语义)',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: '查询内容',\n },\n projectId: {\n type: 'string',\n description: '项目 ID',\n },\n type: {\n type: 'string',\n enum: ['decision', 'solution', 'config', 'code', 'error', 'session'],\n description: '记忆类型',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: '标签过滤',\n },\n strategy: {\n type: 'string',\n enum: ['exact', 'fulltext', 'auto'],\n description: '检索策略(默认 fulltext 全文搜索)',\n },\n limit: {\n type: 'number',\n description: '返回数量',\n },\n },\n required: ['query'],\n },\n },\n {\n name: 'mpulse_timeline',\n description: '查看项目的时间线视图',\n inputSchema: {\n type: 'object',\n properties: {\n projectId: {\n type: 'string',\n description: '项目 ID',\n },\n dateRange: {\n type: 'array',\n items: { type: 'string' },\n description: '日期范围 [start, end]',\n },\n type: {\n type: 'string',\n enum: ['decision', 'solution', 'config', 'code', 'error', 'session'],\n description: '记忆类型',\n },\n limit: {\n type: 'number',\n description: '返回数量',\n },\n offset: {\n type: 'number',\n description: '分页偏移',\n },\n },\n required: ['projectId'],\n },\n },\n {\n name: 'mpulse_relations',\n description: '查询记忆的关系链',\n inputSchema: {\n type: 'object',\n properties: {\n memoryId: {\n type: 'string',\n description: '记忆 ID',\n },\n depth: {\n type: 'number',\n description: '递归深度',\n },\n },\n required: ['memoryId'],\n },\n },\n];\n\n// 注册工具列表\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools,\n}));\n\n// 注册资源列表\nserver.setRequestHandler(ListResourcesRequestSchema, async () => ({\n resources: [\n {\n uri: 'memory://projects',\n name: '所有项目记忆',\n description: '列出所有项目 ID',\n mimeType: 'application/json',\n },\n ],\n}));\n\n// 处理资源读取\nserver.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n const uri = request.params.uri;\n\n try {\n // memory://projects - 列出所有项目\n if (uri === 'memory://projects') {\n // 查询所有记忆,按项目分组\n const allMemories = await storage.recall({ query: '', limit: 10000 });\n const projects = new Set(allMemories.memories.map((m) => m.meta.projectId));\n\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(\n {\n projects: Array.from(projects),\n total: projects.size,\n },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n // memory://project/{projectId} - 列出项目的所有记忆\n const projectMatch = uri.match(/^memory:\\/\\/project\\/(.+)$/);\n if (projectMatch) {\n const projectId = decodeURIComponent(projectMatch[1]);\n const result = await storage.recall({ query: '', projectId, limit: 1000 });\n\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(\n {\n projectId,\n memories: result.memories,\n total: result.total,\n },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n // memory://memory/{memoryId} - 获取单个记忆详情\n const memoryMatch = uri.match(/^memory:\\/\\/memory\\/(.+)$/);\n if (memoryMatch) {\n const memoryId = decodeURIComponent(memoryMatch[1]);\n // 使用 getRelations 获取单个记忆(depth=0 不递归)\n const result = await storage.getRelations({ memoryId, depth: 0 });\n\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(result.memory, null, 2),\n },\n ],\n };\n }\n\n // memory://session/{sessionId} - 列出会话的所有记忆\n const sessionMatch = uri.match(/^memory:\\/\\/session\\/(.+)$/);\n if (sessionMatch) {\n const sessionId = decodeURIComponent(sessionMatch[1]);\n const result = await storage.recall({ query: '', sessionId, limit: 1000 });\n\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(\n {\n sessionId,\n memories: result.memories,\n total: result.total,\n },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n throw new Error(`Unknown resource URI: ${uri}`);\n } catch (error) {\n throw new Error(\n `Failed to read resource ${uri}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n});\n\n// 注册提示词列表\nserver.setRequestHandler(ListPromptsRequestSchema, async () => ({\n prompts: [\n {\n name: 'analyze-decision',\n description: '分析项目中的架构决策',\n arguments: [\n {\n name: 'projectId',\n description: '项目 ID',\n required: true,\n },\n ],\n },\n {\n name: 'summarize-session',\n description: '总结会话中的工作内容',\n arguments: [\n {\n name: 'sessionId',\n description: '会话 ID',\n required: true,\n },\n ],\n },\n {\n name: 'find-related',\n description: '查找与特定主题相关的记忆',\n arguments: [\n {\n name: 'topic',\n description: '主题关键词',\n required: true,\n },\n {\n name: 'projectId',\n description: '项目 ID(可选)',\n required: false,\n },\n ],\n },\n {\n name: 'review-project',\n description: '回顾项目的发展历程',\n arguments: [\n {\n name: 'projectId',\n description: '项目 ID',\n required: true,\n },\n {\n name: 'type',\n description: '记忆类型(可选:decision, solution, session)',\n required: false,\n },\n ],\n },\n ],\n}));\n\n// 处理提示词获取\nserver.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n if (!args) {\n throw new Error('Missing required arguments');\n }\n\n try {\n switch (name) {\n case 'analyze-decision': {\n const projectId = (args as any).projectId;\n const decisions = await storage.recall({\n query: '',\n projectId,\n type: 'decision' as any,\n limit: 100,\n });\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `请分析项目 \"${projectId}\" 中的架构决策。\n\n找到了 ${decisions.total} 个决策记录:\n\n${decisions.memories\n .map((m, idx) => {\n const data = m.content.data as any;\n return `\n${idx + 1}. ${data.question || m.content.summary}\n 选择:${data.chosen || '未知'}\n 理由:${data.reason || '未提供'}\n 时间:${m.meta.timestamp}\n`;\n })\n .join('\\n')}\n\n请总结:\n1. 主要的技术选型有哪些?\n2. 决策的演进趋势如何?\n3. 是否存在可能的技术债务?\n4. 有哪些值得记录的经验教训?`,\n },\n },\n ],\n };\n }\n\n case 'summarize-session': {\n const sessionId = (args as any).sessionId;\n const memories = await storage.recall({\n query: '',\n sessionId,\n limit: 100,\n });\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `请总结会话 \"${sessionId}\" 的工作内容。\n\n会话包含 ${memories.total} 条记忆:\n\n${memories.memories\n .map((m, idx) => `${idx + 1}. [${m.meta.type}] ${m.content.summary}`)\n .join('\\n')}\n\n请生成一个简洁的工作总结,包括:\n1. 主要完成的任务\n2. 做出的重要决策\n3. 遇到的问题和解决方案\n4. 未完成的任务(如有)\n5. 下一步计划建议`,\n },\n },\n ],\n };\n }\n\n case 'find-related': {\n const topic = (args as any).topic;\n const projectId = (args as any).projectId;\n const related = await storage.recall({\n query: topic,\n projectId,\n limit: 20,\n });\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `查找与 \"${topic}\" 相关的记忆${projectId ? `(项目:${projectId})` : ''}。\n\n找到 ${related.total} 条相关记忆:\n\n${related.memories\n .map(\n (m, idx) => `\n${idx + 1}. ${m.content.summary}\n 类型:${m.meta.type}\n 项目:${m.meta.projectId}\n 时间:${m.meta.timestamp}\n`\n )\n .join('\\n')}\n\n请分析这些记忆之间的关联性,并提供:\n1. 这些记忆围绕什么主题?\n2. 是否存在演进关系?\n3. 有哪些有价值的经验可以复用?`,\n },\n },\n ],\n };\n }\n\n case 'review-project': {\n const projectId = (args as any).projectId;\n const type = (args as any).type;\n const timeline = await storage.getTimeline({\n projectId,\n type: type as any,\n limit: 100,\n });\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `回顾项目 \"${projectId}\" 的发展历程${type ? `(类型:${type})` : ''}。\n\n时间线包含 ${timeline.total} 条记录:\n\n${timeline.entries\n .map((entry, idx) => {\n const m = entry.memory;\n return `${idx + 1}. [${new Date(m.meta.timestamp).toLocaleDateString()}] ${m.content.summary}`;\n })\n .join('\\n')}\n\n请生成项目回顾报告,包括:\n1. 项目起源和初始目标\n2. 关键里程碑和决策点\n3. 遇到的挑战和解决方案\n4. 当前状态和未来方向\n5. 经验总结和改进建议`,\n },\n },\n ],\n };\n }\n\n default:\n throw new Error(`Unknown prompt: ${name}`);\n }\n } catch (error) {\n throw new Error(\n `Failed to generate prompt ${name}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n});\n\n// 处理工具调用\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n // MCP SDK 保证 args 存在且类型正确(通过 inputSchema 验证)\n if (!args) {\n throw new Error('Missing required arguments');\n }\n\n try {\n switch (name) {\n case 'mpulse_store': {\n const result = await storage.store({\n content: (args as any).content,\n rawContext: (args as any).rawContext,\n projectId: (args as any).projectId,\n type: (args as any).type,\n tags: (args as any).tags,\n sessionId: (args as any).sessionId,\n });\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'mpulse_store_decision': {\n const decisionParams: DecisionContext & {\n projectId: string;\n tags?: string[];\n sessionId?: string;\n } = {\n question: (args as any).question,\n options: (args as any).options,\n chosen: (args as any).chosen,\n reason: (args as any).reason,\n projectId: (args as any).projectId,\n tags: (args as any).tags,\n sessionId: (args as any).sessionId,\n };\n const result = await storage.storeDecision(decisionParams);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'mpulse_store_solution': {\n const solutionParams: SolutionContext & {\n projectId: string;\n tags?: string[];\n sessionId?: string;\n artifacts?: Record<string, string>;\n } = {\n problem: (args as any).problem,\n rootCause: (args as any).rootCause,\n solution: (args as any).solution,\n prevention: (args as any).prevention,\n relatedIssues: (args as any).relatedIssues,\n projectId: (args as any).projectId,\n tags: (args as any).tags,\n sessionId: (args as any).sessionId,\n artifacts: (args as any).artifacts,\n };\n const result = await storage.storeSolution(solutionParams);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'mpulse_store_session': {\n const sessionParams: SessionContext & {\n projectId: string;\n sessionId: string;\n } = {\n summary: (args as any).summary,\n decisions: (args as any).decisions,\n unfinishedTasks: (args as any).unfinishedTasks,\n nextSteps: (args as any).nextSteps,\n projectId: (args as any).projectId,\n sessionId: (args as any).sessionId,\n };\n const result = await storage.storeSession(sessionParams);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'mpulse_recall': {\n const query = (args as any).query;\n const strategy = (args as any).strategy || 'fulltext';\n\n // 构建检索过滤器\n const filters: SearchFilters = {\n query,\n projectId: (args as any).projectId,\n type: (args as any).type,\n tags: (args as any).tags,\n strategy: strategy as any,\n limit: (args as any).limit,\n };\n\n const result = await storage.recall(filters);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'mpulse_timeline': {\n const options: TimelineOptions = {\n projectId: (args as any).projectId,\n dateRange: (args as any).dateRange,\n type: (args as any).type,\n limit: (args as any).limit,\n offset: (args as any).offset,\n };\n const result = await storage.getTimeline(options);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'mpulse_relations': {\n const options: RelationsOptions = {\n memoryId: (args as any).memoryId,\n depth: (args as any).depth,\n };\n const result = await storage.getRelations(options);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch (error) {\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n});\n\n// 启动服务器\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error('Memory Pulse (记忆脉搏) MCP Server running on stdio');\n}\n\nmain().catch((error) => {\n console.error('Fatal error:', error);\n process.exit(1);\n});\n","import Database from 'better-sqlite3';\nimport { nanoid } from 'nanoid';\nimport {\n type IStorage,\n type SearchFilters,\n type SearchResult,\n type TimelineOptions,\n type TimelineResult,\n type TimelineEntry,\n type RelationsOptions,\n type RelationNode,\n MemoryType,\n SearchStrategy,\n type Memory,\n type DecisionContext,\n type SolutionContext,\n type SessionContext,\n type Vector,\n serializeVector,\n deserializeVector,\n cosineSimilarity,\n} from '@emp/core';\nimport { initSchema } from './schema.js';\nimport { LRUCache } from './cache.js';\n\n/**\n * SQLite存储实现\n */\nexport class SQLiteStorage implements IStorage {\n private db: Database.Database;\n private cache: LRUCache | null;\n\n constructor(dbPath: string = ':memory:', options?: { enableCache?: boolean; cacheSize?: number }) {\n this.db = new Database(dbPath);\n this.db.pragma('journal_mode = WAL'); // 性能优化:Write-Ahead Logging\n this.db.pragma('foreign_keys = ON');\n initSchema(this.db); // 初始化Schema\n\n // 初始化缓存(默认启用,容量100)\n this.cache = options?.enableCache !== false ? new LRUCache(options?.cacheSize || 100) : null;\n }\n\n /**\n * 通用存储方法\n */\n async store(params: {\n content: string;\n rawContext: Record<string, unknown>;\n projectId: string;\n type?: MemoryType;\n tags?: string[];\n sessionId?: string;\n embedding?: Vector;\n relations?: {\n replaces?: string[];\n relatedTo?: string[];\n impacts?: string[];\n derivedFrom?: string;\n };\n }): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date().toISOString();\n const memoryType = params.type || MemoryType.CODE;\n\n const stmt = this.db.prepare(`\n INSERT INTO memories (\n id, projectId, sessionId, timestamp, type, tags,\n summary, data, replaces, relatedTo, impacts, derivedFrom,\n context, keywords, fullText, embedding, createdAt, updatedAt\n ) VALUES (\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?\n )\n `);\n\n stmt.run(\n id,\n params.projectId,\n params.sessionId || null,\n timestamp,\n memoryType,\n params.tags ? JSON.stringify(params.tags) : null,\n params.content, // summary\n JSON.stringify(params.rawContext), // data\n params.relations?.replaces ? JSON.stringify(params.relations.replaces) : null,\n params.relations?.relatedTo ? JSON.stringify(params.relations.relatedTo) : null,\n params.relations?.impacts ? JSON.stringify(params.relations.impacts) : null,\n params.relations?.derivedFrom || null,\n JSON.stringify(params.rawContext), // context\n params.tags ? JSON.stringify(params.tags) : null, // keywords\n params.content, // fullText\n params.embedding ? serializeVector(params.embedding) : null, // embedding\n timestamp,\n timestamp\n );\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 存储决策记忆\n */\n async storeDecision(\n params: DecisionContext & {\n projectId: string;\n tags?: string[];\n sessionId?: string;\n embedding?: Vector;\n relations?: {\n replaces?: string[];\n relatedTo?: string[];\n impacts?: string[];\n derivedFrom?: string;\n };\n }\n ): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date().toISOString();\n const summary = `[决策] ${params.question}`;\n const fullText = `${params.question} ${params.options.map((o) => o.name).join(' ')} ${params.reason}`;\n const keywords = [...(params.tags || []), ...params.options.map((o) => o.name), params.chosen];\n\n const stmt = this.db.prepare(`\n INSERT INTO memories (\n id, projectId, sessionId, timestamp, type, tags,\n summary, data, replaces, relatedTo, impacts, derivedFrom,\n context, keywords, fullText, embedding, createdAt, updatedAt\n ) VALUES (\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?\n )\n `);\n\n stmt.run(\n id,\n params.projectId,\n params.sessionId || null,\n timestamp,\n MemoryType.DECISION,\n params.tags ? JSON.stringify(params.tags) : null,\n summary,\n JSON.stringify({}), // data为空\n params.relations?.replaces ? JSON.stringify(params.relations.replaces) : null,\n params.relations?.relatedTo ? JSON.stringify(params.relations.relatedTo) : null,\n params.relations?.impacts ? JSON.stringify(params.relations.impacts) : null,\n params.relations?.derivedFrom || null,\n JSON.stringify({\n question: params.question,\n options: params.options,\n chosen: params.chosen,\n reason: params.reason,\n }),\n JSON.stringify(keywords),\n fullText,\n params.embedding ? serializeVector(params.embedding) : null,\n timestamp,\n timestamp\n );\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 存储解决方案记忆\n */\n async storeSolution(\n params: SolutionContext & {\n projectId: string;\n tags?: string[];\n sessionId?: string;\n embedding?: Vector;\n artifacts?: Record<string, string>;\n relations?: {\n replaces?: string[];\n relatedTo?: string[];\n impacts?: string[];\n derivedFrom?: string;\n };\n }\n ): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date().toISOString();\n const summary = `[方案] ${params.problem}`;\n const fullText = `${params.problem} ${params.rootCause} ${params.solution} ${params.prevention || ''} ${params.relatedIssues?.join(' ') || ''}`;\n const keywords = [...(params.tags || []), ...(params.relatedIssues || [])];\n\n const stmt = this.db.prepare(`\n INSERT INTO memories (\n id, projectId, sessionId, timestamp, type, tags,\n summary, data, replaces, relatedTo, impacts, derivedFrom,\n context, keywords, fullText, embedding, createdAt, updatedAt\n ) VALUES (\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?\n )\n `);\n\n stmt.run(\n id,\n params.projectId,\n params.sessionId || null,\n timestamp,\n MemoryType.SOLUTION,\n params.tags ? JSON.stringify(params.tags) : null,\n summary,\n JSON.stringify(params.artifacts || {}),\n params.relations?.replaces ? JSON.stringify(params.relations.replaces) : null,\n params.relations?.relatedTo ? JSON.stringify(params.relations.relatedTo) : null,\n params.relations?.impacts ? JSON.stringify(params.relations.impacts) : null,\n params.relations?.derivedFrom || null,\n JSON.stringify({\n problem: params.problem,\n rootCause: params.rootCause,\n solution: params.solution,\n prevention: params.prevention,\n relatedIssues: params.relatedIssues,\n }),\n JSON.stringify(keywords),\n fullText,\n params.embedding ? serializeVector(params.embedding) : null,\n timestamp,\n timestamp\n );\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 存储会话记忆\n */\n async storeSession(\n params: SessionContext & {\n projectId: string;\n sessionId?: string;\n embedding?: Vector;\n }\n ): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date().toISOString();\n const summary = `[会话] ${params.summary}`;\n const fullText = `${params.summary} ${params.decisions?.join(' ') || ''} ${params.unfinishedTasks?.join(' ') || ''} ${params.nextSteps?.join(' ') || ''}`;\n const keywords = [...(params.decisions || []), ...(params.unfinishedTasks || [])];\n\n const stmt = this.db.prepare(`\n INSERT INTO memories (\n id, projectId, sessionId, timestamp, type, tags,\n summary, data, replaces, relatedTo, impacts, derivedFrom,\n context, keywords, fullText, embedding, createdAt, updatedAt\n ) VALUES (\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?\n )\n `);\n\n stmt.run(\n id,\n params.projectId,\n params.sessionId || id, // 使用当前id作为sessionId\n timestamp,\n MemoryType.SESSION,\n null, // tags\n summary,\n JSON.stringify({}),\n null, // replaces\n null, // relatedTo\n null, // impacts\n null, // derivedFrom\n JSON.stringify({\n summary: params.summary,\n decisions: params.decisions,\n unfinishedTasks: params.unfinishedTasks,\n nextSteps: params.nextSteps,\n }),\n JSON.stringify(keywords),\n fullText,\n params.embedding ? serializeVector(params.embedding) : null,\n timestamp,\n timestamp\n );\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 检索记忆\n */\n async recall(filters: SearchFilters): Promise<SearchResult> {\n const startTime = Date.now();\n\n // 检查缓存\n if (this.cache) {\n const cacheKey = LRUCache.generateKey(filters);\n const cached = this.cache.get(cacheKey);\n if (cached) {\n return cached; // 缓存命中,直接返回\n }\n }\n\n const strategy = filters.strategy || SearchStrategy.AUTO;\n const limit = filters.limit || 10;\n const offset = filters.offset || 0;\n\n let actualStrategy: SearchStrategy;\n let results: Memory[];\n let dbStartTime: number;\n let dbEndTime: number;\n let parseStartTime: number;\n\n // 策略选择\n const strategyStartTime = Date.now();\n\n // 如果提供了 queryVector,直接使用语义搜索\n if (filters.queryVector && strategy !== SearchStrategy.EXACT && strategy !== SearchStrategy.FULLTEXT) {\n dbStartTime = Date.now();\n results = this.semanticSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.SEMANTIC;\n }\n // L1: 精确匹配(优先)\n else if (strategy === SearchStrategy.EXACT || strategy === SearchStrategy.AUTO) {\n dbStartTime = Date.now();\n results = this.exactSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.EXACT;\n\n // AUTO 模式:如果L1找不到结果,降级到L2全文搜索\n if (results.length === 0 && strategy === SearchStrategy.AUTO && filters.query) {\n dbStartTime = Date.now();\n results = this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n\n // AUTO 模式:如果L2也找不到,且有 queryVector,降级到L3语义搜索\n if (results.length === 0 && filters.queryVector) {\n dbStartTime = Date.now();\n results = this.semanticSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.SEMANTIC;\n }\n }\n }\n // L2: 全文搜索\n else if (strategy === SearchStrategy.FULLTEXT) {\n dbStartTime = Date.now();\n results = this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n }\n // L3: 语义检索\n else if (strategy === SearchStrategy.SEMANTIC) {\n if (!filters.queryVector) {\n // 无向量时降级到全文搜索\n dbStartTime = Date.now();\n results = this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n } else {\n dbStartTime = Date.now();\n results = this.semanticSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.SEMANTIC;\n }\n }\n // 默认:全文搜索\n else {\n dbStartTime = Date.now();\n results = this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n }\n\n const strategyTime = Date.now() - strategyStartTime;\n const took = Date.now() - startTime;\n\n // 计算解析时间(总时间 - 数据库时间)\n const dbTime = dbEndTime - dbStartTime;\n const parseTime = took - dbTime - strategyTime;\n\n const result: SearchResult = {\n memories: results,\n total: results.length,\n strategy: actualStrategy,\n took,\n metrics: {\n dbTime,\n parseTime: Math.max(0, parseTime), // 确保非负\n strategyTime,\n cacheHit: false, // 数据库查询,标记为未命中\n },\n };\n\n // 写入缓存\n if (this.cache) {\n const cacheKey = LRUCache.generateKey(filters);\n this.cache.set(cacheKey, result);\n }\n\n return result;\n }\n\n /**\n * L1: 精确匹配检索\n */\n private exactSearch(filters: SearchFilters, limit: number, offset: number): Memory[] {\n let sql = 'SELECT * FROM memories WHERE 1=1';\n const params: any[] = [];\n\n if (filters.projectId) {\n sql += ' AND projectId = ?';\n params.push(filters.projectId);\n }\n\n if (filters.type) {\n sql += ' AND type = ?';\n params.push(filters.type);\n }\n\n if (filters.sessionId) {\n sql += ' AND sessionId = ?';\n params.push(filters.sessionId);\n }\n\n // 精确匹配:在summary或fullText中查找完整query\n if (filters.query) {\n sql += ' AND (summary LIKE ? OR fullText LIKE ?)';\n params.push(`%${filters.query}%`, `%${filters.query}%`);\n }\n\n sql += ' ORDER BY timestamp DESC LIMIT ? OFFSET ?';\n params.push(limit, offset);\n\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as any[];\n\n return rows.map(this.rowToMemory);\n }\n\n /**\n * L2: 全文搜索(FTS5)\n */\n private fulltextSearch(filters: SearchFilters, limit: number, offset: number): Memory[] {\n // 先不用FTS5,退化为LIKE查询\n // TODO: 调试FTS5后再启用\n let sql = 'SELECT * FROM memories WHERE 1=1';\n const params: any[] = [];\n\n if (filters.projectId) {\n sql += ' AND projectId = ?';\n params.push(filters.projectId);\n }\n\n if (filters.type) {\n sql += ' AND type = ?';\n params.push(filters.type);\n }\n\n if (filters.sessionId) {\n sql += ' AND sessionId = ?';\n params.push(filters.sessionId);\n }\n\n if (filters.query) {\n // 使用LIKE实现简单的全文搜索\n sql += ' AND (summary LIKE ? OR fullText LIKE ?)';\n params.push(`%${filters.query}%`, `%${filters.query}%`);\n }\n\n sql += ' ORDER BY timestamp DESC LIMIT ? OFFSET ?';\n params.push(limit, offset);\n\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as any[];\n\n return rows.map(this.rowToMemory);\n }\n\n /**\n * L3: 语义搜索(向量相似度)\n * 基于 cosine similarity 进行向量检索\n */\n private semanticSearch(filters: SearchFilters, limit: number, offset: number): Memory[] {\n if (!filters.queryVector) {\n return [];\n }\n\n const threshold = filters.similarityThreshold ?? 0.7;\n\n // 构建基础查询(只取有 embedding 的记录)\n let sql = 'SELECT * FROM memories WHERE embedding IS NOT NULL';\n const params: any[] = [];\n\n if (filters.projectId) {\n sql += ' AND projectId = ?';\n params.push(filters.projectId);\n }\n\n if (filters.type) {\n sql += ' AND type = ?';\n params.push(filters.type);\n }\n\n if (filters.sessionId) {\n sql += ' AND sessionId = ?';\n params.push(filters.sessionId);\n }\n\n sql += ' ORDER BY timestamp DESC';\n\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as any[];\n\n // 计算相似度并过滤\n const queryVector = filters.queryVector;\n const scoredResults: { row: any; similarity: number }[] = [];\n\n for (const row of rows) {\n try {\n const storedVector = deserializeVector(row.embedding);\n const similarity = cosineSimilarity(queryVector, storedVector);\n\n // 只保留超过阈值的结果\n if (similarity >= threshold) {\n scoredResults.push({ row, similarity });\n }\n } catch {\n // 向量解析失败,跳过\n continue;\n }\n }\n\n // 按相似度降序排序\n scoredResults.sort((a, b) => b.similarity - a.similarity);\n\n // 应用分页\n const paginatedResults = scoredResults.slice(offset, offset + limit);\n\n return paginatedResults.map((item) => this.rowToMemory(item.row));\n }\n\n /**\n * 获取时间线\n */\n async getTimeline(options: TimelineOptions): Promise<TimelineResult> {\n let sql = 'SELECT * FROM memories WHERE projectId = ?';\n const params: any[] = [options.projectId];\n\n if (options.type) {\n sql += ' AND type = ?';\n params.push(options.type);\n }\n\n if (options.dateRange) {\n sql += ' AND timestamp >= ? AND timestamp <= ?';\n params.push(options.dateRange[0], options.dateRange[1]);\n }\n\n sql += ' ORDER BY timestamp DESC';\n\n if (options.limit) {\n sql += ' LIMIT ?';\n params.push(options.limit);\n }\n\n if (options.offset) {\n sql += ' OFFSET ?';\n params.push(options.offset);\n }\n\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as any[];\n const memories = rows.map(this.rowToMemory);\n\n const entries: TimelineEntry[] = memories.map((memory, index) => ({\n memory,\n prevMemoryId: index > 0 ? memories[index - 1].meta.id : undefined,\n nextMemoryId: index < memories.length - 1 ? memories[index + 1].meta.id : undefined,\n }));\n\n return {\n entries,\n total: entries.length,\n };\n }\n\n /**\n * 获取关系链\n */\n async getRelations(options: RelationsOptions): Promise<RelationNode> {\n const memory = await this.getById(options.memoryId);\n if (!memory) {\n throw new Error(`Memory ${options.memoryId} not found`);\n }\n\n const depth = options.depth || 1;\n const relatedNodes: RelationNode[] = [];\n\n if (depth > 0) {\n // 查找所有相关记忆\n const relatedIds = [\n ...(memory.relations.replaces || []),\n ...(memory.relations.relatedTo || []),\n ...(memory.relations.impacts || []),\n ];\n\n if (memory.relations.derivedFrom) {\n relatedIds.push(memory.relations.derivedFrom);\n }\n\n for (const relatedId of relatedIds) {\n const relatedMemory = await this.getById(relatedId);\n if (relatedMemory) {\n // 递归查询关系链\n let nestedRelated: RelationNode[] | undefined = undefined;\n if (depth > 1) {\n const nestedResult = await this.getRelations({\n memoryId: relatedId,\n depth: depth - 1,\n });\n nestedRelated = nestedResult.related;\n }\n\n relatedNodes.push({\n memory: relatedMemory,\n related: nestedRelated,\n });\n }\n }\n }\n\n return {\n memory,\n related: relatedNodes.length > 0 ? relatedNodes : undefined,\n };\n }\n\n /**\n * 删除记忆\n */\n async delete(memoryId: string): Promise<{ success: boolean }> {\n // 先查询 projectId 用于缓存失效\n if (this.cache) {\n const memory = this.db.prepare('SELECT projectId FROM memories WHERE id = ?').get(memoryId) as {\n projectId: string;\n } | undefined;\n if (memory) {\n this.cache.invalidateProject(memory.projectId);\n }\n }\n\n const stmt = this.db.prepare('DELETE FROM memories WHERE id = ?');\n const result = stmt.run(memoryId);\n return { success: result.changes > 0 };\n }\n\n /**\n * 更新记忆\n */\n async update(memoryId: string, updates: Partial<Memory>): Promise<{ success: boolean }> {\n const fields: string[] = [];\n const params: any[] = [];\n\n if (updates.content) {\n if (updates.content.summary) {\n fields.push('summary = ?');\n params.push(updates.content.summary);\n }\n if (updates.content.data !== undefined) {\n fields.push('data = ?');\n params.push(JSON.stringify(updates.content.data));\n }\n }\n\n if (updates.meta?.tags) {\n fields.push('tags = ?');\n params.push(JSON.stringify(updates.meta.tags));\n }\n\n if (updates.relations) {\n if (updates.relations.replaces) {\n fields.push('replaces = ?');\n params.push(JSON.stringify(updates.relations.replaces));\n }\n if (updates.relations.relatedTo) {\n fields.push('relatedTo = ?');\n params.push(JSON.stringify(updates.relations.relatedTo));\n }\n if (updates.relations.impacts) {\n fields.push('impacts = ?');\n params.push(JSON.stringify(updates.relations.impacts));\n }\n if (updates.relations.derivedFrom) {\n fields.push('derivedFrom = ?');\n params.push(updates.relations.derivedFrom);\n }\n }\n\n if (fields.length === 0) {\n return { success: false };\n }\n\n fields.push('updatedAt = ?');\n params.push(new Date().toISOString());\n params.push(memoryId);\n\n const sql = `UPDATE memories SET ${fields.join(', ')} WHERE id = ?`;\n const stmt = this.db.prepare(sql);\n const result = stmt.run(...params);\n\n // 失效相关缓存\n if (this.cache && result.changes > 0) {\n const memory = this.db.prepare('SELECT projectId FROM memories WHERE id = ?').get(memoryId) as {\n projectId: string;\n } | undefined;\n if (memory) {\n this.cache.invalidateProject(memory.projectId);\n }\n }\n\n return { success: result.changes > 0 };\n }\n\n /**\n * 根据 ID 获取单个记忆\n */\n async getById(id: string): Promise<Memory | null> {\n const stmt = this.db.prepare('SELECT * FROM memories WHERE id = ?');\n const row = stmt.get(id) as any;\n return row ? this.rowToMemory(row) : null;\n }\n\n /**\n * 将数据库行转换为Memory对象\n */\n private rowToMemory(row: any): Memory {\n return {\n meta: {\n id: row.id,\n projectId: row.projectId,\n sessionId: row.sessionId,\n timestamp: row.timestamp,\n type: row.type as MemoryType,\n tags: row.tags ? JSON.parse(row.tags) : [],\n version: row.version,\n },\n content: {\n summary: row.summary,\n data: row.data ? JSON.parse(row.data) : {},\n },\n relations: {\n replaces: row.replaces ? JSON.parse(row.replaces) : undefined,\n relatedTo: row.relatedTo ? JSON.parse(row.relatedTo) : undefined,\n impacts: row.impacts ? JSON.parse(row.impacts) : undefined,\n derivedFrom: row.derivedFrom || undefined,\n },\n searchable: {\n keywords: row.keywords ? JSON.parse(row.keywords) : [],\n fullText: row.fullText,\n },\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n }\n\n /**\n * 关闭数据库连接\n */\n close(): void {\n this.db.close();\n }\n\n /**\n * 获取统计信息\n */\n async getStats(projectId?: string): Promise<{\n total: number;\n byType: Record<string, number>;\n byProject: Record<string, number>;\n recentCount: number;\n }> {\n // 总数查询\n let totalSql = 'SELECT COUNT(*) as count FROM memories';\n const totalParams: any[] = [];\n if (projectId) {\n totalSql += ' WHERE projectId = ?';\n totalParams.push(projectId);\n }\n const totalResult = this.db.prepare(totalSql).get(...totalParams) as { count: number };\n\n // 按类型统计\n let typeSql = 'SELECT type, COUNT(*) as count FROM memories';\n const typeParams: any[] = [];\n if (projectId) {\n typeSql += ' WHERE projectId = ?';\n typeParams.push(projectId);\n }\n typeSql += ' GROUP BY type';\n const typeResults = this.db.prepare(typeSql).all(...typeParams) as { type: string; count: number }[];\n const byType: Record<string, number> = {};\n typeResults.forEach((row) => {\n byType[row.type] = row.count;\n });\n\n // 按项目统计\n let projectSql = 'SELECT projectId, COUNT(*) as count FROM memories GROUP BY projectId';\n if (projectId) {\n projectSql = 'SELECT projectId, COUNT(*) as count FROM memories WHERE projectId = ? GROUP BY projectId';\n }\n const projectResults = this.db.prepare(projectSql).all(...(projectId ? [projectId] : [])) as { projectId: string; count: number }[];\n const byProject: Record<string, number> = {};\n projectResults.forEach((row) => {\n byProject[row.projectId] = row.count;\n });\n\n // 最近 7 天统计\n const sevenDaysAgo = new Date();\n sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);\n let recentSql = 'SELECT COUNT(*) as count FROM memories WHERE timestamp >= ?';\n const recentParams: any[] = [sevenDaysAgo.toISOString()];\n if (projectId) {\n recentSql += ' AND projectId = ?';\n recentParams.push(projectId);\n }\n const recentResult = this.db.prepare(recentSql).get(...recentParams) as { count: number };\n\n return {\n total: totalResult.count,\n byType,\n byProject,\n recentCount: recentResult.count,\n };\n }\n}\n","/**\n * 记忆类型枚举\n */\nexport enum MemoryType {\n /** 架构决策 */\n DECISION = 'decision',\n /** 问题解决方案 */\n SOLUTION = 'solution',\n /** 配置信息 */\n CONFIG = 'config',\n /** 代码实现 */\n CODE = 'code',\n /** 错误记录 */\n ERROR = 'error',\n /** 会话总结 */\n SESSION = 'session',\n}\n\n/**\n * 检索策略枚举\n */\nexport enum SearchStrategy {\n /** L1: 精确匹配(WHERE + 索引) */\n EXACT = 'exact',\n /** L2: 全文搜索(FTS5/Meilisearch) */\n FULLTEXT = 'fulltext',\n /** L3: 语义检索(Embedding 相似度) */\n SEMANTIC = 'semantic',\n /** 自动选择最优策略 */\n AUTO = 'auto',\n}\n\n/**\n * 关系类型\n */\nexport type RelationType = 'replaces' | 'relatedTo' | 'impacts' | 'derivedFrom';\n","/**\n * Feature Flag 系统\n *\n * 采用 Open Core 模式:\n * - 开源版(MIT):完整功能的 MCP Server、CLI、Web Dashboard、SQLite/PostgreSQL 存储\n * - 闭源部分(Commercial):云平台服务(多租户、计费、SSO、审计等)\n */\n\n// ============ 功能分类 ============\n\n/** 开源功能(默认开启) */\nexport enum OpenSourceFeature {\n // 存储\n SQLITE_STORAGE = 'sqlite_storage',\n POSTGRESQL_STORAGE = 'postgresql_storage',\n\n // 检索\n EXACT_SEARCH = 'exact_search',\n FULLTEXT_SEARCH = 'fulltext_search',\n\n // 记忆类型\n DECISION_MEMORY = 'decision_memory',\n SOLUTION_MEMORY = 'solution_memory',\n SESSION_MEMORY = 'session_memory',\n\n // 视图\n TIMELINE_VIEW = 'timeline_view',\n RELATIONS_VIEW = 'relations_view',\n\n // 接口\n MCP_SERVER = 'mcp_server',\n REST_API = 'rest_api',\n WEB_DASHBOARD = 'web_dashboard',\n CLI_TOOL = 'cli_tool',\n}\n\n/** 云平台功能(需要授权) */\nexport enum CloudFeature {\n // 多租户\n MULTI_TENANT = 'multi_tenant',\n WORKSPACE_MANAGEMENT = 'workspace_management',\n\n // 用户管理\n SSO_SAML = 'sso_saml',\n OAUTH_INTEGRATION = 'oauth_integration',\n RBAC = 'rbac',\n\n // 数据服务\n AUTO_BACKUP = 'auto_backup',\n DATA_EXPORT = 'data_export',\n DATA_MIGRATION = 'data_migration',\n\n // 高级功能\n SEMANTIC_SEARCH = 'semantic_search',\n ADVANCED_ANALYTICS = 'advanced_analytics',\n AUDIT_LOG = 'audit_log',\n\n // 集成\n WEBHOOK = 'webhook',\n CUSTOM_STORAGE = 'custom_storage',\n\n // 支持\n PRIORITY_SUPPORT = 'priority_support',\n}\n\n// ============ 许可证类型 ============\n\nexport enum LicenseType {\n /** 开源版 - 所有开源功能 */\n OPEN_SOURCE = 'open_source',\n\n /** 专业版 - 开源 + 部分云功能 */\n PROFESSIONAL = 'professional',\n\n /** 企业版 - 所有功能 */\n ENTERPRISE = 'enterprise',\n}\n\n// ============ 类型定义 ============\n\nexport type FeatureKey = OpenSourceFeature | CloudFeature;\n\nexport interface FeatureConfig {\n /** 功能键 */\n key: FeatureKey;\n /** 功能名称 */\n name: string;\n /** 功能描述 */\n description: string;\n /** 是否开源功能 */\n isOpenSource: boolean;\n /** 所需最低许可证 */\n requiredLicense: LicenseType;\n /** 是否启用 */\n enabled: boolean;\n}\n\nexport interface LicenseInfo {\n /** 许可证类型 */\n type: LicenseType;\n /** 许可证 ID */\n licenseId?: string;\n /** 组织名称 */\n organization?: string;\n /** 过期时间 */\n expiresAt?: Date;\n /** 最大用户数 */\n maxUsers?: number;\n /** 启用的云功能 */\n enabledCloudFeatures: CloudFeature[];\n}\n\n// ============ 功能注册表 ============\n\nconst FEATURE_REGISTRY: Record<FeatureKey, Omit<FeatureConfig, 'key' | 'enabled'>> = {\n // 开源功能\n [OpenSourceFeature.SQLITE_STORAGE]: {\n name: 'SQLite 存储',\n description: '本地 SQLite 数据库存储',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.POSTGRESQL_STORAGE]: {\n name: 'PostgreSQL 存储',\n description: 'PostgreSQL 云端数据库存储',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.EXACT_SEARCH]: {\n name: '精确搜索',\n description: 'L1 精确匹配搜索',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.FULLTEXT_SEARCH]: {\n name: '全文搜索',\n description: 'L2 全文索引搜索',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.DECISION_MEMORY]: {\n name: '决策记忆',\n description: '结构化架构决策记录',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.SOLUTION_MEMORY]: {\n name: '方案记忆',\n description: '问题解决方案记录',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.SESSION_MEMORY]: {\n name: '会话记忆',\n description: '会话总结记录',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.TIMELINE_VIEW]: {\n name: '时间线视图',\n description: '记忆时间线展示',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.RELATIONS_VIEW]: {\n name: '关系视图',\n description: '记忆关系链展示',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.MCP_SERVER]: {\n name: 'MCP Server',\n description: 'Model Context Protocol 服务器',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.REST_API]: {\n name: 'REST API',\n description: 'HTTP REST API 接口',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.WEB_DASHBOARD]: {\n name: 'Web Dashboard',\n description: 'Web 可视化管理面板',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.CLI_TOOL]: {\n name: 'CLI 工具',\n description: '命令行管理工具',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n\n // 云平台功能\n [CloudFeature.MULTI_TENANT]: {\n name: '多租户',\n description: '多租户隔离与管理',\n isOpenSource: false,\n requiredLicense: LicenseType.ENTERPRISE,\n },\n [CloudFeature.WORKSPACE_MANAGEMENT]: {\n name: '工作空间管理',\n description: '团队工作空间管理',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.SSO_SAML]: {\n name: 'SSO/SAML',\n description: '单点登录与 SAML 集成',\n isOpenSource: false,\n requiredLicense: LicenseType.ENTERPRISE,\n },\n [CloudFeature.OAUTH_INTEGRATION]: {\n name: 'OAuth 集成',\n description: 'OAuth 2.0 身份验证',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.RBAC]: {\n name: '角色权限',\n description: '基于角色的访问控制',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.AUTO_BACKUP]: {\n name: '自动备份',\n description: '定时自动备份数据',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.DATA_EXPORT]: {\n name: '数据导出',\n description: '批量数据导出',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.DATA_MIGRATION]: {\n name: '数据迁移',\n description: '跨存储数据迁移',\n isOpenSource: false,\n requiredLicense: LicenseType.ENTERPRISE,\n },\n [CloudFeature.SEMANTIC_SEARCH]: {\n name: '语义搜索',\n description: 'L3 向量语义搜索',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.ADVANCED_ANALYTICS]: {\n name: '高级分析',\n description: '使用统计与趋势分析',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.AUDIT_LOG]: {\n name: '审计日志',\n description: '操作审计记录',\n isOpenSource: false,\n requiredLicense: LicenseType.ENTERPRISE,\n },\n [CloudFeature.WEBHOOK]: {\n name: 'Webhook',\n description: 'Webhook 事件推送',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.CUSTOM_STORAGE]: {\n name: '自定义存储',\n description: '自定义存储后端',\n isOpenSource: false,\n requiredLicense: LicenseType.ENTERPRISE,\n },\n [CloudFeature.PRIORITY_SUPPORT]: {\n name: '优先支持',\n description: '优先技术支持',\n isOpenSource: false,\n requiredLicense: LicenseType.ENTERPRISE,\n },\n};\n\n// ============ Feature Flag 管理器 ============\n\nexport class FeatureManager {\n private license: LicenseInfo;\n private overrides: Map<FeatureKey, boolean> = new Map();\n\n constructor(license?: Partial<LicenseInfo>) {\n // 默认开源版许可证\n this.license = {\n type: LicenseType.OPEN_SOURCE,\n enabledCloudFeatures: [],\n ...license,\n };\n }\n\n /** 检查功能是否启用 */\n isEnabled(feature: FeatureKey): boolean {\n // 检查手动覆盖\n if (this.overrides.has(feature)) {\n return this.overrides.get(feature)!;\n }\n\n const config = FEATURE_REGISTRY[feature];\n if (!config) {\n return false;\n }\n\n // 开源功能默认启用\n if (config.isOpenSource) {\n return true;\n }\n\n // 云功能需要检查许可证\n return this.checkLicenseForFeature(feature as CloudFeature);\n }\n\n /** 检查许可证是否支持某云功能 */\n private checkLicenseForFeature(feature: CloudFeature): boolean {\n // 检查许可证是否过期\n if (this.license.expiresAt && new Date() > this.license.expiresAt) {\n return false;\n }\n\n // 检查是否在启用列表中\n if (this.license.enabledCloudFeatures.includes(feature)) {\n return true;\n }\n\n // 检查许可证类型是否满足要求\n const config = FEATURE_REGISTRY[feature];\n return this.isLicenseTypeAtLeast(config.requiredLicense);\n }\n\n /** 检查许可证等级 */\n private isLicenseTypeAtLeast(required: LicenseType): boolean {\n const levels: Record<LicenseType, number> = {\n [LicenseType.OPEN_SOURCE]: 0,\n [LicenseType.PROFESSIONAL]: 1,\n [LicenseType.ENTERPRISE]: 2,\n };\n return levels[this.license.type] >= levels[required];\n }\n\n /** 获取功能配置 */\n getFeatureConfig(feature: FeatureKey): FeatureConfig {\n const config = FEATURE_REGISTRY[feature];\n return {\n key: feature,\n ...config,\n enabled: this.isEnabled(feature),\n };\n }\n\n /** 获取所有功能配置 */\n getAllFeatures(): FeatureConfig[] {\n return Object.entries(FEATURE_REGISTRY).map(([key, config]) => ({\n key: key as FeatureKey,\n ...config,\n enabled: this.isEnabled(key as FeatureKey),\n }));\n }\n\n /** 获取所有开源功能 */\n getOpenSourceFeatures(): FeatureConfig[] {\n return this.getAllFeatures().filter(f => f.isOpenSource);\n }\n\n /** 获取所有云功能 */\n getCloudFeatures(): FeatureConfig[] {\n return this.getAllFeatures().filter(f => !f.isOpenSource);\n }\n\n /** 获取当前许可证信息 */\n getLicense(): LicenseInfo {\n return { ...this.license };\n }\n\n /** 更新许可证 */\n setLicense(license: Partial<LicenseInfo>): void {\n this.license = { ...this.license, ...license };\n }\n\n /** 手动覆盖功能开关(用于测试或特殊场景) */\n override(feature: FeatureKey, enabled: boolean): void {\n this.overrides.set(feature, enabled);\n }\n\n /** 清除覆盖 */\n clearOverride(feature: FeatureKey): void {\n this.overrides.delete(feature);\n }\n\n /** 清除所有覆盖 */\n clearAllOverrides(): void {\n this.overrides.clear();\n }\n\n /** 要求某功能可用,否则抛出异常 */\n require(feature: FeatureKey): void {\n if (!this.isEnabled(feature)) {\n const config = FEATURE_REGISTRY[feature];\n throw new FeatureNotAvailableError(\n feature,\n config.name,\n config.requiredLicense\n );\n }\n }\n}\n\n// ============ 错误类型 ============\n\nexport class FeatureNotAvailableError extends Error {\n constructor(\n public readonly feature: FeatureKey,\n public readonly featureName: string,\n public readonly requiredLicense: LicenseType\n ) {\n super(\n `功能 \"${featureName}\" 不可用。需要 ${requiredLicense} 许可证。` +\n `\\n访问 https://memory-pulse.com/pricing 了解更多。`\n );\n this.name = 'FeatureNotAvailableError';\n }\n}\n\n// ============ 全局实例 ============\n\n/** 全局 Feature Manager 实例 */\nlet globalFeatureManager: FeatureManager | null = null;\n\n/** 获取全局 Feature Manager */\nexport function getFeatureManager(): FeatureManager {\n if (!globalFeatureManager) {\n globalFeatureManager = new FeatureManager();\n }\n return globalFeatureManager;\n}\n\n/** 初始化全局 Feature Manager */\nexport function initFeatureManager(license?: Partial<LicenseInfo>): FeatureManager {\n globalFeatureManager = new FeatureManager(license);\n return globalFeatureManager;\n}\n\n/** 快捷方法:检查功能是否启用 */\nexport function isFeatureEnabled(feature: FeatureKey): boolean {\n return getFeatureManager().isEnabled(feature);\n}\n\n/** 快捷方法:要求功能可用 */\nexport function requireFeature(feature: FeatureKey): void {\n getFeatureManager().require(feature);\n}\n","/**\n * Embedding 服务接口\n *\n * 用于将文本转换为向量,支持语义搜索\n */\n\n// ============ 类型定义 ============\n\n/** 向量类型(固定长度的数字数组) */\nexport type Vector = number[];\n\n/** Embedding 结果 */\nexport interface EmbeddingResult {\n /** 向量 */\n vector: Vector;\n /** 模型名称 */\n model: string;\n /** 向量维度 */\n dimensions: number;\n /** token 使用量(如适用) */\n tokenUsage?: number;\n}\n\n/** 批量 Embedding 结果 */\nexport interface BatchEmbeddingResult {\n /** 向量列表 */\n vectors: Vector[];\n /** 模型名称 */\n model: string;\n /** 向量维度 */\n dimensions: number;\n /** 总 token 使用量 */\n totalTokenUsage?: number;\n}\n\n/** Embedding 提供者配置 */\nexport interface EmbeddingProviderConfig {\n /** 提供者类型 */\n provider: 'openai' | 'ollama' | 'local' | 'mock';\n /** API Key(OpenAI 等云服务需要) */\n apiKey?: string;\n /** 模型名称 */\n model?: string;\n /** API 基础 URL(自定义端点) */\n baseUrl?: string;\n /** 向量维度(某些模型支持自定义) */\n dimensions?: number;\n}\n\n// ============ Embedding 服务接口 ============\n\n/** Embedding 服务接口 */\nexport interface IEmbeddingService {\n /** 获取提供者名称 */\n readonly provider: string;\n\n /** 获取模型名称 */\n readonly model: string;\n\n /** 获取向量维度 */\n readonly dimensions: number;\n\n /**\n * 生成单个文本的 Embedding\n * @param text 输入文本\n * @returns Embedding 结果\n */\n embed(text: string): Promise<EmbeddingResult>;\n\n /**\n * 批量生成 Embedding\n * @param texts 输入文本列表\n * @returns 批量 Embedding 结果\n */\n embedBatch(texts: string[]): Promise<BatchEmbeddingResult>;\n\n /**\n * 计算两个向量的相似度\n * @param a 向量 A\n * @param b 向量 B\n * @returns 相似度分数(0-1,1 表示完全相同)\n */\n similarity(a: Vector, b: Vector): number;\n}\n\n// ============ 向量工具函数 ============\n\n/**\n * 计算余弦相似度\n * @param a 向量 A\n * @param b 向量 B\n * @returns 相似度(-1 到 1,1 表示完全相同)\n */\nexport function cosineSimilarity(a: Vector, b: Vector): number {\n if (a.length !== b.length) {\n throw new Error(`向量维度不匹配: ${a.length} vs ${b.length}`);\n }\n\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n\n const magnitude = Math.sqrt(normA) * Math.sqrt(normB);\n if (magnitude === 0) return 0;\n\n return dotProduct / magnitude;\n}\n\n/**\n * 计算欧氏距离\n * @param a 向量 A\n * @param b 向量 B\n * @returns 距离(越小越相似)\n */\nexport function euclideanDistance(a: Vector, b: Vector): number {\n if (a.length !== b.length) {\n throw new Error(`向量维度不匹配: ${a.length} vs ${b.length}`);\n }\n\n let sum = 0;\n for (let i = 0; i < a.length; i++) {\n const diff = a[i] - b[i];\n sum += diff * diff;\n }\n\n return Math.sqrt(sum);\n}\n\n/**\n * 将欧氏距离转换为相似度分数(0-1)\n * @param distance 欧氏距离\n * @returns 相似度分数\n */\nexport function distanceToSimilarity(distance: number): number {\n return 1 / (1 + distance);\n}\n\n/**\n * 归一化向量(使其长度为 1)\n * @param v 输入向量\n * @returns 归一化后的向量\n */\nexport function normalizeVector(v: Vector): Vector {\n const norm = Math.sqrt(v.reduce((sum, x) => sum + x * x, 0));\n if (norm === 0) return v;\n return v.map(x => x / norm);\n}\n\n/**\n * 向量序列化(用于存储)\n * @param v 向量\n * @returns Base64 编码的字符串\n */\nexport function serializeVector(v: Vector): string {\n const buffer = new Float32Array(v);\n const bytes = new Uint8Array(buffer.buffer);\n return Buffer.from(bytes).toString('base64');\n}\n\n/**\n * 向量反序列化\n * @param s Base64 编码的字符串\n * @returns 向量\n */\nexport function deserializeVector(s: string): Vector {\n const bytes = Buffer.from(s, 'base64');\n const buffer = new Float32Array(bytes.buffer, bytes.byteOffset, bytes.length / 4);\n return Array.from(buffer);\n}\n\n// ============ 默认配置 ============\n\n/** OpenAI 默认配置 */\nexport const OPENAI_DEFAULTS = {\n model: 'text-embedding-3-small',\n dimensions: 1536,\n baseUrl: 'https://api.openai.com/v1',\n} as const;\n\n/** Ollama 默认配置 */\nexport const OLLAMA_DEFAULTS = {\n model: 'nomic-embed-text',\n dimensions: 768,\n baseUrl: 'http://localhost:11434',\n} as const;\n\n/** 本地模型默认配置 */\nexport const LOCAL_DEFAULTS = {\n model: 'all-MiniLM-L6-v2',\n dimensions: 384,\n} as const;\n","import type Database from 'better-sqlite3';\n\n/**\n * 数据库迁移:为旧表添加 embedding 字段\n */\nfunction migrateEmbeddingColumn(db: Database.Database): void {\n // 检查 embedding 列是否存在\n const columns = db.pragma('table_info(memories)') as { name: string }[];\n const hasEmbedding = columns.some((col) => col.name === 'embedding');\n\n if (!hasEmbedding) {\n console.log('📦 迁移: 添加 embedding 字段...');\n db.exec('ALTER TABLE memories ADD COLUMN embedding TEXT');\n console.log('✅ 迁移完成');\n }\n}\n\n/**\n * 初始化数据库Schema\n */\nexport function initSchema(db: Database.Database): void {\n // 1. 创建memories主表\n db.exec(`\n CREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n sessionId TEXT,\n timestamp TEXT NOT NULL,\n type TEXT NOT NULL,\n tags TEXT, -- JSON数组: [\"tag1\", \"tag2\"]\n version INTEGER DEFAULT 1,\n\n -- content\n summary TEXT NOT NULL,\n data TEXT, -- JSON对象\n\n -- relations\n replaces TEXT, -- JSON数组\n relatedTo TEXT, -- JSON数组\n impacts TEXT, -- JSON数组\n derivedFrom TEXT,\n\n -- context(特定类型的上下文数据)\n context TEXT, -- JSON对象\n\n -- searchable\n keywords TEXT, -- JSON数组\n fullText TEXT,\n embedding TEXT, -- Base64 编码的向量(用于语义搜索)\n\n -- 时间戳\n createdAt TEXT NOT NULL,\n updatedAt TEXT NOT NULL,\n\n -- 索引字段\n UNIQUE(id)\n );\n `);\n\n // 2. 创建索引\n db.exec(`\n -- 项目ID索引(频繁按项目查询)\n CREATE INDEX IF NOT EXISTS idx_memories_projectId ON memories(projectId);\n\n -- 会话ID索引\n CREATE INDEX IF NOT EXISTS idx_memories_sessionId ON memories(sessionId);\n\n -- 类型索引\n CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);\n\n -- 时间戳索引(用于时间线查询)\n CREATE INDEX IF NOT EXISTS idx_memories_timestamp ON memories(timestamp DESC);\n\n -- 复合索引(项目+类型)- 用于按项目和类型过滤\n CREATE INDEX IF NOT EXISTS idx_memories_project_type ON memories(projectId, type);\n\n -- 复合索引(项目+时间)- 用于项目时间线查询,性能提升显著\n CREATE INDEX IF NOT EXISTS idx_memories_project_timestamp ON memories(projectId, timestamp DESC);\n\n -- 复合索引(项目+类型+时间)- 用于按项目和类型过滤的时间线\n CREATE INDEX IF NOT EXISTS idx_memories_project_type_timestamp ON memories(projectId, type, timestamp DESC);\n\n -- 部分索引(仅索引有会话的记忆)- 减少索引大小\n CREATE INDEX IF NOT EXISTS idx_memories_session_active ON memories(sessionId, timestamp DESC)\n WHERE sessionId IS NOT NULL;\n `);\n\n // 3. 创建FTS5全文搜索表\n db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(\n summary,\n fullText,\n tokenize = 'unicode61'\n );\n `);\n\n // 4. 创建触发器,自动同步FTS表\n db.exec(`\n -- 插入触发器\n CREATE TRIGGER IF NOT EXISTS memories_fts_insert AFTER INSERT ON memories BEGIN\n INSERT INTO memories_fts(rowid, summary, fullText)\n VALUES (new.rowid, new.summary, new.fullText);\n END;\n\n -- 更新触发器\n CREATE TRIGGER IF NOT EXISTS memories_fts_update AFTER UPDATE ON memories BEGIN\n UPDATE memories_fts\n SET summary = new.summary, fullText = new.fullText\n WHERE rowid = new.rowid;\n END;\n\n -- 删除触发器\n CREATE TRIGGER IF NOT EXISTS memories_fts_delete AFTER DELETE ON memories BEGIN\n DELETE FROM memories_fts WHERE rowid = old.rowid;\n END;\n `);\n\n // 5. 数据库迁移(兼容旧数据库)\n migrateEmbeddingColumn(db);\n}\n","import type { SearchResult, SearchFilters } from '@emp/core';\n\n/**\n * LRU 缓存节点\n */\ninterface CacheNode {\n key: string;\n value: SearchResult;\n prev: CacheNode | null;\n next: CacheNode | null;\n}\n\n/**\n * LRU(Least Recently Used)缓存\n * 用于缓存热点查询,提升检索性能\n */\nexport class LRUCache {\n private capacity: number;\n private cache: Map<string, CacheNode>;\n private head: CacheNode | null;\n private tail: CacheNode | null;\n private hits: number;\n private misses: number;\n\n constructor(capacity: number = 100) {\n this.capacity = capacity;\n this.cache = new Map();\n this.head = null;\n this.tail = null;\n this.hits = 0;\n this.misses = 0;\n }\n\n /**\n * 生成缓存 key\n */\n static generateKey(filters: SearchFilters): string {\n const parts = [\n filters.query || '',\n filters.projectId || '',\n filters.type || '',\n filters.sessionId || '',\n filters.strategy || '',\n filters.limit || '',\n filters.offset || '',\n (filters.tags || []).sort().join(','),\n ];\n return parts.join('|');\n }\n\n /**\n * 获取缓存\n */\n get(key: string): SearchResult | null {\n const node = this.cache.get(key);\n if (!node) {\n this.misses++;\n return null;\n }\n\n // 移到链表头部(最近使用)\n this.moveToHead(node);\n this.hits++;\n\n // 标记为缓存命中\n return {\n ...node.value,\n metrics: {\n dbTime: node.value.metrics?.dbTime || 0,\n parseTime: node.value.metrics?.parseTime || 0,\n strategyTime: node.value.metrics?.strategyTime,\n cacheHit: true,\n },\n };\n }\n\n /**\n * 设置缓存\n */\n set(key: string, value: SearchResult): void {\n let node = this.cache.get(key);\n\n if (node) {\n // 更新已存在的节点\n node.value = value;\n this.moveToHead(node);\n } else {\n // 创建新节点\n node = {\n key,\n value,\n prev: null,\n next: null,\n };\n\n this.cache.set(key, node);\n this.addToHead(node);\n\n // 超出容量,删除最少使用的\n if (this.cache.size > this.capacity) {\n const removed = this.removeTail();\n if (removed) {\n this.cache.delete(removed.key);\n }\n }\n }\n }\n\n /**\n * 清空缓存\n */\n clear(): void {\n this.cache.clear();\n this.head = null;\n this.tail = null;\n this.hits = 0;\n this.misses = 0;\n }\n\n /**\n * 失效指定项目的所有缓存\n */\n invalidateProject(projectId: string): void {\n const keysToDelete: string[] = [];\n\n for (const [key, _] of this.cache) {\n if (key.includes(`|${projectId}|`)) {\n keysToDelete.push(key);\n }\n }\n\n for (const key of keysToDelete) {\n const node = this.cache.get(key);\n if (node) {\n this.removeNode(node);\n this.cache.delete(key);\n }\n }\n }\n\n /**\n * 获取缓存统计\n */\n getStats() {\n const total = this.hits + this.misses;\n return {\n size: this.cache.size,\n capacity: this.capacity,\n hits: this.hits,\n misses: this.misses,\n hitRate: total > 0 ? this.hits / total : 0,\n };\n }\n\n // ========== 双向链表操作 ==========\n\n private addToHead(node: CacheNode): void {\n node.next = this.head;\n node.prev = null;\n\n if (this.head) {\n this.head.prev = node;\n }\n\n this.head = node;\n\n if (!this.tail) {\n this.tail = node;\n }\n }\n\n private removeNode(node: CacheNode): void {\n if (node.prev) {\n node.prev.next = node.next;\n } else {\n this.head = node.next;\n }\n\n if (node.next) {\n node.next.prev = node.prev;\n } else {\n this.tail = node.prev;\n }\n }\n\n private moveToHead(node: CacheNode): void {\n this.removeNode(node);\n this.addToHead(node);\n }\n\n private removeTail(): CacheNode | null {\n const node = this.tail;\n if (node) {\n this.removeNode(node);\n }\n return node;\n }\n}\n","import { PrismaClient, Prisma } from '@prisma/client';\nimport { nanoid } from 'nanoid';\nimport {\n type IStorage,\n type SearchFilters,\n type SearchResult,\n type TimelineOptions,\n type TimelineResult,\n type TimelineEntry,\n type RelationsOptions,\n type RelationNode,\n MemoryType,\n SearchStrategy,\n type Memory,\n type DecisionContext,\n type SolutionContext,\n type SessionContext,\n} from '@emp/core';\nimport { LRUCache } from './cache.js';\n\n/**\n * PostgreSQL存储实现(云版)\n * 使用Prisma ORM + PostgreSQL全文搜索\n */\nexport class PostgreSQLStorage implements IStorage {\n private prisma: PrismaClient;\n private cache: LRUCache | null;\n\n constructor(databaseUrl?: string, options?: { enableCache?: boolean; cacheSize?: number }) {\n this.prisma = new PrismaClient({\n datasources: databaseUrl\n ? {\n db: { url: databaseUrl },\n }\n : undefined,\n });\n\n // 初始化缓存(默认启用,容量100)\n this.cache = options?.enableCache !== false ? new LRUCache(options?.cacheSize || 100) : null;\n }\n\n /**\n * 通用存储方法\n */\n async store(params: {\n content: string;\n rawContext: Record<string, unknown>;\n projectId: string;\n type?: MemoryType;\n tags?: string[];\n sessionId?: string;\n relations?: {\n replaces?: string[];\n relatedTo?: string[];\n impacts?: string[];\n derivedFrom?: string;\n };\n }): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date();\n const memoryType = params.type || MemoryType.CODE;\n\n await this.prisma.memory.create({\n data: {\n id,\n projectId: params.projectId,\n sessionId: params.sessionId || null,\n timestamp,\n type: memoryType,\n tags: params.tags || [],\n summary: params.content,\n data: params.rawContext as any,\n replaces: params.relations?.replaces || [],\n relatedTo: params.relations?.relatedTo || [],\n impacts: params.relations?.impacts || [],\n derivedFrom: params.relations?.derivedFrom || null,\n context: params.rawContext as any,\n keywords: params.tags || [],\n fullText: params.content,\n },\n });\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 存储决策记忆\n */\n async storeDecision(\n params: DecisionContext & {\n projectId: string;\n tags?: string[];\n sessionId?: string;\n relations?: {\n replaces?: string[];\n relatedTo?: string[];\n impacts?: string[];\n derivedFrom?: string;\n };\n }\n ): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date();\n const summary = `[决策] ${params.question}`;\n const fullText = `${params.question} ${params.options.map((o) => o.name).join(' ')} ${params.reason}`;\n const keywords = [...(params.tags || []), ...params.options.map((o) => o.name), params.chosen];\n\n await this.prisma.memory.create({\n data: {\n id,\n projectId: params.projectId,\n sessionId: params.sessionId || null,\n timestamp,\n type: MemoryType.DECISION,\n tags: params.tags || [],\n summary,\n data: {},\n replaces: params.relations?.replaces || [],\n relatedTo: params.relations?.relatedTo || [],\n impacts: params.relations?.impacts || [],\n derivedFrom: params.relations?.derivedFrom || null,\n context: {\n question: params.question,\n analysis: params.analysis,\n options: params.options,\n chosen: params.chosen,\n reason: params.reason,\n } as any,\n keywords,\n fullText,\n },\n });\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 存储解决方案记忆\n */\n async storeSolution(\n params: SolutionContext & {\n projectId: string;\n tags?: string[];\n sessionId?: string;\n artifacts?: Record<string, string>;\n relations?: {\n replaces?: string[];\n relatedTo?: string[];\n impacts?: string[];\n derivedFrom?: string;\n };\n }\n ): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date();\n const summary = `[方案] ${params.problem}`;\n const fullText = `${params.problem} ${params.rootCause} ${params.solution} ${params.prevention || ''} ${params.relatedIssues?.join(' ') || ''}`;\n const keywords = [...(params.tags || []), ...(params.relatedIssues || [])];\n\n await this.prisma.memory.create({\n data: {\n id,\n projectId: params.projectId,\n sessionId: params.sessionId || null,\n timestamp,\n type: MemoryType.SOLUTION,\n tags: params.tags || [],\n summary,\n data: (params.artifacts || {}) as any,\n replaces: params.relations?.replaces || [],\n relatedTo: params.relations?.relatedTo || [],\n impacts: params.relations?.impacts || [],\n derivedFrom: params.relations?.derivedFrom || null,\n context: {\n problem: params.problem,\n rootCause: params.rootCause,\n solution: params.solution,\n prevention: params.prevention,\n relatedIssues: params.relatedIssues,\n } as any,\n keywords,\n fullText,\n },\n });\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 存储会话记忆\n */\n async storeSession(\n params: SessionContext & {\n projectId: string;\n sessionId?: string;\n }\n ): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date();\n const summary = `[会话] ${params.summary}`;\n const fullText = `${params.summary} ${params.decisions?.join(' ') || ''} ${params.unfinishedTasks?.join(' ') || ''} ${params.nextSteps?.join(' ') || ''}`;\n const keywords = [...(params.decisions || []), ...(params.unfinishedTasks || [])];\n\n await this.prisma.memory.create({\n data: {\n id,\n projectId: params.projectId,\n sessionId: params.sessionId || id,\n timestamp,\n type: MemoryType.SESSION,\n tags: [],\n summary,\n data: {},\n replaces: [],\n relatedTo: [],\n impacts: [],\n derivedFrom: null,\n context: {\n summary: params.summary,\n decisions: params.decisions,\n unfinishedTasks: params.unfinishedTasks,\n nextSteps: params.nextSteps,\n } as any,\n keywords,\n fullText,\n },\n });\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 检索记忆\n */\n async recall(filters: SearchFilters): Promise<SearchResult> {\n const startTime = Date.now();\n\n // 检查缓存\n if (this.cache) {\n const cacheKey = LRUCache.generateKey(filters);\n const cached = this.cache.get(cacheKey);\n if (cached) {\n return cached; // 缓存命中,直接返回\n }\n }\n\n const strategy = filters.strategy || SearchStrategy.AUTO;\n const limit = filters.limit || 10;\n const offset = filters.offset || 0;\n\n let actualStrategy: SearchStrategy;\n let results: Memory[];\n let dbStartTime: number;\n let dbEndTime: number;\n\n // 策略选择\n const strategyStartTime = Date.now();\n\n // L1: 精确匹配(优先)\n if (strategy === SearchStrategy.EXACT || strategy === SearchStrategy.AUTO) {\n dbStartTime = Date.now();\n results = await this.exactSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.EXACT;\n\n // 如果L1找不到结果,降级到L2全文搜索\n if (results.length === 0 && strategy === SearchStrategy.AUTO) {\n dbStartTime = Date.now();\n results = await this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n }\n }\n // L2: 全文搜索\n else if (strategy === SearchStrategy.FULLTEXT) {\n dbStartTime = Date.now();\n results = await this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n }\n // L3: 语义检索(暂未实现)\n else {\n dbStartTime = Date.now();\n results = await this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n }\n\n const strategyTime = Date.now() - strategyStartTime;\n const took = Date.now() - startTime;\n\n // 计算解析时间(总时间 - 数据库时间)\n const dbTime = dbEndTime - dbStartTime;\n const parseTime = took - dbTime - strategyTime;\n\n const result: SearchResult = {\n memories: results,\n total: results.length,\n strategy: actualStrategy,\n took,\n metrics: {\n dbTime,\n parseTime: Math.max(0, parseTime), // 确保非负\n strategyTime,\n cacheHit: false, // 数据库查询,标记为未命中\n },\n };\n\n // 写入缓存\n if (this.cache) {\n const cacheKey = LRUCache.generateKey(filters);\n this.cache.set(cacheKey, result);\n }\n\n return result;\n }\n\n /**\n * L1: 精确匹配检索\n */\n private async exactSearch(\n filters: SearchFilters,\n limit: number,\n offset: number\n ): Promise<Memory[]> {\n const where: Prisma.MemoryWhereInput = {};\n\n if (filters.projectId) {\n where.projectId = filters.projectId;\n }\n\n if (filters.type) {\n where.type = filters.type;\n }\n\n if (filters.sessionId) {\n where.sessionId = filters.sessionId;\n }\n\n if (filters.query) {\n where.OR = [\n { summary: { contains: filters.query, mode: 'insensitive' } },\n { fullText: { contains: filters.query, mode: 'insensitive' } },\n ];\n }\n\n const rows = await this.prisma.memory.findMany({\n where,\n orderBy: { timestamp: 'desc' },\n take: limit,\n skip: offset,\n });\n\n return rows.map(this.rowToMemory);\n }\n\n /**\n * L2: 全文搜索(PostgreSQL)\n */\n private async fulltextSearch(\n filters: SearchFilters,\n limit: number,\n offset: number\n ): Promise<Memory[]> {\n // 使用PostgreSQL的ILIKE进行简单全文搜索\n // 生产环境可以使用pg_trgm或to_tsvector实现更强大的搜索\n const where: Prisma.MemoryWhereInput = {};\n\n if (filters.projectId) {\n where.projectId = filters.projectId;\n }\n\n if (filters.type) {\n where.type = filters.type;\n }\n\n if (filters.sessionId) {\n where.sessionId = filters.sessionId;\n }\n\n if (filters.query) {\n where.OR = [\n { summary: { contains: filters.query, mode: 'insensitive' } },\n { fullText: { contains: filters.query, mode: 'insensitive' } },\n ];\n }\n\n const rows = await this.prisma.memory.findMany({\n where,\n orderBy: { timestamp: 'desc' },\n take: limit,\n skip: offset,\n });\n\n return rows.map(this.rowToMemory);\n }\n\n /**\n * 获取时间线\n */\n async getTimeline(options: TimelineOptions): Promise<TimelineResult> {\n const where: Prisma.MemoryWhereInput = {\n projectId: options.projectId,\n };\n\n if (options.type) {\n where.type = options.type;\n }\n\n if (options.dateRange) {\n where.timestamp = {\n gte: new Date(options.dateRange[0]),\n lte: new Date(options.dateRange[1]),\n };\n }\n\n const memories = await this.prisma.memory.findMany({\n where,\n orderBy: { timestamp: 'desc' },\n take: options.limit,\n skip: options.offset,\n });\n\n const converted = memories.map(this.rowToMemory);\n\n const entries: TimelineEntry[] = converted.map((memory, index) => ({\n memory,\n prevMemoryId: index > 0 ? converted[index - 1].meta.id : undefined,\n nextMemoryId: index < converted.length - 1 ? converted[index + 1].meta.id : undefined,\n }));\n\n return {\n entries,\n total: entries.length,\n };\n }\n\n /**\n * 获取关系链\n */\n async getRelations(options: RelationsOptions): Promise<RelationNode> {\n const memory = await this.getMemoryById(options.memoryId);\n if (!memory) {\n throw new Error(`Memory ${options.memoryId} not found`);\n }\n\n const depth = options.depth || 1;\n const relatedNodes: RelationNode[] = [];\n\n if (depth > 0) {\n // 查找所有相关记忆\n const relatedIds = [\n ...(memory.relations.replaces || []),\n ...(memory.relations.relatedTo || []),\n ...(memory.relations.impacts || []),\n ];\n\n if (memory.relations.derivedFrom) {\n relatedIds.push(memory.relations.derivedFrom);\n }\n\n for (const relatedId of relatedIds) {\n const relatedMemory = await this.getMemoryById(relatedId);\n if (relatedMemory) {\n // 递归查询关系链\n let nestedRelated: RelationNode[] | undefined = undefined;\n if (depth > 1) {\n const nestedResult = await this.getRelations({\n memoryId: relatedId,\n depth: depth - 1,\n });\n nestedRelated = nestedResult.related;\n }\n\n relatedNodes.push({\n memory: relatedMemory,\n related: nestedRelated,\n });\n }\n }\n }\n\n return {\n memory,\n related: relatedNodes.length > 0 ? relatedNodes : undefined,\n };\n }\n\n /**\n * 根据 ID 获取单个记忆\n */\n async getById(id: string): Promise<Memory | null> {\n const row = await this.prisma.memory.findUnique({\n where: { id },\n });\n return row ? this.rowToMemory(row) : null;\n }\n\n /**\n * 删除记忆\n */\n async delete(memoryId: string): Promise<{ success: boolean }> {\n try {\n // 先查询 projectId 用于缓存失效\n if (this.cache) {\n const memory = await this.prisma.memory.findUnique({\n where: { id: memoryId },\n select: { projectId: true },\n });\n if (memory) {\n this.cache.invalidateProject(memory.projectId);\n }\n }\n\n await this.prisma.memory.delete({\n where: { id: memoryId },\n });\n return { success: true };\n } catch (error) {\n return { success: false };\n }\n }\n\n /**\n * 更新记忆\n */\n async update(memoryId: string, updates: Partial<Memory>): Promise<{ success: boolean }> {\n try {\n const data: Prisma.MemoryUpdateInput = {};\n\n if (updates.content) {\n if (updates.content.summary) {\n data.summary = updates.content.summary;\n }\n if (updates.content.data !== undefined) {\n data.data = updates.content.data as any;\n }\n }\n\n if (updates.meta?.tags) {\n data.tags = updates.meta.tags;\n }\n\n if (updates.relations) {\n if (updates.relations.replaces) {\n data.replaces = updates.relations.replaces;\n }\n if (updates.relations.relatedTo) {\n data.relatedTo = updates.relations.relatedTo;\n }\n if (updates.relations.impacts) {\n data.impacts = updates.relations.impacts;\n }\n if (updates.relations.derivedFrom) {\n data.derivedFrom = updates.relations.derivedFrom;\n }\n }\n\n if (Object.keys(data).length === 0) {\n return { success: false };\n }\n\n await this.prisma.memory.update({\n where: { id: memoryId },\n data,\n });\n\n // 失效相关缓存\n if (this.cache) {\n const memory = await this.prisma.memory.findUnique({\n where: { id: memoryId },\n select: { projectId: true },\n });\n if (memory) {\n this.cache.invalidateProject(memory.projectId);\n }\n }\n\n return { success: true };\n } catch (error) {\n return { success: false };\n }\n }\n\n /**\n * 根据ID获取记忆\n */\n private async getMemoryById(id: string): Promise<Memory | null> {\n const row = await this.prisma.memory.findUnique({\n where: { id },\n });\n return row ? this.rowToMemory(row) : null;\n }\n\n /**\n * 将Prisma行转换为Memory对象\n */\n private rowToMemory(row: any): Memory {\n return {\n meta: {\n id: row.id,\n projectId: row.projectId,\n sessionId: row.sessionId,\n timestamp: row.timestamp.toISOString(),\n type: row.type as MemoryType,\n tags: row.tags || [],\n version: row.version,\n },\n content: {\n summary: row.summary,\n data: (row.data || {}) as Record<string, unknown>,\n },\n relations: {\n replaces: row.replaces || undefined,\n relatedTo: row.relatedTo || undefined,\n impacts: row.impacts || undefined,\n derivedFrom: row.derivedFrom || undefined,\n },\n searchable: {\n keywords: row.keywords || [],\n fullText: row.fullText,\n },\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n }\n\n /**\n * 关闭数据库连接\n */\n async close(): Promise<void> {\n await this.prisma.$disconnect();\n }\n}\n"],"mappings":"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","names":["MemoryType","SearchStrategy","OpenSourceFeature","CloudFeature","LicenseType","nanoid","nanoid"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../../storage/src/sqlite-storage.ts","../../core/src/types.ts","../../core/src/features.ts","../../core/src/embedding.ts","../../storage/src/schema.ts","../../storage/src/cache.ts","../../storage/src/postgresql-storage.ts"],"sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n ListResourcesRequestSchema,\n ReadResourceRequestSchema,\n ListPromptsRequestSchema,\n GetPromptRequestSchema,\n Tool,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { SQLiteStorage, PostgreSQLStorage } from '@emp/storage';\nimport type {\n IStorage,\n DecisionContext,\n SolutionContext,\n SessionContext,\n SearchFilters,\n TimelineOptions,\n RelationsOptions,\n} from '@emp/core';\nimport { SearchStrategy } from '@emp/core';\nimport { execSync } from 'child_process';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\nimport { mkdirSync, writeFileSync } from 'fs';\nimport { homedir } from 'os';\n\n/**\n * Memory Pulse (记忆脉搏) MCP Server\n *\n * 提供以下工具:\n * - mpulse_store: 智能存储\n * - mpulse_store_decision: 存储决策\n * - mpulse_store_solution: 存储解决方案\n * - mpulse_store_session: 存储会话\n * - mpulse_recall: 检索记忆(全文搜索,AI 自己理解语义)\n * - mpulse_timeline: 时间线视图\n * - mpulse_relations: 关系链查询\n */\n\nconst server = new Server(\n {\n name: 'elb-memory-pulse',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n resources: {},\n prompts: {},\n },\n }\n);\n\n// 存储类型:sqlite(默认) 或 postgresql\nconst storageType = process.env.MEMORY_STORAGE || 'sqlite';\n\n// 获取当前文件目录(用于定位 prisma schema)\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// 运行时配置文件路径(供 API Server 读取)\nconst RUNTIME_CONFIG_PATH = join(homedir(), '.emp', 'runtime-config.json');\n\n/**\n * 写入运行时配置,供 API Server 读取\n * 这样用户只需在 MCP 配置中设置数据库参数,Web Dashboard 自动跟随\n */\nfunction writeRuntimeConfig(config: {\n storageType: string;\n databaseUrl?: string;\n dbPath?: string;\n}) {\n try {\n const configDir = dirname(RUNTIME_CONFIG_PATH);\n mkdirSync(configDir, { recursive: true });\n writeFileSync(\n RUNTIME_CONFIG_PATH,\n JSON.stringify(\n {\n ...config,\n updatedAt: new Date().toISOString(),\n pid: process.pid,\n },\n null,\n 2\n )\n );\n console.error(`📝 运行时配置已写入: ${RUNTIME_CONFIG_PATH}`);\n } catch (error) {\n console.error('⚠️ 写入运行时配置失败:', (error as Error).message);\n }\n}\n\n// 初始化存储\nfunction createStorage(): IStorage {\n if (storageType === 'postgresql') {\n const databaseUrl = process.env.DATABASE_URL;\n if (!databaseUrl) {\n console.error('错误: 使用 PostgreSQL 存储需要设置 DATABASE_URL 环境变量');\n process.exit(1);\n }\n console.error(`Memory Pulse 使用 PostgreSQL 存储: ${databaseUrl.replace(/:[^:@]+@/, ':****@')}`);\n\n // 自动推送数据库表结构\n try {\n const schemaPath = join(__dirname, '..', 'prisma', 'schema.prisma');\n console.error('📦 正在同步数据库表结构...');\n execSync(`npx prisma db push --schema=\"${schemaPath}\" --skip-generate`, {\n env: { ...process.env, DATABASE_URL: databaseUrl },\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n console.error('✅ 数据库表结构同步完成');\n } catch (error) {\n console.error('⚠️ 数据库表结构同步失败(可能表已存在):', (error as Error).message);\n }\n\n // 写入运行时配置,供 API Server 读取\n writeRuntimeConfig({\n storageType: 'postgresql',\n databaseUrl,\n });\n\n return new PostgreSQLStorage(databaseUrl);\n }\n\n // SQLite 存储(默认)\n const dbPath = process.env.MEMORY_DB_PATH || './memory.db';\n console.error(`Memory Pulse 使用 SQLite 存储: ${dbPath}`);\n\n // 写入运行时配置,供 API Server 读取\n writeRuntimeConfig({\n storageType: 'sqlite',\n dbPath,\n });\n\n return new SQLiteStorage(dbPath);\n}\n\nconst storage = createStorage();\n\n// 定义工具列表\nconst tools: Tool[] = [\n {\n name: 'mpulse_store',\n description: '智能存储记忆,AI 自动分类和结构化',\n inputSchema: {\n type: 'object',\n properties: {\n content: {\n type: 'string',\n description: 'AI 总结的内容',\n },\n rawContext: {\n type: 'object',\n description: '完整原始数据(不压缩)',\n },\n projectId: {\n type: 'string',\n description: '项目 ID',\n },\n type: {\n type: 'string',\n enum: ['decision', 'solution', 'config', 'code', 'error', 'session'],\n description: '记忆类型(可选,不填则默认为 code)',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: '标签',\n },\n sessionId: {\n type: 'string',\n description: '会话 ID(可选)',\n },\n },\n required: ['content', 'rawContext', 'projectId'],\n },\n },\n {\n name: 'mpulse_store_decision',\n description: '存储架构决策(强制字段,防止 AI 偷懒)',\n inputSchema: {\n type: 'object',\n properties: {\n question: {\n type: 'string',\n description: '决策问题',\n },\n options: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n pros: { type: 'array', items: { type: 'string' } },\n cons: { type: 'array', items: { type: 'string' } },\n },\n required: ['name', 'pros', 'cons'],\n },\n description: '考虑的选项',\n },\n chosen: {\n type: 'string',\n description: '选择的方案',\n },\n reason: {\n type: 'string',\n description: '选择理由',\n },\n projectId: {\n type: 'string',\n description: '项目 ID',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: '标签',\n },\n sessionId: {\n type: 'string',\n description: '会话 ID(可选)',\n },\n },\n required: ['question', 'options', 'chosen', 'reason', 'projectId'],\n },\n },\n {\n name: 'mpulse_store_solution',\n description: '存储问题解决方案',\n inputSchema: {\n type: 'object',\n properties: {\n problem: {\n type: 'string',\n description: '问题描述',\n },\n rootCause: {\n type: 'string',\n description: '根因分析',\n },\n solution: {\n type: 'string',\n description: '解决方案',\n },\n prevention: {\n type: 'string',\n description: '如何预防',\n },\n relatedIssues: {\n type: 'array',\n items: { type: 'string' },\n description: '关联问题',\n },\n projectId: {\n type: 'string',\n description: '项目 ID',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: '标签',\n },\n sessionId: {\n type: 'string',\n description: '会话 ID(可选)',\n },\n artifacts: {\n type: 'object',\n description: '相关文件(代码片段等)',\n },\n },\n required: ['problem', 'rootCause', 'solution', 'projectId'],\n },\n },\n {\n name: 'mpulse_store_session',\n description: '存储会话总结(会话结束时调用)',\n inputSchema: {\n type: 'object',\n properties: {\n summary: {\n type: 'string',\n description: '本次会话总结',\n },\n decisions: {\n type: 'array',\n items: { type: 'string' },\n description: '本次做出的决策',\n },\n unfinishedTasks: {\n type: 'array',\n items: { type: 'string' },\n description: '未完成的任务',\n },\n nextSteps: {\n type: 'array',\n items: { type: 'string' },\n description: '下次从哪继续',\n },\n projectId: {\n type: 'string',\n description: '项目 ID',\n },\n sessionId: {\n type: 'string',\n description: '会话 ID',\n },\n },\n required: ['summary', 'projectId', 'sessionId'],\n },\n },\n {\n name: 'mpulse_recall',\n description: '检索记忆(全文搜索,AI 自己理解结果语义)',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: '查询内容',\n },\n projectId: {\n type: 'string',\n description: '项目 ID',\n },\n type: {\n type: 'string',\n enum: ['decision', 'solution', 'config', 'code', 'error', 'session'],\n description: '记忆类型',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: '标签过滤',\n },\n strategy: {\n type: 'string',\n enum: ['exact', 'fulltext', 'auto'],\n description: '检索策略(默认 fulltext 全文搜索)',\n },\n limit: {\n type: 'number',\n description: '返回数量',\n },\n },\n required: ['query'],\n },\n },\n {\n name: 'mpulse_timeline',\n description: '查看项目的时间线视图',\n inputSchema: {\n type: 'object',\n properties: {\n projectId: {\n type: 'string',\n description: '项目 ID',\n },\n dateRange: {\n type: 'array',\n items: { type: 'string' },\n description: '日期范围 [start, end]',\n },\n type: {\n type: 'string',\n enum: ['decision', 'solution', 'config', 'code', 'error', 'session'],\n description: '记忆类型',\n },\n limit: {\n type: 'number',\n description: '返回数量',\n },\n offset: {\n type: 'number',\n description: '分页偏移',\n },\n },\n required: ['projectId'],\n },\n },\n {\n name: 'mpulse_relations',\n description: '查询记忆的关系链',\n inputSchema: {\n type: 'object',\n properties: {\n memoryId: {\n type: 'string',\n description: '记忆 ID',\n },\n depth: {\n type: 'number',\n description: '递归深度',\n },\n },\n required: ['memoryId'],\n },\n },\n];\n\n// 注册工具列表\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools,\n}));\n\n// 注册资源列表\nserver.setRequestHandler(ListResourcesRequestSchema, async () => ({\n resources: [\n {\n uri: 'memory://projects',\n name: '所有项目记忆',\n description: '列出所有项目 ID',\n mimeType: 'application/json',\n },\n ],\n}));\n\n// 处理资源读取\nserver.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n const uri = request.params.uri;\n\n try {\n // memory://projects - 列出所有项目\n if (uri === 'memory://projects') {\n // 查询所有记忆,按项目分组\n const allMemories = await storage.recall({ query: '', limit: 10000 });\n const projects = new Set(allMemories.memories.map((m) => m.meta.projectId));\n\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(\n {\n projects: Array.from(projects),\n total: projects.size,\n },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n // memory://project/{projectId} - 列出项目的所有记忆\n const projectMatch = uri.match(/^memory:\\/\\/project\\/(.+)$/);\n if (projectMatch) {\n const projectId = decodeURIComponent(projectMatch[1]);\n const result = await storage.recall({ query: '', projectId, limit: 1000 });\n\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(\n {\n projectId,\n memories: result.memories,\n total: result.total,\n },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n // memory://memory/{memoryId} - 获取单个记忆详情\n const memoryMatch = uri.match(/^memory:\\/\\/memory\\/(.+)$/);\n if (memoryMatch) {\n const memoryId = decodeURIComponent(memoryMatch[1]);\n // 使用 getRelations 获取单个记忆(depth=0 不递归)\n const result = await storage.getRelations({ memoryId, depth: 0 });\n\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(result.memory, null, 2),\n },\n ],\n };\n }\n\n // memory://session/{sessionId} - 列出会话的所有记忆\n const sessionMatch = uri.match(/^memory:\\/\\/session\\/(.+)$/);\n if (sessionMatch) {\n const sessionId = decodeURIComponent(sessionMatch[1]);\n const result = await storage.recall({ query: '', sessionId, limit: 1000 });\n\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(\n {\n sessionId,\n memories: result.memories,\n total: result.total,\n },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n throw new Error(`Unknown resource URI: ${uri}`);\n } catch (error) {\n throw new Error(\n `Failed to read resource ${uri}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n});\n\n// 注册提示词列表\nserver.setRequestHandler(ListPromptsRequestSchema, async () => ({\n prompts: [\n {\n name: 'analyze-decision',\n description: '分析项目中的架构决策',\n arguments: [\n {\n name: 'projectId',\n description: '项目 ID',\n required: true,\n },\n ],\n },\n {\n name: 'summarize-session',\n description: '总结会话中的工作内容',\n arguments: [\n {\n name: 'sessionId',\n description: '会话 ID',\n required: true,\n },\n ],\n },\n {\n name: 'find-related',\n description: '查找与特定主题相关的记忆',\n arguments: [\n {\n name: 'topic',\n description: '主题关键词',\n required: true,\n },\n {\n name: 'projectId',\n description: '项目 ID(可选)',\n required: false,\n },\n ],\n },\n {\n name: 'review-project',\n description: '回顾项目的发展历程',\n arguments: [\n {\n name: 'projectId',\n description: '项目 ID',\n required: true,\n },\n {\n name: 'type',\n description: '记忆类型(可选:decision, solution, session)',\n required: false,\n },\n ],\n },\n ],\n}));\n\n// 处理提示词获取\nserver.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n if (!args) {\n throw new Error('Missing required arguments');\n }\n\n try {\n switch (name) {\n case 'analyze-decision': {\n const projectId = (args as any).projectId;\n const decisions = await storage.recall({\n query: '',\n projectId,\n type: 'decision' as any,\n limit: 100,\n });\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `请分析项目 \"${projectId}\" 中的架构决策。\n\n找到了 ${decisions.total} 个决策记录:\n\n${decisions.memories\n .map((m, idx) => {\n const data = m.content.data as any;\n return `\n${idx + 1}. ${data.question || m.content.summary}\n 选择:${data.chosen || '未知'}\n 理由:${data.reason || '未提供'}\n 时间:${m.meta.timestamp}\n`;\n })\n .join('\\n')}\n\n请总结:\n1. 主要的技术选型有哪些?\n2. 决策的演进趋势如何?\n3. 是否存在可能的技术债务?\n4. 有哪些值得记录的经验教训?`,\n },\n },\n ],\n };\n }\n\n case 'summarize-session': {\n const sessionId = (args as any).sessionId;\n const memories = await storage.recall({\n query: '',\n sessionId,\n limit: 100,\n });\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `请总结会话 \"${sessionId}\" 的工作内容。\n\n会话包含 ${memories.total} 条记忆:\n\n${memories.memories\n .map((m, idx) => `${idx + 1}. [${m.meta.type}] ${m.content.summary}`)\n .join('\\n')}\n\n请生成一个简洁的工作总结,包括:\n1. 主要完成的任务\n2. 做出的重要决策\n3. 遇到的问题和解决方案\n4. 未完成的任务(如有)\n5. 下一步计划建议`,\n },\n },\n ],\n };\n }\n\n case 'find-related': {\n const topic = (args as any).topic;\n const projectId = (args as any).projectId;\n const related = await storage.recall({\n query: topic,\n projectId,\n limit: 20,\n });\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `查找与 \"${topic}\" 相关的记忆${projectId ? `(项目:${projectId})` : ''}。\n\n找到 ${related.total} 条相关记忆:\n\n${related.memories\n .map(\n (m, idx) => `\n${idx + 1}. ${m.content.summary}\n 类型:${m.meta.type}\n 项目:${m.meta.projectId}\n 时间:${m.meta.timestamp}\n`\n )\n .join('\\n')}\n\n请分析这些记忆之间的关联性,并提供:\n1. 这些记忆围绕什么主题?\n2. 是否存在演进关系?\n3. 有哪些有价值的经验可以复用?`,\n },\n },\n ],\n };\n }\n\n case 'review-project': {\n const projectId = (args as any).projectId;\n const type = (args as any).type;\n const timeline = await storage.getTimeline({\n projectId,\n type: type as any,\n limit: 100,\n });\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `回顾项目 \"${projectId}\" 的发展历程${type ? `(类型:${type})` : ''}。\n\n时间线包含 ${timeline.total} 条记录:\n\n${timeline.entries\n .map((entry, idx) => {\n const m = entry.memory;\n return `${idx + 1}. [${new Date(m.meta.timestamp).toLocaleDateString()}] ${m.content.summary}`;\n })\n .join('\\n')}\n\n请生成项目回顾报告,包括:\n1. 项目起源和初始目标\n2. 关键里程碑和决策点\n3. 遇到的挑战和解决方案\n4. 当前状态和未来方向\n5. 经验总结和改进建议`,\n },\n },\n ],\n };\n }\n\n default:\n throw new Error(`Unknown prompt: ${name}`);\n }\n } catch (error) {\n throw new Error(\n `Failed to generate prompt ${name}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n});\n\n// 处理工具调用\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n // MCP SDK 保证 args 存在且类型正确(通过 inputSchema 验证)\n if (!args) {\n throw new Error('Missing required arguments');\n }\n\n try {\n switch (name) {\n case 'mpulse_store': {\n const result = await storage.store({\n content: (args as any).content,\n rawContext: (args as any).rawContext,\n projectId: (args as any).projectId,\n type: (args as any).type,\n tags: (args as any).tags,\n sessionId: (args as any).sessionId,\n });\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'mpulse_store_decision': {\n const decisionParams: DecisionContext & {\n projectId: string;\n tags?: string[];\n sessionId?: string;\n } = {\n question: (args as any).question,\n options: (args as any).options,\n chosen: (args as any).chosen,\n reason: (args as any).reason,\n projectId: (args as any).projectId,\n tags: (args as any).tags,\n sessionId: (args as any).sessionId,\n };\n const result = await storage.storeDecision(decisionParams);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'mpulse_store_solution': {\n const solutionParams: SolutionContext & {\n projectId: string;\n tags?: string[];\n sessionId?: string;\n artifacts?: Record<string, string>;\n } = {\n problem: (args as any).problem,\n rootCause: (args as any).rootCause,\n solution: (args as any).solution,\n prevention: (args as any).prevention,\n relatedIssues: (args as any).relatedIssues,\n projectId: (args as any).projectId,\n tags: (args as any).tags,\n sessionId: (args as any).sessionId,\n artifacts: (args as any).artifacts,\n };\n const result = await storage.storeSolution(solutionParams);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'mpulse_store_session': {\n const sessionParams: SessionContext & {\n projectId: string;\n sessionId: string;\n } = {\n summary: (args as any).summary,\n decisions: (args as any).decisions,\n unfinishedTasks: (args as any).unfinishedTasks,\n nextSteps: (args as any).nextSteps,\n projectId: (args as any).projectId,\n sessionId: (args as any).sessionId,\n };\n const result = await storage.storeSession(sessionParams);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'mpulse_recall': {\n const query = (args as any).query;\n const strategy = (args as any).strategy || 'fulltext';\n\n // 构建检索过滤器\n const filters: SearchFilters = {\n query,\n projectId: (args as any).projectId,\n type: (args as any).type,\n tags: (args as any).tags,\n strategy: strategy as any,\n limit: (args as any).limit,\n };\n\n const result = await storage.recall(filters);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'mpulse_timeline': {\n const options: TimelineOptions = {\n projectId: (args as any).projectId,\n dateRange: (args as any).dateRange,\n type: (args as any).type,\n limit: (args as any).limit,\n offset: (args as any).offset,\n };\n const result = await storage.getTimeline(options);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'mpulse_relations': {\n const options: RelationsOptions = {\n memoryId: (args as any).memoryId,\n depth: (args as any).depth,\n };\n const result = await storage.getRelations(options);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch (error) {\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n});\n\n// 启动服务器\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error('Memory Pulse (记忆脉搏) MCP Server running on stdio');\n}\n\nmain().catch((error) => {\n console.error('Fatal error:', error);\n process.exit(1);\n});\n","import Database from 'better-sqlite3';\nimport { nanoid } from 'nanoid';\nimport {\n type IStorage,\n type SearchFilters,\n type SearchResult,\n type TimelineOptions,\n type TimelineResult,\n type TimelineEntry,\n type RelationsOptions,\n type RelationNode,\n MemoryType,\n SearchStrategy,\n type Memory,\n type DecisionContext,\n type SolutionContext,\n type SessionContext,\n type Vector,\n serializeVector,\n deserializeVector,\n cosineSimilarity,\n} from '@emp/core';\nimport { initSchema } from './schema.js';\nimport { LRUCache } from './cache.js';\n\n/**\n * SQLite存储实现\n */\nexport class SQLiteStorage implements IStorage {\n private db: Database.Database;\n private cache: LRUCache | null;\n\n constructor(dbPath: string = ':memory:', options?: { enableCache?: boolean; cacheSize?: number }) {\n this.db = new Database(dbPath);\n this.db.pragma('journal_mode = WAL'); // 性能优化:Write-Ahead Logging\n this.db.pragma('foreign_keys = ON');\n initSchema(this.db); // 初始化Schema\n\n // 初始化缓存(默认启用,容量100)\n this.cache = options?.enableCache !== false ? new LRUCache(options?.cacheSize || 100) : null;\n }\n\n /**\n * 通用存储方法\n */\n async store(params: {\n content: string;\n rawContext: Record<string, unknown>;\n projectId: string;\n type?: MemoryType;\n tags?: string[];\n sessionId?: string;\n embedding?: Vector;\n relations?: {\n replaces?: string[];\n relatedTo?: string[];\n impacts?: string[];\n derivedFrom?: string;\n };\n }): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date().toISOString();\n const memoryType = params.type || MemoryType.CODE;\n\n const stmt = this.db.prepare(`\n INSERT INTO memories (\n id, projectId, sessionId, timestamp, type, tags,\n summary, data, replaces, relatedTo, impacts, derivedFrom,\n context, keywords, fullText, embedding, createdAt, updatedAt\n ) VALUES (\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?\n )\n `);\n\n stmt.run(\n id,\n params.projectId,\n params.sessionId || null,\n timestamp,\n memoryType,\n params.tags ? JSON.stringify(params.tags) : null,\n params.content, // summary\n JSON.stringify(params.rawContext), // data\n params.relations?.replaces ? JSON.stringify(params.relations.replaces) : null,\n params.relations?.relatedTo ? JSON.stringify(params.relations.relatedTo) : null,\n params.relations?.impacts ? JSON.stringify(params.relations.impacts) : null,\n params.relations?.derivedFrom || null,\n JSON.stringify(params.rawContext), // context\n params.tags ? JSON.stringify(params.tags) : null, // keywords\n params.content, // fullText\n params.embedding ? serializeVector(params.embedding) : null, // embedding\n timestamp,\n timestamp\n );\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 存储决策记忆\n */\n async storeDecision(\n params: DecisionContext & {\n projectId: string;\n tags?: string[];\n sessionId?: string;\n embedding?: Vector;\n relations?: {\n replaces?: string[];\n relatedTo?: string[];\n impacts?: string[];\n derivedFrom?: string;\n };\n }\n ): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date().toISOString();\n const summary = `[决策] ${params.question}`;\n const fullText = `${params.question} ${params.options.map((o) => o.name).join(' ')} ${params.reason}`;\n const keywords = [...(params.tags || []), ...params.options.map((o) => o.name), params.chosen];\n\n const stmt = this.db.prepare(`\n INSERT INTO memories (\n id, projectId, sessionId, timestamp, type, tags,\n summary, data, replaces, relatedTo, impacts, derivedFrom,\n context, keywords, fullText, embedding, createdAt, updatedAt\n ) VALUES (\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?\n )\n `);\n\n stmt.run(\n id,\n params.projectId,\n params.sessionId || null,\n timestamp,\n MemoryType.DECISION,\n params.tags ? JSON.stringify(params.tags) : null,\n summary,\n JSON.stringify({}), // data为空\n params.relations?.replaces ? JSON.stringify(params.relations.replaces) : null,\n params.relations?.relatedTo ? JSON.stringify(params.relations.relatedTo) : null,\n params.relations?.impacts ? JSON.stringify(params.relations.impacts) : null,\n params.relations?.derivedFrom || null,\n JSON.stringify({\n question: params.question,\n options: params.options,\n chosen: params.chosen,\n reason: params.reason,\n }),\n JSON.stringify(keywords),\n fullText,\n params.embedding ? serializeVector(params.embedding) : null,\n timestamp,\n timestamp\n );\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 存储解决方案记忆\n */\n async storeSolution(\n params: SolutionContext & {\n projectId: string;\n tags?: string[];\n sessionId?: string;\n embedding?: Vector;\n artifacts?: Record<string, string>;\n relations?: {\n replaces?: string[];\n relatedTo?: string[];\n impacts?: string[];\n derivedFrom?: string;\n };\n }\n ): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date().toISOString();\n const summary = `[方案] ${params.problem}`;\n const fullText = `${params.problem} ${params.rootCause} ${params.solution} ${params.prevention || ''} ${params.relatedIssues?.join(' ') || ''}`;\n const keywords = [...(params.tags || []), ...(params.relatedIssues || [])];\n\n const stmt = this.db.prepare(`\n INSERT INTO memories (\n id, projectId, sessionId, timestamp, type, tags,\n summary, data, replaces, relatedTo, impacts, derivedFrom,\n context, keywords, fullText, embedding, createdAt, updatedAt\n ) VALUES (\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?\n )\n `);\n\n stmt.run(\n id,\n params.projectId,\n params.sessionId || null,\n timestamp,\n MemoryType.SOLUTION,\n params.tags ? JSON.stringify(params.tags) : null,\n summary,\n JSON.stringify(params.artifacts || {}),\n params.relations?.replaces ? JSON.stringify(params.relations.replaces) : null,\n params.relations?.relatedTo ? JSON.stringify(params.relations.relatedTo) : null,\n params.relations?.impacts ? JSON.stringify(params.relations.impacts) : null,\n params.relations?.derivedFrom || null,\n JSON.stringify({\n problem: params.problem,\n rootCause: params.rootCause,\n solution: params.solution,\n prevention: params.prevention,\n relatedIssues: params.relatedIssues,\n }),\n JSON.stringify(keywords),\n fullText,\n params.embedding ? serializeVector(params.embedding) : null,\n timestamp,\n timestamp\n );\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 存储会话记忆\n */\n async storeSession(\n params: SessionContext & {\n projectId: string;\n sessionId?: string;\n embedding?: Vector;\n }\n ): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date().toISOString();\n const summary = `[会话] ${params.summary}`;\n const fullText = `${params.summary} ${params.decisions?.join(' ') || ''} ${params.unfinishedTasks?.join(' ') || ''} ${params.nextSteps?.join(' ') || ''}`;\n const keywords = [...(params.decisions || []), ...(params.unfinishedTasks || [])];\n\n const stmt = this.db.prepare(`\n INSERT INTO memories (\n id, projectId, sessionId, timestamp, type, tags,\n summary, data, replaces, relatedTo, impacts, derivedFrom,\n context, keywords, fullText, embedding, createdAt, updatedAt\n ) VALUES (\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?,\n ?, ?, ?, ?, ?, ?\n )\n `);\n\n stmt.run(\n id,\n params.projectId,\n params.sessionId || id, // 使用当前id作为sessionId\n timestamp,\n MemoryType.SESSION,\n null, // tags\n summary,\n JSON.stringify({}),\n null, // replaces\n null, // relatedTo\n null, // impacts\n null, // derivedFrom\n JSON.stringify({\n summary: params.summary,\n decisions: params.decisions,\n unfinishedTasks: params.unfinishedTasks,\n nextSteps: params.nextSteps,\n }),\n JSON.stringify(keywords),\n fullText,\n params.embedding ? serializeVector(params.embedding) : null,\n timestamp,\n timestamp\n );\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 检索记忆\n */\n async recall(filters: SearchFilters): Promise<SearchResult> {\n const startTime = Date.now();\n\n // 检查缓存\n if (this.cache) {\n const cacheKey = LRUCache.generateKey(filters);\n const cached = this.cache.get(cacheKey);\n if (cached) {\n return cached; // 缓存命中,直接返回\n }\n }\n\n const strategy = filters.strategy || SearchStrategy.AUTO;\n const limit = filters.limit || 10;\n const offset = filters.offset || 0;\n\n let actualStrategy: SearchStrategy;\n let results: Memory[];\n let dbStartTime: number;\n let dbEndTime: number;\n let parseStartTime: number;\n\n // 策略选择\n const strategyStartTime = Date.now();\n\n // 如果提供了 queryVector,直接使用语义搜索\n if (filters.queryVector && strategy !== SearchStrategy.EXACT && strategy !== SearchStrategy.FULLTEXT) {\n dbStartTime = Date.now();\n results = this.semanticSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.SEMANTIC;\n }\n // L1: 精确匹配(优先)\n else if (strategy === SearchStrategy.EXACT || strategy === SearchStrategy.AUTO) {\n dbStartTime = Date.now();\n results = this.exactSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.EXACT;\n\n // AUTO 模式:如果L1找不到结果,降级到L2全文搜索\n if (results.length === 0 && strategy === SearchStrategy.AUTO && filters.query) {\n dbStartTime = Date.now();\n results = this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n\n // AUTO 模式:如果L2也找不到,且有 queryVector,降级到L3语义搜索\n if (results.length === 0 && filters.queryVector) {\n dbStartTime = Date.now();\n results = this.semanticSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.SEMANTIC;\n }\n }\n }\n // L2: 全文搜索\n else if (strategy === SearchStrategy.FULLTEXT) {\n dbStartTime = Date.now();\n results = this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n }\n // L3: 语义检索\n else if (strategy === SearchStrategy.SEMANTIC) {\n if (!filters.queryVector) {\n // 无向量时降级到全文搜索\n dbStartTime = Date.now();\n results = this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n } else {\n dbStartTime = Date.now();\n results = this.semanticSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.SEMANTIC;\n }\n }\n // 默认:全文搜索\n else {\n dbStartTime = Date.now();\n results = this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n }\n\n const strategyTime = Date.now() - strategyStartTime;\n const took = Date.now() - startTime;\n\n // 计算解析时间(总时间 - 数据库时间)\n const dbTime = dbEndTime - dbStartTime;\n const parseTime = took - dbTime - strategyTime;\n\n const result: SearchResult = {\n memories: results,\n total: results.length,\n strategy: actualStrategy,\n took,\n metrics: {\n dbTime,\n parseTime: Math.max(0, parseTime), // 确保非负\n strategyTime,\n cacheHit: false, // 数据库查询,标记为未命中\n },\n };\n\n // 写入缓存\n if (this.cache) {\n const cacheKey = LRUCache.generateKey(filters);\n this.cache.set(cacheKey, result);\n }\n\n return result;\n }\n\n /**\n * L1: 精确匹配检索\n */\n private exactSearch(filters: SearchFilters, limit: number, offset: number): Memory[] {\n let sql = 'SELECT * FROM memories WHERE 1=1';\n const params: any[] = [];\n\n if (filters.projectId) {\n sql += ' AND projectId = ?';\n params.push(filters.projectId);\n }\n\n if (filters.type) {\n sql += ' AND type = ?';\n params.push(filters.type);\n }\n\n if (filters.sessionId) {\n sql += ' AND sessionId = ?';\n params.push(filters.sessionId);\n }\n\n // 精确匹配:在summary或fullText中查找完整query\n if (filters.query) {\n sql += ' AND (summary LIKE ? OR fullText LIKE ?)';\n params.push(`%${filters.query}%`, `%${filters.query}%`);\n }\n\n sql += ' ORDER BY timestamp DESC LIMIT ? OFFSET ?';\n params.push(limit, offset);\n\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as any[];\n\n return rows.map(this.rowToMemory);\n }\n\n /**\n * L2: 全文搜索(FTS5)\n */\n private fulltextSearch(filters: SearchFilters, limit: number, offset: number): Memory[] {\n // 先不用FTS5,退化为LIKE查询\n // TODO: 调试FTS5后再启用\n let sql = 'SELECT * FROM memories WHERE 1=1';\n const params: any[] = [];\n\n if (filters.projectId) {\n sql += ' AND projectId = ?';\n params.push(filters.projectId);\n }\n\n if (filters.type) {\n sql += ' AND type = ?';\n params.push(filters.type);\n }\n\n if (filters.sessionId) {\n sql += ' AND sessionId = ?';\n params.push(filters.sessionId);\n }\n\n if (filters.query) {\n // 使用LIKE实现简单的全文搜索\n sql += ' AND (summary LIKE ? OR fullText LIKE ?)';\n params.push(`%${filters.query}%`, `%${filters.query}%`);\n }\n\n sql += ' ORDER BY timestamp DESC LIMIT ? OFFSET ?';\n params.push(limit, offset);\n\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as any[];\n\n return rows.map(this.rowToMemory);\n }\n\n /**\n * L3: 语义搜索(向量相似度)\n * 基于 cosine similarity 进行向量检索\n */\n private semanticSearch(filters: SearchFilters, limit: number, offset: number): Memory[] {\n if (!filters.queryVector) {\n return [];\n }\n\n const threshold = filters.similarityThreshold ?? 0.7;\n\n // 构建基础查询(只取有 embedding 的记录)\n let sql = 'SELECT * FROM memories WHERE embedding IS NOT NULL';\n const params: any[] = [];\n\n if (filters.projectId) {\n sql += ' AND projectId = ?';\n params.push(filters.projectId);\n }\n\n if (filters.type) {\n sql += ' AND type = ?';\n params.push(filters.type);\n }\n\n if (filters.sessionId) {\n sql += ' AND sessionId = ?';\n params.push(filters.sessionId);\n }\n\n sql += ' ORDER BY timestamp DESC';\n\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as any[];\n\n // 计算相似度并过滤\n const queryVector = filters.queryVector;\n const scoredResults: { row: any; similarity: number }[] = [];\n\n for (const row of rows) {\n try {\n const storedVector = deserializeVector(row.embedding);\n const similarity = cosineSimilarity(queryVector, storedVector);\n\n // 只保留超过阈值的结果\n if (similarity >= threshold) {\n scoredResults.push({ row, similarity });\n }\n } catch {\n // 向量解析失败,跳过\n continue;\n }\n }\n\n // 按相似度降序排序\n scoredResults.sort((a, b) => b.similarity - a.similarity);\n\n // 应用分页\n const paginatedResults = scoredResults.slice(offset, offset + limit);\n\n return paginatedResults.map((item) => this.rowToMemory(item.row));\n }\n\n /**\n * 获取时间线\n */\n async getTimeline(options: TimelineOptions): Promise<TimelineResult> {\n let sql = 'SELECT * FROM memories WHERE projectId = ?';\n const params: any[] = [options.projectId];\n\n if (options.type) {\n sql += ' AND type = ?';\n params.push(options.type);\n }\n\n if (options.dateRange) {\n sql += ' AND timestamp >= ? AND timestamp <= ?';\n params.push(options.dateRange[0], options.dateRange[1]);\n }\n\n sql += ' ORDER BY timestamp DESC';\n\n if (options.limit) {\n sql += ' LIMIT ?';\n params.push(options.limit);\n }\n\n if (options.offset) {\n sql += ' OFFSET ?';\n params.push(options.offset);\n }\n\n const stmt = this.db.prepare(sql);\n const rows = stmt.all(...params) as any[];\n const memories = rows.map(this.rowToMemory);\n\n const entries: TimelineEntry[] = memories.map((memory, index) => ({\n memory,\n prevMemoryId: index > 0 ? memories[index - 1].meta.id : undefined,\n nextMemoryId: index < memories.length - 1 ? memories[index + 1].meta.id : undefined,\n }));\n\n return {\n entries,\n total: entries.length,\n };\n }\n\n /**\n * 获取关系链\n */\n async getRelations(options: RelationsOptions): Promise<RelationNode> {\n const memory = await this.getById(options.memoryId);\n if (!memory) {\n throw new Error(`Memory ${options.memoryId} not found`);\n }\n\n const depth = options.depth || 1;\n const relatedNodes: RelationNode[] = [];\n\n if (depth > 0) {\n // 查找所有相关记忆\n const relatedIds = [\n ...(memory.relations.replaces || []),\n ...(memory.relations.relatedTo || []),\n ...(memory.relations.impacts || []),\n ];\n\n if (memory.relations.derivedFrom) {\n relatedIds.push(memory.relations.derivedFrom);\n }\n\n for (const relatedId of relatedIds) {\n const relatedMemory = await this.getById(relatedId);\n if (relatedMemory) {\n // 递归查询关系链\n let nestedRelated: RelationNode[] | undefined = undefined;\n if (depth > 1) {\n const nestedResult = await this.getRelations({\n memoryId: relatedId,\n depth: depth - 1,\n });\n nestedRelated = nestedResult.related;\n }\n\n relatedNodes.push({\n memory: relatedMemory,\n related: nestedRelated,\n });\n }\n }\n }\n\n return {\n memory,\n related: relatedNodes.length > 0 ? relatedNodes : undefined,\n };\n }\n\n /**\n * 删除记忆\n */\n async delete(memoryId: string): Promise<{ success: boolean }> {\n // 先查询 projectId 用于缓存失效\n if (this.cache) {\n const memory = this.db.prepare('SELECT projectId FROM memories WHERE id = ?').get(memoryId) as {\n projectId: string;\n } | undefined;\n if (memory) {\n this.cache.invalidateProject(memory.projectId);\n }\n }\n\n const stmt = this.db.prepare('DELETE FROM memories WHERE id = ?');\n const result = stmt.run(memoryId);\n return { success: result.changes > 0 };\n }\n\n /**\n * 更新记忆\n */\n async update(memoryId: string, updates: Partial<Memory>): Promise<{ success: boolean }> {\n const fields: string[] = [];\n const params: any[] = [];\n\n if (updates.content) {\n if (updates.content.summary) {\n fields.push('summary = ?');\n params.push(updates.content.summary);\n }\n if (updates.content.data !== undefined) {\n fields.push('data = ?');\n params.push(JSON.stringify(updates.content.data));\n }\n }\n\n if (updates.meta?.tags) {\n fields.push('tags = ?');\n params.push(JSON.stringify(updates.meta.tags));\n }\n\n if (updates.relations) {\n if (updates.relations.replaces) {\n fields.push('replaces = ?');\n params.push(JSON.stringify(updates.relations.replaces));\n }\n if (updates.relations.relatedTo) {\n fields.push('relatedTo = ?');\n params.push(JSON.stringify(updates.relations.relatedTo));\n }\n if (updates.relations.impacts) {\n fields.push('impacts = ?');\n params.push(JSON.stringify(updates.relations.impacts));\n }\n if (updates.relations.derivedFrom) {\n fields.push('derivedFrom = ?');\n params.push(updates.relations.derivedFrom);\n }\n }\n\n if (fields.length === 0) {\n return { success: false };\n }\n\n fields.push('updatedAt = ?');\n params.push(new Date().toISOString());\n params.push(memoryId);\n\n const sql = `UPDATE memories SET ${fields.join(', ')} WHERE id = ?`;\n const stmt = this.db.prepare(sql);\n const result = stmt.run(...params);\n\n // 失效相关缓存\n if (this.cache && result.changes > 0) {\n const memory = this.db.prepare('SELECT projectId FROM memories WHERE id = ?').get(memoryId) as {\n projectId: string;\n } | undefined;\n if (memory) {\n this.cache.invalidateProject(memory.projectId);\n }\n }\n\n return { success: result.changes > 0 };\n }\n\n /**\n * 根据 ID 获取单个记忆\n */\n async getById(id: string): Promise<Memory | null> {\n const stmt = this.db.prepare('SELECT * FROM memories WHERE id = ?');\n const row = stmt.get(id) as any;\n return row ? this.rowToMemory(row) : null;\n }\n\n /**\n * 将数据库行转换为Memory对象\n */\n private rowToMemory(row: any): Memory {\n return {\n meta: {\n id: row.id,\n projectId: row.projectId,\n sessionId: row.sessionId,\n timestamp: row.timestamp,\n type: row.type as MemoryType,\n tags: row.tags ? JSON.parse(row.tags) : [],\n version: row.version,\n },\n content: {\n summary: row.summary,\n data: row.data ? JSON.parse(row.data) : {},\n },\n relations: {\n replaces: row.replaces ? JSON.parse(row.replaces) : undefined,\n relatedTo: row.relatedTo ? JSON.parse(row.relatedTo) : undefined,\n impacts: row.impacts ? JSON.parse(row.impacts) : undefined,\n derivedFrom: row.derivedFrom || undefined,\n },\n searchable: {\n keywords: row.keywords ? JSON.parse(row.keywords) : [],\n fullText: row.fullText,\n },\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n }\n\n /**\n * 关闭数据库连接\n */\n close(): void {\n this.db.close();\n }\n\n /**\n * 获取统计信息\n */\n async getStats(projectId?: string): Promise<{\n total: number;\n byType: Record<string, number>;\n byProject: Record<string, number>;\n recentCount: number;\n }> {\n // 总数查询\n let totalSql = 'SELECT COUNT(*) as count FROM memories';\n const totalParams: any[] = [];\n if (projectId) {\n totalSql += ' WHERE projectId = ?';\n totalParams.push(projectId);\n }\n const totalResult = this.db.prepare(totalSql).get(...totalParams) as { count: number };\n\n // 按类型统计\n let typeSql = 'SELECT type, COUNT(*) as count FROM memories';\n const typeParams: any[] = [];\n if (projectId) {\n typeSql += ' WHERE projectId = ?';\n typeParams.push(projectId);\n }\n typeSql += ' GROUP BY type';\n const typeResults = this.db.prepare(typeSql).all(...typeParams) as { type: string; count: number }[];\n const byType: Record<string, number> = {};\n typeResults.forEach((row) => {\n byType[row.type] = row.count;\n });\n\n // 按项目统计\n let projectSql = 'SELECT projectId, COUNT(*) as count FROM memories GROUP BY projectId';\n if (projectId) {\n projectSql = 'SELECT projectId, COUNT(*) as count FROM memories WHERE projectId = ? GROUP BY projectId';\n }\n const projectResults = this.db.prepare(projectSql).all(...(projectId ? [projectId] : [])) as { projectId: string; count: number }[];\n const byProject: Record<string, number> = {};\n projectResults.forEach((row) => {\n byProject[row.projectId] = row.count;\n });\n\n // 最近 7 天统计\n const sevenDaysAgo = new Date();\n sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);\n let recentSql = 'SELECT COUNT(*) as count FROM memories WHERE timestamp >= ?';\n const recentParams: any[] = [sevenDaysAgo.toISOString()];\n if (projectId) {\n recentSql += ' AND projectId = ?';\n recentParams.push(projectId);\n }\n const recentResult = this.db.prepare(recentSql).get(...recentParams) as { count: number };\n\n return {\n total: totalResult.count,\n byType,\n byProject,\n recentCount: recentResult.count,\n };\n }\n}\n","/**\n * 记忆类型枚举\n */\nexport enum MemoryType {\n /** 架构决策 */\n DECISION = 'decision',\n /** 问题解决方案 */\n SOLUTION = 'solution',\n /** 配置信息 */\n CONFIG = 'config',\n /** 代码实现 */\n CODE = 'code',\n /** 错误记录 */\n ERROR = 'error',\n /** 会话总结 */\n SESSION = 'session',\n}\n\n/**\n * 检索策略枚举\n */\nexport enum SearchStrategy {\n /** L1: 精确匹配(WHERE + 索引) */\n EXACT = 'exact',\n /** L2: 全文搜索(FTS5/Meilisearch) */\n FULLTEXT = 'fulltext',\n /** L3: 语义检索(Embedding 相似度) */\n SEMANTIC = 'semantic',\n /** 自动选择最优策略 */\n AUTO = 'auto',\n}\n\n/**\n * 关系类型\n */\nexport type RelationType = 'replaces' | 'relatedTo' | 'impacts' | 'derivedFrom';\n","/**\n * Feature Flag 系统\n *\n * 采用 Open Core 模式:\n * - 开源版(MIT):完整功能的 MCP Server、CLI、Web Dashboard、SQLite/PostgreSQL 存储\n * - 闭源部分(Commercial):云平台服务(多租户、计费、SSO、审计等)\n */\n\n// ============ 功能分类 ============\n\n/** 开源功能(默认开启) */\nexport enum OpenSourceFeature {\n // 存储\n SQLITE_STORAGE = 'sqlite_storage',\n POSTGRESQL_STORAGE = 'postgresql_storage',\n\n // 检索\n EXACT_SEARCH = 'exact_search',\n FULLTEXT_SEARCH = 'fulltext_search',\n\n // 记忆类型\n DECISION_MEMORY = 'decision_memory',\n SOLUTION_MEMORY = 'solution_memory',\n SESSION_MEMORY = 'session_memory',\n\n // 视图\n TIMELINE_VIEW = 'timeline_view',\n RELATIONS_VIEW = 'relations_view',\n\n // 接口\n MCP_SERVER = 'mcp_server',\n REST_API = 'rest_api',\n WEB_DASHBOARD = 'web_dashboard',\n CLI_TOOL = 'cli_tool',\n}\n\n/** 云平台功能(需要授权) */\nexport enum CloudFeature {\n // 多租户\n MULTI_TENANT = 'multi_tenant',\n WORKSPACE_MANAGEMENT = 'workspace_management',\n\n // 用户管理\n SSO_SAML = 'sso_saml',\n OAUTH_INTEGRATION = 'oauth_integration',\n RBAC = 'rbac',\n\n // 数据服务\n AUTO_BACKUP = 'auto_backup',\n DATA_EXPORT = 'data_export',\n DATA_MIGRATION = 'data_migration',\n\n // 高级功能\n SEMANTIC_SEARCH = 'semantic_search',\n ADVANCED_ANALYTICS = 'advanced_analytics',\n AUDIT_LOG = 'audit_log',\n\n // 集成\n WEBHOOK = 'webhook',\n CUSTOM_STORAGE = 'custom_storage',\n\n // 支持\n PRIORITY_SUPPORT = 'priority_support',\n}\n\n// ============ 许可证类型 ============\n\nexport enum LicenseType {\n /** 开源版 - 所有开源功能 */\n OPEN_SOURCE = 'open_source',\n\n /** 专业版 - 开源 + 部分云功能 */\n PROFESSIONAL = 'professional',\n\n /** 企业版 - 所有功能 */\n ENTERPRISE = 'enterprise',\n}\n\n// ============ 类型定义 ============\n\nexport type FeatureKey = OpenSourceFeature | CloudFeature;\n\nexport interface FeatureConfig {\n /** 功能键 */\n key: FeatureKey;\n /** 功能名称 */\n name: string;\n /** 功能描述 */\n description: string;\n /** 是否开源功能 */\n isOpenSource: boolean;\n /** 所需最低许可证 */\n requiredLicense: LicenseType;\n /** 是否启用 */\n enabled: boolean;\n}\n\nexport interface LicenseInfo {\n /** 许可证类型 */\n type: LicenseType;\n /** 许可证 ID */\n licenseId?: string;\n /** 组织名称 */\n organization?: string;\n /** 过期时间 */\n expiresAt?: Date;\n /** 最大用户数 */\n maxUsers?: number;\n /** 启用的云功能 */\n enabledCloudFeatures: CloudFeature[];\n}\n\n// ============ 功能注册表 ============\n\nconst FEATURE_REGISTRY: Record<FeatureKey, Omit<FeatureConfig, 'key' | 'enabled'>> = {\n // 开源功能\n [OpenSourceFeature.SQLITE_STORAGE]: {\n name: 'SQLite 存储',\n description: '本地 SQLite 数据库存储',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.POSTGRESQL_STORAGE]: {\n name: 'PostgreSQL 存储',\n description: 'PostgreSQL 云端数据库存储',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.EXACT_SEARCH]: {\n name: '精确搜索',\n description: 'L1 精确匹配搜索',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.FULLTEXT_SEARCH]: {\n name: '全文搜索',\n description: 'L2 全文索引搜索',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.DECISION_MEMORY]: {\n name: '决策记忆',\n description: '结构化架构决策记录',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.SOLUTION_MEMORY]: {\n name: '方案记忆',\n description: '问题解决方案记录',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.SESSION_MEMORY]: {\n name: '会话记忆',\n description: '会话总结记录',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.TIMELINE_VIEW]: {\n name: '时间线视图',\n description: '记忆时间线展示',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.RELATIONS_VIEW]: {\n name: '关系视图',\n description: '记忆关系链展示',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.MCP_SERVER]: {\n name: 'MCP Server',\n description: 'Model Context Protocol 服务器',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.REST_API]: {\n name: 'REST API',\n description: 'HTTP REST API 接口',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.WEB_DASHBOARD]: {\n name: 'Web Dashboard',\n description: 'Web 可视化管理面板',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n [OpenSourceFeature.CLI_TOOL]: {\n name: 'CLI 工具',\n description: '命令行管理工具',\n isOpenSource: true,\n requiredLicense: LicenseType.OPEN_SOURCE,\n },\n\n // 云平台功能\n [CloudFeature.MULTI_TENANT]: {\n name: '多租户',\n description: '多租户隔离与管理',\n isOpenSource: false,\n requiredLicense: LicenseType.ENTERPRISE,\n },\n [CloudFeature.WORKSPACE_MANAGEMENT]: {\n name: '工作空间管理',\n description: '团队工作空间管理',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.SSO_SAML]: {\n name: 'SSO/SAML',\n description: '单点登录与 SAML 集成',\n isOpenSource: false,\n requiredLicense: LicenseType.ENTERPRISE,\n },\n [CloudFeature.OAUTH_INTEGRATION]: {\n name: 'OAuth 集成',\n description: 'OAuth 2.0 身份验证',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.RBAC]: {\n name: '角色权限',\n description: '基于角色的访问控制',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.AUTO_BACKUP]: {\n name: '自动备份',\n description: '定时自动备份数据',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.DATA_EXPORT]: {\n name: '数据导出',\n description: '批量数据导出',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.DATA_MIGRATION]: {\n name: '数据迁移',\n description: '跨存储数据迁移',\n isOpenSource: false,\n requiredLicense: LicenseType.ENTERPRISE,\n },\n [CloudFeature.SEMANTIC_SEARCH]: {\n name: '语义搜索',\n description: 'L3 向量语义搜索',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.ADVANCED_ANALYTICS]: {\n name: '高级分析',\n description: '使用统计与趋势分析',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.AUDIT_LOG]: {\n name: '审计日志',\n description: '操作审计记录',\n isOpenSource: false,\n requiredLicense: LicenseType.ENTERPRISE,\n },\n [CloudFeature.WEBHOOK]: {\n name: 'Webhook',\n description: 'Webhook 事件推送',\n isOpenSource: false,\n requiredLicense: LicenseType.PROFESSIONAL,\n },\n [CloudFeature.CUSTOM_STORAGE]: {\n name: '自定义存储',\n description: '自定义存储后端',\n isOpenSource: false,\n requiredLicense: LicenseType.ENTERPRISE,\n },\n [CloudFeature.PRIORITY_SUPPORT]: {\n name: '优先支持',\n description: '优先技术支持',\n isOpenSource: false,\n requiredLicense: LicenseType.ENTERPRISE,\n },\n};\n\n// ============ Feature Flag 管理器 ============\n\nexport class FeatureManager {\n private license: LicenseInfo;\n private overrides: Map<FeatureKey, boolean> = new Map();\n\n constructor(license?: Partial<LicenseInfo>) {\n // 默认开源版许可证\n this.license = {\n type: LicenseType.OPEN_SOURCE,\n enabledCloudFeatures: [],\n ...license,\n };\n }\n\n /** 检查功能是否启用 */\n isEnabled(feature: FeatureKey): boolean {\n // 检查手动覆盖\n if (this.overrides.has(feature)) {\n return this.overrides.get(feature)!;\n }\n\n const config = FEATURE_REGISTRY[feature];\n if (!config) {\n return false;\n }\n\n // 开源功能默认启用\n if (config.isOpenSource) {\n return true;\n }\n\n // 云功能需要检查许可证\n return this.checkLicenseForFeature(feature as CloudFeature);\n }\n\n /** 检查许可证是否支持某云功能 */\n private checkLicenseForFeature(feature: CloudFeature): boolean {\n // 检查许可证是否过期\n if (this.license.expiresAt && new Date() > this.license.expiresAt) {\n return false;\n }\n\n // 检查是否在启用列表中\n if (this.license.enabledCloudFeatures.includes(feature)) {\n return true;\n }\n\n // 检查许可证类型是否满足要求\n const config = FEATURE_REGISTRY[feature];\n return this.isLicenseTypeAtLeast(config.requiredLicense);\n }\n\n /** 检查许可证等级 */\n private isLicenseTypeAtLeast(required: LicenseType): boolean {\n const levels: Record<LicenseType, number> = {\n [LicenseType.OPEN_SOURCE]: 0,\n [LicenseType.PROFESSIONAL]: 1,\n [LicenseType.ENTERPRISE]: 2,\n };\n return levels[this.license.type] >= levels[required];\n }\n\n /** 获取功能配置 */\n getFeatureConfig(feature: FeatureKey): FeatureConfig {\n const config = FEATURE_REGISTRY[feature];\n return {\n key: feature,\n ...config,\n enabled: this.isEnabled(feature),\n };\n }\n\n /** 获取所有功能配置 */\n getAllFeatures(): FeatureConfig[] {\n return Object.entries(FEATURE_REGISTRY).map(([key, config]) => ({\n key: key as FeatureKey,\n ...config,\n enabled: this.isEnabled(key as FeatureKey),\n }));\n }\n\n /** 获取所有开源功能 */\n getOpenSourceFeatures(): FeatureConfig[] {\n return this.getAllFeatures().filter(f => f.isOpenSource);\n }\n\n /** 获取所有云功能 */\n getCloudFeatures(): FeatureConfig[] {\n return this.getAllFeatures().filter(f => !f.isOpenSource);\n }\n\n /** 获取当前许可证信息 */\n getLicense(): LicenseInfo {\n return { ...this.license };\n }\n\n /** 更新许可证 */\n setLicense(license: Partial<LicenseInfo>): void {\n this.license = { ...this.license, ...license };\n }\n\n /** 手动覆盖功能开关(用于测试或特殊场景) */\n override(feature: FeatureKey, enabled: boolean): void {\n this.overrides.set(feature, enabled);\n }\n\n /** 清除覆盖 */\n clearOverride(feature: FeatureKey): void {\n this.overrides.delete(feature);\n }\n\n /** 清除所有覆盖 */\n clearAllOverrides(): void {\n this.overrides.clear();\n }\n\n /** 要求某功能可用,否则抛出异常 */\n require(feature: FeatureKey): void {\n if (!this.isEnabled(feature)) {\n const config = FEATURE_REGISTRY[feature];\n throw new FeatureNotAvailableError(\n feature,\n config.name,\n config.requiredLicense\n );\n }\n }\n}\n\n// ============ 错误类型 ============\n\nexport class FeatureNotAvailableError extends Error {\n constructor(\n public readonly feature: FeatureKey,\n public readonly featureName: string,\n public readonly requiredLicense: LicenseType\n ) {\n super(\n `功能 \"${featureName}\" 不可用。需要 ${requiredLicense} 许可证。` +\n `\\n访问 https://memory-pulse.com/pricing 了解更多。`\n );\n this.name = 'FeatureNotAvailableError';\n }\n}\n\n// ============ 全局实例 ============\n\n/** 全局 Feature Manager 实例 */\nlet globalFeatureManager: FeatureManager | null = null;\n\n/** 获取全局 Feature Manager */\nexport function getFeatureManager(): FeatureManager {\n if (!globalFeatureManager) {\n globalFeatureManager = new FeatureManager();\n }\n return globalFeatureManager;\n}\n\n/** 初始化全局 Feature Manager */\nexport function initFeatureManager(license?: Partial<LicenseInfo>): FeatureManager {\n globalFeatureManager = new FeatureManager(license);\n return globalFeatureManager;\n}\n\n/** 快捷方法:检查功能是否启用 */\nexport function isFeatureEnabled(feature: FeatureKey): boolean {\n return getFeatureManager().isEnabled(feature);\n}\n\n/** 快捷方法:要求功能可用 */\nexport function requireFeature(feature: FeatureKey): void {\n getFeatureManager().require(feature);\n}\n","/**\n * Embedding 服务接口\n *\n * 用于将文本转换为向量,支持语义搜索\n */\n\n// ============ 类型定义 ============\n\n/** 向量类型(固定长度的数字数组) */\nexport type Vector = number[];\n\n/** Embedding 结果 */\nexport interface EmbeddingResult {\n /** 向量 */\n vector: Vector;\n /** 模型名称 */\n model: string;\n /** 向量维度 */\n dimensions: number;\n /** token 使用量(如适用) */\n tokenUsage?: number;\n}\n\n/** 批量 Embedding 结果 */\nexport interface BatchEmbeddingResult {\n /** 向量列表 */\n vectors: Vector[];\n /** 模型名称 */\n model: string;\n /** 向量维度 */\n dimensions: number;\n /** 总 token 使用量 */\n totalTokenUsage?: number;\n}\n\n/** Embedding 提供者配置 */\nexport interface EmbeddingProviderConfig {\n /** 提供者类型 */\n provider: 'openai' | 'ollama' | 'local' | 'mock';\n /** API Key(OpenAI 等云服务需要) */\n apiKey?: string;\n /** 模型名称 */\n model?: string;\n /** API 基础 URL(自定义端点) */\n baseUrl?: string;\n /** 向量维度(某些模型支持自定义) */\n dimensions?: number;\n}\n\n// ============ Embedding 服务接口 ============\n\n/** Embedding 服务接口 */\nexport interface IEmbeddingService {\n /** 获取提供者名称 */\n readonly provider: string;\n\n /** 获取模型名称 */\n readonly model: string;\n\n /** 获取向量维度 */\n readonly dimensions: number;\n\n /**\n * 生成单个文本的 Embedding\n * @param text 输入文本\n * @returns Embedding 结果\n */\n embed(text: string): Promise<EmbeddingResult>;\n\n /**\n * 批量生成 Embedding\n * @param texts 输入文本列表\n * @returns 批量 Embedding 结果\n */\n embedBatch(texts: string[]): Promise<BatchEmbeddingResult>;\n\n /**\n * 计算两个向量的相似度\n * @param a 向量 A\n * @param b 向量 B\n * @returns 相似度分数(0-1,1 表示完全相同)\n */\n similarity(a: Vector, b: Vector): number;\n}\n\n// ============ 向量工具函数 ============\n\n/**\n * 计算余弦相似度\n * @param a 向量 A\n * @param b 向量 B\n * @returns 相似度(-1 到 1,1 表示完全相同)\n */\nexport function cosineSimilarity(a: Vector, b: Vector): number {\n if (a.length !== b.length) {\n throw new Error(`向量维度不匹配: ${a.length} vs ${b.length}`);\n }\n\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n\n const magnitude = Math.sqrt(normA) * Math.sqrt(normB);\n if (magnitude === 0) return 0;\n\n return dotProduct / magnitude;\n}\n\n/**\n * 计算欧氏距离\n * @param a 向量 A\n * @param b 向量 B\n * @returns 距离(越小越相似)\n */\nexport function euclideanDistance(a: Vector, b: Vector): number {\n if (a.length !== b.length) {\n throw new Error(`向量维度不匹配: ${a.length} vs ${b.length}`);\n }\n\n let sum = 0;\n for (let i = 0; i < a.length; i++) {\n const diff = a[i] - b[i];\n sum += diff * diff;\n }\n\n return Math.sqrt(sum);\n}\n\n/**\n * 将欧氏距离转换为相似度分数(0-1)\n * @param distance 欧氏距离\n * @returns 相似度分数\n */\nexport function distanceToSimilarity(distance: number): number {\n return 1 / (1 + distance);\n}\n\n/**\n * 归一化向量(使其长度为 1)\n * @param v 输入向量\n * @returns 归一化后的向量\n */\nexport function normalizeVector(v: Vector): Vector {\n const norm = Math.sqrt(v.reduce((sum, x) => sum + x * x, 0));\n if (norm === 0) return v;\n return v.map(x => x / norm);\n}\n\n/**\n * 向量序列化(用于存储)\n * @param v 向量\n * @returns Base64 编码的字符串\n */\nexport function serializeVector(v: Vector): string {\n const buffer = new Float32Array(v);\n const bytes = new Uint8Array(buffer.buffer);\n return Buffer.from(bytes).toString('base64');\n}\n\n/**\n * 向量反序列化\n * @param s Base64 编码的字符串\n * @returns 向量\n */\nexport function deserializeVector(s: string): Vector {\n const bytes = Buffer.from(s, 'base64');\n const buffer = new Float32Array(bytes.buffer, bytes.byteOffset, bytes.length / 4);\n return Array.from(buffer);\n}\n\n// ============ 默认配置 ============\n\n/** OpenAI 默认配置 */\nexport const OPENAI_DEFAULTS = {\n model: 'text-embedding-3-small',\n dimensions: 1536,\n baseUrl: 'https://api.openai.com/v1',\n} as const;\n\n/** Ollama 默认配置 */\nexport const OLLAMA_DEFAULTS = {\n model: 'nomic-embed-text',\n dimensions: 768,\n baseUrl: 'http://localhost:11434',\n} as const;\n\n/** 本地模型默认配置 */\nexport const LOCAL_DEFAULTS = {\n model: 'all-MiniLM-L6-v2',\n dimensions: 384,\n} as const;\n","import type Database from 'better-sqlite3';\n\n/**\n * 数据库迁移:为旧表添加 embedding 字段\n */\nfunction migrateEmbeddingColumn(db: Database.Database): void {\n // 检查 embedding 列是否存在\n const columns = db.pragma('table_info(memories)') as { name: string }[];\n const hasEmbedding = columns.some((col) => col.name === 'embedding');\n\n if (!hasEmbedding) {\n console.log('📦 迁移: 添加 embedding 字段...');\n db.exec('ALTER TABLE memories ADD COLUMN embedding TEXT');\n console.log('✅ 迁移完成');\n }\n}\n\n/**\n * 初始化数据库Schema\n */\nexport function initSchema(db: Database.Database): void {\n // 1. 创建memories主表\n db.exec(`\n CREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n projectId TEXT NOT NULL,\n sessionId TEXT,\n timestamp TEXT NOT NULL,\n type TEXT NOT NULL,\n tags TEXT, -- JSON数组: [\"tag1\", \"tag2\"]\n version INTEGER DEFAULT 1,\n\n -- content\n summary TEXT NOT NULL,\n data TEXT, -- JSON对象\n\n -- relations\n replaces TEXT, -- JSON数组\n relatedTo TEXT, -- JSON数组\n impacts TEXT, -- JSON数组\n derivedFrom TEXT,\n\n -- context(特定类型的上下文数据)\n context TEXT, -- JSON对象\n\n -- searchable\n keywords TEXT, -- JSON数组\n fullText TEXT,\n embedding TEXT, -- Base64 编码的向量(用于语义搜索)\n\n -- 时间戳\n createdAt TEXT NOT NULL,\n updatedAt TEXT NOT NULL,\n\n -- 索引字段\n UNIQUE(id)\n );\n `);\n\n // 2. 创建索引\n db.exec(`\n -- 项目ID索引(频繁按项目查询)\n CREATE INDEX IF NOT EXISTS idx_memories_projectId ON memories(projectId);\n\n -- 会话ID索引\n CREATE INDEX IF NOT EXISTS idx_memories_sessionId ON memories(sessionId);\n\n -- 类型索引\n CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);\n\n -- 时间戳索引(用于时间线查询)\n CREATE INDEX IF NOT EXISTS idx_memories_timestamp ON memories(timestamp DESC);\n\n -- 复合索引(项目+类型)- 用于按项目和类型过滤\n CREATE INDEX IF NOT EXISTS idx_memories_project_type ON memories(projectId, type);\n\n -- 复合索引(项目+时间)- 用于项目时间线查询,性能提升显著\n CREATE INDEX IF NOT EXISTS idx_memories_project_timestamp ON memories(projectId, timestamp DESC);\n\n -- 复合索引(项目+类型+时间)- 用于按项目和类型过滤的时间线\n CREATE INDEX IF NOT EXISTS idx_memories_project_type_timestamp ON memories(projectId, type, timestamp DESC);\n\n -- 部分索引(仅索引有会话的记忆)- 减少索引大小\n CREATE INDEX IF NOT EXISTS idx_memories_session_active ON memories(sessionId, timestamp DESC)\n WHERE sessionId IS NOT NULL;\n `);\n\n // 3. 创建FTS5全文搜索表\n db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(\n summary,\n fullText,\n tokenize = 'unicode61'\n );\n `);\n\n // 4. 创建触发器,自动同步FTS表\n db.exec(`\n -- 插入触发器\n CREATE TRIGGER IF NOT EXISTS memories_fts_insert AFTER INSERT ON memories BEGIN\n INSERT INTO memories_fts(rowid, summary, fullText)\n VALUES (new.rowid, new.summary, new.fullText);\n END;\n\n -- 更新触发器\n CREATE TRIGGER IF NOT EXISTS memories_fts_update AFTER UPDATE ON memories BEGIN\n UPDATE memories_fts\n SET summary = new.summary, fullText = new.fullText\n WHERE rowid = new.rowid;\n END;\n\n -- 删除触发器\n CREATE TRIGGER IF NOT EXISTS memories_fts_delete AFTER DELETE ON memories BEGIN\n DELETE FROM memories_fts WHERE rowid = old.rowid;\n END;\n `);\n\n // 5. 数据库迁移(兼容旧数据库)\n migrateEmbeddingColumn(db);\n}\n","import type { SearchResult, SearchFilters } from '@emp/core';\n\n/**\n * LRU 缓存节点\n */\ninterface CacheNode {\n key: string;\n value: SearchResult;\n prev: CacheNode | null;\n next: CacheNode | null;\n}\n\n/**\n * LRU(Least Recently Used)缓存\n * 用于缓存热点查询,提升检索性能\n */\nexport class LRUCache {\n private capacity: number;\n private cache: Map<string, CacheNode>;\n private head: CacheNode | null;\n private tail: CacheNode | null;\n private hits: number;\n private misses: number;\n\n constructor(capacity: number = 100) {\n this.capacity = capacity;\n this.cache = new Map();\n this.head = null;\n this.tail = null;\n this.hits = 0;\n this.misses = 0;\n }\n\n /**\n * 生成缓存 key\n */\n static generateKey(filters: SearchFilters): string {\n const parts = [\n filters.query || '',\n filters.projectId || '',\n filters.type || '',\n filters.sessionId || '',\n filters.strategy || '',\n filters.limit || '',\n filters.offset || '',\n (filters.tags || []).sort().join(','),\n ];\n return parts.join('|');\n }\n\n /**\n * 获取缓存\n */\n get(key: string): SearchResult | null {\n const node = this.cache.get(key);\n if (!node) {\n this.misses++;\n return null;\n }\n\n // 移到链表头部(最近使用)\n this.moveToHead(node);\n this.hits++;\n\n // 标记为缓存命中\n return {\n ...node.value,\n metrics: {\n dbTime: node.value.metrics?.dbTime || 0,\n parseTime: node.value.metrics?.parseTime || 0,\n strategyTime: node.value.metrics?.strategyTime,\n cacheHit: true,\n },\n };\n }\n\n /**\n * 设置缓存\n */\n set(key: string, value: SearchResult): void {\n let node = this.cache.get(key);\n\n if (node) {\n // 更新已存在的节点\n node.value = value;\n this.moveToHead(node);\n } else {\n // 创建新节点\n node = {\n key,\n value,\n prev: null,\n next: null,\n };\n\n this.cache.set(key, node);\n this.addToHead(node);\n\n // 超出容量,删除最少使用的\n if (this.cache.size > this.capacity) {\n const removed = this.removeTail();\n if (removed) {\n this.cache.delete(removed.key);\n }\n }\n }\n }\n\n /**\n * 清空缓存\n */\n clear(): void {\n this.cache.clear();\n this.head = null;\n this.tail = null;\n this.hits = 0;\n this.misses = 0;\n }\n\n /**\n * 失效指定项目的所有缓存\n */\n invalidateProject(projectId: string): void {\n const keysToDelete: string[] = [];\n\n for (const [key, _] of this.cache) {\n if (key.includes(`|${projectId}|`)) {\n keysToDelete.push(key);\n }\n }\n\n for (const key of keysToDelete) {\n const node = this.cache.get(key);\n if (node) {\n this.removeNode(node);\n this.cache.delete(key);\n }\n }\n }\n\n /**\n * 获取缓存统计\n */\n getStats() {\n const total = this.hits + this.misses;\n return {\n size: this.cache.size,\n capacity: this.capacity,\n hits: this.hits,\n misses: this.misses,\n hitRate: total > 0 ? this.hits / total : 0,\n };\n }\n\n // ========== 双向链表操作 ==========\n\n private addToHead(node: CacheNode): void {\n node.next = this.head;\n node.prev = null;\n\n if (this.head) {\n this.head.prev = node;\n }\n\n this.head = node;\n\n if (!this.tail) {\n this.tail = node;\n }\n }\n\n private removeNode(node: CacheNode): void {\n if (node.prev) {\n node.prev.next = node.next;\n } else {\n this.head = node.next;\n }\n\n if (node.next) {\n node.next.prev = node.prev;\n } else {\n this.tail = node.prev;\n }\n }\n\n private moveToHead(node: CacheNode): void {\n this.removeNode(node);\n this.addToHead(node);\n }\n\n private removeTail(): CacheNode | null {\n const node = this.tail;\n if (node) {\n this.removeNode(node);\n }\n return node;\n }\n}\n","import { PrismaClient, Prisma } from '@prisma/client';\nimport { nanoid } from 'nanoid';\nimport {\n type IStorage,\n type SearchFilters,\n type SearchResult,\n type TimelineOptions,\n type TimelineResult,\n type TimelineEntry,\n type RelationsOptions,\n type RelationNode,\n MemoryType,\n SearchStrategy,\n type Memory,\n type DecisionContext,\n type SolutionContext,\n type SessionContext,\n} from '@emp/core';\nimport { LRUCache } from './cache.js';\n\n/**\n * PostgreSQL存储实现(云版)\n * 使用Prisma ORM + PostgreSQL全文搜索\n */\nexport class PostgreSQLStorage implements IStorage {\n private prisma: PrismaClient;\n private cache: LRUCache | null;\n\n constructor(databaseUrl?: string, options?: { enableCache?: boolean; cacheSize?: number }) {\n this.prisma = new PrismaClient({\n datasources: databaseUrl\n ? {\n db: { url: databaseUrl },\n }\n : undefined,\n });\n\n // 初始化缓存(默认启用,容量100)\n this.cache = options?.enableCache !== false ? new LRUCache(options?.cacheSize || 100) : null;\n }\n\n /**\n * 通用存储方法\n */\n async store(params: {\n content: string;\n rawContext: Record<string, unknown>;\n projectId: string;\n type?: MemoryType;\n tags?: string[];\n sessionId?: string;\n relations?: {\n replaces?: string[];\n relatedTo?: string[];\n impacts?: string[];\n derivedFrom?: string;\n };\n }): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date();\n const memoryType = params.type || MemoryType.CODE;\n\n await this.prisma.memory.create({\n data: {\n id,\n projectId: params.projectId,\n sessionId: params.sessionId || null,\n timestamp,\n type: memoryType,\n tags: params.tags || [],\n summary: params.content,\n data: params.rawContext as any,\n replaces: params.relations?.replaces || [],\n relatedTo: params.relations?.relatedTo || [],\n impacts: params.relations?.impacts || [],\n derivedFrom: params.relations?.derivedFrom || null,\n context: params.rawContext as any,\n keywords: params.tags || [],\n fullText: params.content,\n },\n });\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 存储决策记忆\n */\n async storeDecision(\n params: DecisionContext & {\n projectId: string;\n tags?: string[];\n sessionId?: string;\n relations?: {\n replaces?: string[];\n relatedTo?: string[];\n impacts?: string[];\n derivedFrom?: string;\n };\n }\n ): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date();\n const summary = `[决策] ${params.question}`;\n const fullText = `${params.question} ${params.options.map((o) => o.name).join(' ')} ${params.reason}`;\n const keywords = [...(params.tags || []), ...params.options.map((o) => o.name), params.chosen];\n\n await this.prisma.memory.create({\n data: {\n id,\n projectId: params.projectId,\n sessionId: params.sessionId || null,\n timestamp,\n type: MemoryType.DECISION,\n tags: params.tags || [],\n summary,\n data: {},\n replaces: params.relations?.replaces || [],\n relatedTo: params.relations?.relatedTo || [],\n impacts: params.relations?.impacts || [],\n derivedFrom: params.relations?.derivedFrom || null,\n context: {\n question: params.question,\n analysis: params.analysis,\n options: params.options,\n chosen: params.chosen,\n reason: params.reason,\n } as any,\n keywords,\n fullText,\n },\n });\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 存储解决方案记忆\n */\n async storeSolution(\n params: SolutionContext & {\n projectId: string;\n tags?: string[];\n sessionId?: string;\n artifacts?: Record<string, string>;\n relations?: {\n replaces?: string[];\n relatedTo?: string[];\n impacts?: string[];\n derivedFrom?: string;\n };\n }\n ): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date();\n const summary = `[方案] ${params.problem}`;\n const fullText = `${params.problem} ${params.rootCause} ${params.solution} ${params.prevention || ''} ${params.relatedIssues?.join(' ') || ''}`;\n const keywords = [...(params.tags || []), ...(params.relatedIssues || [])];\n\n await this.prisma.memory.create({\n data: {\n id,\n projectId: params.projectId,\n sessionId: params.sessionId || null,\n timestamp,\n type: MemoryType.SOLUTION,\n tags: params.tags || [],\n summary,\n data: (params.artifacts || {}) as any,\n replaces: params.relations?.replaces || [],\n relatedTo: params.relations?.relatedTo || [],\n impacts: params.relations?.impacts || [],\n derivedFrom: params.relations?.derivedFrom || null,\n context: {\n problem: params.problem,\n rootCause: params.rootCause,\n solution: params.solution,\n prevention: params.prevention,\n relatedIssues: params.relatedIssues,\n } as any,\n keywords,\n fullText,\n },\n });\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 存储会话记忆\n */\n async storeSession(\n params: SessionContext & {\n projectId: string;\n sessionId?: string;\n }\n ): Promise<{ id: string; success: boolean }> {\n const id = `mem_${nanoid()}`;\n const timestamp = new Date();\n const summary = `[会话] ${params.summary}`;\n const fullText = `${params.summary} ${params.decisions?.join(' ') || ''} ${params.unfinishedTasks?.join(' ') || ''} ${params.nextSteps?.join(' ') || ''}`;\n const keywords = [...(params.decisions || []), ...(params.unfinishedTasks || [])];\n\n await this.prisma.memory.create({\n data: {\n id,\n projectId: params.projectId,\n sessionId: params.sessionId || id,\n timestamp,\n type: MemoryType.SESSION,\n tags: [],\n summary,\n data: {},\n replaces: [],\n relatedTo: [],\n impacts: [],\n derivedFrom: null,\n context: {\n summary: params.summary,\n decisions: params.decisions,\n unfinishedTasks: params.unfinishedTasks,\n nextSteps: params.nextSteps,\n } as any,\n keywords,\n fullText,\n },\n });\n\n // 失效相关缓存\n if (this.cache) {\n this.cache.invalidateProject(params.projectId);\n }\n\n return { id, success: true };\n }\n\n /**\n * 检索记忆\n */\n async recall(filters: SearchFilters): Promise<SearchResult> {\n const startTime = Date.now();\n\n // 检查缓存\n if (this.cache) {\n const cacheKey = LRUCache.generateKey(filters);\n const cached = this.cache.get(cacheKey);\n if (cached) {\n return cached; // 缓存命中,直接返回\n }\n }\n\n const strategy = filters.strategy || SearchStrategy.AUTO;\n const limit = filters.limit || 10;\n const offset = filters.offset || 0;\n\n let actualStrategy: SearchStrategy;\n let results: Memory[];\n let dbStartTime: number;\n let dbEndTime: number;\n\n // 策略选择\n const strategyStartTime = Date.now();\n\n // L1: 精确匹配(优先)\n if (strategy === SearchStrategy.EXACT || strategy === SearchStrategy.AUTO) {\n dbStartTime = Date.now();\n results = await this.exactSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.EXACT;\n\n // 如果L1找不到结果,降级到L2全文搜索\n if (results.length === 0 && strategy === SearchStrategy.AUTO) {\n dbStartTime = Date.now();\n results = await this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n }\n }\n // L2: 全文搜索\n else if (strategy === SearchStrategy.FULLTEXT) {\n dbStartTime = Date.now();\n results = await this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n }\n // L3: 语义检索(暂未实现)\n else {\n dbStartTime = Date.now();\n results = await this.fulltextSearch(filters, limit, offset);\n dbEndTime = Date.now();\n actualStrategy = SearchStrategy.FULLTEXT;\n }\n\n const strategyTime = Date.now() - strategyStartTime;\n const took = Date.now() - startTime;\n\n // 计算解析时间(总时间 - 数据库时间)\n const dbTime = dbEndTime - dbStartTime;\n const parseTime = took - dbTime - strategyTime;\n\n const result: SearchResult = {\n memories: results,\n total: results.length,\n strategy: actualStrategy,\n took,\n metrics: {\n dbTime,\n parseTime: Math.max(0, parseTime), // 确保非负\n strategyTime,\n cacheHit: false, // 数据库查询,标记为未命中\n },\n };\n\n // 写入缓存\n if (this.cache) {\n const cacheKey = LRUCache.generateKey(filters);\n this.cache.set(cacheKey, result);\n }\n\n return result;\n }\n\n /**\n * L1: 精确匹配检索\n */\n private async exactSearch(\n filters: SearchFilters,\n limit: number,\n offset: number\n ): Promise<Memory[]> {\n const where: Prisma.MemoryWhereInput = {};\n\n if (filters.projectId) {\n where.projectId = filters.projectId;\n }\n\n if (filters.type) {\n where.type = filters.type;\n }\n\n if (filters.sessionId) {\n where.sessionId = filters.sessionId;\n }\n\n if (filters.query) {\n where.OR = [\n { summary: { contains: filters.query, mode: 'insensitive' } },\n { fullText: { contains: filters.query, mode: 'insensitive' } },\n ];\n }\n\n const rows = await this.prisma.memory.findMany({\n where,\n orderBy: { timestamp: 'desc' },\n take: limit,\n skip: offset,\n });\n\n return rows.map(this.rowToMemory);\n }\n\n /**\n * L2: 全文搜索(PostgreSQL)\n */\n private async fulltextSearch(\n filters: SearchFilters,\n limit: number,\n offset: number\n ): Promise<Memory[]> {\n // 使用PostgreSQL的ILIKE进行简单全文搜索\n // 生产环境可以使用pg_trgm或to_tsvector实现更强大的搜索\n const where: Prisma.MemoryWhereInput = {};\n\n if (filters.projectId) {\n where.projectId = filters.projectId;\n }\n\n if (filters.type) {\n where.type = filters.type;\n }\n\n if (filters.sessionId) {\n where.sessionId = filters.sessionId;\n }\n\n if (filters.query) {\n where.OR = [\n { summary: { contains: filters.query, mode: 'insensitive' } },\n { fullText: { contains: filters.query, mode: 'insensitive' } },\n ];\n }\n\n const rows = await this.prisma.memory.findMany({\n where,\n orderBy: { timestamp: 'desc' },\n take: limit,\n skip: offset,\n });\n\n return rows.map(this.rowToMemory);\n }\n\n /**\n * 获取时间线\n */\n async getTimeline(options: TimelineOptions): Promise<TimelineResult> {\n const where: Prisma.MemoryWhereInput = {\n projectId: options.projectId,\n };\n\n if (options.type) {\n where.type = options.type;\n }\n\n if (options.dateRange) {\n where.timestamp = {\n gte: new Date(options.dateRange[0]),\n lte: new Date(options.dateRange[1]),\n };\n }\n\n const memories = await this.prisma.memory.findMany({\n where,\n orderBy: { timestamp: 'desc' },\n take: options.limit,\n skip: options.offset,\n });\n\n const converted = memories.map(this.rowToMemory);\n\n const entries: TimelineEntry[] = converted.map((memory, index) => ({\n memory,\n prevMemoryId: index > 0 ? converted[index - 1].meta.id : undefined,\n nextMemoryId: index < converted.length - 1 ? converted[index + 1].meta.id : undefined,\n }));\n\n return {\n entries,\n total: entries.length,\n };\n }\n\n /**\n * 获取关系链\n */\n async getRelations(options: RelationsOptions): Promise<RelationNode> {\n const memory = await this.getMemoryById(options.memoryId);\n if (!memory) {\n throw new Error(`Memory ${options.memoryId} not found`);\n }\n\n const depth = options.depth || 1;\n const relatedNodes: RelationNode[] = [];\n\n if (depth > 0) {\n // 查找所有相关记忆\n const relatedIds = [\n ...(memory.relations.replaces || []),\n ...(memory.relations.relatedTo || []),\n ...(memory.relations.impacts || []),\n ];\n\n if (memory.relations.derivedFrom) {\n relatedIds.push(memory.relations.derivedFrom);\n }\n\n for (const relatedId of relatedIds) {\n const relatedMemory = await this.getMemoryById(relatedId);\n if (relatedMemory) {\n // 递归查询关系链\n let nestedRelated: RelationNode[] | undefined = undefined;\n if (depth > 1) {\n const nestedResult = await this.getRelations({\n memoryId: relatedId,\n depth: depth - 1,\n });\n nestedRelated = nestedResult.related;\n }\n\n relatedNodes.push({\n memory: relatedMemory,\n related: nestedRelated,\n });\n }\n }\n }\n\n return {\n memory,\n related: relatedNodes.length > 0 ? relatedNodes : undefined,\n };\n }\n\n /**\n * 根据 ID 获取单个记忆\n */\n async getById(id: string): Promise<Memory | null> {\n const row = await this.prisma.memory.findUnique({\n where: { id },\n });\n return row ? this.rowToMemory(row) : null;\n }\n\n /**\n * 删除记忆\n */\n async delete(memoryId: string): Promise<{ success: boolean }> {\n try {\n // 先查询 projectId 用于缓存失效\n if (this.cache) {\n const memory = await this.prisma.memory.findUnique({\n where: { id: memoryId },\n select: { projectId: true },\n });\n if (memory) {\n this.cache.invalidateProject(memory.projectId);\n }\n }\n\n await this.prisma.memory.delete({\n where: { id: memoryId },\n });\n return { success: true };\n } catch (error) {\n return { success: false };\n }\n }\n\n /**\n * 更新记忆\n */\n async update(memoryId: string, updates: Partial<Memory>): Promise<{ success: boolean }> {\n try {\n const data: Prisma.MemoryUpdateInput = {};\n\n if (updates.content) {\n if (updates.content.summary) {\n data.summary = updates.content.summary;\n }\n if (updates.content.data !== undefined) {\n data.data = updates.content.data as any;\n }\n }\n\n if (updates.meta?.tags) {\n data.tags = updates.meta.tags;\n }\n\n if (updates.relations) {\n if (updates.relations.replaces) {\n data.replaces = updates.relations.replaces;\n }\n if (updates.relations.relatedTo) {\n data.relatedTo = updates.relations.relatedTo;\n }\n if (updates.relations.impacts) {\n data.impacts = updates.relations.impacts;\n }\n if (updates.relations.derivedFrom) {\n data.derivedFrom = updates.relations.derivedFrom;\n }\n }\n\n if (Object.keys(data).length === 0) {\n return { success: false };\n }\n\n await this.prisma.memory.update({\n where: { id: memoryId },\n data,\n });\n\n // 失效相关缓存\n if (this.cache) {\n const memory = await this.prisma.memory.findUnique({\n where: { id: memoryId },\n select: { projectId: true },\n });\n if (memory) {\n this.cache.invalidateProject(memory.projectId);\n }\n }\n\n return { success: true };\n } catch (error) {\n return { success: false };\n }\n }\n\n /**\n * 根据ID获取记忆\n */\n private async getMemoryById(id: string): Promise<Memory | null> {\n const row = await this.prisma.memory.findUnique({\n where: { id },\n });\n return row ? this.rowToMemory(row) : null;\n }\n\n /**\n * 将Prisma行转换为Memory对象\n */\n private rowToMemory(row: any): Memory {\n return {\n meta: {\n id: row.id,\n projectId: row.projectId,\n sessionId: row.sessionId,\n timestamp: row.timestamp.toISOString(),\n type: row.type as MemoryType,\n tags: row.tags || [],\n version: row.version,\n },\n content: {\n summary: row.summary,\n data: (row.data || {}) as Record<string, unknown>,\n },\n relations: {\n replaces: row.replaces || undefined,\n relatedTo: row.relatedTo || undefined,\n impacts: row.impacts || undefined,\n derivedFrom: row.derivedFrom || undefined,\n },\n searchable: {\n keywords: row.keywords || [],\n fullText: row.fullText,\n },\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n }\n\n /**\n * 关闭数据库连接\n */\n async close(): Promise<void> {\n await this.prisma.$disconnect();\n }\n}\n"],"mappings":"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","names":["MemoryType","SearchStrategy","OpenSourceFeature","CloudFeature","LicenseType","nanoid","nanoid"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memory-pulse-mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Memory Pulse - 精准、结构化的 AI 上下文记忆系统 MCP Server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
13
|
+
"prisma",
|
|
13
14
|
"README.md"
|
|
14
15
|
],
|
|
15
16
|
"keywords": [
|
|
@@ -33,7 +34,8 @@
|
|
|
33
34
|
"dependencies": {
|
|
34
35
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
35
36
|
"better-sqlite3": "^11.0.0",
|
|
36
|
-
"nanoid": "^5.0.9"
|
|
37
|
+
"nanoid": "^5.0.9",
|
|
38
|
+
"prisma": "^6.0.0"
|
|
37
39
|
},
|
|
38
40
|
"optionalDependencies": {
|
|
39
41
|
"@prisma/client": "^6.0.0"
|
|
@@ -52,6 +54,7 @@
|
|
|
52
54
|
"dev": "tsup --watch",
|
|
53
55
|
"test": "vitest",
|
|
54
56
|
"typecheck": "tsc --noEmit",
|
|
55
|
-
"clean": "rm -rf dist"
|
|
57
|
+
"clean": "rm -rf dist",
|
|
58
|
+
"postinstall": "prisma generate --schema=./prisma/schema.prisma || true"
|
|
56
59
|
}
|
|
57
60
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Prisma Schema for Context Memory System (PostgreSQL)
|
|
2
|
+
generator client {
|
|
3
|
+
provider = "prisma-client-js"
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
datasource db {
|
|
7
|
+
provider = "postgresql"
|
|
8
|
+
url = env("DATABASE_URL")
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/// 记忆表
|
|
12
|
+
model Memory {
|
|
13
|
+
/// 主键:记忆唯一标识
|
|
14
|
+
id String @id @default(cuid())
|
|
15
|
+
|
|
16
|
+
/// 元信息
|
|
17
|
+
projectId String
|
|
18
|
+
sessionId String?
|
|
19
|
+
timestamp DateTime @default(now())
|
|
20
|
+
type String // decision, solution, config, code, error, session
|
|
21
|
+
tags String[] @default([])
|
|
22
|
+
version Int @default(1)
|
|
23
|
+
|
|
24
|
+
/// 内容
|
|
25
|
+
summary String
|
|
26
|
+
data Json @default("{}")
|
|
27
|
+
|
|
28
|
+
/// 关系
|
|
29
|
+
replaces String[] @default([])
|
|
30
|
+
relatedTo String[] @default([])
|
|
31
|
+
impacts String[] @default([])
|
|
32
|
+
derivedFrom String?
|
|
33
|
+
|
|
34
|
+
/// 上下文(特定类型的额外数据)
|
|
35
|
+
context Json?
|
|
36
|
+
|
|
37
|
+
/// 检索字段
|
|
38
|
+
keywords String[] @default([])
|
|
39
|
+
fullText String
|
|
40
|
+
|
|
41
|
+
/// 时间戳
|
|
42
|
+
createdAt DateTime @default(now())
|
|
43
|
+
updatedAt DateTime @updatedAt
|
|
44
|
+
|
|
45
|
+
/// 索引
|
|
46
|
+
@@index([projectId])
|
|
47
|
+
@@index([sessionId])
|
|
48
|
+
@@index([type])
|
|
49
|
+
@@index([timestamp(sort: Desc)])
|
|
50
|
+
@@index([projectId, type])
|
|
51
|
+
@@index([projectId, timestamp(sort: Desc)])
|
|
52
|
+
@@index([projectId, type, timestamp(sort: Desc)])
|
|
53
|
+
@@map("memories")
|
|
54
|
+
}
|