# Criando extensões para GitHub Copilot CLI

Crie extensões que adicionam suas próprias ferramentas e comandos com barra ao Copilot CLI.

> \[!NOTE]
> GitHub Copilot CLI no momento, as extensões são um recurso experimental e estão sujeitas a alterações.

Uma 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.

Neste tutorial, você criará duas extensões simples como exemplos do que você pode fazer:

* Uma ferramenta, chamada `tool-time`, que Copilot pode chamar para relatar quanto tempo suas chamadas de ferramenta levaram até agora em uma sessão.
* Um comando slash, chamado `/tokencount`, que informa quantos tokens você usou desde o início da contagem.

Ambos 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).

> \[!WARNING]
> 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.

## Prerequisites

* **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).
* **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.
* **JavaScript**: As extensões são escritas em JavaScript, portanto, você precisará estar familiarizado com esse idioma para criar suas próprias extensões.
* **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.

## Exemplo de extensão 1: uma ferramenta de "tempo de uso"

Este 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.

Para 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.

### Etapa 1: Criar o arquivo de extensão

1. Crie o seguinte diretório e arquivo em seu diretório inicial:

   ```text
   ~/.copilot/extensions/tool-time/extension.mjs
   ```

   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.

2. Adicione este código a `extension.mjs`:

   ```javascript copy
   // Extension: tool-time
   // Adds a session_tool_time tool that reports how long Copilot's tool calls
   // have taken this session. Copilot is never told these timings and they
   // aren't written anywhere, so calling the tool is the only way to find
   // them out.

   import { joinSession } from "@github/copilot-sdk/extension";

   // The tool's own name, so it can avoid timing its own calls.
   const TOOL_NAME = "session_tool_time";

   // Module-level state persists for the whole session, because the extension
   // runs as a single long-lived process.
   const startTimes = new Map(); // tool call id -> Date.now() when call started
   let totalMs = 0; // total milliseconds spent across finished tool calls
   let callCount = 0; // number of finished tool calls measured

   const session = await joinSession({
       tools: [
           {
               name: TOOL_NAME,
               description:
                   "Report how long your tool calls have taken in total so far " +
                   "in THIS session, and how many calls that covers. You are " +
                   "never told how long your tool calls take and the timings " +
                   "aren't recorded anywhere you can read, so call this tool " +
                   "whenever you are asked about it rather than estimating.",
               // Always keep this tool's description in the model's tool list,
               // even when tool search is active, so Copilot reliably sees it:
               defer: "never",
               // Force a permissions approval prompt once, for this extension,
               // rather than on every call of this tool:
               skipPermission: true,
               parameters: { type: "object", properties: {} },
               handler: async () => {
                   const seconds = (totalMs / 1000).toFixed(1);
                   return `So far this session, Copilot's tool calls have taken ${seconds}s in total across ${callCount} call(s).`;
               },
           },
       ],
   });

   // When a tool starts, record the time, keyed by the tool call id so the
   // matching completion can be found later. The tool's own calls are skipped.
   session.on("tool.execution_start", (event) => {
       const data = event.data ?? {};
       if (data.toolName && data.toolName !== TOOL_NAME) {
           startTimes.set(data.toolCallId, Date.now());
       }
   });

   // When a tool finishes, add the elapsed time to the running total.
   session.on("tool.execution_complete", (event) => {
       const data = event.data ?? {};
       const startedAt = startTimes.get(data.toolCallId);
       if (startedAt === undefined) {
           return;
       }
       startTimes.delete(data.toolCallId);
       totalMs += Date.now() - startedAt;
       callCount += 1;
   });
   ```

> \[!NOTE]
> \*
> `@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.
>
> * 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.

### Etapa 2: Carregar a extensão

1. Inicie uma sessão interativa com recursos experimentais habilitados:

   ```shell copy
   copilot ‑‑experimental
   ```

   Como a extensão fica em `~/.copilot/extensions/`, você pode executar a CLI de qualquer diretório e a extensão estará disponível.

   Se você já tiver uma sessão aberta, execute `/clear` para iniciar uma nova sessão, que recarrega extensões do disco.

2. 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**.

   > \[!NOTE]
   > 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:
   >
   > ```shell copy
   > --allow-tool='extension-permission-access(user:tool-time)'
   > ```
   >
   > Para obter mais informações, consulte [Permitir e negar o uso da ferramenta](/pt/copilot/how-tos/copilot-cli/use-copilot-cli/allowing-tools).

### Etapa 3: confirmar se a extensão está em execução

Execute 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.

### Etapa 4: Experimente

1. 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:

   ```copilot copy
   Explore the files in the current directory and give me a short summary of what's here.
   ```

