Work Item → Markdown (para IA)
Extensão do Azure DevOps (web) que exporta um work item — e as tarefas
filhas ainda pendentes — para Markdown, junto com os anexos, num .zip.
O fluxo que ela atende:
- Você abre a tarefa no Azure DevOps pelo browser.
- Clica em Exportar para Markdown (IA) no menu
… do work item — abre a
página de exportação com o progresso.
- Baixa o
.zip.
- Descompacta na raiz do repositório, abre o
.md no VS Code e manda o Claude
Code implementar.
É a irmã web da extensão de VS Code deste mesmo repositório: as duas produzem
exatamente o mesmo Markdown, porque compartilham src/markdown.ts (conversão
HTML→Markdown, recursão nas filhas pendentes e o bloco de instruções para a IA).
Onde o botão aparece
| Contribuição |
Onde fica |
ms.vss-work-web.work-item-form-toolbar-menu |
menu … do formulário do work item aberto |
ms.vss-work-web.work-item-context-menu |
botão direito na lista de queries |
ms.vss-work-web.backlog-item-menu |
botão direito no backlog |
ms.vss-work-web.query-result-work-item-menu |
resultado de query |
As ações navegam para páginas (hubs) em Boards, não para diálogos modais: o
openCustomDialog do Azure DevOps abre com o título correto e conteúdo em
branco nesta organização, enquanto o mesmo código servido como hub renderiza
sem alteração. As páginas também podem ser abertas direto pelo menu de Boards.
No backlog e nas queries dá para selecionar vários itens de uma vez — cada um
vira uma pasta wi-<id>/ dentro do zip.
O que sai no zip
Um item:
wi-1234.md
anexos/diagrama.png
anexos/contrato.pdf
Vários itens:
wi-1234/wi-1234.md
wi-1234/anexos/...
wi-1235/wi-1235.md
Os links no Markdown apontam para anexos/... — caminho relativo ao .md —,
então o Claude Code abre os arquivos direto depois de descompactar.
Relatório de acompanhamento
Em Boards → Relatório de acompanhamento há um hub que gera o mesmo relatório
HTML da extensão do VS Code: capa com cliente e período, resumo executivo,
entregas agrupadas por tipo e a atividade de desenvolvimento.
Escolha o período (7/14/30 dias, mês atual ou personalizado), opcionalmente o
nome do cliente, e gere. A prévia aparece num iframe; Imprimir / Salvar PDF
imprime só o relatório, sem o cromo do portal em volta.
Uma diferença em relação à versão do VS Code, e ela é a favor da web: lá os
commits vêm do git log dos clones que você tem em disco; aqui vêm da REST API
de Git do Azure DevOps, então cobrem todos os repositórios do projeto,
inclusive os que você nunca clonou. O relatório sai como uma seção só do
projeto, com o nome do repositório prefixando cada commit quando há mais de um.
O filtro "Somente meus itens" usa @Me na WIQL para os work items e o seu nome
de exibição no filtro de autor da API de Git. Se o user.name configurado nos
seus commits for diferente do nome de exibição do Azure DevOps, desmarque a
caixa para não perder commits.
Autenticação
Não usa PAT. A extensão roda dentro do portal e recebe o token da sessão do
próprio usuário pelo SDK. Os escopos declarados são vso.work_write (ler work items e — só quando você
confirma no diálogo — comentar, mudar estado e criar tarefas filhas) e
vso.code (ler commits, para o relatório). Quem instala vê apenas o que já
veria no Azure DevOps.
vso.code entrou na 0.2.0 e vso.work_write na 0.3.0. Aumento de escopo
exige que um administrador da organização reautorize a extensão na
atualização. Nenhuma escrita acontece sem você clicar em Aplicar.
Aplicar retorno da IA
O agente não escreve na sua board e não recebe credencial nenhuma. Ele
termina a resposta com o JSON do que fez — sem cerca de código:
{
"workItem": 793,
"comment": "Removido o objetivo da aba...",
"state": "Done",
"children": [{ "title": "Cobrir com teste unitário", "description": "..." }]
}
O parser aceita as duas formas — cru ou cercado, com ou sem a marca json, e
mesmo com a cerca colada no { da mesma linha.
Ele também repara as duas deformações que um retorno de agente realmente sofre:
- quebras de linha cruas dentro de strings, que aparecem sempre que o texto
passa por terminal ou editor com quebra automática;
- aspas duplas sem escape no meio da prosa (
o toggle "Exemplos" continua).
Dentro de uma string, uma " só fecha se o próximo caractere não-branco for
,, }, ] ou :; qualquer outra coisa indica aspa literal.
O caso ambíguo — aspa literal seguida de vírgula, como ele disse "oi", e saiu
— não tem solução sem um parser completo e é recusado com erro, nunca
interpretado por adivinhação. Reparo algum é perigoso aqui porque nada é escrito
sem a prévia: um reparo errado aparece na tela antes de virar comentário.
Você abre o work item, clica em Aplicar retorno da IA no menu …, cola a
resposta inteira (o bloco é localizado sozinho, não precisa recortar) e a
extensão mostra o que vai acontecer — comentário, mudança de estado e a lista
de filhas, cada um com seu checkbox. Nada é escrito antes de você clicar em
Aplicar, e a escrita usa a sua sessão do portal.
Três decisões de segurança que valem saber:
- O item pai é sempre aquele em que você abriu o menu, nunca o que o texto
afirma ser. Divergência vira aviso na tela, não ação.
- Responsável e iteração das filhas vêm do pai lido da API, não do texto —
um retorno malformado não consegue atribuir tarefa a outra pessoa nem jogá-la
em outra sprint.
- Máximo de 20 filhas por aplicação, para um retorno malformado (ou um modelo
em loop) não encher a sprint.
O dropdown de estado é preenchido por getWorkItemTypeStates, então oferece os
estados reais do process template do projeto — nada de chutar entre Done,
Closed e Resolved. O padrão é o primeiro estado da categoria Completed.
A ordem de execução é deliberada: cria as filhas → fecha as filhas → comenta e
fecha o pai. Se algo falhar no meio, você não fica com o pai fechado e nenhuma
filha criada; cada ação reporta seu resultado e falha parcial aparece no log.
O bloco de instruções para a IA
O Markdown exportado termina com as instruções para o agente: rodar os testes e
não tocar no Azure DevOps — em vez disso, devolver o bloco de retorno acima.
Não há credencial em lugar nenhum do fluxo: nem PAT, nem az login, nem token.
O agente escreve texto; quem escreve na board é você, pelo diálogo, com a sua
sessão. Um Markdown que qualquer pessoa pode exportar não tem o direito de
mandar o agente dela sair atrás de credencial.
Desenvolvimento
npm install
npm run typecheck # tsc --noEmit, inclui o ../src/markdown.ts compartilhado
npm run build # webpack → dist/
npm run watch
Webpack e não esbuild de propósito: azure-devops-extension-sdk é publicado como
módulo AMD, que o webpack resolve nativamente e o esbuild não.
As chamadas REST não usam o getClient() do azure-devops-extension-api — ver
src/rest.ts. Aquele helper faz duas chamadas ao host antes de cada requisição
(LocationService.getResourceAreaLocation e getAccessToken), nenhuma com
timeout: quando o host não responde, a página congela em "carregando" sem erro
nenhum no console. rest.ts monta a URL a partir do nome da organização, põe
timeout em tudo e rotula cada chamada, então uma falha vira mensagem na tela.
De quebra o pacote saiu do runtime e os bundles caíram de 150KB para 21KB.
Publicar
O manifesto está com "public": true — a extensão fica visível para qualquer
organização na galeria do Azure DevOps. Para uma versão privada, compartilhada
só com organizações escolhidas, troque para "public": false e use
Share/Unshare no portal do publisher.
- Crie o publisher em https://marketplace.visualstudio.com/manage (o
publisher
do manifesto precisa bater com ele — hoje está LucasCostaBH). Essa etapa é só
na web: envolve aceitar o contrato de publisher do Marketplace.
- Gere um PAT com escopo Marketplace → Publish (não é o mesmo PAT de work
items).
- Empacote e publique:
npm run package # gera vsix/<publisher>.workitem-markdown-export-<versão>.vsix
npx tfx extension publish --manifest-globs vss-extension.json --token <PAT>
Cada publicação exige version maior no vss-extension.json.
Antes de publicar como pública, saiba que: o ID
<publisher>.workitem-markdown-export fica reservado para sempre; despublicar
tira da galeria mas não desinstala de quem já instalou; e um publisher não
verificado exibe um aviso para quem for instalar.
Ponto a validar na primeira execução
O iframe da extensão é sandboxed. O download é disparado por clique do usuário
justamente para maximizar a chance de o browser permitir — mas se o .zip não
baixar, o botão Copiar Markdown entrega o mesmo conteúdo (sem os anexos) e a
correção é trocar o download por HostNavigationService.openNewWindow.