Funcionalidades

Ficheiros e código

As ferramentas de ficheiros e de terminal, a pasta de trabalho, como cada alteração fica registada e se desfaz, que comandos pedem autorização e como o Ploy verifica o que fez.

Quando um pedido cria ou corrige alguma coisa, fala de um ficheiro pelo nome ou é sobre a pasta de trabalho da conversa, entra no modo Código («trabalho com ficheiros e terminal»). O Ploy escreve os ficheiros, corre os comandos e verifica o resultado antes de dizer que está feito.

O Saturn planeia, faz e revê. O Veta faz logo, com menos passos e sem plano. O Kant não usa ferramentas: se o tiveres escolhido, outro modelo faz a tarefa e o Ploy diz-te qual. Ver Modelos.

A pasta de trabalho

Cada conversa trabalha numa pasta. Escolhes a pasta no botão «Pasta de trabalho» do campo do pedido, e ela fica ligada à conversa.

Se não escolheres nenhuma, um pedido de código cria uma pasta nova em ~/Projetos Ploy, com um nome tirado das primeiras palavras do pedido, e o Ploy diz-te onde: «Pasta do projeto: …». Em Definições › Geral e aparência, «Pasta dos projetos» tem «Mostrar no Finder».

As regras da pasta:

  • Escrever só dentro da pasta. Lá dentro não pede autorização: cada escrita fica registada e pode desfazer-se. Um caminho de fora é recusado, e as ligações simbólicas são seguidas, para que uma ligação para outra pasta não sirva para escrever lá.
  • Ler dentro da pasta é livre. Ler fora dela é a permissão «Ler ficheiros fora da pasta de trabalho». Os ficheiros que anexaste leem-se onde estiverem.
  • Segredos pedem sempre, para ler e para escrever, mesmo dentro da pasta: .env, chaves (.pem, .key, id_rsa, id_ed25519), .netrc, .npmrc, credentials, .git/config e tudo dentro de .ssh, .aws e .gnupg, entre outros. A procura em ficheiros salta-os.
  • Escrever na pasta .git pede sempre, com qualquer combinação de maiúsculas (.GIT também conta), porque os hooks e a configuração do git apontam para programas que o git corre.

As ferramentas

Ferramenta O que faz
list_files Árvore da pasta (3 níveis por omissão, até 8), sem pastas de dependências e de compilação como node_modules, .build ou dist.
read_file Linhas numeradas, 400 de cada vez por omissão, até cerca de 20 000 caracteres por leitura. Recusa ficheiros binários.
search_files Procura uma expressão regular e devolve ficheiro:linha, até 200 resultados. Salta ficheiros com mais de 2 MB e ficheiros com segredos.
search_project Procura por palavras, não por padrão, e devolve as passagens mais relevantes com o ficheiro e as linhas.
write_file Cria um ficheiro ou substitui-o por inteiro.
edit_file Troca um pedaço exato de texto. Tolera diferenças de indentação e recusa quando o texto aparece mais de uma vez, a menos que se peça para trocar todos.
delete_file Move para o Lixo. Pede autorização, exceto em «Execução autónoma» quando foste tu a pedir para apagar. A própria pasta de trabalho não pode ser apagada.
run_command Corre uma linha de comandos no zsh, na pasta de trabalho, durante 120 segundos por omissão e no máximo 900.
start_server Arranca um programa que fica a correr, como um servidor de desenvolvimento, e espera que ele escute na porta.
stop_server Para um programa em segundo plano desta conversa, ou todos.
read_document, search_document Leem documentos: ver Documentos, imagens, voz e vídeo.

O modelo pode também escrever um ficheiro inteiro como um bloco de código com o caminho na primeira linha:

```html path=index.html
<!doctype html>
...
```

Enquanto o modelo escreve, vês o tamanho do ficheiro a crescer; o ficheiro é gravado quando o bloco fecha. Se a resposta for cortada a meio, o ficheiro incompleto não é gravado e o modelo é instruído a dividi-lo em ficheiros mais pequenos.

Como as alterações ficam registadas

Cada escrita das ferramentas fica registada com o conteúdo de antes e de depois.

Os comandos também. Antes e depois de cada comando, o Ploy tira uma fotografia da pasta: tamanho e data de cada ficheiro, e o conteúdo dos que têm até 2 MB. Os ficheiros maiores são clonados antes do comando com os clones do APFS, cópias instantâneas que partilham os blocos do disco até uma das duas mudar, por isso um ficheiro de vários gigabytes não custa nada a guardar. O que o comando criou, mudou ou apagou fica registado como qualquer outra alteração.

