@@ -35,6 +35,7 @@ export interface ICopilotRemoteAgentCommandArgs {
3535 userPrompt : string ;
3636 summary ?: string ;
3737 source ?: string ;
38+ followup ?: string ;
3839}
3940
4041const LEARN_MORE = vscode . l10n . t ( 'Learn about Coding Agent' ) ;
@@ -44,6 +45,9 @@ const CONTINUE = vscode.l10n.t('Continue');
4445const PUSH_CHANGES = vscode . l10n . t ( 'Include changes' ) ;
4546const CONTINUE_WITHOUT_PUSHING = vscode . l10n . t ( 'Ignore changes' ) ;
4647
48+ const FOLLOW_UP_REGEX = / o p e n - p u l l - r e q u e s t - w e b v i e w .* ( ( % 7 B .* ?% 7 D ) | ( \{ .* ?\} ) ) / ;
49+ const COPILOT = '@copilot' ;
50+
4751export class CopilotRemoteAgentManager extends Disposable {
4852 public static ID = 'CopilotRemoteAgentManager' ;
4953
@@ -201,12 +205,39 @@ export class CopilotRemoteAgentManager extends Disposable {
201205 return { owner, repo, baseRef, remote, repository, ghRepository, fm } ;
202206 }
203207
208+ private parseFollowup ( followup : string | undefined , repoInfo : { owner : string ; repo : string } ) : number | undefined {
209+ if ( ! followup ) {
210+ return ;
211+ }
212+ const match = followup . match ( FOLLOW_UP_REGEX ) ;
213+ if ( ! match || match . length < 2 ) {
214+ Logger . error ( `Ignoring. Invalid followup format: ${ followup } ` , CopilotRemoteAgentManager . ID ) ;
215+ return ;
216+ }
217+
218+ try {
219+ const followUpData = JSON . parse ( decodeURIComponent ( match [ 1 ] ) ) ;
220+ if ( ! followUpData || ! followUpData . owner || ! followUpData . repo || ! followUpData . pullRequestNumber ) {
221+ Logger . error ( `Ignoring. Invalid followup data: ${ followUpData } ` , CopilotRemoteAgentManager . ID ) ;
222+ return ;
223+ }
224+
225+ if ( repoInfo . owner !== followUpData . owner || repoInfo . repo !== followUpData . repo ) {
226+ Logger . error ( `Ignoring. Follow up data does not match current repository: ${ JSON . stringify ( followUpData ) } ` , CopilotRemoteAgentManager . ID ) ;
227+ return ;
228+ }
229+ return followUpData . pullRequestNumber ;
230+ } catch ( error ) {
231+ Logger . error ( `Ignoring. Error while parsing follow up data: ${ followup } ` , CopilotRemoteAgentManager . ID ) ;
232+ }
233+ }
234+
204235 async commandImpl ( args ?: ICopilotRemoteAgentCommandArgs ) : Promise < string | undefined > {
205236 if ( ! args ) {
206237 return ;
207238 }
208239
209- const { userPrompt, summary, source } = args ;
240+ const { userPrompt, summary, source, followup } = args ;
210241 if ( ! userPrompt || userPrompt . trim ( ) . length === 0 ) {
211242 return ;
212243 }
@@ -216,6 +247,36 @@ export class CopilotRemoteAgentManager extends Disposable {
216247 return ;
217248 }
218249 const { repository, owner, repo } = repoInfo ;
250+
251+ // If this is a followup, parse out the necessary data
252+ // Group 2 is this, url-encoded:
253+ // {"owner":"monalisa","repo":"app","pullRequestNumber":18}
254+ let followUpPR : number | undefined = this . parseFollowup ( followup , repoInfo ) ;
255+ if ( followUpPR ) {
256+ try {
257+ const ghRepo = repoInfo . ghRepository ;
258+ // Fetch the PullRequestModel by number
259+ const pr = await ghRepo . getPullRequest ( followUpPR ) ;
260+ if ( ! pr ) {
261+ Logger . error ( `Could not find pull request #${ followUpPR } ` , CopilotRemoteAgentManager . ID ) ;
262+ return ;
263+ }
264+ // Add a comment tagging @copilot with the user's prompt
265+ const commentBody = `${ COPILOT } ${ userPrompt } \n\n --- \n\n ${ summary ?? '' } ` ;
266+ const commentResult = await pr . createIssueComment ( commentBody ) ;
267+ if ( ! commentResult ) {
268+ Logger . error ( `Failed to add comment to PR #${ followUpPR } ` , CopilotRemoteAgentManager . ID ) ;
269+ return ;
270+ }
271+ Logger . appendLine ( `Added comment ${ commentResult . htmlUrl } ` , CopilotRemoteAgentManager . ID ) ;
272+ // allow-any-unicode-next-line
273+ return vscode . l10n . t ( '🚀 Follow-up comment added to [#{0}]({1})' , followUpPR , commentResult . htmlUrl ) ;
274+ } catch ( err ) {
275+ Logger . error ( `Failed to add follow-up comment to PR #${ followUpPR } : ${ err } ` , CopilotRemoteAgentManager . ID ) ;
276+ return ;
277+ }
278+ }
279+
219280 const repoName = `${ owner } /${ repo } ` ;
220281 const hasChanges = repository . state . workingTreeChanges . length > 0 || repository . state . indexChanges . length > 0 ;
221282 const learnMoreCb = async ( ) => {
0 commit comments