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.
- package/LICENSE +21 -0
- package/README.md +615 -2
- package/bin/ai.js +84 -0
- package/docs/README.en.md +615 -0
- package/docs/README.es.md +618 -0
- package/docs/README.fr.md +630 -0
- package/omni_ai/__init__.py +1 -0
- package/omni_ai/__main__.py +6 -0
- package/omni_ai/chat.py +1458 -0
- package/omni_ai/cli.py +991 -0
- package/omni_ai/config.py +531 -0
- package/omni_ai/deepseek.py +57 -0
- package/omni_ai/grok.py +111 -0
- package/omni_ai/onboarding.py +196 -0
- package/omni_ai/openrouter.py +335 -0
- package/omni_ai/osutils.py +86 -0
- package/omni_ai/pii.py +281 -0
- package/omni_ai/profiles.json +69 -0
- package/omni_ai/skills.py +124 -0
- package/omni_ai/sync.py +199 -0
- package/omni_ai/tools.py +75 -0
- package/omni_ai/ui.py +595 -0
- package/omni_ai/usage.py +305 -0
- package/omni_ai/vendor/prompt_toolkit/LICENSE +27 -0
- package/omni_ai/vendor/prompt_toolkit/__init__.py +52 -0
- package/omni_ai/vendor/prompt_toolkit/application/__init__.py +32 -0
- package/omni_ai/vendor/prompt_toolkit/application/application.py +1626 -0
- package/omni_ai/vendor/prompt_toolkit/application/current.py +195 -0
- package/omni_ai/vendor/prompt_toolkit/application/dummy.py +55 -0
- package/omni_ai/vendor/prompt_toolkit/application/run_in_terminal.py +114 -0
- package/omni_ai/vendor/prompt_toolkit/auto_suggest.py +177 -0
- package/omni_ai/vendor/prompt_toolkit/buffer.py +2029 -0
- package/omni_ai/vendor/prompt_toolkit/cache.py +127 -0
- package/omni_ai/vendor/prompt_toolkit/clipboard/__init__.py +17 -0
- package/omni_ai/vendor/prompt_toolkit/clipboard/base.py +109 -0
- package/omni_ai/vendor/prompt_toolkit/clipboard/in_memory.py +44 -0
- package/omni_ai/vendor/prompt_toolkit/clipboard/pyperclip.py +42 -0
- package/omni_ai/vendor/prompt_toolkit/completion/__init__.py +43 -0
- package/omni_ai/vendor/prompt_toolkit/completion/base.py +438 -0
- package/omni_ai/vendor/prompt_toolkit/completion/deduplicate.py +45 -0
- package/omni_ai/vendor/prompt_toolkit/completion/filesystem.py +118 -0
- package/omni_ai/vendor/prompt_toolkit/completion/fuzzy_completer.py +213 -0
- package/omni_ai/vendor/prompt_toolkit/completion/nested.py +109 -0
- package/omni_ai/vendor/prompt_toolkit/completion/word_completer.py +94 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/__init__.py +0 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/completers/__init__.py +5 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/completers/system.py +64 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/regular_languages/__init__.py +80 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/regular_languages/compiler.py +579 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/regular_languages/completion.py +100 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/regular_languages/lexer.py +94 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/regular_languages/regex_parser.py +279 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/regular_languages/validation.py +60 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/ssh/__init__.py +8 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/ssh/server.py +178 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/telnet/__init__.py +7 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/telnet/log.py +13 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/telnet/protocol.py +209 -0
- package/omni_ai/vendor/prompt_toolkit/contrib/telnet/server.py +428 -0
- package/omni_ai/vendor/prompt_toolkit/cursor_shapes.py +117 -0
- package/omni_ai/vendor/prompt_toolkit/data_structures.py +18 -0
- package/omni_ai/vendor/prompt_toolkit/document.py +1182 -0
- package/omni_ai/vendor/prompt_toolkit/enums.py +19 -0
- package/omni_ai/vendor/prompt_toolkit/eventloop/__init__.py +31 -0
- package/omni_ai/vendor/prompt_toolkit/eventloop/async_generator.py +125 -0
- package/omni_ai/vendor/prompt_toolkit/eventloop/inputhook.py +191 -0
- package/omni_ai/vendor/prompt_toolkit/eventloop/utils.py +101 -0
- package/omni_ai/vendor/prompt_toolkit/eventloop/win32.py +72 -0
- package/omni_ai/vendor/prompt_toolkit/filters/__init__.py +71 -0
- package/omni_ai/vendor/prompt_toolkit/filters/app.py +419 -0
- package/omni_ai/vendor/prompt_toolkit/filters/base.py +261 -0
- package/omni_ai/vendor/prompt_toolkit/filters/cli.py +65 -0
- package/omni_ai/vendor/prompt_toolkit/filters/utils.py +41 -0
- package/omni_ai/vendor/prompt_toolkit/formatted_text/__init__.py +59 -0
- package/omni_ai/vendor/prompt_toolkit/formatted_text/ansi.py +297 -0
- package/omni_ai/vendor/prompt_toolkit/formatted_text/base.py +179 -0
- package/omni_ai/vendor/prompt_toolkit/formatted_text/html.py +145 -0
- package/omni_ai/vendor/prompt_toolkit/formatted_text/pygments.py +32 -0
- package/omni_ai/vendor/prompt_toolkit/formatted_text/utils.py +103 -0
- package/omni_ai/vendor/prompt_toolkit/history.py +306 -0
- package/omni_ai/vendor/prompt_toolkit/input/__init__.py +14 -0
- package/omni_ai/vendor/prompt_toolkit/input/ansi_escape_sequences.py +344 -0
- package/omni_ai/vendor/prompt_toolkit/input/base.py +153 -0
- package/omni_ai/vendor/prompt_toolkit/input/defaults.py +79 -0
- package/omni_ai/vendor/prompt_toolkit/input/posix_pipe.py +118 -0
- package/omni_ai/vendor/prompt_toolkit/input/posix_utils.py +97 -0
- package/omni_ai/vendor/prompt_toolkit/input/typeahead.py +78 -0
- package/omni_ai/vendor/prompt_toolkit/input/vt100.py +309 -0
- package/omni_ai/vendor/prompt_toolkit/input/vt100_parser.py +250 -0
- package/omni_ai/vendor/prompt_toolkit/input/win32.py +749 -0
- package/omni_ai/vendor/prompt_toolkit/input/win32_pipe.py +156 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/__init__.py +22 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/__init__.py +0 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/auto_suggest.py +66 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/basic.py +257 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/completion.py +206 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/cpr.py +30 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/emacs.py +563 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/focus.py +26 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/mouse.py +348 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/named_commands.py +691 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/open_in_editor.py +52 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/page_navigation.py +85 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/scroll.py +190 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/search.py +96 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/bindings/vi.py +2233 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/defaults.py +63 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/digraphs.py +1378 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/emacs_state.py +36 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/key_bindings.py +670 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/key_processor.py +526 -0
- package/omni_ai/vendor/prompt_toolkit/key_binding/vi_state.py +107 -0
- package/omni_ai/vendor/prompt_toolkit/keys.py +222 -0
- package/omni_ai/vendor/prompt_toolkit/layout/__init__.py +147 -0
- package/omni_ai/vendor/prompt_toolkit/layout/containers.py +2738 -0
- package/omni_ai/vendor/prompt_toolkit/layout/controls.py +945 -0
- package/omni_ai/vendor/prompt_toolkit/layout/dimension.py +220 -0
- package/omni_ai/vendor/prompt_toolkit/layout/dummy.py +40 -0
- package/omni_ai/vendor/prompt_toolkit/layout/layout.py +412 -0
- package/omni_ai/vendor/prompt_toolkit/layout/margins.py +304 -0
- package/omni_ai/vendor/prompt_toolkit/layout/menus.py +748 -0
- package/omni_ai/vendor/prompt_toolkit/layout/mouse_handlers.py +56 -0
- package/omni_ai/vendor/prompt_toolkit/layout/processors.py +1010 -0
- package/omni_ai/vendor/prompt_toolkit/layout/screen.py +323 -0
- package/omni_ai/vendor/prompt_toolkit/layout/scrollable_pane.py +494 -0
- package/omni_ai/vendor/prompt_toolkit/layout/utils.py +80 -0
- package/omni_ai/vendor/prompt_toolkit/lexers/__init__.py +21 -0
- package/omni_ai/vendor/prompt_toolkit/lexers/base.py +85 -0
- package/omni_ai/vendor/prompt_toolkit/lexers/pygments.py +328 -0
- package/omni_ai/vendor/prompt_toolkit/log.py +13 -0
- package/omni_ai/vendor/prompt_toolkit/mouse_events.py +85 -0
- package/omni_ai/vendor/prompt_toolkit/output/__init__.py +15 -0
- package/omni_ai/vendor/prompt_toolkit/output/base.py +332 -0
- package/omni_ai/vendor/prompt_toolkit/output/color_depth.py +64 -0
- package/omni_ai/vendor/prompt_toolkit/output/conemu.py +65 -0
- package/omni_ai/vendor/prompt_toolkit/output/defaults.py +106 -0
- package/omni_ai/vendor/prompt_toolkit/output/flush_stdout.py +87 -0
- package/omni_ai/vendor/prompt_toolkit/output/plain_text.py +143 -0
- package/omni_ai/vendor/prompt_toolkit/output/vt100.py +748 -0
- package/omni_ai/vendor/prompt_toolkit/output/win32.py +683 -0
- package/omni_ai/vendor/prompt_toolkit/output/windows10.py +128 -0
- package/omni_ai/vendor/prompt_toolkit/patch_stdout.py +297 -0
- package/omni_ai/vendor/prompt_toolkit/py.typed +0 -0
- package/omni_ai/vendor/prompt_toolkit/renderer.py +814 -0
- package/omni_ai/vendor/prompt_toolkit/search.py +226 -0
- package/omni_ai/vendor/prompt_toolkit/selection.py +58 -0
- package/omni_ai/vendor/prompt_toolkit/shortcuts/__init__.py +46 -0
- package/omni_ai/vendor/prompt_toolkit/shortcuts/dialogs.py +330 -0
- package/omni_ai/vendor/prompt_toolkit/shortcuts/progress_bar/__init__.py +33 -0
- package/omni_ai/vendor/prompt_toolkit/shortcuts/progress_bar/base.py +449 -0
- package/omni_ai/vendor/prompt_toolkit/shortcuts/progress_bar/formatters.py +431 -0
- package/omni_ai/vendor/prompt_toolkit/shortcuts/prompt.py +1513 -0
- package/omni_ai/vendor/prompt_toolkit/shortcuts/utils.py +239 -0
- package/omni_ai/vendor/prompt_toolkit/styles/__init__.py +67 -0
- package/omni_ai/vendor/prompt_toolkit/styles/base.py +184 -0
- package/omni_ai/vendor/prompt_toolkit/styles/defaults.py +236 -0
- package/omni_ai/vendor/prompt_toolkit/styles/named_colors.py +162 -0
- package/omni_ai/vendor/prompt_toolkit/styles/pygments.py +70 -0
- package/omni_ai/vendor/prompt_toolkit/styles/style.py +401 -0
- package/omni_ai/vendor/prompt_toolkit/styles/style_transformation.py +374 -0
- package/omni_ai/vendor/prompt_toolkit/token.py +9 -0
- package/omni_ai/vendor/prompt_toolkit/utils.py +327 -0
- package/omni_ai/vendor/prompt_toolkit/validation.py +192 -0
- package/omni_ai/vendor/prompt_toolkit/widgets/__init__.py +63 -0
- package/omni_ai/vendor/prompt_toolkit/widgets/base.py +995 -0
- package/omni_ai/vendor/prompt_toolkit/widgets/dialogs.py +108 -0
- package/omni_ai/vendor/prompt_toolkit/widgets/menus.py +374 -0
- package/omni_ai/vendor/prompt_toolkit/widgets/toolbars.py +370 -0
- package/omni_ai/vendor/prompt_toolkit/win32_types.py +229 -0
- package/omni_ai/vendor/wcwidth/LICENSE +27 -0
- package/omni_ai/vendor/wcwidth/__init__.py +29 -0
- package/omni_ai/vendor/wcwidth/table_vs16.py +125 -0
- package/omni_ai/vendor/wcwidth/table_wide.py +1493 -0
- package/omni_ai/vendor/wcwidth/table_zero.py +4843 -0
- package/omni_ai/vendor/wcwidth/unicode_versions.py +38 -0
- package/omni_ai/vendor/wcwidth/wcwidth.py +345 -0
- package/package.json +40 -4
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
# Omni AI CLI
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](../LICENSE)
|
|
5
|
+

|
|
6
|
+

|
|
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.
|