O Ploy diz ao modelo que ficheiros cada comando mudou. Se um comando mudar um ficheiro que já existia antes da tarefa, o modelo é avisado de que não o devia reescrever sem lho pedires, tu vês «Um comando alterou ficheiros que já existiam: …», e o resultado da tarefa lista-o com «confirma ou desfaz». Os ficheiros de dados que já existiam (CSV, folhas de cálculo, bases de dados SQLite, XML, texto) e foram reescritos por qualquer meio, mesmo pelas ferramentas de ficheiros, também aparecem no resultado com «confirma ou desfaz».

Desfazer

O painel lateral (⌥⌘I, «Mostrar o painel») tem o separador «Ficheiros»: os ficheiros que a última tarefa da conversa criou ou mudou, cada um com as diferenças, as linhas acrescentadas a verde e as retiradas a vermelho.

«Desfazer tudo» repõe a pasta como estava antes da última tarefa. Só fica ativo quando a tarefa acaba e pede confirmação («Desfazer as alterações da última tarefa?»):

  • os ficheiros alterados voltam ao que eram;
  • os apagados voltam, do Lixo, do clone ou da cópia guardada;
  • os criados vão para o Lixo.

Os ficheiros que a tarefa criou vão para o Lixo; num ficheiro alterado, a versão que a tarefa escreveu é substituída pela anterior e não fica guardada. Um ficheiro cuja versão anterior não ficou guardada é deixado como está, e o resumo diz qual («Sem cópia para repor: …»).

Que comandos pedem autorização

O Ploy lê cada linha de comandos como o zsh a vai ler: divide-a nos comandos simples (em ;, &&, ||, |, & e mudanças de linha), tira as aspas e identifica o programa e os caminhos. Os programas que correm outro programa, como timeout, nohup, env, arch, script ou caffeinate, são vistos por dentro.

Comando Exemplo O que acontece
Trabalha só na pasta python3 app.py, swift test, ls É a permissão «Executar comandos na pasta de trabalho». Em «Confirmar ações» pergunta, com «Nesta tarefa (comandos)» e «Sempre (comandos)». Em «Execução autónoma» corre. Em «Personalizada», depende do que ligaste.
Usa a rede ou lê fora da pasta curl https://…, git fetch, cat ~/notas.txt Não é coberto pela permissão de comandos. Em «Confirmar ações» e «Personalizada» pergunta; em «Execução autónoma» só corre antes de a tarefa ler conteúdo de terceiros.
Sensível ver a lista abaixo Pede sempre, um a um, só com «Não» e «Permitir».

Um servidor de desenvolvimento neste Mac não é a rede: curl http://localhost:3000 conta como um comando na pasta.

É sensível, e pede sempre:

  • apagar, parar ou mudar o sistema: rm, kill, sudo, defaults, launchctl, diskutil, osascript, xargs, eval e outros;
  • instalar, publicar ou descarregar e correr software: brew, pip install, npm install, npx, cargo install e semelhantes;
  • código escrito na própria linha (python3 -c, node -e) ou um interpretador que corre o que lhe chegar (curl … | python3);
  • comandos escondidos dentro de outro ($(…), acentos graves), aspas que o terminal transforma antes de correr ($'rm') e nomes de programa que o terminal ainda expande (/bin/r?, $X);
  • mudar onde os programas são procurados ou o que carregam (PATH=…, DYLD_INSERT_LIBRARIES=…);
  • escrever fora da pasta de trabalho, por redirecionamento, com mv, cp e semelhantes, ou com opções de descarga como curl -o ~/…;
  • tocar em ficheiros com segredos ou escrever na pasta .git;
  • o git que pode desfazer trabalho ou publicar (push, reset, checkout e tudo o que não está numa lista de subcomandos seguros), apagar ramos, e configuração dada na linha de comandos ou escrita com git config;
  • find com -delete ou -exec, awk que corre comandos, sed com o comando e, ou com w para fora da pasta, chmod -R, e ligar a outra máquina com ssh ou scp.

Depois de a tarefa ler conteúdo de terceiros (uma página, um documento, o ecrã de outra aplicação, um anexo ou a saída de um comando de rede, nesta mensagem ou numa anterior da conversa), cada comando pede autorização, um a um, seja o que for que permitiste antes. O cartão diz «Esta tarefa já leu conteúdo da web, do ecrã ou de um documento, por isso cada comando pede autorização.» e deixa de oferecer «Nesta tarefa». Assim, uma instrução escondida nesse conteúdo nunca se autoriza a si própria.

