omni-ai-cli 0.0.0-stage → 1.1.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 +563 -2
- package/bin/ai.js +84 -0
- package/docs/README.en.md +563 -0
- package/docs/README.es.md +566 -0
- package/docs/README.fr.md +578 -0
- package/docs/diagrams/flow1.en.mmd +47 -0
- package/docs/diagrams/flow1.es.mmd +47 -0
- package/docs/diagrams/flow1.fr.mmd +47 -0
- package/docs/diagrams/flow1.pt.mmd +47 -0
- package/docs/diagrams/flow2.en.mmd +14 -0
- package/docs/diagrams/flow2.es.mmd +14 -0
- package/docs/diagrams/flow2.fr.mmd +14 -0
- package/docs/diagrams/flow2.pt.mmd +14 -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 +1083 -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 +44 -4
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/samuelrms/omni-ai-cli/main/docs/assets/omni-ai-cli-logo.png" alt="Omni AI CLI" width="440">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Omni AI CLI
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/omni-ai-cli)
|
|
8
|
+
[](https://www.npmjs.com/package/omni-ai-cli)
|
|
9
|
+
[](https://docs.npmjs.com/trusted-publishers)
|
|
10
|
+
[](../LICENSE)
|
|
11
|
+

|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
> [Português](../README.md) · [Español](README.es.md) · [Français](README.fr.md)
|
|
15
|
+
|
|
16
|
+
A chat terminal that brings **Claude Code, Codex, Cursor, Antigravity, Grok, DeepSeek and
|
|
17
|
+
OpenRouter** together in one place. You type your question, `ai` decides who answers, and
|
|
18
|
+
if a tool fails or runs out of quota, it moves on to the next one without you doing anything.
|
|
19
|
+
|
|
20
|
+
While an answer is being generated, the input box stays free: you keep sending requests,
|
|
21
|
+
they go into a queue shown above the box and run in order.
|
|
22
|
+
|
|
23
|
+
Simple questions go to the cheaper tools. Heavy tasks go to Claude, with automatic
|
|
24
|
+
switching between several accounts when one hits its limit. History is saved, the
|
|
25
|
+
interface speaks Portuguese, English, Spanish and French, and models and accounts are
|
|
26
|
+
configured from inside the chat itself.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Contents
|
|
31
|
+
|
|
32
|
+
- [How it works](#how-it-works)
|
|
33
|
+
- [Installation](#installation)
|
|
34
|
+
- [How to use](#how-to-use)
|
|
35
|
+
- [Chat commands](#chat-commands)
|
|
36
|
+
- [Models](#models)
|
|
37
|
+
- [Claude accounts](#claude-accounts)
|
|
38
|
+
- [API keys](#api-keys)
|
|
39
|
+
- [Modes](#modes)
|
|
40
|
+
- [Skills and MCP](#skills-and-mcp)
|
|
41
|
+
- [Direct use, no chat](#direct-use-no-chat)
|
|
42
|
+
- [Where files live](#where-files-live)
|
|
43
|
+
- [Project structure](#project-structure)
|
|
44
|
+
- [Tests](#tests)
|
|
45
|
+
- [Troubleshooting](#troubleshooting)
|
|
46
|
+
- [Known limitations](#known-limitations)
|
|
47
|
+
- [Privacy](#privacy)
|
|
48
|
+
- [License](#license)
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## How it works
|
|
53
|
+
|
|
54
|
+
From the typed line to the saved answer. The chat (`chat.py`) does not call any AI
|
|
55
|
+
directly: it launches the router (`cli.py`) as a subprocess and reads the events it
|
|
56
|
+
emits, line by line, to show who is answering and what they are doing.
|
|
57
|
+
|
|
58
|
+

|
|
59
|
+
|
|
60
|
+
Three details the diagram makes explicit:
|
|
61
|
+
|
|
62
|
+
- **Each Claude account has its own login folder.** Extra accounts run with
|
|
63
|
+
`CLAUDE_CONFIG_DIR` pointing to `~/.claude-accounts/<nome>`. The main account is
|
|
64
|
+
never logged out, and no credential is copied from one place to another. Copying
|
|
65
|
+
`.credentials.json` does not work reliably on macOS, where the login lives in the
|
|
66
|
+
Keychain.
|
|
67
|
+
- **Ctrl-C kills the whole tree.** The router runs in its own process group, so
|
|
68
|
+
canceling also ends the `claude`, `codex` or `agy` running underneath, instead of
|
|
69
|
+
leaving orphan processes burning quota.
|
|
70
|
+
- **The queue blocks nothing.** Above the box you see the running request, the elapsed
|
|
71
|
+
time and the next ones in line. A request that waited goes through a free classifier
|
|
72
|
+
before running: if the previous answer already covers it, it is skipped. Commands and
|
|
73
|
+
skills always run. Ctrl-C with the queue active cancels everything without leaving the chat. If you
|
|
74
|
+
close the chat with requests in line, they stay saved in the session and `ai --resume ID` offers to run them.
|
|
75
|
+
- **Each answer shows what it cost.** At the end of each request you see the tokens and,
|
|
76
|
+
when the tool reports it (OpenRouter, Grok, Claude on an API key), the cost in dollars.
|
|
77
|
+
`/usage` adds up the day's spend per tool.
|
|
78
|
+
- **You see why a tool was picked.** In `auto` mode, one short line says whether the request
|
|
79
|
+
was treated as a coding task or a simple question and who labelled it (Groq, Cerebras,
|
|
80
|
+
OpenRouter, Grok or the keywords).
|
|
81
|
+
- **Only the answer goes into the history.** Status and diagnostic lines appear on
|
|
82
|
+
screen, but are not sent as context with the next question. The models' internal
|
|
83
|
+
reasoning is also discarded.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Installation
|
|
88
|
+
|
|
89
|
+
One command installs everything and, run again, updates it. Your accounts, keys and models live in `~/.config/smart-ai` and are left untouched.
|
|
90
|
+
|
|
91
|
+
**macOS and Linux**:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
curl -fsSL https://raw.githubusercontent.com/samuelrms/omni-ai-cli/main/get.sh | bash
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Windows** (PowerShell):
|
|
98
|
+
|
|
99
|
+
```powershell
|
|
100
|
+
irm https://raw.githubusercontent.com/samuelrms/omni-ai-cli/main/get.ps1 | iex
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**On npm, yarn, pnpm or bun:**
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npm install -g omni-ai-cli
|
|
107
|
+
yarn global add omni-ai-cli
|
|
108
|
+
pnpm add -g omni-ai-cli
|
|
109
|
+
bun add -g omni-ai-cli
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Any of the commands above (script or package manager) installs the same `ai`.
|
|
113
|
+
|
|
114
|
+
To update later: `ai --update` (or `/update` in the chat).
|
|
115
|
+
|
|
116
|
+
From source, for development:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
git clone https://github.com/samuelrms/omni-ai-cli ~/dev/omni-ai-cli
|
|
120
|
+
cd ~/dev/omni-ai-cli && ./scripts/install.sh # Windows: powershell -File scripts\install.ps1
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The installer:
|
|
124
|
+
|
|
125
|
+
1. installs **Claude Code** through the official installer if it is not on the machine yet;
|
|
126
|
+
2. opens the main account login if there isn't one yet;
|
|
127
|
+
3. creates the `ai` command in `~/.local/bin`;
|
|
128
|
+
4. shows the configured Claude accounts.
|
|
129
|
+
|
|
130
|
+
Requirements: nothing beyond `curl` (macOS/Linux) or PowerShell (Windows). If Python 3.11+ is missing, the installer downloads a Python 3.12 just for Omni AI, without sudo and without touching the system Python.
|
|
131
|
+
Codex (`codex`) and Antigravity (`agy`) are optional and join the fallback queue when they are installed.
|
|
132
|
+
|
|
133
|
+
If `~/.local/bin` is not in your `PATH`, add this to `~/.zshrc`:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
On Windows, the installer creates `ai.cmd` in `%USERPROFILE%\.local\bin` and adds that folder to `PATH`; open a new terminal afterwards.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## How to use
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
ai
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The first time, it asks for the language and offers to install the missing tools
|
|
150
|
+
(Claude Code, Codex, Cursor, Grok Build) with the official installers. Antigravity is
|
|
151
|
+
installed from its own page. After that, just type and press Enter.
|
|
152
|
+
|
|
153
|
+
| Key | Action |
|
|
154
|
+
| --- | --- |
|
|
155
|
+
| Enter | Sends |
|
|
156
|
+
| ↑ / ↓ | Previous lines |
|
|
157
|
+
| Ctrl-C | During an answer: cancels. At the prompt: saves and exits |
|
|
158
|
+
| Ctrl-D | Saves and exits |
|
|
159
|
+
| `\` + Enter · Shift+Enter · Option+Enter | New line without sending (Shift+Enter in iTerm2, Ghostty, Kitty, WezTerm and VS Code; in macOS Terminal use `\` + Enter) |
|
|
160
|
+
| Tab | Completes commands and skills |
|
|
161
|
+
|
|
162
|
+
In the Tab menu every item ends with its owner: `omni`, `claude`, `codex` or `agy`. When you pick a
|
|
163
|
+
skill that takes arguments (like `/pr-review [pr-number | --branch]`), the chat asks for them: Tab
|
|
164
|
+
shows the options, you can type your own text, and Enter alone runs it without arguments.
|
|
165
|
+
|
|
166
|
+
The screen follows Claude Code and Codex: an input box at the bottom with a status bar (tool,
|
|
167
|
+
model, mode and folder), Tab to complete commands and skills, each AI action on one line
|
|
168
|
+
(`● Ran …`, `● Edited …`, `● Called …`) with its output collapsed, markdown answers and a
|
|
169
|
+
"Working…" indicator with elapsed time. On start, a 1.5s full-screen splash (Ctrl-C skips;
|
|
170
|
+
`SMART_AI_NO_SPLASH=1` turns it off).
|
|
171
|
+
|
|
172
|
+
On exit, it shows the command to return to the same conversation:
|
|
173
|
+
|
|
174
|
+
```text
|
|
175
|
+
Sessão salva. Retome com: ai --resume 1f3a9c2b7d40
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Chat commands
|
|
181
|
+
|
|
182
|
+
| Command | What it does |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| `/tool auto\|claude\|codex\|cursor\|agy\|openrouter\|grok\|deepseek` | Pins a tool (`auto` decides on its own) |
|
|
185
|
+
| `/model` | Lists the models of each tool |
|
|
186
|
+
| `/model codex gpt-6-astra` | Changes a model |
|
|
187
|
+
| `/model codex default` | Goes back to the default |
|
|
188
|
+
| `/account` | Lists the Claude accounts and whether they are logged in |
|
|
189
|
+
| `/account add pessoal` | Creates an account and opens the Claude login right there |
|
|
190
|
+
| `/account login NOME` | Redoes the login of an account |
|
|
191
|
+
| `/account sync NAME` | Re-shares skills, plugins and MCPs from the main account |
|
|
192
|
+
| `/account disable\|enable\|remove NOME` | Disables, re-enables or removes |
|
|
193
|
+
| `/key` | Lists the configured API keys (masked) |
|
|
194
|
+
| `/key claude\|codex\|cursor\|agy\|openrouter\|grok\|deepseek\|groq\|cerebras` | Adds a key, without showing what you type |
|
|
195
|
+
| `/key add TOOL [NAME]` | One more key for the same tool (any tool, Claude included); keys are tried in order when one fails or hits its limit |
|
|
196
|
+
| `/key remove TOOL [NAME]` | Removes the key (no name: the main one) |
|
|
197
|
+
| `/status` · `/reset` | Account status · clears cooldowns |
|
|
198
|
+
| `/lang pt\|en\|es\|fr` | Changes the language |
|
|
199
|
+
| `/mode default\|plan\|edits\|auto\|yolo` | Permission mode, the same on all three tools |
|
|
200
|
+
| `/sync` | Shares MCPs and skills across Claude, Codex and Antigravity |
|
|
201
|
+
| `/usage [watch]` · `/limits` | Real usage of each account as bars (e-mail, plan, % of the 5-hour and weekly windows, reset time) for Claude and Codex; key spend on OpenRouter; for the others, the limit message the tool gave. `watch` refreshes every 30 s |
|
|
202
|
+
| `/queue [rm\|up\|down N\|clear]` | Shows the queue; removes (`rm`), moves up (`up`) or down (`down`) a request, or empties (`clear`) what waits |
|
|
203
|
+
| `/versions [N]` | What changed in each version, newest first; `N` opens the technical note. Before the first release, shows the `feat`/`fix` commits on `main`. Titles come in the chat's language (translated by the free classifiers and cached). When the chat opens, one line tells you about a new version. |
|
|
204
|
+
| `/clear` · `/compact` | Clear the conversation · summarize it into one block to save context |
|
|
205
|
+
| `/claude:usage` · `/codex:status` · `/agy:usage` … | Each tool's native commands: opens its screen and returns to Omni on exit |
|
|
206
|
+
| `/setup [install]` | First-run guide: what is left to install, log in and set up; `install` installs the missing tools |
|
|
207
|
+
| `/terminal-setup` | Shows how to get Shift+Enter (or Option+Enter) for new lines in your terminal |
|
|
208
|
+
| `/skills` | Lists project and user skills and commands from Claude, Codex and Antigravity |
|
|
209
|
+
| `/name args` | Runs the skill or command (e.g. `/pr-review 237`). Tab completes |
|
|
210
|
+
| `/history` · `/sent` · `/trace` | Conversation · what was sent · run events |
|
|
211
|
+
| `/sessions` · `/resume ID` · `/new` | Saved sessions |
|
|
212
|
+
| `/parallel codex: tarefa \| deepseek: tarefa` | 2 to 4 analyses in parallel, read-only (codex, openrouter, grok, deepseek) |
|
|
213
|
+
| `/help` · `/exit` | Help · exit |
|
|
214
|
+
|
|
215
|
+
While the queue is running, `/clear`, `/new`, `/resume`, `/key`, `/usage` and the native
|
|
216
|
+
commands wait: they take over the terminal or switch the session. Everything else works right away.
|
|
217
|
+
|
|
218
|
+
The configuration commands also work outside the chat: `ai --model`,
|
|
219
|
+
`ai --account add pessoal`, `ai --key claude`, `ai --status`, `ai --reset`.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Models
|
|
224
|
+
|
|
225
|
+
| Key | Default | Accepted values |
|
|
226
|
+
| --- | --- | --- |
|
|
227
|
+
| `claude` | `opus` (the most capable) | `opus`, `sonnet`, `haiku` or full ID |
|
|
228
|
+
| `codex` | `gpt-6-astra` | Codex model ID |
|
|
229
|
+
| `codex_effort` | `high` | `minimal`, `low`, `medium`, `high`, `xhigh` |
|
|
230
|
+
| `agy` | Antigravity default | Antigravity model ID |
|
|
231
|
+
| `openrouter` | automatic (free) | model ID; paid only with `openrouter_paid on` |
|
|
232
|
+
| `openrouter_paid` | `off` | `on` authorizes paid OpenRouter models |
|
|
233
|
+
| `grok` | Grok default | xAI model ID |
|
|
234
|
+
| `deepseek` | `deepseek-chat` | `deepseek-chat`, `deepseek-reasoner` |
|
|
235
|
+
| `cursor` | Cursor account default | Cursor CLI model ID |
|
|
236
|
+
|
|
237
|
+
The priority order is: environment variable, then what was saved with `/model` (in
|
|
238
|
+
`~/.config/smart-ai/models.json`), then the default. The variables are
|
|
239
|
+
`SMART_AI_CLAUDE_MODEL`, `SMART_AI_CODEX_MODEL`, `SMART_AI_CODEX_EFFORT`,
|
|
240
|
+
`SMART_AI_AGY_MODEL`, `SMART_AI_OPENROUTER_MODEL`, `SMART_AI_GROK_MODEL`,
|
|
241
|
+
`SMART_AI_DEEPSEEK_MODEL` and `SMART_AI_CURSOR_MODEL`. When one of them is set,
|
|
242
|
+
`/model` warns that it takes precedence.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Claude accounts
|
|
247
|
+
|
|
248
|
+
```text
|
|
249
|
+
ai [auto] › /account add trabalho
|
|
250
|
+
Abrindo login do Claude para a conta "trabalho" (pasta isolada ~/.claude-accounts/trabalho).
|
|
251
|
+
Sua conta principal não é afetada.
|
|
252
|
+
✓ Conta "trabalho" adicionada com prioridade 3.
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Accounts are tried in priority order. The one that hits its limit goes on cooldown
|
|
256
|
+
(60 minutes by default, adjustable in `profiles.json`) and the next one takes over. The
|
|
257
|
+
`primary` account uses the normal Claude login (`claude auth login`).
|
|
258
|
+
|
|
259
|
+
Skills, plugins, agents, `CLAUDE.md`, `settings.json` and the main account's MCP servers
|
|
260
|
+
are shared with every extra account at login. Only the login stays separate. If you
|
|
261
|
+
install a new skill or MCP later, run `/account sync NAME`.
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## API keys
|
|
267
|
+
|
|
268
|
+
Besides subscriptions, each tool accepts an API key. **The subscription comes
|
|
269
|
+
first**; the key only comes in when the subscription fails or hits its limit, because a
|
|
270
|
+
key is billed per use. OpenRouter works with a key only.
|
|
271
|
+
|
|
272
|
+
| Tool | Command | Variable the CLI receives | Where to create |
|
|
273
|
+
| --- | --- | --- | --- |
|
|
274
|
+
| Claude | `/key claude` | `ANTHROPIC_API_KEY` | console.anthropic.com/settings/keys |
|
|
275
|
+
| Codex | `/key codex` | `CODEX_API_KEY` | platform.openai.com/api-keys |
|
|
276
|
+
| Antigravity | `/key agy` | `GEMINI_API_KEY` | aistudio.google.com/apikey |
|
|
277
|
+
| OpenRouter | `/key openrouter` | `OPENROUTER_API_KEY` | openrouter.ai/keys |
|
|
278
|
+
| Cursor | `/key cursor` | `CURSOR_API_KEY` | cursor.com/dashboard → Integrations |
|
|
279
|
+
| Grok | `/key grok` | `XAI_API_KEY` | console.x.ai |
|
|
280
|
+
| DeepSeek | `/key deepseek` | `DEEPSEEK_API_KEY` | platform.deepseek.com/api_keys |
|
|
281
|
+
| Groq (classifier) | `/key groq` | `GROQ_API_KEY` | console.groq.com/keys |
|
|
282
|
+
| Cerebras (classifier) | `/key cerebras` | `CEREBRAS_API_KEY` | cloud.cerebras.ai |
|
|
283
|
+
|
|
284
|
+
Cursor uses the account login first (`cursor-agent login`) and only then the keys.
|
|
285
|
+
DeepSeek, like OpenRouter, works only with a key and masks personal data before sending.
|
|
286
|
+
Groq and Cerebras don't answer questions: they only classify each request (for free) and
|
|
287
|
+
check whether a queued request has already been answered.
|
|
288
|
+
|
|
289
|
+
```text
|
|
290
|
+
ai [auto] › /key claude
|
|
291
|
+
Chave de claude (console.anthropic.com/settings/keys). Cole e tecle Enter; ela não aparece na tela.
|
|
292
|
+
>
|
|
293
|
+
✓ Chave de claude salva em ~/.config/smart-ai/keys/claude (permissão 600).
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Keys are stored in `~/.config/smart-ai/keys/`, one per file, with permission 600, and
|
|
297
|
+
are passed only to the tool's process, never to the history or the log. If the variable
|
|
298
|
+
is already set in the environment, it takes precedence. `/key` lists what is
|
|
299
|
+
configured, showing only the start and end of each key.
|
|
300
|
+
|
|
301
|
+
On Claude, the key works as an extra account after all the subscriptions: if it also
|
|
302
|
+
hits its limit, it goes on cooldown like the others.
|
|
303
|
+
|
|
304
|
+
> **Never paste a key as a shell command.** It gets recorded in the zsh history.
|
|
305
|
+
> If that happens, revoke the key on the tool's website and delete the line from
|
|
306
|
+
> `~/.zsh_history`.
|
|
307
|
+
|
|
308
|
+
On OpenRouter the default is free models only: the client picks up to three `:free`
|
|
309
|
+
variants from the catalog and uses `openrouter/free` as a last alternative. Paid models
|
|
310
|
+
stay blocked until you authorize them:
|
|
311
|
+
|
|
312
|
+
```text
|
|
313
|
+
/model openrouter_paid on # authorizes; warns it will be billed to your account
|
|
314
|
+
/model openrouter anthropic/claude-opus-5.5
|
|
315
|
+
/model openrouter_paid off # blocks again and goes back to free
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
With authorization on, the chosen model goes first and free models stay as backup. With
|
|
319
|
+
it off, a zero price cap is sent on every call, so no paid model answers.
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Modes
|
|
324
|
+
|
|
325
|
+
The mode applies to Claude, Codex and Antigravity at once and shows in the prompt
|
|
326
|
+
(`ai [auto · plan] ›`). Each session keeps its own.
|
|
327
|
+
|
|
328
|
+
| Mode | What it does | Claude | Codex | Antigravity |
|
|
329
|
+
| --- | --- | --- | --- | --- |
|
|
330
|
+
| `default` | Each tool's default | — | — | — |
|
|
331
|
+
| `plan` | Reads and plans only, changes nothing | `plan` | `--sandbox read-only` | `--mode plan` |
|
|
332
|
+
| `edits` | Accepts file edits | `acceptEdits` | `--sandbox workspace-write` | `--mode accept-edits` |
|
|
333
|
+
| `auto` | Acts on its own, with the tool's safeguards | `auto` | `workspace-write`, no approval | `--mode auto` |
|
|
334
|
+
| `yolo` | No permissions or sandbox | `bypassPermissions` | `--dangerously-bypass-approvals-and-sandbox` | `--dangerously-skip-permissions` |
|
|
335
|
+
|
|
336
|
+
`/mode yolo` asks for confirmation, because the AI can then delete files and run any
|
|
337
|
+
command. Outside the chat: `ai --mode plan "question"`. `/parallel` always runs in `plan`.
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Skills and MCP
|
|
342
|
+
|
|
343
|
+
`ai` calls the CLIs themselves, so each one uses the skills and MCPs it already has.
|
|
344
|
+
`/sync` gathers everything and installs in each tool what only exists in the others:
|
|
345
|
+
|
|
346
|
+
```text
|
|
347
|
+
ai [auto] › /sync
|
|
348
|
+
Ferramentas encontradas: claude, codex, agy
|
|
349
|
+
MCP github codex → claude
|
|
350
|
+
MCP obsidian claude → codex
|
|
351
|
+
skill humanizer claude → codex (~/.agents/skills/humanizer)
|
|
352
|
+
Aplicar? [s/N]
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
- MCPs are added through each CLI's own `mcp add` command, not by editing files by hand.
|
|
356
|
+
- The same server under different names is recognized by package or URL and not duplicated.
|
|
357
|
+
- MCPs that ship inside an app (like Codex.app's) stay there.
|
|
358
|
+
- Skills are shared by link: `~/.claude/skills`, `~/.agents/skills` (Codex) and
|
|
359
|
+
`~/.gemini/antigravity/skills`. Editing one applies to all three.
|
|
360
|
+
- Extra Claude accounts are refreshed too.
|
|
361
|
+
- MCP environment variables, which may hold tokens, are copied into the other tool's
|
|
362
|
+
config. `/sync` warns before doing it.
|
|
363
|
+
- `/sync --dry-run` only shows what it would do.
|
|
364
|
+
|
|
365
|
+
**Project skills and commands:** the chat reads `.claude/commands`, `.claude/skills`, `.agents/skills`
|
|
366
|
+
and `.agent/workflows` from the open project, plus the user folders. `/pr-review 237` goes to
|
|
367
|
+
Claude exactly as typed, and Claude runs the command natively. A skill that only exists in
|
|
368
|
+
Codex or Antigravity goes to that tool, with the file's instructions in the request.
|
|
369
|
+
|
|
370
|
+
Since the chat doesn't forward approval prompts, an MCP tool only runs if it is already
|
|
371
|
+
allowed in the CLI's permissions or the mode is `auto` or `yolo`. OpenRouter has no skills
|
|
372
|
+
or MCP.
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Direct use, no chat
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
ai "o que é um design pattern?" # automatic routing
|
|
380
|
+
ai --claude "refatorar o módulo X" # forces Claude
|
|
381
|
+
ai --codex "explicar REST" # forces Codex
|
|
382
|
+
ai --agy "pesquisar React hooks" # forces Antigravity
|
|
383
|
+
ai --openrouter "explicar Docker" # forces OpenRouter
|
|
384
|
+
ai --cursor "corrigir o teste X" # forces Cursor
|
|
385
|
+
ai --deepseek "explicar CAP theorem" # forces DeepSeek
|
|
386
|
+
ai --install # installs the missing tools (asks first)
|
|
387
|
+
ai --classify "prompt" # shows how it would be classified
|
|
388
|
+
ai --log # latest calls
|
|
389
|
+
ai doctor # diagnose install, accounts and keys
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## Where files live
|
|
395
|
+
|
|
396
|
+
| Path | Contents |
|
|
397
|
+
| --- | --- |
|
|
398
|
+
| `~/.config/smart-ai/profiles.json` | Claude accounts and routing rules |
|
|
399
|
+
| `~/.config/smart-ai/models.json` | Models chosen with `/model` |
|
|
400
|
+
| `~/.config/smart-ai/lang` | Chat language |
|
|
401
|
+
| `~/.config/smart-ai/keys/<ferramenta>` | API keys, one per file (permission 600) |
|
|
402
|
+
| `~/.claude-accounts/<nome>/` | Isolated login of each extra Claude account |
|
|
403
|
+
| `~/.local/share/smart-ai/sessions/` | Chat sessions |
|
|
404
|
+
| `~/.cache/smart-ai/state.json` | Active cooldowns |
|
|
405
|
+
| `~/.cache/smart-ai/usage.log` | Usage log, metadata only |
|
|
406
|
+
| `~/.cache/smart-ai/costs.jsonl` | Cost and tokens of each chat request, no prompt or answer (day total in `/usage`) |
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## Project structure
|
|
411
|
+
|
|
412
|
+
```text
|
|
413
|
+
omni-ai-cli/
|
|
414
|
+
├── omni_ai/ # the program (Python package)
|
|
415
|
+
│ ├── tools.py # single tool registry: name, color, CLI, model, key
|
|
416
|
+
│ ├── cli.py # ai command: classifies, routes and runs each tool
|
|
417
|
+
│ ├── chat.py # chat: sessions, events, Ctrl-C, languages
|
|
418
|
+
│ ├── ui.py # look: input box, status bar, actions and answers
|
|
419
|
+
│ ├── skills.py # project, user and native skills/commands
|
|
420
|
+
│ ├── config.py # models, keys and Claude accounts (/model, /key, /account)
|
|
421
|
+
│ ├── sync.py # /sync: MCPs and skills across the three tools
|
|
422
|
+
│ ├── openrouter.py # OpenRouter client: free, paid only if authorized
|
|
423
|
+
│ ├── grok.py # xAI client, reused by DeepSeek
|
|
424
|
+
│ ├── deepseek.py # DeepSeek client with personal data masked
|
|
425
|
+
│ ├── pii.py # masks and restores personal data
|
|
426
|
+
│ ├── osutils.py # differences between macOS, Linux and Windows
|
|
427
|
+
│ ├── profiles.json # starting template; yours lives in ~/.config/smart-ai
|
|
428
|
+
│ └── vendor/ # bundled prompt_toolkit and wcwidth (no pip)
|
|
429
|
+
├── bin/ai.js # npm launcher: finds or installs Python and runs the package
|
|
430
|
+
├── scripts/ # install.sh, install.ps1 and ai.cmd
|
|
431
|
+
├── docs/ # README in English, Spanish and French
|
|
432
|
+
├── tests/ # fake executables, no quota used
|
|
433
|
+
├── postman/ # OpenRouter HTTP simulation
|
|
434
|
+
├── get.sh / get.ps1 # one-command install
|
|
435
|
+
└── package.json · LICENSE
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
The router knows nothing about chat: it only runs a question and, with
|
|
439
|
+
`SMART_AI_EVENTS=1`, emits JSON events. The chat knows nothing about credentials:
|
|
440
|
+
accounts and models go through `config.py`.
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Tests
|
|
445
|
+
|
|
446
|
+
```bash
|
|
447
|
+
python3 -m unittest discover -s tests -v
|
|
448
|
+
bash -n scripts/install.sh
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**106 tests**: session persistence and resume, context limit, file permissions, session
|
|
452
|
+
open in two terminals, event reading, process tree cancellation, real parallelism,
|
|
453
|
+
read-only sandbox, personal data masking, OpenRouter → Codex fallback, model
|
|
454
|
+
validation, key storage and the account lifecycle. All the
|
|
455
|
+
executables are fake: **no test authenticates or uses up a subscription.**
|
|
456
|
+
|
|
457
|
+
To test OpenRouter's HTTP against the Postman simulation:
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
postman simulation run postman/simulations/openrouter.sim.yaml --port 4901 --no-history --output ndjson
|
|
461
|
+
SMART_AI_SIM_URL=http://127.0.0.1:4901/openrouter python3 -m unittest discover -s tests -v
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
## Releases and branches
|
|
467
|
+
|
|
468
|
+
Publishing to npm is automatic, run by GitHub Actions with semantic-release. The
|
|
469
|
+
version comes from commit messages (Conventional Commits) — nobody edits `version` in
|
|
470
|
+
`package.json` by hand.
|
|
471
|
+
|
|
472
|
+
| Branch | Publishes as | Example |
|
|
473
|
+
|---|---|---|
|
|
474
|
+
| `main` | `latest` | `1.4.0` |
|
|
475
|
+
| `next` | `next` (release candidate) | `1.5.0-rc.1` |
|
|
476
|
+
| `beta` | `beta` | `2.0.0-beta.1` |
|
|
477
|
+
| others / PR | nothing, CI only | — |
|
|
478
|
+
|
|
479
|
+
| Commit | Version effect |
|
|
480
|
+
|---|---|
|
|
481
|
+
| `fix: ...` | patch (`1.4.0` → `1.4.1`) |
|
|
482
|
+
| `feat: ...` | minor (`1.4.0` → `1.5.0`) |
|
|
483
|
+
| `feat!: ...` or `BREAKING CHANGE:` in the body | major (`1.4.0` → `2.0.0`) |
|
|
484
|
+
| `docs:`, `ci:`, `chore:`, `test:`, `refactor:` | no release |
|
|
485
|
+
|
|
486
|
+
Use squash merge: the PR title becomes the commit, and the `PR title` workflow blocks
|
|
487
|
+
titles that don't follow the convention.
|
|
488
|
+
|
|
489
|
+
### Commit messages
|
|
490
|
+
|
|
491
|
+
`/versions` shows the title of each `feat`/`fix` as the "simple view" and the body as the
|
|
492
|
+
"technical note". So:
|
|
493
|
+
|
|
494
|
+
- **Title:** what changes for the user, in English, present tense, no file or function
|
|
495
|
+
names. `feat: keep the input free and queue new requests while one runs`, not
|
|
496
|
+
`feat: add Queue class to chat.py`.
|
|
497
|
+
- **Body:** the why and the new behavior in short sentences; technical details only at
|
|
498
|
+
the end, if they help.
|
|
499
|
+
- One commit per noticeable change. Refactoring and tests go in `refactor:`/`test:`,
|
|
500
|
+
which don't show up in `/versions`.
|
|
501
|
+
|
|
502
|
+

|
|
503
|
+
|
|
504
|
+
Publishing uses **OIDC / trusted publishing**: GitHub Actions authenticates to npm with no
|
|
505
|
+
token and the package ships with *provenance*. One-time setup:
|
|
506
|
+
|
|
507
|
+
1. **npm → package page → Settings → Trusted Publisher**: add *GitHub Actions* with
|
|
508
|
+
`samuelrms/omni-ai-cli` and the `release.yml` workflow.
|
|
509
|
+
2. **GitHub → Settings → Branches**: protect `main` (and `next`/`beta` if used), requiring a
|
|
510
|
+
PR and the `Tests (...)`, `npm package` and `conventional` checks.
|
|
511
|
+
3. **GitHub → Settings → General → Pull Requests**: allow only *squash merging* and tick
|
|
512
|
+
*Default to pull request title*.
|
|
513
|
+
|
|
514
|
+
The workflow already requests `id-token: write` and `NPM_CONFIG_PROVENANCE`; there is no
|
|
515
|
+
`NPM_TOKEN` to store or rotate.
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
## Troubleshooting
|
|
520
|
+
|
|
521
|
+
| Problem | Solution |
|
|
522
|
+
| --- | --- |
|
|
523
|
+
| `OPENROUTER_API_KEY não configurada` | `/key openrouter` in the chat or `ai --key openrouter`. |
|
|
524
|
+
| `Arquivo de credenciais não encontrado` or `Conta 'X' sem login` | `/account login X`. |
|
|
525
|
+
| `You've hit your session limit` | Account quota. `ai` moves to the next one; add another with `/account add` or a key with `/key claude`. |
|
|
526
|
+
| `Individual quota reached` (Antigravity) | Antigravity quota; it is skipped until it renews. |
|
|
527
|
+
| `Not inside a trusted directory` (Codex) | Old install. Run the installer again. |
|
|
528
|
+
| `Claude Code não instalado` | `./scripts/install.sh` (or `scripts\install.ps1` on Windows) installs it with the official installer. |
|
|
529
|
+
| Windows: skill links fail | Turn on Developer Mode or run as administrator; otherwise `ai` uses folder junctions. |
|
|
530
|
+
| `/model` changes nothing | A `SMART_AI_*_MODEL` variable is set and takes precedence. |
|
|
531
|
+
| `/key` changes nothing | The tool's variable (`ANTHROPIC_API_KEY` etc.) is set and takes precedence. |
|
|
532
|
+
| `Sessão já aberta em outro terminal` | Close the other terminal or use `/new`. |
|
|
533
|
+
| `ai: command not found` | Add `~/.local/bin` to the `PATH`. |
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
537
|
+
## Known limitations
|
|
538
|
+
|
|
539
|
+
- The chat uses the CLIs' non-interactive modes. Native approval prompts (for
|
|
540
|
+
example, "can I edit this file?") do not appear; in those cases, use the native CLI.
|
|
541
|
+
- `/parallel` only analyzes: Codex in `--sandbox read-only` or OpenRouter, which does not
|
|
542
|
+
access the files. The agents do not edit the project at the same time.
|
|
543
|
+
- The simple/complex classification is by keywords and length, not by a model.
|
|
544
|
+
- Switching models does not renew the account's quota.
|
|
545
|
+
- OpenRouter has no streaming in this version: the answer appears whole at the end.
|
|
546
|
+
- On Windows the code uses the native equivalents (process groups and `taskkill`, `msvcrt`, folder junctions), but it has only been tested for real on macOS.
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## Privacy
|
|
551
|
+
|
|
552
|
+
- Sessions, API keys and logs stay only on your machine, with permissions restricted to your user.
|
|
553
|
+
- The usage log records tool, account and status, **never the text of the question**.
|
|
554
|
+
- Before going to OpenRouter, emails, phone numbers, documents and other personal data
|
|
555
|
+
are swapped for placeholders and restored in the answer. Masking is pattern-based and
|
|
556
|
+
does not guarantee full anonymization.
|
|
557
|
+
- Claude, Codex and Antigravity receive the original text, under each service's terms.
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## License
|
|
562
|
+
|
|
563
|
+
[MIT](../LICENSE). Bundled in `vendor/`: prompt_toolkit (BSD-3-Clause) and wcwidth (MIT), each with its license.
|