@@ -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 )
@@ -84,69 +85,73 @@ describe('Pi block search fields', () => {
8485 } )
8586} )
8687
87- describe ( 'Pi Create PR Babysit surface' , ( ) => {
88- it ( 'offers exactly Create PR, Review Code, and Local Dev as top-level modes' , ( ) => {
88+ describe ( 'Pi cloud authoring surface' , ( ) => {
89+ it ( 'offers Create PR, Update PR, Review Code, and Local Dev as top-level modes' , ( ) => {
8990 const mode = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'mode' )
9091 const options =
9192 typeof mode ?. options === 'function'
9293 ? mode . options ( )
9394 : ( mode ?. options as Array < { id : string } > | undefined )
9495
95- expect ( options ?. map ( ( { id } ) => id ) ) . toEqual ( [ 'cloud' , 'cloud_review' , 'local' ] )
96+ expect ( options ?. map ( ( { id } ) => id ) ) . toEqual ( [ 'cloud' , 'cloud_branch' , ' cloud_review', 'local' ] )
9697 } )
9798
98- it ( 'declares the toggle, required reviewer mentions, advanced rounds, and result outputs' , ( ) => {
99- const toggle = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'babysitMode' )
100- const maxRounds = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'maxRounds' )
101- const mentions = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'reviewMentions' )
102-
103- expect ( toggle ) . toMatchObject ( {
104- type : 'switch' ,
105- defaultValue : false ,
106- condition : { field : 'mode' , value : 'cloud' } ,
107- } )
108- expect ( maxRounds ) . toMatchObject ( {
109- type : 'short-input' ,
110- defaultValue : '3' ,
111- mode : 'advanced' ,
112- condition : {
113- field : 'mode' ,
114- value : 'cloud' ,
115- and : { field : 'babysitMode' , value : [ true , 'true' ] } ,
116- } ,
117- } )
118- expect ( mentions ) . toMatchObject ( {
119- type : 'short-input' ,
120- defaultValue : '' ,
121- hideDividerBefore : true ,
122- required : {
123- field : 'mode' ,
124- value : 'cloud' ,
125- and : { field : 'babysitMode' , value : [ true , 'true' ] } ,
126- } ,
127- condition : {
128- field : 'mode' ,
129- value : 'cloud' ,
130- and : { field : 'babysitMode' , value : [ true , 'true' ] } ,
131- } ,
132- } )
133- for ( const output of [
134- 'rounds' ,
135- 'threadsClean' ,
136- 'checksGreen' ,
137- 'threadsResolved' ,
138- 'commitsPushed' ,
139- 'stopReason' ,
140- ] ) {
141- expect ( PiBlock . outputs [ output ] ) . toMatchObject ( {
99+ it . each ( [ 'cloud' , 'cloud_branch' ] ) (
100+ 'declares Babysit controls and outputs for %s' ,
101+ ( authoringMode ) => {
102+ const toggle = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'babysitMode' )
103+ const maxRounds = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'maxRounds' )
104+ const mentions = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'reviewMentions' )
105+
106+ expect ( toggle ) . toMatchObject ( {
107+ type : 'switch' ,
108+ defaultValue : false ,
109+ condition : { field : 'mode' , value : [ 'cloud' , 'cloud_branch' ] } ,
110+ } )
111+ expect ( maxRounds ) . toMatchObject ( {
112+ type : 'short-input' ,
113+ defaultValue : '3' ,
114+ mode : 'advanced' ,
115+ condition : {
116+ field : 'mode' ,
117+ value : [ 'cloud' , 'cloud_branch' ] ,
118+ and : { field : 'babysitMode' , value : [ true , 'true' ] } ,
119+ } ,
120+ } )
121+ expect ( mentions ) . toMatchObject ( {
122+ type : 'short-input' ,
123+ defaultValue : '' ,
124+ hideDividerBefore : true ,
125+ required : {
126+ field : 'mode' ,
127+ value : [ 'cloud' , 'cloud_branch' ] ,
128+ and : { field : 'babysitMode' , value : [ true , 'true' ] } ,
129+ } ,
142130 condition : {
143131 field : 'mode' ,
144- value : 'cloud' ,
132+ value : [ 'cloud' , 'cloud_branch' ] ,
145133 and : { field : 'babysitMode' , value : [ true , 'true' ] } ,
146134 } ,
147135 } )
136+ for ( const output of [
137+ 'rounds' ,
138+ 'threadsClean' ,
139+ 'checksGreen' ,
140+ 'threadsResolved' ,
141+ 'commitsPushed' ,
142+ 'stopReason' ,
143+ ] ) {
144+ expect ( PiBlock . outputs [ output ] ) . toMatchObject ( {
145+ condition : {
146+ field : 'mode' ,
147+ value : [ 'cloud' , 'cloud_branch' ] ,
148+ and : { field : 'babysitMode' , value : [ true , 'true' ] } ,
149+ } ,
150+ } )
151+ }
152+ expect ( evaluateSubBlockCondition ( toggle ?. condition , { mode : authoringMode } ) ) . toBe ( true )
148153 }
149- } )
154+ )
150155
151156 it ( 'requires a task and hides Draft PR while Babysit Mode is enabled' , ( ) => {
152157 const task = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'task' )
@@ -176,4 +181,81 @@ describe('Pi Create PR Babysit surface', () => {
176181 expect ( evaluateSubBlockCondition ( pullNumber ?. condition , { mode : 'cloud' } ) ) . toBe ( false )
177182 expect ( evaluateSubBlockCondition ( pullNumber ?. condition , { mode : 'cloud_review' } ) ) . toBe ( true )
178183 } )
184+
185+ it ( 'requires the target branch only in Update PR mode' , ( ) => {
186+ expect ( targetBranchField ?. type ) . toBe ( 'short-input' )
187+ expect ( targetBranchField ?. required ) . toBe ( true )
188+ expect ( evaluateSubBlockCondition ( targetBranchField ?. condition , { mode : 'cloud_branch' } ) ) . toBe (
189+ true
190+ )
191+ expect ( evaluateSubBlockCondition ( targetBranchField ?. condition , { mode : 'cloud' } ) ) . toBe ( false )
192+ expect ( evaluateSubBlockCondition ( targetBranchField ?. condition , { mode : 'cloud_review' } ) ) . toBe (
193+ false
194+ )
195+ expect ( evaluateSubBlockCondition ( targetBranchField ?. condition , { mode : 'local' } ) ) . toBe ( false )
196+ } )
197+
198+ it ( 'declares the target branch input and branch output for cloud authoring modes' , ( ) => {
199+ expect ( PiBlock . inputs . targetBranch ) . toBeDefined ( )
200+ expect (
201+ evaluateSubBlockCondition ( PiBlock . outputs . branch . condition , { mode : 'cloud_branch' } )
202+ ) . toBe ( true )
203+ expect ( evaluateSubBlockCondition ( PiBlock . outputs . branch . condition , { mode : 'cloud' } ) ) . toBe (
204+ true
205+ )
206+ expect (
207+ evaluateSubBlockCondition ( PiBlock . outputs . branch . condition , { mode : 'cloud_review' } )
208+ ) . toBe ( false )
209+ } )
210+
211+ it ( 'reuses skills and memory fields, including their dependent controls' , ( ) => {
212+ for ( const id of [
213+ 'skills' ,
214+ 'memoryType' ,
215+ 'conversationId' ,
216+ 'slidingWindowSize' ,
217+ 'slidingWindowTokens' ,
218+ ] ) {
219+ const field = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === id )
220+ expect (
221+ evaluateSubBlockCondition ( field ?. condition , {
222+ mode : 'cloud_branch' ,
223+ memoryType : id === 'slidingWindowTokens' ? 'sliding_window_tokens' : 'sliding_window' ,
224+ } )
225+ ) . toBe ( true )
226+ }
227+ } )
228+
229+ it ( 'shows PR metadata controls and hides Create PR and Review Code-only fields' , ( ) => {
230+ for ( const id of [ 'baseBranch' , 'prTitle' , 'prBody' , 'prState' ] ) {
231+ const field = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === id )
232+ expect ( evaluateSubBlockCondition ( field ?. condition , { mode : 'cloud_branch' } ) ) . toBe ( true )
233+ }
234+ for ( const id of [ 'branchName' , 'draft' , 'pullNumber' ] ) {
235+ const field = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === id )
236+ expect ( evaluateSubBlockCondition ( field ?. condition , { mode : 'cloud_branch' } ) ) . toBe ( false )
237+ }
238+ const prState = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'prState' )
239+ expect (
240+ evaluateSubBlockCondition ( prState ?. condition , {
241+ mode : 'cloud_branch' ,
242+ babysitMode : true ,
243+ } )
244+ ) . toBe ( false )
245+ expect (
246+ evaluateSubBlockCondition ( prState ?. condition , {
247+ mode : 'cloud_branch' ,
248+ babysitMode : 'true' ,
249+ } )
250+ ) . toBe ( false )
251+ expect ( PiBlock . inputs . prState ) . toBeDefined ( )
252+ } )
253+
254+ it . each ( [ 'cloud' , 'cloud_branch' ] ) (
255+ 'always shows the model API key for sandbox authoring mode %s' ,
256+ ( mode ) => {
257+ const apiKey = PiBlock . subBlocks . find ( ( subBlock ) => subBlock . id === 'apiKey' )
258+ expect ( evaluateSubBlockCondition ( apiKey ?. condition , { mode } ) ) . toBe ( true )
259+ }
260+ )
179261} )
0 commit comments