{"meta":{"title":"Criando extensões para GitHub Copilot CLI","intro":"Crie extensões que adicionam suas próprias ferramentas e comandos com barra ao Copilot CLI.","product":"GitHub Copilot","breadcrumbs":[{"href":"/pt/copilot","title":"GitHub Copilot"},{"href":"/pt/copilot/tutorials","title":"Tutoriais"},{"href":"/pt/copilot/tutorials/create-an-extension","title":"Criar extensões da CLI"}],"documentType":"article"},"body":"# Criando extensões para GitHub Copilot CLI\n\nCrie extensões que adicionam suas próprias ferramentas e comandos com barra ao Copilot CLI.\n\n> \\[!NOTE]\n> GitHub Copilot CLI no momento, as extensões são um recurso experimental e estão sujeitas a alterações.\n\nUma extensão permite que você adicione seus próprios recursos a Copilot CLI. Cada extensão é um pequeno módulo Node.js que é executado como um processo separado junto com sua sessão interativa e se conecta novamente a ela. Por meio dessa conexão, uma extensão pode adicionar **ferramentas** que Copilot pode chamar enquanto trabalha em seu nome, e **comandos de barra** que você mesmo executa.\n\nNeste tutorial, você criará duas extensões simples como exemplos do que você pode fazer:\n\n* Uma ferramenta, chamada `tool-time`, que Copilot pode chamar para relatar quanto tempo suas chamadas de ferramenta levaram até agora em uma sessão.\n* Um comando slash, chamado `/tokencount`, que informa quantos tokens você usou desde o início da contagem.\n\nAmbos os exemplos dependem apenas do SDK que é agrupado com o Copilot CLI, portanto, não há nada extra para instalar. Para obter informações sobre como as extensões funcionam, consulte [Sobre extensões para GitHub Copilot CLI](/pt/copilot/concepts/agents/copilot-cli/about-cli-extensions).\n\n> \\[!WARNING]\n> As extensões são executadas em seu computador com seus privilégios. Carregue apenas o código de uma extensão em que você confia, assim como só executaria qualquer outro script que você mesmo não escreveu.\n\n## Prerequisites\n\n* **GitHub Copilot CLI**: Você precisa ter Copilot CLI instalado e configurado. Consulte [Introdução à CLI do GitHub Copilot](/pt/copilot/how-tos/copilot-cli/cli-getting-started).\n* **Recursos experimentais habilitados**: as extensões são atualmente um recurso experimental. As etapas neste tutorial ativam os recursos experimentais sempre que você inicia a CLI, usando a opção `‑‑experimental` de linha de comando.\n* **JavaScript**: As extensões são escritas em JavaScript, portanto, você precisará estar familiarizado com esse idioma para criar suas próprias extensões.\n* **Um repositório**: o segundo exemplo adiciona uma extensão no nível do projeto, portanto, você precisará de uma cópia local de um repositório Git no qual adicionar a extensão.\n\n## Exemplo de extensão 1: uma ferramenta de \"tempo de uso\"\n\nEste exemplo adiciona uma extensão **de nível de usuário** chamada `tool-time`. Isso adiciona uma nova ferramenta — chamada `session_tool_time` — que Copilot pode chamar para informar quanto tempo as chamadas de ferramentas levaram até agora nesta sessão e quantas chamadas isso abrange.\n\nPara garantir que uma ferramenta seja usada pela CLI, a ferramenta deve fazer algo que a CLI não pode fazer por conta própria. Nesse caso, a ferramenta `session_tool_time` acompanha a duração das chamadas de ferramenta ao ouvir eventos da CLI sobre quando elas começam e terminam, e registra ela mesma esses tempos. Como a CLI não registra esses intervalos em qualquer lugar que Copilot possa ler, a única maneira de Copilot conhecê-los é chamar a ferramenta. A descrição da ferramenta explica isso ao modelo, o que o leva a usar a ferramenta quando você pergunta sobre os tempos das chamadas da ferramenta.\n\n### Etapa 1: Criar o arquivo de extensão\n\n1. Crie o seguinte diretório e arquivo em seu diretório inicial:\n\n   ```text\n   ~/.copilot/extensions/tool-time/extension.mjs\n   ```\n\n   Como isso está em `~/.copilot/extensions/`, a extensão está disponível em **todas as** suas sessões da CLI, em todos os diretórios — e não apenas em um repositório.\n\n2. Adicione este código a `extension.mjs`:\n\n   ```javascript copy\n   // Extension: tool-time\n   // Adds a session_tool_time tool that reports how long Copilot's tool calls\n   // have taken this session. Copilot is never told these timings and they\n   // aren't written anywhere, so calling the tool is the only way to find\n   // them out.\n\n   import { joinSession } from \"@github/copilot-sdk/extension\";\n\n   // The tool's own name, so it can avoid timing its own calls.\n   const TOOL_NAME = \"session_tool_time\";\n\n   // Module-level state persists for the whole session, because the extension\n   // runs as a single long-lived process.\n   const startTimes = new Map(); // tool call id -> Date.now() when call started\n   let totalMs = 0; // total milliseconds spent across finished tool calls\n   let callCount = 0; // number of finished tool calls measured\n\n   const session = await joinSession({\n       tools: [\n           {\n               name: TOOL_NAME,\n               description:\n                   \"Report how long your tool calls have taken in total so far \" +\n                   \"in THIS session, and how many calls that covers. You are \" +\n                   \"never told how long your tool calls take and the timings \" +\n                   \"aren't recorded anywhere you can read, so call this tool \" +\n                   \"whenever you are asked about it rather than estimating.\",\n               // Always keep this tool's description in the model's tool list,\n               // even when tool search is active, so Copilot reliably sees it:\n               defer: \"never\",\n               // Force a permissions approval prompt once, for this extension,\n               // rather than on every call of this tool:\n               skipPermission: true,\n               parameters: { type: \"object\", properties: {} },\n               handler: async () => {\n                   const seconds = (totalMs / 1000).toFixed(1);\n                   return `So far this session, Copilot's tool calls have taken ${seconds}s in total across ${callCount} call(s).`;\n               },\n           },\n       ],\n   });\n\n   // When a tool starts, record the time, keyed by the tool call id so the\n   // matching completion can be found later. The tool's own calls are skipped.\n   session.on(\"tool.execution_start\", (event) => {\n       const data = event.data ?? {};\n       if (data.toolName && data.toolName !== TOOL_NAME) {\n           startTimes.set(data.toolCallId, Date.now());\n       }\n   });\n\n   // When a tool finishes, add the elapsed time to the running total.\n   session.on(\"tool.execution_complete\", (event) => {\n       const data = event.data ?? {};\n       const startedAt = startTimes.get(data.toolCallId);\n       if (startedAt === undefined) {\n           return;\n       }\n       startTimes.delete(data.toolCallId);\n       totalMs += Date.now() - startedAt;\n       callCount += 1;\n   });\n   ```\n\n> \\[!NOTE]\n> \\*\n> `@github/copilot-sdk/extension` é o SDK de extensão, que é agrupado com a CLI. A CLI resolve essa importação automaticamente quando ela executa sua extensão, portanto, você não precisa adicioná-la a um `package.json` gerenciador de pacotes ou executá-la.\n>\n> * Os valores `startTimes`, `totalMs` e `callCount` estão no escopo do módulo. Como a extensão é executada como um único processo de longa duração para toda a sessão, elas se acumulam enquanto a sessão estiver aberta.\n\n### Etapa 2: Carregar a extensão\n\n1. Inicie uma sessão interativa com recursos experimentais habilitados:\n\n   ```shell copy\n   copilot ‑‑experimental\n   ```\n\n   Como a extensão fica em `~/.copilot/extensions/`, você pode executar a CLI de qualquer diretório e a extensão estará disponível.\n\n   Se você já tiver uma sessão aberta, execute `/clear` para iniciar uma nova sessão, que recarrega extensões do disco.\n\n2. Sem conceder permissões elevadas para a nova extensão, todas as extensões ou todas as ferramentas, você será solicitado a permitir que a nova extensão ignore os prompts de permissão da ferramenta. Escolha **Sim** ou **Sim e sempre permita \"user:tool-time\" neste diretório**.\n\n   > \\[!NOTE]\n   > Para obter as permissões mínimas elevadas para evitar ver essa mensagem ao iniciar a CLI, adicione-a ao comando de inicialização da CLI:\n   >\n   > ```shell copy\n   > --allow-tool='extension-permission-access(user:tool-time)'\n   > ```\n   >\n   > Para obter mais informações, consulte [Permitir e negar o uso da ferramenta](/pt/copilot/how-tos/copilot-cli/use-copilot-cli/allowing-tools).\n\n### Etapa 3: confirmar se a extensão está em execução\n\nExecute o `/extensions manage` comando para abrir o gerenciador de extensões. Sua extensão `tool-time` deve aparecer no grupo **Usuário** com status **em execução**. Pressione <kbd>Esc</kbd> para fechar o gerenciador.\n\n### Etapa 4: Experimente\n\n1. Ao contrário de um comando com barra, você não invoca uma ferramenta por conta própria — Copilot a chama quando isso for útil. Primeiro, dê a Copilot uma tarefa que envolva algumas chamadas de ferramentas, por exemplo:\n\n   ```copilot copy\n   Explore the files in the current directory and give me a short summary of what's here.\n   ```\n\n2. Quando Copilot terminar de responder, pergunte:\n\n   ```copilot copy\n   How long have tool calls taken so far this session?\n   ```\n\n   O agente chama a `session_tool_time` ferramenta, da nova extensão, e a usa para responder à sua pergunta.\n\n   > \\[!TIP]\n   > Você pode confirmar que o agente usou a nova ferramenta examinando o início da Copilotresposta. A resposta deve ser prefixada pelo nome da ferramenta que foi usada; nesse caso, `session_tool_time`.\n\n### Como a ferramenta funciona\n\nA única chamada para `joinSession` é o que transforma um arquivo Node.js simples em uma extensão Copilot CLI. Ele conecta o processo em execução à sessão e registra tudo o que a extensão adiciona à CLI, nesse caso, uma única ferramenta.\n\nUma ferramenta é definida por estes campos:\n\n* **`name`**— o identificador Copilot usa para chamar a ferramenta.\n* **`description`**— o que a ferramenta faz. O modelo depende desse texto para decidir quando chamar a ferramenta, portanto, vale a pena ser explícito. Essa descrição informa ao modelo que ele não é informado sobre esses intervalos em si, o que o orienta a chamar a ferramenta em vez de tentar resolver os tempos de outra maneira.\n* **`parameters`**— um esquema JSON que descreve os argumentos da ferramenta. Essa ferramenta não usa nenhuma, portanto, o esquema é um objeto sem propriedades.\n* **`handler`**— uma função assíncrona que é executada quando Copilot chama a ferramenta. Qualquer cadeia de caracteres retornada torna-se o resultado da ferramenta, que o modelo lê.\n\nDois campos adicionais moldam como a ferramenta é oferecida ao modelo:\n\n* **`defer: \"never\"`**— mantém a descrição da ferramenta na lista de ferramentas do modelo o tempo todo. Por padrão, quando muitas ferramentas estão disponíveis, a CLI pode adiar ferramentas raramente usadas e permitir que o modelo as pesquise sob demanda. Definir `defer` como `\"never\"` exclui esta ferramenta desse comportamento, portanto, Copilot sempre o vê.\n\n  > \\[!IMPORTANT]\n  > `defer: \"never\"` simplesmente torna a ferramenta *disponível* para Copilot. Não \\_força\\_Copilot a chamá-lo. Não há como uma extensão exigir que uma ferramenta específica sempre seja usada se houver um meio alternativo de gerar uma resposta apropriada a um prompt. O modelo sempre decide por si mesmo qual ferramenta usar. Neste exemplo, a nova ferramenta é usada de forma confiável porque não há outra maneira de o modelo conhecer as informações fornecidas pela ferramenta.\n\n* **`skipPermission: true`** permite que a ferramenta seja executada sem solicitar que você aprove cada chamada. Isso é apropriado aqui porque a ferramenta lê somente totais que a extensão já coletou; ele não toca em seus arquivos nem executa comandos.\n\nOs tempos são coletados observando a sessão. A extensão se inscreve em dois eventos que a CLI emite em torno de cada chamada de ferramenta:\n\n```javascript\nsession.on(\"tool.execution_start\", (event) => { /* ... */ });\nsession.on(\"tool.execution_complete\", (event) => { /* ... */ });\n```\n\nUm `tool.execution_start` evento carrega o nome da ferramenta (`event.data.toolName`). Um evento `tool.execution_complete` contém um sinalizador `success`. Nenhum evento carrega as informações do outro, portanto, a extensão as correlaciona usando a `toolCallId` que aparece em cada um: quando uma ferramenta é iniciada, ela registra a hora atual sob essa ID. Quando a conclusão correspondente chega, o tempo decorrido em milissegundos é adicionado ao total acumulado. A ferramenta desconsidera suas próprias chamadas para que a figura reflita o trabalho real de Copilot.\n\nComo os totais residem no processo de extensão de longa duração, eles abrangem toda a sessão. Esse é o tipo de tarefa em que as extensões são boas: observar o que está acontecendo na sessão e manter o estado entre chamadas.\n\n> \\[!NOTE]\n>\n> * Os totais são mantidos na memória, portanto, são redefinidos sempre que a extensão é recarregada ou a sessão é reiniciada (por exemplo, depois `/clear`).\n> * O valor mostrado é o tempo de relógio medido do ponto de vista da extensão — o intervalo entre os eventos de início e conclusão de cada invocação de ferramenta —, portanto inclui também qualquer tempo em que uma chamada ficou aguardando sua aprovação.\n\n## Exemplo de extensão 2: um comando slash para uso de tokens\n\nEste exemplo adiciona uma extensão de projeto chamada `token-counter`. A extensão adiciona um comando slash `/tokencount` que permite verificar quantos tokens você usou ao interagir com Copilot na CLI. Você executa `/tokencount start` quando deseja começar a medir o uso do token e, em seguida, pode executar `/tokencount` em qualquer ponto posterior para verificar quantos tokens você usou desde que iniciou a contagem.\n\nA extensão mantém um total acumulado de tokens usados na sessão ao se inscrever em eventos emitidos pela CLI, algo que um comando único de shell não pode fazer.\n\n### Etapa 1: Criar o arquivo de extensão\n\n1. Na raiz do repositório Git para seu projeto, crie os seguintes diretórios e arquivo:\n\n   ```text\n   .github/extensions/token-counter/extension.mjs\n   ```\n\n2. Adicione este código a `extension.mjs`:\n\n   ```javascript copy\n   // Extension: token-counter\n   // Adds a /tokencount slash command that reports how many tokens you've used\n   // since you started counting.\n\n   import { joinSession } from \"@github/copilot-sdk/extension\";\n\n   // Module-level state. The extension runs as a single long-lived process for\n   // the whole session, so these values persist between command invocations.\n   let tokensUsed = 0; // Running total of tokens used so far this session.\n   let startedAt = null; // tokensUsed when \"/tokencount start\" was last run.\n   // null = not started.\n   // startedAt allows you to count tokens multiple times in a session.\n\n   const session = await joinSession({\n       commands: [\n           {\n               name: \"tokencount\",\n               description: \"Report how many tokens you've used since \" +\n                   \"'/tokencount start'.\",\n               handler: async (ctx) => {\n                   const arg = (ctx.args ?? \"\").trim();\n\n                   if (arg === \"start\") {\n                       // Reset: remember the current total as the new baseline.\n                       startedAt = tokensUsed;\n                       await session.log(\n                           \"Token counter started. Run '/tokencount' later to \" +\n                           \"see how many tokens you've used.\",\n                           { level: \"info\" },\n                       );\n                       return;\n                   }\n\n                   if (startedAt === null) {\n                       await session.log(\n                           \"The token counter has not been started. Start by \" +\n                           \"entering '/tokencount start'.\",\n                           { level: \"info\" },\n                       );\n                       return;\n                   }\n\n                   const used = tokensUsed - startedAt;\n                   await session.log(\n                       `You have used ${used} tokens since entering ` +\n                       \"'/tokencount start'.\",\n                       { level: \"info\" },\n                   );\n               },\n           },\n       ],\n   });\n\n   // The CLI emits an \"assistant.usage\" event after each assistant turn. Add the\n   // tokens it reports to a running total kept in the extension's memory.\n   session.on(\"assistant.usage\", (event) => {\n       const { inputTokens = 0, outputTokens = 0 } = event.data ?? {};\n       tokensUsed += inputTokens + outputTokens;\n   });\n   ```\n\n### Etapa 2: Carregar a extensão\n\nInicie uma sessão interativa no mesmo repositório, com recursos experimentais habilitados:\n\n```shell copy\ncopilot ‑‑experimental\n```\n\nSe você já tiver uma sessão aberta, poderá executar `/clear` para iniciar uma nova sessão, que recarrega extensões do disco.\n\n### Etapa 3: confirmar se a extensão está em execução\n\nExecute o `/extensions manage` comando para abrir o gerenciador de extensões. A extensão `token-counter` deve aparecer no grupo **Project** com o status **em execução**. Pressione <kbd>Esc</kbd> para fechar o gerenciador.\n\nVocê também pode executar `/env` para ver um resumo de tudo o que foi carregado na sessão, incluindo extensões.\n\n### Etapa 4: Experimente\n\nDiferentemente de uma ferramenta, você mesmo executa um comando slash. Inicie o contador:\n\n```copilot copy\n/tokencount start\n```\n\nEnvie um ou dois prompts para Copilot para que use alguns tokens — por exemplo, peça que explique um arquivo. Em seguida, verifique quantos tokens você usou:\n\n```copilot copy\n/tokencount\n```\n\nSe você executar `/tokencount start` novamente, a contagem será reiniciada de zero.\n\n### Como o exemplo funciona\n\nA chamada para `joinSession` registra tudo o que a extensão adiciona à CLI — neste caso, um único comando slash.\n\nUm comando com barra é definido por três campos:\n\n* **`name`**— o nome do comando, sem a barra inicial. Registrar `tokencount` é o que torna `/tokencount` disponível na sessão.\n* **`description`**—o texto exibido ao lado do comando no seletor de comandos com barra.\n* **`handler`**— uma função assíncrona que é executada quando você invoca o comando. Ele recebe um objeto de contexto cuja `args` propriedade contém o texto bruto digitado após o nome do comando. Para `/tokencount start`, `ctx.args` é `\"start\"`; para um `/tokencount` simples, é uma string vazia.\n\nO manipulador grava sua saída de volta para a sessão com `session.log(message, { level: \"info\" })`, que imprime a mensagem na transcrição.\n\nPara saber quantos tokens foram usados, a extensão se inscreve em um evento de sessão:\n\n```javascript\nsession.on(\"assistant.usage\", (event) => {\n    const { inputTokens = 0, outputTokens = 0 } = event.data ?? {};\n    tokensUsed += inputTokens + outputTokens;\n});\n```\n\nCLI emite um evento `assistant.usage` após cada turno do assistente, incluindo as contagens de tokens de entrada e de saída desse turno. A extensão os adiciona ao total em execução em `tokensUsed`. Quando você executa `/tokencount start`, o manipulador registra o total atual em `startedAt`. Inserir `/tokencount` sem argumentos mais tarde na sessão informa a diferença. Como ambas as variáveis vivem no processo de extensão de longa duração, elas persistem durante toda a sessão.\n\n> \\[!NOTE]\n> Os totais são mantidos na memória, portanto, são redefinidos sempre que a extensão é recarregada ou a sessão é reiniciada (por exemplo, depois `/clear`).\n\n## Editando e recarregando uma extensão\n\nAo desenvolver uma extensão, você vai editar `extension.mjs` e vai querer ver suas alterações. Depois de salvar o arquivo, você pode pegar a nova versão de qualquer uma destas maneiras:\n\n* Peça Copilot para recarregar as extensões, por exemplo: `Reload my extensions`.\n* Execute `/clear` para iniciar uma nova sessão, que recarrega extensões do disco.\n* Reinicie a CLI.\n\nSe uma extensão falhar ao iniciar ou se comportar inesperadamente, execute `/extensions manage` e inspecione a extensão para ver seu status e o caminho para o arquivo de log. Cada extensão grava um log em `~/.copilot/logs/extensions/`, que é o melhor lugar para procurar quando algo dá errado.\n\n## Próximas Etapas \n\n* Adapte um desses exemplos às suas próprias necessidades. Na CLI, peça Copilot para modificar o comportamento de qualquer uma das extensões de exemplo.\n* Compartilhe uma extensão no nível do usuário. Por exemplo, mova a `tool-time` extensão para o diretório de `.github/extensions/` um repositório para compartilhá-la com todos que trabalham nesse repositório.\n* Peça Copilot para criar uma nova extensão do zero para você.\n  Copilot CLI as extensões são alimentadas pelo Copilot SDK, portanto, uma extensão pode fazer qualquer coisa que o SDK possibilita, permitindo que você adicione exibições interativas com botões e formulários, bem como novas ferramentas e comandos. Consulte [SDK do Copilot](/pt/copilot/how-tos/copilot-sdk).\n\n## Leitura adicional\n\n* [referência de comando da CLI GitHub Copilot](/pt/copilot/reference/copilot-cli-reference/cli-command-reference)"}