Pular para o conteúdo

Grafo de código

Em vez de ler arquivos “às cegas”, o Context Code constrói um grafo de conhecimento do seu projeto: funções, classes, símbolos, imports e chamadas entre eles, em várias linguagens (TypeScript/JavaScript, Python, Rust, C/C++, C#, entre outras), além dos links internos da sua documentação Markdown.

  • Comunidades de código: módulos que se relacionam entre si, detectados automaticamente — a estrutura real do projeto, não a das pastas.
  • Nós centrais (“god nodes”): peças com dependências demais, candidatas a refatoração.
  • Conexões inesperadas: relações que atravessam comunidades ou pastas diferentes e que, à primeira vista, não parecem relacionadas.

O grafo não sai de uma busca de texto: os arquivos são realmente parseados (árvore de sintaxe, tree-sitter), então um nome dentro de uma string ou de um comentário não inventa uma relação.

  • Imports de TypeScript e JavaScript pelo AST: import … from, export … from, require(…) e import(…) dinâmico. Ao resolver o destino levam-se em conta os aliases do tsconfig.json/jsconfig.json (compilerOptions.paths e baseUrl, seguindo os extends), os barrels (index.ts, index.js…) e os re-exports: se a.ts faz export * from './b', o grafo também desenha a aresta até b. Um import { X } from "@/core" deixa de ser uma dependência “externa” e passa a apontar para o arquivo real.
  • Herança: class A extends B e implements em TypeScript, class A(B) em Python, impl Trait for Tipo em Rust e as classes base de C++ e C#. Aparecem como arestas próprias — Herança e Implementa —, separadas das chamadas.
  • C, C++ e C# também pelo AST: suas funções, classes, structs e métodos são extraídos com tree-sitter igual a TS/JS, Rust e Python. Seus #include e using continuam sendo resolvidos por padrão, e os namespace são ignorados de propósito (não são peças navegáveis).

Uma chamada de TypeScript nunca “pula” para uma função de Rust nem para uma de Python: são linguagens diferentes e o grafo não inventa essas arestas. Mas as duas costuras que mais importam num app cliente/servidor são detectadas e desenhadas.

Comandos do Tauri. Cada invoke("meu_comando") do front se une à fn meu_comando marcada com #[tauri::command] em Rust, com uma aresta Invoke Tauri. E se o comando não existe — um invoke para um nome que ninguém implementa mais, ou seja, um botão que não faz nada —, o grafo cria um nó quebrado e o conta à parte nas estatísticas.

Rotas HTTP. As rotas declaradas por Express, NestJS, FastAPI, Flask, ASP.NET ou axum viram nós de rota (GET /api/x) com uma aresta Rota → handler até a função que as atende.

Tudo isso fica resumido no relatório .context/grafo/GRAPH_REPORT.md, numa seção Pontes front↔back com duas listas bem concretas:

  • Invokes sem comando em Rust — cada linha é um botão que não faz nada, com o arquivo de onde é chamado.
  • Rotas sem handler identificado — rotas declaradas às quais não foi possível associar uma função.

Se o projeto não tem nem invokes nem rotas, a seção não aparece.

O grafo é explorado em uma visão 3D nativa: útil para entender de relance a arquitetura de um projeto grande, ver o que se conecta com o quê e examinar as relações de cada nó.

A visão 3D do grafo: comunidades de código, nós centrais e suas relações.

Na legenda, além dos tipos de sempre, há agora Rota HTTP entre os nós e quatro relações novas entre as arestas: Herança, Implementa, Invoke Tauri e Rota → handler. Cada entrada acende e apaga com um clique, e com o segundo botão você a isola (deixa só aquele tipo).

Atalhos de teclado dentro da visão:

TeclaO que faz
1 … 6Alternam Markdown, Pasta, Etiqueta, Quebrado, Código e MD+Código
7Alterna os nós de Rota HTTP
0Mostrar todos os tipos de novo
Ctrl+K / ⌘KSalta para a busca (filtrar por nome ou caminho)

O agente não lê o JSON do grafo: usa a ferramenta GraphQuery, que devolve texto já resumido e cortado em um teto de tokens. Além das consultas de sempre (summary, neighbors, subgraph, path, tag, orphans), a 3.6.9 traz quatro que respondem exatamente às perguntas que se fazem ao mexer em código alheio:

ConsultaPara que serve
exploreA mais útil: em uma única chamada devolve o código-fonte literal do símbolo, quem o chama, o que ele chama e seu raio de impacto.
symbolBusca símbolos por nome ou substring e lista arquivo, linha, tipo e quantas chamadas entram e saem de cada um.
callers / calleesQuem chama um símbolo, ou o que ele chama, agrupado por arquivo. Aceita depth de 1 a 3.
impactO que quebra se você mexer: quantos nós dependem dele, em quantos arquivos, detalhado por profundidade e com a lista de arquivos afetados. depth de 1 a 4, 2 por padrão.

Quando um resultado não cabe, o agente sabe: o impact avisa se o percurso chegou ao teto de nós e o explore avisa se teve de cortar o fonte.

Não é preciso saber nada disso para aproveitar. Basta perguntar em linguagem simples:

explique handle_livekit_join e o que quebra se eu mudar

O agente resolve as duas coisas com uma única consulta explore — traz a função inteira, quem a chama, o que ela chama e os arquivos que dependem dela — em vez de encadear meia dúzia de buscas e leituras de arquivos inteiros.

Um grafo não pode crescer sem fim, então há tetos: 20.000 símbolos, 20.000 chamadas e 12.000 imports. O que importa é como eles são repartidos: primeiro o código do seu projeto e só depois as pastas vendorizadas — as que terminam em -master, as runtime*, third_party, external, include e afins —, e dentro de cada grupo por profundidade e caminho.

É uma ordem determinista: duas regenerações seguidas dão o mesmo grafo. Antes, num repositório com dependências vendorizadas grandes, o teto era consumido por elas e o código próprio nem entrava.

O grafo é atualizado ao abrir a visão Grafo, com o comando /grafo no chat ou com o botão Regenerar da própria visão. Ao abrir a visão, ele pinta primeiro o grafo que já existia e só reprocessa se algum arquivo mudou desde a última vez; o botão Regenerar sempre reconstrói tudo.

O agente navega o grafo para localizar exatamente o trecho de código de que precisa, em vez de carregar arquivos inteiros no modelo. Menos contexto enviado significa menos tokens — respostas mais baratas e mais rápidas, sobretudo em projetos grandes.