pokt-cli 1.0.8 → 1.0.9

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Pokt CLI
2
2
 
3
- CLI de **Vibe Coding** com IA: OpenRouter, Ollama (local e cloud), Gemini e provedor Pokt (controller).
3
+ CLI de **Vibe Coding** com IA: OpenAI, Grok (xAI), OpenRouter, Ollama (local e cloud), Gemini e provedor Pokt (controller).
4
4
 
5
5
  ## Requisitos
6
6
 
@@ -60,35 +60,71 @@ pokt --help
60
60
  | `pokt models <action>` | Gerenciar modelos (listar, adicionar, trocar) |
61
61
  | `pokt provider use <provider>` | Trocar provedor de API |
62
62
  | `pokt mcp [action]` | Gerenciar servidores MCP (ferramentas externas) |
63
+ | `pokt doctor` | Diagnóstico (credenciais + conectividade) |
63
64
 
64
65
  ### Config (`config`)
65
66
 
66
67
  - `pokt config show` — Mostra a configuração atual (tokens mascarados).
68
+ - `pokt config set-openai -v <key>` — API key OpenAI.
69
+ - `pokt config set-grok -v <key>` — API key Grok (xAI).
67
70
  - `pokt config set-openrouter -v <token>` — Token OpenRouter.
68
71
  - `pokt config set-ollama -v <url>` — URL base do Ollama local.
69
72
  - `pokt config set-ollama-cloud -v <key>` — API key Ollama Cloud.
70
73
  - `pokt config set-gemini -v <key>` — API key Google Gemini.
71
74
  - `pokt config set-pokt-token -v <token>` — Token do controller Pokt.
72
75
  - `pokt config clear-openrouter` — Remove o token OpenRouter.
76
+ - `pokt config clear-openai` — Remove a API key OpenAI.
77
+ - `pokt config clear-grok` — Remove a API key Grok (xAI).
73
78
 
74
79
  ### Modelos (`models`)
75
80
 
76
81
  - `pokt models list` — Lista modelos registrados e o ativo.
82
+ - `pokt models fetch-openai` — Busca modelos disponíveis na OpenAI.
83
+ - `pokt models fetch-grok` — Busca modelos disponíveis no Grok (xAI).
77
84
  - `pokt models fetch-openrouter` — Busca modelos disponíveis no OpenRouter.
78
85
  - `pokt models fetch-ollama` — Busca modelos do Ollama local.
79
86
  - `pokt models fetch-ollama-cloud` — Busca modelos do Ollama Cloud.
80
- - `pokt models add-openrouter`, `add-ollama`, `add-ollama-cloud` — Adiciona modelo (use `-i <id>`).
87
+ - `pokt models add-openai`, `add-grok`, `add-openrouter`, `add-ollama`, `add-ollama-cloud` — Adiciona modelo (use `-i <id>`).
81
88
  - `pokt models use -i <id> -p <provider>` — Define o modelo ativo.
82
89
 
90
+ ### Variáveis de ambiente (opcional)
91
+
92
+ Se preferir não salvar chaves no computador (ou para CI), você pode usar env vars. O Pokt prioriza env var e depois cai no `pokt config`.
93
+
94
+ - `OPENAI_API_KEY`
95
+ - `XAI_API_KEY` (ou `GROK_API_KEY`)
96
+ - `OPENROUTER_API_KEY` (ou `OPENROUTER_TOKEN`)
97
+ - `GEMINI_API_KEY` (ou `GOOGLE_API_KEY`)
98
+ - `OLLAMA_BASE_URL`
99
+ - `OLLAMA_CLOUD_API_KEY`
100
+ - `POKT_TOKEN`
101
+
83
102
  ### Provedores (`provider`)
84
103
 
85
- Provedores suportados: `controller` (Pokt), `openrouter`, `gemini`, `ollama`, `ollama-cloud`.
104
+ Provedores suportados: `controller` (Pokt), `openai`, `grok`, `openrouter`, `gemini`, `ollama`, `ollama-cloud`.
86
105
 
87
106
  ```bash
107
+ pokt provider use openai
108
+ pokt provider use grok
88
109
  pokt provider use openrouter
89
110
  pokt provider use ollama
90
111
  ```
91
112
 
