@zooique/memora 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +148 -0
- package/dist/agent/agent.d.ts +343 -0
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/agent/agent.js +893 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/assembler.d.ts +77 -0
- package/dist/agent/assembler.d.ts.map +1 -0
- package/dist/agent/assembler.js +115 -0
- package/dist/agent/assembler.js.map +1 -0
- package/dist/agent/builtinToolHandlers.d.ts +96 -0
- package/dist/agent/builtinToolHandlers.d.ts.map +1 -0
- package/dist/agent/builtinToolHandlers.js +388 -0
- package/dist/agent/builtinToolHandlers.js.map +1 -0
- package/dist/agent/builtinTools.d.ts +35 -0
- package/dist/agent/builtinTools.d.ts.map +1 -0
- package/dist/agent/builtinTools.js +75 -0
- package/dist/agent/builtinTools.js.map +1 -0
- package/dist/agent/constants.d.ts +67 -0
- package/dist/agent/constants.d.ts.map +1 -0
- package/dist/agent/constants.js +67 -0
- package/dist/agent/constants.js.map +1 -0
- package/dist/agent/contextManager.d.ts +130 -0
- package/dist/agent/contextManager.d.ts.map +1 -0
- package/dist/agent/contextManager.js +287 -0
- package/dist/agent/contextManager.js.map +1 -0
- package/dist/agent/loop.d.ts +288 -0
- package/dist/agent/loop.d.ts.map +1 -0
- package/dist/agent/loop.js +756 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/managers/autoConfigRefiner.d.ts +39 -0
- package/dist/agent/managers/autoConfigRefiner.d.ts.map +1 -0
- package/dist/agent/managers/autoConfigRefiner.js +150 -0
- package/dist/agent/managers/autoConfigRefiner.js.map +1 -0
- package/dist/agent/managers/configManager.d.ts +114 -0
- package/dist/agent/managers/configManager.d.ts.map +1 -0
- package/dist/agent/managers/configManager.js +186 -0
- package/dist/agent/managers/configManager.js.map +1 -0
- package/dist/agent/managers/insightExtractor.d.ts +141 -0
- package/dist/agent/managers/insightExtractor.d.ts.map +1 -0
- package/dist/agent/managers/insightExtractor.js +420 -0
- package/dist/agent/managers/insightExtractor.js.map +1 -0
- package/dist/agent/managers/memoryAdvisor.d.ts +96 -0
- package/dist/agent/managers/memoryAdvisor.d.ts.map +1 -0
- package/dist/agent/managers/memoryAdvisor.js +198 -0
- package/dist/agent/managers/memoryAdvisor.js.map +1 -0
- package/dist/agent/managers/memoryInspector.d.ts +231 -0
- package/dist/agent/managers/memoryInspector.d.ts.map +1 -0
- package/dist/agent/managers/memoryInspector.js +327 -0
- package/dist/agent/managers/memoryInspector.js.map +1 -0
- package/dist/agent/managers/sessionManager.d.ts +89 -0
- package/dist/agent/managers/sessionManager.d.ts.map +1 -0
- package/dist/agent/managers/sessionManager.js +178 -0
- package/dist/agent/managers/sessionManager.js.map +1 -0
- package/dist/agent/managers/userFactExtractor.d.ts +25 -0
- package/dist/agent/managers/userFactExtractor.d.ts.map +1 -0
- package/dist/agent/managers/userFactExtractor.js +81 -0
- package/dist/agent/managers/userFactExtractor.js.map +1 -0
- package/dist/agent/managers/workProjection.d.ts +117 -0
- package/dist/agent/managers/workProjection.d.ts.map +1 -0
- package/dist/agent/managers/workProjection.js +290 -0
- package/dist/agent/managers/workProjection.js.map +1 -0
- package/dist/agent/messageHistory.d.ts +157 -0
- package/dist/agent/messageHistory.d.ts.map +1 -0
- package/dist/agent/messageHistory.js +288 -0
- package/dist/agent/messageHistory.js.map +1 -0
- package/dist/agent/toolExecutor.d.ts +137 -0
- package/dist/agent/toolExecutor.d.ts.map +1 -0
- package/dist/agent/toolExecutor.js +209 -0
- package/dist/agent/toolExecutor.js.map +1 -0
- package/dist/agent/tracer.d.ts +122 -0
- package/dist/agent/tracer.d.ts.map +1 -0
- package/dist/agent/tracer.js +64 -0
- package/dist/agent/tracer.js.map +1 -0
- package/dist/agent/types.d.ts +98 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +19 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/config/loader.d.ts +229 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +194 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/eval/evalTypes.d.ts +118 -0
- package/dist/eval/evalTypes.d.ts.map +1 -0
- package/dist/eval/evalTypes.js +102 -0
- package/dist/eval/evalTypes.js.map +1 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/embedding.d.ts +62 -0
- package/dist/llm/embedding.d.ts.map +1 -0
- package/dist/llm/embedding.js +162 -0
- package/dist/llm/embedding.js.map +1 -0
- package/dist/llm/factory.d.ts +39 -0
- package/dist/llm/factory.d.ts.map +1 -0
- package/dist/llm/factory.js +108 -0
- package/dist/llm/factory.js.map +1 -0
- package/dist/llm/openaiCompatible.d.ts +63 -0
- package/dist/llm/openaiCompatible.d.ts.map +1 -0
- package/dist/llm/openaiCompatible.js +340 -0
- package/dist/llm/openaiCompatible.js.map +1 -0
- package/dist/llm/provider.d.ts +91 -0
- package/dist/llm/provider.d.ts.map +1 -0
- package/dist/llm/provider.js +14 -0
- package/dist/llm/provider.js.map +1 -0
- package/dist/llm/types.d.ts +25 -0
- package/dist/llm/types.d.ts.map +1 -0
- package/dist/llm/types.js +7 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/logging/logger.d.ts +39 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +279 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/logging/loggerInterface.d.ts +33 -0
- package/dist/logging/loggerInterface.d.ts.map +1 -0
- package/dist/logging/loggerInterface.js +2 -0
- package/dist/logging/loggerInterface.js.map +1 -0
- package/dist/memory/inMemoryRelationStore.d.ts +51 -0
- package/dist/memory/inMemoryRelationStore.d.ts.map +1 -0
- package/dist/memory/inMemoryRelationStore.js +65 -0
- package/dist/memory/inMemoryRelationStore.js.map +1 -0
- package/dist/memory/inMemoryStorage.d.ts +97 -0
- package/dist/memory/inMemoryStorage.d.ts.map +1 -0
- package/dist/memory/inMemoryStorage.js +177 -0
- package/dist/memory/inMemoryStorage.js.map +1 -0
- package/dist/memory/loader.d.ts +49 -0
- package/dist/memory/loader.d.ts.map +1 -0
- package/dist/memory/loader.js +93 -0
- package/dist/memory/loader.js.map +1 -0
- package/dist/memory/projectManager.d.ts +182 -0
- package/dist/memory/projectManager.d.ts.map +1 -0
- package/dist/memory/projectManager.js +441 -0
- package/dist/memory/projectManager.js.map +1 -0
- package/dist/memory/recall.d.ts +77 -0
- package/dist/memory/recall.d.ts.map +1 -0
- package/dist/memory/recall.js +147 -0
- package/dist/memory/recall.js.map +1 -0
- package/dist/memory/relationStore.d.ts +78 -0
- package/dist/memory/relationStore.d.ts.map +1 -0
- package/dist/memory/relationStore.js +2 -0
- package/dist/memory/relationStore.js.map +1 -0
- package/dist/memory/sessionStore.d.ts +84 -0
- package/dist/memory/sessionStore.d.ts.map +1 -0
- package/dist/memory/sessionStore.js +2 -0
- package/dist/memory/sessionStore.js.map +1 -0
- package/dist/memory/storageInterface.d.ts +107 -0
- package/dist/memory/storageInterface.d.ts.map +1 -0
- package/dist/memory/storageInterface.js +2 -0
- package/dist/memory/storageInterface.js.map +1 -0
- package/dist/memory/store.d.ts +50 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +160 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/memory/types.d.ts +189 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +230 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/memory/userProfile.d.ts +156 -0
- package/dist/memory/userProfile.d.ts.map +1 -0
- package/dist/memory/userProfile.js +315 -0
- package/dist/memory/userProfile.js.map +1 -0
- package/dist/memory/vectorStore.d.ts +75 -0
- package/dist/memory/vectorStore.d.ts.map +1 -0
- package/dist/memory/vectorStore.js +144 -0
- package/dist/memory/vectorStore.js.map +1 -0
- package/dist/persona/personaManager.d.ts +121 -0
- package/dist/persona/personaManager.d.ts.map +1 -0
- package/dist/persona/personaManager.js +349 -0
- package/dist/persona/personaManager.js.map +1 -0
- package/dist/persona/types.d.ts +32 -0
- package/dist/persona/types.d.ts.map +1 -0
- package/dist/persona/types.js +5 -0
- package/dist/persona/types.js.map +1 -0
- package/dist/security/pathGuard.d.ts +121 -0
- package/dist/security/pathGuard.d.ts.map +1 -0
- package/dist/security/pathGuard.js +276 -0
- package/dist/security/pathGuard.js.map +1 -0
- package/dist/skill/skillManager.d.ts +82 -0
- package/dist/skill/skillManager.d.ts.map +1 -0
- package/dist/skill/skillManager.js +198 -0
- package/dist/skill/skillManager.js.map +1 -0
- package/dist/skill/types.d.ts +28 -0
- package/dist/skill/types.d.ts.map +1 -0
- package/dist/skill/types.js +5 -0
- package/dist/skill/types.js.map +1 -0
- package/dist/utils/errors.d.ts +86 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +143 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/eventEmitter.d.ts +87 -0
- package/dist/utils/eventEmitter.d.ts.map +1 -0
- package/dist/utils/eventEmitter.js +79 -0
- package/dist/utils/eventEmitter.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +24 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +44 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/json.d.ts +20 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +65 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/loggerHolder.d.ts +37 -0
- package/dist/utils/loggerHolder.d.ts.map +1 -0
- package/dist/utils/loggerHolder.js +49 -0
- package/dist/utils/loggerHolder.js.map +1 -0
- package/dist/utils/math.d.ts +5 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/math.js +19 -0
- package/dist/utils/math.js.map +1 -0
- package/dist/utils/path.d.ts +28 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +33 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/safeTimer.d.ts +26 -0
- package/dist/utils/safeTimer.d.ts.map +1 -0
- package/dist/utils/safeTimer.js +49 -0
- package/dist/utils/safeTimer.js.map +1 -0
- package/dist/utils/scanner.d.ts +54 -0
- package/dist/utils/scanner.d.ts.map +1 -0
- package/dist/utils/scanner.js +115 -0
- package/dist/utils/scanner.js.map +1 -0
- package/dist/utils/segmenter.d.ts +30 -0
- package/dist/utils/segmenter.d.ts.map +1 -0
- package/dist/utils/segmenter.js +80 -0
- package/dist/utils/segmenter.js.map +1 -0
- package/dist/utils/strings.d.ts +18 -0
- package/dist/utils/strings.d.ts.map +1 -0
- package/dist/utils/strings.js +25 -0
- package/dist/utils/strings.js.map +1 -0
- package/dist/utils/time.d.ts +23 -0
- package/dist/utils/time.d.ts.map +1 -0
- package/dist/utils/time.js +31 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/toError.d.ts +13 -0
- package/dist/utils/toError.d.ts.map +1 -0
- package/dist/utils/toError.js +22 -0
- package/dist/utils/toError.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 项目管理器 — M-207 多项目并发
|
|
3
|
+
*
|
|
4
|
+
* 核心职责:
|
|
5
|
+
* - 管理项目注册表(~/.memora/projects.json)
|
|
6
|
+
* - 锁文件机制(.memora/.lock)防止同项目并发写入导致数据损坏
|
|
7
|
+
* - Agent 级资源管理(memora.db 全局共享,不随项目切换重建)
|
|
8
|
+
* - 两层记忆加载:项目级(projectPath/.memora/)→ Agent 级(configDir)
|
|
9
|
+
* - 项目切换(只更新 projectPath + security + 重新加载项目 rules/skills)
|
|
10
|
+
*
|
|
11
|
+
* 设计原则(单 Agent 模型):
|
|
12
|
+
* - memora.db 只有一个(Agent 级),所有项目共享同一记忆数据库
|
|
13
|
+
* - 项目切换不重建数据库,只更新安全守卫 + 重新扫描项目规则
|
|
14
|
+
* - 项目级 .memora/ 仅存放 rules/ 和 skills/(无 memora.db)
|
|
15
|
+
*
|
|
16
|
+
* 锁文件策略:
|
|
17
|
+
* - 打开项目时创建 .lock 文件(含 PID + 时间戳 + 主机名)
|
|
18
|
+
* - 关闭/切换项目时删除 .lock 文件
|
|
19
|
+
* - 检测到残留锁时:判断进程是否存活 → 存活则警告 / 已死则清理
|
|
20
|
+
* - 不强制阻止并发(CLI-first,用户决定)
|
|
21
|
+
*
|
|
22
|
+
* 详见 ADR-008 · 目录结构按"职责分层"
|
|
23
|
+
*/
|
|
24
|
+
import { resolve, join } from 'node:path';
|
|
25
|
+
import { hostname } from 'node:os';
|
|
26
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, } from 'node:fs';
|
|
27
|
+
import { mkdir, readFile, writeFile, unlink } from 'node:fs/promises';
|
|
28
|
+
import { FileStore } from '../memory/store.js';
|
|
29
|
+
import { InMemoryStorage } from '../memory/inMemoryStorage.js';
|
|
30
|
+
import { MemoryLoader } from '../memory/loader.js';
|
|
31
|
+
import { logger } from '../logging/logger.js';
|
|
32
|
+
import { toError } from '../utils/errors.js';
|
|
33
|
+
import { expandHome } from '../utils/path.js';
|
|
34
|
+
import { SOURCE_LABELS } from '../memory/types.js';
|
|
35
|
+
// ─── QC-24 类型守卫 ─────────────────────────────────────
|
|
36
|
+
// 对不可信磁盘文件 JSON.parse 结果进行运行时校验,替代 `as` 类型断言
|
|
37
|
+
/**
|
|
38
|
+
* 判断值是否为非数组对象(排除 null)
|
|
39
|
+
*
|
|
40
|
+
* @param value 待校验的值
|
|
41
|
+
* @returns true 表示是普通对象
|
|
42
|
+
*/
|
|
43
|
+
function isPlainObject(value) {
|
|
44
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 判断值是否为 LockInfo(锁文件结构)
|
|
48
|
+
*
|
|
49
|
+
* @param value 待校验的值
|
|
50
|
+
* @returns true 表示符合 LockInfo 结构
|
|
51
|
+
*/
|
|
52
|
+
function isLockInfo(value) {
|
|
53
|
+
if (!isPlainObject(value))
|
|
54
|
+
return false;
|
|
55
|
+
return (typeof value['pid'] === 'number' &&
|
|
56
|
+
typeof value['acquiredAt'] === 'string' &&
|
|
57
|
+
typeof value['hostname'] === 'string');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 判断值是否为 ProjectEntry(项目注册表条目)
|
|
61
|
+
*
|
|
62
|
+
* @param value 待校验的值
|
|
63
|
+
* @returns true 表示符合 ProjectEntry 结构
|
|
64
|
+
*/
|
|
65
|
+
function isProjectEntry(value) {
|
|
66
|
+
if (!isPlainObject(value))
|
|
67
|
+
return false;
|
|
68
|
+
return (typeof value['path'] === 'string' &&
|
|
69
|
+
typeof value['name'] === 'string' &&
|
|
70
|
+
typeof value['lastOpened'] === 'string');
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 判断值是否为 ProjectEntry 数组
|
|
74
|
+
*
|
|
75
|
+
* 过滤掉不符合结构的条目,仅保留合法条目
|
|
76
|
+
*
|
|
77
|
+
* @param value 待校验的值
|
|
78
|
+
* @returns 解析后的合法条目数组(损坏时返回空数组)
|
|
79
|
+
*/
|
|
80
|
+
function asProjectEntryArray(value) {
|
|
81
|
+
if (!Array.isArray(value))
|
|
82
|
+
return [];
|
|
83
|
+
return value.filter(isProjectEntry);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 项目管理器
|
|
87
|
+
*
|
|
88
|
+
* 管理多项目的生命周期:
|
|
89
|
+
* 1. 初始化当前项目(加锁 + 加载两层配置)
|
|
90
|
+
* 2. /project <name> 切换到新项目(解锁旧项目 + 加锁新项目)
|
|
91
|
+
* 3. 退出时清理锁文件
|
|
92
|
+
*/
|
|
93
|
+
export class ProjectManager {
|
|
94
|
+
/** 项目注册表路径 */
|
|
95
|
+
registryPath;
|
|
96
|
+
/** Agent 级数据目录(memora.db 所在目录) */
|
|
97
|
+
agentDataDir;
|
|
98
|
+
/** Agent 级存储实例(全局共享,不随项目切换重建) */
|
|
99
|
+
agentIndex = null;
|
|
100
|
+
/** 当前打开的项目路径 */
|
|
101
|
+
currentProjectPath = null;
|
|
102
|
+
/** 当前持有的锁文件路径 */
|
|
103
|
+
currentLockPath = null;
|
|
104
|
+
/** 外部注入的存储实例(可选,不传则内部创建 InMemoryStorage 兜底) */
|
|
105
|
+
externalStorage;
|
|
106
|
+
/** A-004: SecurityGuard 工厂函数(由 Agent 层注入) */
|
|
107
|
+
createSecurityGuard;
|
|
108
|
+
constructor(options) {
|
|
109
|
+
const { dataDir, storage, registryDir, createSecurityGuard } = options;
|
|
110
|
+
const memoraHome = resolve(expandHome(dataDir));
|
|
111
|
+
this.agentDataDir = memoraHome;
|
|
112
|
+
// 注册表目录:优先使用宿主指定的用户级路径,避免每项目重复存储
|
|
113
|
+
const registryHome = registryDir ? resolve(expandHome(registryDir)) : memoraHome;
|
|
114
|
+
this.registryPath = join(registryHome, 'projects.json');
|
|
115
|
+
// 保存外部注入的存储实例(宿主项目注入时使用)
|
|
116
|
+
this.externalStorage = storage ?? null;
|
|
117
|
+
// A-004: 保存 SecurityGuard 工厂函数
|
|
118
|
+
this.createSecurityGuard = createSecurityGuard;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* 确保 Agent 级资源已初始化(存储实例)
|
|
122
|
+
* 存储实例在整个 Agent 生命周期内共享,不随项目切换重建
|
|
123
|
+
*
|
|
124
|
+
* 如果构造时注入了外部存储实例,直接使用;
|
|
125
|
+
* 否则内部创建 InMemoryStorage(非持久化兜底,仅开发/测试用)。
|
|
126
|
+
*/
|
|
127
|
+
async ensureAgentResources() {
|
|
128
|
+
if (!this.agentIndex) {
|
|
129
|
+
await mkdir(this.agentDataDir, { recursive: true });
|
|
130
|
+
// 优先使用外部注入的存储实例
|
|
131
|
+
if (this.externalStorage) {
|
|
132
|
+
this.agentIndex = this.externalStorage;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// 兜底:InMemoryStorage(非持久化,不依赖 native 模块)
|
|
136
|
+
// 生产环境应由宿主注入持久化实现(如 SqliteStorage)
|
|
137
|
+
logger.warn({ hasStorage: false }, '未注入持久化存储实现,Agent 将使用 InMemoryStorage(数据重启后丢失)');
|
|
138
|
+
this.agentIndex = new InMemoryStorage();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return { index: this.agentIndex };
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 初始化指定项目
|
|
145
|
+
*
|
|
146
|
+
* 两层记忆加载:
|
|
147
|
+
* 1) 项目级:扫描 projectPath/.memora/rules/ + skills/
|
|
148
|
+
* 2) Agent 级:扫描 configDir 下的所有配置(rules/skills/personas/tools)
|
|
149
|
+
*
|
|
150
|
+
* 全局规则不再由内核硬编码路径,宿主可通过 configDir 统一管理。
|
|
151
|
+
*
|
|
152
|
+
* memora.db 是 Agent 级共享资源,不随项目切换重建。
|
|
153
|
+
*
|
|
154
|
+
* @param projectPath 项目根目录
|
|
155
|
+
* @param projectName 项目名称(可选,默认取目录名)
|
|
156
|
+
* @param configDir Agent 级配置目录(personas/rules/skills/tools)
|
|
157
|
+
*/
|
|
158
|
+
async initProject(projectPath, projectName, configDir) {
|
|
159
|
+
// 如果已有打开的项目,先关闭(释放旧项目锁,但不关 Agent 级 DB)
|
|
160
|
+
if (this.currentProjectPath) {
|
|
161
|
+
await this.closeProject();
|
|
162
|
+
}
|
|
163
|
+
const memoraDir = this.resolveMemoraDir(projectPath);
|
|
164
|
+
// 获取锁文件(项目级锁,防止同项目并发)
|
|
165
|
+
await this.acquireLock(memoraDir);
|
|
166
|
+
this.currentProjectPath = projectPath;
|
|
167
|
+
this.currentLockPath = join(memoraDir, '.lock');
|
|
168
|
+
// FD-24: 后续步骤失败时释放锁并重置状态,避免锁文件残留导致下次启动检测失败
|
|
169
|
+
try {
|
|
170
|
+
// 确保项目 .memora/ 目录存在
|
|
171
|
+
await mkdir(memoraDir, { recursive: true });
|
|
172
|
+
// Agent 级共享资源(memora.db 只有一个)
|
|
173
|
+
const { index } = await this.ensureAgentResources();
|
|
174
|
+
// 合并加载结果(两层扫描汇总)
|
|
175
|
+
const loadResult = { loaded: 0, skipped: 0, errors: [] };
|
|
176
|
+
// 1) 项目级 FileStore:扫描 projectPath/.memora/ 下的 rules/ + skills/
|
|
177
|
+
const projectFileStore = new FileStore(memoraDir);
|
|
178
|
+
const projectLoader = new MemoryLoader(projectFileStore, index);
|
|
179
|
+
const projectResult = await projectLoader.loadAllToIndex();
|
|
180
|
+
loadResult.loaded += projectResult.loaded;
|
|
181
|
+
loadResult.skipped += projectResult.skipped;
|
|
182
|
+
loadResult.errors.push(...projectResult.errors);
|
|
183
|
+
// 2) Agent 级 FileStore:扫描 configDir 下的所有配置(rules/skills/personas/tools)
|
|
184
|
+
if (configDir) {
|
|
185
|
+
const configFileStore = new FileStore(configDir);
|
|
186
|
+
const configLoader = new MemoryLoader(configFileStore, index);
|
|
187
|
+
const configResult = await configLoader.loadAllToIndex();
|
|
188
|
+
loadResult.loaded += configResult.loaded;
|
|
189
|
+
loadResult.skipped += configResult.skipped;
|
|
190
|
+
loadResult.errors.push(...configResult.errors);
|
|
191
|
+
}
|
|
192
|
+
// bootstrap 过滤:按 source 获取 rule + skill 必召记忆(跳过 persona,由 PersonaManager 管理)
|
|
193
|
+
const rules = index.getBySource(SOURCE_LABELS.RULE);
|
|
194
|
+
const skills = index.getBySource(SOURCE_LABELS.SKILL);
|
|
195
|
+
const bootstrapMemories = [...rules, ...skills];
|
|
196
|
+
// A-004: 安全守卫由 Agent 层注入的工厂函数创建,解除 memory→security 反向依赖
|
|
197
|
+
const security = this.createSecurityGuard
|
|
198
|
+
? this.createSecurityGuard(projectPath, memoraDir, configDir, this.agentDataDir)
|
|
199
|
+
: null;
|
|
200
|
+
// 注册到项目表
|
|
201
|
+
const name = projectName || this.inferProjectName(projectPath);
|
|
202
|
+
this.registerProject(projectPath, name);
|
|
203
|
+
logger.info({
|
|
204
|
+
projectPath,
|
|
205
|
+
projectName: name,
|
|
206
|
+
memoraDir,
|
|
207
|
+
loaded: loadResult.loaded,
|
|
208
|
+
bootstrapCount: bootstrapMemories.length,
|
|
209
|
+
}, '项目初始化完成');
|
|
210
|
+
return {
|
|
211
|
+
projectPath,
|
|
212
|
+
projectName: name,
|
|
213
|
+
memoraDir,
|
|
214
|
+
dbPath: join(this.agentDataDir, 'memora.db'),
|
|
215
|
+
fileStore: projectFileStore,
|
|
216
|
+
index,
|
|
217
|
+
security,
|
|
218
|
+
bootstrapMemories,
|
|
219
|
+
loadResult,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
// FD-24: 后续步骤失败时释放锁并重置状态,避免锁文件残留导致下次启动检测失败
|
|
224
|
+
await this.releaseLock().catch((releaseErr) => {
|
|
225
|
+
logger.warn({ err: releaseErr }, '释放项目锁失败');
|
|
226
|
+
});
|
|
227
|
+
this.currentProjectPath = null;
|
|
228
|
+
this.currentLockPath = null;
|
|
229
|
+
throw err;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* 关闭当前项目
|
|
234
|
+
* 释放锁文件,但不关闭 Agent 级数据库(memora.db 是共享的)
|
|
235
|
+
*/
|
|
236
|
+
async closeProject() {
|
|
237
|
+
// Agent 级 index/sessionStore 不关闭——它们是共享的,在整个 Agent 生命周期内持久存在
|
|
238
|
+
await this.releaseLock();
|
|
239
|
+
this.currentProjectPath = null;
|
|
240
|
+
this.currentLockPath = null;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* 完全关闭:释放项目锁 + 关闭 Agent 级数据库
|
|
244
|
+
* 应在 Agent 整体关闭时调用(而非项目切换时)
|
|
245
|
+
*/
|
|
246
|
+
async shutdown() {
|
|
247
|
+
if (this.currentProjectPath) {
|
|
248
|
+
await this.closeProject();
|
|
249
|
+
}
|
|
250
|
+
if (this.agentIndex) {
|
|
251
|
+
try {
|
|
252
|
+
this.agentIndex.close?.();
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
logger.warn({ err }, '关闭 Agent 数据库失败');
|
|
256
|
+
}
|
|
257
|
+
this.agentIndex = null;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* 列出已注册的项目(IX-02:统一为 getter 风格,与 persona/skill 一致)
|
|
262
|
+
*/
|
|
263
|
+
get list() {
|
|
264
|
+
return this.readRegistry();
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* 列出已注册的项目
|
|
268
|
+
* @deprecated 请使用 `projectManager.list` getter 代替
|
|
269
|
+
*/
|
|
270
|
+
listProjects() {
|
|
271
|
+
return this.readRegistry();
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* 注册项目到注册表
|
|
275
|
+
*/
|
|
276
|
+
registerProject(projectPath, name) {
|
|
277
|
+
const registry = this.readRegistry();
|
|
278
|
+
// Windows 文件系统不区分大小写,路径大小写不同视为同一项目
|
|
279
|
+
const existing = registry.findIndex((e) => e.path.toLowerCase() === projectPath.toLowerCase());
|
|
280
|
+
const entry = {
|
|
281
|
+
path: projectPath,
|
|
282
|
+
name,
|
|
283
|
+
lastOpened: new Date().toISOString(),
|
|
284
|
+
};
|
|
285
|
+
if (existing >= 0) {
|
|
286
|
+
registry[existing] = entry;
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
registry.push(entry);
|
|
290
|
+
}
|
|
291
|
+
this.writeRegistry(registry);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* 从注册表移除项目
|
|
295
|
+
*/
|
|
296
|
+
unregisterProject(projectPath) {
|
|
297
|
+
const registry = this.readRegistry();
|
|
298
|
+
// Windows 文件系统不区分大小写,大小写不同视为同一项目
|
|
299
|
+
const filtered = registry.filter((e) => e.path.toLowerCase() !== projectPath.toLowerCase());
|
|
300
|
+
this.writeRegistry(filtered);
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* 获取当前项目路径
|
|
304
|
+
*/
|
|
305
|
+
get currentProject() {
|
|
306
|
+
return this.currentProjectPath;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* 获取锁文件
|
|
310
|
+
* 如果锁文件存在且进程存活,发出警告但不阻止
|
|
311
|
+
* 如果锁文件存在但进程已死,清理残留锁
|
|
312
|
+
*/
|
|
313
|
+
async acquireLock(memoraDir) {
|
|
314
|
+
const lockPath = join(memoraDir, '.lock');
|
|
315
|
+
try {
|
|
316
|
+
// 尝试读取锁文件(存在时)
|
|
317
|
+
const raw = await readFile(lockPath, 'utf-8');
|
|
318
|
+
// QC-24 使用类型守卫校验 JSON.parse 结果,替代 `as LockInfo` 类型断言
|
|
319
|
+
const parsed = JSON.parse(raw);
|
|
320
|
+
if (!isLockInfo(parsed)) {
|
|
321
|
+
// 锁文件结构损坏,清理后重新获取
|
|
322
|
+
logger.warn({ path: lockPath }, '锁文件结构损坏,清理残留');
|
|
323
|
+
await this.safeUnlink(lockPath);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const info = parsed;
|
|
327
|
+
// 检查进程是否存活
|
|
328
|
+
if (this.isProcessAlive(info.pid)) {
|
|
329
|
+
logger.warn({ pid: info.pid, acquiredAt: info.acquiredAt, hostname: info.hostname }, '项目已被其他进程打开(锁文件存在),继续操作可能导致数据冲突');
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
// 残留锁,清理
|
|
333
|
+
logger.info({ pid: info.pid }, '清理残留锁文件(进程已退出)');
|
|
334
|
+
await this.safeUnlink(lockPath);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
catch (err) {
|
|
338
|
+
// 锁文件不存在或损坏,清理:记录 debug 日志便于排查(不存在属正常首次启动)
|
|
339
|
+
logger.debug({ path: lockPath, err: toError(err).message }, '锁文件读取失败,清理残留');
|
|
340
|
+
await this.safeUnlink(lockPath);
|
|
341
|
+
}
|
|
342
|
+
// 写入新锁
|
|
343
|
+
const lockInfo = {
|
|
344
|
+
pid: process.pid,
|
|
345
|
+
acquiredAt: new Date().toISOString(),
|
|
346
|
+
hostname: hostname(),
|
|
347
|
+
};
|
|
348
|
+
await mkdir(memoraDir, { recursive: true });
|
|
349
|
+
await writeFile(lockPath, JSON.stringify(lockInfo, null, 2), 'utf-8');
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* 释放锁文件
|
|
353
|
+
*/
|
|
354
|
+
async releaseLock() {
|
|
355
|
+
if (this.currentLockPath) {
|
|
356
|
+
await this.safeUnlink(this.currentLockPath);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* 安全删除文件(忽略不存在的错误)
|
|
361
|
+
*/
|
|
362
|
+
async safeUnlink(filePath) {
|
|
363
|
+
try {
|
|
364
|
+
await unlink(filePath);
|
|
365
|
+
}
|
|
366
|
+
catch (err) {
|
|
367
|
+
logger.debug({ path: filePath, err: toError(err).message }, 'safeUnlink 忽略删除失败');
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* 检查进程是否存活
|
|
372
|
+
* Windows: tasklist /FI "PID eq <pid>"
|
|
373
|
+
* POSIX: kill(pid, 0)
|
|
374
|
+
*/
|
|
375
|
+
isProcessAlive(pid) {
|
|
376
|
+
try {
|
|
377
|
+
// 发送信号 0 检查进程是否存在(POSIX 兼容)
|
|
378
|
+
// Windows 上 process.kill(pid, 0) 也会抛出错误如果进程不存在
|
|
379
|
+
process.kill(pid, 0);
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
logger.debug({ pid }, '进程不存在');
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* 解析项目的 .memora/ 目录路径
|
|
389
|
+
* 每个项目有独立的 .memora/ 目录(在项目根目录下)
|
|
390
|
+
* 这与 config.memory.dataDir(用户级默认目录)不同
|
|
391
|
+
*/
|
|
392
|
+
resolveMemoraDir(projectPath) {
|
|
393
|
+
return resolve(projectPath, '.memora');
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* 从项目路径推断项目名称
|
|
397
|
+
* 取路径最后一段目录名
|
|
398
|
+
*/
|
|
399
|
+
inferProjectName(projectPath) {
|
|
400
|
+
const parts = projectPath.replace(/[/\\]+$/, '').split(/[/\\]/);
|
|
401
|
+
return parts[parts.length - 1] || 'unnamed';
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* 读取项目注册表
|
|
405
|
+
*
|
|
406
|
+
* 同步读取:list getter 契约要求同步返回,注册表操作低频,同步 I/O 影响可控
|
|
407
|
+
* 损坏时返回空数组并记录警告日志,避免静默吞错掩盖磁盘故障
|
|
408
|
+
*/
|
|
409
|
+
readRegistry() {
|
|
410
|
+
if (!existsSync(this.registryPath)) {
|
|
411
|
+
return [];
|
|
412
|
+
}
|
|
413
|
+
try {
|
|
414
|
+
const raw = readFileSync(this.registryPath, 'utf-8');
|
|
415
|
+
// QC-24 使用类型守卫校验 JSON.parse 结果,替代 `as ProjectEntry[]` 类型断言
|
|
416
|
+
// 过滤掉不符合结构的条目,仅保留合法条目
|
|
417
|
+
const parsed = JSON.parse(raw);
|
|
418
|
+
const entries = asProjectEntryArray(parsed);
|
|
419
|
+
if (entries.length === 0 && Array.isArray(parsed) && parsed.length > 0) {
|
|
420
|
+
// 数组存在但所有条目都不合法,记录警告
|
|
421
|
+
logger.warn({ path: this.registryPath, totalEntries: parsed.length }, '项目注册表所有条目结构不合法,返回空列表');
|
|
422
|
+
}
|
|
423
|
+
return entries;
|
|
424
|
+
}
|
|
425
|
+
catch (err) {
|
|
426
|
+
// 注册表损坏:记录警告日志便于排查(不存在属正常首次启动,损坏需排查)
|
|
427
|
+
logger.warn({ path: this.registryPath, err: toError(err).message }, '项目注册表解析失败,返回空列表');
|
|
428
|
+
return [];
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* 写入项目注册表
|
|
433
|
+
*/
|
|
434
|
+
writeRegistry(entries) {
|
|
435
|
+
// 确保目录存在
|
|
436
|
+
const dir = this.registryPath.replace(/[/\\][^/\\]+$/, '');
|
|
437
|
+
mkdirSync(dir, { recursive: true });
|
|
438
|
+
writeFileSync(this.registryPath, JSON.stringify(entries, null, 2), 'utf-8');
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
//# sourceMappingURL=projectManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectManager.js","sourceRoot":"","sources":["../../src/memory/projectManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 记忆召回 — 简化关键词搜索
|
|
3
|
+
*
|
|
4
|
+
* 设计哲学:每次用户发消息,从所有记忆中搜索最相关的几条注入上下文
|
|
5
|
+
* 基于基元驱动模型,通过 source 开放字符串区分记忆来源,
|
|
6
|
+
* 通过双通道(语义 + 关键词)召回,无需独立管理器
|
|
7
|
+
*
|
|
8
|
+
* 详见 ADR-004 · 记忆统一模型 + architecture_philosophy_rules.md §6 增量召回
|
|
9
|
+
*/
|
|
10
|
+
import type { Memory } from '../memory/types.js';
|
|
11
|
+
import type { IMemoryStorage } from '../memory/storageInterface.js';
|
|
12
|
+
import type { VectorStore } from '../memory/vectorStore.js';
|
|
13
|
+
/** 语义搜索召回倍率(在最终 limit 基础上多召回一些,供后续融合排序) */
|
|
14
|
+
export declare const RECALL_LIMIT_MULTIPLIER = 2;
|
|
15
|
+
/** 综合排序时语义相似度权重 */
|
|
16
|
+
export declare const VECTOR_SCORE_WEIGHT = 0.6;
|
|
17
|
+
/** 综合排序时记忆 score 权重 */
|
|
18
|
+
export declare const MEMORY_SCORE_WEIGHT = 0.4;
|
|
19
|
+
/** 一天对应的毫秒数 */
|
|
20
|
+
export declare const ONE_DAY_MS: number;
|
|
21
|
+
/**
|
|
22
|
+
* 从文本中提取关键词(用于记忆召回)
|
|
23
|
+
*
|
|
24
|
+
* 基于 segmentText() 精确分词,叠加停用词过滤 + 英文词补充 + 去重。
|
|
25
|
+
* 分词基础设施统一由 segmenter.ts 提供,避免重复实现。
|
|
26
|
+
*
|
|
27
|
+
* @param input - 输入文本
|
|
28
|
+
* @returns 关键词数组(去重 + 停用词过滤)
|
|
29
|
+
*/
|
|
30
|
+
export declare function extractKeywords(input: string): string[];
|
|
31
|
+
/**
|
|
32
|
+
* 召回选项
|
|
33
|
+
*/
|
|
34
|
+
export interface RecallOptions {
|
|
35
|
+
/** 返回数量上限(默认 5) */
|
|
36
|
+
limit?: number;
|
|
37
|
+
/** 排除的 source 标签(默认排除 persona 和 rule) */
|
|
38
|
+
excludeSources?: string[];
|
|
39
|
+
/** 向量存储(可选,提供时启用语义搜索) */
|
|
40
|
+
vectorStore?: VectorStore;
|
|
41
|
+
/** 语义搜索相似度阈值(默认 0.3) */
|
|
42
|
+
minSimilarity?: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 从记忆存储中搜索相关记忆
|
|
46
|
+
*
|
|
47
|
+
* 双通道召回策略:
|
|
48
|
+
* 1. 语义搜索(VectorStore 可用时):向量余弦相似度
|
|
49
|
+
* 2. 关键词搜索(兜底):LIKE 匹配
|
|
50
|
+
* 3. 两路结果合并去重,按 score + similarity 综合排序
|
|
51
|
+
* 4. 排除已单独注入的记忆(persona、rule)
|
|
52
|
+
* 5. 返回 top N
|
|
53
|
+
*
|
|
54
|
+
* @param storage - 记忆存储实例
|
|
55
|
+
* @param query - 搜索查询文本
|
|
56
|
+
* @param options - 召回选项
|
|
57
|
+
* @returns 匹配的记忆列表
|
|
58
|
+
*/
|
|
59
|
+
export declare function recall(storage: IMemoryStorage, query: string, options?: RecallOptions): Promise<Memory[]>;
|
|
60
|
+
/**
|
|
61
|
+
* 召回时提升记忆的 score(上限 1.0)
|
|
62
|
+
*
|
|
63
|
+
* 每次被召回时,记忆的 score 略微提升,体现"越常用越重要"。
|
|
64
|
+
*
|
|
65
|
+
* @param memory - 被召回的记忆
|
|
66
|
+
* @param now - 当前时间戳(ISO 8601)
|
|
67
|
+
*/
|
|
68
|
+
export declare function boostScore(memory: Memory, now?: string): void;
|
|
69
|
+
/**
|
|
70
|
+
* 对单条记忆执行衰减计算
|
|
71
|
+
*
|
|
72
|
+
* @param memory - 要衰减的记忆
|
|
73
|
+
* @param now - 当前时间(Date 对象)
|
|
74
|
+
* @returns 是否实际发生了衰减
|
|
75
|
+
*/
|
|
76
|
+
export declare function applyDecayToMemory(memory: Memory, now: Date): boolean;
|
|
77
|
+
//# sourceMappingURL=recall.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../src/memory/recall.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAU3D,2CAA2C;AAC3C,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,mBAAmB;AACnB,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC,uBAAuB;AACvB,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAiBvC,eAAe;AACf,eAAO,MAAM,UAAU,QAAsB,CAAC;AAE9C;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAUvD;AAID;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,yBAAyB;IACzB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,wBAAwB;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,MAAM,CAC1B,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,MAAM,EAAE,CAAC,CAoEnB;AAID;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAG7D;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAcrE"}
|