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
@@ -0,0 +1,618 @@
1
+ # Omni AI CLI
2
+
3
+ ![npm](https://img.shields.io/badge/npm-pr%C3%B3ximamente-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
+ > [Português](../README.md) · [English](README.en.md) · [Français](README.fr.md)
9
+
10
+ Una terminal de chat que reúne **Claude Code, Codex, Cursor, Antigravity, Grok, DeepSeek y
11
+ OpenRouter** en un solo lugar. Escribes la pregunta, `ai` decide quién responde y, si la
12
+ herramienta falla o agota la cuota, pasa a la siguiente sin que hagas nada.
13
+
14
+ Mientras se genera una respuesta, la caja de entrada sigue libre: puedes seguir enviando
15
+ pedidos, que entran en una cola visible sobre la caja y se ejecutan en orden.
16
+
17
+ Las preguntas simples van a las herramientas más baratas. Las tareas pesadas van a
18
+ Claude, con cambio automático entre varias cuentas cuando una llega al límite. El historial
19
+ queda guardado, la interfaz habla portugués, inglés, español y francés, y los modelos y
20
+ las cuentas se configuran desde el propio chat.
21
+
22
+ ---
23
+
24
+ ## Índice
25
+
26
+ - [Cómo funciona](#cómo-funciona)
27
+ - [Instalación](#instalación)
28
+ - [Cómo usar](#cómo-usar)
29
+ - [Comandos del chat](#comandos-del-chat)
30
+ - [Modelos](#modelos)
31
+ - [Cuentas de Claude](#cuentas-de-claude)
32
+ - [Claves de API](#claves-de-api)
33
+ - [Modos](#modos)
34
+ - [Skills y MCP](#skills-y-mcp)
35
+ - [Uso directo, sin chat](#uso-directo-sin-chat)
36
+ - [Dónde están los archivos](#dónde-están-los-archivos)
37
+ - [Estructura del proyecto](#estructura-del-proyecto)
38
+ - [Pruebas](#pruebas)
39
+ - [Troubleshooting](#troubleshooting)
40
+ - [Limitaciones conocidas](#limitaciones-conocidas)
41
+ - [Privacidad](#privacidad)
42
+ - [Licencia](#licencia)
43
+
44
+ ---
45
+
46
+ ## Cómo funciona
47
+
48
+ Desde la línea escrita hasta la respuesta guardada. El chat (`chat.py`) no llama a
49
+ ninguna IA directamente: lanza el enrutador (`cli.py`) como subproceso y lee los
50
+ eventos que este emite, línea por línea, para mostrar quién está atendiendo y qué está
51
+ haciendo.
52
+
53
+ ```mermaid
54
+ flowchart TD
55
+ A["Escribes y presionas Enter<br/>(la caja nunca se bloquea)"] --> B{"¿Empieza con / ?"}
56
+ B -- sí --> C["Comando interno<br/>/model · /account · /key · /lang · /versions"]
57
+ C --> C1["config.py guarda en<br/>models.json, profiles.json o keys/"]
58
+ B -- no --> FQ["Entra en la cola<br/>con la herramienta del momento del envío"]
59
+
60
+ subgraph CHAT ["chat.py — chat"]
61
+ FQ --> FW{"¿Esperó en la cola y la respuesta<br/>anterior ya resuelve el pedido?"}
62
+ FW -- "sí (clasificador gratis)" --> FS["Omitido, avisa en pantalla"]
63
+ FW -- no --> D["Arma el contexto: últimos mensajes<br/>de la sesión hasta 48 mil caracteres + idioma"]
64
+ D --> E["Worker en hilo lanza el enrutador<br/>en un grupo de procesos propio"]
65
+ E -. "eventos JSON línea por línea" .-> F["Muestra proveedor, comandos y respuesta"]
66
+ X["Ctrl-C"] -. "vacía la cola; SIGTERM al grupo,<br/>tras 5 s, SIGKILL" .-> E
67
+ end
68
+
69
+ subgraph ROUTER ["cli.py — enrutador"]
70
+ E --> G["Carga modelos:<br/>env > models.json > predeterminado"]
71
+ G --> H{"¿Herramienta fijada<br/>con /tool?"}
72
+ H -- sí --> H1["Solo la herramienta elegida"]
73
+ H -- auto --> I{"Clasifica: Groq → Cerebras →<br/>OpenRouter gratis → Grok;<br/>sin respuesta, palabras clave"}
74
+ I -- simple --> J["OpenRouter: gratuitos, o pagos<br/>si se autorizan · datos personales enmascarados"]
75
+ J -- "sin clave o falló" --> K["Codex: suscripción,<br/>luego clave de API"]
76
+ K -- falló --> L["Antigravity: suscripción,<br/>luego clave de API"]
77
+ L -- falló --> LP["De pago solo si están en fallback_order:<br/>Cursor, Grok, DeepSeek"]
78
+ LP -- falló --> M
79
+ I -- compleja --> M["Claude: siguiente cuenta activa<br/>por prioridad"]
80
+ M --> N{"¿Rate limit?"}
81
+ N -- sí --> O["Cuenta en cooldown de 60 min"]
82
+ O --> P{"¿Otra cuenta<br/>disponible?"}
83
+ P -- sí --> M
84
+ P -- no --> PK{"¿Clave de API<br/>de Anthropic?"}
85
+ PK -- sí --> PK1["Claude con ANTHROPIC_API_KEY"]
86
+ PK1 -- ok --> R
87
+ PK1 -- falló --> Q
88
+ PK -- no --> Q["Último recurso:<br/>Codex, luego Antigravity"]
89
+ end
90
+
91
+ N -- no --> R["Respuesta"]
92
+ J -- ok --> R
93
+ K -- ok --> R
94
+ L -- ok --> R
95
+ LP -- ok --> R
96
+ Q --> R
97
+ H1 --> R
98
+ R --> F
99
+ F --> S[("Sesión guardada en disco<br/>con escritura atómica")]
100
+ S --> FQ
101
+ ```
102
+
103
+ Tres detalles que el diagrama deja explícitos:
104
+
105
+ - **Cada cuenta de Claude tiene su propia carpeta de login.** Las cuentas adicionales
106
+ corren con `CLAUDE_CONFIG_DIR` apuntando a `~/.claude-accounts/<nombre>`. La cuenta
107
+ principal nunca se desloguea, y ninguna credencial se copia de un lugar a otro. Copiar
108
+ el `.credentials.json` no funciona de forma confiable en macOS, donde el login queda
109
+ en el Keychain.
110
+ - **Ctrl-C mata todo el árbol de procesos.** El enrutador corre en un grupo de procesos
111
+ propio, así que cancelar también termina el `claude`, el `codex` o el `agy` que esté
112
+ corriendo debajo, en lugar de dejar procesos huérfanos gastando cuota.
113
+ - **La cola no bloquea nada.** Sobre la caja aparecen el pedido en ejecución, el tiempo y
114
+ los siguientes de la cola. Un pedido que esperó pasa por un clasificador gratis antes de
115
+ ejecutarse: si la respuesta anterior ya lo resuelve, se omite. Los comandos y skills
116
+ siempre se ejecutan. Ctrl-C con la cola activa cancela todo sin salir del chat. Si cierras el chat
117
+ con pedidos en la cola, quedan guardados en la sesión y `ai --resume ID` pregunta si quieres continuar.
118
+ - **Cada respuesta muestra cuánto costó.** Al final de cada pedido aparecen los tokens y,
119
+ cuando la herramienta lo informa (OpenRouter, Grok, Claude con clave de API), el costo en
120
+ dólares. `/usage` suma el gasto del día por herramienta.
121
+ - **Ves por qué se eligió la herramienta.** En modo `auto`, una línea corta dice si el pedido
122
+ se trató como tarea de código o pregunta simple y quién lo clasificó (Groq, Cerebras,
123
+ OpenRouter, Grok o las palabras clave).
124
+ - **Solo la respuesta entra al historial.** Las líneas de estado y diagnóstico aparecen
125
+ en pantalla, pero no se envían como contexto en la siguiente pregunta. El razonamiento
126
+ interno de los modelos también se descarta.
127
+
128
+ ---
129
+
130
+ ## Instalación
131
+
132
+ Un comando instala todo y, ejecutado de nuevo, actualiza. Tus cuentas, claves y modelos quedan en `~/.config/smart-ai` y no se tocan.
133
+
134
+ **macOS y Linux**:
135
+
136
+ ```bash
137
+ curl -fsSL https://raw.githubusercontent.com/samuelrms/omni-ai-cli/main/get.sh | bash
138
+ ```
139
+
140
+ **Windows** (PowerShell):
141
+
142
+ ```powershell
143
+ irm https://raw.githubusercontent.com/samuelrms/omni-ai-cli/main/get.ps1 | iex
144
+ ```
145
+
146
+ **Pronto en npm, yarn, pnpm y bun.** El paquete `omni-ai-cli` está listo y sale en cuanto se libere la publicación:
147
+
148
+ ```bash
149
+ npm install -g omni-ai-cli
150
+ yarn global add omni-ai-cli
151
+ pnpm add -g omni-ai-cli
152
+ bun add -g omni-ai-cli
153
+ ```
154
+
155
+ Por ahora, usa el comando de macOS/Linux o Windows de arriba.
156
+
157
+ Para actualizar después: `ai --update` (o `/update` en el chat).
158
+
159
+ Desde el código fuente, para desarrollar:
160
+
161
+ ```bash
162
+ git clone https://github.com/samuelrms/omni-ai-cli ~/dev/omni-ai-cli
163
+ cd ~/dev/omni-ai-cli && ./scripts/install.sh # Windows: powershell -File scripts\install.ps1
164
+ ```
165
+
166
+ El instalador:
167
+
168
+ 1. instala **Claude Code** con el instalador oficial si todavía no está en la máquina;
169
+ 2. abre el login de la cuenta principal si aún no hay uno;
170
+ 3. crea el comando `ai` en `~/.local/bin`;
171
+ 4. muestra las cuentas de Claude configuradas.
172
+
173
+ Requisitos: nada más que `curl` (macOS/Linux) o PowerShell (Windows). Si falta Python 3.11+, el instalador descarga un Python 3.12 solo para Omni AI, sin sudo y sin tocar el Python del sistema.
174
+ Codex (`codex`) y Antigravity (`agy`) son opcionales y entran en la cola de alternativas cuando están instalados.
175
+
176
+ Si `~/.local/bin` no está en el `PATH`, agrégalo al `~/.zshrc`:
177
+
178
+ ```bash
179
+ export PATH="$HOME/.local/bin:$PATH"
180
+ ```
181
+
182
+ En Windows, el instalador crea `ai.cmd` en `%USERPROFILE%\.local\bin` y agrega esa carpeta al `PATH`; abre una terminal nueva después.
183
+
184
+ ---
185
+
186
+ ## Cómo usar
187
+
188
+ ```bash
189
+ ai
190
+ ```
191
+
192
+ La primera vez pregunta el idioma y ofrece instalar las herramientas que faltan
193
+ (Claude Code, Codex, Cursor, Grok Build) con los instaladores oficiales. Antigravity se
194
+ instala desde su página. Después solo escribe y presiona Enter.
195
+
196
+ | Tecla | Acción |
197
+ | --- | --- |
198
+ | Enter | Envía |
199
+ | ↑ / ↓ | Líneas anteriores |
200
+ | Ctrl-C | Durante la respuesta: cancela. En el prompt: guarda y sale |
201
+ | Ctrl-D | Guarda y sale |
202
+ | `\` + Enter · Shift+Enter · Option+Enter | Nueva línea sin enviar (Shift+Enter en iTerm2, Ghostty, Kitty, WezTerm y VS Code; en Terminal de macOS usa `\` + Enter) |
203
+ | Tab | Completa comandos y skills |
204
+
205
+ En el menú de Tab cada elemento termina diciendo de quién es: `omni`, `claude`, `codex` o `agy`. Al elegir
206
+ una skill con argumentos (como `/pr-review [pr-number | --branch]`), el chat los pregunta: Tab muestra
207
+ las opciones, puedes escribir tu propio texto, y Enter vacío la ejecuta sin argumentos.
208
+
209
+ La pantalla sigue el estilo de Claude Code y Codex: caja de entrada abajo con barra de estado
210
+ (herramienta, modelo, modo y carpeta), Tab para completar comandos y skills, cada acción de la IA
211
+ en una línea (`● Ran …`, `● Edited …`, `● Called …`) con la salida recogida, respuestas en markdown
212
+ y un indicador "Trabajando…" con el tiempo. Al abrir, una splash de 1,5 s a pantalla completa (Ctrl-C la
213
+ salta; `SMART_AI_NO_SPLASH=1` la desactiva).
214
+
215
+ Al salir, muestra el comando para volver a la misma conversación:
216
+
217
+ ```text
218
+ Sessão salva. Retome com: ai --resume 1f3a9c2b7d40
219
+ ```
220
+
221
+ ---
222
+
223
+ ## Comandos del chat
224
+
225
+ | Comando | Qué hace |
226
+ | --- | --- |
227
+ | `/tool auto\|claude\|codex\|cursor\|agy\|openrouter\|grok\|deepseek` | Fija una herramienta (`auto` decide solo) |
228
+ | `/model` | Lista los modelos de cada herramienta |
229
+ | `/model codex gpt-6-astra` | Cambia un modelo |
230
+ | `/model codex default` | Vuelve al predeterminado |
231
+ | `/account` | Lista las cuentas de Claude y si tienen sesión iniciada |
232
+ | `/account add pessoal` | Crea una cuenta y abre ahí mismo el login de Claude |
233
+ | `/account login NOME` | Rehace el login de una cuenta |
234
+ | `/account sync NOMBRE` | Vuelve a compartir skills, plugins y MCPs de la cuenta principal |
235
+ | `/account disable\|enable\|remove NOME` | Desactiva, reactiva o elimina |
236
+ | `/key` | Lista las claves de API configuradas (enmascaradas) |
237
+ | `/key claude\|codex\|cursor\|agy\|openrouter\|grok\|deepseek\|groq\|cerebras` | Agrega una clave, sin mostrar lo que escribes |
238
+ | `/key add HERRAMIENTA [NOMBRE]` | Una clave más para la misma herramienta (todas, incluido Claude); se prueban en orden cuando una falla o llega al límite |
239
+ | `/key remove HERRAMIENTA [NOMBRE]` | Elimina la clave (sin nombre, la principal) |
240
+ | `/status` · `/reset` | Estado de las cuentas · reinicia los cooldowns |
241
+ | `/lang pt\|en\|es\|fr` | Cambia el idioma |
242
+ | `/mode default\|plan\|edits\|auto\|yolo` | Modo de permisos, igual en las tres herramientas |
243
+ | `/sync` | Comparte MCPs y skills entre Claude, Codex y Antigravity |
244
+ | `/usage [watch]` · `/limits` | Uso real de cada cuenta en barras (e-mail, plan, % de la ventana de 5 h y semanal, hora de reinicio) para Claude y Codex; gasto de la clave en OpenRouter; en las demás, el aviso de límite que dio la herramienta. `watch` actualiza cada 30 s |
245
+ | `/queue [rm\|up\|down N\|clear]` | Muestra la cola; quita (`rm`), sube (`up`), baja (`down`) un pedido o vacía (`clear`) lo que espera |
246
+ | `/versions [N]` | Qué cambió en cada versión, la más reciente primero; `N` abre la nota técnica. Antes de la primera release, muestra los `feat`/`fix` de `main`. Los títulos salen en el idioma del chat (traducidos por los clasificadores gratis y guardados). Al abrir el chat, una línea avisa si hay versión nueva. |
247
+ | `/clear` · `/compact` | Limpiar la conversación · resumirla en un bloque para ahorrar contexto |
248
+ | `/claude:usage` · `/codex:status` · `/agy:usage` … | Comandos nativos de cada herramienta: abre su pantalla y vuelve a Omni al salir |
249
+ | `/setup [install]` | Guía de primer acceso: lo que falta instalar, iniciar sesión y configurar; `install` instala las herramientas que faltan |
250
+ | `/terminal-setup` | Muestra cómo tener Shift+Enter (u Option+Enter) para nueva línea en tu terminal |
251
+ | `/skills` | Lista skills y comandos del proyecto y del usuario, de Claude, Codex y Antigravity |
252
+ | `/nombre args` | Ejecuta la skill o comando (ej.: `/pr-review 237`). Tab completa |
253
+ | `/history` · `/sent` · `/trace` | Conversación · lo que se envió · eventos de la ejecución |
254
+ | `/sessions` · `/resume ID` · `/new` | Sesiones guardadas |
255
+ | `/parallel codex: tarefa \| deepseek: tarefa` | De 2 a 4 análisis en paralelo, solo lectura (codex, openrouter, grok, deepseek) |
256
+ | `/help` · `/exit` | Ayuda · salir |
257
+
258
+ Mientras la cola corre, `/clear`, `/new`, `/resume`, `/key`, `/usage` y los comandos nativos
259
+ esperan: toman la terminal o cambian la sesión. El resto funciona al instante.
260
+
261
+ Los comandos de configuración también funcionan fuera del chat: `ai --model`,
262
+ `ai --account add pessoal`, `ai --key claude`, `ai --status`, `ai --reset`.
263
+
264
+ ---
265
+
266
+ ## Modelos
267
+
268
+ | Clave | Predeterminado | Valores aceptados |
269
+ | --- | --- | --- |
270
+ | `claude` | `opus` (el más capaz) | `opus`, `sonnet`, `haiku` o ID completo |
271
+ | `codex` | `gpt-6-astra` | ID de modelo de Codex |
272
+ | `codex_effort` | `high` | `minimal`, `low`, `medium`, `high`, `xhigh` |
273
+ | `agy` | predeterminado de Antigravity | ID de modelo de Antigravity |
274
+ | `openrouter` | automático (gratuito) | ID del modelo; de pago solo con `openrouter_paid on` |
275
+ | `openrouter_paid` | `off` | `on` autoriza modelos de pago de OpenRouter |
276
+ | `grok` | predeterminado de Grok | ID de modelo de xAI |
277
+ | `deepseek` | `deepseek-chat` | `deepseek-chat`, `deepseek-reasoner` |
278
+ | `cursor` | predeterminado de la cuenta Cursor | ID de modelo de Cursor CLI |
279
+
280
+ El orden de prioridad es: variable de entorno, luego lo guardado con `/model` (en
281
+ `~/.config/smart-ai/models.json`), luego el predeterminado. Las variables son
282
+ `SMART_AI_CLAUDE_MODEL`, `SMART_AI_CODEX_MODEL`, `SMART_AI_CODEX_EFFORT`,
283
+ `SMART_AI_AGY_MODEL`, `SMART_AI_OPENROUTER_MODEL`, `SMART_AI_GROK_MODEL`,
284
+ `SMART_AI_DEEPSEEK_MODEL` y `SMART_AI_CURSOR_MODEL`. Cuando una de ellas está definida,
285
+ `/model` avisa que tiene precedencia.
286
+
287
+ ---
288
+
289
+ ## Cuentas de Claude
290
+
291
+ ```text
292
+ ai [auto] › /account add trabalho
293
+ Abrindo login do Claude para a conta "trabalho" (pasta isolada ~/.claude-accounts/trabalho).
294
+ Sua conta principal não é afetada.
295
+ ✓ Conta "trabalho" adicionada com prioridade 3.
296
+ ```
297
+
298
+ Las cuentas se prueban por orden de prioridad. La que llega al límite entra en cooldown
299
+ (60 minutos por defecto, ajustable en `profiles.json`) y la siguiente toma su lugar. La
300
+ cuenta `primary` usa el login normal de Claude (`claude auth login`).
301
+
302
+ Skills, plugins, agentes, `CLAUDE.md`, `settings.json` y los servidores MCP de la cuenta
303
+ principal se comparten con cada cuenta extra al iniciar sesión. Solo el login queda
304
+ separado. Si instalas una skill o un MCP nuevo después, ejecuta `/account sync NOMBRE`.
305
+
306
+
307
+ ---
308
+
309
+ ## Claves de API
310
+
311
+ Además de las suscripciones, cada herramienta acepta una clave de API. **La suscripción
312
+ va primero**; la clave solo entra cuando la suscripción falla o llega al límite, porque
313
+ la clave se cobra por uso. OpenRouter funciona solo con clave.
314
+
315
+ | Herramienta | Comando | Variable que recibe el CLI | Dónde crearla |
316
+ | --- | --- | --- | --- |
317
+ | Claude | `/key claude` | `ANTHROPIC_API_KEY` | console.anthropic.com/settings/keys |
318
+ | Codex | `/key codex` | `CODEX_API_KEY` | platform.openai.com/api-keys |
319
+ | Antigravity | `/key agy` | `GEMINI_API_KEY` | aistudio.google.com/apikey |
320
+ | OpenRouter | `/key openrouter` | `OPENROUTER_API_KEY` | openrouter.ai/keys |
321
+ | Cursor | `/key cursor` | `CURSOR_API_KEY` | cursor.com/dashboard → Integrations |
322
+ | Grok | `/key grok` | `XAI_API_KEY` | console.x.ai |
323
+ | DeepSeek | `/key deepseek` | `DEEPSEEK_API_KEY` | platform.deepseek.com/api_keys |
324
+ | Groq (clasificador) | `/key groq` | `GROQ_API_KEY` | console.groq.com/keys |
325
+ | Cerebras (clasificador) | `/key cerebras` | `CEREBRAS_API_KEY` | cloud.cerebras.ai |
326
+
327
+ Cursor usa primero el login de la cuenta (`cursor-agent login`) y solo después las claves.
328
+ DeepSeek, como OpenRouter, funciona solo con clave y enmascara los datos personales antes
329
+ del envío. Groq y Cerebras no responden preguntas: solo clasifican cada pedido (gratis) y
330
+ verifican si un pedido de la cola ya fue resuelto.
331
+
332
+ ```text
333
+ ai [auto] › /key claude
334
+ Chave de claude (console.anthropic.com/settings/keys). Cole e tecle Enter; ela não aparece na tela.
335
+ >
336
+ ✓ Chave de claude salva em ~/.config/smart-ai/keys/claude (permissão 600).
337
+ ```
338
+
339
+ Las claves quedan en `~/.config/smart-ai/keys/`, una por archivo, con permiso 600, y
340
+ se pasan solo al proceso de la herramienta, nunca al historial ni al log. Si la variable
341
+ ya está definida en el entorno, tiene precedencia. `/key` lista lo que está configurado,
342
+ mostrando solo el inicio y el final de cada clave.
343
+
344
+ En Claude, la clave funciona como una cuenta adicional después de todas las
345
+ suscripciones: si también llega al límite, entra en cooldown como las demás.
346
+
347
+ > **Nunca pegues una clave como comando en el shell.** Queda grabada en el historial de
348
+ > zsh. Si eso pasa, revoca la clave en el sitio de la herramienta y borra la línea de
349
+ > `~/.zsh_history`.
350
+
351
+ En OpenRouter, por defecto solo se usan modelos gratuitos: el cliente elige hasta tres
352
+ variantes `:free` del catálogo y usa `openrouter/free` como última alternativa. Los
353
+ modelos de pago quedan bloqueados hasta que los autorices:
354
+
355
+ ```text
356
+ /model openrouter_paid on # autoriza; avisa que se cobrará en tu cuenta
357
+ /model openrouter anthropic/claude-opus-5.5
358
+ /model openrouter_paid off # bloquea de nuevo y vuelve a lo gratuito
359
+ ```
360
+
361
+ Con la autorización activa, el modelo elegido va primero y los gratuitos quedan de
362
+ respaldo. Desactivada, se envía un límite de precio cero en cada llamada, así que ningún
363
+ modelo de pago responde.
364
+
365
+ ---
366
+
367
+ ## Modos
368
+
369
+ El modo vale para Claude, Codex y Antigravity a la vez y aparece en el prompt
370
+ (`ai [auto · plan] ›`). Cada sesión guarda el suyo.
371
+
372
+ | Modo | Qué hace | Claude | Codex | Antigravity |
373
+ | --- | --- | --- | --- | --- |
374
+ | `default` | Predeterminado de cada herramienta | — | — | — |
375
+ | `plan` | Solo lee y planifica, no cambia nada | `plan` | `--sandbox read-only` | `--mode plan` |
376
+ | `edits` | Acepta ediciones de archivos | `acceptEdits` | `--sandbox workspace-write` | `--mode accept-edits` |
377
+ | `auto` | Actúa solo, con las protecciones de la herramienta | `auto` | `workspace-write`, sin aprobación | `--mode auto` |
378
+ | `yolo` | Sin permisos ni sandbox | `bypassPermissions` | `--dangerously-bypass-approvals-and-sandbox` | `--dangerously-skip-permissions` |
379
+
380
+ `/mode yolo` pide confirmación, porque la IA puede borrar archivos y ejecutar cualquier
381
+ comando. Fuera del chat: `ai --mode plan "pregunta"`. `/parallel` siempre corre en `plan`.
382
+
383
+ ---
384
+
385
+ ## Skills y MCP
386
+
387
+ `ai` llama a los propios CLIs, así que cada uno usa las skills y MCPs que ya tiene.
388
+ `/sync` reúne todo e instala en cada herramienta lo que solo existe en las otras:
389
+
390
+ ```text
391
+ ai [auto] › /sync
392
+ Ferramentas encontradas: claude, codex, agy
393
+ MCP github codex → claude
394
+ MCP obsidian claude → codex
395
+ skill humanizer claude → codex (~/.agents/skills/humanizer)
396
+ Aplicar? [s/N]
397
+ ```
398
+
399
+ - Los MCPs se agregan con el comando `mcp add` de cada CLI, sin editar archivos a mano.
400
+ - El mismo servidor con nombres distintos se reconoce por paquete o URL y no se duplica.
401
+ - Los MCPs que vienen dentro de una app (como los de Codex.app) se quedan ahí.
402
+ - Las skills se comparten por enlace: `~/.claude/skills`, `~/.agents/skills` (Codex) y
403
+ `~/.gemini/antigravity/skills`. Editar una vale para las tres.
404
+ - Las cuentas extra de Claude también se actualizan.
405
+ - Las variables de entorno de los MCPs, que pueden tener tokens, se copian a la config de
406
+ la otra herramienta. `/sync` avisa antes.
407
+ - `/sync --dry-run` solo muestra lo que haría.
408
+
409
+ **Skills y comandos del proyecto:** el chat lee `.claude/commands`, `.claude/skills`, `.agents/skills` y
410
+ `.agent/workflows` del proyecto abierto, además de las carpetas del usuario. `/pr-review 237` va a
411
+ Claude tal como se escribió, y Claude ejecuta el comando de forma nativa. Una skill que solo existe
412
+ en Codex o Antigravity va a esa herramienta, con las instrucciones del archivo en el pedido.
413
+
414
+ Como el chat no reenvía las solicitudes de aprobación, una herramienta MCP solo corre si ya
415
+ está permitida en el CLI o si el modo es `auto` o `yolo`. OpenRouter no tiene skills ni MCP.
416
+
417
+ ---
418
+
419
+ ## Uso directo, sin chat
420
+
421
+ ```bash
422
+ ai "o que é um design pattern?" # enrutamiento automático
423
+ ai --claude "refatorar o módulo X" # fuerza Claude
424
+ ai --codex "explicar REST" # fuerza Codex
425
+ ai --agy "pesquisar React hooks" # fuerza Antigravity
426
+ ai --openrouter "explicar Docker" # fuerza OpenRouter
427
+ ai --cursor "corrigir o teste X" # fuerza Cursor
428
+ ai --deepseek "explicar CAP theorem" # fuerza DeepSeek
429
+ ai --install # instala las herramientas que faltan (pregunta antes)
430
+ ai --classify "prompt" # muestra cómo se clasificaría
431
+ ai --log # últimas llamadas
432
+ ```
433
+
434
+ ---
435
+
436
+ ## Dónde están los archivos
437
+
438
+ | Ruta | Contenido |
439
+ | --- | --- |
440
+ | `~/.config/smart-ai/profiles.json` | Cuentas de Claude y reglas de enrutamiento |
441
+ | `~/.config/smart-ai/models.json` | Modelos elegidos con `/model` |
442
+ | `~/.config/smart-ai/lang` | Idioma del chat |
443
+ | `~/.config/smart-ai/keys/<ferramenta>` | Claves de API, una por archivo (permiso 600) |
444
+ | `~/.claude-accounts/<nome>/` | Login aislado de cada cuenta extra de Claude |
445
+ | `~/.local/share/smart-ai/sessions/` | Sesiones del chat |
446
+ | `~/.cache/smart-ai/state.json` | Cooldowns activos |
447
+ | `~/.cache/smart-ai/usage.log` | Log de uso, solo metadatos |
448
+ | `~/.cache/smart-ai/costs.jsonl` | Costo y tokens de cada pedido del chat, sin pregunta ni respuesta (total del día en `/usage`) |
449
+
450
+ ---
451
+
452
+ ## Estructura del proyecto
453
+
454
+ ```text
455
+ omni-ai-cli/
456
+ ├── omni_ai/ # el programa (paquete Python)
457
+ │ ├── tools.py # registro único de herramientas: nombre, color, CLI, modelo, clave
458
+ │ ├── cli.py # comando ai: clasifica, enruta y ejecuta cada herramienta
459
+ │ ├── chat.py # chat: sesiones, eventos, Ctrl-C, idiomas
460
+ │ ├── ui.py # aspecto: caja de entrada, barra de estado, acciones y respuestas
461
+ │ ├── skills.py # skills y comandos del proyecto, del usuario y nativos
462
+ │ ├── config.py # modelos, claves y cuentas Claude (/model, /key, /account)
463
+ │ ├── sync.py # /sync: MCPs y skills entre las tres herramientas
464
+ │ ├── openrouter.py # cliente OpenRouter: gratuitos, de pago solo si se autorizan
465
+ │ ├── grok.py # cliente xAI, reutilizado por DeepSeek
466
+ │ ├── deepseek.py # cliente DeepSeek con datos personales enmascarados
467
+ │ ├── pii.py # enmascara y restaura datos personales
468
+ │ ├── osutils.py # diferencias entre macOS, Linux y Windows
469
+ │ ├── profiles.json # plantilla inicial; la tuya queda en ~/.config/smart-ai
470
+ │ └── vendor/ # prompt_toolkit y wcwidth incluidos (sin pip)
471
+ ├── bin/ai.js # lanzador npm: encuentra o instala Python y ejecuta el paquete
472
+ ├── scripts/ # install.sh, install.ps1 y ai.cmd
473
+ ├── docs/ # README en inglés, español y francés
474
+ ├── tests/ # ejecutables ficticios, sin consumir cuota
475
+ ├── postman/ # simulación HTTP de OpenRouter
476
+ ├── get.sh / get.ps1 # instalación con un comando
477
+ └── package.json · LICENSE
478
+ ```
479
+
480
+ El enrutador no sabe nada del chat: solo ejecuta una pregunta y, con
481
+ `SMART_AI_EVENTS=1`, emite eventos JSON. El chat no sabe nada de credenciales: las
482
+ cuentas y los modelos pasan por `config.py`.
483
+
484
+ ---
485
+
486
+ ## Pruebas
487
+
488
+ ```bash
489
+ python3 -m unittest discover -s tests -v
490
+ bash -n scripts/install.sh
491
+ ```
492
+
493
+ **38 pruebas**: persistencia y reanudación de sesión, límite de contexto, permisos de
494
+ los archivos, sesión abierta en dos terminales, lectura de eventos, cancelación del árbol
495
+ de procesos, paralelismo real, sandbox de solo lectura, enmascaramiento de datos
496
+ personales, fallback OpenRouter → Codex, validación de modelos, almacenamiento de las
497
+ claves y el ciclo de vida de las cuentas. Todos los ejecutables son ficticios: **ninguna
498
+ prueba autentica ni consume suscripción.**
499
+
500
+ Para probar el HTTP de OpenRouter contra la simulación de Postman:
501
+
502
+ ```bash
503
+ postman simulation run postman/simulations/openrouter.sim.yaml --port 4901 --no-history --output ndjson
504
+ SMART_AI_SIM_URL=http://127.0.0.1:4901/openrouter python3 -m unittest discover -s tests -v
505
+ ```
506
+
507
+ ---
508
+
509
+ ## Releases y ramas
510
+
511
+ La publicación en npm es automática, hecha por GitHub Actions con semantic-release. La
512
+ versión sale de los mensajes de commit (Conventional Commits) — nadie edita `version` en
513
+ `package.json` a mano.
514
+
515
+ | Rama | Publica como | Ejemplo |
516
+ |---|---|---|
517
+ | `main` | `latest` | `1.4.0` |
518
+ | `next` | `next` (release candidate) | `1.5.0-rc.1` |
519
+ | `beta` | `beta` | `2.0.0-beta.1` |
520
+ | otras / PR | nada, solo CI | — |
521
+
522
+ | Commit | Efecto en la versión |
523
+ |---|---|
524
+ | `fix: ...` | patch (`1.4.0` → `1.4.1`) |
525
+ | `feat: ...` | minor (`1.4.0` → `1.5.0`) |
526
+ | `feat!: ...` o `BREAKING CHANGE:` en el cuerpo | major (`1.4.0` → `2.0.0`) |
527
+ | `docs:`, `ci:`, `chore:`, `test:`, `refactor:` | sin release |
528
+
529
+ Usa squash merge: el título del PR se vuelve el commit, y el workflow `PR title` bloquea
530
+ títulos fuera del estándar.
531
+
532
+ ### Mensajes de commit
533
+
534
+ `/versions` muestra el título de cada `feat`/`fix` como la "vista simple" y el cuerpo como
535
+ "nota técnica". Por eso:
536
+
537
+ - **Título:** qué cambia para quien lo usa, en inglés, en presente, sin nombres de archivo
538
+ ni de función. `feat: keep the input free and queue new requests while one runs`, no
539
+ `feat: add Queue class to chat.py`.
540
+ - **Cuerpo:** el porqué y el comportamiento nuevo en frases cortas; detalles técnicos solo
541
+ al final, si ayudan.
542
+ - Un commit por cambio perceptible. Refactorizaciones y tests van en `refactor:`/`test:`,
543
+ que no aparecen en `/versions`.
544
+
545
+ ```mermaid
546
+ flowchart TD
547
+ A[PR abierto] --> B[CI: tests Python 3.11-3.13 en Linux y macOS<br/>+ npm pack + launcher]
548
+ A --> C[PR title: ¿Conventional Commits?]
549
+ B -->|falló| X[Merge bloqueado]
550
+ C -->|inválido| X
551
+ B -->|ok| D[Squash merge en main / next / beta]
552
+ C -->|ok| D
553
+ D --> E[Release: CI corre de nuevo]
554
+ E -->|falló| Y[No se publica nada]
555
+ E -->|ok| F{semantic-release:<br/>¿hay feat/fix/breaking<br/>desde la última tag?}
556
+ F -->|no| Z[Sin release]
557
+ F -->|sí| G[Calcula versión y crea tag vX.Y.Z]
558
+ G --> H[npm publish con provenance<br/>en el dist-tag de la rama]
559
+ G --> I[GitHub Release con notas]
560
+ ```
561
+
562
+ Configuración única en GitHub:
563
+
564
+ 1. **Settings → Secrets and variables → Actions**: crear `NPM_TOKEN` (token *Automation*
565
+ o *Granular* de npmjs.com con permiso de publish).
566
+ 2. **Settings → Branches**: proteger `main` (y `next`/`beta` si se usan) exigiendo PR y
567
+ los checks `Tests (...)`, `npm package` y `conventional`.
568
+ 3. **Settings → General → Pull Requests**: permitir solo *squash merging* y marcar
569
+ *Default to pull request title*.
570
+
571
+ ---
572
+
573
+ ## Troubleshooting
574
+
575
+ | Problema | Solución |
576
+ | --- | --- |
577
+ | `OPENROUTER_API_KEY não configurada` | `/key openrouter` en el chat o `ai --key openrouter`. |
578
+ | `Arquivo de credenciais não encontrado` o `Conta 'X' sem login` | `/account login X`. |
579
+ | `You've hit your session limit` | Cuota de la cuenta. `ai` pasa a la siguiente; agrega otra con `/account add` o una clave con `/key claude`. |
580
+ | `Individual quota reached` (Antigravity) | Cuota de Antigravity; se omite hasta la renovación. |
581
+ | `Not inside a trusted directory` (Codex) | Instalación antigua. Ejecuta el instalador de nuevo. |
582
+ | `Claude Code não instalado` | `./scripts/install.sh` (o `scripts\install.ps1` en Windows) lo instala con el instalador oficial. |
583
+ | Windows: fallan los enlaces de skills | Activa el Modo de desarrollador o ejecuta como administrador; si no, `ai` usa uniones de carpeta. |
584
+ | `/model` no cambia nada | Hay una variable `SMART_AI_*_MODEL` definida y tiene precedencia. |
585
+ | `/key` no cambia nada | La variable de la herramienta (`ANTHROPIC_API_KEY`, etc.) está definida y tiene precedencia. |
586
+ | `Sessão já aberta em outro terminal` | Cierra la otra terminal o usa `/new`. |
587
+ | `ai: command not found` | Agrega `~/.local/bin` al `PATH`. |
588
+
589
+ ---
590
+
591
+ ## Limitaciones conocidas
592
+
593
+ - El chat usa los modos no interactivos de los CLI. Las solicitudes de aprobación
594
+ nativas (por ejemplo, "¿puedo editar este archivo?") no aparecen; en esos casos, usa
595
+ el CLI nativo.
596
+ - `/parallel` solo analiza: Codex con `--sandbox read-only` u OpenRouter, que no accede
597
+ a los archivos. Los agentes no editan el proyecto al mismo tiempo.
598
+ - La clasificación simple/compleja se hace por palabras clave y tamaño, no con un modelo.
599
+ - Cambiar de modelo no renueva la cuota de la cuenta.
600
+ - OpenRouter no tiene streaming en esta versión: la respuesta aparece completa al final.
601
+ - En Windows el código usa los equivalentes nativos (grupos de procesos y `taskkill`, `msvcrt`, uniones de carpeta), pero solo se probó de verdad en macOS.
602
+
603
+ ---
604
+
605
+ ## Privacidad
606
+
607
+ - Las sesiones, las claves de API y los logs quedan solo en tu máquina, con permiso restringido a tu usuario.
608
+ - El log de uso registra herramienta, cuenta y estado, **nunca el texto de la pregunta**.
609
+ - Antes de ir a OpenRouter, los correos, teléfonos, documentos y otros datos personales
610
+ se cambian por marcadores y se restauran en la respuesta. El enmascaramiento es por
611
+ patrones y no garantiza un anonimato total.
612
+ - Claude, Codex y Antigravity reciben el texto original, bajo los términos de cada servicio.
613
+
614
+ ---
615
+
616
+ ## Licencia
617
+
618
+ [MIT](../LICENSE). Incluidas en `vendor/`: prompt_toolkit (BSD-3-Clause) y wcwidth (MIT), cada una con su licencia.