Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Asking GitHub Copilot to create a pull request
shortTitle: Create a PR
intro: 'You can ask {% data variables.product.prodname_copilot_short %} to create a pull request from many places, including the agents panel, {% data variables.copilot.copilot_chat_short %}, and agentic coding tools and IDEs with Model Context Protocol (MCP) support.'
intro: 'You can ask {% data variables.product.prodname_copilot_short %} to create a pull request from many places, including the agents panel, {% data variables.copilot.copilot_chat_short %}, the {% data variables.product.prodname_cli %}, and agentic coding tools and IDEs with Model Context Protocol (MCP) support.'
product: '{% data reusables.gated-features.copilot-coding-agent %}<br><a href="https://github.com/features/copilot/plans?ref_cta=Copilot+plans+signup&ref_loc=asking+copilot+to+create+a+pull+request&ref_page=docs" target="_blank" class="btn btn-primary mt-3 mr-3 no-underline"><span>Sign up for {% data variables.product.prodname_copilot_short %}</span> {% octicon "link-external" height:16 %}</a>'
versions:
feature: copilot
Expand All @@ -28,6 +28,7 @@ You can ask {% data variables.product.prodname_copilot_short %} to work on a tas
* The agents panel, available across {% data variables.product.github %}
* The agents page on {% data variables.product.github %}
* {% data variables.copilot.copilot_chat_short %} in {% data variables.product.prodname_vscode %}, {% data variables.product.prodname_vs %}, JetBrains IDEs and {% data variables.product.prodname_dotcom_the_website %}
* The {% data variables.product.prodname_cli %}
* Your preferred IDE or agentic coding tool with Model Context Protocol (MCP) support
* The Raycast launcher on macOS

Expand Down Expand Up @@ -100,6 +101,25 @@ You can ask {% data variables.product.prodname_copilot_short %} to open a pull r

{% data variables.product.prodname_copilot_short %} will start a new session and respond with a link to the pull request it creates. It will work on the task and push changes to the pull request, and then add you as a reviewer when it has finished, triggering a notification.

## Asking {% data variables.product.prodname_copilot_short %} to create a pull request from the {% data variables.product.prodname_cli %}

> [!NOTE]
> The `agent-task` command set is only available in v2.80.0 or later of the {% data variables.product.prodname_cli %}. This command set is a {% data variables.release-phases.public_preview %} and is subject to change.

You can start a new {% data variables.copilot.copilot_coding_agent %} session with the `gh agent-task create` command in the {% data variables.product.prodname_cli %}.

When you run the command without any arguments, you are asked to enter a prompt. {% data variables.copilot.copilot_coding_agent %} acts on the prompt and opens a pull request in the current repository.

You can use command line options to:

* Provide the prompt (`gh agent-task create "Example prompt"`)
* Choose a base branch, instead of using the repository's default branch (`--base`)
* Select a repository, instead of targeting the current repository (`--repo`)
* Follow the session log in real time (`--follow`)


To see all of the available options, run `gh agent-task create --help`.

## Asking {% data variables.product.prodname_copilot_short %} to create a pull request from the {% data variables.product.github %} MCP server

As an alternative to using {% data variables.copilot.copilot_chat_short %}, you can use the remote {% data variables.product.github %} MCP server to trigger {% data variables.copilot.copilot_coding_agent %} from any MCP host.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Tracking GitHub Copilot's sessions
shortTitle: Track Copilot sessions
intro: 'You can use the agents panel or page, {% data variables.product.prodname_vscode %}, Raycast and session logs to track {% data variables.product.prodname_copilot_short %}''s progress and understand its approach.'
intro: 'You can use the agents panel or page, {% data variables.product.prodname_vscode %}, the {% data variables.product.prodname_cli %}, Raycast and session logs to track {% data variables.product.prodname_copilot_short %}''s progress and understand its approach.'
product: '{% data reusables.gated-features.copilot-coding-agent %}<br><a href="https://github.com/features/copilot/plans?ref_cta=Copilot+plans+signup&ref_loc=using+the+copilot+coding+agent+logs&ref_page=docs" target="_blank" class="btn btn-primary mt-3 mr-3 no-underline"><span>Sign up for {% data variables.product.prodname_copilot_short %}</span> {% octicon "link-external" height:16 %}</a>'
versions:
feature: copilot
Expand All @@ -24,7 +24,7 @@ contentType: how-tos