2. Quando Copilot terminar de responder, pergunte:

   ```copilot copy
   How long have tool calls taken so far this session?
   ```

   O agente chama a `session_tool_time` ferramenta, da nova extensão, e a usa para responder à sua pergunta.

   > \[!TIP]
   > 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`.

### Como a ferramenta funciona

A ú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.

Uma ferramenta é definida por estes campos:

* **`name`**— o identificador Copilot usa para chamar a ferramenta.
* **`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.
* **`parameters`**— um esquema JSON que descreve os argumentos da ferramenta. Essa ferramenta não usa nenhuma, portanto, o esquema é um objeto sem propriedades.
* **`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ê.

Dois campos adicionais moldam como a ferramenta é oferecida ao modelo:

* **`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ê.

  > \[!IMPORTANT]
  > `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.

* **`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.

Os 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:

```javascript
session.on("tool.execution_start", (event) => { /* ... */ });
session.on("tool.execution_complete", (event) => { /* ... */ });
```

Um `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.

Como 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.

> \[!NOTE]
>
> * 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`).
> * 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.

## Exemplo de extensão 2: um comando slash para uso de tokens

Este 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.

A 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.

### Etapa 1: Criar o arquivo de extensão

1. Na raiz do repositório Git para seu projeto, crie os seguintes diretórios e arquivo:

   ```text
   .github/extensions/token-counter/extension.mjs
   ```

2. Adicione este código a `extension.mjs`:

   ```javascript copy
   // Extension: token-counter
   // Adds a /tokencount slash command that reports how many tokens you've used
   // since you started counting.

   import { joinSession } from "@github/copilot-sdk/extension";

   // Module-level state. The extension runs as a single long-lived process for
   // the whole session, so these values persist between command invocations.
   let tokensUsed = 0; // Running total of tokens used so far this session.
   let startedAt = null; // tokensUsed when "/tokencount start" was last run.
   // null = not started.
   // startedAt allows you to count tokens multiple times in a session.

   const session = await joinSession({
       commands: [
           {
               name: "tokencount",
               description: "Report how many tokens you've used since " +
                   "'/tokencount start'.",
               handler: async (ctx) => {
                   const arg = (ctx.args ?? "").trim();

                   if (arg === "start") {
                       // Reset: remember the current total as the new baseline.
                       startedAt = tokensUsed;
                       await session.log(
                           "Token counter started. Run '/tokencount' later to " +
                           "see how many tokens you've used.",
                           { level: "info" },
                       );
                       return;
                   }

                   if (startedAt === null) {
                       await session.log(
                           "The token counter has not been started. Start by " +
                           "entering '/tokencount start'.",
                           { level: "info" },
                       );
                       return;
                   }

                   const used = tokensUsed - startedAt;
                   await session.log(
                       `You have used ${used} tokens since entering ` +
                       "'/tokencount start'.",
                       { level: "info" },
                   );
               },
           },
       ],
   });

   // The CLI emits an "assistant.usage" event after each assistant turn. Add the
   // tokens it reports to a running total kept in the extension's memory.
   session.on("assistant.usage", (event) => {
       const { inputTokens = 0, outputTokens = 0 } = event.data ?? {};
       tokensUsed += inputTokens + outputTokens;
   });
   ```

### Etapa 2: Carregar a extensão

Inicie uma sessão interativa no mesmo repositório, com recursos experimentais habilitados:

```shell copy
copilot ‑‑experimental
```

Se você já tiver uma sessão aberta, poderá executar `/clear` para iniciar uma nova sessão, que recarrega extensões do disco.

### Etapa 3: confirmar se a extensão está em execução

Execute 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.

Você também pode executar `/env` para ver um resumo de tudo o que foi carregado na sessão, incluindo extensões.

### Etapa 4: Experimente

Diferentemente de uma ferramenta, você mesmo executa um comando slash. Inicie o contador:

```copilot copy
/tokencount start
```

Envie 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:

```copilot copy
/tokencount
```

Se você executar `/tokencount start` novamente, a contagem será reiniciada de zero.

### Como o exemplo funciona

A chamada para `joinSession` registra tudo o que a extensão adiciona à CLI — neste caso, um único comando slash.

Um comando com barra é definido por três campos:

* **`name`**— o nome do comando, sem a barra inicial. Registrar `tokencount` é o que torna `/tokencount` disponível na sessão.
* **`description`**—o texto exibido ao lado do comando no seletor de comandos com barra.
* **`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.

O manipulador grava sua saída de volta para a sessão com `session.log(message, { level: "info" })`, que imprime a mensagem na transcrição.

Para saber quantos tokens foram usados, a extensão se inscreve em um evento de sessão:

```javascript
session.on("assistant.usage", (event) => {
    const { inputTokens = 0, outputTokens = 0 } = event.data ?? {};
    tokensUsed += inputTokens + outputTokens;
});
```

CLI 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.

> \[!NOTE]
> 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`).

## Editando e recarregando uma extensão

Ao 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:

* Peça Copilot para recarregar as extensões, por exemplo: `Reload my extensions`.
* Execute `/clear` para iniciar uma nova sessão, que recarrega extensões do disco.
* Reinicie a CLI.

Se 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.

## Próximas Etapas 

* 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.
* 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.
* Peça Copilot para criar uma nova extensão do zero para você.
  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).

## Leitura adicional

* [referência de comando da CLI GitHub Copilot](/pt/copilot/reference/copilot-cli-reference/cli-command-reference)