Skip to content

Commit 3e27146

Browse files
committed
refactor: unify hub access via MemoryHubDatabase.getDefault() in application layer
- Add MemoryHubDatabase.getDefault() factory that respects test override - Add MemoryHubDatabase.setTestOverride() synced from MemoryStore.setSharedHubForTests - getDefault() creates a new connection to the same path (safe to close per-consumer) - Replace direct new MemoryHubDatabase() in application and monitoring layers - Eliminates the bypass path that caused ghost project leaks in tests
1 parent 9353d95 commit 3e27146

6 files changed

Lines changed: 40 additions & 10 deletions

File tree

src/application/memory/executeAutoRecord.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ function resolveProjectRoot(projectId?: string): string {
4242
return path.resolve(projectId);
4343
}
4444

45-
const db = new MemoryHubDatabase();
45+
const db = MemoryHubDatabase.getDefault();
4646
try {
4747
const project = db.getProject(projectId);
4848
if (!project?.path) {

src/application/memory/executeMemoryHub.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export async function executeQuerySharedMemories(
105105
'MCP query_shared_memories 调用开始',
106106
);
107107

108-
const db = new MemoryHubDatabase();
108+
const db = MemoryHubDatabase.getDefault();
109109

110110
try {
111111
const normalizedQueryText = buildFtsPrefixQuery(effectiveQuery);
@@ -215,7 +215,7 @@ export async function executeLinkMemories(args: LinkMemoriesInput): Promise<Memo
215215

216216
logger.info({ from, to, type }, 'MCP link_memories 调用开始');
217217

218-
const db = new MemoryHubDatabase();
218+
const db = MemoryHubDatabase.getDefault();
219219

220220
try {
221221
const fromMemory = db.getMemory(from.project, from.module);
@@ -266,7 +266,7 @@ export async function executeGetDependencyChain(
266266

267267
logger.info({ project, module, recursive }, 'MCP get_dependency_chain 调用开始');
268268

269-
const db = new MemoryHubDatabase();
269+
const db = MemoryHubDatabase.getDefault();
270270

271271
try {
272272
const memory = db.getMemory(project, module);
@@ -359,7 +359,7 @@ export async function executeGetDependencyChain(
359359
}
360360

361361
export async function executeManageProjects(args: ManageProjectsInput): Promise<MemoryToolResponse> {
362-
const db = new MemoryHubDatabase();
362+
const db = MemoryHubDatabase.getDefault();
363363

364364
try {
365365
switch (args.action) {

src/memory/MemoryHubDatabase.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,33 @@ const REPAIR_PLACEHOLDER_PREFIX = '__cw_repair__';
151151
export class MemoryHubDatabase {
152152
private db: Database.Database;
153153

154+
/**
155+
* 测试覆盖实例 — 由 MemoryStore.setSharedHubForTests 同步设置
156+
*
157+
* 应用层通过 getDefault() 获取 hub 时会自动使用此覆盖实例,
158+
* 从而确保测试隔离不需要在每个应用函数中单独处理。
159+
*/
160+
private static testOverride: MemoryHubDatabase | null = null;
161+
162+
/** 设置测试覆盖(由 MemoryStore.setSharedHubForTests 调用) */
163+
static setTestOverride(hub: MemoryHubDatabase | null): void {
164+
MemoryHubDatabase.testOverride = hub;
165+
}
166+
167+
/**
168+
* 获取默认 hub 实例。
169+
*
170+
* 在测试环境下,使用测试覆盖实例的路径创建新连接(而非返回同一实例),
171+
* 确保消费者可以安全地 close() 自己的连接而不影响其他调用方。
172+
* 在生产环境下,等价于 `new MemoryHubDatabase()`。
173+
*/
174+
static getDefault(): MemoryHubDatabase {
175+
if (MemoryHubDatabase.testOverride) {
176+
return new MemoryHubDatabase(MemoryHubDatabase.testOverride.dbPath);
177+
}
178+
return new MemoryHubDatabase();
179+
}
180+
154181
constructor(dbPath?: string) {
155182
this.dbPath = dbPath || resolveDefaultHubPath();
156183
fs.mkdirSync(path.dirname(this.dbPath), { recursive: true });
@@ -159,7 +186,8 @@ export class MemoryHubDatabase {
159186
this.initializeSchema();
160187
}
161188

162-
private dbPath: string;
189+
/** 数据库文件路径(getDefault() 需读取以创建同路径新连接) */
190+
readonly dbPath: string;
163191

164192
/**
165193
* 初始化数据库 schema

src/memory/MemoryStore.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ export class MemoryStore {
4242

4343
static setSharedHubForTests(hub: MemoryHubDatabase | null): void {
4444
MemoryStore.sharedHub = hub;
45+
MemoryHubDatabase.setTestOverride(hub);
4546
}
4647

4748
static resetSharedHubForTests(): void {
4849
MemoryStore.sharedHub = null;
50+
MemoryHubDatabase.setTestOverride(null);
4951
}
5052

5153
private readonly projectRoot: string;

src/monitoring/memoryHealth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ function buildOverallAssessment(report: MemoryHealthReport): void {
305305
export async function analyzeMemoryHealth(
306306
options: { projectRoots?: string[]; staleDays?: number; excludeGhostProjects?: boolean } = {},
307307
): Promise<MemoryHealthReport> {
308-
const hub = new MemoryHubDatabase();
308+
const hub = MemoryHubDatabase.getDefault();
309309
try {
310310
const allowedProjectRoots = options.projectRoots?.length
311311
? new Set(options.projectRoots.map((projectRoot) => path.resolve(projectRoot)))

src/monitoring/opsMetrics.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ function parseFeedbackOutcome(summary: string): string | null {
148148
async function collectProjectStaleRates(
149149
staleDays?: number,
150150
): Promise<Map<string, { projectName: string; staleMemoryRate: number; correctionRate: number }>> {
151-
const hub = new MemoryHubDatabase();
151+
const hub = MemoryHubDatabase.getDefault();
152152
try {
153153
const projects = hub.listProjects();
154154
const result = new Map<
@@ -207,7 +207,7 @@ async function collectProjectStaleRates(
207207
async function collectModuleQualityDistribution(
208208
staleDays?: number,
209209
): Promise<OpsMetricsReport['moduleQualityDistribution']> {
210-
const hub = new MemoryHubDatabase();
210+
const hub = MemoryHubDatabase.getDefault();
211211
try {
212212
const projects = hub.listProjects();
213213
const result: OpsMetricsReport['moduleQualityDistribution'] = [];
@@ -285,7 +285,7 @@ async function collectGovernanceSummary(
285285
},
286286
};
287287

288-
const hub = new MemoryHubDatabase();
288+
const hub = MemoryHubDatabase.getDefault();
289289
try {
290290
const projects = hub.listProjects();
291291
for (const project of projects) {

0 commit comments

Comments
 (0)