↓ Ir para o conteúdo principal

Plugins externos

Versão documentada: v0.5.1

Tradução da página original em inglês, que é a referência se algo estiver diferente.

Um plugin é um executável em ~/.config/lazyagents/plugins/ ou $XDG_CONFIG_HOME/lazyagents/plugins/. O nome sem extensão é o ID: vira aba da TUI, subcomando lazyagents <id> e seção <id>: de config.yaml. IDs seguem ^[a-z0-9][a-z0-9_-]{0,31}$ e não podem repetir abas internas (skills, sessions, agents, providers, hooks, usage, plugins) nem comandos da CLI.

Qualquer linguagem serve: o contrato usa JSON Lines na entrada/saída padrão. Há um exemplo shell completo em examples/plugins/hello.

Modos de execução
#

ComandoQuandoContrato
<bin> serveabre a TUIprotocolo abaixo, processo vivo até fechar a TUI
<bin> <args…>lazyagents <id> <args…>repassa stdin/stdout/stderr e código de saída
<bin> doctordoctor, se o manifesto tiver doctor: trueproblemas em stdout; código diferente de zero indica problema; sem terminal, mostra saída ao terminar; após 30 s falha e encerra árvore de processos

Comandos solicitados por exec recebem o ambiente do plugin e são cancelados ao fechar o aplicativo. No Windows, aceita executáveis .exe; o exemplo shell exige ambiente POSIX.

Todos os modos recebem LAZYAGENTS_HOME, LAZYAGENTS_CONFIG_DIR, LAZYAGENTS_DATA_DIR, LAZYAGENTS_LIBRARY_DIR e LAZYAGENTS_PROTOCOL.

Protocolo v1 (serve)
#

Uma mensagem JSON por linha, UTF-8, até 1 MiB. type identifica a mensagem. O hospedeiro é o lazyagents; o plugin lê stdin e escreve stdout. stdout é exclusivo do protocolo: logs vão para stderr, capturado pelo hospedeiro; os últimos 4 KiB aparecem na aba se houver falha.

Hospedeiro → plugin
#

typeCamposQuando
initprotocol (1), id, home, configDir, dataDir, libraryDir, theme{id, colors{role: "#hex"}} (tokens Primary/Bg/Info e papéis ui.accent/ansi.red; veja internal/tui/theme/README.md), config (seção <id>: de config.yaml em JSON, omitida se ausente), width, heightprimeira linha após iniciar
resizewidth, heightárea útil mudou, já descontando cabeçalho, abas e margens
keykey, texttecla pressionada com aba ativa; nomes Bubble Tea: a, enter, space, esc, ctrl+x, shift+tab
pastetexttexto colado
mousemouse{kind: "wheel"|"click", x, y, button}coordenadas relativas ao corpo da aba
commandnameescolha de <id> <name> na paleta (:)
reload—:reload ou tecla de recarga
agentsagents[{id, name, installed, version, managedDir, readDirs}]após detecção dos agentes e novamente após reiniciar o plugin
exec_resultexecId, code, stdout, stderr, errorexec terminou; stdout/stderr só em execução não interativa, até 1 MiB

Teclas globais (q, ?, :, tab, shift+tab, 1–9) não chegam ao plugin, salvo se o último quadro tiver capturing: true, usado enquanto um campo tem foco.

Plugin → hospedeiro
#

typeCamposRegras
manifesttitle, help[{title, keys[[key, description]]}], commands[{name, desc}], doctorprimeira linha, em até 3 s de init; título até 40 caracteres; nomes de comandos seguem ^[a-z0-9][a-z0-9_-]*$, mostrados como <id> <name>
frameview, count, capturingestado completo da aba, a qualquer momento; último prevalece; count é o contador da aba, omitido para ocultar
execexecId, argv, dir, interactivepede execução ao hospedeiro; interativa suspende a TUI e entrega o terminal (editor/CLI), não interativa executa em segundo plano e retorna saída em exec_result

view é texto com \n. Caracteres de controle usam escapes JSON (\u001b[1m para ESC). Cores SGR (ESC[…m) são mantidas; outros controles (cursor, limpeza, OSC) são removidos. O hospedeiro recorta ao tamanho da aba e repinta o fundo após cada ESC[0m.

Ciclo de vida e falhas
#

  • Ao fechar stdin (EOF), o plugin deve sair. O hospedeiro envia SIGTERM e, 2 s depois, SIGKILL. No Linux/macOS, há um grupo próprio e os sinais atingem todo o grupo; processos restantes são encerrados após a saída. No Windows, o plugin inicia suspenso, entra num Job Object com encerramento ao fechar e só então executa: nada escapa. A parada encerra a árvore (taskkill /T durante execução); restos do job são encerrados após sair, inclusive se o lazyagents morrer. O mesmo vale para exec não interativo; o interativo mantém o terminal e executa como filho comum.
  • Sem manifesto, linha não JSON, type vazio, linha maior que 1 MiB ou processo morto: a aba mostra erro e stderr; :reload reinicia. A TUI continua funcionando.
  • Se o plugin parar de ler stdin e a fila de 256 mensagens encher, o hospedeiro o encerra.

Configuração
#

Crie uma seção com o ID em config.yaml; ela chega inteira em init.config:

hello:
  greeting: hi

Testes
#

mkdir -p ~/.config/lazyagents/plugins
cp examples/plugins/hello ~/.config/lazyagents/plugins/hello
chmod +x ~/.config/lazyagents/plugins/hello
lazyagents doctor          # negociação inicial e `hello doctor`
lazyagents hello a b       # argumentos repassados
lazyagents                 # aba Hello

Para depurar manualmente: printf '{"type":"init","protocol":1,"width":80,"height":24}\n{"type":"key","key":"x"}\n' | ./hello serve.