Visão Geral do Pacote
Este monorepo contém dois pacotes principais: @qwen-code/qwen-code e @qwen-code/qwen-code-core.
@qwen-code/qwen-code
Este é o pacote principal do Qwen Code. Ele é responsável pela interface do usuário, parsing de comandos e todas as outras funcionalidades voltadas ao usuário.
Quando este pacote é publicado, ele é empacotado em um único arquivo executável. Este bundle inclui todas as dependências do pacote, incluindo @qwen-code/qwen-code-core. Isso significa que, quer um usuário instale o pacote com npm install -g @qwen-code/qwen-code ou o execute diretamente com npx @qwen-code/qwen-code, ele estará usando este único executável autocontido.
@qwen-code/qwen-code-core
Esse pacote contém a lógica principal do CLI. Ele é responsável por fazer requisições API para os providers configurados, gerenciar autenticação e controlar o cache local.
Esse pacote não é bundled. Quando publicado, ele é distribuído como um pacote Node.js padrão com suas próprias dependências. Isso permite que ele seja usado como um pacote independente em outros projetos, se necessário. Todo o código JS transpilado na pasta dist está incluído no pacote.
Processo de Release
Este projeto segue um processo estruturado de release para garantir que todos os pacotes sejam versionados e publicados corretamente. O processo foi projetado para ser o mais automatizado possível.
Como fazer uma Release
As releases são gerenciadas através do workflow do GitHub Actions release.yml . Para realizar uma release manual de um patch ou hotfix:
- Navegue até a aba Actions do repositório.
- Selecione o workflow Release na lista.
- Clique no botão dropdown Run workflow.
- Preencha os inputs necessários:
- Version: A versão exata a ser lançada (ex:
v0.2.1). - Ref: O branch ou commit SHA a partir do qual será feito o release (o padrão é
main). - Dry Run: Deixe como
truepara testar o workflow sem publicar, ou defina comofalsepara realizar uma release real.
- Version: A versão exata a ser lançada (ex:
- Clique em Run workflow.
Releases Noturnas (Nightly)
Além das releases manuais, este projeto possui um processo automatizado de release noturna para fornecer a versão mais recente e instável (“bleeding edge”) para testes e desenvolvimento.
Processo
Todo dia à meia-noite UTC, o workflow de Release é executado automaticamente conforme agendado. Ele executa os seguintes passos:
- Faz o checkout do código mais recente a partir da branch
main. - Instala todas as dependências.
- Executa a suite completa de checks
preflighte testes de integração. - Se todos os testes passarem, calcula o próximo número de versão nightly (ex.:
v0.2.1-nightly.20230101). - Em seguida, faz o build e publica os pacotes no npm com a dist-tag
nightly. - Por fim, cria um GitHub Release para a versão nightly.
Tratamento de Falhas
Se qualquer etapa do workflow nightly falhar, ele criará automaticamente uma nova issue no repositório com as labels bug e nightly-failure. A issue conterá um link para a execução do workflow que falhou, facilitando o debug.
Como Usar a Nightly Build
Para instalar a última nightly build, utilize a tag @nightly:
npm install -g @qwen-code/qwen-code@nightlyTambém executamos um Google Cloud Build chamado release-docker.yml, que publica a imagem Docker do sandbox para corresponder ao seu release. Isso também será movido para o GitHub e combinado com o arquivo principal de release assim que as permissões da service account forem resolvidas.
Após o Release
Após a conclusão bem-sucedida do workflow, você pode acompanhar seu progresso na aba GitHub Actions . Uma vez concluído, você deve:
- Ir para a página de pull requests do repositório.
- Criar um novo pull request da branch
release/vX.Y.Zparamain. - Revisar o pull request (ele deve conter apenas atualizações de versão nos arquivos
package.json) e fazer o merge. Isso mantém a versão na branchmainatualizada.
Validação de Release
Após fazer o push de uma nova release, deve-se realizar um smoke test para garantir que os pacotes estão funcionando conforme o esperado. Isso pode ser feito instalando os pacotes localmente e executando um conjunto de testes para verificar se estão operando corretamente.
npx -y @qwen-code/qwen-code@latest --versionpara validar se o push funcionou como esperado, caso você não esteja fazendo um tag rc ou devnpx -y @qwen-code/qwen-code@<release tag> --versionpara validar se a tag foi publicada corretamente- Isso é destrutivo localmente
npm uninstall @qwen-code/qwen-code && npm uninstall -g @qwen-code/qwen-code && npm cache clean --force && npm install @qwen-code/qwen-code@<version> - É recomendado fazer um smoke test básico, executando alguns comandos e ferramentas de LLM para garantir que os pacotes estão funcionando conforme o esperado. Vamos formalizar isso mais no futuro.
Quando fazer merge da alteração de versão, ou não?
O padrão acima para criar releases de patch ou hotfix a partir de commits atuais ou antigos deixa o repositório no seguinte estado:
- A Tag (
vX.Y.Z-patch.1): Esta tag aponta corretamente para o commit original na main que contém o código estável que você pretendia lançar. Isso é crucial. Qualquer pessoa que fizer checkout desta tag obtém exatamente o código que foi publicado. - O Branch (
release-vX.Y.Z-patch.1): Este branch contém um novo commit em cima do commit marcado com a tag. Esse novo commit contém apenas a alteração do número da versão no package.json (e outros arquivos relacionados como package-lock.json).
Essa separação é boa. Ela mantém o histórico do seu branch main limpo de bumps de versão específicos para release até que você decida fazer merge deles.
Esta é a decisão crítica, e depende inteiramente da natureza do release.
Merge Back para Patches Estáveis e Hotfixes
Quase sempre você vai querer fazer o merge da branch release-<tag> de volta para main para qualquer patch estável ou release de hotfix.
- Por quê? O principal motivo é atualizar a versão no package.json da branch main. Se você lançar a v1.2.1 a partir de um commit mais antigo mas nunca fizer o merge da atualização de versão de volta, o package.json da sua branch main ainda vai dizer “version”: “1.2.0”. O próximo desenvolvedor que começar a trabalhar na próxima feature release (v1.3.0) vai estar criando uma branch a partir de uma base de código que tem um número de versão incorreto e desatualizado. Isso gera confusão e requer atualização manual da versão depois.
- O Processo: Após a branch release-v1.2.1 ser criada e o pacote ser publicado com sucesso, você deve abrir um pull request para fazer o merge de release-v1.2.1 em main. Este PR vai conter apenas um commit: “chore: bump version to v1.2.1”. É uma integração limpa e simples que mantém sua branch main sincronizada com a última versão lançada.
NÃO Faça Merge de Volta para Pré-Lançamentos (RC, Beta, Dev)
Normalmente, você não faz merge das branches de release para pré-lançamentos de volta para main.
- Por quê? Versões de pré-lançamento (ex: v1.3.0-rc.1, v1.3.0-rc.2) são, por definição, instáveis e temporárias. Você não quer poluir o histórico da sua branch principal com uma série de atualizações de versão para release candidates. O package.json no main deve refletir a versão mais recente e estável, não uma RC.
- O Processo: A branch release-v1.3.0-rc.1 é criada, o npm publish —tag rc acontece e então… a branch cumpriu seu propósito. Você pode simplesmente deletá-la. O código da RC já está no main (ou em uma feature branch), então nenhum código funcional é perdido. A release branch era apenas um veículo temporário para o número da versão.
Teste e Validação Local: Alterações no Processo de Empacotamento e Publicação
Se você precisar testar o processo de release sem publicar de fato no NPM ou criar um release público no GitHub, é possível acionar o workflow manualmente pela interface do GitHub.
- Acesse a aba Actions do repositório.
- Clique no dropdown “Run workflow”.
- Mantenha a opção
dry_runmarcada (true). - Clique no botão “Run workflow”.
Isso executará todo o processo de release, mas pulará os passos npm publish e gh release create. Você pode inspecionar os logs do workflow para garantir que tudo está funcionando conforme o esperado.
É essencial testar localmente quaisquer alterações no processo de empacotamento e publicação antes de fazer o commit. Isso assegura que os pacotes serão publicados corretamente e funcionarão como esperado quando instalados por um usuário.
Para validar suas alterações, você pode realizar um dry run do processo de publicação. Isso simulará a publicação sem efetivamente enviar os pacotes ao registry do npm.
npm_package_version=9.9.9 SANDBOX_IMAGE_REGISTRY="registry" SANDBOX_IMAGE_NAME="thename" npm run publish:npm --dry-runEste comando irá:
- Construir todos os pacotes.
- Executar todos os scripts de prepublish.
- Criar os tarballs dos pacotes que seriam publicados no npm.
- Exibir um resumo dos pacotes que seriam publicados.
Você pode então inspecionar os tarballs gerados para garantir que contenham os arquivos corretos e que os arquivos package.json tenham sido atualizados adequadamente. Os tarballs serão criados na raiz do diretório de cada pacote (ex: packages/cli/qwen-code-0.1.6.tgz).
Ao realizar um dry run, você pode ter confiança de que suas alterações no processo de empacotamento estão corretas e que os pacotes serão publicados com sucesso.
Análise Profunda do Release
O objetivo principal do processo de release é pegar o código-fonte do diretório packages/, fazer o build e montar um pacote limpo e autocontido em um diretório temporário chamado bundle na raiz do projeto. É esse diretório bundle que realmente é publicado no NPM.
Aqui estão as etapas principais:
Etapa 1: Verificações de Sanidade e Versionamento Pré-Release
- O que acontece: Antes de mover qualquer arquivo, o processo garante que o projeto esteja em bom estado. Isso envolve rodar testes, linter e verificação de tipos (
npm run preflight). O número da versão nopackage.jsonda raiz e empackages/cli/package.jsoné atualizado para a nova versão de release. - Por quê: Isso garante que apenas código de alta qualidade e funcional seja liberado. O versionamento é o primeiro passo para sinalizar uma nova release.
Etapa 2: Build do Código-Fonte
- O que acontece: O código TypeScript em
packages/core/srcepackages/cli/srcé compilado para JavaScript. - Movimentação de arquivos:
packages/core/src/**/*.ts→ compilado para →packages/core/dist/packages/cli/src/**/*.ts→ compilado para →packages/cli/dist/
- Por quê: O código TypeScript escrito durante o desenvolvimento precisa ser convertido em JavaScript puro para poder ser executado pelo Node.js. O pacote core é construído primeiro porque o pacote cli depende dele.
Etapa 3: Montagem do Pacote Final Publicável
Esta é a etapa mais crítica, onde os arquivos são movidos e transformados em sua forma final para publicação. Uma pasta temporária bundle é criada na raiz do projeto para armazenar o conteúdo final do pacote.
1. Transformação do package.json:
- O que acontece: O
package.jsondepackages/cli/é lido, modificado e salvo no diretóriobundle/da raiz. - Movimentação de arquivos:
packages/cli/package.json→ (transformação em memória) →bundle/package.json - Por quê: O
package.jsonfinal deve ser diferente do usado no desenvolvimento. Alterações importantes incluem:- Remoção das
devDependencies. - Remoção das dependências específicas do workspace:
{ "@qwen-code/core": "workspace:*" }, garantindo que o código do core seja embutido diretamente no arquivo JavaScript final. - Garantir que os campos
bin,mainefilesapontem para os locais corretos dentro da estrutura final do pacote.
- Remoção das
2. Criação do Bundle JavaScript:
- O que acontece: O JavaScript já compilado de
packages/core/distepackages/cli/disté empacotado em um único arquivo JavaScript executável. - Movimentação de arquivos:
packages/cli/dist/index.js+packages/core/dist/index.js→ (empacotado com esbuild) →bundle/gemini.js(ou nome similar). - Por quê: Isso cria um único arquivo otimizado contendo todo o código necessário da aplicação. Simplifica o pacote ao eliminar a necessidade de que o pacote core seja uma dependência separada no NPM, já que seu código agora está incluso diretamente.
3. Cópia de Arquivos Estáticos e de Suporte:
- O que acontece: Arquivos essenciais que não fazem parte do código-fonte mas são necessários para o funcionamento correto ou descrição adequada do pacote são copiados para o diretório
bundle. - Movimentação de arquivos:
README.md→bundle/README.mdLICENSE→bundle/LICENSEpackages/cli/src/utils/*.sb(perfis sandbox) →bundle/
- Por quê:
- O
README.mdeLICENSEsão arquivos padrão que devem estar presentes em qualquer pacote NPM. - Os perfis sandbox (arquivos
.sb) são recursos críticos em tempo de execução necessários para o recurso de sandboxing do CLI. Devem ficar junto ao executável final.
- O
Etapa 4: Publicação no NPM
- O que acontece: O comando
npm publishé executado a partir do diretóriobundlena raiz. - Por quê: Ao rodar
npm publishdentro do diretóriobundle, somente os arquivos cuidadosamente montados na Etapa 3 são enviados ao registro do NPM. Isso evita que código-fonte, arquivos de teste ou configurações de desenvolvimento sejam acidentalmente publicados, resultando em um pacote limpo e mínimo para os usuários.
Resumo do Fluxo de Arquivos
Esse processo garante que o artefato final publicado seja uma representação limpa, eficiente e feita sob medida do projeto — e não uma cópia direta do workspace de desenvolvimento.
NPM Workspaces
Este projeto usa NPM Workspaces para gerenciar os pacotes dentro deste monorepo. Isso simplifica o desenvolvimento, permitindo que a gente gerencie dependências e execute scripts em vários pacotes a partir da raiz do projeto.
Como Funciona
O arquivo package.json da raiz define os workspaces para este projeto:
{
"workspaces": ["packages/*"]
}Isso diz ao NPM que qualquer pasta dentro do diretório packages é um pacote separado que deve ser gerenciado como parte do workspace.
Benefícios dos Workspaces
- Gerenciamento Simplificado de Dependências: Executar
npm installna raiz do projeto irá instalar todas as dependências de todos os pacotes no workspace e fazer o link entre eles. Isso significa que você não precisa executarnpm installno diretório de cada pacote. - Linkagem Automática: Pacotes dentro do workspace podem depender uns dos outros. Quando você executa
npm install, o NPM cria automaticamente symlinks entre os pacotes. Isso significa que quando você faz alterações em um pacote, as mudanças ficam imediatamente disponíveis para outros pacotes que dependem dele. - Execução Simplificada de Scripts: Você pode rodar scripts em qualquer pacote a partir da raiz do projeto usando a flag
--workspace. Por exemplo, para executar o scriptbuildno pacotecli, você pode rodarnpm run build --workspace @qwen-code/qwen-code.