mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-10 02:24:35 +08:00
feat(issue-plan): enhance conflict detection and resolution process with semantic grouping and user clarifications
This commit is contained in:
179
ccw/tests/core-memory-store.test.ts
Normal file
179
ccw/tests/core-memory-store.test.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* Unit tests for CoreMemoryStore (core memory persistence + clustering helpers).
|
||||
*
|
||||
* Notes:
|
||||
* - Targets the runtime implementation shipped in `ccw/dist`.
|
||||
* - Uses a real temporary CCW data directory to avoid touching user state.
|
||||
* - Exercises SQLite-backed CRUD behavior (better-sqlite3) in an isolated temp dir.
|
||||
*/
|
||||
|
||||
import { after, afterEach, before, beforeEach, describe, it, mock } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { existsSync, mkdtempSync, mkdirSync, rmSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
|
||||
const TEST_CCW_HOME = mkdtempSync(join(tmpdir(), 'ccw-core-memory-store-home-'));
|
||||
const TEST_PROJECT_ROOT = mkdtempSync(join(tmpdir(), 'ccw-core-memory-store-project-'));
|
||||
|
||||
const coreMemoryStoreUrl = new URL('../dist/core/core-memory-store.js', import.meta.url);
|
||||
coreMemoryStoreUrl.searchParams.set('t', String(Date.now()));
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let mod: any;
|
||||
|
||||
const originalEnv = { CCW_DATA_DIR: process.env.CCW_DATA_DIR };
|
||||
|
||||
function resetDir(dirPath: string): void {
|
||||
if (existsSync(dirPath)) {
|
||||
rmSync(dirPath, { recursive: true, force: true });
|
||||
}
|
||||
mkdirSync(dirPath, { recursive: true });
|
||||
}
|
||||
|
||||
describe('CoreMemoryStore', async () => {
|
||||
before(async () => {
|
||||
process.env.CCW_DATA_DIR = TEST_CCW_HOME;
|
||||
mod = await import(coreMemoryStoreUrl.href);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
process.env.CCW_DATA_DIR = TEST_CCW_HOME;
|
||||
mock.method(console, 'warn', () => {});
|
||||
|
||||
try {
|
||||
mod?.closeAllStores?.();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
resetDir(TEST_CCW_HOME);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mock.restoreAll();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
try {
|
||||
mod?.closeAllStores?.();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
process.env.CCW_DATA_DIR = originalEnv.CCW_DATA_DIR;
|
||||
rmSync(TEST_CCW_HOME, { recursive: true, force: true });
|
||||
rmSync(TEST_PROJECT_ROOT, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('upserts, lists, archives, and deletes memories', () => {
|
||||
const store = mod.getCoreMemoryStore(TEST_PROJECT_ROOT);
|
||||
|
||||
const created = store.upsertMemory({
|
||||
id: 'CMEM-TEST-1',
|
||||
content: 'Hello world',
|
||||
summary: 'Greeting',
|
||||
});
|
||||
assert.equal(created.id, 'CMEM-TEST-1');
|
||||
assert.equal(created.content, 'Hello world');
|
||||
assert.equal(created.archived, false);
|
||||
|
||||
const fetched = store.getMemory('CMEM-TEST-1');
|
||||
assert.ok(fetched);
|
||||
assert.equal(fetched?.summary, 'Greeting');
|
||||
|
||||
// Default listing excludes archived
|
||||
const active = store.getMemories({ limit: 10 });
|
||||
assert.equal(active.length, 1);
|
||||
assert.equal(active[0].id, 'CMEM-TEST-1');
|
||||
|
||||
// Update existing record (including archived flag)
|
||||
const updated = store.upsertMemory({
|
||||
id: 'CMEM-TEST-1',
|
||||
content: 'Hello updated',
|
||||
archived: true,
|
||||
metadata: JSON.stringify({ source: 'test' }),
|
||||
});
|
||||
assert.equal(updated.content, 'Hello updated');
|
||||
assert.equal(updated.archived, true);
|
||||
assert.equal(updated.metadata, JSON.stringify({ source: 'test' }));
|
||||
|
||||
assert.equal(store.getMemories({ limit: 10 }).length, 0);
|
||||
assert.equal(store.getMemories({ archived: true, limit: 10 }).length, 1);
|
||||
|
||||
// Delete should remove the record (no throw for missing ids)
|
||||
store.deleteMemory('CMEM-TEST-1');
|
||||
assert.equal(store.getMemory('CMEM-TEST-1'), null);
|
||||
store.deleteMemory('CMEM-TEST-1');
|
||||
});
|
||||
|
||||
it('lists projects with memory/cluster counts', () => {
|
||||
const store = mod.getCoreMemoryStore(TEST_PROJECT_ROOT);
|
||||
store.upsertMemory({ id: 'CMEM-TEST-2', content: 'Project memory' });
|
||||
|
||||
const cluster = store.createCluster({ name: 'Cluster A' });
|
||||
assert.ok(cluster);
|
||||
|
||||
const projects = mod.listAllProjects();
|
||||
assert.equal(projects.length, 1);
|
||||
assert.equal(projects[0].memoriesCount, 1);
|
||||
assert.equal(projects[0].clustersCount, 1);
|
||||
assert.ok(typeof projects[0].id === 'string' && projects[0].id.length > 0);
|
||||
});
|
||||
|
||||
it('manages cluster membership and session metadata cache', () => {
|
||||
const store = mod.getCoreMemoryStore(TEST_PROJECT_ROOT);
|
||||
|
||||
const meta1 = store.upsertSessionMetadata({
|
||||
session_id: 'WFS-TEST-1',
|
||||
session_type: 'workflow',
|
||||
title: 'Auth flow',
|
||||
summary: 'JWT + refresh',
|
||||
keywords: ['auth', 'jwt'],
|
||||
token_estimate: 42,
|
||||
file_patterns: ['src/auth/**'],
|
||||
});
|
||||
assert.ok(meta1);
|
||||
assert.equal(meta1?.access_count, 1);
|
||||
|
||||
const meta2 = store.upsertSessionMetadata({
|
||||
session_id: 'WFS-TEST-1',
|
||||
session_type: 'workflow',
|
||||
title: 'Auth flow (updated)',
|
||||
keywords: ['auth', 'jwt', 'refresh'],
|
||||
});
|
||||
assert.ok(meta2);
|
||||
assert.equal(meta2?.access_count, 2);
|
||||
|
||||
const matches = store.searchSessionsByKeyword('auth');
|
||||
assert.equal(matches.length, 1);
|
||||
assert.equal(matches[0].session_id, 'WFS-TEST-1');
|
||||
|
||||
const cluster = store.createCluster({ name: 'Cluster B', description: 'Testing clusters' });
|
||||
assert.ok(cluster);
|
||||
|
||||
store.addClusterMember({
|
||||
cluster_id: cluster.id,
|
||||
session_id: 'WFS-TEST-1',
|
||||
session_type: 'workflow',
|
||||
sequence_order: 1,
|
||||
relevance_score: 1.0,
|
||||
});
|
||||
|
||||
const sessionClusters = store.getSessionClusters('WFS-TEST-1');
|
||||
assert.equal(sessionClusters.length, 1);
|
||||
assert.equal(sessionClusters[0].id, cluster.id);
|
||||
|
||||
assert.equal(store.removeClusterMember(cluster.id, 'WFS-TEST-1'), true);
|
||||
assert.equal(store.getSessionClusters('WFS-TEST-1').length, 0);
|
||||
});
|
||||
|
||||
it('throws clear errors for invalid cross-project access', () => {
|
||||
assert.throws(
|
||||
() => mod.getMemoriesFromProject('missing-project-id'),
|
||||
(err: any) => err instanceof Error && err.message.includes('Project not found'),
|
||||
);
|
||||
|
||||
assert.equal(mod.findMemoryAcrossProjects('CMEM-NOT-THERE'), null);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user