Os hooks executam scripts personalizados em momentos-chave do ciclo de vida do agente Qoder CN CLI. Eles permitem bloquear comandos perigosos, enviar notificações ao concluir tarefas ou aplicar lint automaticamente em arquivos modificados.
Defina os hooks em um arquivo de configuração JSON para que entrem em vigor imediatamente, sem necessidade de alterar o código.
Início rápido
Este exemplo impede que o Agente execute comandos rm -rf.
Etapa 1: Crie o script
mkdir -p ~/.qoder-cn/hooks
cat > ~/.qoder-cn/hooks/block-rm.sh << 'EOF'
#!/bin/bash
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command')
if echo "$command" | grep -q 'rm -rf'; then
echo "Dangerous command blocked: $command" >&2
exit 2
fi
exit 0
EOF
chmod +x ~/.qoder-cn/hooks/block-rm.sh
Etapa 2: Edite o arquivo de configuração
Adicione o conteúdo abaixo ao arquivo ~/.qoder-cn/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.qoder-cn/hooks/block-rm.sh"
}
]
}
]
}
}
Etapa 3: Verifique o resultado
Inicie o Qoder CN CLI e solicite ao Agente a execução de um comando que contenha rm -rf. O hook bloqueará a execução e notificará o Agente.
Configuração
Locais dos arquivos de configuração
O sistema carrega as configurações de hooks dos três arquivos listados abaixo. As definições de todos os níveis são mescladas e executadas:
~/.qoder-cn/settings.json # User-level: applies to all projects.
${project}/.qoder/settings.json # Project-level: applies to the current project. Can be committed to Git to share with your team.
${project}/.qoder/settings.local.json # Project-level (local): has the highest priority. Recommended to add to .gitignore.
Formato da configuração
{
"hooks": {
"EventName": [
{
"matcher": "match condition",
"hooks": [
{
"type": "command",
"command": "command to run",
"timeout": 60
}
]
}
]
}
}
Campos:
|
Campo |
Obrigatório |
Descrição |
|
|
Sim |
Defina como |
|
|
Sim |
Comando de shell a executar. |
|
|
Não |
Tempo limite em segundos. Padrão: 60. |
|
|
Não |
Condição de correspondência. Se omitido, o hook se aplica a todas as instâncias. |
Um único evento aceita vários grupos de correspondência (matcher), cada um contendo múltiplos comandos de hook.
Regras de correspondência
O campo matcher determina quando acionar um hook. Cada evento faz a correspondência com base em um campo diferente.
|
Sintaxe |
Descrição |
Exemplo |
||
|
Em branco ou |
Corresponde a tudo. |
Aciona para todas as ferramentas. |
||
|
Valor exato |
Correspondência exata. |
|
||
|
Delimitador |
` |
Corresponde a múltiplos valores. |
|
Edit"` corresponde à ferramenta Write ou Edit. |
|
Expressão regular |
Correspondência por expressão regular. |
|
Como escrever scripts de hook
Os scripts de hook recebem um payload JSON via stdin e usam códigos de saída e stdout para controlar o comportamento. Cada evento adiciona campos específicos à estrutura comum descrita abaixo.
Entrada
Todos os eventos incluem os seguintes campos no stdin:
|
Campo |
Descrição |
|
|
ID da sessão atual. |
|
|
Diretório de trabalho atual. |
|
|
Nome do evento que acionou o hook. |
Analise a entrada com jq:
#!/bin/bash
input=$(cat)
tool_name=$(echo "$input" | jq -r '.tool_name')
Saída
O hook controla o comportamento pelo código de saída: 0 indica sucesso; 2 bloqueia a operação (apenas em eventos compatíveis); qualquer outro valor diferente de zero representa um erro sem bloqueio. Alguns eventos também analisam um objeto JSON no stdout para oferecer controle refinado quando o código de saída é 0.
Variáveis de ambiente
Os scripts de hook podem acessar as seguintes variáveis de ambiente:
|
Variável |
Descrição |
|
|
Diretório de trabalho do projeto atual. |
Eventos suportados
O Qoder CN CLI oferece suporte aos seguintes eventos de hook durante o ciclo de vida da sessão.
SessionStart
Aciona ao iniciar uma sessão.
Campo de correspondência: Origem da sessão
|
Valor de correspondência |
Cenário de acionamento |
|
|
Início de uma nova sessão. |
|
|
Retomada de uma sessão existente. |
|
|
Conclusão da compactação de contexto. |
Campos adicionais de entrada:
{
"source": "startup",
"model": "Auto"
}
SessionEnd
Aciona ao terminar uma sessão.
Campo de correspondência: Motivo do encerramento
|
Valor de correspondência |
Cenário de acionamento |
|
|
O usuário fecha o prompt (por exemplo, pressionando Ctrl+D). |
|
|
A sessão termina por outros motivos. |
Campos adicionais de entrada:
{
"reason": "prompt_input_exit"
}
UserPromptSubmit
Aciona após o envio de um prompt pelo usuário, mas antes do processamento pelo Agente.
Campos adicionais de entrada:
{
"prompt": "Write a sorting function for me"
}
PreToolUse
Aciona antes da execução de uma ferramenta. Este hook pode bloquear essa execução.
matcher: Nome da ferramenta (como Bash, Write, Edit, Read, Glob, Grep ou um nome de ferramenta MCP como mcp__server__tool)
Campos adicionais de entrada:
{
"tool_name": "Bash",
"tool_input": {"command": "rm -rf /tmp/build"},
"tool_use_id": "toolu_01ABC123"
}
Bloquear a execução da ferramenta: Retorne o código de saída 2. O conteúdo enviado para stderr chega ao Agente como mensagem de erro.
PostToolUse
Aciona após a execução bem-sucedida de uma ferramenta.
Campo de correspondência: Nome da ferramenta
Campos adicionais de entrada:
{
"tool_name": "Write",
"tool_input": {"file_path": "/path/to/file.ts", "content": "..."},
"tool_response": "File written successfully",
"tool_use_id": "toolu_01ABC123"
}
PostToolUseFailure
Aciona quando falha a execução de uma ferramenta.
Campo de correspondência: Nome da ferramenta
Campos adicionais de entrada:
{
"tool_name": "Bash",
"tool_input": {"command": "npm test"},
"tool_use_id": "toolu_01ABC123",
"error": "Command exited with non-zero status code 1",
"is_interrupt": false
}
Stop
Aciona quando o Agente finaliza a resposta sem chamadas de ferramenta pendentes. Use este hook para impedir que o Agente pare e solicitar que continue.
Impedir que o Agente pare: Retorne o código de saída 2. O conteúdo do stderr é injetado na conversa para solicitar que o Agente continue.
SubagentStart / SubagentStop
Aciona quando um subagente inicia ou para. O evento SubagentStop funciona de maneira semelhante ao Stop e pode impedir que um subagente pare.
Campo de correspondência: Nome do tipo de agente
Campos adicionais de entrada:
{
"agent_id": "a1b2c3d4",
"agent_type": "task"
}
PreCompact
Aciona antes da compactação de contexto.
Campo de correspondência: Método de acionamento
|
Valor de correspondência |
Cenário de acionamento |
|
|
Execução manual de |
|
|
Acionamento automático da compactação quando a janela de contexto está cheia. |
Campos adicionais de entrada:
{
"trigger": "manual",
"custom_instructions": "Keep all tool call results"
}
Notification
Aciona em eventos de notificação, como solicitações de permissão ou conclusões de tarefas.
Campo de correspondência: Tipo de notificação
|
Valor de correspondência |
Cenário de acionamento |
|
|
Notificação de solicitação de permissão. |
|
|
Notificação referente a um resultado gerado pelo Agente. |
Campos adicionais de entrada:
{
"message": "Agent is requesting permission to run: rm -rf node_modules",
"title": "Permission Required",
"notification_type": "permission"
}
PermissionRequest
Aciona quando uma ferramenta exige autorização do usuário para execução.
Campo de correspondência: Nome da ferramenta
Campos adicionais de entrada:
{
"tool_name": "Bash",
"tool_input": {"command": "rm -rf node_modules"}
}
Casos de uso
Enviar notificações de desktop
Envie uma notificação de desktop do macOS quando o Agente concluir uma tarefa ou solicitar autorização. Salve o script abaixo em ~/.qoder-cn/hooks/notify.sh:
#!/bin/bash
input=$(cat)
message=$(echo "$input" | jq -r '.message')
if echo "$message" | grep -q "^Agent"; then
osascript -e 'display notification "Task completed" with title "Qoder CN CLI"'
else
osascript -e 'display notification "Authorization required" with title "Qoder CN CLI"'
fi
exit 0
Configuração:
{
"hooks": {
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "~/.qoder-cn/hooks/notify.sh"
}
]
}
]
}
}
Aplicar lint automaticamente em arquivos modificados
Aplique lint automaticamente em arquivos JavaScript e TypeScript após o Agente escrevê-los ou editá-los. Salve o script abaixo em ${project}/.qoder-cn/hooks/auto-lint.sh:
#!/bin/bash
input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path')
# Only check JS/TS files
case "$file_path" in
*.js|*.ts|*.jsx|*.tsx)
npx eslint "$file_path" --fix 2>/dev/null
;;
esac
exit 0
Defina o evento como PostToolUse, o matcher como Write|Edit e o command como .qoder-cn/hooks/auto-lint.sh.
Manter o Agente em execução
Verifique se há alterações não confirmadas no Git quando o Agente parar e solicite que ele continue caso existam. Salve o script abaixo em ~/.qoder-cn/hooks/check-continue.sh:
#!/bin/bash
# Check for uncommitted Git changes
if [ -n "$(git status --porcelain 2>/dev/null)" ]; then
echo "Uncommitted changes detected. Please commit your changes." >&2
exit 2
fi
exit 0
Defina o evento como Stop e o comando como ~/.qoder-cn/hooks/check-continue.sh.