@@ -20,6 +20,7 @@ import { GitWorkflowService } from "../../../git/GitWorkflowService.ts";
2020import * as BootstrapTurnStartDispatcher from "../../../orchestration/Services/BootstrapTurnStartDispatcher.ts" ;
2121import { OrchestrationEngineService } from "../../../orchestration/Services/OrchestrationEngine.ts" ;
2222import { ProjectionSnapshotQuery } from "../../../orchestration/Services/ProjectionSnapshotQuery.ts" ;
23+ import * as ServerRuntimeStartup from "../../../serverRuntimeStartup.ts" ;
2324import * as McpInvocationContext from "../../McpInvocationContext.ts" ;
2425import { ThreadToolkitRegistrationLive } from "../../McpHttpServer.ts" ;
2526import { ThreadStartRuntimeLive } from "./handlers.ts" ;
@@ -90,14 +91,26 @@ const TestCryptoLive = Layer.sync(Crypto.Crypto, () => {
9091 } ) ;
9192} ) ;
9293
93- const makeTestLayer = ( commands : OrchestrationCommand [ ] ) => {
94+ const makeTestLayer = (
95+ commands : OrchestrationCommand [ ] ,
96+ options : { readonly enqueueCalls ?: number [ ] } = { } ,
97+ ) => {
9498 const bootstrapTurnStartDispatcherLayer = Layer . mock (
9599 BootstrapTurnStartDispatcher . BootstrapTurnStartDispatcher ,
96100 ) ( {
97101 dispatch : ( command ) =>
98102 Effect . sync ( ( ) => {
99103 commands . push ( command ) ;
100- return { sequence : 1 } ;
104+ return {
105+ sequence : 1 ,
106+ branch :
107+ command . bootstrap ?. prepareWorktree ?. branch ??
108+ command . bootstrap ?. createThread ?. branch ??
109+ null ,
110+ worktreePath : command . bootstrap ?. prepareWorktree
111+ ? "/repo/.worktrees/generated"
112+ : ( command . bootstrap ?. createThread ?. worktreePath ?? null ) ,
113+ } ;
101114 } ) ,
102115 } ) ;
103116
@@ -161,10 +174,24 @@ const makeTestLayer = (commands: OrchestrationCommand[]) => {
161174 streamDomainEvents : Stream . empty ,
162175 } ) ,
163176 ) ,
177+ Layer . provide (
178+ Layer . mock ( ServerRuntimeStartup . ServerRuntimeStartup ) ( {
179+ awaitCommandReady : Effect . void ,
180+ markHttpListening : Effect . void ,
181+ enqueueCommand : ( effect ) =>
182+ Effect . sync ( ( ) => {
183+ options . enqueueCalls ?. push ( 1 ) ;
184+ } ) . pipe ( Effect . flatMap ( ( ) => effect ) ) ,
185+ } ) ,
186+ ) ,
164187 ) ;
165188} ;
166189
167- const callStartTool = ( arguments_ : Record < string , unknown > , commands : OrchestrationCommand [ ] ) =>
190+ const callStartTool = (
191+ arguments_ : Record < string , unknown > ,
192+ commands : OrchestrationCommand [ ] ,
193+ options : { readonly enqueueCalls ?: number [ ] } = { } ,
194+ ) =>
168195 Effect . gen ( function * ( ) {
169196 const server = yield * McpServer . McpServer ;
170197 return yield * server
@@ -173,7 +200,7 @@ const callStartTool = (arguments_: Record<string, unknown>, commands: Orchestrat
173200 Effect . provideService ( McpInvocationContext . McpInvocationContext , invocation ) ,
174201 Effect . provideService ( McpSchema . McpServerClient , client ) ,
175202 ) ;
176- } ) . pipe ( Effect . provide ( makeTestLayer ( commands ) ) ) ;
203+ } ) . pipe ( Effect . provide ( makeTestLayer ( commands , options ) ) ) ;
177204
178205it . effect ( "starts a new worktree thread by default and inherits source settings" , ( ) =>
179206 Effect . gen ( function * ( ) {
@@ -184,7 +211,7 @@ it.effect("starts a new worktree thread by default and inherits source settings"
184211 expect ( result . structuredContent ) . toMatchObject ( {
185212 projectId,
186213 mode : "new_worktree" ,
187- worktreePath : null ,
214+ worktreePath : "/repo/.worktrees/generated" ,
188215 } ) ;
189216 const command = commands [ 0 ] ;
190217 expect ( command ?. type ) . toBe ( "thread.turn.start" ) ;
@@ -202,6 +229,46 @@ it.effect("starts a new worktree thread by default and inherits source settings"
202229 } ) ,
203230) ;
204231
232+ it . effect ( "queues thread starts through server runtime startup" , ( ) =>
233+ Effect . gen ( function * ( ) {
234+ const commands : OrchestrationCommand [ ] = [ ] ;
235+ const enqueueCalls : number [ ] = [ ] ;
236+ const result = yield * callStartTool ( { prompt : "Wait for server readiness" } , commands , {
237+ enqueueCalls,
238+ } ) ;
239+
240+ expect ( result . isError ) . toBe ( false ) ;
241+ expect ( enqueueCalls ) . toHaveLength ( 1 ) ;
242+ expect ( commands ) . toHaveLength ( 1 ) ;
243+ } ) ,
244+ ) ;
245+
246+ it . effect ( "passes explicit setup script requests for existing worktrees" , ( ) =>
247+ Effect . gen ( function * ( ) {
248+ const commands : OrchestrationCommand [ ] = [ ] ;
249+ const result = yield * callStartTool (
250+ {
251+ prompt : "Use existing checkout" ,
252+ mode : "existing_worktree" ,
253+ worktreePath : "/repo/existing" ,
254+ runSetupScript : true ,
255+ } ,
256+ commands ,
257+ ) ;
258+
259+ expect ( result . isError ) . toBe ( false ) ;
260+ expect ( result . structuredContent ) . toMatchObject ( {
261+ mode : "existing_worktree" ,
262+ worktreePath : "/repo/existing" ,
263+ } ) ;
264+ const command = commands [ 0 ] ;
265+ expect ( command ?. type ) . toBe ( "thread.turn.start" ) ;
266+ if ( command ?. type !== "thread.turn.start" ) return ;
267+ expect ( command . bootstrap ?. prepareWorktree ) . toBeUndefined ( ) ;
268+ expect ( command . bootstrap ?. runSetupScript ) . toBe ( true ) ;
269+ } ) ,
270+ ) ;
271+
205272it . effect ( "starts current-checkout threads with warning metadata" , ( ) =>
206273 Effect . gen ( function * ( ) {
207274 const commands : OrchestrationCommand [ ] = [ ] ;
0 commit comments