checklist-qa
v0.6.1
Published
Conversational QA checklist interview engine, independent of any LLM provider.
Maintainers
Readme
checklist-qa
Transforma uma entrevista de QA (conduzida por qualquer LLM) numa experiência conversacional interativa, e entrega ao final um arquivo checklistQA.md pronto para uso.
O pacote não sabe nada sobre QA — todas as perguntas, regras de negócio e formato do checklist vivem inteiramente no prompt de entrevista (prompts/checklist-interview.md). O pacote apenas orquestra a conversa: envia o histórico ao seu provider de IA, guarda as respostas, detecta o fim da entrevista e disponibiliza o markdown resultante.
- Independente de modelo de IA: funciona com OpenAI, Anthropic, Gemini, Ollama, Azure OpenAI, DeepSeek ou qualquer outro, através de uma única interface (
LLMProvider). - TypeScript com tipagem completa, ESM + CommonJS, Node 20+.
- Zero perguntas hardcoded no código — tudo vem do prompt.
Instalação
npm install checklist-qaCLI
O pacote inclui um CLI mínimo que roda a entrevista direto no terminal, usando o prompt embutido no pacote — útil para testar sem escrever código:
npx checklist-qa --provider anthropic| Flag | Descrição |
| --- | --- |
| --provider <nome> | openai, anthropic ou ollama. Se omitido, é detectado a partir de ANTHROPIC_API_KEY > OPENAI_API_KEY_CHECKLIST > Ollama local. |
| --model <nome> | Nome do modelo (padrão depende do provider). |
| --prompt <arquivo> | Prompt de entrevista customizado (padrão: prompts/checklist-interview.md do pacote). |
| --output-dir <dir> | Diretório onde checklistQA.md será gravado (padrão: diretório atual). |
| --context-dir <dir> | Diretório onde procurar a pasta .diffai/ para usar como contexto adicional da entrevista (padrão: diretório atual). |
| --no-extension-guess | Desliga a heurística de classificar arquivos como Backend/Frontend pela extensão (.js = Backend, .ts = Frontend) quando não há indicação explícita no contexto. Use em projetos onde essa convenção não vale (ex.: backend em TypeScript). Ativa por padrão quando a flag é omitida. |
| -h, --help | Mostra a ajuda. |
Antes de iniciar a entrevista, o CLI consulta o npm para checar se a versão instalada é a mais recente publicada de checklist-qa e bloqueia a execução (com instruções de atualização) se não for. Se a consulta ao registro falhar (ex.: sem internet), o CLI apenas avisa e segue com a versão instalada, em vez de travar.
Contexto adicional (.diffai/)
Se o diretório de contexto (padrão: onde o CLI é executado, ou o valor de --context-dir) contiver uma pasta .diffai/, o CLI lê todos os arquivos dessa pasta recursivamente e anexa o conteúdo ao prompt de entrevista antes de iniciar a conversa. A IA analisa esse contexto antes de perguntar qualquer coisa e gera as perguntas dinamicamente a partir dele. docs/ (ex.: docs/analysis.md) não é lida: é apenas uma renderização em prosa do mesmo conteúdo de .diffai/analysis.json, então incluí-la também só duplicaria informação no prompt sem agregar nada novo.
Cada pergunta é apresentada já com uma resposta sugerida, pré-preenchida a partir do contexto e editável: no CLI, a sugestão abre no seu editor de texto ($VISUAL/$EDITOR, ou Notepad no Windows / nano nos demais), onde o desenvolvedor edita à vontade em várias linhas, salva e fecha para enviar. Quando o contexto não permite sugerir nada com segurança, o editor abre em branco. Se o contexto identificar mais de uma funcionalidade, elas são enumeradas (Funcionalidade 1, 2, ...) e tratadas separadamente na entrevista e no checklist. Ao final, o checklistQA.md combina o contexto (.diffai/) com as respostas confirmadas, destacando as mudanças importantes no sistema e os pontos de atenção.
Em entradas não interativas (stdin via pipe), o CLI faz fallback para uma leitura de linha única, sem abrir editor.
Se a pasta não existir, o comportamento é idêntico ao anterior: a entrevista é conduzida sem contexto extra, e nenhuma resposta é pré-preenchida.
Para usar essa mesma lógica fora do CLI, a classe ContextLoader está disponível publicamente:
import { ContextLoader } from "checklist-qa";
const context = await ContextLoader.loadFromDirectories(["./.diffai"]);Classificação Backend/Frontend gerada por código
Antes, a IA precisava interpretar sozinha os arquivos .diffai/analysis.*.json para decidir quais testes eram de backend e quais de frontend — e frequentemente errava, misturando os dois lados. Agora o CLI faz essa separação por código, de forma determinística, com a classe DiffaiClassifier: ele lê os arquivos analysis.backend-*.json e analysis.frontend-*.json, usa o lado declarado no nome de cada análise como autoridade (conferindo com o caminho de cada arquivo) e anexa ao prompt um bloco "Classificação Backend/Frontend determinada por código (AUTORITATIVA)" com as listas prontas de testes e arquivos de cada lado. A IA é instruída a copiar essa classificação exatamente como está — em vez de reinferi-la — e a não inventar arquivos que não constem do contexto. Nomes de teste "nus" (sem caminho), como transactionModel.test.js ou new-sale.component.spec.ts, também são classificados corretamente porque o lado vem do nome da análise de origem.
A flag --no-extension-guess também vale aqui: com ela, arquivos que não tenham lado determinável pelo nome da análise nem pelo caminho ficam marcados como indeterminado em vez de serem chutados pela extensão. Para usar a classificação fora do CLI:
import { DiffaiClassifier } from "checklist-qa";
const classification = await DiffaiClassifier.classifyDirectory("./.diffai");
const block = DiffaiClassifier.buildContextBlock(classification);Variáveis de ambiente usadas pelos providers embutidos: ANTHROPIC_API_KEY, OPENAI_API_KEY_CHECKLIST e OLLAMA_BASE_URL (opcional, padrão http://localhost:11434). São os mesmos providers mínimos descritos em examples/providers — o CLI é só um ponto de entrada de terminal para o mesmo ChecklistQA. Use VISUAL ou EDITOR para escolher o editor em que as respostas são editadas (padrão: Notepad no Windows, nano nos demais).
O CLI carrega automaticamente um arquivo .env do diretório onde for executado (não do diretório do pacote), sem sobrescrever variáveis já exportadas no shell.
Uso rápido
import { ChecklistQA, PromptLoader } from "checklist-qa";
import { myProvider } from "./my-provider.js";
const prompt = await PromptLoader.loadFromFile("./node_modules/checklist-qa/prompts/checklist-interview.md");
const qa = new ChecklistQA({
provider: myProvider,
prompt,
});
let question = await qa.start();
while (!qa.isFinished()) {
console.log(question);
// Resposta sugerida a partir do contexto (.diffai): apresente-a já preenchida e editável.
const answer = await getAnswerFromUser(qa.suggestedAnswer()); // sua UI, CLI, etc.
question = await qa.answer(answer);
}
console.log(qa.getMarkdown()); // conteúdo final do checklistQA.md
await qa.download(); // grava checklistQA.md em disco (Node) ou dispara o download (browser)Você também pode copiar prompts/checklist-interview.md para o seu próprio projeto e ajustá-lo, desde que mantenha o marcador <QA_CHECKLIST_READY> (veja Como funciona a entrevista).
Configuração
interface ChecklistQAOptions {
provider: LLMProvider; // obrigatório — seu adaptador de IA
prompt: string; // obrigatório — texto do prompt de entrevista
outputFileName?: string; // padrão: "checklistQA.md"
autoDownload?: boolean; // padrão: false — baixa/gera o arquivo automaticamente ao concluir
marker?: string; // padrão: "<QA_CHECKLIST_READY>"
suggestionMarker?: string; // padrão: "<RESPOSTA_SUGERIDA>" — separa a pergunta da resposta pré-preenchida
progressMarker?: string; // padrão: "<PROGRESSO>" — precede a estimativa "pergunta atual/total"
sessionId?: string; // padrão: gerado automaticamente (crypto.randomUUID)
}API
| Método | Descrição |
| --- | --- |
| qa.start() | Envia o prompt ao provider e retorna a primeira pergunta. |
| qa.answer(texto) | Envia a resposta do usuário e retorna a próxima pergunta ("" quando a entrevista termina). |
| qa.question() | Última pergunta feita pela IA. |
| qa.suggestedAnswer() | Resposta sugerida (pré-preenchida a partir do contexto) para a última pergunta ("" quando não há). |
| qa.progress() | { current, total } autorreportado pela IA para a última pergunta (undefined quando não informado). total é uma estimativa que pode mudar entre perguntas. |
| qa.isFinished() | true quando o marcador de conclusão foi detectado. |
| qa.getMarkdown() | Conteúdo do checklistQA.md (undefined até a entrevista terminar). |
| qa.getHistory() | Histórico completo da conversa (nunca perde mensagens). |
| qa.download(outputDir?) | Grava o arquivo em disco (Node) ou dispara o download (browser). |
Criando um Provider
A única coisa que o pacote exige de um provider é:
interface LLMProvider {
chat(messages: Message[]): Promise<Message>;
}
type Role = "system" | "user" | "assistant";
interface Message {
role: Role;
content: string;
}Toda vez que uma pergunta precisa ser feita, o InterviewEngine chama provider.chat(historicoCompleto) e espera de volta uma única mensagem assistant. Você decide como essa chamada conversa com a IA por trás.
Exemplos completos ficam em examples/providers: OpenAI, Anthropic e Ollama. Um provider mínimo para qualquer serviço com API compatível:
import type { LLMProvider, Message } from "checklist-qa";
export class MyProvider implements LLMProvider {
async chat(messages: Message[]): Promise<Message> {
const content = await callMyLLM(messages);
return { role: "assistant", content };
}
}Como funciona a entrevista
qa.start()envia o prompt de entrevista (mensagemsystem) para oLLMProvidere recebe a primeira pergunta.A cada
qa.answer(resposta), a resposta do usuário é adicionada ao histórico e o histórico completo é reenviado ao provider — o pacote nunca trunca ou reescreve mensagens anteriores.O pacote nunca mostra mais de uma pergunta por vez — isso é responsabilidade do prompt, que já instrui a IA a perguntar um item por mensagem.
Cada pergunta pode vir acompanhada de uma resposta sugerida (derivada do contexto), separada da pergunta pelo marcador
<RESPOSTA_SUGERIDA>. OInterviewEnginesepara a pergunta (antes do marcador) da sugestão (depois dele) e expõe a sugestão viaqa.suggestedAnswer()— apresente-a já preenchida e editável na sua UI. Se a pergunta não tiver marcador,qa.suggestedAnswer()retorna"". 4b. Cada pergunta também pode vir com uma estimativa de progresso, no formato<PROGRESSO>\npergunta_atual/total_estimado. Como a entrevista é dinâmica (sem lista fixa de perguntas), ototalé a própria IA quem estima e pode revisar a cada pergunta. OInterviewEngineexpõe isso viaqa.progress()(undefinedquando a pergunta não trouxe a estimativa).Quando a IA decide que a entrevista terminou, ela responde exatamente com o marcador:
<QA_CHECKLIST_READY>seguido, na mesma mensagem, do conteúdo completo do
checklistQA.mdem Markdown.O
InterviewEnginedetecta o marcador, separa qualquer texto antes dele (última "pergunta", normalmente vazia) do conteúdo após ele (o Markdown), marca a sessão como finalizada e armazena o Markdown.A partir daí,
qa.isFinished()retornatrueeqa.getMarkdown()/qa.download()ficam disponíveis.
Use as opções marker, suggestionMarker e progressMarker em ChecklistQAOptions caso seu prompt use marcadores diferentes.
Geração e download do Markdown
qa.getMarkdown()retorna a string do Markdown assim que a entrevista termina.qa.download(outputDir?):- Node: grava
checklistQA.md(ou ooutputFileNameconfigurado) em disco viafs/promises, opcionalmente dentro deoutputDir, e retorna o caminho gravado. - Browser: cria um
Blobe dispara o download pelo navegador (sem depender de nenhum framework).
- Node: grava
- Configure
autoDownload: truepara que o download aconteça automaticamente assim queqa.isFinished()se tornartrue, sem precisar chamarqa.download()manualmente.
FAQ
Preciso reescrever as perguntas da entrevista no código?
Não. Todas as perguntas, regras e o formato do checklist final vivem em prompts/checklist-interview.md. O pacote só orquestra o fluxo.
Posso usar qualquer LLM?
Sim. Implemente LLMProvider (um único método, chat) para o serviço que preferir. O pacote nunca importa um SDK de IA específico.
O que acontece se a IA esquecer o marcador <QA_CHECKLIST_READY>?
A entrevista nunca é marcada como concluída e qa.getMarkdown()/qa.download() continuam indisponíveis — ajuste o prompt ou o marker configurado se isso acontecer com frequência.
Funciona em CommonJS? Sim, o pacote publica builds ESM e CommonJS com tipos para ambos.
Como troco de provider no meio do desenvolvimento?
Basta passar uma instância diferente em provider ao criar o ChecklistQA — nada mais no pacote precisa mudar.
