33 * Provides isolated test environments for integration testing
44 */
55
6- import { SQLiteAdapter , SQLiteConfig } from '../../../core/database/sqlite-adapter.js' ;
6+ import {
7+ SQLiteAdapter ,
8+ SQLiteConfig ,
9+ } from '../../../core/database/sqlite-adapter.js' ;
710import { FrameManager } from '../../../core/context/index.js' ;
8- import { SharedContextLayer } from '../../../core/context/shared-context-layer.js' ;
9- import { ContextBridge } from '../../../core/context/context-bridge.js' ;
11+ import {
12+ SharedContextLayer ,
13+ ContextBridge ,
14+ } from '../../../core/context/shared-context-layer.js' ;
1015import { ContextRetriever } from '../../../core/retrieval/context-retriever.js' ;
1116import { QueryRouter } from '../../../core/database/query-router.js' ;
1217import { execSync } from 'child_process' ;
@@ -19,7 +24,7 @@ export interface TestSession {
1924 sharedContext : SharedContextLayer ;
2025 contextBridge ?: ContextBridge ;
2126 retriever : ContextRetriever ;
22-
27+
2328 recordActivity ( activities : ActivityRecord [ ] ) : Promise < string [ ] > ;
2429 saveContext ( ) : Promise < SavedContext > ;
2530 generateHandoff ( ) : Promise < string > ;
@@ -50,10 +55,18 @@ export class TestEnvironment {
5055
5156 private constructor ( projectId : string ) {
5257 this . projectId = projectId ;
53- this . tempDir = path . join ( os . tmpdir ( ) , `stackmemory-test-${ Date . now ( ) } -${ Math . random ( ) . toString ( 36 ) . slice ( 2 ) } ` ) ;
54- this . dbPath = path . join ( this . tempDir , '.stackmemory' , 'db' , 'stackmemory.db' ) ;
58+ this . tempDir = path . join (
59+ os . tmpdir ( ) ,
60+ `stackmemory-test-${ Date . now ( ) } -${ Math . random ( ) . toString ( 36 ) . slice ( 2 ) } `
61+ ) ;
62+ this . dbPath = path . join (
63+ this . tempDir ,
64+ '.stackmemory' ,
65+ 'db' ,
66+ 'stackmemory.db'
67+ ) ;
5568 this . cliPath = path . join ( process . cwd ( ) , 'dist' , 'cli' , 'index.js' ) ;
56-
69+
5770 // Adapter will be created after directories are set up
5871 this . adapter = null as any ; // Will be initialized in setup()
5972 }
@@ -66,20 +79,26 @@ export class TestEnvironment {
6679
6780 private async setup ( ) : Promise < void > {
6881 // Create directory structure
69- fs . mkdirSync ( path . join ( this . tempDir , '.stackmemory' , 'db' ) , { recursive : true } ) ;
70- fs . mkdirSync ( path . join ( this . tempDir , '.stackmemory' , 'contexts' ) , { recursive : true } ) ;
71- fs . mkdirSync ( path . join ( this . tempDir , '.stackmemory' , 'handoffs' ) , { recursive : true } ) ;
72-
82+ fs . mkdirSync ( path . join ( this . tempDir , '.stackmemory' , 'db' ) , {
83+ recursive : true ,
84+ } ) ;
85+ fs . mkdirSync ( path . join ( this . tempDir , '.stackmemory' , 'contexts' ) , {
86+ recursive : true ,
87+ } ) ;
88+ fs . mkdirSync ( path . join ( this . tempDir , '.stackmemory' , 'handoffs' ) , {
89+ recursive : true ,
90+ } ) ;
91+
7392 // Create adapter with test configuration
7493 const config : SQLiteConfig = {
7594 dbPath : this . dbPath ,
7695 walMode : false , // Disable for testing
7796 busyTimeout : 5000 ,
7897 synchronous : 'NORMAL' ,
7998 } ;
80-
99+
81100 this . adapter = new SQLiteAdapter ( this . projectId , config ) ;
82-
101+
83102 // Initialize database
84103 await this . adapter . connect ( ) ;
85104 await this . adapter . initializeSchema ( ) ;
@@ -104,7 +123,7 @@ export class TestEnvironment {
104123 path : this . dbPath ,
105124 } ,
106125 } ;
107-
126+
108127 fs . writeFileSync (
109128 path . join ( this . tempDir , 'stackmemory.json' ) ,
110129 JSON . stringify ( config , null , 2 )
@@ -114,12 +133,18 @@ export class TestEnvironment {
114133 async createProject ( name : string ) : Promise < { id : string ; path : string } > {
115134 const projectPath = path . join ( this . tempDir , name ) ;
116135 fs . mkdirSync ( projectPath , { recursive : true } ) ;
117-
136+
118137 // Initialize git repo
119138 execSync ( 'git init' , { cwd : projectPath , stdio : 'pipe' } ) ;
120- execSync ( 'git config user.email "test@example.com"' , { cwd : projectPath , stdio : 'pipe' } ) ;
121- execSync ( 'git config user.name "Test User"' , { cwd : projectPath , stdio : 'pipe' } ) ;
122-
139+ execSync ( 'git config user.email "test@example.com"' , {
140+ cwd : projectPath ,
141+ stdio : 'pipe' ,
142+ } ) ;
143+ execSync ( 'git config user.name "Test User"' , {
144+ cwd : projectPath ,
145+ stdio : 'pipe' ,
146+ } ) ;
147+
123148 return {
124149 id : `${ this . projectId } -${ name } ` ,
125150 path : projectPath ,
@@ -128,7 +153,7 @@ export class TestEnvironment {
128153
129154 async startSession ( sessionId ?: string ) : Promise < TestSession > {
130155 const id = sessionId || `session-${ Date . now ( ) } ` ;
131-
156+
132157 // Create FrameManager without auto-initialization
133158 const frameManager = Object . create ( FrameManager . prototype ) ;
134159 Object . assign ( frameManager , {
@@ -141,94 +166,97 @@ export class TestEnvironment {
141166 maxDepth : 10 ,
142167 } ,
143168 } ) ;
144-
169+
145170 const sharedContext = new SharedContextLayer ( {
146171 projectId : this . projectId ,
147172 maxSharedFrames : 100 ,
148173 syncInterval : 1000 ,
149174 } ) ;
150-
175+
151176 const retriever = new ContextRetriever ( this . adapter ) ;
152-
177+
153178 const session : TestSession = {
154179 frameManager,
155180 sharedContext,
156181 retriever,
157-
182+
158183 recordActivity : async ( activities : ActivityRecord [ ] ) => {
159184 const frameIds : string [ ] = [ ] ;
160-
185+
161186 for ( const activity of activities ) {
162187 const frameId = await this . adapter . createFrame ( {
163188 parent_frame_id : frameIds [ frameIds . length - 1 ] || null ,
164189 project_id : this . projectId ,
165190 run_id : id ,
166191 type : activity . type === 'error' ? 'error' : 'operation' ,
167192 name : this . getActivityName ( activity ) ,
168- state : activity . type === 'error' || activity . status === 'fail' ? 'error' : 'completed' ,
193+ state :
194+ activity . type === 'error' || activity . status === 'fail'
195+ ? 'error'
196+ : 'completed' ,
169197 depth : frameIds . length ,
170198 digest_text : this . getActivityDigest ( activity ) ,
171199 } ) ;
172-
200+
173201 frameIds . push ( frameId ) ;
174202 }
175-
203+
176204 return frameIds ;
177205 } ,
178-
206+
179207 saveContext : async ( ) => {
180208 const frames = await this . adapter . search ( {
181209 query : '' ,
182210 searchType : 'recent' ,
183211 limit : 100 ,
184212 } ) ;
185-
213+
186214 const context : SavedContext = {
187215 frames,
188216 timestamp : Date . now ( ) ,
189217 sessionId : id ,
190218 } ;
191-
219+
192220 // Save to file for persistence testing
193221 fs . writeFileSync (
194222 path . join ( this . tempDir , '.stackmemory' , 'contexts' , `${ id } .json` ) ,
195223 JSON . stringify ( context , null , 2 )
196224 ) ;
197-
225+
198226 return context ;
199227 } ,
200-
228+
201229 generateHandoff : async ( ) => {
202230 const frames = await this . adapter . search ( {
203231 query : '' ,
204232 searchType : 'recent' ,
205233 limit : 50 ,
206234 } ) ;
207-
235+
208236 let handoff = '# Session Handoff\n\n' ;
209237 handoff += '## Session Summary\n\n' ;
210238 handoff += `- Session ID: ${ id } \n` ;
211239 handoff += `- Total Frames: ${ frames . length } \n` ;
212240 handoff += `- Timestamp: ${ new Date ( ) . toISOString ( ) } \n\n` ;
213-
241+
214242 handoff += '## Activity Log\n\n' ;
215243 for ( const frame of frames ) {
216244 handoff += `- [${ frame . type } ] ${ frame . name } \n` ;
217245 if ( frame . digest_text ) {
218246 handoff += ` ${ frame . digest_text } \n` ;
219247 }
220248 }
221-
249+
222250 // Save handoff
223251 fs . writeFileSync (
224252 path . join ( this . tempDir , '.stackmemory' , 'handoffs' , `${ id } .md` ) ,
225253 handoff
226254 ) ;
227-
255+
228256 return handoff ;
229257 } ,
230258 } ;
231-
259+
232260 this . sessions . set ( id , session ) ;
233261 return session ;
234262 }
@@ -241,27 +269,39 @@ export class TestEnvironment {
241269 if ( ( session . frameManager as any ) . frames ) {
242270 ( session . frameManager as any ) . frames . clear ( ) ;
243271 }
244-
272+
245273 // SharedContextLayer doesn't have a clear method, so we just reset the sessions
246274 // The context is persisted in files/database anyway
247275 }
248276 }
249277
250278 async restoreContext ( sessionId ?: string ) : Promise < SavedContext > {
251- const contextFiles = fs . readdirSync ( path . join ( this . tempDir , '.stackmemory' , 'contexts' ) ) ;
252-
279+ const contextFiles = fs . readdirSync (
280+ path . join ( this . tempDir , '.stackmemory' , 'contexts' )
281+ ) ;
282+
253283 if ( sessionId ) {
254- const contextPath = path . join ( this . tempDir , '.stackmemory' , 'contexts' , `${ sessionId } .json` ) ;
284+ const contextPath = path . join (
285+ this . tempDir ,
286+ '.stackmemory' ,
287+ 'contexts' ,
288+ `${ sessionId } .json`
289+ ) ;
255290 return JSON . parse ( fs . readFileSync ( contextPath , 'utf8' ) ) ;
256291 }
257-
292+
258293 // Return most recent context
259294 if ( contextFiles . length > 0 ) {
260295 const latestFile = contextFiles . sort ( ) . pop ( ) ! ;
261- const contextPath = path . join ( this . tempDir , '.stackmemory' , 'contexts' , latestFile ) ;
296+ const contextPath = path . join (
297+ this . tempDir ,
298+ '.stackmemory' ,
299+ 'contexts' ,
300+ latestFile
301+ ) ;
262302 return JSON . parse ( fs . readFileSync ( contextPath , 'utf8' ) ) ;
263303 }
264-
304+
265305 return {
266306 frames : [ ] ,
267307 timestamp : Date . now ( ) ,
@@ -280,7 +320,9 @@ export class TestEnvironment {
280320 } ,
281321 } ) ;
282322 } catch ( error : any ) {
283- throw new Error ( `CLI command failed: ${ error . message } \nOutput: ${ error . stdout || error . stderr } ` ) ;
323+ throw new Error (
324+ `CLI command failed: ${ error . message } \nOutput: ${ error . stdout || error . stderr } `
325+ ) ;
284326 }
285327 }
286328
@@ -290,7 +332,7 @@ export class TestEnvironment {
290332
291333 async createQueryRouter ( ) : Promise < QueryRouter > {
292334 const router = new QueryRouter ( ) ;
293-
335+
294336 router . registerTier ( {
295337 name : 'sqlite' ,
296338 adapter : this . adapter ,
@@ -302,7 +344,7 @@ export class TestEnvironment {
302344 routingRules : [ ] ,
303345 } ,
304346 } ) ;
305-
347+
306348 return router ;
307349 }
308350
@@ -313,12 +355,12 @@ export class TestEnvironment {
313355 session . contextBridge . stop ( ) ;
314356 }
315357 }
316-
358+
317359 // Disconnect database
318360 if ( this . adapter ) {
319361 await this . adapter . disconnect ( ) ;
320362 }
321-
363+
322364 // Remove temp directory
323365 if ( fs . existsSync ( this . tempDir ) ) {
324366 fs . rmSync ( this . tempDir , { recursive : true , force : true } ) ;
@@ -362,4 +404,4 @@ export class TestEnvironment {
362404 return '' ;
363405 }
364406 }
365- }
407+ }
0 commit comments