O que mac-declutter faz?
Um playbook testado em batalha para desorganizar o Mac de um desenvolvedor: proliferação de agentes de IA, serviços em segundo plano mortos, sobras de aplicativos, armadilhas de proxy e auditorias de desempenho.
Princípios fundamentais:
- Inventário antes de deletar. Nunca desinstale no escuro — meça o tamanho, a data do último uso e o estado de execução primeiro, depois deixe o usuário escolher.
- Nunca toque em registros de sessão ou dados do usuário a menos que explicitamente solicitado. Caches se regeneram; sessões não.
- Verifique após cada mutação — processo encerrado, porta fechada, item de login removido.
- A Proteção de Integridade do Sistema (SIP) é um muro intransponível. Aplicativos de propriedade do root, contêineres sandbox e extensões DriverKit têm cada um um caminho de remoção autorizado; não lute contra o SO.
Fase 0 — Triagem de rede (faça isso primeiro)
O sintoma "tudo está desconectado" é quase sempre um proxy local morto, não aplicativos quebrados:
scutil --proxy # para onde o proxy do sistema aponta
nc -z -w 2 127.0.0.1 <porta> # algo está realmente ouvindo?
lsof -nP -iTCP:<porta> -sTCP:LISTEN # quem é o dono
A armadilha clássica: ferramentas estilo Clash/V2Ray configuram o proxy do macOS para 127.0.0.1:PORTA, depois o núcleo morre — o modo de regra não importa, todo o tráfego morre na porta. Aplicativos que honram o proxy do sistema (a maioria dos aplicativos GUI, alguns CLIs) falham todos; curl ainda funciona porque ignora o proxy do sistema, o que engana o diagnóstico. Correções: reinicie o núcleo do proxy, ou desabilite o proxy (networksetup -setwebproxystate Wi-Fi off + -setsecurewebproxystate + -setsocksfirewallproxystate + WPAD off), ou aponte a configuração de proxy do próprio aplicativo para nada. Lembre-se: curl ignora o proxy do sistema — teste a conectividade no estilo do aplicativo com curl -x http://127.0.0.1:PORTA.
Fase 1 — Inventário (somente leitura)
Execute scripts/inventory.sh, ou cubra manualmente estas dimensões:
- Diretórios de configuração de agente:
~/.claude,~/.codex,~/.pi,~/.jcode,~/.config/opencode, etc. Para cada um: tamanho (du -sh), última atividade (mtime do arquivo mais recente), se o binário CLI ainda existe (which). - Estado de login/auth:
auth.json,openai-auth.json, arquivos de credenciais — liste as chaves, nunca imprima segredos. - Serviços em segundo plano:
launchctl list | grep -v com.applee~/Library/LaunchAgents/*.plist— leia oProgramArgumentsde cada plist para saber o que realmente é executado. - Aplicativos: para cada
.appnão Apple em/Applicationse~/Applications, colete tamanho,kMDItemLastUsedDateviamdls, e presença de_MASReceipt(aplicativos da App Store). "Nunca aberto" + grande = candidato principal. - Caches:
~/Library/Caches,~/.npm, caches pip/bun — grandes e sempre seguros de limpar.
Apresente os resultados como uma tabela manter/remover e deixe o usuário escolher. Sinalize aplicativos pagos/por assinatura (ex.: _MASReceipt, produtos de assinatura conhecidos) para que o usuário cancele a cobrança antes de deletar.
Fase 2 — Playbook de desinstalação
Por alvo, nesta ordem:
- Pare serviços:
launchctl remove <rótulo>para cada LaunchAgent/Daemon relacionado. - Delete plists:
~/Library/LaunchAgents/<rótulo>.plist. - Delete o aplicativo/CLI:
rm -rfdo.app/npm uninstall -g <pacote>/ remova o binário.Permission denied→ de propriedade do root (instalado por pacote). Useosascript -e 'do shell script "rm -rf ..." with administrator privileges'(um prompt de senha GUI). Nuncasudocegamente.
- Sobras da biblioteca: verifique e remova
~/Library/{Application Support,Caches,Containers,HTTPStorages,Preferences}/<aplicativo-ou-id-de-pacote>.Containers/*sandbox podem resistir até mesmo ao root (proteção do gerenciador de contêiner). Se pequenos, deixe-os — o SO coleta contêineres órfãos; desabilitar a SIP nunca vale a pena.
- Extensões do sistema:
systemextensionsctl list. A SIP bloqueia desinstalação direta — o único caminho limpo é reinstalar o aplicativo do fornecedor e executar seu desinstalador oficial (procure poruninstall.shem/Library/Application Support/<fornecedor>/). Drivers.dextdo DriverKit são descarregados apenas na próxima reinicialização — informe ao usuário que ele desapareceu após reiniciar. - Itens de login obsoletos: após deletar um aplicativo, sua entrada "Abrir no Login" frequentemente permanece como um zumbi. Remova com
osascript -e 'tell application "System Events" to delete login item "<nome>"'. - Sobras em execução: aplicativos deletados podem deixar processos em execução a partir de diretórios temporários de atualização (ex.: staging
ShipItdo Squirrel).ps aux | grep -i <nome>, mate-os, e verifique se há um diretório de dados em$HOME(~/.<nomedoaplicativo>) — daemons gerados por atualizadores frequentemente escondem centenas de MB lá.
Fase 3 — Limpeza de cache (risco zero)
npm cache clean --force
rm -rf ~/Library/Caches/pip ~/.bun/install/cache
rm -rf ~/Library/Caches/<aplicativo-deletado>/*
Caches se regeneram. Históricos de sessão (sessions/, projects/, logs de conversa *.jsonl) não — deixe-os a menos que o usuário diga explicitamente o contrário.
Fase 4 — Auditoria de desempenho
memory_pressure | tail -2 # % livre e pressão
sysctl -n vm.swapusage # swap usado deve ser ~0 em uma máquina saudável
sysctl -n vm.loadavg
ps -axm -o rss,comm | awk 'NR>1 {rss=$1; $1=""; sub(/^ "/,""); a[$0]+=rss} END {for (k in a) printf "%d\t%s\n", a[k]/1024, k}' | sort -rn | head -15
- "Memória usada" no Monitor de Atividade inclui cache de arquivos — julgue pela cor da pressão de memória e swap, não pelo número em GB.
- Após exclusão em massa, o Spotlight (
mds_stores,corespotlightd) re-indexa por algumas horas — temporário, não "corrija". - Agrupe RSS por família de aplicativos (navegadores e aplicativos de chat geram muitos auxiliares); reporte totais por família, não ruído por processo.
- Não otimize o que não é um problema: em uma máquina com zero swap e pressão verde, trocar a UX do driver diário (ex.: um IME inteligente) por algumas centenas de MB é uma troca ruim — diga isso.
Fase 5 — Verificação final
- Rótulos deletados ausentes de
launchctl list; plists removidas; nenhum processo correspondendo a nomes deletados (exceto drivers pendentes de reinicialização). - A porta de escuta do proxy corresponde a
scutil --proxy; endpoints-chave da API acessíveis (401= acessível mas precisa de autenticação, o que é um passe). - Cada CLI de agente sobrevivente passa por um teste ponta a ponta real (envie um prompt de uma linha, espere uma resposta).
df -h /antes/depois para a pontuação.