d9e966d8f4
* fix: make migration 17 idempotent and standardize column names Migration 17 renamed columns from sdk_session_id to memory_session_id, but the migration wasn't fully idempotent - it could fail on databases in intermediate states. This caused errors like: - "no such column: sdk_session_id" (when columns already renamed) - "table observations has no column named memory_session_id" (when not renamed) Changes: - Rewrite renameSessionIdColumns() to check each table individually - Use safeRenameColumn() helper that handles all edge cases gracefully - Deprecate migration 19 (repair migration) since 17 is now idempotent - Update maintenance scripts to use memory_session_id column name - Update test files to use new column names Fixes column mismatch bug in v8.2.6+ * Merge origin/main into column-mismatch --------- Co-authored-by: Alex Newman <thedotmack@gmail.com>
107 lines
3.1 KiB
TypeScript
107 lines
3.1 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
|
|
import { SessionStore } from '../src/services/sqlite/SessionStore.js';
|
|
|
|
describe('SessionStore', () => {
|
|
let store: SessionStore;
|
|
|
|
beforeEach(() => {
|
|
store = new SessionStore(':memory:');
|
|
});
|
|
|
|
afterEach(() => {
|
|
store.close();
|
|
});
|
|
|
|
it('should correctly count user prompts', () => {
|
|
const claudeId = 'claude-session-1';
|
|
store.createSDKSession(claudeId, 'test-project', 'initial prompt');
|
|
|
|
// Should be 0 initially
|
|
expect(store.getPromptNumberFromUserPrompts(claudeId)).toBe(0);
|
|
|
|
// Save prompt 1
|
|
store.saveUserPrompt(claudeId, 1, 'First prompt');
|
|
expect(store.getPromptNumberFromUserPrompts(claudeId)).toBe(1);
|
|
|
|
// Save prompt 2
|
|
store.saveUserPrompt(claudeId, 2, 'Second prompt');
|
|
expect(store.getPromptNumberFromUserPrompts(claudeId)).toBe(2);
|
|
|
|
// Save prompt for another session
|
|
store.createSDKSession('claude-session-2', 'test-project', 'initial prompt');
|
|
store.saveUserPrompt('claude-session-2', 1, 'Other prompt');
|
|
expect(store.getPromptNumberFromUserPrompts(claudeId)).toBe(2);
|
|
});
|
|
|
|
it('should store observation with timestamp override', () => {
|
|
const claudeId = 'claude-sess-obs';
|
|
const sdkId = store.createSDKSession(claudeId, 'test-project', 'initial prompt');
|
|
|
|
// Get the memory_session_id string (createSDKSession returns number ID, need string for FK)
|
|
// createSDKSession inserts using memory_session_id = content_session_id in the current implementation
|
|
// "VALUES (?, ?, ?, ?, ?, ?, 'active')" -> contentSessionId, contentSessionId, ...
|
|
|
|
const obs = {
|
|
type: 'discovery',
|
|
title: 'Test Obs',
|
|
subtitle: null,
|
|
facts: [],
|
|
narrative: 'Testing',
|
|
concepts: [],
|
|
files_read: [],
|
|
files_modified: []
|
|
};
|
|
|
|
const pastTimestamp = 1600000000000; // Some time in the past
|
|
|
|
const result = store.storeObservation(
|
|
claudeId, // sdkSessionId is same as claudeSessionId in createSDKSession
|
|
'test-project',
|
|
obs,
|
|
1,
|
|
0,
|
|
pastTimestamp
|
|
);
|
|
|
|
expect(result.createdAtEpoch).toBe(pastTimestamp);
|
|
|
|
const stored = store.getObservationById(result.id);
|
|
expect(stored).not.toBeNull();
|
|
expect(stored?.created_at_epoch).toBe(pastTimestamp);
|
|
|
|
// Verify ISO string matches
|
|
expect(new Date(stored!.created_at).getTime()).toBe(pastTimestamp);
|
|
});
|
|
|
|
it('should store summary with timestamp override', () => {
|
|
const claudeId = 'claude-sess-sum';
|
|
store.createSDKSession(claudeId, 'test-project', 'initial prompt');
|
|
|
|
const summary = {
|
|
request: 'Do something',
|
|
investigated: 'Stuff',
|
|
learned: 'Things',
|
|
completed: 'Done',
|
|
next_steps: 'More',
|
|
notes: null
|
|
};
|
|
|
|
const pastTimestamp = 1650000000000;
|
|
|
|
const result = store.storeSummary(
|
|
claudeId,
|
|
'test-project',
|
|
summary,
|
|
1,
|
|
0,
|
|
pastTimestamp
|
|
);
|
|
|
|
expect(result.createdAtEpoch).toBe(pastTimestamp);
|
|
|
|
const stored = store.getSummaryForSession(claudeId);
|
|
expect(stored).not.toBeNull();
|
|
expect(stored?.created_at_epoch).toBe(pastTimestamp);
|
|
});
|
|
});
|