113
+ ### MCP por projeto (`pokt_cli/mcp.json`)
114
+
115
+ Na **raiz do seu repositório** (subindo pastas a partir do diretório atual), o Pokt procura uma pasta chamada **`pokt_cli`**, **`Pokt_CLI`**, **`Pot_cli`**, etc. (aceita essas variações, comparação sem diferenciar maiúsculas).
116
+
117
+ Dentro dela, o arquivo **`mcp.json`** define servidores MCP. O Pokt aceita a chave **`mcpServers`** (Cursor/Claude) ou **`servers`** (ex.: Neon e outros). Opcionalmente `mcp.servers` / `mcp.mcpServers`. O Pokt **mescla** isso com servidores **globais** (`pokt mcp add`); se o **mesmo nome** existir nos dois, vale o do **projeto**.
118
+
119
+ - `pokt mcp init` — cria `./pokt_cli/mcp.json` com exemplo (no diretório atual).
120
+ - `pokt mcp list` — mostra origem `[projeto]` / `[global]`.
121
+ - `pokt mcp test` — testa stdio e HTTP (Streamable HTTP ou `transport: "sse"`).
122
+ - `pokt mcp link -n <nome>` — para entradas HTTP com `"oauth": true`: abre o navegador, autoriza e grava tokens em `pokt_cli/.mcp-oauth/` (adicione `.mcp-oauth` ao `.gitignore` se não quiser versionar).
123
+
124
+ Em strings do JSON você pode usar **`${NOME_DA_VARIÁVEL}`** para ler variáveis de ambiente (ex.: tokens em `headers`).
125
+
126
+ No **chat**, as tools MCP aparecem com prefixo `mcp_`; a IA também pode usar `run_command` e `write_file` para scripts (Python, etc.) quando fizer sentido.
127
+
92
128
  ## Desenvolvimento
93
129
 
