@@ -7,6 +7,11 @@ let createPromptSubmit: typeof import("./submit").createPromptSubmit
77
88const createdClients : string [ ] = [ ]
99const createdSessions : string [ ] = [ ]
10+ const sessionCreateInputs : Array < {
11+ agent ?: string
12+ model ?: { id : string ; providerID : string ; variant ?: string }
13+ location ?: { directory : string }
14+ } > = [ ]
1015const enabledAutoAccept : Array < { server : string ; sessionID : string ; directory : string } > = [ ]
1116const optimistic : Array < {
1217 directory ?: string
@@ -19,11 +24,15 @@ const optimistic: Array<{
1924} > = [ ]
2025const optimisticSeeded : boolean [ ] = [ ]
2126const storedSessions : Record < string , Array < { id : string ; title ?: string } > > = { }
22- const sessionDirectories : Record < string , string > = { }
2327const promoted : Array < { directory : string ; sessionID : string } > = [ ]
24- const sentShell : string [ ] = [ ]
28+ const sentShell : Array < { sessionID : string ; id ?: string ; command : string } > = [ ]
2529const syncedDirectories : string [ ] = [ ]
2630const promotedDrafts : Array < { draftID : string ; server : string ; sessionId : string } > = [ ]
31+ const sentPrompts : string [ ] = [ ]
32+ const promptInputs : unknown [ ] = [ ]
33+ const sentCommands : unknown [ ] = [ ]
34+ const commands : Array < { name : string } > = [ ]
35+ let serverSessionSyncs = 0
2736
2837let params : { id ?: string } = { }
2938let search : { draftId ?: string } = { }
@@ -32,7 +41,7 @@ let variant: string | undefined
3241let permissionServer = "server-a"
3342let createSessionGate : Promise < void > | undefined
3443
35- const promptValue : Prompt = [ { type : "text" , content : "ls" , start : 0 , end : 2 } ]
44+ let promptValue : Prompt = [ { type : "text" , content : "ls" , start : 0 , end : 2 } ]
3645const [ promptStore , setPromptStore ] = createStore < PromptStore > ( {
3746 prompt : promptValue ,
3847 cursor : 0 ,
@@ -64,23 +73,39 @@ const prompt = {
6473const clientFor = ( directory : string ) => {
6574 createdClients . push ( directory )
6675 return {
67- session : {
68- create : async ( ) => {
69- await createSessionGate
70- createdSessions . push ( directory )
71- return {
72- data : {
76+ api : {
77+ session : {
78+ create : async ( input : ( typeof sessionCreateInputs ) [ number ] ) => {
79+ await createSessionGate
80+ const location = input . location ?. directory ?? directory
81+ createdSessions . push ( location )
82+ sessionCreateInputs . push ( input )
83+ return {
7384 id : `session-${ createdSessions . length } ` ,
85+ projectID : "project" ,
86+ agent : input . agent ,
87+ model : input . model ,
88+ cost : 0 ,
89+ tokens : { input : 0 , output : 0 , reasoning : 0 , cache : { read : 0 , write : 0 } } ,
90+ time : { created : 1 , updated : 1 } ,
7491 title : `New session ${ createdSessions . length } ` ,
75- } ,
76- }
77- } ,
78- shell : async ( ) => {
79- sentShell . push ( directory )
80- return { data : undefined }
92+ location : { directory : location } ,
93+ }
94+ } ,
95+ prompt : async ( input : unknown ) => {
96+ sentPrompts . push ( directory )
97+ promptInputs . push ( input )
98+ return { data : undefined }
99+ } ,
100+ command : async ( input : unknown ) => {
101+ sentCommands . push ( input )
102+ } ,
103+ shell : async ( input : { sessionID : string ; id ?: string ; command : string } ) => {
104+ sentShell . push ( input )
105+ } ,
81106 } ,
82- prompt : async ( ) => ( { data : undefined } ) ,
83- promptAsync : async ( ) => ( { data : undefined } ) ,
107+ } ,
108+ session : {
84109 command : async ( ) => ( { data : undefined } ) ,
85110 abort : async ( ) => ( { data : undefined } ) ,
86111 } ,
@@ -90,27 +115,6 @@ const clientFor = (directory: string) => {
90115 }
91116}
92117
93- const api = {
94- session : {
95- async create ( input : { location : { directory : string } } ) {
96- await createSessionGate
97- createdSessions . push ( input . location . directory )
98- const session = {
99- id : `session-${ createdSessions . length } ` ,
100- title : `New session ${ createdSessions . length } ` ,
101- }
102- sessionDirectories [ session . id ] = input . location . directory
103- return session
104- } ,
105- async shell ( input : { sessionID : string } ) {
106- sentShell . push ( sessionDirectories [ input . sessionID ] ?? "/repo/main" )
107- } ,
108- async prompt ( ) { } ,
109- async command ( ) { } ,
110- async interrupt ( ) { } ,
111- } ,
112- }
113-
114118beforeAll ( async ( ) => {
115119 const rootClient = clientFor ( "/repo/main" )
116120
@@ -193,8 +197,8 @@ beforeAll(async () => {
193197 const sdk = {
194198 scope : "local" ,
195199 directory : "/repo/main" ,
196- api,
197200 client : rootClient ,
201+ api : rootClient . api ,
198202 url : "http://localhost:4096" ,
199203 createClient ( opts : any ) {
200204 return clientFor ( opts . directory )
@@ -206,7 +210,7 @@ beforeAll(async () => {
206210
207211 mock . module ( "@/context/sync" , ( ) => ( {
208212 useSync : ( ) => ( ) => ( {
209- data : { command : [ ] } ,
213+ data : { command : commands } ,
210214 session : {
211215 optimistic : {
212216 add : ( value : {
@@ -233,6 +237,9 @@ beforeAll(async () => {
233237 session : {
234238 remember : ( ) => undefined ,
235239 set : ( ) => undefined ,
240+ sync : async ( ) => {
241+ serverSessionSyncs ++
242+ } ,
236243 } ,
237244 child : ( directory : string ) => {
238245 syncedDirectories . push ( directory )
@@ -274,11 +281,17 @@ beforeAll(async () => {
274281beforeEach ( ( ) => {
275282 createdClients . length = 0
276283 createdSessions . length = 0
284+ sessionCreateInputs . length = 0
277285 enabledAutoAccept . length = 0
278286 optimistic . length = 0
279287 optimisticSeeded . length = 0
280288 promoted . length = 0
281289 promotedDrafts . length = 0
290+ sentPrompts . length = 0
291+ promptInputs . length = 0
292+ sentCommands . length = 0
293+ commands . length = 0
294+ promptValue = [ { type : "text" , content : "ls" , start : 0 , end : 2 } ]
282295 params = { }
283296 search = { }
284297 sentShell . length = 0
@@ -287,8 +300,8 @@ beforeEach(() => {
287300 variant = undefined
288301 permissionServer = "server-a"
289302 createSessionGate = undefined
303+ serverSessionSyncs = 0
290304 for ( const key of Object . keys ( storedSessions ) ) delete storedSessions [ key ]
291- for ( const key of Object . keys ( sessionDirectories ) ) delete sessionDirectories [ key ]
292305} )
293306
294307describe ( "prompt submit worktree selection" , ( ) => {
@@ -321,8 +334,24 @@ describe("prompt submit worktree selection", () => {
321334
322335 expect ( createdClients ) . toEqual ( [ "/repo/worktree-a" , "/repo/worktree-b" ] )
323336 expect ( createdSessions ) . toEqual ( [ "/repo/worktree-a" , "/repo/worktree-b" ] )
324- expect ( sentShell ) . toEqual ( [ "/repo/worktree-a" , "/repo/worktree-b" ] )
337+ expect ( sessionCreateInputs ) . toEqual ( [
338+ {
339+ agent : "agent" ,
340+ model : { id : "model" , providerID : "provider" , variant : undefined } ,
341+ location : { directory : "/repo/worktree-a" } ,
342+ } ,
343+ {
344+ agent : "agent" ,
345+ model : { id : "model" , providerID : "provider" , variant : undefined } ,
346+ location : { directory : "/repo/worktree-b" } ,
347+ } ,
348+ ] )
349+ expect ( sentShell ) . toEqual ( [
350+ expect . objectContaining ( { sessionID : "session-1" , id : expect . stringMatching ( / ^ e v t _ / ) , command : "ls" } ) ,
351+ expect . objectContaining ( { sessionID : "session-2" , id : expect . stringMatching ( / ^ e v t _ / ) , command : "ls" } ) ,
352+ ] )
325353 expect ( syncedDirectories ) . toEqual ( [ "/repo/worktree-a" , "/repo/worktree-a" , "/repo/worktree-b" , "/repo/worktree-b" ] )
354+ expect ( serverSessionSyncs ) . toBe ( 0 )
326355 expect ( promoted ) . toEqual ( [
327356 { directory : "/repo/worktree-a" , sessionID : "session-1" } ,
328357 { directory : "/repo/worktree-b" , sessionID : "session-2" } ,
@@ -443,6 +472,7 @@ describe("prompt submit worktree selection", () => {
443472 const event = { preventDefault : ( ) => undefined } as unknown as Event
444473
445474 await submit . handleSubmit ( event )
475+ await Bun . sleep ( 0 )
446476
447477 expect ( optimistic ) . toHaveLength ( 1 )
448478 expect ( optimistic [ 0 ] ) . toMatchObject ( {
@@ -451,6 +481,53 @@ describe("prompt submit worktree selection", () => {
451481 model : { providerID : "provider" , modelID : "model" , variant : "high" } ,
452482 } ,
453483 } )
484+ expect ( sentPrompts ) . toEqual ( [ "/repo/main" ] )
485+ expect ( promptInputs [ 0 ] ) . toMatchObject ( {
486+ sessionID : "session-1" ,
487+ text : "ls" ,
488+ files : [ ] ,
489+ agents : [ ] ,
490+ } )
491+ expect ( ( promptInputs [ 0 ] as { id ?: string } ) . id ) . toStartWith ( "msg_" )
492+ } )
493+
494+ test ( "submits slash commands through the current session API" , async ( ) => {
495+ params = { id : "session-1" }
496+ variant = "high"
497+ commands . push ( { name : "review" } )
498+ promptValue = [ { type : "text" , content : "/review staged changes" , start : 0 , end : 22 } ]
499+
500+ const submit = createPromptSubmit ( {
501+ prompt,
502+ info : ( ) => ( { id : "session-1" } ) ,
503+ imageAttachments : ( ) => [ ] ,
504+ commentCount : ( ) => 0 ,
505+ autoAccept : ( ) => false ,
506+ mode : ( ) => "normal" ,
507+ working : ( ) => false ,
508+ editor : ( ) => undefined ,
509+ queueScroll : ( ) => undefined ,
510+ promptLength : ( value ) => value . reduce ( ( sum , part ) => sum + ( "content" in part ? part . content . length : 0 ) , 0 ) ,
511+ addToHistory : ( ) => undefined ,
512+ resetHistoryNavigation : ( ) => undefined ,
513+ setMode : ( ) => undefined ,
514+ setPopover : ( ) => undefined ,
515+ } )
516+
517+ await submit . handleSubmit ( { preventDefault : ( ) => undefined } as unknown as Event )
518+
519+ expect ( sentCommands ) . toEqual ( [
520+ {
521+ sessionID : "session-1" ,
522+ id : expect . stringMatching ( / ^ m s g _ / ) ,
523+ command : "review" ,
524+ arguments : "staged changes" ,
525+ agent : "agent" ,
526+ model : { id : "model" , providerID : "provider" , variant : "high" } ,
527+ files : [ ] ,
528+ } ,
529+ ] )
530+ expect ( serverSessionSyncs ) . toBe ( 0 )
454531 } )
455532
456533 test ( "uses an injected model selection" , async ( ) => {
@@ -511,7 +588,8 @@ describe("prompt submit worktree selection", () => {
511588
512589 await submit . handleSubmit ( event )
513590
514- expect ( storedSessions [ "/repo/worktree-a" ] ) . toEqual ( [ { id : "session-1" , title : "New session 1" } ] )
591+ expect ( storedSessions [ "/repo/worktree-a" ] ) . toHaveLength ( 1 )
592+ expect ( storedSessions [ "/repo/worktree-a" ] ?. [ 0 ] ) . toMatchObject ( { id : "session-1" , title : "New session 1" } )
515593 expect ( optimisticSeeded ) . toEqual ( [ true ] )
516594 } )
517595} )
0 commit comments