Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ graphify-out/

# lixo de redirecionamento acidental — builtin `cd` com output redirecionado cria um arquivo "cd"
/cd
AGENTS.md
GEMINI.md
CLAUDE.md
83 changes: 39 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,67 +68,71 @@ terminal — **window _and_ tab**.

## Requirements

- **Linux**. X11: full support (GNOME/Mutter tested). **Wayland: partial** —
the overlay runs via XWayland; tab-focus works in Warp (`focus_url`);
window focus reaches XWayland terminals only. See Troubleshooting.
- `wmctrl`, `xdotool`, `jq` — `sudo apt install wmctrl xdotool jq`
- **Linux** (X11: full support, Wayland: partial — see [Troubleshooting](#troubleshooting)) or **macOS** (supports Apple Silicon M1–M5).
- On Linux: `wmctrl`, `xdotool`, `jq` — `sudo apt install wmctrl xdotool jq`
- On macOS: Homebrew and `jq` — `brew install jq`
- Node.js 20+
- A supported agent: [Claude Code](https://claude.com/claude-code),
[Antigravity CLI](https://antigravity.google/docs/cli/reference),
[Codex](https://github.com/openai/codex) or [OpenCode](https://opencode.ai)

## Install

Pick whichever fits. **All three require the agent hooks** so the overlay can
see Claude Code / Antigravity / OpenCode sessions — from source you run
`npm run setup-hook`; in a packaged build you click **Install hooks** in the
tray menu (or the overlay's onboarding button).
Pick whichever fits your platform. **All options require the agent hooks** so the overlay can see Claude Code / Antigravity / OpenCode sessions — from source you run `npm run setup-hook`; in a packaged build you click **Install/update hooks** in the tray menu or Preferences window (or the overlay's onboarding button).

### A — AppImage (recommended, self-updating)
### macOS (M1 to M5 / arm64)

**One line** — fetches the latest release, makes it executable, installs the icon
into the system theme and creates the application-menu shortcut (with
`StartupWMClass` matching the app's real WM_CLASS):
#### Option 1: Automated script (recommended)
Run the following single-line command in your terminal. It will verify dependencies (installing `jq` via Homebrew if needed), download the latest `.dmg` release, copy `AI Traffic Lights.app` to `/Applications`, and configure shell aliases (`atl` and `ai-traffic-lights`) in your `~/.zshrc` and `~/.bash_profile`:

```bash
curl -fsSL https://raw.githubusercontent.com/aronpc/ai-traffic-lights/main/install.sh | bash
curl -fsSL https://raw.githubusercontent.com/aronpc/ai-traffic-lights/main/install_macos.sh | bash
```

To run the application from the terminal, open a new shell session (or run `source ~/.zshrc`) and execute:
```bash
atl
```

Then open it from your **application menu** (search "AI Traffic Lights") or run
`~/Applications/AI-Traffic-Lights.AppImage`. To remove:
`curl -fsSL .../install.sh | bash -s -- --uninstall`.
#### Option 2: Manual Install
1. Download the `.dmg` file from the [latest release](https://github.com/aronpc/ai-traffic-lights/releases/latest).
2. Open the `.dmg` file and drag `AI Traffic Lights.app` to your `/Applications` folder.

This is the only build that **updates itself**: on launch and hourly it checks
for a new release, the version badge becomes `↓ vX` (download) → `↻` (restart
into the new version), and the tray has a "Check for updates" entry.
---

<details><summary>Without <code>install.sh</code> (manual)</summary>
### Linux

Grab the `.AppImage` from the [latest release](https://github.com/aronpc/ai-traffic-lights/releases/latest),
drop it in a **user-writable** folder (the self-updater rewrites that file in
place — so not `/opt` or `/usr`), and run it:
#### Option 1: AppImage (recommended, self-updating)
A single command that fetches the latest release, makes it executable, installs the icon into the system theme, and creates an application menu shortcut:

```bash
curl -fsSL https://raw.githubusercontent.com/aronpc/ai-traffic-lights/main/install.sh | bash
```

Then open it from your application menu or run `~/Applications/AI-Traffic-Lights.AppImage`. To uninstall:
```bash
curl -fsSL https://raw.githubusercontent.com/aronpc/ai-traffic-lights/main/install.sh | bash -s -- --uninstall
```

<details><summary>Manual AppImage install</summary>

Grab the `.AppImage` from the [latest release](https://github.com/aronpc/ai-traffic-lights/releases/latest), drop it in a user-writable folder (the self-updater rewrites that file in place — do not use `/opt` or `/usr`), and run:
```bash
chmod +x AI-Traffic-Lights-*.AppImage
./AI-Traffic-Lights-*.AppImage
```

</details>

### B — .deb

Grab the `.deb` from the [latest release](https://github.com/aronpc/ai-traffic-lights/releases/latest) and:
#### Option 2: Debian Package (.deb)
Download the `.deb` from the [latest release](https://github.com/aronpc/ai-traffic-lights/releases/latest) and install it:

```bash
sudo dpkg -i ai-traffic-lights_*.deb
```

Installs under `/opt` and registers a `.desktop` entry. **No self-update** on
this path (the updater can't replace a root-owned package) — you only get a
`↑ vX` prompt that opens the release page when a new version ships.

### C — from source (development)
---

### From Source (Development - Linux & macOS)
```bash
git clone https://github.com/aronpc/ai-traffic-lights.git
cd ai-traffic-lights
Expand All @@ -139,16 +143,9 @@ npm run setup-hook # registers the adapters: Claude Code (~/.claude),
npm start # opens the overlay
```

`setup-hook` is idempotent and surgical: it backs up `settings.json` and never
touches hooks from other tools. The registered command points to a
self-updating **stable copy** of the hook in
`~/.local/share/ai-traffic-lights/bin/` — so moving the project (or running
the packaged AppImage, whose mount path changes every run) never breaks it.
`npm run remove-hook` undoes everything just as cleanly. The tray menu offers
the same install/remove actions for packaged installs.
`setup-hook` is idempotent and surgical: it backs up `settings.json` and never touches hooks from other tools. The registered command points to a self-updating **stable copy** of the hook in `~/.local/share/ai-traffic-lights/bin/` — so moving the project (or running the packaged AppImage/App, whose mount path changes every run) never breaks it. `npm run remove-hook` undoes everything just as cleanly. The tray menu and Preferences window offer the same install/remove actions for packaged installs.

New Claude Code sessions show up immediately; sessions already open appear on
their next event.
New Claude Code sessions show up immediately; sessions already open appear on their next event.

## How it works

Expand Down Expand Up @@ -259,9 +256,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details.

- **Overlay shows "no active sessions"** — did you run `npm run setup-hook`?
Already-open sessions only appear after their next event (send any prompt).
- **Click doesn't focus / focuses the wrong window** — check `wmctrl` and
`xdotool` are installed; on Wayland they don't work (roadmap). The exact-tab
jump only works in Warp for now.
- **Click doesn't focus / focuses the wrong window** — on Linux, check that `wmctrl` and `xdotool` are installed. On macOS, click-to-focus uses AppleScript (`osascript`) to focus the window. If it fails, ensure `AI Traffic Lights.app` (or your terminal if running from source) has **Accessibility** permissions granted in *System Settings > Privacy & Security > Accessibility*.
- **Wayland** — the overlay itself runs fine (XWayland). Native-Wayland
windows can't be focused by third parties, so click-to-focus relies on the
terminal's focus URI (Warp today); the global shortcut may not fire while a
Expand Down
84 changes: 39 additions & 45 deletions README.pt-BR.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,68 +67,71 @@ por sessão, clique para pular pro terminal — **janela _e_ aba**.

## Requisitos

- **Linux**. X11: suporte completo (testado em GNOME/Mutter). **Wayland:
parcial** — o overlay roda via XWayland; o foco de aba funciona no Warp
(`focus_url`); o foco de janela alcança só terminais XWayland. Ver Solução
de problemas.
- `wmctrl`, `xdotool`, `jq` — `sudo apt install wmctrl xdotool jq`
- **Linux** (suporte completo no X11, parcial no Wayland — veja [Solução de problemas](#solução-de-problemas)) ou **macOS** (suporta Apple Silicon M1–M5).
- No Linux: `wmctrl`, `xdotool`, `jq` — `sudo apt install wmctrl xdotool jq`
- No macOS: Homebrew e `jq` — `brew install jq`
- Node.js 20+
- Um agente suportado: [Claude Code](https://claude.com/claude-code),
[Antigravity CLI](https://antigravity.google/docs/cli/reference),
[Codex](https://github.com/openai/codex) ou [OpenCode](https://opencode.ai)

## Instalação

Escolha a que preferir. **Todas exigem os hooks dos agentes** para o overlay
enxergar sessões do Claude Code / Antigravity / OpenCode — pelo fonte você roda
`npm run setup-hook`; num build empacotado você clica em **Instalar hooks** no
menu do tray (ou no botão de onboarding do overlay).
Escolha a que preferir para a sua plataforma. **Todas as opções exigem os hooks dos agentes** para o overlay enxergar as sessões do Claude Code / Antigravity / OpenCode — pelo fonte você roda `npm run setup-hook`; num build empacotado você clica em **Instalar/atualizar hooks** no menu do tray ou na janela de Preferências (ou no botão de onboarding do overlay).

### A — AppImage (recomendado, auto-atualizável)
### macOS (M1 a M5 / arm64)

**Uma linha** — baixa a versão mais recente, dá permissão de execução, instala o
ícone no tema do sistema e cria o atalho no menu de aplicativos (com
`StartupWMClass` casando o WM_CLASS real do app):
#### Opção 1: Script automatizado (recomendado)
Rode o comando de linha única abaixo no terminal. Ele irá verificar dependências (instalando o `jq` via Homebrew se necessário), baixar a versão `.dmg` mais recente, copiar o `AI Traffic Lights.app` para `/Applications` e configurar aliases de terminal (`atl` e `ai-traffic-lights`) no seu `~/.zshrc` e `~/.bash_profile`:

```bash
curl -fsSL https://raw.githubusercontent.com/aronpc/ai-traffic-lights/main/install.sh | bash
curl -fsSL https://raw.githubusercontent.com/aronpc/ai-traffic-lights/main/install_macos.sh | bash
```

Para iniciar o aplicativo via terminal, abra uma nova aba do terminal (ou execute `source ~/.zshrc`) e execute:
```bash
atl
```

Depois abra pelo **menu de aplicativos** (busque "AI Traffic Lights") ou rode
`~/Applications/AI-Traffic-Lights.AppImage`. Para remover:
`curl -fsSL .../install.sh | bash -s -- --uninstall`.
#### Opção 2: Instalação Manual
1. Baixe o arquivo `.dmg` da [última release](https://github.com/aronpc/ai-traffic-lights/releases/latest).
2. Abra o arquivo `.dmg` e arraste o `AI Traffic Lights.app` para a sua pasta `/Applications`.

É o único build que **se atualiza sozinho**: no boot e a cada hora ele checa por
uma release nova, o badge de versão vira `↓ vX` (baixar) → `↻` (reiniciar na
versão nova), e o tray tem um item "Verificar atualizações".
---

<details><summary>Sem o <code>install.sh</code> (manual)</summary>
### Linux

Baixe o `.AppImage` da [última release](https://github.com/aronpc/ai-traffic-lights/releases/latest)
numa pasta **gravável pelo usuário** (o auto-updater reescreve esse arquivo no
lugar — então não `/opt` nem `/usr`), e rode:
#### Opção 1: AppImage (recomendado, auto-atualizável)
Um comando único que baixa a versão mais recente, torna-a executável, instala o ícone no tema do sistema e cria o atalho no menu de aplicativos:

```bash
curl -fsSL https://raw.githubusercontent.com/aronpc/ai-traffic-lights/main/install.sh | bash
```

Depois abra pelo menu de aplicativos ou execute `~/Applications/AI-Traffic-Lights.AppImage`. Para desinstalar:
```bash
curl -fsSL https://raw.githubusercontent.com/aronpc/ai-traffic-lights/main/install.sh | bash -s -- --uninstall
```

<details><summary>Instalação manual do AppImage</summary>

Baixe o `.AppImage` da [última release](https://github.com/aronpc/ai-traffic-lights/releases/latest), coloque em uma pasta com permissão de escrita para o usuário (o auto-atualizador reescreve esse arquivo no lugar — não use `/opt` ou `/usr`) e rode:
```bash
chmod +x AI-Traffic-Lights-*.AppImage
./AI-Traffic-Lights-*.AppImage
```

</details>

### B — .deb

Baixe o `.deb` da [última release](https://github.com/aronpc/ai-traffic-lights/releases/latest) e:
#### Opção 2: Pacote Debian (.deb)
Baixe o `.deb` da [última release](https://github.com/aronpc/ai-traffic-lights/releases/latest) e instale:

```bash
sudo dpkg -i ai-traffic-lights_*.deb
```

Instala em `/opt` e registra um `.desktop`. **Sem auto-update** nesse caminho (o
updater não consegue substituir um pacoto root-owned) — você só recebe um aviso
`↑ vX` que abre a página da release quando sai uma versão nova.

### C — pelo fonte (desenvolvimento)
---

### Pelo fonte (Desenvolvimento - Linux & macOS)
```bash
git clone https://github.com/aronpc/ai-traffic-lights.git
cd ai-traffic-lights
Expand All @@ -139,16 +142,9 @@ npm run setup-hook # registra os adapters: Claude Code (~/.claude),
npm start # abre o overlay
```

O `setup-hook` é idempotente e cirúrgico: faz backup do `settings.json` e
nunca toca hooks de outras ferramentas. O comando registrado aponta para uma
**cópia estável** auto-atualizada do hook em
`~/.local/share/ai-traffic-lights/bin/` — mover o projeto (ou rodar o
AppImage, cujo ponto de montagem muda a cada execução) nunca quebra nada.
`npm run remove-hook` desfaz tudo com o mesmo cuidado. O menu do tray oferece
as mesmas ações de instalar/remover para instalações empacotadas.
O `setup-hook` é idempotente e cirúrgico: faz backup do `settings.json` e nunca toca hooks de outras ferramentas. O comando registrado aponta para uma **cópia estável** auto-atualizada do hook em `~/.local/share/ai-traffic-lights/bin/` — mover o projeto (ou rodar o AppImage/App, cujo ponto de montagem muda a cada execução) nunca quebra nada. `npm run remove-hook` desfaz tudo com o mesmo cuidado. O menu do tray e a janela de Preferências oferecem as mesmas ações de instalar/remover para instalações empacotadas.

Sessões novas do Claude Code aparecem imediatamente; sessões já abertas
aparecem no próximo evento delas.
Sessões novas do Claude Code aparecem imediatamente; sessões já abertas aparecem no próximo evento delas.

## Como funciona

Expand Down Expand Up @@ -257,9 +253,7 @@ Detalhes em [CONTRIBUTING.md](CONTRIBUTING.md).

- **Overlay mostra "nenhuma sessão ativa"** — rodou `npm run setup-hook`?
Sessões já abertas só aparecem no próximo evento (mande qualquer prompt).
- **Clique não foca / foca a janela errada** — `wmctrl` e `xdotool`
instalados? No Wayland eles não funcionam (roadmap). O pulo pra aba exata
só existe no Warp por enquanto.
- **Clique não foca / foca a janela errada** — no Linux, certifique-se de que `wmctrl` e `xdotool` estão instalados. No macOS, o click-to-focus utiliza AppleScript (`osascript`) para focar a janela. Se falhar, certifique-se de que o `AI Traffic Lights.app` (ou o seu terminal, caso execute pelo fonte) possui permissões de **Acessibilidade** concedidas em *Ajustes do Sistema > Privacidade e Segurança > Acessibilidade*.
- **Wayland** — o overlay em si roda bem (XWayland). Janelas Wayland nativas
não podem ser focadas por terceiros, então o click-to-focus depende da URI
de foco do terminal (Warp hoje); o atalho global pode não disparar com um
Expand Down
50 changes: 33 additions & 17 deletions hooks/traffic-hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -97,23 +97,37 @@ main() {
ntype="${BASH_REMATCH[1]}"
fi

# Sobe a árvore até achar o processo do agente. Zero forks.
# claude: binário próprio (comm=claude). antigravity/gemini: script Node (comm=node) ou binário agy/antigravity —
# o PRIMEIRO ancestral é o agente. codex: binário Rust (comm=codex).
# Sobe a árvore até achar o processo do agente. Zero forks no Linux.
# No macOS (sem /proc), usamos ps.
local agent_pid=$$ pid=$$ comm="" ppid=""
while [ "${pid:-0}" -gt 1 ] 2>/dev/null; do
comm=""
read -r comm < "/proc/$pid/comm" 2>/dev/null
case "$AGENT:$comm" in
claude:claude|claude:claude-agent-acp|gemini:node|antigravity:node|antigravity:agy|antigravity:antigravity|codex:codex) agent_pid="$pid"; break ;;
esac
ppid=""
while IFS=$' \t' read -r k v; do
[ "$k" = "PPid:" ] && { ppid="$v"; break; }
done < "/proc/$pid/status" 2>/dev/null
[ -z "$ppid" ] && break
pid="$ppid"
done
if [ -d "/proc" ]; then
while [ "${pid:-0}" -gt 1 ] 2>/dev/null; do
comm=""
read -r comm < "/proc/$pid/comm" 2>/dev/null
case "$AGENT:$comm" in
claude:claude|claude:claude-agent-acp|gemini:node|antigravity:node|antigravity:agy|antigravity:antigravity|codex:codex) agent_pid="$pid"; break ;;
esac
ppid=""
while IFS=$' \t' read -r k v; do
[ "$k" = "PPid:" ] && { ppid="$v"; break; }
done < "/proc/$pid/status" 2>/dev/null
[ -z "$ppid" ] && break
pid="$ppid"
done
else
while [ "${pid:-0}" -gt 1 ] 2>/dev/null; do
local ps_out
ps_out=$(ps -p "$pid" -o ppid=,comm= 2>/dev/null)
ppid="" comm=""
read -r ppid comm <<< "$ps_out"
comm=$(basename "$comm")
case "$AGENT:$comm" in
claude:claude|claude:claude-agent-acp|gemini:node|antigravity:node|antigravity:agy|antigravity:antigravity|codex:codex) agent_pid="$pid"; break ;;
esac
[ -z "$ppid" ] && break
pid="$ppid"
done
fi

# Canais nativos de foco de aba (invisível pro X11; só o terminal alcança):
# Warp → WARP_FOCUS_URL (warp://session/<uuid>) via xdg-open
Expand All @@ -133,7 +147,9 @@ main() {
fi

local ts
printf -v ts '%(%s)T' -1 # epoch fork-free (bash 4.2+)
if ! printf -v ts '%(%s)T' -1 2>/dev/null || [ -z "${ts:-}" ]; then
ts=$(date +%s)
fi

[ -d "$STATE_DIR" ] || mkdir -p "$STATE_DIR" 2>/dev/null || return 0
local file="$STATE_DIR/${sid}.json"
Expand Down
Loading
Loading