94
130
  ```bash
package/dist/bin/pokt.js CHANGED
@@ -9,10 +9,13 @@ import { mcpCommand } from '../commands/mcp.js';
9
9
  import { updateCommand } from '../commands/update.js';
10
10
  import { uninstallCommand } from '../commands/uninstall.js';
11
11
  import { proCommand, runProFlow } from '../commands/pro.js';
12
+ import { doctorCommand } from '../commands/doctor.js';
12
13
  import prompts from 'prompts';
13
14
  import chalk from 'chalk';
14
15
  import { ui } from '../ui.js';
15
16
  const argv = hideBin(process.argv);
17
+ /** Banner typewriter só na 1ª vez do menu nesta execução; ao voltar de submenus, banner instantâneo. Novo `pokt` = animação de novo. */
18
+ let mainMenuBannerAnimatedThisProcess = false;
16
19
  if (argv.length === 0) {
17
20
  showMenu();
18
21
  }
@@ -25,6 +28,7 @@ else {
25
28
  .command(chatCommand)
26
29
  .command(providerCommand)
27
30
  .command(mcpCommand)
31
+ .command(doctorCommand)
28
32
  .command(updateCommand)
29
33
  .command(uninstallCommand)
30
34
  .command(proCommand)
@@ -37,7 +41,10 @@ async function showMenu() {
37
41
  const active = getEffectiveActiveModel();
38
42
  const providerLabel = active ? (PROVIDER_LABELS[active.provider] ?? active.provider) : 'No provider';
39
43
  console.log('');
40
- await ui.printBanner({ animate: true });
44
+ const animateBanner = !mainMenuBannerAnimatedThisProcess;
45
+ if (animateBanner)
46
+ mainMenuBannerAnimatedThisProcess = true;
47
+ await ui.printBanner({ animate: animateBanner });
41
48
  console.log(ui.statusLine(providerLabel));
42
49
  console.log('');
43
50
  console.log(ui.separator());
@@ -52,6 +59,7 @@ async function showMenu() {
52
59
  { title: '➕ Add / sync models', value: 'add-models' },
53
60
  { title: '🏠 Switch API Provider (casa de API)', value: 'provider' },
54
61
  { title: '🔌 MCP Servers (tools externos)', value: 'mcp' },
62
+ { title: '🩺 Doctor (diagnóstico)', value: 'doctor' },
55
63
  { title: '⚙️ Configure API Keys / Tokens', value: 'config' },
56
64
  { title: '⭐ Torne-se Pro (site — pagamento + chave)', value: 'pro' },
57
65
  { title: '🔄 Atualizar Pokt CLI', value: 'update' },
@@ -64,7 +72,8 @@ async function showMenu() {
64
72
  }
65
73
  if (response.action === 'chat') {
66
74
  const { chatCommand } = await import('../commands/chat.js');
67
- chatCommand.handler({ fromMenu: true });
75
+ await chatCommand.handler({ fromMenu: true });
76
+ return showMenu();
68
77
  }
69
78
  else if (response.action === 'models') {
70
79
  await handleModelsMenu();
@@ -78,6 +87,11 @@ async function showMenu() {
78
87
  else if (response.action === 'config') {
79
88
  await handleConfigMenu();
80
89
  }
90
+ else if (response.action === 'doctor') {
91
+ const { doctorCommand } = await import('../commands/doctor.js');
92
+ await doctorCommand.handler({});
93
+ return showMenu();
94
+ }
81
95
  else if (response.action === 'pro') {
82
96
  runProFlow();
83
97
  return showMenu();
@@ -98,8 +112,9 @@ async function showMenu() {
98
112
  name: 'mcpAction',
99
113
  message: 'MCP:',
100
114
  choices: [
101
- { title: '🧪 Test connection', value: 'test' },
102
- { title: '🔙 Back', value: 'back' }
115
+ { title: '📄 Criar pokt_cli/mcp.json neste diretório (init)', value: 'init' },
116
+ { title: '🧪 Testar conexão (global + projeto)', value: 'test' },
117
+ { title: '🔙 Voltar', value: 'back' }
103
118
  ]
104
119
  });
105
120
  if (mcpResp.mcpAction === 'back')
@@ -179,9 +194,13 @@ async function handleAddModelsMenu() {
179
194
  name: 'action',
180
195
  message: 'Add or sync models from which provider?',
181
196
  choices: [
197
+ { title: 'OpenAI — sync all from API', value: 'fetch-openai' },
198
+ { title: 'Grok (xAI) — sync all from API', value: 'fetch-grok' },
182
199
  { title: 'OpenRouter — sync all from API', value: 'fetch-openrouter' },
183
200
  { title: 'Ollama (local) — sync from your Ollama (list models)', value: 'fetch-ollama' },
184
201
  { title: 'Ollama Cloud — sync from API', value: 'fetch-ollama-cloud' },
202
+ { title: 'OpenAI — add model by ID', value: 'add-openai' },
203
+ { title: 'Grok (xAI) — add model by ID', value: 'add-grok' },
185
204
  { title: 'OpenRouter — add model by ID', value: 'add-openrouter' },
186
205
  { title: 'Ollama (local) — add model by ID', value: 'add-ollama' },
187
206
  { title: 'Ollama Cloud — add model by ID', value: 'add-ollama-cloud' },
@@ -190,14 +209,18 @@ async function handleAddModelsMenu() {
190
209
  });
191
210
  if (response.action === 'back')
192
211
  return showMenu();
193
- const addActions = ['add-openrouter', 'add-ollama', 'add-ollama-cloud'];
212
+ const addActions = ['add-openai', 'add-grok', 'add-openrouter', 'add-ollama', 'add-ollama-cloud'];
194
213
  if (addActions.includes(response.action)) {
195
214
  const idPrompt = await prompts({
196
215
  type: 'text',
197
216
  name: 'id',
198
- message: response.action === 'add-openrouter'
199
- ? 'Model ID (ex: google/gemini-2.5-flash):'
200
- : 'Model ID (ex: llama3):'
217
+ message: response.action === 'add-openai'
218
+ ? 'Model ID (ex: gpt-4o-mini):'
219
+ : response.action === 'add-grok'
220
+ ? 'Model ID (ex: grok-2-latest):'
221
+ : response.action === 'add-openrouter'
222
+ ? 'Model ID (ex: google/gemini-2.5-flash):'
223
+ : 'Model ID (ex: llama3):'
201
224
  });
202
225
  const id = typeof idPrompt.id === 'string' ? idPrompt.id.trim() : '';
203
226
  if (id) {
@@ -222,6 +245,8 @@ async function handleConfigMenu() {
222
245
  choices: [
223
246
  { title: 'View current config', value: 'show' },
224
247
  { title: 'Pokt Token (do painel — só isso para usar Controller)', value: 'set-pokt-token' },
248
+ { title: 'OpenAI API Key', value: 'set-openai' },
249
+ { title: 'Grok (xAI) API Key', value: 'set-grok' },
225
250
  { title: 'OpenRouter Token', value: 'set-openrouter' },
226
251
  { title: 'Gemini API Key', value: 'set-gemini' },
227
252
  { title: 'Ollama Base URL (local)', value: 'set-ollama' },
@@ -233,6 +258,8 @@ async function handleConfigMenu() {
233
258
  return showMenu();
234
259
  if (response.type === 'show') {
235
260
  const { getControllerBaseUrl } = await import('../config.js');
261
+ const openai = config.get('openaiApiKey');
262
+ const grok = config.get('grokApiKey');
236
263
  const openrouter = config.get('openrouterToken');
237
264
  const gemini = config.get('geminiApiKey');
238
265
  const ollama = config.get('ollamaBaseUrl');
@@ -241,6 +268,8 @@ async function handleConfigMenu() {
241
268
  console.log(chalk.blue('\nCurrent config (tokens masked):'));
242
269
  console.log(ui.dim(' Controller URL:'), getControllerBaseUrl(), ui.dim('(já configurado)'));
243
270
  console.log(ui.dim(' Pokt Token:'), poktToken ? poktToken.slice(0, 10) + '****' : '(not set)');
271
+ console.log(ui.dim(' OpenAI API Key:'), openai ? openai.slice(0, 8) + '****' : '(not set)');
272
+ console.log(ui.dim(' Grok (xAI) API Key:'), grok ? grok.slice(0, 8) + '****' : '(not set)');
244
273
  console.log(ui.dim(' OpenRouter Token:'), openrouter ? openrouter.slice(0, 8) + '****' : '(not set)');
245
274
  console.log(ui.dim(' Gemini API Key:'), gemini ? gemini.slice(0, 8) + '****' : '(not set)');
246
275
  console.log(ui.dim(' Ollama Base URL (local):'), ollama || '(not set)');
@@ -259,6 +288,8 @@ async function handleConfigMenu() {
259
288
  if (valueResponse.val) {
260
289
  const keyMap = {
261
290
  'set-gemini': 'geminiApiKey',
291
+ 'set-openai': 'openaiApiKey',
292
+ 'set-grok': 'grokApiKey',
262
293
  'set-openrouter': 'openrouterToken',
263
294
  'set-ollama': 'ollamaBaseUrl',
264
295
  'set-ollama-cloud': 'ollamaCloudApiKey',
@@ -1,9 +1,9 @@
1
1
  import OpenAI from 'openai';
2
- import { config, getControllerBaseUrl } from '../config.js';
2
+ import { getControllerBaseUrl, getOpenAIApiKey, getGrokApiKey, getOpenRouterToken, getGeminiApiKey, getOllamaCloudApiKey, getOllamaBaseUrl, getPoktToken, } from '../config.js';
3
3
  export async function getClient(modelConfig) {
4
4
  if (modelConfig.provider === 'controller') {
5
5
  const baseUrl = getControllerBaseUrl();
6
- const token = config.get('poktToken');
6
+ const token = getPoktToken();
7
7
  if (!token) {
8
8
  throw new Error('Token Pokt não configurado. No painel gere um token e use: pokt config set-pokt-token -v <token>');
9
9
  }
@@ -16,10 +16,30 @@ export async function getClient(modelConfig) {
16
16
  }
17
17
  });
18
18
  }
19
+ else if (modelConfig.provider === 'openai') {
20
+ const apiKey = getOpenAIApiKey();
21
+ if (!apiKey) {
22
+ throw new Error('OpenAI API key não configurada. Use: pokt config set-openai -v <key>');
23
+ }
24
+ return new OpenAI({
25
+ baseURL: 'https://api.openai.com/v1',
26
+ apiKey,
27
+ });
28
+ }
29
+ else if (modelConfig.provider === 'grok') {
30
+ const apiKey = getGrokApiKey();
31
+ if (!apiKey) {
32
+ throw new Error('Grok (xAI) API key não configurada. Use: pokt config set-grok -v <key>');
33
+ }
34
+ return new OpenAI({
35
+ baseURL: 'https://api.x.ai/v1',
36
+ apiKey,
37
+ });
38
+ }
19
39
  else if (modelConfig.provider === 'openrouter') {
20
40
  return new OpenAI({
21
41
  baseURL: 'https://openrouter.ai/api/v1',
22
- apiKey: config.get('openrouterToken'),
42
+ apiKey: getOpenRouterToken(),
23
43
  defaultHeaders: {
24
44
  'HTTP-Referer': 'https://github.com/pokt-cli',
25
45
  'X-Title': 'Pokt CLI',
@@ -27,7 +47,7 @@ export async function getClient(modelConfig) {
27
47
  });
28
48
  }
29
49
  else if (modelConfig.provider === 'gemini') {
30
- const apiKey = config.get('geminiApiKey');
50
+ const apiKey = getGeminiApiKey();
31
51
  if (!apiKey) {
32
52
  throw new Error('Gemini API key not set. Use: pokt config set-gemini -v <key>');
33
53
  }
@@ -37,7 +57,7 @@ export async function getClient(modelConfig) {
37
57
  });
38
58
  }
39
59
  else if (modelConfig.provider === 'ollama-cloud') {
40
- const apiKey = config.get('ollamaCloudApiKey');
60
+ const apiKey = getOllamaCloudApiKey();
41
61
  if (!apiKey) {
42
62
  throw new Error('Ollama Cloud API key não configurada. Crie uma em https://ollama.com/settings/keys e use: pokt config set-ollama-cloud -v <key>');
43
63
  }
@@ -52,7 +72,7 @@ export async function getClient(modelConfig) {
52
72
  else {
53
73
  // Ollama (local) — não precisa de API key
54
74
  return new OpenAI({
55
- baseURL: `${config.get('ollamaBaseUrl')}/v1`,
75
+ baseURL: `${getOllamaBaseUrl()}/v1`,
56
76
  apiKey: 'ollama',
57
77
  });
58
78
  }