@@ -22,6 +22,7 @@ import { PI_SEARCH_PROVIDERS } from '@/executor/handlers/pi/keys'
2222
2323const searchProviderField = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'searchProvider' )
2424const searchApiKeyField = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'searchApiKey' )
25+ const targetBranchField = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'targetBranch' )
2526
2627function searchKeyVisible ( values : Record < string , unknown > ) : boolean {
2728 return evaluateSubBlockCondition ( searchApiKeyField ?. condition , values )
@@ -74,69 +75,73 @@ describe('Pi block search fields', () => {
7475 } )
7576} )
7677
77- describe ( 'Pi Create PR Babysit surface' , ( ) => {
78- it ( 'offers exactly Create PR, Review Code, and Local Dev as top-level modes' , ( ) => {
78+ describe ( 'Pi cloud authoring surface' , ( ) => {
79+ it ( 'offers Create PR, Update Branch , Review Code, and Local Dev as top-level modes' , ( ) => {
7980 const mode = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'mode' )
8081 const options =
8182 typeof mode ?. options === 'function'
8283 ? mode . options ( )
8384 : ( mode ?. options as Array < { id : string } > | undefined )
8485
85- expect ( options ?. map ( ( { id } ) => id ) ) . toEqual ( [ 'cloud' , 'cloud_review' , 'local' ] )
86+ expect ( options ?. map ( ( { id } ) => id ) ) . toEqual ( [ 'cloud' , 'cloud_branch' , ' cloud_review', 'local' ] )
8687 } )
8788
88- it ( 'declares the toggle, required reviewer mentions, advanced rounds, and result outputs' , ( ) => {
89- const toggle = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'babysitMode' )
90- const maxRounds = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'maxRounds' )
91- const mentions = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'reviewMentions' )
92-
93- expect ( toggle ) . toMatchObject ( {
94- type : 'switch' ,
95- defaultValue : false ,
96- condition : { field : 'mode' , value : 'cloud' } ,
97- } )
98- expect ( maxRounds ) . toMatchObject ( {
99- type : 'short-input' ,
100- defaultValue : '3' ,
101- mode : 'advanced' ,
102- condition : {
103- field : 'mode' ,
104- value : 'cloud' ,
105- and : { field : 'babysitMode' , value : true } ,
106- } ,
107- } )
108- expect ( mentions ) . toMatchObject ( {
109- type : 'short-input' ,
110- defaultValue : '' ,
111- hideDividerBefore : true ,
112- required : {
113- field : 'mode' ,
114- value : 'cloud' ,
115- and : { field : 'babysitMode' , value : true } ,
116- } ,
117- condition : {
118- field : 'mode' ,
119- value : 'cloud' ,
120- and : { field : 'babysitMode' , value : true } ,
121- } ,
122- } )
123- for ( const output of [
124- 'rounds' ,
125- 'threadsClean' ,
126- 'checksGreen' ,
127- 'threadsResolved' ,
128- 'commitsPushed' ,
129- 'stopReason' ,
130- ] ) {
131- expect ( PiBlock . outputs [ output ] ) . toMatchObject ( {
89+ it . each ( [ 'cloud' , 'cloud_branch' ] ) (
90+ 'declares Babysit controls and outputs for %s' ,
91+ ( authoringMode ) => {
92+ const toggle = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'babysitMode' )
93+ const maxRounds = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'maxRounds' )
94+ const mentions = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'reviewMentions' )
95+
96+ expect ( toggle ) . toMatchObject ( {
97+ type : 'switch' ,
98+ defaultValue : false ,
99+ condition : { field : 'mode' , value : [ 'cloud' , 'cloud_branch' ] } ,
100+ } )
101+ expect ( maxRounds ) . toMatchObject ( {
102+ type : 'short-input' ,
103+ defaultValue : '3' ,
104+ mode : 'advanced' ,
132105 condition : {
133106 field : 'mode' ,
134- value : 'cloud' ,
107+ value : [ 'cloud' , 'cloud_branch' ] ,
135108 and : { field : 'babysitMode' , value : true } ,
136109 } ,
137110 } )
111+ expect ( mentions ) . toMatchObject ( {
112+ type : 'short-input' ,
113+ defaultValue : '' ,
114+ hideDividerBefore : true ,
115+ required : {
116+ field : 'mode' ,
117+ value : [ 'cloud' , 'cloud_branch' ] ,
118+ and : { field : 'babysitMode' , value : true } ,
119+ } ,
120+ condition : {
121+ field : 'mode' ,
122+ value : [ 'cloud' , 'cloud_branch' ] ,
123+ and : { field : 'babysitMode' , value : true } ,
124+ } ,
125+ } )
126+ for ( const output of [
127+ 'rounds' ,
128+ 'threadsClean' ,
129+ 'checksGreen' ,
130+ 'threadsResolved' ,
131+ 'commitsPushed' ,
132+ 'stopReason' ,
133+ ] ) {
134+ expect ( PiBlock . outputs [ output ] ) . toMatchObject ( {
135+ condition : {
136+ field : 'mode' ,
137+ value : [ 'cloud' , 'cloud_branch' ] ,
138+ and : { field : 'babysitMode' , value : true } ,
139+ } ,
140+ } )
141+ }
142+ expect ( evaluateSubBlockCondition ( toggle ?. condition , { mode : authoringMode } ) ) . toBe ( true )
138143 }
139- } )
144+ )
140145
141146 it ( 'requires a task and hides Draft PR while Babysit Mode is enabled' , ( ) => {
142147 const task = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'task' )
@@ -157,4 +162,55 @@ describe('Pi Create PR Babysit surface', () => {
157162 expect ( evaluateSubBlockCondition ( pullNumber ?. condition , { mode : 'cloud' } ) ) . toBe ( false )
158163 expect ( evaluateSubBlockCondition ( pullNumber ?. condition , { mode : 'cloud_review' } ) ) . toBe ( true )
159164 } )
165+
166+ it ( 'requires the target branch only in Update Branch mode' , ( ) => {
167+ expect ( targetBranchField ?. type ) . toBe ( 'short-input' )
168+ expect ( targetBranchField ?. required ) . toBe ( true )
169+ expect ( evaluateSubBlockCondition ( targetBranchField ?. condition , { mode : 'cloud_branch' } ) ) . toBe (
170+ true
171+ )
172+ expect ( evaluateSubBlockCondition ( targetBranchField ?. condition , { mode : 'cloud' } ) ) . toBe ( false )
173+ expect ( evaluateSubBlockCondition ( targetBranchField ?. condition , { mode : 'cloud_review' } ) ) . toBe (
174+ false
175+ )
176+ expect ( evaluateSubBlockCondition ( targetBranchField ?. condition , { mode : 'local' } ) ) . toBe ( false )
177+ } )
178+
179+ it ( 'declares the target branch input and branch output for cloud authoring modes' , ( ) => {
180+ expect ( PiBlock . inputs . targetBranch ) . toBeDefined ( )
181+ expect (
182+ evaluateSubBlockCondition ( PiBlock . outputs . branch . condition , { mode : 'cloud_branch' } )
183+ ) . toBe ( true )
184+ expect ( evaluateSubBlockCondition ( PiBlock . outputs . branch . condition , { mode : 'cloud' } ) ) . toBe (
185+ true
186+ )
187+ expect (
188+ evaluateSubBlockCondition ( PiBlock . outputs . branch . condition , { mode : 'cloud_review' } )
189+ ) . toBe ( false )
190+ } )
191+
192+ it ( 'reuses skills and memory fields, including their dependent controls' , ( ) => {
193+ for ( const id of [
194+ 'skills' ,
195+ 'memoryType' ,
196+ 'conversationId' ,
197+ 'slidingWindowSize' ,
198+ 'slidingWindowTokens' ,
199+ ] ) {
200+ const field = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === id )
201+ expect (
202+ evaluateSubBlockCondition ( field ?. condition , {
203+ mode : 'cloud_branch' ,
204+ memoryType : id === 'slidingWindowTokens' ? 'sliding_window_tokens' : 'sliding_window' ,
205+ } )
206+ ) . toBe ( true )
207+ }
208+ } )
209+
210+ it ( 'hides Create PR and Review Code-specific fields' , ( ) => {
211+ for ( const id of [ 'baseBranch' , 'branchName' , 'draft' , 'prTitle' , 'prBody' , 'pullNumber' ] ) {
212+ const field = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === id )
213+ expect ( evaluateSubBlockCondition ( field ?. condition , { mode : 'cloud_branch' } ) ) . toBe ( false )
214+ }
215+ } )
160216} )
0 commit comments