O ambiente dos comandos

  • O PATH é o da tua shell de login, para o Homebrew e as tuas ferramentas estarem lá, com as pastas habituais acrescentadas.
  • Os comandos correm sem cores e sem paginador (TERM=dumb, NO_COLOR=1, PAGER=cat, CI=1).
  • Variáveis cujo nome contém API_KEY, TOKEN ou SECRET, ou começa por PLOY_, são retiradas.
  • Os segredos com formato conhecido são retirados da saída antes de a veres, de chegar ao modelo e de ser guardada.

Como o resultado é verificado

Uma tarefa de código só fica «Verificado» quando alguma coisa o confirmou. Há quatro tipos de verificação.

Cada ficheiro, quando é escrito (e outra vez quando um comando o muda):

Tipo Verificação
JSON tem de ser lido sem erros
JavaScript sintaxe verificada com o JavaScriptCore, sem correr nada, também em módulos
HTML tem de ser uma página, as etiquetas <script> têm de fechar e os scripts embutidos têm a sintaxe verificada
CSS chavetas equilibradas
Shell bash -n
Python ast.parse

Um ficheiro que falha a verificação volta ao modelo com o erro exato.

As páginas, quando o modelo diz que acabou. O Ploy abre cada página HTML que a tarefa escreveu (até quatro) no WebKit, sem janela, servida a partir de um endereço próprio para os erros chegarem com a mensagem e a linha. Espera que os scripts assentem e carrega uma vez em cada botão (até 80), como faria uma pessoa curiosa. Recolhe os erros de script, os console.error, os ficheiros que não carregam (um style.css em falta, por exemplo), uma página que não mostra nada e um botão que bloqueia a página (desiste ao fim de seis segundos). A página corre sem acesso à rede: os pedidos para a internet são bloqueados, para que carregar nos botões nunca envie, apague ou compre nada a sério. Os problemas voltam ao modelo, com até quatro rondas de correção por tarefa. Medido no Mac de referência: 2 a 3 segundos por página. A mesma verificação existe na linha de comandos, com ploy inspect pagina.html.

Os comandos de verificação. Testes, compilações, linters, verificadores de tipos e correr o próprio script contam quando passam. Uma verificação que passa mais tarde resolve a falha anterior da mesma verificação. Um comando exploratório que falhou pelo caminho não conta contra a tarefa.

Os requisitos (Saturn). Quando o pedido cria alguma coisa, ou é longo, o Saturn começa por um plano curto: até dez requisitos concretos, os ficheiros e como verificar, que vês como «Planeado». No fim, revê o código contra cada requisito. O que falta volta ao modelo para ser feito; um requisito que a revisão não julgou fica «Não confirmado», nunca cumprido.

Pelo caminho, se o modelo descrever o que vai fazer em vez de o fazer, o Ploy pede-lhe que o faça; se escrever código sem ficheiro, pede-lhe que o grave.

No fim:

  • «Verificado» quando pelo menos um ficheiro ou um comando de verificação passou, nada falhou e nada ficou por confirmar;
  • «Por verificar» nos outros casos, com a lista do que falhou ou do que ninguém verificou, por exemplo «Feito, mas sem nada que o confirmasse automaticamente.»

Processos longos e limpeza

Cada comando corre no seu próprio grupo de processos, debaixo de um pequeno guarda, por isso parar um comando para tudo o que ele arrancou.

  • run_command: no fim do tempo ou quando carregas em «Parar», o grupo recebe ordem para terminar e, se ainda houver alguma coisa viva ao fim de um segundo e meio, é forçado. Quando o comando acaba, o que ele deixou a correr no grupo é parado também.
  • start_server: o programa continua a correr depois de a tarefa acabar e pertence à conversa. O separador «Processos» do painel lateral mostra-o, com o pid e a hora a que arrancou, e um botão «Parar». Para também quando o modelo chama stop_server, quando apagas a conversa e quando sais do Ploy.
  • Se o Ploy falhar ou for forçado a sair, o guarda nota-o em cerca de um segundo e para o comando. Medido no Mac de referência: um processo em segundo plano desapareceu 1,6 segundos depois de o Ploy ser morto.

Uma saída muito longa fica com o princípio e o fim, onde os erros costumam estar: o modelo lê cerca de 6000 caracteres de cada saída.