After you give {% data variables.product.prodname_copilot_short %} a task, it works autonomously in the background to complete it. See [AUTOTITLE](/copilot/concepts/about-copilot-coding-agent).

The agents panel, [agents page](https://github.com/copilot/agents), and {% data variables.product.prodname_copilot %} extension for Raycast provide an overview of your agent sessions across repositories. You can use them to kick off new tasks and track {% data variables.product.prodname_copilot_short %}'s progress.
The agents panel, [agents page](https://github.com/copilot/agents), the {% data variables.product.prodname_cli %}, and {% data variables.product.prodname_copilot %} extension for Raycast provide an overview of your agent sessions across repositories. You can use them to kick off new tasks and track {% data variables.product.prodname_copilot_short %}'s progress.

You can also track {% data variables.product.prodname_copilot_short %}'s sessions in a specific repository from {% data variables.product.prodname_vscode %}.

Expand All @@ -46,6 +46,19 @@ To view the session logs, click through to the pull request in the list, then fi

You can also start new agent sessions from the page and panel. See [AUTOTITLE](/copilot/how-tos/agents/copilot-coding-agent/asking-copilot-to-create-a-pull-request).

## Tracking agent sessions from the {% data variables.product.prodname_cli %}

> [!NOTE]
> The `agent-task` command set is only available in v2.80.0 or later of the {% data variables.product.prodname_cli %}. This command set is a {% data variables.release-phases.public_preview %} and is subject to change.

You can see a list of your running and past agent sessions from the {% data variables.product.prodname_cli %} with the `gh agent-task list` command. The output will show a list of your recent sessions.

To see more information on a specific session, use the `gh agent-task view` command. For example, to view information about the session associated with pull request #123 in the `monalisa/bookstore` repository, run `gh agent-task view --repo monalisa/bookstore 123`.

To view the session logs, add the `--log` option. Optionally, use the `--follow` option to stream live logs as the agent works.

To see all of the available options, run `gh agent-task list --help` or `gh agent-task view --help`.

## Tracking agent sessions from Raycast

{% data reusables.copilot.coding-agent.raycast-intro %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import fs from 'fs'
// is unpredictable in GitHub Actions because of how it does `git clone`.
// So we rely on environment variables instead.

export function getDiffFiles() {
export function getDiffFiles(): string[] {
// Instead of testing every single file possible, if there's
// an environment variable called `DIFF_FILES` or one called
// `DIFF_FILE` then use that.
// If `DIFF_FILES` is set, it's expected to be a space separated
// string. If `DIFF_FILE` is set, it's expected to be a text file
// which contains a space separated string.
const diffFiles = []
const diffFiles: string[] = []
// Setting an environment variable called `DIFF_FILES` is optional.
// But if and only if it's set, we will respect it.
// And if it set, turn it into a cleaned up Set so it's made available
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
// @ts-ignore - markdownlint-rule-helpers doesn't provide TypeScript declarations
import { addError, filterTokens, newLineRe } from 'markdownlint-rule-helpers'

export const codeFenceLineLength = {
import type { RuleParams, RuleErrorCallback, MarkdownToken, Rule } from '@/content-linter/types'

export const codeFenceLineLength: Rule = {
names: ['GHD030', 'code-fence-line-length'],
description: 'Code fence lines should not exceed a maximum length',
tags: ['code', 'accessibility'],
parser: 'markdownit',
function: (params, onError) => {
const MAX_LINE_LENGTH = String(params.config.maxLength || 60)
filterTokens(params, 'fence', (token) => {
const lines = token.content.split(newLineRe)
lines.forEach((line, index) => {
function: (params: RuleParams, onError: RuleErrorCallback) => {
const MAX_LINE_LENGTH: number = params.config?.maxLength || 60
filterTokens(params, 'fence', (token: MarkdownToken) => {
if (!token.content) return
const lines: string[] = token.content.split(newLineRe)
lines.forEach((line: string, index: number) => {
if (line.length > MAX_LINE_LENGTH) {
// The token line number is the line number of the first line of the
// code fence. We want to report the line number of the content within
// the code fence so we need to add 1 + the index.
const lineNumber = token.lineNumber + index + 1
const lineNumber: number = token.lineNumber + index + 1
addError(
onError,
lineNumber,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// used below to remove extra newlines in TOC lists
const endLine = '</a>\r?\n'
const blankLine = '\\s*?[\r\n]*'
const startNextLine = '[^\\S\r\n]*?[-\\*] <a'
const blankLineInList = new RegExp(`(${endLine})${blankLine}(${startNextLine})`, 'mg')
const endLine: string = '</a>\r?\n'
const blankLine: string = '\\s*?[\r\n]*'
const startNextLine: string = '[^\\S\r\n]*?[-\\*] <a'
const blankLineInList: RegExp = new RegExp(`(${endLine})${blankLine}(${startNextLine})`, 'mg')

export function processLiquidPost(template) {
export function processLiquidPost(template: string): string {
template = cleanUpListEmptyLines(template)
template = cleanUpExtraEmptyLines(template)
return template
}

function cleanUpListEmptyLines(template) {
function cleanUpListEmptyLines(template: string): string {
// clean up empty lines in TOC lists left by unrendered list items (due to productVersions)
// for example, remove the blank line here:
// - <a>foo</a>
Expand All @@ -22,7 +22,7 @@ function cleanUpListEmptyLines(template) {
return template
}

function cleanUpExtraEmptyLines(template) {
function cleanUpExtraEmptyLines(template: string): string {
// this removes any extra newlines left by (now resolved) liquid
// statements so that extra space doesn't mess with list numbering
template = template.replace(/(\r?\n){3}/g, '\n\n')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
// src/content-render/liquid/prompt.js
// src/content-render/liquid/prompt.ts
// Defines {% prompt %}…{% endprompt %} to wrap its content in <code> and append the Copilot icon.

// @ts-ignore - @primer/octicons doesn't provide TypeScript declarations
import octicons from '@primer/octicons'

export const Prompt = {
interface LiquidTag {
type: 'block'
templates?: any[] // Note: Using 'any' because liquidjs doesn't provide proper types for template objects
// Note: Using 'any' for liquid-related parameters because liquidjs doesn't provide comprehensive TypeScript definitions
parse(tagToken: any, remainTokens: any): void
render(scope: any): Generator<any, string, unknown>
}

export const Prompt: LiquidTag = {
type: 'block',

// Collect everything until {% endprompt %}
parse(tagToken, remainTokens) {
parse(tagToken: any, remainTokens: any): void {
this.templates = []
const stream = this.liquid.parser.parseStream(remainTokens)
stream
.on('template', (tpl) => this.templates.push(tpl))
.on('template', (tpl: any) => this.templates.push(tpl))
.on('tag:endprompt', () => stream.stop())
.on('end', () => {
throw new Error(`{% prompt %} tag not closed`)
Expand All @@ -20,12 +29,12 @@ export const Prompt = {
},

// Render the inner Markdown, wrap in <code>, then append the SVG
render: function* (scope) {
render: function* (scope: any): Generator<any, string, unknown> {
const content = yield this.liquid.renderer.renderTemplates(this.templates, scope)

// build a URL with the prompt text encoded as query parameter
const promptParam = encodeURIComponent(content)
const href = `https://github.com/copilot?prompt=${promptParam}`
const promptParam: string = encodeURIComponent(content as string)
const href: string = `https://github.com/copilot?prompt=${promptParam}`
return `<code>${content}</code><a href="${href}" target="_blank" class="tooltipped tooltipped-nw ml-1" aria-label="Run this prompt in Copilot Chat" style="text-decoration:none;">${octicons.copilot.toSVG()}</a>`
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { renderContent } from '@/content-render/index'

describe('prompt tag', () => {
test('wraps content in <code> and appends svg', async () => {
const input = 'Here is your prompt: {% prompt %}example prompt text{% endprompt %}.'
const output = await renderContent(input)
const input: string = 'Here is your prompt: {% prompt %}example prompt text{% endprompt %}.'
const output: string = await renderContent(input)
expect(output).toContain('<code>example prompt text</code><a')
expect(output).toContain('<svg')
})
Expand Down
32 changes: 0 additions & 32 deletions src/content-render/unified/parse-info-string.js

This file was deleted.

45 changes: 45 additions & 0 deletions src/content-render/unified/parse-info-string.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Based on https://spec.commonmark.org/0.30/#info-string
// Parse out info strings on fenced code blocks, example:
// ```javascript lineNumbers:left copy:all annotate
// becomes...
// node.lang = javascript
// node.meta = { lineNumbers: 'left', copy: 'all', annotate: true }
// Also parse equals signs, where id=some-id becomes { id: 'some-id' }

import { visit } from 'unist-util-visit'

interface CodeNode {
type: 'code'
lang?: string
meta?: string | Record<string, string | boolean>
value: string
}

// Note: Using 'any' for node because unist-util-visit's type constraints
// don't easily allow for proper code node typing without complex generics
const matcher = (node: any): node is CodeNode => node.type === 'code' && node.lang

export default function parseInfoString() {
// Note: Using 'any' for tree because unified's AST types are complex and
// this function works with different tree types depending on the processor
return (tree: any) => {
visit(tree, matcher, (node: CodeNode) => {
node.meta = strToObj(node.meta as string)

// Temporary, remove {:copy} to avoid highlight parse error in translations.
if (node.lang) {
node.lang = node.lang.replace('{:copy}', '')
}
})
}
}

function strToObj(str?: string): Record<string, string | boolean> {
if (!str) return {}
return Object.fromEntries(
str
.split(/\s+/g)
.map((k: string) => k.split(/[:=]/)) // split by colon or equals sign
.map(([k, ...v]: string[]) => [k, v.length ? v.join(':') : true]),
)
}
29 changes: 0 additions & 29 deletions src/content-render/unified/use-english-headings.js

This file was deleted.

41 changes: 41 additions & 0 deletions src/content-render/unified/use-english-headings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import GithubSlugger from 'github-slugger'
import { encode } from 'html-entities'
import { toString } from 'hast-util-to-string'
import { visit } from 'unist-util-visit'

const slugger = new GithubSlugger()

// Note: Using 'any' for node because the unist/hast type system is complex and
// the visit function's type constraints don't easily allow for proper element typing
// without extensive type gymnastics. The runtime check ensures type safety.
const matcher = (node: any) => node.type === 'element' && ['h2', 'h3', 'h4'].includes(node.tagName)

interface UseEnglishHeadingsOptions {
englishHeadings?: Record<string, string>
}

// replace translated IDs and links in headings with English
export default function useEnglishHeadings({ englishHeadings }: UseEnglishHeadingsOptions) {
if (!englishHeadings) return
// Note: Using 'any' for tree because unified's AST types are complex and
// this function works with different tree types depending on the processor
return (tree: any) => {
// Note: Using 'any' for node because visit() callback typing is restrictive
// and doesn't easily allow for proper element typing without complex generics
visit(tree, matcher, (node: any) => {
slugger.reset()
// Get the plain text content of the heading node
const text: string = toString(node)
// find English heading in the collection
const englishHeading: string = englishHeadings[encode(text)]
// get English slug
const englishSlug: string = slugger.slug(englishHeading)
// use English slug for heading ID and link
if (englishSlug) {
// only use English slug if there is one, otherwise we'll end up with
// empty IDs
node.properties.id = englishSlug
}
})
}
}
Loading
Loading