omni-ai-cli 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +615 -2
  3. package/bin/ai.js +84 -0
  4. package/docs/README.en.md +615 -0
  5. package/docs/README.es.md +618 -0
  6. package/docs/README.fr.md +630 -0
  7. package/omni_ai/__init__.py +1 -0
  8. package/omni_ai/__main__.py +6 -0
  9. package/omni_ai/chat.py +1458 -0
  10. package/omni_ai/cli.py +991 -0
  11. package/omni_ai/config.py +531 -0
  12. package/omni_ai/deepseek.py +57 -0
  13. package/omni_ai/grok.py +111 -0
  14. package/omni_ai/onboarding.py +196 -0
  15. package/omni_ai/openrouter.py +335 -0
  16. package/omni_ai/osutils.py +86 -0
  17. package/omni_ai/pii.py +281 -0
  18. package/omni_ai/profiles.json +69 -0
  19. package/omni_ai/skills.py +124 -0
  20. package/omni_ai/sync.py +199 -0
  21. package/omni_ai/tools.py +75 -0
  22. package/omni_ai/ui.py +595 -0
  23. package/omni_ai/usage.py +305 -0
  24. package/omni_ai/vendor/prompt_toolkit/LICENSE +27 -0
  25. package/omni_ai/vendor/prompt_toolkit/__init__.py +52 -0
  26. package/omni_ai/vendor/prompt_toolkit/application/__init__.py +32 -0
  27. package/omni_ai/vendor/prompt_toolkit/application/application.py +1626 -0
  28. package/omni_ai/vendor/prompt_toolkit/application/current.py +195 -0
  29. package/omni_ai/vendor/prompt_toolkit/application/dummy.py +55 -0
  30. package/omni_ai/vendor/prompt_toolkit/application/run_in_terminal.py +114 -0
  31. package/omni_ai/vendor/prompt_toolkit/auto_suggest.py +177 -0
  32. package/omni_ai/vendor/prompt_toolkit/buffer.py +2029 -0
  33. package/omni_ai/vendor/prompt_toolkit/cache.py +127 -0
  34. package/omni_ai/vendor/prompt_toolkit/clipboard/__init__.py +17 -0
  35. package/omni_ai/vendor/prompt_toolkit/clipboard/base.py +109 -0
  36. package/omni_ai/vendor/prompt_toolkit/clipboard/in_memory.py +44 -0
  37. package/omni_ai/vendor/prompt_toolkit/clipboard/pyperclip.py +42 -0
  38. package/omni_ai/vendor/prompt_toolkit/completion/__init__.py +43 -0
  39. package/omni_ai/vendor/prompt_toolkit/completion/base.py +438 -0
  40. package/omni_ai/vendor/prompt_toolkit/completion/deduplicate.py +45 -0
  41. package/omni_ai/vendor/prompt_toolkit/completion/filesystem.py +118 -0
  42. package/omni_ai/vendor/prompt_toolkit/completion/fuzzy_completer.py +213 -0
  43. package/omni_ai/vendor/prompt_toolkit/completion/nested.py +109 -0
  44. package/omni_ai/vendor/prompt_toolkit/completion/word_completer.py +94 -0
  45. package/omni_ai/vendor/prompt_toolkit/contrib/__init__.py +0 -0
  46. package/omni_ai/vendor/prompt_toolkit/contrib/completers/__init__.py +5 -0
  47. package/omni_ai/vendor/prompt_toolkit/contrib/completers/system.py +64 -0
  48. package/omni_ai/vendor/prompt_toolkit/contrib/regular_languages/__init__.py +80 -0
  49. package/omni_ai/vendor/prompt_toolkit/contrib/regular_languages/compiler.py +579 -0
  50. package/omni_ai/vendor/prompt_toolkit/contrib/regular_languages/completion.py +100 -0
  51. package/omni_ai/vendor/prompt_toolkit/contrib/regular_languages/lexer.py +94 -0
  52. package/omni_ai/vendor/prompt_toolkit/contrib/regular_languages/regex_parser.py +279 -0
  53. package/omni_ai/vendor/prompt_toolkit/contrib/regular_languages/validation.py +60 -0
  54. package/omni_ai/vendor/prompt_toolkit/contrib/ssh/__init__.py +8 -0
  55. package/omni_ai/vendor/prompt_toolkit/contrib/ssh/server.py +178 -0
  56. package/omni_ai/vendor/prompt_toolkit/contrib/telnet/__init__.py +7 -0
  57. package/omni_ai/vendor/prompt_toolkit/contrib/telnet/log.py +13 -0
  58. package/omni_ai/vendor/prompt_toolkit/contrib/telnet/protocol.py +209 -0
  59. package/omni_ai/vendor/prompt_toolkit/contrib/telnet/server.py +428 -0
  60. package/omni_ai/vendor/prompt_toolkit/cursor_shapes.py +117 -0
  61. package/omni_ai/vendor/prompt_toolkit/data_structures.py +18 -0
  62. package/omni_ai/vendor/prompt_toolkit/document.py +1182 -0
  63. package/omni_ai/vendor/prompt_toolkit/enums.py +19 -0
  64. package/omni_ai/vendor/prompt_toolkit/eventloop/__init__.py +31 -0
  65. package/omni_ai/vendor/prompt_toolkit/eventloop/async_generator.py +125 -0
  66. package/omni_ai/vendor/prompt_toolkit/eventloop/inputhook.py +191 -0
  67. package/omni_ai/vendor/prompt_toolkit/eventloop/utils.py +101 -0
  68. package/omni_ai/vendor/prompt_toolkit/eventloop/win32.py +72 -0
  69. package/omni_ai/vendor/prompt_toolkit/filters/__init__.py +71 -0
  70. package/omni_ai/vendor/prompt_toolkit/filters/app.py +419 -0
  71. package/omni_ai/vendor/prompt_toolkit/filters/base.py +261 -0
  72. package/omni_ai/vendor/prompt_toolkit/filters/cli.py +65 -0
  73. package/omni_ai/vendor/prompt_toolkit/filters/utils.py +41 -0
  74. package/omni_ai/vendor/prompt_toolkit/formatted_text/__init__.py +59 -0
  75. package/omni_ai/vendor/prompt_toolkit/formatted_text/ansi.py +297 -0
  76. package/omni_ai/vendor/prompt_toolkit/formatted_text/base.py +179 -0
  77. package/omni_ai/vendor/prompt_toolkit/formatted_text/html.py +145 -0
  78. package/omni_ai/vendor/prompt_toolkit/formatted_text/pygments.py +32 -0
  79. package/omni_ai/vendor/prompt_toolkit/formatted_text/utils.py +103 -0
  80. package/omni_ai/vendor/prompt_toolkit/history.py +306 -0
  81. package/omni_ai/vendor/prompt_toolkit/input/__init__.py +14 -0
  82. package/omni_ai/vendor/prompt_toolkit/input/ansi_escape_sequences.py +344 -0
  83. package/omni_ai/vendor/prompt_toolkit/input/base.py +153 -0
  84. package/omni_ai/vendor/prompt_toolkit/input/defaults.py +79 -0
  85. package/omni_ai/vendor/prompt_toolkit/input/posix_pipe.py +118 -0
  86. package/omni_ai/vendor/prompt_toolkit/input/posix_utils.py +97 -0
  87. package/omni_ai/vendor/prompt_toolkit/input/typeahead.py +78 -0
  88. package/omni_ai/vendor/prompt_toolkit/input/vt100.py +309 -0
  89. package/omni_ai/vendor/prompt_toolkit/input/vt100_parser.py +250 -0
  90. package/omni_ai/vendor/prompt_toolkit/input/win32.py +749 -0
  91. package/omni_ai/vendor/prompt_toolkit/input/win32_pipe.py +156 -0
  92. package/omni_ai/vendor/prompt_toolkit/key_binding/__init__.py +22 -0
  93. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/__init__.py +0 -0
  94. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/auto_suggest.py +66 -0
  95. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/basic.py +257 -0
  96. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/completion.py +206 -0
  97. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/cpr.py +30 -0
  98. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/emacs.py +563 -0
  99. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/focus.py +26 -0
  100. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/mouse.py +348 -0
  101. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/named_commands.py +691 -0
  102. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/open_in_editor.py +52 -0
  103. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/page_navigation.py +85 -0
  104. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/scroll.py +190 -0
  105. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/search.py +96 -0
  106. package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/vi.py +2233 -0
  107. package/omni_ai/vendor/prompt_toolkit/key_binding/defaults.py +63 -0
  108. package/omni_ai/vendor/prompt_toolkit/key_binding/digraphs.py +1378 -0
  109. package/omni_ai/vendor/prompt_toolkit/key_binding/emacs_state.py +36 -0
  110. package/omni_ai/vendor/prompt_toolkit/key_binding/key_bindings.py +670 -0
  111. package/omni_ai/vendor/prompt_toolkit/key_binding/key_processor.py +526 -0
  112. package/omni_ai/vendor/prompt_toolkit/key_binding/vi_state.py +107 -0
  113. package/omni_ai/vendor/prompt_toolkit/keys.py +222 -0
  114. package/omni_ai/vendor/prompt_toolkit/layout/__init__.py +147 -0
  115. package/omni_ai/vendor/prompt_toolkit/layout/containers.py +2738 -0
  116. package/omni_ai/vendor/prompt_toolkit/layout/controls.py +945 -0
  117. package/omni_ai/vendor/prompt_toolkit/layout/dimension.py +220 -0
  118. package/omni_ai/vendor/prompt_toolkit/layout/dummy.py +40 -0
  119. package/omni_ai/vendor/prompt_toolkit/layout/layout.py +412 -0
  120. package/omni_ai/vendor/prompt_toolkit/layout/margins.py +304 -0
  121. package/omni_ai/vendor/prompt_toolkit/layout/menus.py +748 -0
  122. package/omni_ai/vendor/prompt_toolkit/layout/mouse_handlers.py +56 -0
  123. package/omni_ai/vendor/prompt_toolkit/layout/processors.py +1010 -0
  124. package/omni_ai/vendor/prompt_toolkit/layout/screen.py +323 -0
  125. package/omni_ai/vendor/prompt_toolkit/layout/scrollable_pane.py +494 -0
  126. package/omni_ai/vendor/prompt_toolkit/layout/utils.py +80 -0
  127. package/omni_ai/vendor/prompt_toolkit/lexers/__init__.py +21 -0
  128. package/omni_ai/vendor/prompt_toolkit/lexers/base.py +85 -0
  129. package/omni_ai/vendor/prompt_toolkit/lexers/pygments.py +328 -0
  130. package/omni_ai/vendor/prompt_toolkit/log.py +13 -0
  131. package/omni_ai/vendor/prompt_toolkit/mouse_events.py +85 -0
  132. package/omni_ai/vendor/prompt_toolkit/output/__init__.py +15 -0
  133. package/omni_ai/vendor/prompt_toolkit/output/base.py +332 -0
  134. package/omni_ai/vendor/prompt_toolkit/output/color_depth.py +64 -0
  135. package/omni_ai/vendor/prompt_toolkit/output/conemu.py +65 -0
  136. package/omni_ai/vendor/prompt_toolkit/output/defaults.py +106 -0
  137. package/omni_ai/vendor/prompt_toolkit/output/flush_stdout.py +87 -0
  138. package/omni_ai/vendor/prompt_toolkit/output/plain_text.py +143 -0
  139. package/omni_ai/vendor/prompt_toolkit/output/vt100.py +748 -0
  140. package/omni_ai/vendor/prompt_toolkit/output/win32.py +683 -0
  141. package/omni_ai/vendor/prompt_toolkit/output/windows10.py +128 -0
  142. package/omni_ai/vendor/prompt_toolkit/patch_stdout.py +297 -0
  143. package/omni_ai/vendor/prompt_toolkit/py.typed +0 -0
  144. package/omni_ai/vendor/prompt_toolkit/renderer.py +814 -0
  145. package/omni_ai/vendor/prompt_toolkit/search.py +226 -0
  146. package/omni_ai/vendor/prompt_toolkit/selection.py +58 -0
  147. package/omni_ai/vendor/prompt_toolkit/shortcuts/__init__.py +46 -0
  148. package/omni_ai/vendor/prompt_toolkit/shortcuts/dialogs.py +330 -0
  149. package/omni_ai/vendor/prompt_toolkit/shortcuts/progress_bar/__init__.py +33 -0
  150. package/omni_ai/vendor/prompt_toolkit/shortcuts/progress_bar/base.py +449 -0
  151. package/omni_ai/vendor/prompt_toolkit/shortcuts/progress_bar/formatters.py +431 -0
  152. package/omni_ai/vendor/prompt_toolkit/shortcuts/prompt.py +1513 -0
  153. package/omni_ai/vendor/prompt_toolkit/shortcuts/utils.py +239 -0
  154. package/omni_ai/vendor/prompt_toolkit/styles/__init__.py +67 -0
  155. package/omni_ai/vendor/prompt_toolkit/styles/base.py +184 -0
  156. package/omni_ai/vendor/prompt_toolkit/styles/defaults.py +236 -0
  157. package/omni_ai/vendor/prompt_toolkit/styles/named_colors.py +162 -0
  158. package/omni_ai/vendor/prompt_toolkit/styles/pygments.py +70 -0
  159. package/omni_ai/vendor/prompt_toolkit/styles/style.py +401 -0
  160. package/omni_ai/vendor/prompt_toolkit/styles/style_transformation.py +374 -0
  161. package/omni_ai/vendor/prompt_toolkit/token.py +9 -0
  162. package/omni_ai/vendor/prompt_toolkit/utils.py +327 -0
  163. package/omni_ai/vendor/prompt_toolkit/validation.py +192 -0
  164. package/omni_ai/vendor/prompt_toolkit/widgets/__init__.py +63 -0
  165. package/omni_ai/vendor/prompt_toolkit/widgets/base.py +995 -0
  166. package/omni_ai/vendor/prompt_toolkit/widgets/dialogs.py +108 -0
  167. package/omni_ai/vendor/prompt_toolkit/widgets/menus.py +374 -0
  168. package/omni_ai/vendor/prompt_toolkit/widgets/toolbars.py +370 -0
  169. package/omni_ai/vendor/prompt_toolkit/win32_types.py +229 -0
  170. package/omni_ai/vendor/wcwidth/LICENSE +27 -0
  171. package/omni_ai/vendor/wcwidth/__init__.py +29 -0
  172. package/omni_ai/vendor/wcwidth/table_vs16.py +125 -0
  173. package/omni_ai/vendor/wcwidth/table_wide.py +1493 -0
  174. package/omni_ai/vendor/wcwidth/table_zero.py +4843 -0
  175. package/omni_ai/vendor/wcwidth/unicode_versions.py +38 -0
  176. package/omni_ai/vendor/wcwidth/wcwidth.py +345 -0
  177. package/package.json +40 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 samuelrms
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,616 @@
1
- # Temporary Holding Version
1
+ # Omni AI CLI
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ ![npm](https://img.shields.io/badge/npm-em%20breve-1A1714)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-C4552F.svg)](LICENSE)
5
+ ![Plataformas](https://img.shields.io/badge/macOS%20·%20Linux%20·%20Windows-1A1714)
6
+ ![Idiomas](https://img.shields.io/badge/pt--BR%20·%20en%20·%20es%20·%20fr-C4552F)
7
+
8
+ > [English](docs/README.en.md) · [Español](docs/README.es.md) · [Français](docs/README.fr.md)
9
+
10
+ Um terminal de chat que junta **Claude Code, Codex, Cursor, Antigravity, Grok, DeepSeek e
11
+ OpenRouter** num lugar só. Você escreve a pergunta, o `ai` decide quem responde e, se a
12
+ ferramenta falhar ou estourar a cota, passa para a próxima sem você fazer nada.
13
+
14
+ Enquanto uma resposta está sendo gerada, a caixa de entrada continua livre: você segue
15
+ mandando pedidos, eles entram numa fila visível acima da caixa e rodam em ordem.
16
+
17
+ Perguntas simples vão para as ferramentas mais baratas. Tarefas pesadas vão para o
18
+ Claude, com troca automática entre várias contas quando uma bate no limite. O histórico
19
+ fica salvo, a interface fala português, inglês, espanhol e francês, e modelos e contas
20
+ se configuram de dentro do próprio chat.
21
+
22
+ ---
23
+
24
+ ## Índice
25
+
26
+ - [Como funciona](#como-funciona)
27
+ - [Instalação](#instalação)
28
+ - [Como usar](#como-usar)
29
+ - [Comandos do chat](#comandos-do-chat)
30
+ - [Modelos](#modelos)
31
+ - [Contas Claude](#contas-claude)
32
+ - [Chaves de API](#chaves-de-api)
33
+ - [Modos](#modos)
34
+ - [Skills e MCP](#skills-e-mcp)
35
+ - [Uso direto, sem chat](#uso-direto-sem-chat)
36
+ - [Onde ficam os arquivos](#onde-ficam-os-arquivos)
37
+ - [Estrutura do projeto](#estrutura-do-projeto)
38
+ - [Testes](#testes)
39
+ - [Troubleshooting](#troubleshooting)
40
+ - [Limitações conhecidas](#limitações-conhecidas)
41
+ - [Privacidade](#privacidade)
42
+ - [Licença](#licença)
43
+
44
+ ---
45
+
46
+ ## Como funciona
47
+
48
+ Da linha digitada até a resposta salva. O chat (`chat.py`) não chama nenhuma IA
49
+ direto: ele dispara o roteador (`cli.py`) como subprocesso e lê os eventos que ele
50
+ emite, linha a linha, para mostrar quem está atendendo e o que está fazendo.
51
+
52
+ ```mermaid
53
+ flowchart TD
54
+ A["Você digita e tecla Enter<br/>(a caixa nunca trava)"] --> B{"Começa com / ?"}
55
+ B -- sim --> C["Comando interno<br/>/model · /account · /key · /lang · /versions"]
56
+ C --> C1["config.py grava em<br/>models.json, profiles.json ou keys/"]
57
+ B -- não --> FQ["Entra na fila<br/>com a ferramenta do momento do envio"]
58
+
59
+ subgraph CHAT ["chat.py — chat"]
60
+ FQ --> FW{"Esperou na fila e a resposta<br/>anterior já resolve o pedido?"}
61
+ FW -- "sim (classificador grátis)" --> FS["Pulado, avisa na tela"]
62
+ FW -- não --> D["Monta o contexto: últimas mensagens<br/>da sessão até 48 mil caracteres + idioma"]
63
+ D --> E["Worker em thread dispara o roteador<br/>em grupo de processos próprio"]
64
+ E -. "eventos JSON linha a linha" .-> F["Mostra provedor, comandos e resposta"]
65
+ X["Ctrl-C"] -. "esvazia a fila; SIGTERM no grupo,<br/>após 5 s, SIGKILL" .-> E
66
+ end
67
+
68
+ subgraph ROUTER ["cli.py — roteador"]
69
+ E --> G["Carrega modelos:<br/>env > models.json > padrão"]
70
+ G --> H{"Ferramenta fixada<br/>com /tool?"}
71
+ H -- sim --> H1["Só a ferramenta escolhida"]
72
+ H -- auto --> I{"Classifica: Groq → Cerebras →<br/>OpenRouter grátis → Grok;<br/>sem resposta, palavras-chave"}
73
+ I -- simples --> J["OpenRouter: gratuitos, ou pagos<br/>se autorizados · dados pessoais mascarados"]
74
+ J -- "sem chave ou falhou" --> K["Codex: assinatura,<br/>depois chave de API"]
75
+ K -- falhou --> L["Antigravity: assinatura,<br/>depois chave de API"]
76
+ L -- falhou --> LP["Pagos só se listados em fallback_order:<br/>Cursor, Grok, DeepSeek"]
77
+ LP -- falhou --> M
78
+ I -- complexa --> M["Claude: próxima conta ativa<br/>por prioridade"]
79
+ M --> N{"Rate limit?"}
80
+ N -- sim --> O["Conta em cooldown de 60 min"]
81
+ O --> P{"Outra conta<br/>disponível?"}
82
+ P -- sim --> M
83
+ P -- não --> PK{"Chave de API<br/>da Anthropic?"}
84
+ PK -- sim --> PK1["Claude com ANTHROPIC_API_KEY"]
85
+ PK1 -- ok --> R
86
+ PK1 -- falhou --> Q
87
+ PK -- não --> Q["Último recurso:<br/>Codex, depois Antigravity"]
88
+ end
89
+
90
+ N -- não --> R["Resposta"]
91
+ J -- ok --> R
92
+ K -- ok --> R
93
+ L -- ok --> R
94
+ LP -- ok --> R
95
+ Q --> R
96
+ H1 --> R
97
+ R --> F
98
+ F --> S[("Sessão salva em disco<br/>com escrita atômica")]
99
+ S --> FQ
100
+ ```
101
+
102
+ Três detalhes que o diagrama torna explícitos:
103
+
104
+ - **Cada conta Claude tem sua própria pasta de login.** Contas extras rodam com
105
+ `CLAUDE_CONFIG_DIR` apontando para `~/.claude-accounts/<nome>`. A conta principal
106
+ nunca é deslogada, e nenhuma credencial é copiada de um lugar para outro. Copiar o
107
+ `.credentials.json` não funciona de forma confiável no macOS, onde o login fica no
108
+ Keychain.
109
+ - **Ctrl-C mata a árvore inteira.** O roteador roda num grupo de processos próprio, então
110
+ cancelar encerra também o `claude`, o `codex` ou o `agy` que estiver rodando embaixo,
111
+ em vez de deixar processos órfãos gastando cota.
112
+ - **A fila não bloqueia nada.** Acima da caixa aparece o pedido em execução, o tempo e
113
+ os próximos da fila. Um pedido que esperou passa por um classificador grátis antes de
114
+ rodar: se a resposta anterior já o resolve, ele é pulado. Comandos e skills sempre
115
+ rodam. Ctrl-C com a fila ativa cancela tudo sem sair do chat. Se você fechar o chat com
116
+ pedidos na fila, eles ficam salvos na sessão e o `ai --resume ID` pergunta se quer continuar.
117
+ - **Cada resposta mostra quanto custou.** No fim de cada pedido aparecem os tokens e, quando
118
+ a ferramenta informa (OpenRouter, Grok, Claude com chave de API), o custo em dólar. O
119
+ `/usage` soma o gasto do dia por ferramenta.
120
+ - **Você vê por que a ferramenta foi escolhida.** No modo `auto`, uma linha curta diz se o
121
+ pedido foi tratado como tarefa de código ou pergunta simples e quem classificou (Groq,
122
+ Cerebras, OpenRouter, Grok ou as palavras-chave).
123
+ - **Só a resposta entra no histórico.** Linhas de status e diagnóstico aparecem na tela,
124
+ mas não são enviadas como contexto na próxima pergunta. Raciocínio interno dos modelos
125
+ também é descartado.
126
+
127
+ ---
128
+
129
+ ## Instalação
130
+
131
+ Um comando instala tudo e, rodado de novo, atualiza. Suas contas, chaves e modelos ficam em `~/.config/smart-ai` e não são tocados.
132
+
133
+ **macOS e Linux**:
134
+
135
+ ```bash
136
+ curl -fsSL https://raw.githubusercontent.com/samuelrms/omni-ai-cli/main/get.sh | bash
137
+ ```
138
+
139
+ **Windows** (PowerShell):
140
+
141
+ ```powershell
142
+ irm https://raw.githubusercontent.com/samuelrms/omni-ai-cli/main/get.ps1 | iex
143
+ ```
144
+
145
+ **Em breve no npm, yarn, pnpm e bun.** O pacote `omni-ai-cli` está pronto e sai assim que a publicação for liberada:
146
+
147
+ ```bash
148
+ npm install -g omni-ai-cli
149
+ yarn global add omni-ai-cli
150
+ pnpm add -g omni-ai-cli
151
+ bun add -g omni-ai-cli
152
+ ```
153
+
154
+ Por enquanto, use o comando de macOS/Linux ou Windows acima.
155
+
156
+ Para atualizar depois: `ai --update` (ou `/update` no chat).
157
+
158
+ Pelo código-fonte, para desenvolver:
159
+
160
+ ```bash
161
+ git clone https://github.com/samuelrms/omni-ai-cli ~/dev/omni-ai-cli
162
+ cd ~/dev/omni-ai-cli && ./scripts/install.sh # Windows: powershell -File scripts\install.ps1
163
+ ```
164
+
165
+ O instalador:
166
+
167
+ 1. instala o **Claude Code** pelo instalador oficial se ele ainda não estiver na máquina;
168
+ 2. abre o login da conta principal se ainda não houver um;
169
+ 3. cria o comando `ai` em `~/.local/bin`;
170
+ 4. mostra as contas Claude configuradas.
171
+
172
+ Requisitos: nenhum além de `curl` (macOS/Linux) ou PowerShell (Windows). Se não houver Python 3.11+, o instalador baixa um Python 3.12 só para o Omni AI, sem sudo e sem mexer no Python do sistema.
173
+ Codex (`codex`) e Antigravity (`agy`) são opcionais e entram na fila de alternativas quando estão instalados.
174
+
175
+ Se `~/.local/bin` não estiver no `PATH`, adicione ao `~/.zshrc`:
176
+
177
+ ```bash
178
+ export PATH="$HOME/.local/bin:$PATH"
179
+ ```
180
+
181
+ No Windows, o instalador cria `ai.cmd` em `%USERPROFILE%\.local\bin` e adiciona essa pasta ao `PATH`; abra um terminal novo depois.
182
+
183
+ ---
184
+
185
+ ## Como usar
186
+
187
+ ```bash
188
+ ai
189
+ ```
190
+
191
+ Na primeira vez ele pergunta o idioma e oferece instalar as ferramentas que faltam
192
+ (Claude Code, Codex, Cursor, Grok Build) com os instaladores oficiais. O Antigravity se
193
+ instala pela página dele. Depois é só escrever e teclar Enter.
194
+
195
+ | Tecla | Ação |
196
+ | --- | --- |
197
+ | Enter | Envia |
198
+ | ↑ / ↓ | Linhas anteriores |
199
+ | Ctrl-C | Durante a resposta: cancela. No prompt: salva e sai |
200
+ | Ctrl-D | Salva e sai |
201
+ | `\` + Enter · Shift+Enter · Option+Enter | Nova linha sem enviar (Shift+Enter no iTerm2, Ghostty, Kitty, WezTerm e VS Code; no Terminal do Mac use `\` + Enter) |
202
+ | Tab | Completa comandos e skills |
203
+
204
+ No menu do Tab, cada item termina dizendo de quem é: `omni`, `claude`, `codex` ou `agy`. Ao escolher
205
+ uma skill que tem argumentos (como `/pr-review [pr-number | --branch]`), o chat pergunta os
206
+ argumentos: Tab mostra as opções, dá para escrever o próprio texto, e Enter sem nada roda sem argumentos.
207
+
208
+ A tela segue o estilo do Claude Code e do Codex: caixa de entrada no rodapé com a barra de status
209
+ (ferramenta, modelo, modo e pasta), Tab para completar comandos e skills, cada ação da IA numa linha
210
+ (`● Ran …`, `● Edited …`, `● Called …`) com a saída recolhida, respostas em markdown e um indicador
211
+ "Trabalhando…" com o tempo. Ao abrir, uma splash de 1,5 s em tela cheia (Ctrl-C pula;
212
+ `SMART_AI_NO_SPLASH=1` desliga).
213
+
214
+ Ao sair, ele mostra o comando para voltar à mesma conversa:
215
+
216
+ ```text
217
+ Sessão salva. Retome com: ai --resume 1f3a9c2b7d40
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Comandos do chat
223
+
224
+ | Comando | O que faz |
225
+ | --- | --- |
226
+ | `/tool auto\|claude\|codex\|cursor\|agy\|openrouter\|grok\|deepseek` | Fixa uma ferramenta (`auto` decide sozinho) |
227
+ | `/model` | Lista os modelos de cada ferramenta |
228
+ | `/model codex gpt-6-astra` | Troca um modelo |
229
+ | `/model codex default` | Volta ao padrão |
230
+ | `/account` | Lista as contas Claude e se estão logadas |
231
+ | `/account add pessoal` | Cria uma conta e abre o login do Claude ali mesmo |
232
+ | `/account login NOME` | Refaz o login de uma conta |
233
+ | `/account sync NOME` | Recompartilha skills, plugins e MCPs da conta principal |
234
+ | `/account disable\|enable\|remove NOME` | Desativa, reativa ou remove |
235
+ | `/key` | Lista as chaves de API configuradas (mascaradas) |
236
+ | `/key claude\|codex\|cursor\|agy\|openrouter\|grok\|deepseek\|groq\|cerebras` | Adiciona uma chave, sem mostrar o que você digita |
237
+ | `/key add FERRAMENTA [NOME]` | Mais uma chave para a mesma ferramenta (vale para todas, inclusive Claude); as chaves são tentadas em ordem quando uma falha ou bate no limite |
238
+ | `/key remove FERRAMENTA [NOME]` | Remove a chave (sem nome, a principal) |
239
+ | `/status` · `/reset` | Status das contas · zera cooldowns |
240
+ | `/lang pt\|en\|es\|fr` | Muda o idioma |
241
+ | `/mode default\|plan\|edits\|auto\|yolo` | Modo de permissão, igual nas três ferramentas |
242
+ | `/sync` | Compartilha MCPs e skills entre Claude, Codex e Antigravity |
243
+ | `/usage [watch]` · `/limits` | Uso real de cada conta em barras (e-mail, plano, % da janela de 5 h e da semana, horário de reset) para Claude e Codex; gasto da chave no OpenRouter; nas demais, o aviso de limite que a ferramenta deu. `watch` atualiza a cada 30 s |
244
+ | `/queue [rm\|up\|down N\|clear]` | Mostra a fila; tira (`rm`), sobe (`up`), desce (`down`) um pedido ou esvazia (`clear`) o que espera |
245
+ | `/versions [N]` | O que mudou em cada versão, mais recente primeiro; `N` abre a nota técnica. Antes da primeira release, mostra os `feat`/`fix` do `main`. Os títulos saem no idioma do chat (traduzidos pelos classificadores grátis e guardados). Ao abrir o chat, uma linha avisa quando há versão nova. |
246
+ | `/clear` · `/compact` | Limpar a conversa · resumir a conversa num único bloco para economizar contexto |
247
+ | `/claude:usage` · `/codex:status` · `/agy:usage` … | Comandos nativos de cada ferramenta: abre a tela dela e volta ao Omni ao sair |
248
+ | `/setup [install]` | Guia de primeiro acesso: o que falta instalar, logar e configurar; `install` instala as ferramentas que faltam |
249
+ | `/terminal-setup` | Mostra como ter Shift+Enter (ou Option+Enter) para nova linha no seu terminal |
250
+ | `/skills` | Lista skills e comandos do projeto e do usuário, de Claude, Codex e Antigravity |
251
+ | `/nome args` | Roda a skill ou comando (ex.: `/pr-review 237`). Tab completa |
252
+ | `/history` · `/sent` · `/trace` | Conversa · o que foi enviado · eventos da execução |
253
+ | `/sessions` · `/resume ID` · `/new` | Sessões salvas |
254
+ | `/parallel codex: tarefa \| deepseek: tarefa` | 2 a 4 análises em paralelo, somente leitura (codex, openrouter, grok, deepseek) |
255
+ | `/help` · `/exit` | Ajuda · sair |
256
+
257
+ Enquanto a fila roda, `/clear`, `/new`, `/resume`, `/key`, `/usage` e os comandos nativos
258
+ esperam: eles tomam o terminal ou trocam a sessão. O resto funciona na hora.
259
+
260
+ Os comandos de configuração também funcionam fora do chat: `ai --model`,
261
+ `ai --account add pessoal`, `ai --key claude`, `ai --status`, `ai --reset`.
262
+
263
+ ---
264
+
265
+ ## Modelos
266
+
267
+ | Chave | Padrão | Valores aceitos |
268
+ | --- | --- | --- |
269
+ | `claude` | `opus` (o mais capaz) | `opus`, `sonnet`, `haiku` ou ID completo |
270
+ | `codex` | `gpt-6-astra` | ID de modelo do Codex |
271
+ | `codex_effort` | `high` | `minimal`, `low`, `medium`, `high`, `xhigh` |
272
+ | `agy` | padrão do Antigravity | ID de modelo do Antigravity |
273
+ | `openrouter` | automático (gratuito) | ID do modelo; pago só com `openrouter_paid on` |
274
+ | `openrouter_paid` | `off` | `on` autoriza modelos pagos do OpenRouter |
275
+ | `grok` | padrão do Grok | ID de modelo da xAI |
276
+ | `deepseek` | `deepseek-chat` | `deepseek-chat`, `deepseek-reasoner` |
277
+ | `cursor` | padrão da conta Cursor | ID de modelo do Cursor CLI |
278
+
279
+ A ordem de prioridade é: variável de ambiente, depois o que foi salvo com `/model` (em
280
+ `~/.config/smart-ai/models.json`), depois o padrão. As variáveis são
281
+ `SMART_AI_CLAUDE_MODEL`, `SMART_AI_CODEX_MODEL`, `SMART_AI_CODEX_EFFORT`,
282
+ `SMART_AI_AGY_MODEL`, `SMART_AI_OPENROUTER_MODEL`, `SMART_AI_GROK_MODEL`,
283
+ `SMART_AI_DEEPSEEK_MODEL` e `SMART_AI_CURSOR_MODEL`. Quando uma delas está definida, o
284
+ `/model` avisa que ela tem precedência.
285
+
286
+ ---
287
+
288
+ ## Contas Claude
289
+
290
+ ```text
291
+ ai [auto] › /account add trabalho
292
+ Abrindo login do Claude para a conta "trabalho" (pasta isolada ~/.claude-accounts/trabalho).
293
+ Sua conta principal não é afetada.
294
+ ✓ Conta "trabalho" adicionada com prioridade 3.
295
+ ```
296
+
297
+ As contas são tentadas por ordem de prioridade. A que bate no limite entra em cooldown
298
+ (60 minutos por padrão, ajustável em `~/.config/smart-ai/profiles.json`) e a próxima assume. A conta
299
+ `primary` usa o login normal do Claude (`claude auth login`).
300
+
301
+ Skills, plugins, agentes, `CLAUDE.md`, `settings.json` e os servidores MCP da conta
302
+ principal são compartilhados com cada conta extra no login. Só o login fica separado.
303
+ Se você instalar uma skill ou um MCP novo depois, rode `/account sync NOME`.
304
+
305
+
306
+ ---
307
+
308
+ ## Chaves de API
309
+
310
+ Além das assinaturas, cada ferramenta aceita uma chave de API. **A assinatura vem
311
+ primeiro**; a chave só entra quando a assinatura falha ou bate no limite, porque chave é
312
+ cobrada por uso. O OpenRouter funciona só com chave.
313
+
314
+ | Ferramenta | Comando | Variável que o CLI recebe | Onde criar |
315
+ | --- | --- | --- | --- |
316
+ | Claude | `/key claude` | `ANTHROPIC_API_KEY` | console.anthropic.com/settings/keys |
317
+ | Codex | `/key codex` | `CODEX_API_KEY` | platform.openai.com/api-keys |
318
+ | Antigravity | `/key agy` | `GEMINI_API_KEY` | aistudio.google.com/apikey |
319
+ | OpenRouter | `/key openrouter` | `OPENROUTER_API_KEY` | openrouter.ai/keys |
320
+ | Cursor | `/key cursor` | `CURSOR_API_KEY` | cursor.com/dashboard → Integrations |
321
+ | Grok | `/key grok` | `XAI_API_KEY` | console.x.ai |
322
+ | DeepSeek | `/key deepseek` | `DEEPSEEK_API_KEY` | platform.deepseek.com/api_keys |
323
+ | Groq (classificador) | `/key groq` | `GROQ_API_KEY` | console.groq.com/keys |
324
+ | Cerebras (classificador) | `/key cerebras` | `CEREBRAS_API_KEY` | cloud.cerebras.ai |
325
+
326
+ O Cursor usa primeiro o login da conta (`cursor-agent login`) e só depois as chaves. O
327
+ DeepSeek, como o OpenRouter, funciona só com chave e mascara dados pessoais antes do
328
+ envio. Groq e Cerebras não respondem perguntas: só classificam cada pedido (grátis) e
329
+ checam se um pedido da fila já foi resolvido.
330
+
331
+ ```text
332
+ ai [auto] › /key claude
333
+ Chave de claude (console.anthropic.com/settings/keys). Cole e tecle Enter; ela não aparece na tela.
334
+ >
335
+ ✓ Chave de claude salva em ~/.config/smart-ai/keys/claude (permissão 600).
336
+ ```
337
+
338
+ As chaves ficam em `~/.config/smart-ai/keys/`, uma por arquivo, com permissão 600, e
339
+ são passadas só ao processo da ferramenta, nunca ao histórico nem ao log. Se a variável
340
+ já estiver definida no ambiente, ela tem precedência. `/key` lista o que está
341
+ configurado, mostrando só o início e o fim de cada chave.
342
+
343
+ No Claude, a chave funciona como uma conta extra depois de todas as assinaturas: se ela
344
+ também bater no limite, entra em cooldown como as outras.
345
+
346
+ > **Nunca cole uma chave como comando no shell.** Ela fica gravada no histórico do zsh.
347
+ > Se isso acontecer, revogue a chave no site da ferramenta e apague a linha de
348
+ > `~/.zsh_history`.
349
+
350
+ No OpenRouter, o padrão é usar só modelos gratuitos: o cliente escolhe até três
351
+ variantes `:free` do catálogo e usa `openrouter/free` como última alternativa. Modelos
352
+ pagos ficam bloqueados até você autorizar:
353
+
354
+ ```text
355
+ /model openrouter_paid on # autoriza; avisa que será cobrado na sua conta
356
+ /model openrouter anthropic/claude-opus-5.5
357
+ /model openrouter_paid off # bloqueia de novo e volta ao gratuito
358
+ ```
359
+
360
+ Com a autorização ligada, o modelo escolhido vem primeiro e os gratuitos ficam como
361
+ reserva. Desligada, o limite de preço zero é enviado em toda chamada, então nenhum
362
+ modelo pago responde.
363
+
364
+ ---
365
+
366
+ ## Modos
367
+
368
+ O modo vale para Claude, Codex e Antigravity ao mesmo tempo e aparece no prompt
369
+ (`ai [auto · plan] ›`). Cada sessão guarda o seu.
370
+
371
+ | Modo | O que faz | Claude | Codex | Antigravity |
372
+ | --- | --- | --- | --- | --- |
373
+ | `default` | Padrão de cada ferramenta | — | — | — |
374
+ | `plan` | Só lê e planeja, não altera nada | `plan` | `--sandbox read-only` | `--mode plan` |
375
+ | `edits` | Aceita edições de arquivo | `acceptEdits` | `--sandbox workspace-write` | `--mode accept-edits` |
376
+ | `auto` | Age sozinho, com as proteções da ferramenta | `auto` | `workspace-write`, sem aprovação | `--mode auto` |
377
+ | `yolo` | Sem permissões nem sandbox | `bypassPermissions` | `--dangerously-bypass-approvals-and-sandbox` | `--dangerously-skip-permissions` |
378
+
379
+ `/mode yolo` pede confirmação, porque a IA passa a poder apagar arquivos e rodar qualquer
380
+ comando. Fora do chat: `ai --mode plan "pergunta"`. O `/parallel` roda sempre em `plan`.
381
+
382
+ ---
383
+
384
+ ## Skills e MCP
385
+
386
+ O `ai` chama os próprios CLIs, então cada um usa as skills e os MCPs que já tem. O
387
+ `/sync` junta tudo e instala em cada ferramenta o que só existe nas outras:
388
+
389
+ ```text
390
+ ai [auto] › /sync
391
+ Ferramentas encontradas: claude, codex, agy
392
+ MCP github codex → claude
393
+ MCP obsidian claude → codex
394
+ skill humanizer claude → codex (~/.agents/skills/humanizer)
395
+ Aplicar? [s/N]
396
+ ```
397
+
398
+ - Os MCPs são adicionados pelo comando `mcp add` de cada CLI, não editando arquivos na mão.
399
+ - O mesmo servidor com nomes diferentes é reconhecido pelo pacote ou URL e não é duplicado.
400
+ - MCPs que vêm dentro de um app (como os do Codex.app) ficam só nele.
401
+ - As skills são compartilhadas por atalho: `~/.claude/skills`, `~/.agents/skills` (Codex) e
402
+ `~/.gemini/antigravity/skills`. Editar uma vale para as três.
403
+ - As contas Claude extras são atualizadas junto.
404
+ - Variáveis de ambiente dos MCPs, que podem ter tokens, são copiadas para a config da
405
+ outra ferramenta. O `/sync` avisa antes.
406
+ - `/sync --dry-run` só mostra o que faria.
407
+
408
+ **Skills e comandos do projeto:** o chat lê `.claude/commands`, `.claude/skills`, `.agents/skills` e
409
+ `.agent/workflows` do projeto aberto, além das pastas do usuário. `/pr-review 237` vai para o
410
+ Claude do jeito que foi digitado, e ele executa o comando nativamente. Uma skill que só existe
411
+ no Codex ou no Antigravity vai para essa ferramenta, com as instruções do arquivo no pedido.
412
+
413
+ Como o chat não repassa pedidos de aprovação, uma ferramenta de MCP só roda se já estiver
414
+ liberada nas permissões do CLI ou se o modo for `auto` ou `yolo`. O OpenRouter não tem
415
+ skills nem MCP.
416
+
417
+ ---
418
+
419
+ ## Uso direto, sem chat
420
+
421
+ ```bash
422
+ ai "o que é um design pattern?" # roteamento automático
423
+ ai --claude "refatorar o módulo X" # força Claude
424
+ ai --codex "explicar REST" # força Codex
425
+ ai --agy "pesquisar React hooks" # força Antigravity
426
+ ai --openrouter "explicar Docker" # força OpenRouter
427
+ ai --cursor "corrigir o teste X" # força Cursor
428
+ ai --deepseek "explicar CAP theorem" # força DeepSeek
429
+ ai --install # instala as ferramentas que faltam (pergunta antes)
430
+ ai --classify "prompt" # mostra como seria classificado
431
+ ai --log # últimas chamadas
432
+ ```
433
+
434
+ ---
435
+
436
+ ## Onde ficam os arquivos
437
+
438
+ | Caminho | Conteúdo |
439
+ | --- | --- |
440
+ | `~/.config/smart-ai/profiles.json` | Contas Claude e regras de roteamento |
441
+ | `~/.config/smart-ai/models.json` | Modelos escolhidos com `/model` |
442
+ | `~/.config/smart-ai/lang` | Idioma do chat |
443
+ | `~/.config/smart-ai/keys/<ferramenta>` | Chaves de API, uma por arquivo (permissão 600) |
444
+ | `~/.claude-accounts/<nome>/` | Login isolado de cada conta Claude extra |
445
+ | `~/.local/share/smart-ai/sessions/` | Sessões do chat |
446
+ | `~/.cache/smart-ai/state.json` | Cooldowns ativos |
447
+ | `~/.cache/smart-ai/usage.log` | Log de uso, só metadados |
448
+ | `~/.cache/smart-ai/costs.jsonl` | Custo e tokens de cada pedido do chat, sem pergunta nem resposta (soma do dia no `/usage`) |
449
+
450
+ ---
451
+
452
+ ## Estrutura do projeto
453
+
454
+ ```text
455
+ omni-ai-cli/
456
+ ├── omni_ai/ # o programa (pacote Python)
457
+ │ ├── tools.py # cadastro único das ferramentas: nome, cor, CLI, modelo, chave
458
+ │ ├── cli.py # comando ai: classifica, roteia e executa cada ferramenta
459
+ │ ├── chat.py # chat: sessões, eventos, Ctrl-C, idiomas
460
+ │ ├── ui.py # visual: caixa de entrada, barra de status, ações e respostas
461
+ │ ├── skills.py # skills e comandos do projeto, do usuário e nativos
462
+ │ ├── config.py # modelos, chaves e contas Claude (/model, /key, /account)
463
+ │ ├── sync.py # /sync: MCPs e skills entre as três ferramentas
464
+ │ ├── openrouter.py # cliente OpenRouter: gratuitos, pagos só se autorizados
465
+ │ ├── grok.py # cliente xAI, reaproveitado pelo DeepSeek
466
+ │ ├── deepseek.py # cliente DeepSeek com dados pessoais mascarados
467
+ │ ├── pii.py # mascara e restaura dados pessoais
468
+ │ ├── osutils.py # diferenças entre macOS, Linux e Windows
469
+ │ ├── profiles.json # modelo inicial; o seu fica em ~/.config/smart-ai
470
+ │ └── vendor/ # prompt_toolkit e wcwidth embutidos (sem pip)
471
+ ├── bin/ai.js # lançador npm: acha ou instala o Python e roda o pacote
472
+ ├── scripts/ # install.sh, install.ps1 e ai.cmd
473
+ ├── docs/ # README em inglês, espanhol e francês
474
+ ├── tests/ # executáveis fictícios, sem consumir cota
475
+ ├── postman/ # simulação HTTP do OpenRouter
476
+ ├── get.sh / get.ps1 # instalação com um comando
477
+ └── package.json · LICENSE
478
+ ```
479
+
480
+ O roteador não sabe nada de chat: ele só executa uma pergunta e, com
481
+ `SMART_AI_EVENTS=1`, emite eventos JSON. O chat não sabe nada de credenciais: contas e
482
+ modelos passam pelo `config.py`.
483
+
484
+ ---
485
+
486
+ ## Testes
487
+
488
+ ```bash
489
+ python3 -m unittest discover -s tests -v
490
+ bash -n scripts/install.sh
491
+ ```
492
+
493
+ **38 testes**: persistência e retomada de sessão, limite de contexto, permissão dos
494
+ arquivos, sessão aberta em dois terminais, leitura de eventos, cancelamento da árvore de
495
+ processos, paralelismo real, sandbox somente leitura, mascaramento de dados pessoais,
496
+ fallback OpenRouter → Codex, validação de modelos, armazenamento das chaves e o ciclo de vida das contas. Todos os
497
+ executáveis são fictícios: **nenhum teste autentica nem consome assinatura.**
498
+
499
+ Para testar o HTTP do OpenRouter contra a simulação Postman:
500
+
501
+ ```bash
502
+ postman simulation run postman/simulations/openrouter.sim.yaml --port 4901 --no-history --output ndjson
503
+ SMART_AI_SIM_URL=http://127.0.0.1:4901/openrouter python3 -m unittest discover -s tests -v
504
+ ```
505
+
506
+ ---
507
+
508
+ ## Releases e branches
509
+
510
+ Publicação no npm é automática, feita pelo GitHub Actions com semantic-release. A versão
511
+ sai das mensagens de commit (Conventional Commits) — ninguém edita `version` no
512
+ `package.json` à mão.
513
+
514
+ | Branch | Publica como | Exemplo |
515
+ |---|---|---|
516
+ | `main` | `latest` | `1.4.0` |
517
+ | `next` | `next` (release candidate) | `1.5.0-rc.1` |
518
+ | `beta` | `beta` | `2.0.0-beta.1` |
519
+ | outras / PR | nada, só CI | — |
520
+
521
+ | Commit | Efeito na versão |
522
+ |---|---|
523
+ | `fix: ...` | patch (`1.4.0` → `1.4.1`) |
524
+ | `feat: ...` | minor (`1.4.0` → `1.5.0`) |
525
+ | `feat!: ...` ou `BREAKING CHANGE:` no corpo | major (`1.4.0` → `2.0.0`) |
526
+ | `docs:`, `ci:`, `chore:`, `test:`, `refactor:` | sem release |
527
+
528
+ Use squash merge: o título do PR vira o commit, e o workflow `PR title` bloqueia título
529
+ fora do padrão.
530
+
531
+ ### Mensagens de commit
532
+
533
+ O `/versions` mostra o título de cada `feat`/`fix` como a "visão simples" e o corpo como
534
+ "nota técnica". Por isso:
535
+
536
+ - **Título:** o que muda para quem usa, em inglês, no presente, sem nome de arquivo ou
537
+ função. `feat: keep the input free and queue new requests while one runs`, não
538
+ `feat: add Queue class to chat.py`.
539
+ - **Corpo:** o porquê e o comportamento novo em frases curtas; detalhes técnicos só no
540
+ fim, se ajudarem.
541
+ - Um commit por mudança perceptível. Refatoração e testes vão em `refactor:`/`test:`,
542
+ que não aparecem em `/versions`.
543
+
544
+ ```mermaid
545
+ flowchart TD
546
+ A[PR aberto] --> B[CI: testes Python 3.11-3.13 em Linux e macOS<br/>+ npm pack + launcher]
547
+ A --> C[PR title: Conventional Commits?]
548
+ B -->|falhou| X[Merge bloqueado]
549
+ C -->|fora do padrão| X
550
+ B -->|ok| D[Squash merge em main / next / beta]
551
+ C -->|ok| D
552
+ D --> E[Release: CI roda de novo]
553
+ E -->|falhou| Y[Nada é publicado]
554
+ E -->|ok| F{semantic-release:<br/>há feat/fix/breaking<br/>desde a última tag?}
555
+ F -->|não| Z[Sem release]
556
+ F -->|sim| G[Calcula versão e cria tag vX.Y.Z]
557
+ G --> H[npm publish com provenance<br/>no dist-tag da branch]
558
+ G --> I[GitHub Release com notas]
559
+ ```
560
+
561
+ Configuração única no GitHub:
562
+
563
+ 1. **Settings → Secrets and variables → Actions**: criar `NPM_TOKEN` (token *Automation*
564
+ ou *Granular* com permissão de publish no npmjs.com).
565
+ 2. **Settings → Branches**: proteger `main` (e `next`/`beta`, se usar) exigindo PR e os
566
+ checks `Tests (...)`, `npm package` e `conventional`.
567
+ 3. **Settings → General → Pull Requests**: deixar só *Allow squash merging* e marcar
568
+ *Default to pull request title*.
569
+
570
+ ---
571
+
572
+ ## Troubleshooting
573
+
574
+ | Problema | Solução |
575
+ | --- | --- |
576
+ | `OPENROUTER_API_KEY não configurada` | `/key openrouter` no chat ou `ai --key openrouter`. |
577
+ | `Arquivo de credenciais não encontrado` ou `Conta 'X' sem login` | `/account login X`. |
578
+ | `You've hit your session limit` | Cota da conta. O `ai` passa para a próxima; adicione outra com `/account add` ou uma chave com `/key claude`. |
579
+ | `Individual quota reached` (Antigravity) | Cota do Antigravity; ele é pulado até a renovação. |
580
+ | `Not inside a trusted directory` (Codex) | Instalação antiga. Rode o instalador de novo. |
581
+ | `Claude Code não instalado` | `./scripts/install.sh` (ou `scripts\install.ps1` no Windows) instala pelo instalador oficial. |
582
+ | Windows: atalhos de skills falham | Ative o Modo de Desenvolvedor ou rode como administrador; sem isso o `ai` usa junções de pasta. |
583
+ | `/model` não muda nada | Uma variável `SMART_AI_*_MODEL` está definida e tem precedência. |
584
+ | `/key` não muda nada | A variável da ferramenta (`ANTHROPIC_API_KEY` etc.) está definida e tem precedência. |
585
+ | `Sessão já aberta em outro terminal` | Feche o outro terminal ou use `/new`. |
586
+ | `ai: command not found` | Adicione `~/.local/bin` ao `PATH`. |
587
+
588
+ ---
589
+
590
+ ## Limitações conhecidas
591
+
592
+ - O chat usa os modos não interativos dos CLIs. Pedidos de aprovação nativos (por
593
+ exemplo, "posso editar este arquivo?") não aparecem; nesses casos, use o CLI nativo.
594
+ - `/parallel` só analisa: Codex em `--sandbox read-only` ou OpenRouter, que não acessa os
595
+ arquivos. Os agentes não editam o projeto ao mesmo tempo.
596
+ - A classificação simples/complexa é por palavras-chave e tamanho, não por um modelo.
597
+ - Trocar de modelo não renova a cota da conta.
598
+ - O OpenRouter não tem streaming nesta versão: a resposta aparece inteira no final.
599
+ - No Windows, o código usa os equivalentes nativos (grupo de processos e `taskkill`, `msvcrt`, junções de pasta), mas foi testado de verdade só no macOS.
600
+
601
+ ---
602
+
603
+ ## Privacidade
604
+
605
+ - Sessões, chaves de API e logs ficam só na sua máquina, com permissão restrita ao seu usuário.
606
+ - O log de uso grava ferramenta, conta e status, **nunca o texto da pergunta**.
607
+ - Antes de ir para o OpenRouter, e-mails, telefones, documentos e outros dados pessoais
608
+ são trocados por marcadores e restaurados na resposta. O mascaramento é por padrões e
609
+ não garante anonimização total.
610
+ - Claude, Codex e Antigravity recebem o texto original, sob os termos de cada serviço.
611
+
612
+ ---
613
+
614
+ ## Licença
615
+
616
+ [MIT](LICENSE). Bibliotecas embutidas em `vendor/`: prompt_toolkit (BSD-3-Clause) e wcwidth (MIT), com as licenças em cada pasta.